WebP encoder: use WebPAnimEncoder API when available.

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>
This commit is contained in:
Urvang Joshi 2015-05-19 18:04:07 -07:00 committed by Michael Niedermayer
parent ebb0ca3d70
commit 02cf59f3a6
6 changed files with 159 additions and 3 deletions

View File

@ -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:

9
configure vendored
View File

@ -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"; } } &&

View 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

View 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);

View File

@ -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,
};

View 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, \