[FFmpeg-devel] [RFC][PATCH] libwebp: combine libwebp_anim and libwebp encoders into one

James Almer jamrial at gmail.com
Sun May 24 21:22:42 CEST 2015


Use either the WebPEncoder or WebPAnimEncoder APIs depending on availability
of the latter.

Signed-off-by: James Almer <jamrial at gmail.com>
---
This is an RFC because the resulting encoder will use one of the two APIs, which
is a change from the current behavior of having one encoder for each API.
The new encoder was added only two days ago so removing it shouldn't be an issue.
Basically, is there any benefit from using the native lavf muxer over letting
WebPAnimEncoder do the entire process to justify having two encoders?

The resulting ifdeffery is minimal now that the webp muxer can act as a raw muxer
cleanly, so the only concern is the above. We can deal with cosmetics later, but
the functional change needs to be done asap least we want to deal with deprecation
nonsense if the new encoder makes it into a release.

 configure                           |   6 +-
 libavcodec/Makefile                 |   3 +-
 libavcodec/allcodecs.c              |   1 -
 libavcodec/libwebpenc.c             | 365 +++++++++++++++++++++++++++++++++++-
 libavcodec/libwebpenc_animencoder.c | 150 ---------------
 libavcodec/libwebpenc_common.c      | 254 -------------------------
 libavcodec/libwebpenc_common.h      |  84 ---------
 7 files changed, 362 insertions(+), 501 deletions(-)
 delete mode 100644 libavcodec/libwebpenc_animencoder.c
 delete mode 100644 libavcodec/libwebpenc_common.c
 delete mode 100644 libavcodec/libwebpenc_common.h

diff --git a/configure b/configure
index 09f49d2..930ea42 100755
--- a/configure
+++ b/configure
@@ -1695,6 +1695,7 @@ HEADERS_LIST="
     udplite_h
     unistd_h
     valgrind_valgrind_h
+    webp_mux_h
     windows_h
     winsock2_h
 "
@@ -5103,9 +5104,8 @@ enabled libvpx            && {
     enabled libvpx_vp9_decoder && { check_lib2 "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp9_dx" -lvpx || disable libvpx_vp9_decoder; }
     enabled libvpx_vp9_encoder && { check_lib2 "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp9_cx VP9E_SET_AQ_MODE" -lvpx || disable libvpx_vp9_encoder; } }
 enabled libwavpack        && require libwavpack wavpack/wavpack.h WavpackOpenFileOutput  -lwavpack
-enabled libwebp           && {
-    enabled libwebp_encoder      && require_pkg_config "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion
-    enabled libwebp_anim_encoder && { use_pkg_config "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit || disable libwebp_anim_encoder; } }
+enabled libwebp           && require_pkg_config "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion &&
+                              use_pkg_config "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit
 enabled libx264           && { use_pkg_config x264 "stdint.h x264.h" x264_encoder_encode ||
                                { require libx264 x264.h x264_encoder_encode -lx264 &&
                                  warn "using libx264 without pkg-config"; } } &&
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 02aa61e..cb88fd1 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -783,8 +783,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_ENCODER)         += libvpxenc.o
 OBJS-$(CONFIG_LIBVPX_VP9_DECODER)         += libvpxdec.o libvpx.o
 OBJS-$(CONFIG_LIBVPX_VP9_ENCODER)         += libvpxenc.o libvpx.o
 OBJS-$(CONFIG_LIBWAVPACK_ENCODER)         += libwavpackenc.o
-OBJS-$(CONFIG_LIBWEBP_ENCODER)            += libwebpenc_common.o libwebpenc.o
-OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER)       += libwebpenc_common.o libwebpenc_animencoder.o
+OBJS-$(CONFIG_LIBWEBP_ENCODER)            += libwebpenc.o
 OBJS-$(CONFIG_LIBX264_ENCODER)            += libx264.o
 OBJS-$(CONFIG_LIBX265_ENCODER)            += libx265.o
 OBJS-$(CONFIG_LIBXAVS_ENCODER)            += libxavs.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index fe79d0b..2552962 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -540,7 +540,6 @@ void avcodec_register_all(void)
     REGISTER_ENCDEC (LIBVPX_VP8,        libvpx_vp8);
     REGISTER_ENCDEC (LIBVPX_VP9,        libvpx_vp9);
     REGISTER_ENCODER(LIBWAVPACK,        libwavpack);
-    REGISTER_ENCODER(LIBWEBP_ANIM,      libwebp_anim);  /* preferred over libwebp */
     REGISTER_ENCODER(LIBWEBP,           libwebp);
     REGISTER_ENCODER(LIBX264,           libx264);
     REGISTER_ENCODER(LIBX264RGB,        libx264rgb);
diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c
index db96e16..94779b7 100644
--- a/libavcodec/libwebpenc.c
+++ b/libavcodec/libwebpenc.c
@@ -24,25 +24,345 @@
  * WebP encoder using libwebp (WebPEncode API)
  */
 
-#include "libwebpenc_common.h"
+#include "libavutil/common.h"
+#include "libavutil/frame.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "internal.h"
 
