Remove DemuxerStream::GetAVStream() once and for all.

We now use AudioDecoderConfig and VideoDecoderConfig to pass decoder initialization information.


Review URL: http://codereview.chromium.org/8341033

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@107494 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/media/base/demuxer_stream.cc b/media/base/demuxer_stream.cc
index 30adecc..daede65 100644
--- a/media/base/demuxer_stream.cc
+++ b/media/base/demuxer_stream.cc
@@ -8,8 +8,4 @@
 
 DemuxerStream::~DemuxerStream() {}
 
-AVStream* DemuxerStream::GetAVStream() {
-  return NULL;
-}
-
 }  // namespace media
diff --git a/media/base/demuxer_stream.h b/media/base/demuxer_stream.h
index e81423e..07dfe71 100644
--- a/media/base/demuxer_stream.h
+++ b/media/base/demuxer_stream.h
@@ -15,6 +15,7 @@
 
 class AudioDecoderConfig;
 class Buffer;
+class VideoDecoderConfig;
 
 class MEDIA_EXPORT DemuxerStream
     : public base::RefCountedThreadSafe<DemuxerStream> {
@@ -32,13 +33,14 @@
   // object takes ownership of the buffer by AddRef()'ing the buffer.
   virtual void Read(const ReadCallback& read_callback) = 0;
 
-  // Returns an |AVStream*| if supported, or NULL.
-  virtual AVStream* GetAVStream();
-
   // Returns the audio decoder configuration. It is an error to call this method
   // if type() != AUDIO.
   virtual const AudioDecoderConfig& audio_decoder_config() = 0;
 
+  // Returns the video decoder configuration. It is an error to call this method
+  // if type() != VIDEO.
+  virtual const VideoDecoderConfig& video_decoder_config() = 0;
+
   // Returns the type of stream.
   virtual Type type() = 0;
 
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index ee3c3d1b..8199b88 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -21,6 +21,7 @@
 #include "media/base/filters.h"
 #include "media/base/filter_collection.h"
 #include "media/base/pipeline.h"
+#include "media/base/video_decoder_config.h"
 #include "media/base/video_frame.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -161,8 +162,8 @@
   // DemuxerStream implementation.
   MOCK_METHOD0(type, Type());
   MOCK_METHOD1(Read, void(const ReadCallback& read_callback));
-  MOCK_METHOD0(GetAVStream, AVStream*());
   MOCK_METHOD0(audio_decoder_config, const AudioDecoderConfig&());
+  MOCK_METHOD0(video_decoder_config, const VideoDecoderConfig&());
   MOCK_METHOD0(EnableBitstreamConverter, void());
 
  protected:
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc
index 81583c1..d055f49 100644
--- a/media/base/video_decoder_config.cc
+++ b/media/base/video_decoder_config.cc
@@ -4,6 +4,8 @@
 
 #include "media/base/video_decoder_config.h"
 
+#include <cmath>
+
 #include "base/logging.h"
 
 namespace media {
@@ -13,6 +15,8 @@
       format_(VideoFrame::INVALID),
       frame_rate_numerator_(0),
       frame_rate_denominator_(0),
+      aspect_ratio_numerator_(0),
+      aspect_ratio_denominator_(0),
       extra_data_size_(0) {
 }
 
@@ -22,10 +26,13 @@
                                        const gfx::Rect& visible_rect,
                                        int frame_rate_numerator,
                                        int frame_rate_denominator,
+                                       int aspect_ratio_numerator,
+                                       int aspect_ratio_denominator,
                                        const uint8* extra_data,
                                        size_t extra_data_size) {
   Initialize(codec, format, coded_size, visible_rect,
              frame_rate_numerator, frame_rate_denominator,
+             aspect_ratio_numerator, aspect_ratio_denominator,
              extra_data, extra_data_size);
 }
 
@@ -37,6 +44,8 @@
                                     const gfx::Rect& visible_rect,
                                     int frame_rate_numerator,
                                     int frame_rate_denominator,
+                                    int aspect_ratio_numerator,
+                                    int aspect_ratio_denominator,
                                     const uint8* extra_data,
                                     size_t extra_data_size) {
   CHECK((extra_data_size != 0) == (extra_data != NULL));
@@ -47,6 +56,8 @@
   visible_rect_ = visible_rect;
   frame_rate_numerator_ = frame_rate_numerator;
   frame_rate_denominator_ = frame_rate_denominator;
+  aspect_ratio_numerator_ = aspect_ratio_numerator;
+  aspect_ratio_denominator_ = aspect_ratio_denominator;
   extra_data_size_ = extra_data_size;
 
   if (extra_data_size_ > 0) {
@@ -55,13 +66,31 @@
   } else {
     extra_data_.reset();
   }
+
+  // Calculate the natural size given the aspect ratio and visible rect.
+  if (aspect_ratio_denominator == 0) {
+    natural_size_.SetSize(0, 0);
+    return;
+  }
+
+  double aspect_ratio = aspect_ratio_numerator /
+      static_cast<double>(aspect_ratio_denominator);
+
+  int width = floor(visible_rect.width() * aspect_ratio + 0.5);
+  int height = visible_rect.height();
+
+  // An even width makes things easier for YV12 and appears to be the behavior
+  // expected by WebKit layout tests.
+  natural_size_.SetSize(width & ~1, height);
 }
 
 bool VideoDecoderConfig::IsValidConfig() const {
   return codec_ != kUnknownVideoCodec &&
       format_ != VideoFrame::INVALID &&
       frame_rate_numerator_ > 0 &&
-      frame_rate_denominator_ > 0;
+      frame_rate_denominator_ > 0 &&
+      aspect_ratio_numerator_ > 0 &&
+      aspect_ratio_denominator_ > 0;
 }
 
 VideoCodec VideoDecoderConfig::codec() const {
@@ -80,6 +109,10 @@
   return visible_rect_;
 }
 
