diff -urN -x.svn ffmpeg.orig/Changelog ffmpeg/Changelog
--- ffmpeg.orig/Changelog	Wed May 26 17:31:36 2010
+++ ffmpeg/Changelog	Wed May 26 17:21:20 2010
@@ -88,6 +88,8 @@
 - 35% faster VP3/Theora decoding
 - faster AAC decoding
 - faster H.264 decoding
+- VP8 de/encoding via libvpx
+- WebM support in Matroska de/muxer
 
 
 
diff -urN -x.svn ffmpeg.orig/configure ffmpeg/configure
--- ffmpeg.orig/configure	Wed May 26 17:31:36 2010
+++ ffmpeg/configure	Wed May 26 17:50:31 2010
@@ -1352,6 +1352,7 @@
 libtheora_encoder_deps="libtheora"
 libvorbis_encoder_deps="libvorbis"
 libvpx_decoder_deps="libvpx"
+libvpx_encoder_deps="libvpx"
 libx264_encoder_deps="libx264"
 libxvid_encoder_deps="libxvid"
 
@@ -2624,7 +2625,8 @@
 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     && require2 libvpx "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_dec_init_ver" -lvpx
+enabled libvpx     && require2 libvpx "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_dec_init_ver" -lvpx &&
+                      require2 libvpx_vp8 "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_enc_init_ver" -lvpx
 enabled libx264    && require  libx264 x264.h x264_encoder_encode -lx264 -lm -lpthread -lws2_32 &&
                       { check_cpp_condition x264.h "X264_BUILD >= 90" ||
                         die "ERROR: libx264 version must be >= 0.90."; }
diff -urN -x.svn ffmpeg.orig/doc/general.texi ffmpeg/doc/general.texi
--- ffmpeg.orig/doc/general.texi	Wed May 26 17:31:27 2010
+++ ffmpeg/doc/general.texi	Wed May 26 17:22:46 2010
@@ -236,7 +236,8 @@
 @item VC-1 test bitstream       @tab X @tab X
 @item WAV                       @tab X @tab X
 @item WavPack                   @tab   @tab X