-typedef LibWebPContextCommon LibWebPContext;
+#include <webp/encode.h>
+#if HAVE_WEBP_MUX_H
+#include <webp/mux.h>
+#endif
+
+typedef struct LibWebPContext {
+    AVClass *class;         // class for AVOptions
+    float quality;          // lossy quality 0 - 100
+    int lossless;           // use lossless encoding
+    int preset;             // configuration preset
+    int chroma_warning;     // chroma linesize mismatch warning has been printed
+    int conversion_warning; // pixel format conversion warning has been printed
+    WebPConfig config;      // libwebp configuration
+    AVFrame *ref;
+    int cr_size;
+    int cr_threshold;
+#if HAVE_WEBP_MUX_H
+    WebPAnimEncoder *enc;     // the main AnimEncoder object
+    int64_t prev_frame_pts;   // pts of the previously encoded frame.
+    int done;                 // If true, we have assembled the bitstream already
+#endif
+} LibWebPContext;
+
+static int libwebp_error_to_averror(int err)
+{
+    switch (err) {
+    case VP8_ENC_ERROR_OUT_OF_MEMORY:
+    case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
+        return AVERROR(ENOMEM);
+    case VP8_ENC_ERROR_NULL_PARAMETER:
+    case VP8_ENC_ERROR_INVALID_CONFIGURATION:
+    case VP8_ENC_ERROR_BAD_DIMENSION:
+        return AVERROR(EINVAL);
+    }
+    return AVERROR_UNKNOWN;
+}
 
 static av_cold int libwebp_encode_init(AVCodecContext *avctx)
 {
-    return ff_libwebp_encode_init_common(avctx);
+    LibWebPContext *s = avctx->priv_data;
+    int ret;
+
+    if (avctx->global_quality >= 0)
+        s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA,
+                              0.0f, 100.0f);
+
+    if (avctx->compression_level < 0 || avctx->compression_level > 6) {
+        av_log(avctx, AV_LOG_WARNING, "invalid compression level: %d\n",
+               avctx->compression_level);
+        avctx->compression_level = av_clip(avctx->compression_level, 0, 6);
+    }
+
+    if (s->preset >= WEBP_PRESET_DEFAULT) {
+        ret = WebPConfigPreset(&s->config, s->preset, s->quality);
+        if (!ret)
+            return AVERROR_UNKNOWN;
+        s->lossless              = s->config.lossless;
+        s->quality               = s->config.quality;
+        avctx->compression_level = s->config.method;
+    } else {
+        ret = WebPConfigInit(&s->config);
+        if (!ret)
+            return AVERROR_UNKNOWN;
+
+        s->config.lossless = s->lossless;
+        s->config.quality  = s->quality;
+        s->config.method   = avctx->compression_level;
+
+        ret = WebPValidateConfig(&s->config);
+        if (!ret)
+            return AVERROR(EINVAL);
+    }
+
+    av_log(avctx, AV_LOG_DEBUG, "%s - quality=%.1f method=%d\n",
+           s->lossless ? "Lossless" : "Lossy", s->quality,
+           avctx->compression_level);
+
+#if HAVE_WEBP_MUX_H
+    {
+        WebPAnimEncoderOptions enc_options;
+        WebPAnimEncoderOptionsInit(&enc_options);
+        // TODO(urvang): Expose some options on command-line perhaps.
+        s->enc = WebPAnimEncoderNew(avctx->width, avctx->height, &enc_options);
+        if (!s->enc)
+            return AVERROR(EINVAL);
+        s->prev_frame_pts = -1;
+        s->done = 0;
+    }
+#endif
+
+    return 0;
+}
+
+static int libwebp_get_frame(AVCodecContext *avctx, LibWebPContext *s,
+                             const AVFrame *frame, AVFrame **alt_frame_ptr,
+                             WebPPicture **pic_ptr)
+{
+    int ret;
+    WebPPicture *pic = NULL;
+    AVFrame *alt_frame = NULL;
+
+    if (avctx->width > WEBP_MAX_DIMENSION || avctx->height > WEBP_MAX_DIMENSION) {
+        av_log(avctx, AV_LOG_ERROR, "Picture size is too large. Max is %dx%d.\n",
+               WEBP_MAX_DIMENSION, WEBP_MAX_DIMENSION);
+        return AVERROR(EINVAL);
+    }
+
+    *pic_ptr = av_malloc(sizeof(*pic));
+    pic = *pic_ptr;
+    if (!pic)
+        return AVERROR(ENOMEM);
+
+    ret = WebPPictureInit(pic);
+    if (!ret) {
+        ret = AVERROR_UNKNOWN;
+        goto end;
+    }
+    pic->width  = avctx->width;
+    pic->height = avctx->height;
+
+    if (avctx->pix_fmt == AV_PIX_FMT_RGB32) {
+        if (!s->lossless) {
+            /* libwebp will automatically convert RGB input to YUV when
+               encoding lossy. */
+            if (!s->conversion_warning) {
+                av_log(avctx, AV_LOG_WARNING,
+                       "Using libwebp for RGB-to-YUV conversion. You may want "
+                       "to consider passing in YUV instead for lossy "
+                       "encoding.\n");
+                s->conversion_warning = 1;
+            }
+        }
+        pic->use_argb    = 1;
+        pic->argb        = (uint32_t *)frame->data[0];
+        pic->argb_stride = frame->linesize[0] / 4;
+    } else {
+        if (frame->linesize[1] != frame->linesize[2] || s->cr_threshold) {
+            if (!s->chroma_warning && !s->cr_threshold) {
+                av_log(avctx, AV_LOG_WARNING,
+                       "Copying frame due to differing chroma linesizes.\n");
+                s->chroma_warning = 1;
+            }
+            *alt_frame_ptr = av_frame_alloc();
+            alt_frame = *alt_frame_ptr;
+            if (!alt_frame) {
+                ret = AVERROR(ENOMEM);
+                goto end;
+            }
+            alt_frame->width  = frame->width;
+            alt_frame->height = frame->height;
+            alt_frame->format = frame->format;
+            if (s->cr_threshold)
+                alt_frame->format = AV_PIX_FMT_YUVA420P;
+            ret = av_frame_get_buffer(alt_frame, 32);
+            if (ret < 0)
+                goto end;
+            alt_frame->format = frame->format;
+            av_frame_copy(alt_frame, frame);
+            frame = alt_frame;
+            if (s->cr_threshold) {
+                int x,y, x2, y2, p;
+                int bs = s->cr_size;
+
+                if (!s->ref) {
+                    s->ref = av_frame_clone(frame);
+                    if (!s->ref) {
+                        ret = AVERROR(ENOMEM);
+                        goto end;
+                    }
+                }
+
+                alt_frame->format = AV_PIX_FMT_YUVA420P;
+                for (y = 0; y < frame->height; y+= bs) {
+                    for (x = 0; x < frame->width; x+= bs) {
+                        int skip;
+                        int sse = 0;
+                        for (p = 0; p < 3; p++) {
+                            int bs2 = bs >> !!p;
+                            int w = FF_CEIL_RSHIFT(frame->width , !!p);
+                            int h = FF_CEIL_RSHIFT(frame->height, !!p);
+                            int xs = x >> !!p;
+                            int ys = y >> !!p;
+                            for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) {
+                                for (x2 = xs; x2 < FFMIN(xs + bs2, w); x2++) {
+                                    int diff =  frame->data[p][frame->linesize[p] * y2 + x2]
+                                              -s->ref->data[p][frame->linesize[p] * y2 + x2];
+                                    sse += diff*diff;
+                                }
+                            }
+                        }
+                        skip = sse < s->cr_threshold && frame->data[3] != s->ref->data[3];
+                        if (!skip)
+                            for (p = 0; p < 3; p++) {
+                                int bs2 = bs >> !!p;
+                                int w = FF_CEIL_RSHIFT(frame->width , !!p);
+                                int h = FF_CEIL_RSHIFT(frame->height, !!p);
+                                int xs = x >> !!p;
+                                int ys = y >> !!p;
+                                for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) {
+                                    memcpy(&s->ref->data[p][frame->linesize[p] * y2 + xs],
+                                            & frame->data[p][frame->linesize[p] * y2 + xs], FFMIN(bs2, w-xs));
+                                }
+                            }
+                        for (y2 = y; y2 < FFMIN(y+bs, frame->height); y2++) {
+                            memset(&frame->data[3][frame->linesize[3] * y2 + x],
+                                    skip ? 0 : 255,
+                                    FFMIN(bs, frame->width-x));
+                        }
+                    }
+                }
+            }
+        }
+
+        pic->use_argb  = 0;
+        pic->y         = frame->data[0];
+        pic->u         = frame->data[1];
+        pic->v         = frame->data[2];
+        pic->y_stride  = frame->linesize[0];
+        pic->uv_stride = frame->linesize[1];
+        if (frame->format == AV_PIX_FMT_YUVA420P) {
+            pic->colorspace = WEBP_YUV420A;
+            pic->a          = frame->data[3];
+            pic->a_stride   = frame->linesize[3];
+            if (alt_frame)
+                WebPCleanupTransparentArea(pic);
+        } else {
+            pic->colorspace = WEBP_YUV420;
+        }
+
+        if (s->lossless) {
+            /* We do not have a way to automatically prioritize RGB over YUV
+               in automatic pixel format conversion based on whether we're
+               encoding lossless or lossy, so we do conversion with libwebp as
+               a convenience. */
+            if (!s->conversion_warning) {
+                av_log(avctx, AV_LOG_WARNING,
+                       "Using libwebp for YUV-to-RGB conversion. You may want "
+                       "to consider passing in RGB instead for lossless "
+                       "encoding.\n");
+                s->conversion_warning = 1;
+            }
+
+#if (WEBP_ENCODER_ABI_VERSION <= 0x201)
+            /* libwebp should do the conversion automatically, but there is a
+               bug that causes it to return an error instead, so a work-around
+               is required.
+               See https://code.google.com/p/webp/issues/detail?id=178 */
+            pic->memory_ = (void*)1;  /* something non-null */
+            ret = WebPPictureYUVAToARGB(pic);
+            if (!ret) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "WebPPictureYUVAToARGB() failed with error: %d\n",
+                       pic->error_code);
+                ret = libwebp_error_to_averror(pic->error_code);
+                goto end;
+            }
+            pic->memory_ = NULL;  /* restore pointer */
+#endif
+        }
+    }
+end:
+    return ret;
 }
 
 static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                                 const AVFrame *frame, int *got_packet)
 {
     LibWebPContext *s  = avctx->priv_data;
+    int ret;
+
+#if HAVE_WEBP_MUX_H
+    if (!frame) {
+        if (s->done) {  // Second flush: return empty package to denote finish.
+            *got_packet = 0;
+            return 0;
+        } else {  // First flush: assemble bitstream and return it.
+            WebPData assembled_data = { 0 };
+            ret = WebPAnimEncoderAssemble(s->enc, &assembled_data);
+            if (ret) {
+                ret = ff_alloc_packet(pkt, assembled_data.size);
+                if (ret < 0)
+                    return ret;
+                memcpy(pkt->data, assembled_data.bytes, assembled_data.size);
+                s->done = 1;
+                pkt->flags |= AV_PKT_FLAG_KEY;
+                pkt->pts = pkt->dts = s->prev_frame_pts + 1;
+                *got_packet = 1;
+                return 0;
+            } else {
+                av_log(s, AV_LOG_ERROR,
+                       "WebPAnimEncoderAssemble() failed with error: %d\n",
+                       VP8_ENC_ERROR_OUT_OF_MEMORY);
+                return AVERROR(ENOMEM);
+            }
+        }
+    } else {
+        int timestamp_ms;
+        WebPPicture *pic = NULL;
+        AVFrame *alt_frame = NULL;
+        ret = libwebp_get_frame(avctx, s, frame, &alt_frame, &pic);
+        if (ret < 0)
+            goto end;
+
+        timestamp_ms =
+            avctx->time_base.num * frame->pts * 1000 / avctx->time_base.den;
+        ret = WebPAnimEncoderAdd(s->enc, pic, timestamp_ms, &s->config);
+        if (!ret) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "Encoding WebP frame failed with error: %d\n",
+                   pic->error_code);
+            ret = libwebp_error_to_averror(pic->error_code);
+            goto end;
+        }
+
+        pkt->pts = pkt->dts = frame->pts;
+        s->prev_frame_pts = frame->pts;  // Save for next frame.
+        ret = 0;
+        *got_packet = 1;
+
+end:
+        WebPPictureFree(pic);
+        av_freep(&pic);
+        av_frame_free(&alt_frame);
+        return ret;
+    }
+
+#else
     WebPPicture *pic = NULL;
     AVFrame *alt_frame = NULL;
     WebPMemoryWriter mw = { 0 };
 
