]> git.sesse.net Git - vlc/commitdiff
contribs: added Google's libvpx patch for ffmpeg with a couple of compilation fixes...
authorFelix Paul Kühne <fkuehne@videolan.org>
Sun, 23 May 2010 00:41:13 +0000 (02:41 +0200)
committerFelix Paul Kühne <fkuehne@videolan.org>
Sun, 23 May 2010 00:41:13 +0000 (02:41 +0200)
extras/contrib/src/Makefile
extras/contrib/src/Patches/ffmpeg-libvpx.patch [new file with mode: 0644]
extras/contrib/src/Patches/libvpx-darwin.patch

index 0dfb3474b2e0abb9b2a7b53a8aabe10e1f952e67..b8e44916aa4c6691e3f084f3d1ff1ff1090543e9 100644 (file)
@@ -1078,6 +1078,7 @@ 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
@@ -1116,7 +1117,7 @@ else
 ifdef HAVE_WIN32
 FFMPEGCONF += --disable-bzlib --disable-decoder=dca --disable-encoder=vorbis --enable-libmp3lame --enable-w32threads --enable-dxva2 --disable-bsfs
 else
-FFMPEGCONFG += --enable-pthreads
+FFMPEGCONF += --enable-pthreads
 endif
 endif
 
diff --git a/extras/contrib/src/Patches/ffmpeg-libvpx.patch b/extras/contrib/src/Patches/ffmpeg-libvpx.patch
new file mode 100644 (file)
index 0000000..f799c7c
--- /dev/null
@@ -0,0 +1,1371 @@
+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,128 @@
++/*
++ * 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 <vpx_decoder.h>
++#include <vp8dx.h>
++
++#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 {{{
++ * <table>
++ * <tr><td>g_threads</td><td>AVCodecContext::thread_count</td><td>-threads</td></tr>
++ * <tr><td>g_lag_in_frames</td><td>AVCodecContext::lag</td><td>-lag</td></tr>
++ * <tr><td>rc_target_bitrate</td><td>AVCodecContext::bit_rate/1000</td><td>-vb</td></tr>
++ * <tr><td>kf_max_dist</td><td>AVCodecContext::gop_size</td><td>-g</td></tr>
++ * <tr><td>kf_min_dist</td><td>AVCodecContext::keyint_min</td><td>-keyint_min</td></tr>
++ * <tr><td><code>VPX_KF_FIXED</code></td><td>AVCodecContext::keyint_min == AVCodecContext::gop_size</td><td>-keyint_min -g</td></tr>
++ * <tr><td>rc_min_quantizer</td><td>((AVCodecContext::qmin*5+1)&gt;&gt;2) - 1</td><td>-qmin</td></tr>
++ * <tr><td>rc_max_quantizer</td><td>((AVCodecContext::qmax*5+1)&gt;&gt;2) - 1</td><td>-qmax</td></tr>
++ * <tr><td>rc_buf_sz</td><td>AVCodecContext::rc_buffer_size*1000 / AVCodecContext::bit_rate</td><td>-bufsize -vb</td></tr>
++ * <tr><td>rc_buf_initial_sz</td><td>AVCodecContext::rc_initial_buffer_occupancy*1000 / AVCodecContext::bit_rate</td><td>-rc_init_occupancy -vb</td></tr>
++ * <tr><td>rc_buf_optimal_sz</td><td>AVCodecContext::rc_optimal_buffer_occupancy*1000 / AVCodecContext::bit_rate</td><td>-rc_opt_occupancy -vb</td></tr>
++ * <tr><td>rc_dropframe_thresh</td><td>AVCodecContext::frame_skip_threshold</td><td>-skip_threshold</td></tr>
++ * <tr><td>rc_undershoot_pct</td><td>AVCodecContext::rc_buffer_aggressivity*100</td><td>-rc_buf_aggressivity</td></tr>
++ * <tr><td>rc_overshoot_pct</td><td>AVCodecContext::bit_rate_tolerance*100 / AVCodecContext::bit_rate</td><td>-bt -vb</td></tr>
++ * <tr><td>rc_resize_allowed</td><td>AVCodecContext::spatial_rsmpl</td><td>-spatial_rsmpl</td></tr>
++ * <tr><td>rc_resize_up_thresh</td><td>AVCodecContext::spatial_rsmpl_up</td><td>-spatial_rsmpl_up</td></tr>
++ * <tr><td>rc_resize_down_thresh</td><td>AVCodecContext::spatial_rsmpl_down</td><td>-spatial_rsmpl_down</td></tr>
++ * <tr><td>rc_2pass_vbr_bias_pct</td><td>AVCodecContext::vbr_bias</td><td>-vbr_bias</td></tr>
++ * <tr><td>rc_2pass_vbr_maxsection_pct</td><td>AVCodecContext::rc_max_rate*100 / AVCodecContext::bit_rate</td><td>-maxrate -vb</td></tr>
++ * <tr><td>rc_2pass_vbr_minsection_pct</td><td>AVCodecContext::rc_min_rate*100 / AVCodecContext::bit_rate</td><td>-minrate -vb</td></tr>
++ * <tr><td>VPX_CBR</td><td>AVCodecContext::rc_min_rate == AVCodecContext::rc_max_rate &amp;&amp; AVCodecContext::rc_min_rate == AVCodecContext::bit_rate</td><td>-minrate -maxrate -vb</td></tr>
++ * <tr><td>g_profile</td><td>AVCodecContext::profile</td><td>-profile</td></tr>
++ * <tr><td>g_error_resilient</td><td>AVCodecContext::level&lt;0</td><td>-level</td></tr>
++ * <tr><td><code>VPX_DL_BEST_QUALITY(1)/VPX_DL_GOOD_QUALITY(2)/VPX_DL_REALTIME(3)</code></td><td>#FFABS(AVCodecContext::level)/100</td><td>-level</td></tr>
++ * <tr><td><code>VP8E_SET_CPUUSED</code></td><td>#FFABS(AVCodecContext::level)%%100-16</td><td>-level</td></tr>
++ * <tr><td><code>VP8E_SET_NOISE_SENSITIVITY</code></td><td>AVCodecContext::noise_reduction</td><td>-nr</td></tr>
++ * <tr><td><code>VP8E_SET_SHARPNESS</code></td><td>AVCodecContext::sharpness</td><td>-sharpness</td></tr>
++ * <tr><td><code>VP8E_SET_ENABLEAUTOALTREF</code></td><td>AVCodecContext::altref</td><td>-altref</td></tr>
++ * <tr><td><code>VP8E_SET_ARNR_MAXFRAMES</code></td><td>AVCodecContext::ar_max_frames</td><td>-ar_max_frames</td></tr>
++ * <tr><td><code>VP8E_SET_ARNR_TYPE</code></td><td>AVCodecContext::ar_type</td><td>-ar_type</td></tr>
++ * <tr><td><code>VP8E_SET_ARNR_STRENGTH</code></td><td>AVCodecContext::ar_strength</td><td>-ar_strength</td></tr>
++ * <tr><td><code>VP8E_SET_STATIC_THRESHOLD</code></td><td>AVCodecContext::mb_static_threshold</td><td>-mb_static_threshold</td></tr>
++ * <tr><td><code>VP8E_SET_TOKEN_PARTITIONS</code></td><td>AVCodecContext::token_partitions</td><td>-token_partitions</td></tr>
++ * </table> }}}
++ */
++
++#include "avcodec.h"
++#include "libavutil/base64.h"
++
++#ifndef HAVE_STDINT_H
++# define HAVE_STDINT_H 1
++#endif
++#define VPX_CODEC_DISABLE_COMPAT 1
++#include <vpx_encoder.h>
++#include <vp8cx.h>
++
++/**
++ * 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/matroskaenc.c
+===================================================================
+--- libavformat/matroskaenc.c  (revision 23210)
++++ libavformat/matroskaenc.c  (working copy)
+@@ -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 @@ typedef struct MatroskaMuxContext {
+     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 @@ static int put_xiph_codecpriv(AVFormatCo
+     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 @@ static void get_aac_sample_rates(AVForma
+         *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 @@ static int mkv_write_codecprivate(AVForm
+     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 @@ static int mkv_write_codecprivate(AVForm
+             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 @@ static int mkv_write_tracks(AVFormatCont
+         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);
+@@ -566,8 +586,16 @@ static int mkv_write_tracks(AVFormatCont
+         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);
++#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 +611,7 @@ static int mkv_write_tracks(AVFormatCont
+                     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 +625,13 @@ static int mkv_write_tracks(AVFormatCont
+                 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 +728,7 @@ static int mkv_write_header(AVFormatCont
+     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 +781,20 @@ static int mkv_write_header(AVFormatCont
+     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 +880,12 @@ static void mkv_write_block(AVFormatCont
+     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 +961,10 @@ static int mkv_write_packet(AVFormatCont
+         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 +976,59 @@ static int mkv_write_packet(AVFormatCont
+     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 +1036,18 @@ static int mkv_write_trailer(AVFormatCon
+     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 +1086,15 @@ static int mkv_write_trailer(AVFormatCon
+     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 +1110,23 @@ AVOutputFormat matroska_muxer = {
+     .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 +1141,4 @@ AVOutputFormat matroska_audio_muxer = {
+     .flags = AVFMT_GLOBALHEADER,
+     .codec_tag = (const AVCodecTag* const []){ff_codec_wav_tags, 0},
+ };
++#endif
+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);
index f1970cbaed1063b74d49ddb2e23b5905789370e5..7a0c4b0ebacd2e3a2f09fdd26dad2850a7f21e32 100644 (file)
      # check system headers
      check_header stdint.h
      check_header pthread.h
+--- vpx/vpx_ports/vpx_integer.h        2010-05-18 17:58:33.000000000 +0200
++++ vpx_fixed/vpx_ports/vpx_integer.h  2010-05-23 01:41:37.000000000 +0200
+@@ -43,10 +43,6 @@
+ typedef signed char int_fast8_t;
+ typedef unsigned char uint_fast8_t;
+-#ifndef _UINTPTR_T_DEFINED
+-typedef unsigned int   uintptr_t;
+-#endif
+-
+ #endif
+ #endif