WebP encoder: use WebPAnimEncoder API when available.
authorUrvang Joshi <urvang@google.com>
Wed, 20 May 2015 01:04:07 +0000 (18:04 -0700)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 23 May 2015 01:31:28 +0000 (03:31 +0200)
WebPAnimEncoder API is a combination of encoder (WebPEncoder) and muxer
(WebPMux). It performs several optimizations to make it more efficient
than the combination of WebPEncode() and native ffmpeg muxer.

When WebPAnimEncoder API is used:
- In the encoder layer: we use WebPAnimEncoderAdd() instead of
  WebPEncode().
- The muxer layer: works like a raw muxer.

On the other hand, when WebPAnimEncoder API isn't available, the old code is
used as it is:
- In the codec layer: WebPEncode is used to encode each frame
- In the muxer layer:  ffmpeg muxer is used

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Changelog
configure
libavcodec/Makefile
libavcodec/allcodecs.c
libavcodec/libwebpenc_animencoder.c [new file with mode: 0644]
libavcodec/version.h

index 667dd29..e9e925a 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -21,6 +21,7 @@ version <next>:
 - Automatically rotate videos based on metadata in ffmpeg
 - improved Quickdraw compatibility
 - VP9 high bit-depth and extended colorspaces decoding support
+- WebPAnimEncoder API when available for encoding and muxing WebP
 
 
 version 2.6:
index a02fe4a..8b9c3e2 100755 (executable)
--- a/configure
+++ b/configure
@@ -1695,6 +1695,7 @@ HEADERS_LIST="
     udplite_h
     unistd_h
     valgrind_valgrind_h
+    webp_mux_h
     windows_h
     winsock2_h
 "
@@ -1897,6 +1898,7 @@ CONFIG_EXTRA="
     intrax8
     jpegtables
     lgplv3
+    libwebp_anim
     llauddsp
     llviddsp
     lpc
@@ -2451,6 +2453,7 @@ libvpx_vp9_decoder_deps="libvpx"
 libvpx_vp9_encoder_deps="libvpx"
 libwavpack_encoder_deps="libwavpack"
 libwebp_encoder_deps="libwebp"
+libwebp_anim_encoder_deps="libwebp"
 libx264_encoder_deps="libx264"
 libx264rgb_encoder_deps="libx264"
 libx264rgb_encoder_select="libx264_encoder"
@@ -5102,7 +5105,11 @@ 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           && require_pkg_config "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion
+enabled libwebp           && {
+    enabled libwebp_encoder && require_pkg_config "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion;
+    enabled libwebp_anim_encoder && require_pkg_config "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion &&
+                                    { use_pkg_config "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit ||
+                                      { disable libwebp_anim_encoder && warn "using libwebp without libwebpmux"; } } }
 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"; } } &&
index 789a6d0..02aa61e 100644 (file)
@@ -784,6 +784,7 @@ 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_LIBX264_ENCODER)            += libx264.o
 OBJS-$(CONFIG_LIBX265_ENCODER)            += libx265.o
 OBJS-$(CONFIG_LIBXAVS_ENCODER)            += libxavs.o
index 2552962..fe79d0b 100644 (file)
@@ -540,6 +540,7 @@ 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_animencoder.c b/libavcodec/libwebpenc_animencoder.c
new file mode 100644 (file)
index 0000000..860973e
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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"
+
+#if HAVE_WEBP_MUX_H
+#include <webp/mux.h>
+#endif
+
+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)
+{
+    int ret = ff_libwebp_encode_close_common(avctx);
+    if (!ret) {
+        LibWebPAnimContext *s = avctx->priv_data;
+        WebPAnimEncoderDelete(s->enc);
+    }
+    return ret;
+}
+
+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,
+};
index dd47af0..b9f99d7 100644 (file)
@@ -29,8 +29,8 @@
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR 56
-#define LIBAVCODEC_VERSION_MINOR  39
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MINOR  40
+#define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \