diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-27 00:43:19 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-27 00:43:19 +0000 |
commit | fbf03889bb066ffa0b99c58b60680ff73acdebda (patch) | |
tree | fba6df9c448e2309e9828b5e9a1b5a3991cbd062 | |
parent | 137e0863a23adcf500ecb9c7de67d83adbd6f747 (diff) | |
download | chromium_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.cc | 4 | ||||
-rw-r--r-- | media/base/demuxer_stream.h | 8 | ||||
-rw-r--r-- | media/base/mock_filters.h | 3 | ||||
-rw-r--r-- | media/base/video_decoder_config.cc | 43 | ||||
-rw-r--r-- | media/base/video_decoder_config.h | 22 | ||||
-rw-r--r-- | media/ffmpeg/ffmpeg_common.cc | 146 | ||||
-rw-r--r-- | media/ffmpeg/ffmpeg_common.h | 17 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.cc | 16 | ||||
-rw-r--r-- | media/filters/dummy_demuxer.cc | 5 | ||||
-rw-r--r-- | media/filters/dummy_demuxer.h | 3 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.cc | 13 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.h | 4 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer_unittest.cc | 35 | ||||
-rw-r--r-- | media/filters/ffmpeg_video_decoder.cc | 25 | ||||
-rw-r--r-- | media/filters/ffmpeg_video_decoder_unittest.cc | 45 | ||||
-rw-r--r-- | media/video/ffmpeg_video_decode_engine.cc | 22 | ||||
-rw-r--r-- | media/video/ffmpeg_video_decode_engine_unittest.cc | 7 |
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); |