summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-27 00:43:19 +0000
committerscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-27 00:43:19 +0000
commitfbf03889bb066ffa0b99c58b60680ff73acdebda (patch)
treefba6df9c448e2309e9828b5e9a1b5a3991cbd062
parent137e0863a23adcf500ecb9c7de67d83adbd6f747 (diff)
downloadchromium_src-fbf03889bb066ffa0b99c58b60680ff73acdebda.zip
chromium_src-fbf03889bb066ffa0b99c58b60680ff73acdebda.tar.gz
chromium_src-fbf03889bb066ffa0b99c58b60680ff73acdebda.tar.bz2
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
-rw-r--r--media/base/demuxer_stream.cc4
-rw-r--r--media/base/demuxer_stream.h8
-rw-r--r--media/base/mock_filters.h3
-rw-r--r--media/base/video_decoder_config.cc43
-rw-r--r--media/base/video_decoder_config.h22
-rw-r--r--media/ffmpeg/ffmpeg_common.cc146
-rw-r--r--media/ffmpeg/ffmpeg_common.h17
-rw-r--r--media/filters/chunk_demuxer.cc16
-rw-r--r--media/filters/dummy_demuxer.cc5
-rw-r--r--media/filters/dummy_demuxer.h3
-rw-r--r--media/filters/ffmpeg_demuxer.cc13
-rw-r--r--media/filters/ffmpeg_demuxer.h4
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc35
-rw-r--r--media/filters/ffmpeg_video_decoder.cc25
-rw-r--r--media/filters/ffmpeg_video_decoder_unittest.cc45
-rw-r--r--media/video/ffmpeg_video_decode_engine.cc22
-rw-r--r--media/video/ffmpeg_video_decode_engine_unittest.cc7
17 files changed, 251 insertions, 167 deletions
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 @@ namespace media {
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 @@ namespace media {
class AudioDecoderConfig;
class Buffer;
+class VideoDecoderConfig;
class MEDIA_EXPORT DemuxerStream
: public base::RefCountedThreadSafe<DemuxerStream> {
@@ -32,13 +33,14 @@ class MEDIA_EXPORT DemuxerStream
// 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 ee3c3d1..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 @@ class MockDemuxerStream : public DemuxerStream {
// 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 @@ VideoDecoderConfig::VideoDecoderConfig()
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 @@ VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
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 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
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 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
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 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
} 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 @@ gfx::Rect VideoDecoderConfig::visible_rect() const {
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 @@ int VideoDecoderConfig::frame_rate_denominator() const {
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 @@ class MEDIA_EXPORT VideoDecoderConfig {
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 @@ class MEDIA_EXPORT VideoDecoderConfig {
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 @@ class MEDIA_EXPORT VideoDecoderConfig {
// 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 @@ class MEDIA_EXPORT VideoDecoderConfig {
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 c7089c0..1b8a81c 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -83,6 +83,48 @@ static CodecID AudioCodecToCodecID(AudioCodec audio_codec,
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 @@ void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config,
}
}
-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 @@ PixelFormat VideoFormatToPixelFormat(VideoFrame::Format video_format) {
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 @@ void AudioDecoderConfigToAVCodecContext(
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 @@ VideoFrame::Format PixelFormatToVideoFormat(PixelFormat pixel_format);
// 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 @@ namespace media {
// 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 @@ class ChunkDemuxerStream : public DemuxerStream {
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 @@ ChunkDemuxerStream::ChunkDemuxerStream(Type type, AVStream* stream)
last_buffer_timestamp_(kNoTimestamp) {
if (type_ == AUDIO) {
AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_);
+ } else if (type_ == VIDEO) {
+ AVStreamToVideoDecoderConfig(stream, &video_config_);
}
}
@@ -271,13 +274,16 @@ DemuxerStream::Type ChunkDemuxerStream::type() { return type_; }
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 @@ const AudioDecoderConfig& DummyDemuxerStream::audio_decoder_config() {
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 1b74d01..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 @@ class DummyDemuxerStream : public DemuxerStream {
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 @@ class DummyDemuxerStream : public DemuxerStream {
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 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
break;
case AVMEDIA_TYPE_VIDEO:
type_ = VIDEO;
+ AVStreamToVideoDecoderConfig(stream, &video_config_);
break;
default:
NOTREACHED();
@@ -254,15 +255,16 @@ void FFmpegDemuxerStream::EnableBitstreamConverter() {
}
}
-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 @@ void FFmpegDemuxer::DisableAudioStreamTask() {
// 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 @@ class FFmpegDemuxerStream : public DemuxerStream {
// |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 @@ class FFmpegDemuxerStream : public DemuxerStream {
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 @@ TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
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 d540227..998eea9 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -58,22 +58,11 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
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 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
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 8b6a8e6..a2ba238 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -26,6 +26,7 @@ using ::testing::DoAll;
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 @@ using ::testing::Invoke;
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 @@ class FFmpegVideoDecoderTest : public testing::Test {
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 @@ class FFmpegVideoDecoderTest : public testing::Test {
}
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 @@ class FFmpegVideoDecoderTest : public testing::Test {
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 @@ void FFmpegVideoDecodeEngine::Initialize(
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 @@ void FFmpegVideoDecodeEngine::Initialize(
// 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 b4ce626..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::Size kCodedSize(320, 240);
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 @@ class FFmpegVideoDecodeEngineTest
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 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) {
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 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) {
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);