+gfx::Size VideoDecoderConfig::natural_size() const {
+  return natural_size_;
+}
+
 int VideoDecoderConfig::frame_rate_numerator() const {
   return frame_rate_numerator_;
 }
@@ -88,6 +121,14 @@
   return frame_rate_denominator_;
 }
 
+int VideoDecoderConfig::aspect_ratio_numerator() const {
+  return aspect_ratio_numerator_;
+}
+
+int VideoDecoderConfig::aspect_ratio_denominator() const {
+  return aspect_ratio_denominator_;
+}
+
 uint8* VideoDecoderConfig::extra_data() const {
   return extra_data_.get();
 }
diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h
index 44182df4..00a19eb 100644
--- a/media/base/video_decoder_config.h
+++ b/media/base/video_decoder_config.h
@@ -42,6 +42,7 @@
                      const gfx::Size& coded_size,
                      const gfx::Rect& visible_rect,
                      int frame_rate_numerator, int frame_rate_denominator,
+                     int aspect_ratio_numerator, int aspect_ratio_denominator,
                      const uint8* extra_data, size_t extra_data_size);
 
   ~VideoDecoderConfig();
@@ -52,6 +53,7 @@
                   const gfx::Size& coded_size,
                   const gfx::Rect& visible_rect,
                   int frame_rate_numerator, int frame_rate_denominator,
+                  int aspect_ratio_numerator, int aspect_ratio_denominator,
                   const uint8* extra_data, size_t extra_data_size);
 
   // Returns true if this object has appropriate configuration values, false
@@ -70,11 +72,25 @@
   // Region of |coded_size_| that is visible.
   gfx::Rect visible_rect() const;
 
+  // Final visible width and height of a video frame with aspect ratio taken
+  // into account.
+  gfx::Size natural_size() const;
+
   // Frame rate in seconds expressed as a fraction.
-  // TODO(scherkus): fairly certain decoders don't require frame rates.
+  //
+  // This information is required to properly timestamp video frames for
+  // codecs that contain repeated frames, such as found in H.264's
+  // supplemental enhancement information.
   int frame_rate_numerator() const;
   int frame_rate_denominator() const;
 
+  // Aspect ratio of the decoded video frame expressed as a fraction.
+  //
+  // TODO(scherkus): think of a better way to avoid having video decoders
+  // handle tricky aspect ratio dimension calculations.
+  int aspect_ratio_numerator() const;
+  int aspect_ratio_denominator() const;
+
   // Optional byte data required to initialize video decoders, such as H.264
   // AAVC data.
   uint8* extra_data() const;
@@ -87,10 +103,14 @@
 
   gfx::Size coded_size_;
   gfx::Rect visible_rect_;
+  gfx::Size natural_size_;
 
   int frame_rate_numerator_;
   int frame_rate_denominator_;
 
+  int aspect_ratio_numerator_;
+  int aspect_ratio_denominator_;
+
   scoped_array<uint8> extra_data_;
   size_t extra_data_size_;
 
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index c7089c08c..1b8a81c65 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -83,6 +83,48 @@
   return CODEC_ID_NONE;
 }
 