-    int ret = ff_libwebp_get_frame(avctx, s, frame, &alt_frame, &pic);
-    if (ret < 0)
+    if ((ret = libwebp_get_frame(avctx, s, frame, &alt_frame, &pic)) < 0)
         goto end;
 
     WebPMemoryWriterInit(&mw);
@@ -53,7 +373,7 @@ static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     if (!ret) {
         av_log(avctx, AV_LOG_ERROR, "WebPEncode() failed with error: %d\n",
                pic->error_code);
-        ret = ff_libwebp_error_to_averror(pic->error_code);
+        ret = libwebp_error_to_averror(pic->error_code);
         goto end;
     }
 
@@ -76,16 +396,44 @@ end:
     av_frame_free(&alt_frame);
 
     return ret;
+#endif
 }
 
 static int libwebp_encode_close(AVCodecContext *avctx)
 {
-    LibWebPContextCommon *s  = avctx->priv_data;
+    LibWebPContext *s  = avctx->priv_data;
     av_frame_free(&s->ref);
+#if HAVE_WEBP_MUX_H
+    WebPAnimEncoderDelete(s->enc);
+#endif
 
     return 0;
 }
 
+#define OFFSET(x) offsetof(LibWebPContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    { "lossless",   "Use lossless mode",       OFFSET(lossless), AV_OPT_TYPE_INT,   { .i64 =  0 },  0, 1,                           VE           },
+    { "preset",     "Configuration preset",    OFFSET(preset),   AV_OPT_TYPE_INT,   { .i64 = -1 }, -1, WEBP_PRESET_TEXT,            VE, "preset" },
+    { "none",       "do not use a preset",                              0, AV_OPT_TYPE_CONST, { .i64 = -1                  }, 0, 0, VE, "preset" },
+    { "default",    "default preset",                                   0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DEFAULT }, 0, 0, VE, "preset" },
+    { "picture",    "digital picture, like portrait, inner shot",       0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PICTURE }, 0, 0, VE, "preset" },
+    { "photo",      "outdoor photograph, with natural lighting",        0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PHOTO   }, 0, 0, VE, "preset" },
+    { "drawing",    "hand or line drawing, with high-contrast details", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DRAWING }, 0, 0, VE, "preset" },
+    { "icon",       "small-sized colorful images",                      0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_ICON    }, 0, 0, VE, "preset" },
+    { "text",       "text-like",                                        0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_TEXT    }, 0, 0, VE, "preset" },
+    { "cr_threshold","Conditional replenishment threshold",     OFFSET(cr_threshold), AV_OPT_TYPE_INT, { .i64 =  0  },  0, INT_MAX, VE           },
+    { "cr_size"     ,"Conditional replenishment block size",    OFFSET(cr_size)     , AV_OPT_TYPE_INT, { .i64 =  16 },  0, 256,     VE           },
+    { "quality"     ,"Quality",                OFFSET(quality),  AV_OPT_TYPE_FLOAT, { .dbl =  75 }, 0, 100,                         VE           },
+    { NULL },
+};
+
+static const AVCodecDefault libwebp_defaults[] = {
+    { "compression_level",  "4"  },
+    { "global_quality",     "-1" },
+    { NULL },
+};
+
 static const AVClass class = {
     .class_name = "libwebp",
     .item_name  = av_default_item_name,
@@ -102,6 +450,9 @@ AVCodec ff_libwebp_encoder = {
     .init           = libwebp_encode_init,
     .encode2        = libwebp_encode_frame,
     .close          = libwebp_encode_close,
+#if HAVE_WEBP_MUX_H
+    .capabilities   = CODEC_CAP_DELAY,
+#endif
     .pix_fmts       = (const enum AVPixelFormat[]) {
         AV_PIX_FMT_RGB32,
         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
diff --git a/libavcodec/libwebpenc_animencoder.c b/libavcodec/libwebpenc_animencoder.c
deleted file mode 100644
index e958201..0000000
--- a/libavcodec/libwebpenc_animencoder.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * WebP encoding support via libwebp
- * Copyright (c) 2015 Urvang Joshi
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * WebP encoder using libwebp (WebPAnimEncoder API)
- */
-
-#include "config.h"
-#include "libwebpenc_common.h"
-
-#include <webp/mux.h>
-
-typedef struct LibWebPAnimContext {
-    LibWebPContextCommon cc;
-    WebPAnimEncoder *enc;     // the main AnimEncoder object
-    int64_t prev_frame_pts;   // pts of the previously encoded frame.
-    int done;                 // If true, we have assembled the bitstream already
-} LibWebPAnimContext;
-
-static av_cold int libwebp_anim_encode_init(AVCodecContext *avctx)
-{
-    int ret = ff_libwebp_encode_init_common(avctx);
-    if (!ret) {
-        LibWebPAnimContext *s = avctx->priv_data;
-        WebPAnimEncoderOptions enc_options;
-        WebPAnimEncoderOptionsInit(&enc_options);
-        // TODO(urvang): Expose some options on command-line perhaps.
-        s->enc = WebPAnimEncoderNew(avctx->width, avctx->height, &enc_options);
-        if (!s->enc)
-            return AVERROR(EINVAL);
-        s->prev_frame_pts = -1;
-        s->done = 0;
-    }
-    return ret;
-}
-
-static int libwebp_anim_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
-                                     const AVFrame *frame, int *got_packet) {
-    LibWebPAnimContext *s = avctx->priv_data;
-    int ret;
-
-    if (!frame) {
-        if (s->done) {  // Second flush: return empty package to denote finish.
-            *got_packet = 0;
-            return 0;
-        } else {  // First flush: assemble bitstream and return it.
-            WebPData assembled_data = { 0 };
-            ret = WebPAnimEncoderAssemble(s->enc, &assembled_data);
-            if (ret) {
-                ret = ff_alloc_packet(pkt, assembled_data.size);
-                if (ret < 0)
-                    return ret;
-                memcpy(pkt->data, assembled_data.bytes, assembled_data.size);
-                s->done = 1;
-                pkt->flags |= AV_PKT_FLAG_KEY;
-                pkt->pts = pkt->dts = s->prev_frame_pts + 1;
-                *got_packet = 1;
-                return 0;
-            } else {
-                av_log(s, AV_LOG_ERROR,
-                       "WebPAnimEncoderAssemble() failed with error: %d\n",
-                       VP8_ENC_ERROR_OUT_OF_MEMORY);
-                return AVERROR(ENOMEM);
-            }
-        }
-    } else {
-        int timestamp_ms;
-        WebPPicture *pic = NULL;
-        AVFrame *alt_frame = NULL;
-        ret = ff_libwebp_get_frame(avctx, &s->cc, frame, &alt_frame, &pic);
-        if (ret < 0)
-            goto end;
-
-        timestamp_ms =
-            avctx->time_base.num * frame->pts * 1000 / avctx->time_base.den;
-        ret = WebPAnimEncoderAdd(s->enc, pic, timestamp_ms, &s->cc.config);
-        if (!ret) {
-                av_log(avctx, AV_LOG_ERROR,
-                       "Encoding WebP frame failed with error: %d\n",
-                   pic->error_code);
-            ret = ff_libwebp_error_to_averror(pic->error_code);
-            goto end;
-        }
-
-        pkt->pts = pkt->dts = frame->pts;
-        s->prev_frame_pts = frame->pts;  // Save for next frame.
-        ret = 0;
-        *got_packet = 1;
-
-end:
-        WebPPictureFree(pic);
-        av_freep(&pic);
-        av_frame_free(&alt_frame);
-        return ret;
-    }
-}
-
-static int libwebp_anim_encode_close(AVCodecContext *avctx)
-{
-    LibWebPAnimContext *s = avctx->priv_data;
-    av_frame_free(&s->cc.ref);
-    WebPAnimEncoderDelete(s->enc);
-
-    return 0;
-}
-
-static const AVClass class = {
-    .class_name = "libwebp_anim",
-    .item_name  = av_default_item_name,
-    .option     = options,
-    .version    = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_libwebp_anim_encoder = {
-    .name           = "libwebp_anim",
-    .long_name      = NULL_IF_CONFIG_SMALL("libwebp WebP image"),
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = AV_CODEC_ID_WEBP,
-    .priv_data_size = sizeof(LibWebPAnimContext),
-    .init           = libwebp_anim_encode_init,
-    .encode2        = libwebp_anim_encode_frame,
-    .close          = libwebp_anim_encode_close,
-    .capabilities   = CODEC_CAP_DELAY,
-    .pix_fmts       = (const enum AVPixelFormat[]) {
-        AV_PIX_FMT_RGB32,
-        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
-        AV_PIX_FMT_NONE
-    },
-    .priv_class     = &class,
-    .defaults       = libwebp_defaults,
-};
diff --git a/libavcodec/libwebpenc_common.c b/libavcodec/libwebpenc_common.c
deleted file mode 100644
index a76b6da..0000000
--- a/libavcodec/libwebpenc_common.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * WebP encoding support via libwebp
- * Copyright (c) 2013 Justin Ruggles <justin.ruggles at gmail.com>
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * WebP encoder using libwebp: common structs and methods.
- */
-
-#include "libwebpenc_common.h"
-
-int ff_libwebp_error_to_averror(int err)
-{
-    switch (err) {
-    case VP8_ENC_ERROR_OUT_OF_MEMORY:
-    case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
-        return AVERROR(ENOMEM);
-    case VP8_ENC_ERROR_NULL_PARAMETER:
-    case VP8_ENC_ERROR_INVALID_CONFIGURATION:
-    case VP8_ENC_ERROR_BAD_DIMENSION:
-        return AVERROR(EINVAL);
-    }
-    return AVERROR_UNKNOWN;
-}
-
-av_cold int ff_libwebp_encode_init_common(AVCodecContext *avctx)
-{
-    LibWebPContextCommon *s = avctx->priv_data;
-    int ret;
-
-    if (avctx->global_quality >= 0)
-        s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA,
-                              0.0f, 100.0f);
-
-    if (avctx->compression_level < 0 || avctx->compression_level > 6) {
-        av_log(avctx, AV_LOG_WARNING, "invalid compression level: %d\n",
-               avctx->compression_level);
-        avctx->compression_level = av_clip(avctx->compression_level, 0, 6);
-    }
-
-    if (s->preset >= WEBP_PRESET_DEFAULT) {
-        ret = WebPConfigPreset(&s->config, s->preset, s->quality);
-        if (!ret)
-            return AVERROR_UNKNOWN;
-        s->lossless              = s->config.lossless;
-        s->quality               = s->config.quality;
-        avctx->compression_level = s->config.method;
-    } else {
-        ret = WebPConfigInit(&s->config);
-        if (!ret)
-            return AVERROR_UNKNOWN;
-
-        s->config.lossless = s->lossless;
-        s->config.quality  = s->quality;
-        s->config.method   = avctx->compression_level;
-
-        ret = WebPValidateConfig(&s->config);
-        if (!ret)
-            return AVERROR(EINVAL);
-    }
-
-    av_log(avctx, AV_LOG_DEBUG, "%s - quality=%.1f method=%d\n",
-           s->lossless ? "Lossless" : "Lossy", s->quality,
-           avctx->compression_level);
-
-    return 0;
-}
-
-int ff_libwebp_get_frame(AVCodecContext *avctx, LibWebPContextCommon *s,
-                         const AVFrame *frame, AVFrame **alt_frame_ptr,
-                         WebPPicture **pic_ptr) {
-    int ret;
-    WebPPicture *pic = NULL;
-    AVFrame *alt_frame = NULL;
-
-    if (avctx->width > WEBP_MAX_DIMENSION || avctx->height > WEBP_MAX_DIMENSION) {
-        av_log(avctx, AV_LOG_ERROR, "Picture size is too large. Max is %dx%d.\n",
-               WEBP_MAX_DIMENSION, WEBP_MAX_DIMENSION);
-        return AVERROR(EINVAL);
-    }
-
-    *pic_ptr = av_malloc(sizeof(*pic));
-    pic = *pic_ptr;
-    if (!pic)
-        return AVERROR(ENOMEM);
-
-    ret = WebPPictureInit(pic);
-    if (!ret) {
-        ret = AVERROR_UNKNOWN;
-        goto end;
-    }
-    pic->width  = avctx->width;
-    pic->height = avctx->height;
-
-    if (avctx->pix_fmt == AV_PIX_FMT_RGB32) {
-        if (!s->lossless) {
-            /* libwebp will automatically convert RGB input to YUV when
-               encoding lossy. */
-            if (!s->conversion_warning) {
-                av_log(avctx, AV_LOG_WARNING,
-                       "Using libwebp for RGB-to-YUV conversion. You may want "
-                       "to consider passing in YUV instead for lossy "
-                       "encoding.\n");
-                s->conversion_warning = 1;
-            }
-        }
-        pic->use_argb    = 1;
-        pic->argb        = (uint32_t *)frame->data[0];
-        pic->argb_stride = frame->linesize[0] / 4;
-    } else {
-        if (frame->linesize[1] != frame->linesize[2] || s->cr_threshold) {
-            if (!s->chroma_warning && !s->cr_threshold) {
-                av_log(avctx, AV_LOG_WARNING,
-                       "Copying frame due to differing chroma linesizes.\n");
-                s->chroma_warning = 1;
-            }
-            *alt_frame_ptr = av_frame_alloc();
-            alt_frame = *alt_frame_ptr;
-            if (!alt_frame) {
-                ret = AVERROR(ENOMEM);
-                goto end;
-            }
-            alt_frame->width  = frame->width;
-            alt_frame->height = frame->height;
-            alt_frame->format = frame->format;
-            if (s->cr_threshold)
-                alt_frame->format = AV_PIX_FMT_YUVA420P;
-            ret = av_frame_get_buffer(alt_frame, 32);
-            if (ret < 0)
-                goto end;
-            alt_frame->format = frame->format;
-            av_frame_copy(alt_frame, frame);
-            frame = alt_frame;
-            if (s->cr_threshold) {
-                int x,y, x2, y2, p;
-                int bs = s->cr_size;
-
-                if (!s->ref) {
-                    s->ref = av_frame_clone(frame);
-                    if (!s->ref) {
-                        ret = AVERROR(ENOMEM);
-                        goto end;
-                    }
-                }
-
-                alt_frame->format = AV_PIX_FMT_YUVA420P;
-                for (y = 0; y < frame->height; y+= bs) {
-                    for (x = 0; x < frame->width; x+= bs) {
-                        int skip;
-                        int sse = 0;
-                        for (p = 0; p < 3; p++) {
-                            int bs2 = bs >> !!p;
-                            int w = FF_CEIL_RSHIFT(frame->width , !!p);
-                            int h = FF_CEIL_RSHIFT(frame->height, !!p);
-                            int xs = x >> !!p;
-                            int ys = y >> !!p;
-                            for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) {
-                                for (x2 = xs; x2 < FFMIN(xs + bs2, w); x2++) {
-                                    int diff =  frame->data[p][frame->linesize[p] * y2 + x2]
-                                              -s->ref->data[p][frame->linesize[p] * y2 + x2];
-                                    sse += diff*diff;
-                                }
-                            }
-                        }
-                        skip = sse < s->cr_threshold && frame->data[3] != s->ref->data[3];
-                        if (!skip)
-                            for (p = 0; p < 3; p++) {
-                                int bs2 = bs >> !!p;
-                                int w = FF_CEIL_RSHIFT(frame->width , !!p);
-                                int h = FF_CEIL_RSHIFT(frame->height, !!p);
-                                int xs = x >> !!p;
-                                int ys = y >> !!p;
-                                for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) {
-                                    memcpy(&s->ref->data[p][frame->linesize[p] * y2 + xs],
-                                            & frame->data[p][frame->linesize[p] * y2 + xs], FFMIN(bs2, w-xs));
-                                }
-                            }
-                        for (y2 = y; y2 < FFMIN(y+bs, frame->height); y2++) {
-                            memset(&frame->data[3][frame->linesize[3] * y2 + x],
-                                    skip ? 0 : 255,
-                                    FFMIN(bs, frame->width-x));
-                        }
-                    }
-                }
-            }
-        }
-
-        pic->use_argb  = 0;
-        pic->y         = frame->data[0];
-        pic->u         = frame->data[1];
-        pic->v         = frame->data[2];
-        pic->y_stride  = frame->linesize[0];
-        pic->uv_stride = frame->linesize[1];
-        if (frame->format == AV_PIX_FMT_YUVA420P) {
-            pic->colorspace = WEBP_YUV420A;
-            pic->a          = frame->data[3];
-            pic->a_stride   = frame->linesize[3];
-            if (alt_frame)
-                WebPCleanupTransparentArea(pic);
-        } else {
-            pic->colorspace = WEBP_YUV420;
-        }
-
-        if (s->lossless) {
-            /* We do not have a way to automatically prioritize RGB over YUV
-               in automatic pixel format conversion based on whether we're
-               encoding lossless or lossy, so we do conversion with libwebp as
-               a convenience. */
-            if (!s->conversion_warning) {
-                av_log(avctx, AV_LOG_WARNING,
-                       "Using libwebp for YUV-to-RGB conversion. You may want "
-                       "to consider passing in RGB instead for lossless "
-                       "encoding.\n");
-                s->conversion_warning = 1;
-            }
-
-#if (WEBP_ENCODER_ABI_VERSION <= 0x201)
-            /* libwebp should do the conversion automatically, but there is a
-               bug that causes it to return an error instead, so a work-around
-               is required.
-               See https://code.google.com/p/webp/issues/detail?id=178 */
-            pic->memory_ = (void*)1;  /* something non-null */
-            ret = WebPPictureYUVAToARGB(pic);
-            if (!ret) {
-                av_log(avctx, AV_LOG_ERROR,
-                       "WebPPictureYUVAToARGB() failed with error: %d\n",
-                       pic->error_code);
-                ret = libwebp_error_to_averror(pic->error_code);
-                goto end;
-            }
-            pic->memory_ = NULL;  /* restore pointer */
-#endif
-        }
-    }
-end:
-    return ret;
-}
diff --git a/libavcodec/libwebpenc_common.h b/libavcodec/libwebpenc_common.h
deleted file mode 100644
index e74e579..0000000
--- a/libavcodec/libwebpenc_common.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * WebP encoding support via libwebp
- * Copyright (c) 2013 Justin Ruggles <justin.ruggles at gmail.com>
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * WebP encoder using libwebp: common structs and methods.
- */
-
-#ifndef AVCODEC_LIBWEBPENC_COMMON_H
-#define AVCODEC_LIBWEBPENC_COMMON_H
-
-#include <webp/encode.h>
-
-#include "libavutil/common.h"
-#include "libavutil/frame.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/opt.h"
-#include "avcodec.h"
-#include "internal.h"
-
-typedef struct LibWebPContextCommon {
-    AVClass *class;         // class for AVOptions
-    float quality;          // lossy quality 0 - 100
-    int lossless;           // use lossless encoding
-    int preset;             // configuration preset
-    int chroma_warning;     // chroma linesize mismatch warning has been printed
-    int conversion_warning; // pixel format conversion warning has been printed
-    WebPConfig config;      // libwebp configuration
-    AVFrame *ref;
-    int cr_size;
-    int cr_threshold;
-} LibWebPContextCommon;
-
-int ff_libwebp_error_to_averror(int err);
-
-av_cold int ff_libwebp_encode_init_common(AVCodecContext *avctx);
-
-int ff_libwebp_get_frame(AVCodecContext *avctx, LibWebPContextCommon *s,
-                         const AVFrame *frame, AVFrame **alt_frame_ptr,
-                         WebPPicture **pic_ptr);
-
-#define OFFSET(x) offsetof(LibWebPContextCommon, x)
-#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
-static const AVOption options[] = {
-    { "lossless",   "Use lossless mode",       OFFSET(lossless), AV_OPT_TYPE_INT,   { .i64 =  0 },  0, 1,                           VE           },
-    { "preset",     "Configuration preset",    OFFSET(preset),   AV_OPT_TYPE_INT,   { .i64 = -1 }, -1, WEBP_PRESET_TEXT,            VE, "preset" },
-    { "none",       "do not use a preset",                              0, AV_OPT_TYPE_CONST, { .i64 = -1                  }, 0, 0, VE, "preset" },
-    { "default",    "default preset",                                   0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DEFAULT }, 0, 0, VE, "preset" },
-    { "picture",    "digital picture, like portrait, inner shot",       0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PICTURE }, 0, 0, VE, "preset" },
-    { "photo",      "outdoor photograph, with natural lighting",        0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PHOTO   }, 0, 0, VE, "preset" },
-    { "drawing",    "hand or line drawing, with high-contrast details", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DRAWING }, 0, 0, VE, "preset" },
-    { "icon",       "small-sized colorful images",                      0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_ICON    }, 0, 0, VE, "preset" },
-    { "text",       "text-like",                                        0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_TEXT    }, 0, 0, VE, "preset" },
-    { "cr_threshold","Conditional replenishment threshold",     OFFSET(cr_threshold), AV_OPT_TYPE_INT, { .i64 =  0  },  0, INT_MAX, VE           },
-    { "cr_size"     ,"Conditional replenishment block size",    OFFSET(cr_size)     , AV_OPT_TYPE_INT, { .i64 =  16 },  0, 256,     VE           },
-    { "quality"     ,"Quality",                OFFSET(quality),  AV_OPT_TYPE_FLOAT, { .dbl =  75 }, 0, 100,                         VE           },
-    { NULL },
-};
-
-static const AVCodecDefault libwebp_defaults[] = {
-    { "compression_level",  "4"  },
-    { "global_quality",     "-1" },
-    { NULL },
-};
-
-#endif /* AVCODEC_LIBWEBPENC_COMMON_H */
-- 
2.4.1



More information about the ffmpeg-devel mailing list