From 7700501e81b5b2eb092d93273d3849b19348b812 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Kempf Date: Mon, 7 Jun 2010 22:16:22 +0200 Subject: [PATCH] Contribs: take libvpx GIT and not the tarballs Because now the license is ok. And update the patches on ffmpeg --- extras/contrib/src/Makefile | 31 +- .../contrib/src/Patches/ffmpeg-libvpx.patch | 1371 ----------------- 2 files changed, 15 insertions(+), 1387 deletions(-) delete mode 100644 extras/contrib/src/Patches/ffmpeg-libvpx.patch diff --git a/extras/contrib/src/Makefile b/extras/contrib/src/Makefile index 73533feebf..9e1c978ca3 100644 --- a/extras/contrib/src/Makefile +++ b/extras/contrib/src/Makefile @@ -911,18 +911,18 @@ DISTCLEAN_PKG += faad2-$(FAAD2_VERSION).tar.gz # libvp8 # *************************************************************************** -libvpx-$(VPX_VERSION).tar.bz2: - $(WGET) $(VPX_URL) +#ibvpx-$(VPX_VERSION).tar.bz2: +#$(WGET) $(VPX_URL) -vpx: libvpx-$(VPX_VERSION).tar.bz2 - $(EXTRACT_BZ2) - patch -p0 < Patches/libvpx-cross.patch +libvpx: + $(GIT) clone git://review.webmproject.org/libvpx.git ifdef HAVE_DARWIN_OS patch -p0 < Patches/libvpx-darwin.patch endif ifdef HAVE_WIN32 VPX_TARGET=x86-win32-gcc +CROSS= else ifdef HAVE_DARWIN_OS ifdef HAVE_DARWIN_64 @@ -939,16 +939,16 @@ VPX_TARGET=FIXME endif endif -.vpx: vpx - (cd $<; ./configure --target=$(VPX_TARGET) --disable-install-bins --disable-install-srcs --disable-install-libs --disable-examples && XCC=$(CC) XNM=$(NM) XSTRIP=$(STRIP) make && make install) - (cd $<; cp vp8/*.h vpx_codec/*.h vpx_ports/*.h $(PREFIX)/include) # Of course, why the hell would one expect it to be listed or in make install? - rm $(PREFIX)/include/config.h +.libvpx: libvpx + (cd $<; CROSS=$(HOST)- ./configure --target=$(VPX_TARGET) --disable-install-bins --disable-install-srcs --disable-install-libs --disable-examples && make && make install) + (rm -rf $(PREFIX)/include/vpx/ && mkdir $(PREFIX)/include/vpx/; cd $< && cp vpx/*.h vpx_ports/*.h $(PREFIX)/include/vpx/) # Of course, why the hell would one expect it to be listed or in make install? + rm $(PREFIX)/include/vpx/config.h (cd $<; $(RANLIB) libvpx.a && cp libvpx.a $(PREFIX)/lib) # Of course, why the hell would one expect it to be listed or in make install? touch $@ -CLEAN_FILE += .vpx -CLEAN_PKG += vpx -DISTCLEAN_PKG += libvpx-$(VPX_VERSION).tar.bz2 +CLEAN_FILE += .libvpx +CLEAN_PKG += libvpx +#DISTCLEAN_PKG += libvpx-$(VPX_VERSION).tar.bz2 # *************************************************************************** # lame @@ -1068,7 +1068,6 @@ else ffmpeg: endif $(SVN) co $(FFMPEG_SVN) ffmpeg - (cd ffmpeg; patch -p0 < ../Patches/ffmpeg-libvpx.patch;) ifdef HAVE_ISA_THUMB patch -p0 < Patches/ffmpeg-avcodec-no-thumb.patch endif @@ -1117,10 +1116,10 @@ else ifdef HAVE_UCLIBC .ffmpeg: ffmpeg else -.ffmpeg: ffmpeg .lame .gsm +.ffmpeg: ffmpeg .lame .gsm .libvpx endif endif - (cd $<; $(HOSTCC) ./configure --prefix=$(PREFIX) --extra-cflags="$(CFLAGS) $(FFMPEG_CFLAGS)" --extra-ldflags="$(LDFLAGS)" $(FFMPEGCONF) --disable-shared --enable-static && make && make install-libs install-headers) + (cd $<; $(HOSTCC) ./configure --prefix=$(PREFIX) --extra-cflags="$(CFLAGS) $(FFMPEG_CFLAGS) -DHAVE_STDINT_H" --extra-ldflags="$(LDFLAGS)" $(FFMPEGCONF) --disable-shared --enable-static && make && make install-libs install-headers) touch $@ ifdef SVN @@ -1323,7 +1322,7 @@ goom$(GOOM2k4_VERSION).tar.gz: goom: goom$(GOOM2k4_VERSION).tar.gz $(EXTRACT_GZ) ifdef HAVE_WIN32 - (cd $@; dos2unix configure.in) + (cd $@; fromdos configure.in) patch -p0 < Patches/goom2k4-0-win32.patch else patch -p0 < Patches/goom2k4-0-mmx.patch diff --git a/extras/contrib/src/Patches/ffmpeg-libvpx.patch b/extras/contrib/src/Patches/ffmpeg-libvpx.patch deleted file mode 100644 index df84efb37f..0000000000 --- a/extras/contrib/src/Patches/ffmpeg-libvpx.patch +++ /dev/null @@ -1,1371 +0,0 @@ -Index: configure -=================================================================== ---- configure (revision 23210) -+++ configure (working copy) -@@ -183,6 +183,7 @@ External library support: - --enable-libtheora enable Theora encoding via libtheora [no] - --enable-libvorbis enable Vorbis encoding via libvorbis, - native implementation exists [no] -+ --enable-libvpx enable VP8 support via libvpx [no] - --enable-libx264 enable H.264 encoding via x264 [no] - --enable-libxvid enable Xvid encoding via xvidcore, - native MPEG-4/Xvid encoder exists [no] -@@ -927,6 +928,7 @@ CONFIG_LIST=" - libspeex - libtheora - libvorbis -+ libvpx - libx264 - libxvid - lpc -@@ -1349,6 +1351,8 @@ libschroedinger_encoder_deps="libschroed - libspeex_decoder_deps="libspeex" - libtheora_encoder_deps="libtheora" - libvorbis_encoder_deps="libvorbis" -+libvpx_decoder_deps="libvpx" -+libvpx_encoder_deps="libvpx" - libx264_encoder_deps="libx264" - libxvid_encoder_deps="libxvid" - -@@ -2617,6 +2621,9 @@ enabled libschroedinger && add_cflags $( - enabled libspeex && require libspeex speex/speex.h speex_decoder_init -lspeex - enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg - enabled libvorbis && require libvorbis vorbis/vorbisenc.h vorbis_info_init -lvorbisenc -lvorbis -logg -+enabled libvpx && add_cflags -DHAVE_STDINT_H && -+ require2 libvpx "vpx_decoder.h vp8dx.h" "vpx_codec_dec_init_ver" -lvpx && -+ require2 libvpx "vpx_encoder.h vp8cx.h" "vpx_codec_enc_init_ver" -lvpx - enabled libx264 && require libx264 x264.h x264_encoder_encode -lx264 -lm && - { check_cpp_condition x264.h "X264_BUILD >= 90" || - die "ERROR: libx264 version must be >= 0.90."; } -@@ -2886,6 +2893,7 @@ echo "libschroedinger enabled ${libsch - echo "libspeex enabled ${libspeex-no}" - echo "libtheora enabled ${libtheora-no}" - echo "libvorbis enabled ${libvorbis-no}" -+echo "libvpx enabled ${libvpx-no}" - echo "libx264 enabled ${libx264-no}" - echo "libxvid enabled ${libxvid-no}" - echo "zlib enabled ${zlib-no}" -Index: libavcodec/libvpxdec.c -=================================================================== ---- libavcodec/libvpxdec.c (revision 0) -+++ libavcodec/libvpxdec.c (revision 0) -@@ -0,0 +1,132 @@ -+/* -+ * Copyright (c) 2010, Google, Inc. -+ * -+ * 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 -+ * VP8 decoder support via libvpx -+ */ -+ -+#ifndef HAVE_STDINT_H -+# define HAVE_STDINT_H 1 -+#endif -+ -+#define VPX_CODEC_DISABLE_COMPAT 1 -+#include -+#include -+ -+#include "avcodec.h" -+ -+typedef struct VP8DecoderContext { -+ vpx_codec_ctx_t decoder; -+} VP8Context; -+ -+static av_cold int vp8_init(AVCodecContext *avctx) -+{ -+ VP8Context *ctx = avctx->priv_data; -+ const struct vpx_codec_iface *iface = &vpx_codec_vp8_dx_algo; -+ struct vpx_codec_dec_cfg deccfg = { -+ /* token partitions+1 would be a decent choice */ -+ .threads = FFMIN(avctx->thread_count, 16) -+ }; -+ -+ av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str()); -+ av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config()); -+ -+ if (vpx_codec_dec_init(&ctx->decoder, iface, &deccfg, 0) != VPX_CODEC_OK) { -+ const char *error = vpx_codec_error(&ctx->decoder); -+ av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n", -+ error); -+ return AVERROR(EINVAL); -+ } -+ -+ avctx->pix_fmt = PIX_FMT_YUV420P; -+ return 0; -+} -+ -+static int vp8_decode(AVCodecContext *avctx, -+ void *data, int *data_size, AVPacket *avpkt) -+{ -+ VP8Context *ctx = avctx->priv_data; -+ AVFrame *picture = data; -+ const void *iter = NULL; -+ vpx_image_t *img; -+ -+ /* end of stream, vp8 does no buffering */ -+ if (!avpkt->size) -+ return 0; -+ -+ if (vpx_codec_decode(&ctx->decoder, avpkt->data, avpkt->size, NULL, 0) != -+ VPX_CODEC_OK) { -+ const char *error = vpx_codec_error(&ctx->decoder); -+ const char *detail = vpx_codec_error_detail(&ctx->decoder); -+ -+ av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error); -+ if (detail) -+ av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", -+ detail); -+ return AVERROR_INVALIDDATA; -+ } -+ -+ if ((img = vpx_codec_get_frame(&ctx->decoder, &iter))) { -+ if (img->fmt != IMG_FMT_I420) { -+ av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d)\n", -+ img->fmt); -+ return AVERROR_INVALIDDATA; -+ } -+ -+ if ((int) img->d_w != avctx->width || (int) img->d_h != avctx->height) { -+ av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n", -+ avctx->width, avctx->height, img->d_w, img->d_h); -+ if (avcodec_check_dimensions(avctx, img->d_w, img->d_h)) -+ return AVERROR_INVALIDDATA; -+ avcodec_set_dimensions(avctx, img->d_w, img->d_h); -+ } -+ picture->data[0] = img->planes[0]; -+ picture->data[1] = img->planes[1]; -+ picture->data[2] = img->planes[2]; -+ picture->data[3] = NULL; -+ picture->linesize[0] = img->stride[0]; -+ picture->linesize[1] = img->stride[1]; -+ picture->linesize[2] = img->stride[2]; -+ picture->linesize[3] = 0; -+ *data_size = sizeof(AVPicture); -+ } -+ return avpkt->size; -+} -+ -+static av_cold int vp8_free(AVCodecContext *avctx) -+{ -+ VP8Context *ctx = avctx->priv_data; -+ vpx_codec_destroy(&ctx->decoder); -+ return 0; -+} -+ -+AVCodec libvpx_decoder = { -+ "libvpx", -+ AVMEDIA_TYPE_VIDEO, -+ CODEC_ID_VP8, -+ sizeof(VP8Context), -+ vp8_init, -+ NULL, /* encode */ -+ vp8_free, -+ vp8_decode, -+ 0, /* capabilities */ -+ .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"), -+}; -Index: libavcodec/options.c -=================================================================== ---- libavcodec/options.c (revision 23210) -+++ libavcodec/options.c (working copy) -@@ -414,6 +414,19 @@ static const AVOption options[]={ - {"intra_refresh", "use periodic insertion of intra blocks instead of keyframes", 0, FF_OPT_TYPE_CONST, CODEC_FLAG2_INTRA_REFRESH, INT_MIN, INT_MAX, V|E, "flags2"}, - {"crf_max", "in crf mode, prevents vbv from lowering quality beyond this point", OFFSET(crf_max), FF_OPT_TYPE_FLOAT, DEFAULT, 0, 51, V|E}, - {"log_level_offset", "set the log level offset", OFFSET(log_level_offset), FF_OPT_TYPE_INT, 0, INT_MIN, INT_MAX }, -+{"spatial_rsmpl", "Enable spatial resampling (VP8)", OFFSET(spatial_rsmpl), FF_OPT_TYPE_INT, 0, 0, 1, V|E}, -+{"spatial_rsmpl_up", "Spatial resampling up watermark, percentage of target data buffer. (VP8)", OFFSET(spatial_rsmpl_up), FF_OPT_TYPE_INT, 60, 0, 100, V|E}, -+{"spatial_rsmpl_down", "Spatial resampling down watermark, percentage of target data buffer. (VP8)", OFFSET(spatial_rsmpl_down), FF_OPT_TYPE_INT, 30, 0, 100, V|E}, -+{"vbr_bias", "Two-pass mode CBR/VBR bias, 0-100 (VP8)", OFFSET(vbr_bias), FF_OPT_TYPE_INT, 50, 0, 100, V|E}, -+{"lag", "Allow lagged encoding, given as frames (VP8)", OFFSET(lag), FF_OPT_TYPE_INT, 0, 0, INT_MAX, V|E}, -+{"sharpness", "[0-7] (VP8)", OFFSET(sharpness), FF_OPT_TYPE_INT, 0, 0, 7, V|E}, -+{"altref", "Allow use of alternate reference frame", OFFSET(altref), FF_OPT_TYPE_INT, 0, 0, 1, V|E}, -+{"ar_max_frames", "Max frames used in creating alt. ref. [0,25]", OFFSET(ar_max_frames), FF_OPT_TYPE_INT, 0, 0, 25, V|E}, -+{"ar_type", "Filter type used in creating alt. ref.", OFFSET(ar_type), FF_OPT_TYPE_INT, 0, 0, INT_MAX, V|E}, -+{"ar_strength", "Filter strength used in creating alt. ref. [0,6]", OFFSET(ar_strength), FF_OPT_TYPE_INT, 0, 0, 6, V|E}, -+{"mb_static_threshold", "", OFFSET(mb_static_threshold), FF_OPT_TYPE_INT, 800, 0, INT_MAX, V|E}, -+{"rc_opt_occupancy", "number of bits which should be kept in the rc buffer during decoding", OFFSET(rc_optimal_buffer_occupancy), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, V|E}, -+{"token_partitions", "Number of sub-streams in bitstream (1,2,4,8). Used for parallelized decoding.", OFFSET(token_partitions), FF_OPT_TYPE_INT, 1, 1, INT_MAX, V|E}, - {NULL}, - }; - -Index: libavcodec/allcodecs.c -=================================================================== ---- libavcodec/allcodecs.c (revision 23210) -+++ libavcodec/allcodecs.c (working copy) -@@ -349,6 +349,7 @@ void avcodec_register_all(void) - REGISTER_DECODER (LIBSPEEX, libspeex); - REGISTER_ENCODER (LIBTHEORA, libtheora); - REGISTER_ENCODER (LIBVORBIS, libvorbis); -+ REGISTER_ENCDEC (LIBVPX, libvpx); - REGISTER_ENCODER (LIBX264, libx264); - REGISTER_ENCODER (LIBXVID, libxvid); - -Index: libavcodec/avcodec.h -=================================================================== ---- libavcodec/avcodec.h (revision 23210) -+++ libavcodec/avcodec.h (working copy) -@@ -30,7 +30,7 @@ - #include "libavutil/avutil.h" - - #define LIBAVCODEC_VERSION_MAJOR 52 --#define LIBAVCODEC_VERSION_MINOR 68 -+#define LIBAVCODEC_VERSION_MINOR 69 - #define LIBAVCODEC_VERSION_MICRO 3 - - #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ -@@ -2659,6 +2659,160 @@ typedef struct AVCodecContext { - float crf_max; - - int log_level_offset; -+ -+ /** -+ * Enable spatial resampling -+ * -+ * Spatial resampling allows the codec to compress a lower resolution -+ * version of the frame, which is then upscaled by the encoder to the -+ * correct presentation resolution. This increases visual quality at low -+ * data rates, at the expense of CPU time on the encoder/decoder. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int spatial_rsmpl; -+ -+ /** -+ * Spatial resampling up watermark. -+ * -+ * This threshold is described as a percentage of the target data buffer. -+ * When the data buffer rises above this percentage of fullness, the -+ * encoder will step up to a higher resolution version of the frame. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int spatial_rsmpl_up; -+ -+ /** -+ * Spatial resampling down watermark. -+ * -+ * This threshold is described as a percentage of the target data buffer. -+ * When the data buffer falls below this percentage of fullness, the -+ * encoder will step down to a lower resolution version of the frame. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int spatial_rsmpl_down; -+ -+ /** -+ * Two-pass mode CBR/VBR bias. -+ * -+ * Bias, expressed on a scale of 0 to 100, for determining target size for -+ * the current frame. The value 0 indicates the optimal CBR mode value -+ * should be used. The value 100 indicates the optimal VBR mode value -+ * should be used. Values in between indicate which way the encoder should -+ * "lean." RC mode bias between CBR and VBR(0-100: 0->CBR, 100->VBR) -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int vbr_bias; -+ -+ /** -+ * Allow lagged encoding. -+ * -+ * If set, this value allows the encoder to consume a number of input -+ * frames before producing output frames. This allows the encoder to base -+ * decisions for the current frame on future frames. This does increase the -+ * latency of the encoding pipeline, so it is not appropriate in all -+ * situations (ex: realtime encoding). Half the output average output -+ * framerate is a reasonable default in other cases. -+ * -+ * Note that this is a maximum value -- the encoder may produce frames -+ * sooner than the given limit. Set this value to 0 to disable this -+ * feature. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int lag; -+ -+ /** -+ * Control sharpness preprocessing -+ * -+ * This setting does not impact any other setting and is largely a matter -+ * of personal preference. A low sharpness setting will result in fewer -+ * visible artifacts but may blur the image somewhat; a high sharpness will -+ * result in a sharper image but may result in more visible artifacts. -+ * Valid Range: [0,7] -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int sharpness; -+ -+ /** -+ * Allow encoder to automatically set and use alternate reference frame. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int altref; -+ -+ /** -+ * Set the max number of frames blurred creating the alternate reference frame. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int ar_max_frames; -+ -+ /** -+ * Set the type of filter to use for the alternate reference frame. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int ar_type; -+ -+ /** -+ * Set the filter strength for the alternate reference frame. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int ar_strength; -+ -+ /** -+ * Set the threshold for macroblocks treated as static. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int mb_static_threshold; -+ -+ /** -+ * Number of bits which should be maintained in rc buffer during decoding. -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int rc_optimal_buffer_occupancy; -+ -+ /** -+ * Number of token partitions. -+ * Valid Values: {1,2,4,8} -+ * - encoding: Set by user. -+ * - decoding: unused -+ * -+ * \attention VP8 specific -+ */ -+ int token_partitions; - } AVCodecContext; - - /** -Index: libavcodec/Makefile -=================================================================== ---- libavcodec/Makefile (revision 23210) -+++ libavcodec/Makefile (working copy) -@@ -512,6 +512,7 @@ OBJS-$(CONFIG_OGG_DEMUXER) + - dirac.o mpeg12data.o - OBJS-$(CONFIG_OGG_MUXER) += xiph.o flacdec.o flacdata.o flac.o - OBJS-$(CONFIG_RTP_MUXER) += mpegvideo.o -+OBJS-$(CONFIG_WEBM_MUXER) += xiph.o - - # external codec libraries - OBJS-$(CONFIG_LIBDIRAC_DECODER) += libdiracdec.o -@@ -536,6 +537,8 @@ OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) - OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o - OBJS-$(CONFIG_LIBTHEORA_ENCODER) += libtheoraenc.o - OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbis.o -+OBJS-$(CONFIG_LIBVPX_DECODER) += libvpxdec.o -+OBJS-$(CONFIG_LIBVPX_ENCODER) += libvpxenc.o - OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o - OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvidff.o libxvid_rc.o - -Index: libavcodec/libvpxenc.c -=================================================================== ---- libavcodec/libvpxenc.c (revision 0) -+++ libavcodec/libvpxenc.c (revision 0) -@@ -0,0 +1,506 @@ -+/* -+ * Copyright (c) 2010, Google, Inc. -+ * -+ * 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 -+ * VP8 encoder support via libvpx -+ * -+ * @par VPx SDK param./#AVCodecContext param./Assoc. cli opt {{{ -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ *
g_threadsAVCodecContext::thread_count-threads
g_lag_in_framesAVCodecContext::lag-lag
rc_target_bitrateAVCodecContext::bit_rate/1000-vb
kf_max_distAVCodecContext::gop_size-g
kf_min_distAVCodecContext::keyint_min-keyint_min
VPX_KF_FIXEDAVCodecContext::keyint_min == AVCodecContext::gop_size-keyint_min -g
rc_min_quantizer((AVCodecContext::qmin*5+1)>>2) - 1-qmin
rc_max_quantizer((AVCodecContext::qmax*5+1)>>2) - 1-qmax
rc_buf_szAVCodecContext::rc_buffer_size*1000 / AVCodecContext::bit_rate-bufsize -vb
rc_buf_initial_szAVCodecContext::rc_initial_buffer_occupancy*1000 / AVCodecContext::bit_rate-rc_init_occupancy -vb
rc_buf_optimal_szAVCodecContext::rc_optimal_buffer_occupancy*1000 / AVCodecContext::bit_rate-rc_opt_occupancy -vb
rc_dropframe_threshAVCodecContext::frame_skip_threshold-skip_threshold
rc_undershoot_pctAVCodecContext::rc_buffer_aggressivity*100-rc_buf_aggressivity
rc_overshoot_pctAVCodecContext::bit_rate_tolerance*100 / AVCodecContext::bit_rate-bt -vb
rc_resize_allowedAVCodecContext::spatial_rsmpl-spatial_rsmpl
rc_resize_up_threshAVCodecContext::spatial_rsmpl_up-spatial_rsmpl_up
rc_resize_down_threshAVCodecContext::spatial_rsmpl_down-spatial_rsmpl_down
rc_2pass_vbr_bias_pctAVCodecContext::vbr_bias-vbr_bias
rc_2pass_vbr_maxsection_pctAVCodecContext::rc_max_rate*100 / AVCodecContext::bit_rate-maxrate -vb
rc_2pass_vbr_minsection_pctAVCodecContext::rc_min_rate*100 / AVCodecContext::bit_rate-minrate -vb
VPX_CBRAVCodecContext::rc_min_rate == AVCodecContext::rc_max_rate && AVCodecContext::rc_min_rate == AVCodecContext::bit_rate-minrate -maxrate -vb
g_profileAVCodecContext::profile-profile
g_error_resilientAVCodecContext::level<0-level
VPX_DL_BEST_QUALITY(1)/VPX_DL_GOOD_QUALITY(2)/VPX_DL_REALTIME(3)#FFABS(AVCodecContext::level)/100-level
VP8E_SET_CPUUSED#FFABS(AVCodecContext::level)%%100-16-level
VP8E_SET_NOISE_SENSITIVITYAVCodecContext::noise_reduction-nr
VP8E_SET_SHARPNESSAVCodecContext::sharpness-sharpness
VP8E_SET_ENABLEAUTOALTREFAVCodecContext::altref-altref
VP8E_SET_ARNR_MAXFRAMESAVCodecContext::ar_max_frames-ar_max_frames
VP8E_SET_ARNR_TYPEAVCodecContext::ar_type-ar_type
VP8E_SET_ARNR_STRENGTHAVCodecContext::ar_strength-ar_strength
VP8E_SET_STATIC_THRESHOLDAVCodecContext::mb_static_threshold-mb_static_threshold
VP8E_SET_TOKEN_PARTITIONSAVCodecContext::token_partitions-token_partitions
}}} -+ */ -+ -+#include "avcodec.h" -+#include "libavutil/base64.h" -+ -+#ifndef HAVE_STDINT_H -+# define HAVE_STDINT_H 1 -+#endif -+#define VPX_CODEC_DISABLE_COMPAT 1 -+#include -+#include -+ -+/** -+ * Portion of #vpx_codec_cx_pkt_t from vpx_encoder.h. -+ * One encoded frame returned from the library. -+ */ -+struct FrameListData { -+ void *buf; /**< compressed data buffer */ -+ size_t sz; /**< length of compressed data */ -+ vpx_codec_pts_t pts; /**< time stamp to show frame -+ (in timebase units) */ -+ unsigned long duration; /**< duration to show frame -+ (in timebase units) */ -+ vpx_codec_frame_flags_t flags; /**< flags for this frame */ -+ struct FrameListData *next; -+}; -+ -+typedef struct VP8EncoderContext { -+ vpx_codec_ctx_t encoder; -+ vpx_image_t rawimg; -+ vpx_fixed_buf_t twopass_stats; -+ unsigned long deadline; //i.e., RT/GOOD/BEST -+ struct FrameListData* coded_frame_list; -+} VP8Context; -+ -+static int vp8_free(AVCodecContext *avctx); -+static void free_frame_list(struct FrameListData* list); -+static void free_coded_frame(struct FrameListData* cx_frame); -+static void coded_frame_add(void* list, struct FrameListData* cx_frame); -+static void log_encoder_error(AVCodecContext *avctx, const char* desc); -+static void dump_enc_cfg(AVCodecContext *avctx, const vpx_codec_enc_cfg_t* cfg); -+ -+static av_cold int vp8_init(AVCodecContext *avctx) -+{ -+ VP8Context* const ctx = avctx->priv_data; -+ vpx_codec_iface_t* const iface = &vpx_codec_vp8_cx_algo; -+ const int log_field_width = -30; -+ const unsigned int usage = 0; //should be 0 for current VP8 -+ const vpx_codec_flags_t flags = 0; -+ int cpuused = 3; -+ vpx_codec_enc_cfg_t enccfg; -+ vpx_codec_err_t res; -+ -+ av_log(avctx,AV_LOG_INFO,"%s\n",vpx_codec_version_str()); -+ av_log(avctx,AV_LOG_VERBOSE,"%s\n",vpx_codec_build_config()); -+ -+ if((res= vpx_codec_enc_config_default(iface,&enccfg,usage))!=VPX_CODEC_OK) { -+ av_log(avctx,AV_LOG_ERROR,"Failed to get config: %s\n",vpx_codec_err_to_string(res)); -+ return -1; -+ } -+ dump_enc_cfg(avctx,&enccfg); -+ -+ enccfg.g_w = avctx->width; -+ enccfg.g_h = avctx->height; -+ -+ /*With altref set an additional frame at the same pts may be produced. -+ Increasing the time_base gives the library a window to place these frames -+ ensuring strictly increasing timestamps.*/ -+ if(avctx->altref) { -+ avctx->ticks_per_frame = 2; -+ avctx->time_base = av_mul_q(avctx->time_base,(AVRational){1,avctx->ticks_per_frame}); -+ } -+ enccfg.g_timebase.num = avctx->time_base.num; -+ enccfg.g_timebase.den = avctx->time_base.den; -+ -+ enccfg.g_threads = FFMIN(avctx->thread_count,64); -+ if(avctx->flags&CODEC_FLAG_PASS1) enccfg.g_pass= VPX_RC_FIRST_PASS; -+ else if(avctx->flags&CODEC_FLAG_PASS2) enccfg.g_pass= VPX_RC_LAST_PASS; -+ else enccfg.g_pass= VPX_RC_ONE_PASS; -+ -+ enccfg.rc_resize_allowed = avctx->spatial_rsmpl; -+ enccfg.rc_resize_up_thresh = avctx->spatial_rsmpl_up; -+ enccfg.rc_resize_down_thresh = avctx->spatial_rsmpl_down; -+ enccfg.rc_dropframe_thresh = avctx->frame_skip_threshold; -+ -+ if(avctx->rc_min_rate==avctx->rc_max_rate && avctx->rc_min_rate==avctx->bit_rate) -+ enccfg.rc_end_usage = VPX_CBR; -+ enccfg.rc_target_bitrate = (unsigned int)av_rescale_rnd(avctx->bit_rate,1,1000,AV_ROUND_NEAR_INF); -+ enccfg.rc_overshoot_pct = avctx->bit_rate_tolerance*100/avctx->bit_rate; -+ -+ //convert [1,51] -> [0,63] -+ enccfg.rc_min_quantizer = ((avctx->qmin*5+1)>>2) - 1; -+ enccfg.rc_max_quantizer = ((avctx->qmax*5+1)>>2) - 1; -+ if(avctx->rc_buffer_size) -+ enccfg.rc_buf_sz = avctx->rc_buffer_size*1000/avctx->bit_rate; -+ if(avctx->rc_initial_buffer_occupancy) -+ enccfg.rc_buf_initial_sz = avctx->rc_initial_buffer_occupancy*1000/avctx->bit_rate; -+ if(avctx->rc_optimal_buffer_occupancy) -+ enccfg.rc_buf_optimal_sz = avctx->rc_optimal_buffer_occupancy*1000/avctx->bit_rate; -+ if(avctx->rc_buffer_aggressivity) -+ enccfg.rc_undershoot_pct = (unsigned int)round(avctx->rc_buffer_aggressivity*100); -+ -+ enccfg.rc_2pass_vbr_bias_pct= avctx->vbr_bias; -+ if(avctx->rc_min_rate) -+ enccfg.rc_2pass_vbr_minsection_pct = avctx->rc_min_rate*100/avctx->bit_rate; -+ if(avctx->rc_max_rate) -+ enccfg.rc_2pass_vbr_maxsection_pct = avctx->rc_max_rate*100/avctx->bit_rate; -+ -+ if(avctx->keyint_min==avctx->gop_size) enccfg.kf_mode= VPX_KF_FIXED; -+ //_enc_init() will balk if kf_min_dist is set in this case -+ if(enccfg.kf_mode!=VPX_KF_AUTO) enccfg.kf_min_dist= avctx->keyint_min; -+ enccfg.kf_max_dist = avctx->gop_size; -+ enccfg.g_lag_in_frames= avctx->lag; -+ -+ if(enccfg.g_pass==VPX_RC_FIRST_PASS) enccfg.g_lag_in_frames= 0; -+ if(enccfg.g_pass==VPX_RC_LAST_PASS) { -+ int decode_size; -+ -+ if(!avctx->stats_in) { -+ av_log(avctx,AV_LOG_ERROR,"No stats file for second pass\n"); -+ return -1; -+ } -+ -+ ctx->twopass_stats.sz = strlen(avctx->stats_in) * 3/4; -+ ctx->twopass_stats.buf = av_malloc(ctx->twopass_stats.sz); -+ if(!ctx->twopass_stats.buf) { -+ av_log(avctx,AV_LOG_ERROR,"Stat buffer alloc (%zu bytes) failed\n",ctx->twopass_stats.sz); -+ return AVERROR(ENOMEM); -+ } -+ decode_size = -+ av_base64_decode(ctx->twopass_stats.buf, avctx->stats_in, ctx->twopass_stats.sz); -+ if(decode_size<0) { -+ av_log(avctx,AV_LOG_ERROR,"Stat buffer decode failed\n"); -+ return -1; -+ } -+ -+ ctx->twopass_stats.sz = decode_size; -+ enccfg.rc_twopass_stats_in = ctx->twopass_stats; -+ } -+ -+ if(avctx->profile!=FF_PROFILE_UNKNOWN) enccfg.g_profile= avctx->profile; -+ switch(FFABS(avctx->level)/100) { -+ case 1: ctx->deadline = VPX_DL_BEST_QUALITY; break; -+ case 2: default: ctx->deadline = VPX_DL_GOOD_QUALITY; break; -+ case 3: ctx->deadline = VPX_DL_REALTIME; break; -+ } -+ av_log(avctx,AV_LOG_DEBUG,"Using deadline: %lu\n",ctx->deadline); -+ -+ if(avctx->level!=FF_LEVEL_UNKNOWN) { -+ enccfg.g_error_resilient = avctx->level<0; -+ cpuused = FFABS(avctx->level)%100-16; -+ } -+ -+ dump_enc_cfg(avctx,&enccfg); -+ /* Construct Encoder Context */ -+ res = vpx_codec_enc_init(&ctx->encoder,iface,&enccfg,flags); -+ if(res!=VPX_CODEC_OK) { log_encoder_error(avctx,"Failed to initialize encoder"); return -1; } -+ -+ //codec control failures are currently treated only as warnings -+ av_log(avctx,AV_LOG_DEBUG,"vpx_codec_control\n"); -+ #define codecctl(id,val)\ -+ do if(av_log(avctx,AV_LOG_DEBUG,"%*s%d\n",log_field_width," "#id":",val),\ -+ (res= vpx_codec_control(&ctx->encoder,id,val))!=VPX_CODEC_OK) {\ -+ log_encoder_error(avctx,"Failed to set "#id" codec control");\ -+ } while(0); -+ codecctl(VP8E_SET_CPUUSED,cpuused); -+ codecctl(VP8E_SET_NOISE_SENSITIVITY,avctx->noise_reduction); -+ codecctl(VP8E_SET_SHARPNESS,avctx->sharpness); -+ codecctl(VP8E_SET_ENABLEAUTOALTREF,avctx->altref); -+ codecctl(VP8E_SET_ARNR_MAXFRAMES,avctx->ar_max_frames); -+ codecctl(VP8E_SET_ARNR_TYPE,avctx->ar_type); -+ codecctl(VP8E_SET_ARNR_STRENGTH,avctx->ar_strength); -+ codecctl(VP8E_SET_STATIC_THRESHOLD,avctx->mb_static_threshold); -+ codecctl(VP8E_SET_TOKEN_PARTITIONS,av_log2(avctx->token_partitions)); -+ #undef codecctl -+ -+ //provide dummy value to initialize wrapper, values will be updated each _encode() -+ vpx_img_wrap(&ctx->rawimg,IMG_FMT_I420,avctx->width,avctx->height,1,(unsigned char*)1); -+ -+ avctx->coded_frame = avcodec_alloc_frame(); -+ if(!avctx->coded_frame) { -+ av_log(avctx,AV_LOG_ERROR,"Error allocating coded frame\n"); -+ vp8_free(avctx); -+ return AVERROR(ENOMEM); -+ } -+ return 0; -+} -+ -+static inline void cx_pktcpy(struct FrameListData* dst, const vpx_codec_cx_pkt_t* src) -+{ -+ dst->pts = src->data.frame.pts; -+ dst->duration = src->data.frame.duration; -+ dst->flags = src->data.frame.flags; -+ dst->sz = src->data.frame.sz; -+ dst->buf = src->data.frame.buf; -+} -+ -+/** -+ * Store coded frame information in format suitable for return from encode(). -+ * -+ * Write buffer information from @a cx_frame to @a buf & @a buf_size. -+ * Timing/frame details to @a coded_frame. -+ * @return Frame size written to @a buf on success -+ * @return -1 on error -+ */ -+static int storeframe(AVCodecContext *avctx, struct FrameListData* cx_frame, -+ uint8_t* buf, int buf_size, AVFrame* coded_frame) -+{ -+ if((int)cx_frame->sz<=buf_size) { -+ buf_size = cx_frame->sz; -+ memcpy(buf,cx_frame->buf,buf_size); -+ coded_frame->pts = cx_frame->pts; -+ coded_frame->key_frame = !!(cx_frame->flags&VPX_FRAME_IS_KEY); -+ -+ if(coded_frame->key_frame) -+ coded_frame->pict_type = FF_I_TYPE; -+ else -+ coded_frame->pict_type = FF_P_TYPE; -+ } else { -+ av_log(avctx,AV_LOG_ERROR, -+ "Compressed frame larger than storage provided! (%zu/%d)\n", -+ cx_frame->sz,buf_size); -+ return -1; -+ } -+ return buf_size; -+} -+ -+/** -+ * Queue multiple output frames from the encoder, returning the front-most. -+ * In cases where vpx_codec_get_cx_data() returns more than 1 frame append -+ * the frame queue. Return the head frame if available. -+ * @return Stored frame size -+ * @return -1 on error -+ */ -+static int queue_frames(AVCodecContext *avctx, uint8_t* buf, int buf_size, AVFrame* coded_frame) -+{ -+ VP8Context* const ctx = avctx->priv_data; -+ const vpx_codec_cx_pkt_t* pkt; -+ vpx_codec_iter_t iter = NULL; -+ int size = 0; -+ -+ if(ctx->coded_frame_list) { -+ struct FrameListData* const cx_frame = ctx->coded_frame_list; -+ /*return the leading frame if we've already begun queueing*/ -+ size = storeframe(avctx,cx_frame,buf,buf_size,coded_frame); -+ if(size<0) -+ return -1; -+ ctx->coded_frame_list = cx_frame->next; -+ free_coded_frame(cx_frame); -+ } -+ -+ /*consume all available output from the encoder before returning. buffers -+ are only good through the next vpx_codec call*/ -+ while( (pkt= vpx_codec_get_cx_data(&ctx->encoder,&iter)) ) { -+ switch(pkt->kind) { -+ case VPX_CODEC_CX_FRAME_PKT: { -+ if(!size) { -+ struct FrameListData cx_frame; -+ -+ /*avoid storing the frame when the list is empty and we haven't yet -+ provided a frame for output*/ -+ assert(!ctx->coded_frame_list); -+ cx_pktcpy(&cx_frame,pkt); -+ size = storeframe(avctx,&cx_frame,buf,buf_size,coded_frame); -+ if(size<0) -+ return -1; -+ } else { -+ struct FrameListData* const cx_frame = av_malloc(sizeof(struct FrameListData)); -+ -+ if(!cx_frame) { -+ av_log(avctx,AV_LOG_ERROR,"Frame queue element alloc failed\n"); -+ return AVERROR(ENOMEM); -+ } -+ cx_pktcpy(cx_frame,pkt); -+ cx_frame->buf = av_malloc(cx_frame->sz); -+ -+ if(!cx_frame->buf) { -+ av_log(avctx,AV_LOG_ERROR,"Data buffer alloc (%zu bytes) failed\n", -+ cx_frame->sz); -+ return AVERROR(ENOMEM); -+ } -+ memcpy(cx_frame->buf,pkt->data.frame.buf,pkt->data.frame.sz); -+ coded_frame_add(&ctx->coded_frame_list,cx_frame); -+ } -+ break; } -+ case VPX_CODEC_STATS_PKT: { -+ vpx_fixed_buf_t* const stats = &ctx->twopass_stats; -+ stats->buf = av_realloc(stats->buf,stats->sz+pkt->data.twopass_stats.sz); -+ if(!stats->buf) { -+ av_log(avctx,AV_LOG_ERROR,"Stat buffer realloc failed\n"); -+ return AVERROR(ENOMEM); -+ } -+ memcpy((uint8_t*)stats->buf + stats->sz, -+ pkt->data.twopass_stats.buf, -+ pkt->data.twopass_stats.sz); -+ stats->sz += pkt->data.twopass_stats.sz; -+ break; } -+ case VPX_CODEC_CUSTOM_PKT: -+ //ignore unsupported/unrecognized packet types -+ break; -+ } -+ } -+ -+ return size; -+} -+ -+static int vp8_encode(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data) -+{ -+ VP8Context* const ctx = avctx->priv_data; -+ AVFrame* const frame = data; -+ vpx_image_t* rawimg = NULL; -+ int coded_size; -+ -+ if(frame) { -+ rawimg = &ctx->rawimg; -+ rawimg->planes[PLANE_Y] = frame->data[0]; -+ rawimg->planes[PLANE_U] = frame->data[1]; -+ rawimg->planes[PLANE_V] = frame->data[2]; -+ rawimg->stride[PLANE_Y] = frame->linesize[0]; -+ rawimg->stride[PLANE_U] = frame->linesize[1]; -+ rawimg->stride[PLANE_V] = frame->linesize[2]; -+ } -+ -+ { vpx_codec_err_t res; -+ const vpx_codec_pts_t timestamp = frame?frame->pts:0; -+ const unsigned long framedur = avctx->ticks_per_frame; -+ const vpx_enc_frame_flags_t flags = 0; //VPX_EFLAG_FORCE_KF -+ const unsigned long deadline = ctx->deadline; -+ -+ //FIXME use vpx_codec_set_cx_data_buf? -+ res = vpx_codec_encode(&ctx->encoder,rawimg,timestamp,framedur,flags,deadline); -+ if(res!=VPX_CODEC_OK) { log_encoder_error(avctx,"Error encoding frame"); return -1; } } -+ coded_size = queue_frames(avctx,buf,buf_size,avctx->coded_frame); -+ -+ if(!frame && avctx->flags&CODEC_FLAG_PASS1) { -+ const unsigned int b64_size = ((ctx->twopass_stats.sz + 2) / 3) * 4 + 1; -+ -+ avctx->stats_out = av_malloc(b64_size); -+ if(!avctx->stats_out) { -+ av_log(avctx,AV_LOG_ERROR,"Stat buffer alloc (%d bytes) failed\n",b64_size); -+ return AVERROR(ENOMEM); -+ } -+ av_base64_encode(avctx->stats_out, b64_size, ctx->twopass_stats.buf, ctx->twopass_stats.sz); -+ } -+ return coded_size; -+} -+ -+static av_cold int vp8_free(AVCodecContext *avctx) -+{ -+ VP8Context* const ctx = avctx->priv_data; -+ -+ vpx_codec_destroy(&ctx->encoder); -+ av_freep(&ctx->twopass_stats.buf); -+ av_freep(&avctx->coded_frame); -+ av_freep(&avctx->stats_out); -+ free_frame_list(ctx->coded_frame_list); -+ return 0; -+} -+ -+static av_cold void free_coded_frame(struct FrameListData* cx_frame) -+{ -+ av_freep(&cx_frame->buf); -+ av_freep(&cx_frame); -+} -+ -+static av_cold void free_frame_list(struct FrameListData* list) -+{ -+ struct FrameListData* p = list; -+ -+ while(p) { -+ list = list->next; -+ free_coded_frame(p); -+ p = list; -+ } -+} -+ -+static void coded_frame_add(void* list, struct FrameListData* cx_frame) -+{ -+ struct FrameListData** p = list; -+ -+ while(*p!=NULL) p= &(*p)->next; -+ *p = cx_frame; -+ cx_frame->next = NULL; -+} -+ -+static av_cold void log_encoder_error(AVCodecContext *avctx, const char* desc) -+{ -+ VP8Context* const ctx = avctx->priv_data; -+ const char* error = vpx_codec_error(&ctx->encoder); -+ const char* detail = vpx_codec_error_detail(&ctx->encoder); -+ -+ av_log(avctx,AV_LOG_ERROR,"%s: %s\n",desc,error); -+ if(detail) av_log(avctx,AV_LOG_ERROR," Additional information: %s\n",detail); -+} -+ -+static av_cold void dump_enc_cfg(AVCodecContext *avctx, const vpx_codec_enc_cfg_t* cfg) -+{ -+ const int width = -30; -+ const int level = AV_LOG_DEBUG; -+ -+ av_log(avctx,level,"vpx_codec_enc_cfg\n"); -+ av_log(avctx,level," %*s%u\n", width, " g_usage:", cfg->g_usage); -+ av_log(avctx,level," %*s%u\n", width, " g_threads:", cfg->g_threads); -+ av_log(avctx,level," %*s%u\n", width, " g_profile:", cfg->g_profile); -+ av_log(avctx,level," %*s%u\n", width, " g_w:", cfg->g_w); -+ av_log(avctx,level," %*s%u\n", width, " g_h:", cfg->g_h); -+ av_log(avctx,level," %*s{%u/%u}\n", width, " g_timebase:", cfg->g_timebase.num, cfg->g_timebase.den); -+ av_log(avctx,level," %*s%u\n", width, " g_error_resilient:", cfg->g_error_resilient); -+ av_log(avctx,level," %*s%d\n", width, " g_pass:", cfg->g_pass); -+ av_log(avctx,level," %*s%u\n", width, " g_lag_in_frames:", cfg->g_lag_in_frames); -+ av_log(avctx,level," %*s%u\n", width, " rc_dropframe_thresh:", cfg->rc_dropframe_thresh); -+ av_log(avctx,level," %*s%u\n", width, " rc_resize_allowed:", cfg->rc_resize_allowed); -+ av_log(avctx,level," %*s%u\n", width, " rc_resize_up_thresh:", cfg->rc_resize_up_thresh); -+ av_log(avctx,level," %*s%u\n", width, " rc_resize_down_thresh:", cfg->rc_resize_down_thresh); -+ av_log(avctx,level," %*s%d\n", width, " rc_end_usage:", cfg->rc_end_usage); -+ av_log(avctx,level," %*s%p(%zu)\n", width, " rc_twopass_stats_in:", cfg->rc_twopass_stats_in.buf, cfg->rc_twopass_stats_in.sz); -+ av_log(avctx,level," %*s%u\n", width, " rc_target_bitrate:", cfg->rc_target_bitrate); -+ av_log(avctx,level," %*s%u\n", width, " rc_min_quantizer:", cfg->rc_min_quantizer); -+ av_log(avctx,level," %*s%u\n", width, " rc_max_quantizer:", cfg->rc_max_quantizer); -+ av_log(avctx,level," %*s%u\n", width, " rc_undershoot_pct:", cfg->rc_undershoot_pct); -+ av_log(avctx,level," %*s%u\n", width, " rc_overshoot_pct:", cfg->rc_overshoot_pct); -+ av_log(avctx,level," %*s%u\n", width, " rc_buf_sz:", cfg->rc_buf_sz); -+ av_log(avctx,level," %*s%u\n", width, " rc_buf_initial_sz:", cfg->rc_buf_initial_sz); -+ av_log(avctx,level," %*s%u\n", width, " rc_buf_optimal_sz:", cfg->rc_buf_optimal_sz); -+ av_log(avctx,level," %*s%u\n", width, " rc_2pass_vbr_bias_pct:", cfg->rc_2pass_vbr_bias_pct); -+ av_log(avctx,level," %*s%u\n", width, " rc_2pass_vbr_minsection_pct:", cfg->rc_2pass_vbr_minsection_pct); -+ av_log(avctx,level," %*s%u\n", width, " rc_2pass_vbr_maxsection_pct:", cfg->rc_2pass_vbr_maxsection_pct); -+ av_log(avctx,level," %*s%d\n", width, " kf_mode:", cfg->kf_mode); -+ av_log(avctx,level," %*s%u\n", width, " kf_min_dist:", cfg->kf_min_dist); -+ av_log(avctx,level," %*s%u\n", width, " kf_max_dist:", cfg->kf_max_dist); -+ av_log(avctx,level,"\n"); -+} -+ -+AVCodec libvpx_encoder = { -+ "libvpx", -+ AVMEDIA_TYPE_VIDEO, -+ CODEC_ID_VP8, -+ sizeof(VP8Context), -+ vp8_init, -+ vp8_encode, -+ vp8_free, -+ NULL, -+ CODEC_CAP_DELAY, -+ .pix_fmts = (const enum PixelFormat[]) { PIX_FMT_YUV420P, PIX_FMT_NONE }, -+ .long_name = NULL_IF_CONFIG_SMALL("libvpx VP8"), -+}; -Index: ffpresets/libvpx-720p50_60.ffpreset -=================================================================== ---- ffpresets/libvpx-720p50_60.ffpreset (revision 0) -+++ ffpresets/libvpx-720p50_60.ffpreset (revision 0) -@@ -0,0 +1,17 @@ -+vcodec=libvpx -+bt=4M -+g=120 -+lag=25 -+level=216 -+mb_static_threshold=0 -+profile=0 -+qmax=42 -+qmin=10 -+rc_buf_aggressivity=0.95 -+token_partitions=4 -+vb=2M -+ -+#ignored unless using -pass 2 -+altref=1 -+maxrate=24M -+minrate=100k -Index: ffpresets/libvpx-1080p.ffpreset -=================================================================== ---- ffpresets/libvpx-1080p.ffpreset (revision 0) -+++ ffpresets/libvpx-1080p.ffpreset (revision 0) -@@ -0,0 +1,17 @@ -+vcodec=libvpx -+bt=4M -+g=120 -+lag=16 -+level=216 -+mb_static_threshold=0 -+profile=1 -+qmax=42 -+qmin=10 -+rc_buf_aggressivity=0.95 -+token_partitions=4 -+vb=2M -+ -+#ignored unless using -pass 2 -+altref=1 -+maxrate=24M -+minrate=100k -Index: ffpresets/libvpx-1080p50_60.ffpreset -=================================================================== ---- ffpresets/libvpx-1080p50_60.ffpreset (revision 0) -+++ ffpresets/libvpx-1080p50_60.ffpreset (revision 0) -@@ -0,0 +1,17 @@ -+vcodec=libvpx -+bt=4M -+g=120 -+lag=25 -+level=216 -+mb_static_threshold=0 -+profile=1 -+qmax=42 -+qmin=10 -+rc_buf_aggressivity=0.95 -+token_partitions=4 -+vb=2M -+ -+#ignored unless using -pass 2 -+altref=1 -+maxrate=24M -+minrate=100k -Index: ffpresets/libvpx-360p.ffpreset -=================================================================== ---- ffpresets/libvpx-360p.ffpreset (revision 0) -+++ ffpresets/libvpx-360p.ffpreset (revision 0) -@@ -0,0 +1,16 @@ -+vcodec=libvpx -+bt=1.5M -+g=120 -+lag=16 -+level=216 -+mb_static_threshold=0 -+profile=0 -+qmax=51 -+qmin=1 -+rc_buf_aggressivity=0.95 -+vb=768k -+ -+#ignored unless using -pass 2 -+altref=1 -+maxrate=1.5M -+minrate=40k -Index: ffpresets/libvpx-720p.ffpreset -=================================================================== ---- ffpresets/libvpx-720p.ffpreset (revision 0) -+++ ffpresets/libvpx-720p.ffpreset (revision 0) -@@ -0,0 +1,17 @@ -+vcodec=libvpx -+bt=4M -+g=120 -+lag=16 -+level=216 -+mb_static_threshold=0 -+profile=0 -+qmax=42 -+qmin=10 -+rc_buf_aggressivity=0.95 -+token_partitions=4 -+vb=2M -+ -+#ignored unless using -pass 2 -+altref=1 -+maxrate=24M -+minrate=100k -Index: libavformat/Makefile -=================================================================== ---- libavformat/Makefile (revision 23210) -+++ libavformat/Makefile (working copy) -@@ -255,6 +255,8 @@ OBJS-$(CONFIG_W64_DEMUXER) - OBJS-$(CONFIG_WAV_DEMUXER) += wav.o riff.o raw.o - OBJS-$(CONFIG_WAV_MUXER) += wav.o riff.o - OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o -+OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \ -+ riff.o - OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood.o - OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood.o - OBJS-$(CONFIG_WV_DEMUXER) += wv.o apetag.o id3v1.o -Index: libavformat/allformats.c -=================================================================== ---- libavformat/allformats.c (revision 23210) -+++ libavformat/allformats.c (working copy) -@@ -203,6 +203,7 @@ void av_register_all(void) - REGISTER_DEMUXER (W64, w64); - REGISTER_MUXDEMUX (WAV, wav); - REGISTER_DEMUXER (WC3, wc3); -+ REGISTER_MUXER (WEBM, webm); - REGISTER_DEMUXER (WSAUD, wsaud); - REGISTER_DEMUXER (WSVQA, wsvqa); - REGISTER_DEMUXER (WV, wv); ---- libavformat/matroskaenc.c.orig 2010-05-24 23:47:39.000000000 +0200 -+++ libavformat/matroskaenc.c 2010-05-24 23:49:11.000000000 +0200 -@@ -20,15 +20,21 @@ - */ - - #include "avformat.h" -+#if CONFIG_MATROSKA_MUXER - #include "riff.h" - #include "isom.h" -+#endif - #include "matroska.h" -+#if CONFIG_MATROSKA_MUXER - #include "avc.h" - #include "flacenc.h" -+#endif - #include "libavutil/intreadwrite.h" - #include "libavutil/md5.h" - #include "libavcodec/xiph.h" -+#if CONFIG_MATROSKA_MUXER - #include "libavcodec/mpeg4audio.h" -+#endif - - typedef struct ebml_master { - int64_t pos; ///< absolute offset in the file where the master's elements start -@@ -81,6 +87,12 @@ - mkv_track *tracks; - - struct AVMD5 *md5_ctx; -+ int max_cluster_size; -+ int max_cluster_pts; -+#if CONFIG_WEBM_MUXER -+ unsigned int audio_buffer_size; -+ AVPacket cur_audio_pkt; -+#endif - } MatroskaMuxContext; - - -@@ -429,6 +441,7 @@ - return 0; - } - -+#if CONFIG_MATROSKA_MUXER - static void get_aac_sample_rates(AVFormatContext *s, AVCodecContext *codec, int *sample_rate, int *output_sample_rate) - { - int sri; -@@ -455,6 +468,7 @@ - *output_sample_rate = ff_mpeg4audio_sample_rates[sri]; - } - } -+#endif - - static int mkv_write_codecprivate(AVFormatContext *s, ByteIOContext *pb, AVCodecContext *codec, int native_id, int qt_id) - { -@@ -469,12 +483,15 @@ - if (native_id) { - if (codec->codec_id == CODEC_ID_VORBIS || codec->codec_id == CODEC_ID_THEORA) - ret = put_xiph_codecpriv(s, dyn_cp, codec); -+#if CONFIG_MATROSKA_MUXER - else if (codec->codec_id == CODEC_ID_FLAC) - ret = ff_flac_write_header(dyn_cp, codec, 1); - else if (codec->codec_id == CODEC_ID_H264) - ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); -+#endif - else if (codec->extradata_size) - put_buffer(dyn_cp, codec->extradata, codec->extradata_size); -+#if CONFIG_MATROSKA_MUXER - } else if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { - if (qt_id) { - if (!codec->codec_tag) -@@ -503,6 +520,7 @@ - codec->codec_tag = tag; - - ff_put_wav_header(dyn_cp, codec); -+#endif - } - - codecpriv_size = url_close_dyn_buf(dyn_cp, &codecpriv); -@@ -537,8 +555,10 @@ - if (!bit_depth) - bit_depth = av_get_bits_per_sample_format(codec->sample_fmt); - -+#if CONFIG_MATROSKA_MUXER - if (codec->codec_id == CODEC_ID_AAC) - get_aac_sample_rates(s, codec, &sample_rate, &output_sample_rate); -+#endif - - track = start_ebml_master(pb, MATROSKA_ID_TRACKENTRY, 0); - put_ebml_uint (pb, MATROSKA_ID_TRACKNUMBER , i + 1); -@@ -565,9 +585,18 @@ - - switch (codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: -+#if CONFIG_WEBM_MUXER -+ if (codec->codec_id != CODEC_ID_VP8 && -+ !strcmp("webm", s->oformat->name)) { -+ av_log(s, AV_LOG_INFO, "WebM only supports VP8 video.\n"); -+ return -1; -+ } -+#endif -+ - put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_VIDEO); - put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, av_q2d(codec->time_base)*1E9); - -+#if CONFIG_MATROSKA_MUXER - if (!native_id && - ff_codec_get_tag(codec_movvideo_tags, codec->codec_id) && - (!ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id) -@@ -583,7 +612,7 @@ - put_ebml_string(pb, MATROSKA_ID_CODECID, "V_MS/VFW/FOURCC"); - mkv->tracks[i].write_dts = 1; - } -- -+#endif - subinfo = start_ebml_master(pb, MATROSKA_ID_TRACKVIDEO, 0); - // XXX: interlace flag? - put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELWIDTH , codec->width); -@@ -597,6 +626,13 @@ - break; - - case AVMEDIA_TYPE_AUDIO: -+#if CONFIG_WEBM_MUXER -+ if (codec->codec_id != CODEC_ID_VORBIS && -+ !strcmp("webm", s->oformat->name)) { -+ av_log(s, AV_LOG_INFO, "WebM only supports Vorbis audio.\n"); -+ return -1; -+ } -+#endif - put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_AUDIO); - - if (!native_id) -@@ -693,7 +729,7 @@ - put_ebml_uint (pb, EBML_ID_EBMLREADVERSION , 1); - put_ebml_uint (pb, EBML_ID_EBMLMAXIDLENGTH , 4); - put_ebml_uint (pb, EBML_ID_EBMLMAXSIZELENGTH , 8); -- put_ebml_string (pb, EBML_ID_DOCTYPE , "matroska"); -+ put_ebml_string (pb, EBML_ID_DOCTYPE , s->oformat->name); - put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 2); - put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2); - end_ebml_master(pb, ebml_header); -@@ -746,6 +782,20 @@ - if (mkv->cues == NULL) - return AVERROR(ENOMEM); - -+#if CONFIG_WEBM_MUXER -+ av_init_packet(&mkv->cur_audio_pkt); -+ mkv->cur_audio_pkt.size = 0; -+ mkv->audio_buffer_size = 0; -+#endif -+ -+ if (!strcmp("webm", s->oformat->name)) { -+ mkv->max_cluster_size = 500*1024*1024; // 500 MB -+ mkv->max_cluster_pts = 30000; // 30 seconds -+ } else { -+ mkv->max_cluster_size = 5*1024*1024; // 5 MB -+ mkv->max_cluster_pts = 5000; // 5 seconds -+ } -+ - put_flush_packet(pb); - return 0; - } -@@ -831,10 +881,12 @@ - av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, " - "pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n", - url_ftell(pb), pkt->size, pkt->pts, pkt->dts, pkt->duration, flags); -+#if CONFIG_MATROSKA_MUXER - if (codec->codec_id == CODEC_ID_H264 && codec->extradata_size > 0 && - (AV_RB24(codec->extradata) == 1 || AV_RB32(codec->extradata) == 1)) - ff_avc_parse_nal_units_buf(pkt->data, &data, &size); - else -+#endif - data = pkt->data; - put_ebml_id(pb, blockid); - put_ebml_num(pb, size+4, 0); -@@ -910,9 +962,10 @@ - if (ret < 0) return ret; - } - -- // start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming -+ // start a new cluster every 32k / 1 sec for streaming - if ((url_is_streamed(s->pb) && (url_ftell(pb) > 32*1024 || ts > mkv->cluster_pts + 1000)) -- || url_ftell(pb) > mkv->cluster_pos + 5*1024*1024 || ts > mkv->cluster_pts + 5000) { -+ || url_ftell(pb) > mkv->cluster_pos + mkv->max_cluster_size -+ || ts > mkv->cluster_pts + mkv->max_cluster_pts) { - av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64 - " bytes, pts %" PRIu64 "\n", url_ftell(pb), ts); - end_ebml_master(pb, mkv->cluster); -@@ -924,7 +977,59 @@ - mkv->duration = FFMAX(mkv->duration, ts + duration); - return 0; - } -+#if CONFIG_WEBM_MUXER -+static int mkv_copy_packet(MatroskaMuxContext *mkv, const AVPacket *pkt) -+{ -+ uint8_t *data = mkv->cur_audio_pkt.data; -+ mkv->cur_audio_pkt = *pkt; -+ mkv->cur_audio_pkt.data = av_fast_realloc(data, &mkv->audio_buffer_size, pkt->size); -+ if (mkv->cur_audio_pkt.data == NULL) -+ return AVERROR(ENOMEM); -+ -+ memcpy(mkv->cur_audio_pkt.data, pkt->data, pkt->size); -+ mkv->cur_audio_pkt.size = pkt->size; -+ return 0; -+} -+ -+static int mkv_write_packet2(AVFormatContext *s, AVPacket *pkt) -+{ -+ MatroskaMuxContext *mkv = s->priv_data; -+ ByteIOContext *pb = s->pb; -+ AVCodecContext *codec = s->streams[pkt->stream_index]->codec; -+ int keyframe = !!(pkt->flags & PKT_FLAG_KEY); -+ int ret = 0; -+ -+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe && mkv->cluster_pos) { -+ // Start a new cluster when we get a key frame -+ int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts; -+ -+ av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64 -+ " bytes, pts %" PRIu64 "\n", url_ftell(pb), ts); - -+ end_ebml_master(pb, mkv->cluster); -+ mkv->cluster_pos = 0; -+ if (mkv->dyn_bc) -+ mkv_flush_dynbuf(s); -+ } -+ -+ // Check if we have an audio packet cached -+ if ( (codec->codec_type == AVMEDIA_TYPE_AUDIO || codec->codec_type == AVMEDIA_TYPE_VIDEO) -+ && mkv->cur_audio_pkt.size > 0) { -+ ret = mkv_write_packet(s, &mkv->cur_audio_pkt); -+ mkv->cur_audio_pkt.size = 0; -+ if (ret < 0) { -+ av_log(s, AV_LOG_ERROR, "Could not write cached audio packet ret:%d\n", ret); -+ return ret; -+ } -+ } -+ -+ if (codec->codec_type == AVMEDIA_TYPE_AUDIO) -+ ret = mkv_copy_packet(mkv, pkt); -+ else -+ ret = mkv_write_packet(s, pkt); -+ return ret; -+} -+#endif - static int mkv_write_trailer(AVFormatContext *s) - { - MatroskaMuxContext *mkv = s->priv_data; -@@ -932,6 +1037,18 @@ - int64_t currentpos, second_seekhead, cuespos; - int ret; - -+#if CONFIG_WEBM_MUXER -+ // Check if we have an audio packet cached -+ if (mkv->cur_audio_pkt.size > 0) { -+ ret = mkv_write_packet(s, &mkv->cur_audio_pkt); -+ mkv->cur_audio_pkt.size = 0; -+ if (ret < 0) { -+ av_log(s, AV_LOG_ERROR, "Could not write cached audio packet ret:%d\n", ret); -+ return ret; -+ } -+ } -+#endif -+ - if (mkv->dyn_bc) { - end_ebml_master(mkv->dyn_bc, mkv->cluster); - mkv_flush_dynbuf(s); -@@ -970,10 +1087,15 @@ - end_ebml_master(pb, mkv->segment); - av_free(mkv->md5_ctx); - av_free(mkv->tracks); -+#if CONFIG_WEBM_MUXER -+ if (!strcmp("webm", s->oformat->name)) -+ av_destruct_packet(&mkv->cur_audio_pkt); -+#endif - put_flush_packet(pb); - return 0; - } - -+#if CONFIG_MATROSKA_MUXER - AVOutputFormat matroska_muxer = { - "matroska", - NULL_IF_CONFIG_SMALL("Matroska file format"), -@@ -989,7 +1111,23 @@ - .codec_tag = (const AVCodecTag* const []){ff_codec_bmp_tags, ff_codec_wav_tags, 0}, - .subtitle_codec = CODEC_ID_TEXT, - }; -- -+#endif -+#if CONFIG_WEBM_MUXER -+AVOutputFormat webm_muxer = { -+ "webm", -+ NULL_IF_CONFIG_SMALL("WebM file format"), -+ "video/webm", -+ "webm", -+ sizeof(MatroskaMuxContext), -+ CODEC_ID_VORBIS, -+ CODEC_ID_VP8, -+ mkv_write_header, -+ mkv_write_packet2, -+ mkv_write_trailer, -+ .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS, -+}; -+#endif -+#if CONFIG_MATROSKA_AUDIO_MUXER - AVOutputFormat matroska_audio_muxer = { - "matroska", - NULL_IF_CONFIG_SMALL("Matroska file format"), -@@ -1004,3 +1142,4 @@ - .flags = AVFMT_GLOBALHEADER, - .codec_tag = (const AVCodecTag* const []){ff_codec_wav_tags, 0}, - }; -+#endif -- 2.39.2