+static VideoCodec CodecIDToVideoCodec(CodecID codec_id) {
+  switch (codec_id) {
+    case CODEC_ID_VC1:
+      return kCodecVC1;
+    case CODEC_ID_H264:
+      return kCodecH264;
+    case CODEC_ID_THEORA:
+      return kCodecTheora;
+    case CODEC_ID_MPEG2VIDEO:
+      return kCodecMPEG2;
+    case CODEC_ID_MPEG4:
+      return kCodecMPEG4;
+    case CODEC_ID_VP8:
+      return kCodecVP8;
+    default:
+      NOTREACHED();
+  }
+  return kUnknownVideoCodec;
+}
+
+static CodecID VideoCodecToCodecID(VideoCodec video_codec) {
+  switch (video_codec) {
+    case kUnknownVideoCodec:
+      return CODEC_ID_NONE;
+    case kCodecVC1:
+      return CODEC_ID_VC1;
+    case kCodecH264:
+      return CODEC_ID_H264;
+    case kCodecTheora:
+      return CODEC_ID_THEORA;
+    case kCodecMPEG2:
+      return CODEC_ID_MPEG2VIDEO;
+    case kCodecMPEG4:
+      return CODEC_ID_MPEG4;
+    case kCodecVP8:
+      return CODEC_ID_VP8;
+    default:
+      NOTREACHED();
+  }
+  return CODEC_ID_NONE;
+}
+
 void AVCodecContextToAudioDecoderConfig(
     const AVCodecContext* codec_context,
     AudioDecoderConfig* config) {
@@ -144,46 +186,53 @@
   }
 }
 
