Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * WebP encoding support via libwebp
  3.  * Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com>
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * WebP encoder using libwebp: common structs and methods.
  25.  */
  26.  
  27. #include "libwebpenc_common.h"
  28.  
  29. int ff_libwebp_error_to_averror(int err)
  30. {
  31.     switch (err) {
  32.     case VP8_ENC_ERROR_OUT_OF_MEMORY:
  33.     case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
  34.         return AVERROR(ENOMEM);
  35.     case VP8_ENC_ERROR_NULL_PARAMETER:
  36.     case VP8_ENC_ERROR_INVALID_CONFIGURATION:
  37.     case VP8_ENC_ERROR_BAD_DIMENSION:
  38.         return AVERROR(EINVAL);
  39.     }
  40.     return AVERROR_UNKNOWN;
  41. }
  42.  
  43. av_cold int ff_libwebp_encode_init_common(AVCodecContext *avctx)
  44. {
  45.     LibWebPContextCommon *s = avctx->priv_data;
  46.     int ret;
  47.  
  48.     if (avctx->global_quality >= 0)
  49.         s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA,
  50.                               0.0f, 100.0f);
  51.  
  52.     if (avctx->compression_level < 0 || avctx->compression_level > 6) {
  53.         av_log(avctx, AV_LOG_WARNING, "invalid compression level: %d\n",
  54.                avctx->compression_level);
  55.         avctx->compression_level = av_clip(avctx->compression_level, 0, 6);
  56.     }
  57.  
  58.     if (s->preset >= WEBP_PRESET_DEFAULT) {
  59.         ret = WebPConfigPreset(&s->config, s->preset, s->quality);
  60.         if (!ret)
  61.             return AVERROR_UNKNOWN;
  62.         s->lossless              = s->config.lossless;
  63.         s->quality               = s->config.quality;
  64.         avctx->compression_level = s->config.method;
  65.     } else {
  66.         ret = WebPConfigInit(&s->config);
  67.         if (!ret)
  68.             return AVERROR_UNKNOWN;
  69.  
  70.         s->config.lossless = s->lossless;
  71.         s->config.quality  = s->quality;
  72.         s->config.method   = avctx->compression_level;
  73.  
  74.         ret = WebPValidateConfig(&s->config);
  75.         if (!ret)
  76.             return AVERROR(EINVAL);
  77.     }
  78.  
  79.     av_log(avctx, AV_LOG_DEBUG, "%s - quality=%.1f method=%d\n",
  80.            s->lossless ? "Lossless" : "Lossy", s->quality,
  81.            avctx->compression_level);
  82.  
  83.     return 0;
  84. }
  85.  
  86. int ff_libwebp_get_frame(AVCodecContext *avctx, LibWebPContextCommon *s,
  87.                          const AVFrame *frame, AVFrame **alt_frame_ptr,
  88.                          WebPPicture **pic_ptr) {
  89.     int ret;
  90.     WebPPicture *pic = NULL;
  91.     AVFrame *alt_frame = NULL;
  92.  
  93.     if (avctx->width > WEBP_MAX_DIMENSION || avctx->height > WEBP_MAX_DIMENSION) {
  94.         av_log(avctx, AV_LOG_ERROR, "Picture size is too large. Max is %dx%d.\n",
  95.                WEBP_MAX_DIMENSION, WEBP_MAX_DIMENSION);
  96.         return AVERROR(EINVAL);
  97.     }
  98.  
  99.     *pic_ptr = av_malloc(sizeof(*pic));
  100.     pic = *pic_ptr;
  101.     if (!pic)
  102.         return AVERROR(ENOMEM);
  103.  
  104.     ret = WebPPictureInit(pic);
  105.     if (!ret) {
  106.         ret = AVERROR_UNKNOWN;
  107.         goto end;
  108.     }
  109.     pic->width  = avctx->width;
  110.     pic->height = avctx->height;
  111.  
  112.     if (avctx->pix_fmt == AV_PIX_FMT_RGB32) {
  113.         if (!s->lossless) {
  114.             /* libwebp will automatically convert RGB input to YUV when
  115.                encoding lossy. */
  116.             if (!s->conversion_warning) {
  117.                 av_log(avctx, AV_LOG_WARNING,
  118.                        "Using libwebp for RGB-to-YUV conversion. You may want "
  119.                        "to consider passing in YUV instead for lossy "
  120.                        "encoding.\n");
  121.                 s->conversion_warning = 1;
  122.             }
  123.         }
  124.         pic->use_argb    = 1;
  125.         pic->argb        = (uint32_t *)frame->data[0];
  126.         pic->argb_stride = frame->linesize[0] / 4;
  127.     } else {
  128.         if (frame->linesize[1] != frame->linesize[2] || s->cr_threshold) {
  129.             if (!s->chroma_warning && !s->cr_threshold) {
  130.                 av_log(avctx, AV_LOG_WARNING,
  131.                        "Copying frame due to differing chroma linesizes.\n");
  132.                 s->chroma_warning = 1;
  133.             }
  134.             *alt_frame_ptr = av_frame_alloc();
  135.             alt_frame = *alt_frame_ptr;
  136.             if (!alt_frame) {
  137.                 ret = AVERROR(ENOMEM);
  138.                 goto end;
  139.             }
  140.             alt_frame->width  = frame->width;
  141.             alt_frame->height = frame->height;
  142.             alt_frame->format = frame->format;
  143.             if (s->cr_threshold)
  144.                 alt_frame->format = AV_PIX_FMT_YUVA420P;
  145.             ret = av_frame_get_buffer(alt_frame, 32);
  146.             if (ret < 0)
  147.                 goto end;
  148.             alt_frame->format = frame->format;
  149.             av_frame_copy(alt_frame, frame);
  150.             frame = alt_frame;
  151.             if (s->cr_threshold) {
  152.                 int x,y, x2, y2, p;
  153.                 int bs = s->cr_size;
  154.  
  155.                 if (!s->ref) {
  156.                     s->ref = av_frame_clone(frame);
  157.                     if (!s->ref) {
  158.                         ret = AVERROR(ENOMEM);
  159.                         goto end;
  160.                     }
  161.                 }
  162.  
  163.                 alt_frame->format = AV_PIX_FMT_YUVA420P;
  164.                 for (y = 0; y < frame->height; y+= bs) {
  165.                     for (x = 0; x < frame->width; x+= bs) {
  166.                         int skip;
  167.                         int sse = 0;
  168.                         for (p = 0; p < 3; p++) {
  169.                             int bs2 = bs >> !!p;
  170.                             int w = FF_CEIL_RSHIFT(frame->width , !!p);
  171.                             int h = FF_CEIL_RSHIFT(frame->height, !!p);
  172.                             int xs = x >> !!p;
  173.                             int ys = y >> !!p;
  174.                             for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) {
  175.                                 for (x2 = xs; x2 < FFMIN(xs + bs2, w); x2++) {
  176.                                     int diff =  frame->data[p][frame->linesize[p] * y2 + x2]
  177.                                               -s->ref->data[p][frame->linesize[p] * y2 + x2];
  178.                                     sse += diff*diff;
  179.                                 }
  180.                             }
  181.                         }
  182.                         skip = sse < s->cr_threshold && frame->data[3] != s->ref->data[3];
  183.                         if (!skip)
  184.                             for (p = 0; p < 3; p++) {
  185.                                 int bs2 = bs >> !!p;
  186.                                 int w = FF_CEIL_RSHIFT(frame->width , !!p);
  187.                                 int h = FF_CEIL_RSHIFT(frame->height, !!p);
  188.                                 int xs = x >> !!p;
  189.                                 int ys = y >> !!p;
  190.                                 for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) {
  191.                                     memcpy(&s->ref->data[p][frame->linesize[p] * y2 + xs],
  192.                                             & frame->data[p][frame->linesize[p] * y2 + xs], FFMIN(bs2, w-xs));
  193.                                 }
  194.                             }
  195.                         for (y2 = y; y2 < FFMIN(y+bs, frame->height); y2++) {
  196.                             memset(&frame->data[3][frame->linesize[3] * y2 + x],
  197.                                     skip ? 0 : 255,
  198.                                     FFMIN(bs, frame->width-x));
  199.                         }
  200.                     }
  201.                 }
  202.             }
  203.         }
  204.  
  205.         pic->use_argb  = 0;
  206.         pic->y         = frame->data[0];
  207.         pic->u         = frame->data[1];
  208.         pic->v         = frame->data[2];
  209.         pic->y_stride  = frame->linesize[0];
  210.         pic->uv_stride = frame->linesize[1];
  211.         if (frame->format == AV_PIX_FMT_YUVA420P) {
  212.             pic->colorspace = WEBP_YUV420A;
  213.             pic->a          = frame->data[3];
  214.             pic->a_stride   = frame->linesize[3];
  215.             if (alt_frame)
  216.                 WebPCleanupTransparentArea(pic);
  217.         } else {
  218.             pic->colorspace = WEBP_YUV420;
  219.         }
  220.  
  221.         if (s->lossless) {
  222.             /* We do not have a way to automatically prioritize RGB over YUV
  223.                in automatic pixel format conversion based on whether we're
  224.                encoding lossless or lossy, so we do conversion with libwebp as
  225.                a convenience. */
  226.             if (!s->conversion_warning) {
  227.                 av_log(avctx, AV_LOG_WARNING,
  228.                        "Using libwebp for YUV-to-RGB conversion. You may want "
  229.                        "to consider passing in RGB instead for lossless "
  230.                        "encoding.\n");
  231.                 s->conversion_warning = 1;
  232.             }
  233.  
  234. #if (WEBP_ENCODER_ABI_VERSION <= 0x201)
  235.             /* libwebp should do the conversion automatically, but there is a
  236.                bug that causes it to return an error instead, so a work-around
  237.                is required.
  238.                See https://code.google.com/p/webp/issues/detail?id=178 */
  239.             pic->memory_ = (void*)1;  /* something non-null */
  240.             ret = WebPPictureYUVAToARGB(pic);
  241.             if (!ret) {
  242.                 av_log(avctx, AV_LOG_ERROR,
  243.                        "WebPPictureYUVAToARGB() failed with error: %d\n",
  244.                        pic->error_code);
  245.                 ret = libwebp_error_to_averror(pic->error_code);
  246.                 goto end;
  247.             }
  248.             pic->memory_ = NULL;  /* restore pointer */
  249. #endif
  250.         }
  251.     }
  252. end:
  253.     return ret;
  254. }
  255.