-@item WebM                      @tab   @tab X
+@item WebM                      @tab X @tab X
+    @tab @url{http://www.webmproject.org/about}
 @item Wing Commander III movie  @tab   @tab X
     @tab Multimedia format used in Origin's Wing Commander III computer game.
 @item Westwood Studios audio    @tab   @tab X
@@ -439,7 +440,7 @@
     @tab fourcc: VP50
 @item On2 VP6                @tab     @tab  X
     @tab fourcc: VP60,VP61,VP62
-@item VP8                    @tab     @tab  X
+@item VP8                    @tab  X  @tab  X
     @tab fourcc: VP80, decoding supported through external library libvpx
 @item planar RGB             @tab     @tab  X
     @tab fourcc: 8BPS
diff -urN -x.svn ffmpeg.orig/ffpresets/libvpx-1080p.ffpreset ffmpeg/ffpresets/libvpx-1080p.ffpreset
--- ffmpeg.orig/ffpresets/libvpx-1080p.ffpreset	Thu Jan  1 09:00:00 1970
+++ ffmpeg/ffpresets/libvpx-1080p.ffpreset	Wed May 26 17:10:58 2010
@@ -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
diff -urN -x.svn ffmpeg.orig/ffpresets/libvpx-1080p50_60.ffpreset ffmpeg/ffpresets/libvpx-1080p50_60.ffpreset
--- ffmpeg.orig/ffpresets/libvpx-1080p50_60.ffpreset	Thu Jan  1 09:00:00 1970
+++ ffmpeg/ffpresets/libvpx-1080p50_60.ffpreset	Wed May 26 17:10:58 2010
@@ -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
diff -urN -x.svn ffmpeg.orig/ffpresets/libvpx-360p.ffpreset ffmpeg/ffpresets/libvpx-360p.ffpreset
--- ffmpeg.orig/ffpresets/libvpx-360p.ffpreset	Thu Jan  1 09:00:00 1970
+++ ffmpeg/ffpresets/libvpx-360p.ffpreset	Wed May 26 17:10:58 2010
@@ -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
diff -urN -x.svn ffmpeg.orig/ffpresets/libvpx-720p.ffpreset ffmpeg/ffpresets/libvpx-720p.ffpreset
--- ffmpeg.orig/ffpresets/libvpx-720p.ffpreset	Thu Jan  1 09:00:00 1970
+++ ffmpeg/ffpresets/libvpx-720p.ffpreset	Wed May 26 17:10:58 2010
@@ -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
diff -urN -x.svn ffmpeg.orig/ffpresets/libvpx-720p50_60.ffpreset ffmpeg/ffpresets/libvpx-720p50_60.ffpreset
--- ffmpeg.orig/ffpresets/libvpx-720p50_60.ffpreset	Thu Jan  1 09:00:00 1970
+++ ffmpeg/ffpresets/libvpx-720p50_60.ffpreset	Wed May 26 17:10:58 2010
@@ -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
diff -urN -x.svn ffmpeg.orig/libavcodec/Makefile ffmpeg/libavcodec/Makefile
--- ffmpeg.orig/libavcodec/Makefile	Wed May 26 17:31:11 2010
+++ ffmpeg/libavcodec/Makefile	Wed May 26 17:26:17 2010
@@ -512,6 +512,7 @@
                                           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
@@ -537,6 +538,7 @@
 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
 
diff -urN -x.svn ffmpeg.orig/libavcodec/allcodecs.c ffmpeg/libavcodec/allcodecs.c
--- ffmpeg.orig/libavcodec/allcodecs.c	Wed May 26 17:31:09 2010
+++ ffmpeg/libavcodec/allcodecs.c	Wed May 26 17:43:31 2010
@@ -349,7 +349,7 @@
     REGISTER_DECODER (LIBSPEEX, libspeex);
     REGISTER_ENCODER (LIBTHEORA, libtheora);
     REGISTER_ENCODER (LIBVORBIS, libvorbis);
-    REGISTER_DECODER (LIBVPX, libvpx);
+    REGISTER_ENCDEC  (LIBVPX, libvpx);
     REGISTER_ENCODER (LIBX264, libx264);
     REGISTER_ENCODER (LIBXVID, libxvid);
 
diff -urN -x.svn ffmpeg.orig/libavcodec/avcodec.h ffmpeg/libavcodec/avcodec.h
--- ffmpeg.orig/libavcodec/avcodec.h	Wed May 26 17:31:09 2010
+++ ffmpeg/libavcodec/avcodec.h	Wed May 26 17:23:45 2010
@@ -2664,6 +2664,160 @@
     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;
 
 /**
diff -urN -x.svn ffmpeg.orig/libavcodec/libvpxdec.c ffmpeg/libavcodec/libvpxdec.c
--- ffmpeg.orig/libavcodec/libvpxdec.c	Wed May 26 17:31:07 2010
+++ ffmpeg/libavcodec/libvpxdec.c	Wed May 26 17:25:10 2010
@@ -64,6 +64,10 @@
     const void *iter = NULL;
     struct vpx_image *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);
diff -urN -x.svn ffmpeg.orig/libavcodec/libvpxenc.c ffmpeg/libavcodec/libvpxenc.c
--- ffmpeg.orig/libavcodec/libvpxenc.c	Thu Jan  1 09:00:00 1970
+++ ffmpeg/libavcodec/libvpxenc.c	Wed May 26 17:49:20 2010
@@ -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/vpx_encoder.h>
+#include <vpx/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,VPX_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[VPX_PLANE_Y] = frame->data[0];
+    rawimg->planes[VPX_PLANE_U] = frame->data[1];
+    rawimg->planes[VPX_PLANE_V] = frame->data[2];
+    rawimg->stride[VPX_PLANE_Y] = frame->linesize[0];
+    rawimg->stride[VPX_PLANE_U] = frame->linesize[1];
+    rawimg->stride[VPX_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"),
+};
diff -urN -x.svn ffmpeg.orig/libavcodec/options.c ffmpeg/libavcodec/options.c
--- ffmpeg.orig/libavcodec/options.c	Wed May 26 17:31:08 2010
+++ ffmpeg/libavcodec/options.c	Wed May 26 17:40:11 2010
@@ -414,6 +414,19 @@
 {"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},
 };
 
diff -urN -x.svn ffmpeg.orig/libavformat/Makefile ffmpeg/libavformat/Makefile
--- ffmpeg.orig/libavformat/Makefile	Wed May 26 17:31:35 2010
+++ ffmpeg/libavformat/Makefile	Wed May 26 17:12:04 2010
@@ -258,6 +258,8 @@
 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
diff -urN -x.svn ffmpeg.orig/libavformat/allformats.c ffmpeg/libavformat/allformats.c
--- ffmpeg.orig/libavformat/allformats.c	Wed May 26 17:31:35 2010
+++ ffmpeg/libavformat/allformats.c	Wed May 26 17:12:04 2010
@@ -206,6 +206,7 @@
     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);
diff -urN -x.svn ffmpeg.orig/libavformat/matroskadec.c ffmpeg/libavformat/matroskadec.c
--- ffmpeg.orig/libavformat/matroskadec.c	Wed May 26 17:31:34 2010
+++ ffmpeg/libavformat/matroskadec.c	Wed May 26 17:28:05 2010
@@ -1155,10 +1155,15 @@
         return AVERROR_PATCHWELCOME;
     }
     for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++)
-        if (!strcmp(ebml.doctype, matroska_doctypes[i]))
+        if (!strcmp(ebml.doctype, matroska_doctypes[i])) {
+            av_log(s, AV_LOG_DEBUG, "EBML doctype '%s'\n", ebml.doctype);
+            av_metadata_set2(&s->metadata, "doctype", ebml.doctype, 0);
             break;
+        }
     if (i >= FF_ARRAY_ELEMS(matroska_doctypes)) {
-        av_log(s, AV_LOG_WARNING, "Unknown EBML doctype '%s'\n", ebml.doctype);
+        av_log(s, AV_LOG_ERROR, "Unknown EBML doctype '%s'\n", ebml.doctype);
+        ebml_free(ebml_syntax, &ebml);
+        return AVERROR_PATCHWELCOME;
     }
     ebml_free(ebml_syntax, &ebml);
 
diff -urN -x.svn ffmpeg.orig/libavformat/matroskaenc.c ffmpeg/libavformat/matroskaenc.c
--- ffmpeg.orig/libavformat/matroskaenc.c	Wed May 26 17:31:33 2010
+++ ffmpeg/libavformat/matroskaenc.c	Wed May 26 17:12:04 2010
@@ -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,17 @@
 
         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 +611,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 +625,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 +728,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 +781,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 +880,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 +961,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 +976,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 +1036,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 +1086,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 +1110,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 +1141,4 @@
     .flags = AVFMT_GLOBALHEADER,
     .codec_tag = (const AVCodecTag* const []){ff_codec_wav_tags, 0},
 };
+#endif