-VideoCodec CodecIDToVideoCodec(CodecID codec_id) {
-  switch (codec_id) {
-    case CODEC_ID_VC1:
-      return kCodecVC1;
-    case CODEC_ID_H264:
-      return kCodecH264;
-    case CODEC_ID_THEORA:
-      return kCodecTheora;
-    case CODEC_ID_MPEG2VIDEO:
-      return kCodecMPEG2;
-    case CODEC_ID_MPEG4:
-      return kCodecMPEG4;
-    case CODEC_ID_VP8:
-      return kCodecVP8;
-    default:
-      NOTREACHED();
-  }
-  return kUnknownVideoCodec;
+void AVStreamToVideoDecoderConfig(
+    const AVStream* stream,
+    VideoDecoderConfig* config) {
+  gfx::Size coded_size(stream->codec->coded_width, stream->codec->coded_height);
+
+  // TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true
+  // for now, but may not always be true forever. Fix this in the future.
+  gfx::Rect visible_rect(stream->codec->width, stream->codec->height);
+
+  AVRational aspect_ratio = { 1, 1 };
+  if (stream->sample_aspect_ratio.num)
+    aspect_ratio = stream->sample_aspect_ratio;
+  else if (stream->codec->sample_aspect_ratio.num)
+    aspect_ratio = stream->codec->sample_aspect_ratio;
+
+  config->Initialize(CodecIDToVideoCodec(stream->codec->codec_id),
+                     PixelFormatToVideoFormat(stream->codec->pix_fmt),
+                     coded_size, visible_rect,
+                     stream->r_frame_rate.num,
+                     stream->r_frame_rate.den,
+                     aspect_ratio.num,
+                     aspect_ratio.den,
+                     stream->codec->extradata,
+                     stream->codec->extradata_size);
 }
 
-CodecID VideoCodecToCodecID(VideoCodec video_codec) {
-  switch (video_codec) {
-    case kUnknownVideoCodec:
-      return CODEC_ID_NONE;
-    case kCodecVC1:
-      return CODEC_ID_VC1;
-    case kCodecH264:
-      return CODEC_ID_H264;
-    case kCodecTheora:
-      return CODEC_ID_THEORA;
-    case kCodecMPEG2:
-      return CODEC_ID_MPEG2VIDEO;
-    case kCodecMPEG4:
-      return CODEC_ID_MPEG4;
-    case kCodecVP8:
-      return CODEC_ID_VP8;
-    default:
-      NOTREACHED();
+void VideoDecoderConfigToAVCodecContext(
+    const VideoDecoderConfig& config,
+    AVCodecContext* codec_context) {
+  codec_context->codec_type = AVMEDIA_TYPE_VIDEO;
+  codec_context->codec_id = VideoCodecToCodecID(config.codec());
+  codec_context->coded_width = config.coded_size().width();
+  codec_context->coded_height = config.coded_size().height();
+  codec_context->pix_fmt = VideoFormatToPixelFormat(config.format());
+
+  if (config.extra_data()) {
+    codec_context->extradata_size = config.extra_data_size();
+    codec_context->extradata = reinterpret_cast<uint8_t*>(
+        av_malloc(config.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE));
+    memcpy(codec_context->extradata, config.extra_data(),
+           config.extra_data_size());
+    memset(codec_context->extradata + config.extra_data_size(), '\0',
+           FF_INPUT_BUFFER_PADDING_SIZE);
+  } else {
+    codec_context->extradata = NULL;
+    codec_context->extradata_size = 0;
   }
-  return CODEC_ID_NONE;
 }
 
 ChannelLayout ChannelLayoutToChromeChannelLayout(int64_t layout,
@@ -255,27 +304,14 @@
   return PIX_FMT_NONE;
 }
 
-base::TimeDelta GetFrameDuration(AVStream* stream) {
-  AVRational time_base = { stream->r_frame_rate.den, stream->r_frame_rate.num };
+base::TimeDelta GetFrameDuration(const VideoDecoderConfig& config) {
+  AVRational time_base = {
+    config.frame_rate_denominator(),
+    config.frame_rate_numerator()
+  };
   return ConvertFromTimeBase(time_base, 1);
 }
 
-gfx::Size GetNaturalSize(AVStream* stream) {
-  double aspect_ratio = 1.0;
-
-  if (stream->sample_aspect_ratio.num)
-    aspect_ratio = av_q2d(stream->sample_aspect_ratio);
-  else if (stream->codec->sample_aspect_ratio.num)
-    aspect_ratio = av_q2d(stream->codec->sample_aspect_ratio);
-
-  int height = stream->codec->height;
-  int width = floor(stream->codec->width * aspect_ratio + 0.5);
-
-  // An even width makes things easier for YV12 and appears to be the behavior
-  // expected by WebKit layout tests.
-  return gfx::Size(width & ~1, height);
-}
-
 void DestroyAVFormatContext(AVFormatContext* format_context) {
   DCHECK(format_context);
 
diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h
index 8808f45..bb01f4f 100644
--- a/media/ffmpeg/ffmpeg_common.h
+++ b/media/ffmpeg/ffmpeg_common.h
@@ -74,8 +74,12 @@
     const AudioDecoderConfig& config,
     AVCodecContext* codec_context);
 
-VideoCodec CodecIDToVideoCodec(CodecID codec_id);
-CodecID VideoCodecToCodecID(VideoCodec video_codec);
+void AVStreamToVideoDecoderConfig(
+    const AVStream* stream,
+    VideoDecoderConfig* config);
+void VideoDecoderConfigToAVCodecContext(
+    const VideoDecoderConfig& config,
+    AVCodecContext* codec_context);
 
 // Converts FFmpeg's channel layout to chrome's ChannelLayout.  |channels| can
 // be used when FFmpeg's channel layout is not informative in order to make a
@@ -89,12 +93,9 @@
 // Converts video formats to its corresponding FFmpeg's pixel formats.
 PixelFormat VideoFormatToPixelFormat(VideoFrame::Format video_format);
 
-// Calculates duration of one frame in the |stream| based on its frame rate.
-base::TimeDelta GetFrameDuration(AVStream* stream);
-
-// Calculates the natural width and height of the video using the video's
-// encoded dimensions and sample_aspect_ratio.
-gfx::Size GetNaturalSize(AVStream* stream);
+// Calculates the duration of one frame based on the frame rate specified by
+// |config|.
+base::TimeDelta GetFrameDuration(const VideoDecoderConfig& config);
 
 // Closes & destroys all AVStreams in the context and then closes &
 // destroys the AVFormatContext.
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index b75a71a..383b9e3 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -29,8 +29,8 @@
 // we are making the INFO & TRACKS data look like a small WebM
 // file so we can use FFmpeg to initialize the AVFormatContext.
 //
-// TODO(acolwell): Remove this once GetAVStream() has been removed from
-// the DemuxerStream interface.
+// TODO(acolwell): Remove this when we construct AudioDecoderConfig and
+// VideoDecoderConfig without requiring an AVStream object.
 static const uint8 kWebMHeader[] = {
   0x1A, 0x45, 0xDF, 0xA3, 0x9F,  // EBML (size = 0x1f)
   0x42, 0x86, 0x81, 0x01,  // EBMLVersion = 1
@@ -79,13 +79,14 @@
   virtual void Read(const ReadCallback& read_callback);
   virtual Type type();
   virtual void EnableBitstreamConverter();
-  virtual AVStream* GetAVStream();
   virtual const AudioDecoderConfig& audio_decoder_config();
+  virtual const VideoDecoderConfig& video_decoder_config();
 
  private:
   Type type_;
   AVStream* av_stream_;
   AudioDecoderConfig audio_config_;
+  VideoDecoderConfig video_config_;
 
   mutable base::Lock lock_;
   ReadCBQueue read_cbs_;
@@ -109,6 +110,8 @@
       last_buffer_timestamp_(kNoTimestamp) {
   if (type_ == AUDIO) {
     AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_);
+  } else if (type_ == VIDEO) {
+    AVStreamToVideoDecoderConfig(stream, &video_config_);
   }
 }
 
@@ -271,13 +274,16 @@
 
 void ChunkDemuxerStream::EnableBitstreamConverter() {}
 
-AVStream* ChunkDemuxerStream::GetAVStream() { return av_stream_; }
-
 const AudioDecoderConfig& ChunkDemuxerStream::audio_decoder_config() {
   CHECK_EQ(type_, AUDIO);
   return audio_config_;
 }
 
+const VideoDecoderConfig& ChunkDemuxerStream::video_decoder_config() {
+  CHECK_EQ(type_, VIDEO);
+  return video_config_;
+}
+
 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
     : state_(WAITING_FOR_INIT),
       client_(client),
diff --git a/media/filters/dummy_demuxer.cc b/media/filters/dummy_demuxer.cc
index a9afbfc..24307b9 100644
--- a/media/filters/dummy_demuxer.cc
+++ b/media/filters/dummy_demuxer.cc
@@ -23,6 +23,11 @@
   return audio_config_;
 }
 
+const VideoDecoderConfig& DummyDemuxerStream::video_decoder_config() {
+  CHECK_EQ(type_, VIDEO);
+  return video_config_;
+}
+
 void DummyDemuxerStream::Read(const ReadCallback& read_callback) {}
 
 void DummyDemuxerStream::EnableBitstreamConverter() {}
diff --git a/media/filters/dummy_demuxer.h b/media/filters/dummy_demuxer.h
index 1b74d010..b029aa5 100644
--- a/media/filters/dummy_demuxer.h
+++ b/media/filters/dummy_demuxer.h
@@ -13,6 +13,7 @@
 
 #include "media/base/audio_decoder_config.h"
 #include "media/base/demuxer.h"
+#include "media/base/video_decoder_config.h"
 
 namespace media {
 
@@ -24,6 +25,7 @@
   virtual void Read(const ReadCallback& read_callback) OVERRIDE;
   virtual Type type() OVERRIDE;
   virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
+  virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
   virtual void EnableBitstreamConverter() OVERRIDE;
 
  private:
@@ -31,6 +33,7 @@
 
   Type type_;
   AudioDecoderConfig audio_config_;
+  VideoDecoderConfig video_config_;
 
   DISALLOW_COPY_AND_ASSIGN(DummyDemuxerStream);
 };
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 45e5298..0c63fde 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -73,6 +73,7 @@
       break;
     case AVMEDIA_TYPE_VIDEO:
       type_ = VIDEO;
+      AVStreamToVideoDecoderConfig(stream, &video_config_);
       break;
     default:
       NOTREACHED();
@@ -254,15 +255,16 @@
   }
 }
 
-AVStream* FFmpegDemuxerStream::GetAVStream() {
-  return stream_;
-}
-
 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() {
   CHECK_EQ(type_, AUDIO);
   return audio_config_;
 }
 
+const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() {
+  CHECK_EQ(type_, VIDEO);
+  return video_config_;
+}
+
 // static
 base::TimeDelta FFmpegDemuxerStream::ConvertStreamTimestamp(
     const AVRational& time_base, int64 timestamp) {
@@ -684,8 +686,7 @@
     // If the codec type is audio, remove the reference. DemuxTask() will
     // look for such reference, and this will result in deleting the
     // audio packets after they are demuxed.
-    if (packet_streams_[i]->GetAVStream()->codec->codec_type ==
-        AVMEDIA_TYPE_AUDIO) {
+    if (packet_streams_[i]->type() == DemuxerStream::AUDIO) {
       packet_streams_[i] = NULL;
     }
   }
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 1c1dfc2..8bf7705 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -32,6 +32,7 @@
 #include "media/base/buffers.h"
 #include "media/base/demuxer.h"
 #include "media/base/pipeline.h"
+#include "media/base/video_decoder_config.h"
 #include "media/filters/ffmpeg_glue.h"
 
 // FFmpeg forward declarations.
@@ -81,8 +82,8 @@
   // |lock_| is held throughout the life of the callback.
   virtual void Read(const ReadCallback& read_callback) OVERRIDE;
   virtual void EnableBitstreamConverter() OVERRIDE;
-  virtual AVStream* GetAVStream() OVERRIDE;
   virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
+  virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
 
  private:
   virtual ~FFmpegDemuxerStream();
@@ -102,6 +103,7 @@
   FFmpegDemuxer* demuxer_;
   AVStream* stream_;
   AudioDecoderConfig audio_config_;
+  VideoDecoderConfig video_config_;
   Type type_;
   base::TimeDelta duration_;
   bool discontinuous_;
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index 64c6095..4af3060 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -182,22 +182,35 @@
       demuxer_->GetStream(DemuxerStream::VIDEO);
   ASSERT_TRUE(stream);
   EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
-  ASSERT_TRUE(stream->GetAVStream());
+
+  const VideoDecoderConfig& video_config = stream->video_decoder_config();
+  EXPECT_EQ(kCodecVP8, video_config.codec());
+  EXPECT_EQ(VideoFrame::YV12, video_config.format());
+  EXPECT_EQ(320, video_config.coded_size().width());
+  EXPECT_EQ(240, video_config.coded_size().height());
+  EXPECT_EQ(0, video_config.visible_rect().x());
+  EXPECT_EQ(0, video_config.visible_rect().y());
+  EXPECT_EQ(320, video_config.visible_rect().width());
+  EXPECT_EQ(240, video_config.visible_rect().height());
+  EXPECT_EQ(30000, video_config.frame_rate_numerator());
+  EXPECT_EQ(1001, video_config.frame_rate_denominator());
+  EXPECT_EQ(1, video_config.aspect_ratio_numerator());
+  EXPECT_EQ(1, video_config.aspect_ratio_denominator());
+  EXPECT_FALSE(video_config.extra_data());
+  EXPECT_EQ(0u, video_config.extra_data_size());
 
   // Audio stream should be present.
   stream = demuxer_->GetStream(DemuxerStream::AUDIO);
   ASSERT_TRUE(stream);
   EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
-  ASSERT_TRUE(stream->GetAVStream());
 
-  // FFmpegDemuxer's audio streams support AudioDecoderConfig structs.
-  const AudioDecoderConfig& config = stream->audio_decoder_config();
-  EXPECT_EQ(kCodecVorbis, config.codec());
-  EXPECT_EQ(16, config.bits_per_channel());
-  EXPECT_EQ(CHANNEL_LAYOUT_STEREO, config.channel_layout());
-  EXPECT_EQ(44100, config.samples_per_second());
-  EXPECT_TRUE(config.extra_data());
-  EXPECT_GT(config.extra_data_size(), 0u);
+  const AudioDecoderConfig& audio_config = stream->audio_decoder_config();
+  EXPECT_EQ(kCodecVorbis, audio_config.codec());
+  EXPECT_EQ(16, audio_config.bits_per_channel());
+  EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout());
+  EXPECT_EQ(44100, audio_config.samples_per_second());
+  EXPECT_TRUE(audio_config.extra_data());
+  EXPECT_GT(audio_config.extra_data_size(), 0u);
 }
 
 TEST_F(FFmpegDemuxerTest, Read_Audio) {
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index d5402279..998eea9 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -58,22 +58,11 @@
   initialize_callback_ = callback;
   statistics_callback_ = stats_callback;
 
-  AVStream* av_stream = demuxer_stream->GetAVStream();
-  if (!av_stream) {
-    OnInitializeComplete(false);
-    return;
-  }
+  const VideoDecoderConfig& config = demuxer_stream->video_decoder_config();
 
-  pts_stream_.Initialize(GetFrameDuration(av_stream));
+  pts_stream_.Initialize(GetFrameDuration(config));
 
-  gfx::Size coded_size(
-      av_stream->codec->coded_width, av_stream->codec->coded_height);
-  // TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true
-  // for now, but may not always be true forever. Fix this in the future.
-  gfx::Rect visible_rect(
-      av_stream->codec->width, av_stream->codec->height);
-
-  natural_size_ = GetNaturalSize(av_stream);
+  natural_size_ = config.natural_size();
   if (natural_size_.width() > Limits::kMaxDimension ||
       natural_size_.height() > Limits::kMaxDimension ||
       natural_size_.GetArea() > Limits::kMaxCanvas) {
@@ -81,14 +70,6 @@
     return;
   }
 
-  VideoDecoderConfig config(CodecIDToVideoCodec(av_stream->codec->codec_id),
-                            PixelFormatToVideoFormat(av_stream->codec->pix_fmt),
-                            coded_size, visible_rect,
-                            av_stream->r_frame_rate.num,
-                            av_stream->r_frame_rate.den,
-                            av_stream->codec->extradata,
-                            av_stream->codec->extradata_size);
-
   state_ = kInitializing;
   decode_engine_->Initialize(message_loop_, this, NULL, config);
 }
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 8b6a8e64..a2ba238 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -26,6 +26,7 @@
 using ::testing::Message;
 using ::testing::Return;
 using ::testing::ReturnNull;
