diff --git a/Changelog b/Changelog index 667dd2961b..e9e925af5d 100644 --- a/Changelog +++ b/Changelog @@ -21,6 +21,7 @@ version : - 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: diff --git a/configure b/configure index a02fe4a57c..8b9c3e2217 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 " @@ -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"; } } && diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 789a6d0fa5..02aa61e682 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -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 diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 25529628da..fe79d0bb3b 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -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 index 0000000000..860973e7a3 --- /dev/null +++ b/libavcodec/libwebpenc_animencoder.c @@ -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 +#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, +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index dd47af0f81..b9f99d7181 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -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, \