diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-11 22:31:24 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-11 22:31:24 +0000 |
commit | 0b5f7e52bab18455a11ea763ae424f30755dc20f (patch) | |
tree | ddcfd55906e694285269a2bf683175d2320cab95 /media | |
parent | 33cdc9b854044864f7494c23a21f78733a961236 (diff) | |
download | chromium_src-0b5f7e52bab18455a11ea763ae424f30755dc20f.zip chromium_src-0b5f7e52bab18455a11ea763ae424f30755dc20f.tar.gz chromium_src-0b5f7e52bab18455a11ea763ae424f30755dc20f.tar.bz2 |
Remove FFmpegVideoDecodeEngine's dependency on AVStream (again).
First step of many towards removing DemuxerStream::QueryInterface, AVStreamProvider, and MediaFormat.
This time without memory leaks!
BUG=28206
TEST=media_unittests
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77875 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/mock_ffmpeg.cc | 4 | ||||
-rw-r--r-- | media/base/mock_ffmpeg.h | 1 | ||||
-rw-r--r-- | media/ffmpeg/ffmpeg_common.cc | 42 | ||||
-rw-r--r-- | media/ffmpeg/ffmpeg_common.h | 4 | ||||
-rw-r--r-- | media/filters/ffmpeg_video_decoder.cc | 30 | ||||
-rw-r--r-- | media/filters/omx_video_decoder.cc | 28 | ||||
-rw-r--r-- | media/tools/omx_test/omx_test.cc | 31 | ||||
-rw-r--r-- | media/video/ffmpeg_video_decode_engine.cc | 62 | ||||
-rw-r--r-- | media/video/ffmpeg_video_decode_engine.h | 13 | ||||
-rw-r--r-- | media/video/ffmpeg_video_decode_engine_unittest.cc | 90 | ||||
-rw-r--r-- | media/video/mft_h264_decode_engine.cc | 8 | ||||
-rw-r--r-- | media/video/mft_h264_decode_engine.h | 6 | ||||
-rw-r--r-- | media/video/omx_video_decode_engine.cc | 10 | ||||
-rw-r--r-- | media/video/omx_video_decode_engine.h | 6 | ||||
-rw-r--r-- | media/video/video_decode_engine.cc | 59 | ||||
-rw-r--r-- | media/video/video_decode_engine.h | 48 |
16 files changed, 271 insertions, 171 deletions
diff --git a/media/base/mock_ffmpeg.cc b/media/base/mock_ffmpeg.cc index ec19b1b..f1e28f9 100644 --- a/media/base/mock_ffmpeg.cc +++ b/media/base/mock_ffmpeg.cc @@ -120,6 +120,10 @@ void avcodec_flush_buffers(AVCodecContext* avctx) { return MockFFmpeg::get()->AVCodecFlushBuffers(avctx); } +AVCodecContext* avcodec_alloc_context() { + return MockFFmpeg::get()->AVCodecAllocContext(); +} + AVFrame* avcodec_alloc_frame() { return MockFFmpeg::get()->AVCodecAllocFrame(); } diff --git a/media/base/mock_ffmpeg.h b/media/base/mock_ffmpeg.h index 89402fe..b004aa4 100644 --- a/media/base/mock_ffmpeg.h +++ b/media/base/mock_ffmpeg.h @@ -28,6 +28,7 @@ class MockFFmpeg { MOCK_METHOD1(AVCodecClose, int(AVCodecContext* avctx)); MOCK_METHOD2(AVCodecThreadInit, int(AVCodecContext* avctx, int threads)); MOCK_METHOD1(AVCodecFlushBuffers, void(AVCodecContext* avctx)); + MOCK_METHOD0(AVCodecAllocContext, AVCodecContext*()); MOCK_METHOD0(AVCodecAllocFrame, AVFrame*()); MOCK_METHOD4(AVCodecDecodeVideo2, int(AVCodecContext* avctx, AVFrame* picture, diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc index 244d2729..dce96a5 100644 --- a/media/ffmpeg/ffmpeg_common.cc +++ b/media/ffmpeg/ffmpeg_common.cc @@ -4,8 +4,50 @@ #include "media/ffmpeg/ffmpeg_common.h" +#include "base/logging.h" + namespace media { // TODO(scherkus): combine ffmpeg_common.h with ffmpeg_util.h +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 kUnknown; +} + +CodecID VideoCodecToCodecID(VideoCodec video_codec) { + switch (video_codec) { + 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; +} + } // namespace media diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h index 714a6a1..3b0d0ee 100644 --- a/media/ffmpeg/ffmpeg_common.h +++ b/media/ffmpeg/ffmpeg_common.h @@ -10,6 +10,7 @@ #include "base/compiler_specific.h" #include "base/singleton.h" +#include "media/video/video_decode_engine.h" // Include FFmpeg header files. extern "C" { @@ -48,6 +49,9 @@ class ScopedPtrAVFreePacket { } }; +VideoCodec CodecIDToVideoCodec(CodecID codec_id); +CodecID VideoCodecToCodecID(VideoCodec video_codec); + } // namespace media #endif // MEDIA_FFMPEG_FFMPEG_COMMON_H_ diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc index 698423b..313d55c 100644 --- a/media/filters/ffmpeg_video_decoder.cc +++ b/media/filters/ffmpeg_video_decoder.cc @@ -67,8 +67,8 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, time_base_->den = av_stream->r_frame_rate.num; time_base_->num = av_stream->r_frame_rate.den; - int width = av_stream->codec->width; - int height = av_stream->codec->height; + int width = av_stream->codec->coded_width; + int height = av_stream->codec->coded_height; if (width > Limits::kMaxDimension || height > Limits::kMaxDimension || (width * height) > Limits::kMaxCanvas) { @@ -77,26 +77,12 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, return; } - VideoCodecConfig config; - switch (av_stream->codec->codec_id) { - case CODEC_ID_VC1: - config.codec = kCodecVC1; break; - case CODEC_ID_H264: - config.codec = kCodecH264; break; - case CODEC_ID_THEORA: - config.codec = kCodecTheora; break; - case CODEC_ID_MPEG2VIDEO: - config.codec = kCodecMPEG2; break; - case CODEC_ID_MPEG4: - config.codec = kCodecMPEG4; break; - case CODEC_ID_VP8: - config.codec = kCodecVP8; break; - default: - NOTREACHED(); - } - config.opaque_context = av_stream; - config.width = width; - config.height = height; + VideoCodecConfig config(CodecIDToVideoCodec(av_stream->codec->codec_id), + width, height, + 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/omx_video_decoder.cc b/media/filters/omx_video_decoder.cc index c8962a3..0dc25f9 100644 --- a/media/filters/omx_video_decoder.cc +++ b/media/filters/omx_video_decoder.cc @@ -62,8 +62,8 @@ void OmxVideoDecoder::Initialize(DemuxerStream* demuxer_stream, } AVStream* av_stream = av_stream_provider->GetAVStream(); - int width = av_stream->codec->width; - int height = av_stream->codec->height; + int width = av_stream->codec->coded_width; + int height = av_stream->codec->coded_height; if (width > Limits::kMaxDimension || height > Limits::kMaxDimension || (width * height) > Limits::kMaxCanvas) { @@ -72,24 +72,12 @@ void OmxVideoDecoder::Initialize(DemuxerStream* demuxer_stream, return; } - VideoCodecConfig config; - switch (av_stream->codec->codec_id) { - case CODEC_ID_VC1: - config.codec = kCodecVC1; break; - case CODEC_ID_H264: - config.codec = kCodecH264; break; - case CODEC_ID_THEORA: - config.codec = kCodecTheora; break; - case CODEC_ID_MPEG2VIDEO: - config.codec = kCodecMPEG2; break; - case CODEC_ID_MPEG4: - config.codec = kCodecMPEG4; break; - default: - NOTREACHED(); - } - config.opaque_context = NULL; - config.width = width; - config.height = height; + VideoCodecConfig config(CodecIDToVideoCodec(av_stream->codec->codec_id), + width, height, + av_stream->r_frame_rate.num, + av_stream->r_frame_rate.den, + av_stream->codec->extradata, + av_stream->codec->extradata_size); decode_engine_->Initialize(message_loop_, this, NULL, config); } diff --git a/media/tools/omx_test/omx_test.cc b/media/tools/omx_test/omx_test.cc index 24cf4cc..2821f08 100644 --- a/media/tools/omx_test/omx_test.cc +++ b/media/tools/omx_test/omx_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -170,26 +170,15 @@ class TestApp : public base::RefCountedThreadSafe<TestApp>, void Run() { StartProfiler(); - // Setup the |engine_| with the message loop of the current thread. Also - // setup codec format and callbacks. - media::VideoCodecConfig config; - switch (av_stream_->codec->codec_id) { - case CODEC_ID_VC1: - config.codec = media::kCodecVC1; break; - case CODEC_ID_H264: - config.codec = media::kCodecH264; break; - case CODEC_ID_THEORA: - config.codec = media::kCodecTheora; break; - case CODEC_ID_MPEG2VIDEO: - config.codec = media::kCodecMPEG2; break; - case CODEC_ID_MPEG4: - config.codec = media::kCodecMPEG4; break; - default: - NOTREACHED(); break; - } - config.opaque_context = NULL; - config.width = av_stream_->codec->width; - config.height = av_stream_->codec->height; + media::VideoCodecConfig config( + media::CodecIDToVideoCodec(av_stream_->codec->codec_id), + av_stream_->codec->coded_width, + av_stream_->codec->coded_height, + av_stream_->r_frame_rate.num, + av_stream_->r_frame_rate.den, + av_stream_->codec->extradata, + av_stream_->codec->extradata_size); + engine_.reset(new OmxVideoDecodeEngine()); engine_->Initialize(&message_loop_, this, NULL, config); diff --git a/media/video/ffmpeg_video_decode_engine.cc b/media/video/ffmpeg_video_decode_engine.cc index 786be41..20fc480 100644 --- a/media/video/ffmpeg_video_decode_engine.cc +++ b/media/video/ffmpeg_video_decode_engine.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -21,8 +21,9 @@ namespace media { FFmpegVideoDecodeEngine::FFmpegVideoDecodeEngine() : codec_context_(NULL), - av_stream_(NULL), event_handler_(NULL), + frame_rate_numerator_(0), + frame_rate_denominator_(0), direct_rendering_(false), pending_input_buffers_(0), pending_output_buffers_(0), @@ -31,6 +32,11 @@ FFmpegVideoDecodeEngine::FFmpegVideoDecodeEngine() } FFmpegVideoDecodeEngine::~FFmpegVideoDecodeEngine() { + if (codec_context_) { + av_free(codec_context_->extradata); + avcodec_close(codec_context_); + av_free(codec_context_); + } } void FFmpegVideoDecodeEngine::Initialize( @@ -52,8 +58,27 @@ void FFmpegVideoDecodeEngine::Initialize( static const int kDecodeThreads = 2; static const int kMaxDecodeThreads = 16; - av_stream_ = static_cast<AVStream*>(config.opaque_context); - codec_context_ = av_stream_->codec; + // Initialize AVCodecContext structure. + codec_context_ = avcodec_alloc_context(); + + // TODO(scherkus): should video format get passed in via VideoCodecConfig? + codec_context_->pix_fmt = PIX_FMT_YUV420P; + codec_context_->codec_type = AVMEDIA_TYPE_VIDEO; + codec_context_->codec_id = VideoCodecToCodecID(config.codec()); + codec_context_->coded_width = config.width(); + codec_context_->coded_height = config.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())); + memcpy(codec_context_->extradata, config.extra_data(), + config.extra_data_size()); + } + // Enable motion vector search (potentially slow), strong deblocking filter // for damaged macroblocks, and set our error detection sensitivity. codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; @@ -93,8 +118,8 @@ void FFmpegVideoDecodeEngine::Initialize( info.provides_buffers = true; info.stream_info.surface_type = VideoFrame::TYPE_SYSTEM_MEMORY; info.stream_info.surface_format = GetSurfaceFormat(); - info.stream_info.surface_width = config.width; - info.stream_info.surface_height = config.height; + info.stream_info.surface_width = config.width(); + info.stream_info.surface_height = config.height(); // If we do not have enough buffers, we will report error too. bool buffer_allocated = true; @@ -104,8 +129,8 @@ void FFmpegVideoDecodeEngine::Initialize( for (size_t i = 0; i < Limits::kMaxVideoFrames; ++i) { scoped_refptr<VideoFrame> video_frame; VideoFrame::CreateFrame(VideoFrame::YV12, - config.width, - config.height, + config.width(), + config.height(), kNoTimestamp, kNoTimestamp, &video_frame); @@ -258,18 +283,15 @@ void FFmpegVideoDecodeEngine::DecodeFrame(scoped_refptr<Buffer> buffer) { // Determine timestamp and calculate the duration based on the repeat picture // count. According to FFmpeg docs, the total duration can be calculated as // follows: + // fps = 1 / time_base + // // duration = (1 / fps) + (repeat_pict) / (2 * fps) // = (2 + repeat_pict) / (2 * fps) + // = (2 + repeat_pict) / (2 * (1 / time_base)) DCHECK_LE(av_frame_->repeat_pict, 2); // Sanity check. - // Even frame rate is fixed, for some streams and codecs, the value of - // |codec_context_->time_base| and |av_stream_->time_base| are not the - // inverse of the |av_stream_->r_frame_rate|. They use 1 milli-second as - // time-base units and use increment of av_packet->pts which is not one. - // Use the inverse of |av_stream_->r_frame_rate| instead of time_base. AVRational doubled_time_base; - doubled_time_base.den = av_stream_->r_frame_rate.num; - doubled_time_base.num = av_stream_->r_frame_rate.den; - doubled_time_base.den *= 2; + doubled_time_base.num = frame_rate_denominator_; + doubled_time_base.den = frame_rate_numerator_ * 2; base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque); @@ -341,14 +363,6 @@ void FFmpegVideoDecodeEngine::Seek() { event_handler_->OnSeekComplete(); } -AVCodecContext* FFmpegVideoDecodeEngine::codec_context() const { - return codec_context_; -} - -void FFmpegVideoDecodeEngine::SetCodecContextForTest(AVCodecContext* context) { - codec_context_ = context; -} - void FFmpegVideoDecodeEngine::ReadInput() { DCHECK_EQ(output_eos_reached_, false); pending_input_buffers_++; diff --git a/media/video/ffmpeg_video_decode_engine.h b/media/video/ffmpeg_video_decode_engine.h index 53baa54..b9e76b7 100644 --- a/media/video/ffmpeg_video_decode_engine.h +++ b/media/video/ffmpeg_video_decode_engine.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,7 +14,6 @@ // FFmpeg types. struct AVCodecContext; struct AVFrame; -struct AVStream; namespace media { @@ -36,21 +35,21 @@ class FFmpegVideoDecodeEngine : public VideoDecodeEngine { virtual void Flush(); virtual void Seek(); - virtual AVCodecContext* codec_context() const; - - virtual void SetCodecContextForTest(AVCodecContext* context); - VideoFrame::Format GetSurfaceFormat() const; + private: void DecodeFrame(scoped_refptr<Buffer> buffer); void ReadInput(); void TryToFinishPendingFlush(); AVCodecContext* codec_context_; - AVStream* av_stream_; scoped_ptr_malloc<AVFrame, ScopedPtrAVFree> av_frame_; VideoDecodeEngine::EventHandler* event_handler_; + // Frame rate of the video. + int frame_rate_numerator_; + int frame_rate_denominator_; + // Whether direct rendering is used. bool direct_rendering_; diff --git a/media/video/ffmpeg_video_decode_engine_unittest.cc b/media/video/ffmpeg_video_decode_engine_unittest.cc index e3bea41..ca5c48a 100644 --- a/media/video/ffmpeg_video_decode_engine_unittest.cc +++ b/media/video/ffmpeg_video_decode_engine_unittest.cc @@ -23,7 +23,7 @@ namespace media { static const int kWidth = 320; static const int kHeight = 240; -static const AVRational kTimeBase = { 1, 100 }; +static const AVRational kFrameRate = { 100, 1 }; static void InitializeFrame(uint8_t* data, int width, AVFrame* frame) { frame->data[0] = data; @@ -35,7 +35,7 @@ static void InitializeFrame(uint8_t* data, int width, AVFrame* frame) { } ACTION_P(DecodeComplete, decoder) { - decoder->video_frame_ = arg0; + decoder->set_video_frame(arg0); } ACTION_P2(DemuxComplete, engine, buffer) { @@ -43,33 +43,27 @@ ACTION_P2(DemuxComplete, engine, buffer) { } ACTION_P(SaveInitializeResult, engine) { - engine->info_ = arg0; + engine->set_video_codec_info(arg0); } class FFmpegVideoDecodeEngineTest : public testing::Test, public VideoDecodeEngine::EventHandler { - protected: - FFmpegVideoDecodeEngineTest() { + public: + FFmpegVideoDecodeEngineTest() + : config_(kCodecH264, kWidth, kHeight, + kFrameRate.num, kFrameRate.den, NULL, 0) { + // Setup FFmpeg structures. frame_buffer_.reset(new uint8[kWidth * kHeight]); memset(&yuv_frame_, 0, sizeof(yuv_frame_)); InitializeFrame(frame_buffer_.get(), kWidth, &yuv_frame_); memset(&codec_context_, 0, sizeof(codec_context_)); - codec_context_.width = kWidth; - codec_context_.height = kHeight; - codec_context_.time_base = kTimeBase; - memset(&codec_, 0, sizeof(codec_)); - memset(&stream_, 0, sizeof(stream_)); - stream_.codec = &codec_context_; - stream_.r_frame_rate.num = kTimeBase.den; - stream_.r_frame_rate.den = kTimeBase.num; buffer_ = new DataBuffer(1); test_engine_.reset(new FFmpegVideoDecodeEngine()); - test_engine_->SetCodecContextForTest(&codec_context_); VideoFrame::CreateFrame(VideoFrame::YV12, kWidth, @@ -84,7 +78,9 @@ class FFmpegVideoDecodeEngineTest : public testing::Test, } void Initialize() { - EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_NONE)) + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) + .WillOnce(Return(&codec_context_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) .WillOnce(Return(&codec_)); EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) .WillOnce(Return(&yuv_frame_)); @@ -92,13 +88,13 @@ class FFmpegVideoDecodeEngineTest : public testing::Test, .WillOnce(Return(0)); EXPECT_CALL(mock_ffmpeg_, AVCodecOpen(&codec_context_, &codec_)) .WillOnce(Return(0)); + EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) + .WillOnce(Return(0)); EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) .Times(1); + EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) + .Times(1); - config_.codec = kCodecH264; - config_.opaque_context = &stream_; - config_.width = kWidth; - config_.height = kHeight; EXPECT_CALL(*this, OnInitializeComplete(_)) .WillOnce(SaveInitializeResult(this)); test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); @@ -126,7 +122,7 @@ class FFmpegVideoDecodeEngineTest : public testing::Test, codec_context_.height = height; } - public: + // VideoDecodeEngine::EventHandler implementation. MOCK_METHOD2(ConsumeVideoFrame, void(scoped_refptr<VideoFrame> video_frame, const PipelineStatistics& statistics)); @@ -140,20 +136,30 @@ class FFmpegVideoDecodeEngineTest : public testing::Test, MOCK_METHOD0(OnError, void()); MOCK_METHOD1(OnFormatChange, void(VideoStreamInfo stream_info)); - scoped_refptr<VideoFrame> video_frame_; + // Used by gmock actions. + void set_video_frame(scoped_refptr<VideoFrame> video_frame) { + video_frame_ = video_frame; + } + + void set_video_codec_info(const VideoCodecInfo& info) { + info_ = info; + } + + protected: VideoCodecConfig config_; VideoCodecInfo info_; - protected: + scoped_refptr<VideoFrame> video_frame_; scoped_ptr<FFmpegVideoDecodeEngine> test_engine_; scoped_array<uint8_t> frame_buffer_; StrictMock<MockFFmpeg> mock_ffmpeg_; AVFrame yuv_frame_; AVCodecContext codec_context_; - AVStream stream_; AVCodec codec_; scoped_refptr<DataBuffer> buffer_; + private: + DISALLOW_COPY_AND_ASSIGN(FFmpegVideoDecodeEngineTest); }; TEST_F(FFmpegVideoDecodeEngineTest, Initialize_Normal) { @@ -162,17 +168,19 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_Normal) { TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) { // Test avcodec_find_decoder() returning NULL. - EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_NONE)) + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) + .WillOnce(Return(&codec_context_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) .WillOnce(ReturnNull()); EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) .WillOnce(Return(&yuv_frame_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) + .WillOnce(Return(0)); EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) .Times(1); + EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) + .Times(1); - config_.codec = kCodecH264; - config_.opaque_context = &stream_; - config_.width = kWidth; - config_.height = kHeight; EXPECT_CALL(*this, OnInitializeComplete(_)) .WillOnce(SaveInitializeResult(this)); test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); @@ -182,19 +190,21 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_FindDecoderFails) { // Note There are 2 threads for FFmpeg-mt. TEST_F(FFmpegVideoDecodeEngineTest, Initialize_InitThreadFails) { // Test avcodec_thread_init() failing. - EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_NONE)) + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) + .WillOnce(Return(&codec_context_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) .WillOnce(Return(&codec_)); EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) .WillOnce(Return(&yuv_frame_)); EXPECT_CALL(mock_ffmpeg_, AVCodecThreadInit(&codec_context_, 2)) .WillOnce(Return(-1)); + EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) + .WillOnce(Return(0)); EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) .Times(1); + EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) + .Times(1); - config_.codec = kCodecH264; - config_.opaque_context = &stream_; - config_.width = kWidth; - config_.height = kHeight; EXPECT_CALL(*this, OnInitializeComplete(_)) .WillOnce(SaveInitializeResult(this)); test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); @@ -203,7 +213,9 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_InitThreadFails) { TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) { // Test avcodec_open() failing. - EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_NONE)) + EXPECT_CALL(mock_ffmpeg_, AVCodecAllocContext()) + .WillOnce(Return(&codec_context_)); + EXPECT_CALL(mock_ffmpeg_, AVCodecFindDecoder(CODEC_ID_H264)) .WillOnce(Return(&codec_)); EXPECT_CALL(mock_ffmpeg_, AVCodecAllocFrame()) .WillOnce(Return(&yuv_frame_)); @@ -211,13 +223,13 @@ TEST_F(FFmpegVideoDecodeEngineTest, Initialize_OpenDecoderFails) { .WillOnce(Return(0)); EXPECT_CALL(mock_ffmpeg_, AVCodecOpen(&codec_context_, &codec_)) .WillOnce(Return(-1)); + EXPECT_CALL(mock_ffmpeg_, AVCodecClose(&codec_context_)) + .WillOnce(Return(0)); EXPECT_CALL(mock_ffmpeg_, AVFree(&yuv_frame_)) .Times(1); + EXPECT_CALL(mock_ffmpeg_, AVFree(&codec_context_)) + .Times(1); - config_.codec = kCodecH264; - config_.opaque_context = &stream_; - config_.width = kWidth; - config_.height = kHeight; EXPECT_CALL(*this, OnInitializeComplete(_)) .WillOnce(SaveInitializeResult(this)); test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); @@ -310,6 +322,8 @@ TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) { } TEST_F(FFmpegVideoDecodeEngineTest, GetSurfaceFormat) { + Initialize(); + // YV12 formats. codec_context_.pix_fmt = PIX_FMT_YUV420P; EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); diff --git a/media/video/mft_h264_decode_engine.cc b/media/video/mft_h264_decode_engine.cc index bb3143c..4acfc7f 100644 --- a/media/video/mft_h264_decode_engine.cc +++ b/media/video/mft_h264_decode_engine.cc @@ -151,11 +151,12 @@ const GUID ConvertVideoFrameFormatToGuid(VideoFrame::Format format) { MftH264DecodeEngine::MftH264DecodeEngine(bool use_dxva) : use_dxva_(use_dxva), state_(kUninitialized), + width_(0), + height_(0), event_handler_(NULL), context_(NULL) { memset(&input_stream_info_, 0, sizeof(input_stream_info_)); memset(&output_stream_info_, 0, sizeof(output_stream_info_)); - memset(&config_, 0, sizeof(config_)); memset(&info_, 0, sizeof(info_)); } @@ -177,7 +178,6 @@ void MftH264DecodeEngine::Initialize( return; } context_ = context; - config_ = config; event_handler_ = event_handler; info_.provides_buffers = true; @@ -473,8 +473,8 @@ bool MftH264DecodeEngine::SetDecodeEngineOutputMediaType(const GUID subtype) { hr = MFGetAttributeSize(out_media_type, MF_MT_FRAME_SIZE, reinterpret_cast<UINT32*>(&info_.stream_info.surface_width), reinterpret_cast<UINT32*>(&info_.stream_info.surface_height)); - config_.width = info_.stream_info.surface_width; - config_.height = info_.stream_info.surface_height; + width_ = info_.stream_info.surface_width; + height_ = info_.stream_info.surface_height; if (FAILED(hr)) { LOG(ERROR) << "Failed to SetOutputType to |subtype| or obtain " << "width/height " << std::hex << hr; diff --git a/media/video/mft_h264_decode_engine.h b/media/video/mft_h264_decode_engine.h index d543631..9ce7935 100644 --- a/media/video/mft_h264_decode_engine.h +++ b/media/video/mft_h264_decode_engine.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -88,8 +88,10 @@ class MftH264DecodeEngine : public media::VideoDecodeEngine { State state_; + int width_; + int height_; + VideoDecodeEngine::EventHandler* event_handler_; - VideoCodecConfig config_; VideoCodecInfo info_; VideoDecodeContext* context_; diff --git a/media/video/omx_video_decode_engine.cc b/media/video/omx_video_decode_engine.cc index df3f9cf..a6996d3 100644 --- a/media/video/omx_video_decode_engine.cc +++ b/media/video/omx_video_decode_engine.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -90,8 +90,8 @@ void OmxVideoDecodeEngine::Initialize( message_loop_ = message_loop; event_handler_ = event_handler; - width_ = config.width; - height_ = config.height; + width_ = config.width(); + height_ = config.height(); // TODO(wjia): Find the right way to determine the codec type. OmxConfigurator::MediaFormat input_format, output_format; @@ -115,8 +115,8 @@ void OmxVideoDecodeEngine::Initialize( uses_egl_image_ ? VideoFrame::TYPE_GL_TEXTURE : VideoFrame::TYPE_SYSTEM_MEMORY; info.stream_info.surface_format = GetSurfaceFormat(); - info.stream_info.surface_width = config.width; - info.stream_info.surface_height = config.height; + info.stream_info.surface_width = config.width(); + info.stream_info.surface_height = config.height(); event_handler_->OnInitializeComplete(info); } diff --git a/media/video/omx_video_decode_engine.h b/media/video/omx_video_decode_engine.h index 9a6c0a7..1609548 100644 --- a/media/video/omx_video_decode_engine.h +++ b/media/video/omx_video_decode_engine.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -175,8 +175,8 @@ class OmxVideoDecodeEngine : public VideoDecodeEngine { scoped_refptr<VideoFrame> CreateOmxBufferVideoFrame( OMX_BUFFERHEADERTYPE* omx_buffer); - size_t width_; - size_t height_; + int width_; + int height_; MessageLoop* message_loop_; diff --git a/media/video/video_decode_engine.cc b/media/video/video_decode_engine.cc index 04f3bea..ca0093f 100644 --- a/media/video/video_decode_engine.cc +++ b/media/video/video_decode_engine.cc @@ -1,18 +1,61 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "media/video/video_decode_engine.h" +#include "base/logging.h" + namespace media { -VideoCodecConfig::VideoCodecConfig() - : codec(kCodecH264), - profile(kProfileDoNotCare), - level(kLevelDoNotCare), - width(0), - height(0), - opaque_context(NULL) { +VideoCodecConfig::VideoCodecConfig(VideoCodec codec, + int width, + int height, + int frame_rate_numerator, + int frame_rate_denominator, + uint8* extra_data, + size_t extra_data_size) + : codec_(codec), + width_(width), + height_(height), + frame_rate_numerator_(frame_rate_numerator), + frame_rate_denominator_(frame_rate_denominator), + extra_data_size_(extra_data_size) { + CHECK(extra_data_size_ == 0 || extra_data); + if (extra_data_size_ > 0) { + extra_data_.reset(new uint8[extra_data_size_]); + memcpy(extra_data_.get(), extra_data, extra_data_size_); + } +} + +VideoCodecConfig::~VideoCodecConfig() {} + +VideoCodec VideoCodecConfig::codec() const { + return codec_; +} + +int VideoCodecConfig::width() const { + return width_; +} + +int VideoCodecConfig::height() const { + return height_; +} + +int VideoCodecConfig::frame_rate_numerator() const { + return frame_rate_numerator_; +} + +int VideoCodecConfig::frame_rate_denominator() const { + return frame_rate_denominator_; +} + +uint8* VideoCodecConfig::extra_data() const { + return extra_data_.get(); +} + +size_t VideoCodecConfig::extra_data_size() const { + return extra_data_size_; } } // namespace media diff --git a/media/video/video_decode_engine.h b/media/video/video_decode_engine.h index 57b76a2..5893b3a 100644 --- a/media/video/video_decode_engine.h +++ b/media/video/video_decode_engine.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,7 @@ #define MEDIA_VIDEO_VIDEO_DECODE_ENGINE_H_ #include "base/callback.h" +#include "base/scoped_ptr.h" #include "media/base/video_frame.h" class MessageLoop; @@ -18,6 +19,7 @@ class VideoDecodeContext; struct PipelineStatistics; enum VideoCodec { + kUnknown, kCodecH264, kCodecVC1, kCodecMPEG2, @@ -26,26 +28,38 @@ enum VideoCodec { kCodecVP8, }; -static const uint32 kProfileDoNotCare = static_cast<uint32>(-1); -static const uint32 kLevelDoNotCare = static_cast<uint32>(-1); - -struct VideoCodecConfig { - VideoCodecConfig(); +class VideoCodecConfig { + public: + VideoCodecConfig(VideoCodec codec, int width, int height, + int frame_rate_numerator, int frame_rate_denominator, + uint8* extra_data, size_t extra_data_size); + ~VideoCodecConfig(); + + VideoCodec codec() const; + int width() const; + int height() const; + int frame_rate_numerator() const; + int frame_rate_denominator() const; + uint8* extra_data() const; + size_t extra_data_size() const; + + private: + VideoCodec codec_; - VideoCodec codec; + // Container's concept of width and height of this video. + int width_; + int height_; - // TODO(jiesun): video profile and level are specific to individual codec. - // Define enum to. - uint32 profile; - uint32 level; + // Frame rate in seconds expressed as a fraction. + // TODO(scherkus): fairly certain decoders don't require frame rates. + int frame_rate_numerator_; + int frame_rate_denominator_; - // Container's concept of width and height of this video. - int32 width; - int32 height; // TODO(jiesun): Do we allow height to be negative to - // indicate output is upside-down? + // Optional byte data requied to initialize video decoders. + scoped_array<uint8> extra_data_; + size_t extra_data_size_; - // FFMPEG's will use this to pass AVStream. Otherwise, we should remove this. - void* opaque_context; + DISALLOW_COPY_AND_ASSIGN(VideoCodecConfig); }; struct VideoStreamInfo { |