+using ::testing::ReturnRef;
 using ::testing::SetArgumentPointee;
 using ::testing::StrictMock;
 using ::testing::WithArg;
@@ -33,9 +34,12 @@
 
 namespace media {
 
+static const VideoFrame::Format kVideoFormat = VideoFrame::YV12;
 static const gfx::Size kCodedSize(1280, 720);
 static const gfx::Rect kVisibleRect(1280, 720);
 static const gfx::Size kNaturalSize(1280, 720);
+static const AVRational kFrameRate = { 100, 1 };
+static const AVRational kAspectRatio = { 1, 1 };
 
 // Holds timestamp and duration data needed for properly enqueuing a frame.
 struct TimeTuple {
@@ -134,26 +138,22 @@
     demuxer_ = new StrictMock<MockDemuxerStream>();
 
     // Initialize FFmpeg fixtures.
-    memset(&stream_, 0, sizeof(stream_));
-    memset(&codec_context_, 0, sizeof(codec_context_));
-    memset(&codec_, 0, sizeof(codec_));
     memset(&yuv_frame_, 0, sizeof(yuv_frame_));
     base::TimeDelta zero;
     video_frame_ = VideoFrame::CreateFrame(VideoFrame::YV12,
                                            kVisibleRect.width(),
                                            kVisibleRect.height(),
                                            zero, zero);
-    stream_.codec = &codec_context_;
-    codec_context_.width = kVisibleRect.width();
-    codec_context_.height = kVisibleRect.height();
-    codec_context_.codec_id = CODEC_ID_H264;
-    stream_.r_frame_rate.num = 1;
-    stream_.r_frame_rate.den = 1;
     buffer_ = new DataBuffer(1);
     end_of_stream_buffer_ = new DataBuffer(0);
 
     EXPECT_CALL(stats_callback_object_, OnStatistics(_))
         .Times(AnyNumber());
+
+    config_.Initialize(kCodecVP8, kVideoFormat, kCodedSize, kVisibleRect,
+                       kFrameRate.num, kFrameRate.den,
+                       kAspectRatio.num, kAspectRatio.den,
+                       NULL, 0);
   }
 
   virtual ~FFmpegVideoDecoderTest() {
@@ -170,9 +170,8 @@
   }
 
   void InitializeDecoderSuccessfully() {
-    // Test successful initialization.
-    EXPECT_CALL(*demuxer_, GetAVStream())
-        .WillOnce(Return(&stream_));
+    EXPECT_CALL(*demuxer_, video_decoder_config())
+        .WillOnce(ReturnRef(config_));
 
     EXPECT_CALL(*engine_, Initialize(_, _, _, _))
         .WillOnce(EngineInitialize(engine_, true));
@@ -199,32 +198,18 @@
   MessageLoop message_loop_;
 
   // FFmpeg fixtures.
-  AVStream stream_;
-  AVCodecContext codec_context_;
-  AVCodec codec_;
   AVFrame yuv_frame_;
   scoped_refptr<VideoFrame> video_frame_;
 
+  VideoDecoderConfig config_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecoderTest);
 };
 
-TEST_F(FFmpegVideoDecoderTest, Initialize_GetAVStreamFails) {
-  // Test GetAVStream returning NULL.
-  EXPECT_CALL(*demuxer_, GetAVStream())
-      .WillOnce(ReturnNull());
-  EXPECT_CALL(host_, SetError(PIPELINE_ERROR_DECODE));
-
-  decoder_->Initialize(demuxer_,
-                       NewExpectedClosure(), NewStatisticsCallback());
-
-  message_loop_.RunAllPending();
-}
-
 TEST_F(FFmpegVideoDecoderTest, Initialize_EngineFails) {
-  // Test successful initialization.
-  EXPECT_CALL(*demuxer_, GetAVStream())
-      .WillOnce(Return(&stream_));
+  EXPECT_CALL(*demuxer_, video_decoder_config())
+      .WillOnce(ReturnRef(config_));
 
   EXPECT_CALL(*engine_, Initialize(_, _, _, _))
       .WillOnce(EngineInitialize(engine_, false));
diff --git a/media/video/ffmpeg_video_decode_engine.cc b/media/video/ffmpeg_video_decode_engine.cc
index 0fe4810..05af31f 100644
--- a/media/video/ffmpeg_video_decode_engine.cc
+++ b/media/video/ffmpeg_video_decode_engine.cc
@@ -41,6 +41,9 @@
     VideoDecodeEngine::EventHandler* event_handler,
     VideoDecodeContext* context,
     const VideoDecoderConfig& config) {
+  frame_rate_numerator_ = config.frame_rate_numerator();
+  frame_rate_denominator_ = config.frame_rate_denominator();
+
   // Always try to use three threads for video decoding.  There is little reason
   // not to since current day CPUs tend to be multi-core and we measured
   // performance benefits on older machines such as P4s with hyperthreading.
@@ -55,24 +58,7 @@
 
   // Initialize AVCodecContext structure.
   codec_context_ = avcodec_alloc_context();
-  codec_context_->pix_fmt = VideoFormatToPixelFormat(config.format());
-  codec_context_->codec_type = AVMEDIA_TYPE_VIDEO;
-  codec_context_->codec_id = VideoCodecToCodecID(config.codec());
-  codec_context_->coded_width = config.coded_size().width();
-  codec_context_->coded_height = config.coded_size().height();
-
-  frame_rate_numerator_ = config.frame_rate_numerator();
-  frame_rate_denominator_ = config.frame_rate_denominator();
-
-  if (config.extra_data() != NULL) {
-    codec_context_->extradata_size = config.extra_data_size();
-    codec_context_->extradata = reinterpret_cast<uint8_t*>(
-        av_malloc(config.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE));
-    memcpy(codec_context_->extradata, config.extra_data(),
-           config.extra_data_size());
-    memset(codec_context_->extradata + config.extra_data_size(), '\0',
-           FF_INPUT_BUFFER_PADDING_SIZE);
-  }
+  VideoDecoderConfigToAVCodecContext(config, codec_context_);
 
   // Enable motion vector search (potentially slow), strong deblocking filter
   // for damaged macroblocks, and set our error detection sensitivity.
diff --git a/media/video/ffmpeg_video_decode_engine_unittest.cc b/media/video/ffmpeg_video_decode_engine_unittest.cc
index b4ce6265..c5469b4 100644
--- a/media/video/ffmpeg_video_decode_engine_unittest.cc
+++ b/media/video/ffmpeg_video_decode_engine_unittest.cc
@@ -27,6 +27,7 @@
 static const gfx::Rect kVisibleRect(320, 240);
 static const gfx::Size kNaturalSize(522, 288);
 static const AVRational kFrameRate = { 100, 1 };
+static const AVRational kAspectRatio = { 1, 1 };
 
 ACTION_P2(DemuxComplete, engine, buffer) {
   engine->ConsumeVideoSample(buffer);
@@ -38,7 +39,9 @@
  public:
   FFmpegVideoDecodeEngineTest()
       : config_(kCodecVP8, kVideoFormat, kCodedSize, kVisibleRect,
-                kFrameRate.num, kFrameRate.den, NULL, 0) {
+                kFrameRate.num, kFrameRate.den,
+                kAspectRatio.num, kAspectRatio.den,
+                NULL, 0) {
     CHECK(FFmpegGlue::GetInstance());
 
     // Setup FFmpeg structures.
@@ -146,6 +149,7 @@
   VideoDecoderConfig config(kUnknownVideoCodec, kVideoFormat,
                             kCodedSize, kVisibleRect,
                             kFrameRate.num, kFrameRate.den,
+                            kAspectRatio.num, kAspectRatio.den,
                             NULL, 0);
 
   // Test avcodec_find_decoder() returning NULL.
@@ -158,6 +162,7 @@
   VideoDecoderConfig config(kCodecTheora, kVideoFormat,
                             kCodedSize, kVisibleRect,
                             kFrameRate.num, kFrameRate.den,
+                            kAspectRatio.num, kAspectRatio.den,
                             NULL, 0);
   EXPECT_CALL(*this, OnInitializeComplete(false));
   test_engine_->Initialize(MessageLoop::current(), this, NULL, config);