diff options
author | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-03 00:30:39 +0000 |
---|---|---|
committer | xhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-03 00:30:39 +0000 |
commit | e1d75490aebae7cefd4be491dff0facde1bb2d53 (patch) | |
tree | 7a9d929cd7b348da09efe494495f79a6981c1e5b | |
parent | f7b0633c3475362a1e6933277304df5b7e8af4c7 (diff) | |
download | chromium_src-e1d75490aebae7cefd4be491dff0facde1bb2d53.zip chromium_src-e1d75490aebae7cefd4be491dff0facde1bb2d53.tar.gz chromium_src-e1d75490aebae7cefd4be491dff0facde1bb2d53.tar.bz2 |
Remove VideoDecoder from the Filter heirarchy.
This is the second step to move VideoDecoder out of Filter hierarchy (See r128289). VideoDecoder is not a Filter any more and Seek()/Pause()/Play() methods are removed from its definition and all implementations.
BUG=108340
TEST=media_unittest,content_unittest,normal html5 video playback
Review URL: http://codereview.chromium.org/9724011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135051 0039d316-1c4b-4281-b951-d872f2087c98
27 files changed, 354 insertions, 590 deletions
diff --git a/content/renderer/media/capture_video_decoder.cc b/content/renderer/media/capture_video_decoder.cc index 72d2d1ba..cecfd22 100644 --- a/content/renderer/media/capture_video_decoder.cc +++ b/content/renderer/media/capture_video_decoder.cc @@ -7,7 +7,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "content/renderer/media/video_capture_impl_manager.h" -#include "media/base/filter_host.h" +#include "media/base/demuxer_stream.h" #include "media/base/limits.h" #include "media/base/video_util.h" @@ -31,58 +31,33 @@ CaptureVideoDecoder::CaptureVideoDecoder( DCHECK(vc_manager); } -void CaptureVideoDecoder::Play(const base::Closure& callback) { - message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&CaptureVideoDecoder::PlayOnDecoderThread, - this, callback)); -} - -void CaptureVideoDecoder::Seek(base::TimeDelta time, - const media::PipelineStatusCB& cb) { - message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&CaptureVideoDecoder::SeekOnDecoderThread, - this, time, cb)); -} - -void CaptureVideoDecoder::Pause(const base::Closure& callback) { - message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&CaptureVideoDecoder::PauseOnDecoderThread, - this, callback)); -} - -void CaptureVideoDecoder::Flush(const base::Closure& callback) { +void CaptureVideoDecoder::Initialize( + const scoped_refptr<media::DemuxerStream>& stream, + const media::PipelineStatusCB& status_cb, + const media::StatisticsCB& statistics_cb) { message_loop_proxy_->PostTask( FROM_HERE, - base::Bind(&CaptureVideoDecoder::FlushOnDecoderThread, - this, callback)); + base::Bind(&CaptureVideoDecoder::InitializeOnDecoderThread, + this, stream, status_cb, statistics_cb)); } -void CaptureVideoDecoder::Stop(const base::Closure& callback) { +void CaptureVideoDecoder::Read(const ReadCB& read_cb) { message_loop_proxy_->PostTask( FROM_HERE, - base::Bind(&CaptureVideoDecoder::StopOnDecoderThread, - this, callback)); + base::Bind(&CaptureVideoDecoder::ReadOnDecoderThread, + this, read_cb)); } -void CaptureVideoDecoder::Initialize( - media::DemuxerStream* demuxer_stream, - const media::PipelineStatusCB& status_cb, - const media::StatisticsCB& statistics_cb) { +void CaptureVideoDecoder::Reset(const base::Closure& closure) { message_loop_proxy_->PostTask( FROM_HERE, - base::Bind(&CaptureVideoDecoder::InitializeOnDecoderThread, - this, make_scoped_refptr(demuxer_stream), - status_cb, statistics_cb)); + base::Bind(&CaptureVideoDecoder::ResetOnDecoderThread, this, closure)); } -void CaptureVideoDecoder::Read(const ReadCB& read_cb) { +void CaptureVideoDecoder::Stop(const base::Closure& closure) { message_loop_proxy_->PostTask( FROM_HERE, - base::Bind(&CaptureVideoDecoder::ReadOnDecoderThread, - this, read_cb)); + base::Bind(&CaptureVideoDecoder::StopOnDecoderThread, this, closure)); } const gfx::Size& CaptureVideoDecoder::natural_size() { @@ -134,31 +109,29 @@ void CaptureVideoDecoder::OnDeviceInfoReceived( CaptureVideoDecoder::~CaptureVideoDecoder() {} -void CaptureVideoDecoder::PlayOnDecoderThread(const base::Closure& callback) { - DVLOG(1) << "PlayOnDecoderThread"; +void CaptureVideoDecoder::InitializeOnDecoderThread( + const scoped_refptr<media::DemuxerStream>& /* stream */, + const media::PipelineStatusCB& status_cb, + const media::StatisticsCB& statistics_cb) { + DVLOG(1) << "InitializeOnDecoderThread"; DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - callback.Run(); -} -void CaptureVideoDecoder::SeekOnDecoderThread( - base::TimeDelta time, - const media::PipelineStatusCB& cb) { - DVLOG(1) << "SeekOnDecoderThread"; - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + capture_engine_ = vc_manager_->AddDevice(video_stream_id_, this); - cb.Run(media::PIPELINE_OK); + statistics_cb_ = statistics_cb; + status_cb.Run(media::PIPELINE_OK); state_ = kNormal; + capture_engine_->StartCapture(this, capability_); } -void CaptureVideoDecoder::PauseOnDecoderThread(const base::Closure& callback) { - DVLOG(1) << "PauseOnDecoderThread"; +void CaptureVideoDecoder::ReadOnDecoderThread(const ReadCB& read_cb) { DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - state_ = kPaused; - callback.Run(); + CHECK(read_cb_.is_null()); + read_cb_ = read_cb; } -void CaptureVideoDecoder::FlushOnDecoderThread(const base::Closure& callback) { - DVLOG(1) << "FlushOnDecoderThread"; +void CaptureVideoDecoder::ResetOnDecoderThread(const base::Closure& closure) { + DVLOG(1) << "ResetOnDecoderThread"; DCHECK(message_loop_proxy_->BelongsToCurrentThread()); if (!read_cb_.is_null()) { scoped_refptr<media::VideoFrame> video_frame = @@ -166,38 +139,17 @@ void CaptureVideoDecoder::FlushOnDecoderThread(const base::Closure& callback) { natural_size_.height()); DeliverFrame(video_frame); } - media::VideoDecoder::Flush(callback); + closure.Run(); } -void CaptureVideoDecoder::StopOnDecoderThread(const base::Closure& callback) { +void CaptureVideoDecoder::StopOnDecoderThread(const base::Closure& closure) { DVLOG(1) << "StopOnDecoderThread"; DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - pending_stop_cb_ = callback; + pending_stop_cb_ = closure; state_ = kStopped; capture_engine_->StopCapture(this); } -void CaptureVideoDecoder::InitializeOnDecoderThread( - media::DemuxerStream* demuxer_stream, - const media::PipelineStatusCB& status_cb, - const media::StatisticsCB& statistics_cb) { - DVLOG(1) << "InitializeOnDecoderThread"; - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - - capture_engine_ = vc_manager_->AddDevice(video_stream_id_, this); - - statistics_cb_ = statistics_cb; - status_cb.Run(media::PIPELINE_OK); - state_ = kNormal; - capture_engine_->StartCapture(this, capability_); -} - -void CaptureVideoDecoder::ReadOnDecoderThread(const ReadCB& read_cb) { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - CHECK(read_cb_.is_null()); - read_cb_ = read_cb; -} - void CaptureVideoDecoder::OnStoppedOnDecoderThread( media::VideoCapture* capture) { DVLOG(1) << "OnStoppedOnDecoderThread"; diff --git a/content/renderer/media/capture_video_decoder.h b/content/renderer/media/capture_video_decoder.h index cafd533f..daa6c2c 100644 --- a/content/renderer/media/capture_video_decoder.h +++ b/content/renderer/media/capture_video_decoder.h @@ -7,16 +7,17 @@ #include "base/time.h" #include "content/common/content_export.h" -#include "media/base/demuxer_stream.h" -#include "media/base/filters.h" #include "media/base/pipeline_status.h" -#include "media/base/video_frame.h" +#include "media/base/video_decoder.h" #include "media/video/capture/video_capture.h" #include "media/video/capture/video_capture_types.h" namespace base { class MessageLoopProxy; } +namespace media { +class VideoFrame; +} class VideoCaptureImplManager; // A filter takes raw frames from video capture engine and passes them to media @@ -31,20 +32,13 @@ class CONTENT_EXPORT CaptureVideoDecoder VideoCaptureImplManager* vc_manager, const media::VideoCaptureCapability& capability); - // Filter implementation. - virtual void Play(const base::Closure& callback) OVERRIDE; - virtual void Seek(base::TimeDelta time, - const media::PipelineStatusCB& cb) OVERRIDE; - virtual void Pause(const base::Closure& callback) OVERRIDE; - virtual void Flush(const base::Closure& callback) OVERRIDE; - virtual void Stop(const base::Closure& callback) OVERRIDE; - - // Decoder implementation. - virtual void Initialize( - media::DemuxerStream* demuxer_stream, - const media::PipelineStatusCB& status_cb, - const media::StatisticsCB& statistics_cb) OVERRIDE; - virtual void Read(const ReadCB& callback) OVERRIDE; + // media::VideoDecoder implementation. + virtual void Initialize(const scoped_refptr<media::DemuxerStream>& stream, + const media::PipelineStatusCB& status_cb, + const media::StatisticsCB& statistics_cb) OVERRIDE; + virtual void Read(const ReadCB& read_cb) OVERRIDE; + virtual void Reset(const base::Closure& closure) OVERRIDE; + virtual void Stop(const base::Closure& closure) OVERRIDE; virtual const gfx::Size& natural_size() OVERRIDE; // VideoCapture::EventHandler implementation. @@ -73,18 +67,13 @@ class CONTENT_EXPORT CaptureVideoDecoder kPaused }; - void PlayOnDecoderThread(const base::Closure& callback); - void SeekOnDecoderThread(base::TimeDelta time, - const media::PipelineStatusCB& cb); - void PauseOnDecoderThread(const base::Closure& callback); - void FlushOnDecoderThread(const base::Closure& callback); - void StopOnDecoderThread(const base::Closure& callback); - void InitializeOnDecoderThread( - media::DemuxerStream* demuxer_stream, + const scoped_refptr<media::DemuxerStream>& stream, const media::PipelineStatusCB& status_cb, const media::StatisticsCB& statistics_cb); - void ReadOnDecoderThread(const ReadCB& callback); + void ReadOnDecoderThread(const ReadCB& read_cb); + void ResetOnDecoderThread(const base::Closure& closure); + void StopOnDecoderThread(const base::Closure& closure); void OnStoppedOnDecoderThread(media::VideoCapture* capture); void OnBufferReadyOnDecoderThread( diff --git a/content/renderer/media/capture_video_decoder_unittest.cc b/content/renderer/media/capture_video_decoder_unittest.cc index c87bd56..6853caf 100644 --- a/content/renderer/media/capture_video_decoder_unittest.cc +++ b/content/renderer/media/capture_video_decoder_unittest.cc @@ -6,7 +6,6 @@ #include "content/renderer/media/capture_video_decoder.h" #include "content/renderer/media/video_capture_impl.h" #include "content/renderer/media/video_capture_impl_manager.h" -#include "media/base/filters.h" #include "media/base/limits.h" #include "media/base/mock_callback.h" #include "media/base/mock_filters.h" @@ -140,21 +139,6 @@ class CaptureVideoDecoderTest : public ::testing::Test { message_loop_->RunAllPending(); } - void Play() { - decoder_->Play(media::NewExpectedClosure()); - message_loop_->RunAllPending(); - } - - void Flush() { - // Issue a read. - EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, _)); - decoder_->Read(read_cb_); - - decoder_->Pause(media::NewExpectedClosure()); - decoder_->Flush(media::NewExpectedClosure()); - message_loop_->RunAllPending(); - } - void Stop() { EXPECT_CALL(*vc_impl_, StopCapture(capture_client())) .Times(1) @@ -185,14 +169,18 @@ class CaptureVideoDecoderTest : public ::testing::Test { DISALLOW_COPY_AND_ASSIGN(CaptureVideoDecoderTest); }; -TEST_F(CaptureVideoDecoderTest, Play) { - // Test basic initialize, play, and teardown sequence. +TEST_F(CaptureVideoDecoderTest, ReadAndReset) { + // Test basic initialize and teardown sequence. Initialize(); // Natural size should be initialized to default capability. EXPECT_EQ(kWidth, decoder_->natural_size().width()); EXPECT_EQ(kHeight, decoder_->natural_size().height()); - Play(); - Flush(); + + EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, _)); + decoder_->Read(read_cb_); + decoder_->Reset(media::NewExpectedClosure()); + message_loop_->RunAllPending(); + Stop(); } diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc index ea15a02..7f9e095 100644 --- a/content/renderer/media/rtc_video_decoder.cc +++ b/content/renderer/media/rtc_video_decoder.cc @@ -10,7 +10,6 @@ #include "base/callback.h" #include "base/message_loop.h" #include "media/base/demuxer.h" -#include "media/base/filters.h" #include "media/base/limits.h" #include "media/base/video_frame.h" #include "media/base/video_util.h" @@ -20,7 +19,6 @@ using media::CopyUPlane; using media::CopyVPlane; using media::CopyYPlane; using media::DemuxerStream; -using media::PipelineStatusCB; using media::kNoTimestamp; using media::PIPELINE_OK; using media::PipelineStatusCB; @@ -36,51 +34,41 @@ RTCVideoDecoder::RTCVideoDecoder(MessageLoop* message_loop, got_first_frame_(false) { } -void RTCVideoDecoder::Play(const base::Closure& callback) { +void RTCVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, + const PipelineStatusCB& status_cb, + const StatisticsCB& statistics_cb) { if (MessageLoop::current() != message_loop_) { - message_loop_->PostTask(FROM_HERE, - base::Bind(&RTCVideoDecoder::Play, this, callback)); + message_loop_->PostTask( + FROM_HERE, + base::Bind(&RTCVideoDecoder::Initialize, this, + stream, status_cb, statistics_cb)); return; } DCHECK_EQ(MessageLoop::current(), message_loop_); - - callback.Run(); -} - -void RTCVideoDecoder::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { - if (MessageLoop::current() != message_loop_) { - message_loop_->PostTask(FROM_HERE, - base::Bind(&RTCVideoDecoder::Seek, this, - time, cb)); - return; - } - - DCHECK_EQ(MessageLoop::current(), message_loop_); state_ = kNormal; - cb.Run(PIPELINE_OK); + status_cb.Run(PIPELINE_OK); + + // TODO(acolwell): Implement stats. } -void RTCVideoDecoder::Pause(const base::Closure& callback) { +void RTCVideoDecoder::Read(const ReadCB& read_cb) { if (MessageLoop::current() != message_loop_) { - message_loop_->PostTask(FROM_HERE, - base::Bind(&RTCVideoDecoder::Pause, - this, callback)); + message_loop_->PostTask( + FROM_HERE, + base::Bind(&RTCVideoDecoder::Read, this, read_cb)); return; } - DCHECK_EQ(MessageLoop::current(), message_loop_); - - state_ = kPaused; - - callback.Run(); + base::AutoLock auto_lock(lock_); + CHECK(read_cb_.is_null()); + read_cb_ = read_cb; } -void RTCVideoDecoder::Flush(const base::Closure& callback) { +void RTCVideoDecoder::Reset(const base::Closure& closure) { if (MessageLoop::current() != message_loop_) { message_loop_->PostTask(FROM_HERE, - base::Bind(&RTCVideoDecoder::Flush, - this, callback)); + base::Bind(&RTCVideoDecoder::Reset, this, closure)); return; } @@ -101,14 +89,13 @@ void RTCVideoDecoder::Flush(const base::Closure& callback) { read_cb.Run(kOk, video_frame); } - VideoDecoder::Flush(callback); + closure.Run(); } -void RTCVideoDecoder::Stop(const base::Closure& callback) { +void RTCVideoDecoder::Stop(const base::Closure& closure) { if (MessageLoop::current() != message_loop_) { message_loop_->PostTask(FROM_HERE, - base::Bind(&RTCVideoDecoder::Stop, - this, callback)); + base::Bind(&RTCVideoDecoder::Stop, this, closure)); return; } @@ -116,39 +103,7 @@ void RTCVideoDecoder::Stop(const base::Closure& callback) { state_ = kStopped; - VideoDecoder::Stop(callback); -} - -void RTCVideoDecoder::Initialize(DemuxerStream* demuxer_stream, - const PipelineStatusCB& status_cb, - const StatisticsCB& statistics_cb) { - if (MessageLoop::current() != message_loop_) { - message_loop_->PostTask( - FROM_HERE, - base::Bind(&RTCVideoDecoder::Initialize, this, - make_scoped_refptr(demuxer_stream), - status_cb, statistics_cb)); - return; - } - - DCHECK_EQ(MessageLoop::current(), message_loop_); - state_ = kNormal; - status_cb.Run(PIPELINE_OK); - - // TODO(acolwell): Implement stats. -} - -void RTCVideoDecoder::Read(const ReadCB& callback) { - if (MessageLoop::current() != message_loop_) { - message_loop_->PostTask( - FROM_HERE, - base::Bind(&RTCVideoDecoder::Read, this, callback)); - return; - } - DCHECK_EQ(MessageLoop::current(), message_loop_); - base::AutoLock auto_lock(lock_); - CHECK(read_cb_.is_null()); - read_cb_ = callback; + closure.Run(); } const gfx::Size& RTCVideoDecoder::natural_size() { diff --git a/content/renderer/media/rtc_video_decoder.h b/content/renderer/media/rtc_video_decoder.h index ca615431..8317049 100644 --- a/content/renderer/media/rtc_video_decoder.h +++ b/content/renderer/media/rtc_video_decoder.h @@ -12,8 +12,7 @@ #include "base/synchronization/lock.h" #include "base/time.h" #include "content/common/content_export.h" -#include "media/base/filters.h" -#include "media/base/video_frame.h" +#include "media/base/video_decoder.h" #include "third_party/libjingle/source/talk/session/phone/mediachannel.h" #include "third_party/libjingle/source/talk/session/phone/videorenderer.h" @@ -29,20 +28,13 @@ class CONTENT_EXPORT RTCVideoDecoder public: RTCVideoDecoder(MessageLoop* message_loop, const std::string& url); - // Filter implementation. - virtual void Play(const base::Closure& callback) OVERRIDE; - virtual void Seek(base::TimeDelta time, - const media::PipelineStatusCB& cb) OVERRIDE; - virtual void Pause(const base::Closure& callback) OVERRIDE; - virtual void Flush(const base::Closure& callback) OVERRIDE; - virtual void Stop(const base::Closure& callback) OVERRIDE; - - // Decoder implementation. - virtual void Initialize( - media::DemuxerStream* demuxer_stream, - const media::PipelineStatusCB& status_cb, - const media::StatisticsCB& statistics_cb) OVERRIDE; - virtual void Read(const ReadCB& callback) OVERRIDE; + // media::VideoDecoder implementation. + virtual void Initialize(const scoped_refptr<media::DemuxerStream>& stream, + const media::PipelineStatusCB& status_cb, + const media::StatisticsCB& statistics_cb) OVERRIDE; + virtual void Read(const ReadCB& read_cb) OVERRIDE; + virtual void Reset(const base::Closure& clusure) OVERRIDE; + virtual void Stop(const base::Closure& clusure) OVERRIDE; virtual const gfx::Size& natural_size() OVERRIDE; // cricket::VideoRenderer implementation @@ -55,15 +47,13 @@ class CONTENT_EXPORT RTCVideoDecoder private: friend class RTCVideoDecoderTest; FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, Initialize_Successful); - FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, DoSeek); - FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, DoFlush); + FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, DoReset); FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, DoRenderFrame); FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, DoSetSize); enum DecoderState { kUnInitialized, kNormal, - kPaused, kStopped }; diff --git a/content/renderer/media/rtc_video_decoder_unittest.cc b/content/renderer/media/rtc_video_decoder_unittest.cc index 5380e99..a2f94ba 100644 --- a/content/renderer/media/rtc_video_decoder_unittest.cc +++ b/content/renderer/media/rtc_video_decoder_unittest.cc @@ -133,7 +133,7 @@ class RTCVideoDecoderTest : public testing::Test { DCHECK(decoder_); - EXPECT_CALL(stats_callback_object_, OnStatistics(_)) + EXPECT_CALL(statistics_cb_, OnStatistics(_)) .Times(AnyNumber()); } @@ -151,7 +151,7 @@ class RTCVideoDecoderTest : public testing::Test { StatisticsCB NewStatisticsCB() { return base::Bind(&MockStatisticsCB::OnStatistics, - base::Unretained(&stats_callback_object_)); + base::Unretained(&statistics_cb_)); } MOCK_METHOD2(FrameReady, void(media::VideoDecoder::DecoderStatus status, @@ -160,7 +160,7 @@ class RTCVideoDecoderTest : public testing::Test { // Fixture members. scoped_refptr<RTCVideoDecoder> decoder_; scoped_refptr<MockVideoRenderer> renderer_; - MockStatisticsCB stats_callback_object_; + MockStatisticsCB statistics_cb_; MessageLoop message_loop_; media::VideoDecoder::ReadCB read_cb_; @@ -182,35 +182,18 @@ TEST_F(RTCVideoDecoderTest, Initialize_Successful) { EXPECT_EQ(kHeight, decoder_->natural_size().height()); } -TEST_F(RTCVideoDecoderTest, DoSeek) { - const base::TimeDelta kZero; - - InitializeDecoderSuccessfully(); - - // Expect seek and verify the results. - decoder_->Seek(kZero, NewExpectedStatusCB(PIPELINE_OK)); - - message_loop_.RunAllPending(); - EXPECT_EQ(RTCVideoDecoder::kNormal, decoder_->state_); -} - -TEST_F(RTCVideoDecoderTest, DoFlush) { - const base::TimeDelta kZero; - +TEST_F(RTCVideoDecoderTest, DoReset) { InitializeDecoderSuccessfully(); EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, _)); decoder_->Read(read_cb_); - decoder_->Pause(media::NewExpectedClosure()); - decoder_->Flush(media::NewExpectedClosure()); + decoder_->Reset(media::NewExpectedClosure()); message_loop_.RunAllPending(); - EXPECT_EQ(RTCVideoDecoder::kPaused, decoder_->state_); + EXPECT_EQ(RTCVideoDecoder::kNormal, decoder_->state_); } TEST_F(RTCVideoDecoderTest, DoRenderFrame) { - const base::TimeDelta kZero; - InitializeDecoderSuccessfully(); NullVideoFrame video_frame; diff --git a/media/base/filter_collection.cc b/media/base/filter_collection.cc index 537dd60..205da15 100644 --- a/media/base/filter_collection.cc +++ b/media/base/filter_collection.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "media/base/audio_decoder.h" +#include "media/base/video_decoder.h" namespace media { diff --git a/media/base/filter_collection.h b/media/base/filter_collection.h index 8d8591d..0f5e320 100644 --- a/media/base/filter_collection.h +++ b/media/base/filter_collection.h @@ -14,6 +14,7 @@ namespace media { class AudioDecoder; +class VideoDecoder; // This is a collection of Filter objects used to form a media playback // pipeline. See src/media/base/pipeline.h for more information. diff --git a/media/base/filters.cc b/media/base/filters.cc index 5682be3..d5bd6d7 100644 --- a/media/base/filters.cc +++ b/media/base/filters.cc @@ -57,34 +57,4 @@ void Filter::Seek(base::TimeDelta time, const PipelineStatusCB& callback) { void Filter::OnAudioRendererDisabled() { } -VideoDecoder::VideoDecoder() {} - -VideoDecoder::~VideoDecoder() {} - -// TODO(xhwang): Remove the following four functions when VideoDecoder is not a -// Filter any more. See bug: http://crbug.com/108340 -void VideoDecoder::Play(const base::Closure& /* callback */) { - LOG(FATAL) << "VideoDecoder::Play is not supposed to be called."; -} - -void VideoDecoder::Pause(const base::Closure& /* callback */) { - LOG(FATAL) << "VideoDecoder::Pause is not supposed to be called."; -} - -void VideoDecoder::Seek(base::TimeDelta /* time */, - const PipelineStatusCB& /* callback */) { - LOG(FATAL) << "VideoDecoder::Seek is not supposed to be called."; -} - -FilterHost* VideoDecoder::host() { - LOG(FATAL) << "VideoDecoder::host is not supposed to be called."; - return NULL; -} - -bool VideoDecoder::HasAlpha() const { - return false; -} - -void VideoDecoder::PrepareForShutdownHack() {} - } // namespace media diff --git a/media/base/filters.h b/media/base/filters.h index 0126995..c96d82f 100644 --- a/media/base/filters.h +++ b/media/base/filters.h @@ -30,11 +30,9 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/time.h" -#include "media/base/channel_layout.h" #include "media/base/media_export.h" #include "media/base/pipeline_status.h" #include "media/base/video_frame.h" -#include "ui/gfx/size.h" namespace media { @@ -44,6 +42,7 @@ class Decoder; class DemuxerStream; class Filter; class FilterHost; +class VideoDecoder; class MEDIA_EXPORT Filter : public base::RefCountedThreadSafe<Filter> { public: @@ -107,77 +106,6 @@ class MEDIA_EXPORT Filter : public base::RefCountedThreadSafe<Filter> { DISALLOW_COPY_AND_ASSIGN(Filter); }; -class MEDIA_EXPORT VideoDecoder : public Filter { - public: - // Status codes for read operations on VideoDecoder. - enum DecoderStatus { - kOk, // Everything went as planned. - kDecodeError, // Decoding error happened. - kDecryptError // Decrypting error happened. - }; - - // Initialize a VideoDecoder with the given DemuxerStream, executing the - // callback upon completion. - // statistics_cb is used to update global pipeline statistics. - virtual void Initialize(DemuxerStream* stream, - const PipelineStatusCB& status_cb, - const StatisticsCB& statistics_cb) = 0; - - // Requests a frame to be decoded. The status of the decoder and decoded frame - // are returned via the provided callback. Only one read may be in flight at - // any given time. - // - // Implementations guarantee that the callback will not be called from within - // this method. - // - // If the returned status is not kOk, some error has occurred in the video - // decoder. In this case, the returned frame should always be NULL. - // - // Otherwise, the video decoder is in good shape. In this case, Non-NULL - // frames contain decoded video data or may indicate the end of the stream. - // NULL video frames indicate an aborted read. This can happen if the - // DemuxerStream gets flushed and doesn't have any more data to return. - typedef base::Callback<void(DecoderStatus, scoped_refptr<VideoFrame>)> ReadCB; - virtual void Read(const ReadCB& read_cb) = 0; - - // Returns the natural width and height of decoded video in pixels. - // - // Clients should NOT rely on these values to remain constant. Instead, use - // the width/height from decoded video frames themselves. - // - // TODO(scherkus): why not rely on prerolling and decoding a single frame to - // get dimensions? - virtual const gfx::Size& natural_size() = 0; - - // Returns true if the output format has an alpha channel. Most formats do not - // have alpha so the default is false. Override and return true for decoders - // that return formats with an alpha channel. - virtual bool HasAlpha() const; - - // Prepare decoder for shutdown. This is a HACK needed because - // PipelineImpl::Stop() goes through a Pause/Flush/Stop dance to all its - // filters, waiting for each state transition to complete before starting the - // next, but WebMediaPlayerImpl::Destroy() holds the renderer loop hostage for - // the duration. Default implementation does nothing; derived decoders may - // override as needed. http://crbug.com/110228 tracks removing this. - virtual void PrepareForShutdownHack(); - - protected: - VideoDecoder(); - virtual ~VideoDecoder(); - - private: - // These functions will be removed later. Declare here to make sure they are - // not called from VideoDecoder interface anymore. - // TODO(xhwang): Remove them when VideoDecoder is not a Filter any more. - // See bug: http://crbug.com/108340 - virtual void Play(const base::Closure& callback) OVERRIDE; - virtual void Pause(const base::Closure& callback) OVERRIDE; - virtual void Seek(base::TimeDelta time, - const PipelineStatusCB& callback) OVERRIDE; - virtual FilterHost* host() OVERRIDE; -}; - class MEDIA_EXPORT VideoRenderer : public Filter { public: // Used to update the pipeline's clock time. The parameter is the time that diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc index 258e396..00347cd 100644 --- a/media/base/mock_filters.cc +++ b/media/base/mock_filters.cc @@ -84,10 +84,6 @@ scoped_ptr<FilterCollection> MockFilterCollection::Create() { return collection.Pass(); } -void RunFilterCallback(::testing::Unused, const base::Closure& closure) { - closure.Run(); -} - void RunPipelineStatusCB(const PipelineStatusCB& status_cb) { status_cb.Run(PIPELINE_OK); } @@ -107,7 +103,7 @@ void RunPipelineStatusCB4(::testing::Unused, const PipelineStatusCB& status_cb, status_cb.Run(PIPELINE_OK); } -void RunStopFilterCallback(const base::Closure& closure) { +void RunClosure(const base::Closure& closure) { closure.Run(); } diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index 409d09d..a5060d3 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h @@ -22,6 +22,7 @@ #include "media/base/filters.h" #include "media/base/filter_collection.h" #include "media/base/pipeline.h" +#include "media/base/video_decoder.h" #include "media/base/video_decoder_config.h" #include "media/base/video_frame.h" #include "testing/gmock/include/gmock/gmock.h" @@ -146,18 +147,13 @@ class MockVideoDecoder : public VideoDecoder { public: MockVideoDecoder(); - // Filter implementation. - MOCK_METHOD1(Flush, void(const base::Closure& callback)); - MOCK_METHOD1(Stop, void(const base::Closure& callback)); - MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); - MOCK_METHOD2(Seek, void(base::TimeDelta time, const PipelineStatusCB& cb)); - MOCK_METHOD0(OnAudioRendererDisabled, void()); - // VideoDecoder implementation. - MOCK_METHOD3(Initialize, void(DemuxerStream* stream, - const PipelineStatusCB& status_cb, - const StatisticsCB& statistics_cb)); - MOCK_METHOD1(Read, void(const ReadCB& read_cb)); + MOCK_METHOD3(Initialize, void(const scoped_refptr<DemuxerStream>&, + const PipelineStatusCB&, + const StatisticsCB&)); + MOCK_METHOD1(Read, void(const ReadCB&)); + MOCK_METHOD1(Reset, void(const base::Closure&)); + MOCK_METHOD1(Stop, void(const base::Closure&)); MOCK_METHOD0(natural_size, const gfx::Size&()); MOCK_CONST_METHOD0(HasAlpha, bool()); @@ -274,9 +270,8 @@ class MockFilterCollection { }; // Helper gmock functions that immediately executes and destroys the -// Closure on behalf of the provided filter. Can be used when mocking +// Closure on behalf of the provided filter. Can be used when mocking // the Initialize() and Seek() methods. -void RunFilterCallback(::testing::Unused, const base::Closure& closure); void RunPipelineStatusCB(const PipelineStatusCB& status_cb); void RunPipelineStatusCB2(::testing::Unused, const PipelineStatusCB& status_cb); void RunPipelineStatusCB3(::testing::Unused, const PipelineStatusCB& status_cb, @@ -284,8 +279,8 @@ void RunPipelineStatusCB3(::testing::Unused, const PipelineStatusCB& status_cb, void RunPipelineStatusCB4(::testing::Unused, const PipelineStatusCB& status_cb, ::testing::Unused, ::testing::Unused); // Helper gmock function that immediately executes the Closure on behalf of the -// provided filter. Can be used when mocking the Stop() method. -void RunStopFilterCallback(const base::Closure& closure); +// provided filter. Can be used when mocking the Stop() method. +void RunClosure(const base::Closure& closure); // Helper gmock action that calls SetError() on behalf of the provided filter. ACTION_P2(SetError, filter, error) { diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc index 719f579..c231910 100644 --- a/media/base/pipeline.cc +++ b/media/base/pipeline.cc @@ -21,6 +21,7 @@ #include "media/base/filter_collection.h" #include "media/base/filters.h" #include "media/base/media_log.h" +#include "media/base/video_decoder.h" namespace media { diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc index a18c55f..dc11d8c 100644 --- a/media/base/pipeline_unittest.cc +++ b/media/base/pipeline_unittest.cc @@ -113,7 +113,7 @@ class PipelineTest : public ::testing::Test { Invoke(&RunPipelineStatusCB2))); EXPECT_CALL(*mocks_->demuxer(), SetPlaybackRate(0.0f)); EXPECT_CALL(*mocks_->demuxer(), Stop(_)) - .WillOnce(Invoke(&RunStopFilterCallback)); + .WillOnce(Invoke(&RunClosure)); // Demuxer properties. EXPECT_CALL(*mocks_->demuxer(), GetBitrate()) @@ -145,7 +145,7 @@ class PipelineTest : public ::testing::Test { } // Sets up expectations to allow the video decoder to initialize. - void InitializeVideoDecoder(MockDemuxerStream* stream) { + void InitializeVideoDecoder(const scoped_refptr<DemuxerStream>& stream) { EXPECT_CALL(*mocks_->video_decoder(), Initialize(stream, _, _)) .WillOnce(Invoke(&RunPipelineStatusCB3)); @@ -167,7 +167,7 @@ class PipelineTest : public ::testing::Test { Seek(mocks_->demuxer()->GetStartTime(), _)) .WillOnce(Invoke(&RunPipelineStatusCB2)); EXPECT_CALL(*mocks_->video_renderer(), Stop(_)) - .WillOnce(Invoke(&RunStopFilterCallback)); + .WillOnce(Invoke(&RunClosure)); } // Sets up expectations to allow the audio renderer to initialize. @@ -187,7 +187,7 @@ class PipelineTest : public ::testing::Test { EXPECT_CALL(*mocks_->audio_renderer(), Seek(base::TimeDelta(), _)) .WillOnce(Invoke(&RunPipelineStatusCB2)); EXPECT_CALL(*mocks_->audio_renderer(), Stop(_)) - .WillOnce(Invoke(&RunStopFilterCallback)); + .WillOnce(Invoke(&RunClosure)); } // Sets up expectations on the callback and initializes the pipeline. Called @@ -304,7 +304,7 @@ TEST_F(PipelineTest, NeverInitializes) { // Don't execute the callback passed into Initialize(). EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _)); EXPECT_CALL(*mocks_->demuxer(), Stop(_)) - .WillOnce(Invoke(&RunStopFilterCallback)); + .WillOnce(Invoke(&RunClosure)); // This test hangs during initialization by never calling // InitializationComplete(). StrictMock<> will ensure that the callback is @@ -346,7 +346,7 @@ TEST_F(PipelineTest, URLNotFound) { EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _)) .WillOnce(InitializeDemuxerWithError(PIPELINE_ERROR_URL_NOT_FOUND)); EXPECT_CALL(*mocks_->demuxer(), Stop(_)) - .WillOnce(Invoke(&RunStopFilterCallback)); + .WillOnce(Invoke(&RunClosure)); InitializePipeline(PIPELINE_ERROR_URL_NOT_FOUND); EXPECT_FALSE(pipeline_->IsInitialized()); @@ -356,7 +356,7 @@ TEST_F(PipelineTest, NoStreams) { EXPECT_CALL(*mocks_->demuxer(), Initialize(_, _)) .WillOnce(Invoke(&RunPipelineStatusCB2)); EXPECT_CALL(*mocks_->demuxer(), Stop(_)) - .WillOnce(Invoke(&RunStopFilterCallback)); + .WillOnce(Invoke(&RunClosure)); InitializePipeline(PIPELINE_ERROR_COULD_NOT_RENDER); EXPECT_FALSE(pipeline_->IsInitialized()); diff --git a/media/base/video_decoder.cc b/media/base/video_decoder.cc new file mode 100644 index 0000000..b5100b8 --- /dev/null +++ b/media/base/video_decoder.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2012 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/base/video_decoder.h" + +namespace media { + +VideoDecoder::VideoDecoder() {} + +VideoDecoder::~VideoDecoder() {} + +bool VideoDecoder::HasAlpha() const { + return false; +} + +void VideoDecoder::PrepareForShutdownHack() {} + +} // namespace media diff --git a/media/base/video_decoder.h b/media/base/video_decoder.h new file mode 100644 index 0000000..61b626e --- /dev/null +++ b/media/base/video_decoder.h @@ -0,0 +1,95 @@ +// Copyright (c) 2012 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. + +#ifndef MEDIA_BASE_VIDEO_DECODER_H_ +#define MEDIA_BASE_VIDEO_DECODER_H_ + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "media/base/pipeline_status.h" +#include "media/base/media_export.h" +#include "ui/gfx/size.h" + +namespace media { + +class Buffer; +class DemuxerStream; +class VideoFrame; + +class MEDIA_EXPORT VideoDecoder + : public base::RefCountedThreadSafe<VideoDecoder> { + public: + // Status codes for read operations on VideoDecoder. + enum DecoderStatus { + kOk, // Everything went as planned. + kDecodeError, // Decoding error happened. + kDecryptError // Decrypting error happened. + }; + + // Initialize a VideoDecoder with the given DemuxerStream, executing the + // callback upon completion. + // statistics_cb is used to update global pipeline statistics. + virtual void Initialize(const scoped_refptr<DemuxerStream>& stream, + const PipelineStatusCB& status_cb, + const StatisticsCB& statistics_cb) = 0; + + // Requests a frame to be decoded. The status of the decoder and decoded frame + // are returned via the provided callback. Only one read may be in flight at + // any given time. + // + // Implementations guarantee that the callback will not be called from within + // this method. + // + // If the returned status is not kOk, some error has occurred in the video + // decoder. In this case, the returned frame should always be NULL. + // + // Otherwise, the video decoder is in good shape. In this case, Non-NULL + // frames contain decoded video data or may indicate the end of the stream. + // NULL video frames indicate an aborted read. This can happen if the + // DemuxerStream gets flushed and doesn't have any more data to return. + typedef base::Callback<void(DecoderStatus, scoped_refptr<VideoFrame>)> ReadCB; + virtual void Read(const ReadCB& read_cb) = 0; + + // Reset decoder state, fulfilling all pending ReadCB and dropping extra + // queued decoded data. After this call, the decoder is back to an initialized + // clean state. + virtual void Reset(const base::Closure& closure) = 0; + + // Stop decoder and set it to an uninitialized state. Note that a VideoDecoder + // should/could not be re-initialized after it has been stopped. + virtual void Stop(const base::Closure& closure) = 0; + + // Returns the natural width and height of decoded video in pixels. + // + // Clients should NOT rely on these values to remain constant. Instead, use + // the width/height from decoded video frames themselves. + // + // TODO(scherkus): why not rely on prerolling and decoding a single frame to + // get dimensions? + virtual const gfx::Size& natural_size() = 0; + + // Returns true if the output format has an alpha channel. Most formats do not + // have alpha so the default is false. Override and return true for decoders + // that return formats with an alpha channel. + virtual bool HasAlpha() const; + + // Prepare decoder for shutdown. This is a HACK needed because + // PipelineImpl::Stop() goes through a Pause/Flush/Stop dance to all its + // filters, waiting for each state transition to complete before starting the + // next, but WebMediaPlayerImpl::Destroy() holds the renderer loop hostage for + // the duration. Default implementation does nothing; derived decoders may + // override as needed. http://crbug.com/110228 tracks removing this. + virtual void PrepareForShutdownHack(); + + protected: + friend class base::RefCountedThreadSafe<VideoDecoder>; + virtual ~VideoDecoder(); + VideoDecoder(); + + DISALLOW_COPY_AND_ASSIGN(VideoDecoder); +}; + +} // namespace media + +#endif // MEDIA_BASE_VIDEO_DECODER_H_ diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc index e61affb..5ba22a0 100644 --- a/media/filters/ffmpeg_video_decoder.cc +++ b/media/filters/ffmpeg_video_decoder.cc @@ -63,7 +63,7 @@ FFmpegVideoDecoder::~FFmpegVideoDecoder() { ReleaseFFmpegResources(); } -void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, +void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, const PipelineStatusCB& status_cb, const StatisticsCB& statistics_cb) { if (!message_loop_) { @@ -72,22 +72,22 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, message_loop_->PostTask(FROM_HERE, base::Bind( &FFmpegVideoDecoder::Initialize, this, - make_scoped_refptr(demuxer_stream), status_cb, statistics_cb)); + stream, status_cb, statistics_cb)); return; } DCHECK_EQ(MessageLoop::current(), message_loop_); DCHECK(!demuxer_stream_); - if (!demuxer_stream) { + if (!stream) { status_cb.Run(PIPELINE_ERROR_DECODE); return; } - demuxer_stream_ = demuxer_stream; + demuxer_stream_ = stream; statistics_cb_ = statistics_cb; - const VideoDecoderConfig& config = demuxer_stream->video_decoder_config(); + const VideoDecoderConfig& config = stream->video_decoder_config(); // TODO(scherkus): this check should go in Pipeline prior to creating // decoder objects. @@ -127,69 +127,48 @@ void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, status_cb.Run(PIPELINE_OK); } -void FFmpegVideoDecoder::Stop(const base::Closure& callback) { - if (MessageLoop::current() != message_loop_) { - message_loop_->PostTask(FROM_HERE, base::Bind( - &FFmpegVideoDecoder::Stop, this, callback)); - return; - } - - ReleaseFFmpegResources(); - state_ = kUninitialized; - callback.Run(); -} - -void FFmpegVideoDecoder::Seek(base::TimeDelta time, - const PipelineStatusCB& cb) { - if (MessageLoop::current() != message_loop_) { - message_loop_->PostTask(FROM_HERE, base::Bind( - &FFmpegVideoDecoder::Seek, this, time, cb)); - return; - } - - cb.Run(PIPELINE_OK); -} - -void FFmpegVideoDecoder::Pause(const base::Closure& callback) { - if (MessageLoop::current() != message_loop_) { - message_loop_->PostTask(FROM_HERE, base::Bind( - &FFmpegVideoDecoder::Pause, this, callback)); - return; - } - - callback.Run(); +void FFmpegVideoDecoder::Read(const ReadCB& read_cb) { + // Complete operation asynchronously on different stack of execution as per + // the API contract of VideoDecoder::Read() + message_loop_->PostTask(FROM_HERE, base::Bind( + &FFmpegVideoDecoder::DoRead, this, read_cb)); } -void FFmpegVideoDecoder::Flush(const base::Closure& callback) { +void FFmpegVideoDecoder::Reset(const base::Closure& closure) { if (MessageLoop::current() != message_loop_) { message_loop_->PostTask(FROM_HERE, base::Bind( - &FFmpegVideoDecoder::Flush, this, callback)); + &FFmpegVideoDecoder::Reset, this, closure)); return; } - flush_cb_ = callback; + reset_cb_ = closure; - // Defer the flush if a read is pending. + // Defer the reset if a read is pending. if (!read_cb_.is_null()) return; - DoFlush(); + DoReset(); } -void FFmpegVideoDecoder::DoFlush() { +void FFmpegVideoDecoder::DoReset() { DCHECK(read_cb_.is_null()); avcodec_flush_buffers(codec_context_); state_ = kNormal; - flush_cb_.Run(); - flush_cb_.Reset(); + reset_cb_.Run(); + reset_cb_.Reset(); } -void FFmpegVideoDecoder::Read(const ReadCB& read_cb) { - // Complete operation asynchronously on different stack of execution as per - // the API contract of VideoDecoder::Read() - message_loop_->PostTask(FROM_HERE, base::Bind( - &FFmpegVideoDecoder::DoRead, this, read_cb)); +void FFmpegVideoDecoder::Stop(const base::Closure& closure) { + if (MessageLoop::current() != message_loop_) { + message_loop_->PostTask(FROM_HERE, base::Bind( + &FFmpegVideoDecoder::Stop, this, closure)); + return; + } + + ReleaseFFmpegResources(); + state_ = kUninitialized; + closure.Run(); } const gfx::Size& FFmpegVideoDecoder::natural_size() { @@ -242,9 +221,9 @@ void FFmpegVideoDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& buffer) { DCHECK_NE(state_, kDecodeFinished); DCHECK(!read_cb_.is_null()); - if (!flush_cb_.is_null()) { + if (!reset_cb_.is_null()) { DeliverFrame(NULL); - DoFlush(); + DoReset(); return; } @@ -276,7 +255,7 @@ void FFmpegVideoDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& buffer) { // kFlushCodec -> kDecodeFinished: // When avcodec_decode_video2() returns 0 data or errors out. // (any state) -> kNormal: - // Any time Flush() is called. + // Any time Reset() is called. // Transition to kFlushCodec on the first end of stream buffer. if (state_ == kNormal && buffer->IsEndOfStream()) { diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h index 60ec0a5..a50bbce 100644 --- a/media/filters/ffmpeg_video_decoder.h +++ b/media/filters/ffmpeg_video_decoder.h @@ -9,9 +9,8 @@ #include "base/callback.h" #include "base/memory/scoped_ptr.h" -#include "media/base/filters.h" +#include "media/base/video_decoder.h" #include "media/crypto/aes_decryptor.h" -#include "ui/gfx/size.h" class MessageLoop; @@ -25,17 +24,13 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { FFmpegVideoDecoder(const base::Callback<MessageLoop*()>& message_loop_cb); virtual ~FFmpegVideoDecoder(); - // Filter implementation. - virtual void Stop(const base::Closure& callback) OVERRIDE; - virtual void Seek(base::TimeDelta time, const PipelineStatusCB& cb) OVERRIDE; - virtual void Pause(const base::Closure& callback) OVERRIDE; - virtual void Flush(const base::Closure& callback) OVERRIDE; - // VideoDecoder implementation. - virtual void Initialize(DemuxerStream* demuxer_stream, + virtual void Initialize(const scoped_refptr<DemuxerStream>& stream, const PipelineStatusCB& status_cb, const StatisticsCB& statistics_cb) OVERRIDE; virtual void Read(const ReadCB& read_cb) OVERRIDE; + virtual void Reset(const base::Closure& closure) OVERRIDE; + virtual void Stop(const base::Closure& closure) OVERRIDE; virtual const gfx::Size& natural_size() OVERRIDE; AesDecryptor* decryptor(); @@ -67,8 +62,8 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { // and resets them to NULL. void ReleaseFFmpegResources(); - // Flush decoder and call |flush_cb_|. - void DoFlush(); + // Reset decoder and call |reset_cb_|. + void DoReset(); // Allocates a video frame based on the current format and dimensions based on // the current state of |codec_context_|. @@ -84,7 +79,7 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { StatisticsCB statistics_cb_; ReadCB read_cb_; - base::Closure flush_cb_; + base::Closure reset_cb_; // FFmpeg structures owned by this object. AVCodecContext* codec_context_; diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc index cb674d5..24e716e 100644 --- a/media/filters/ffmpeg_video_decoder_unittest.cc +++ b/media/filters/ffmpeg_video_decoder_unittest.cc @@ -10,11 +10,11 @@ #include "base/string_util.h" #include "media/base/data_buffer.h" #include "media/base/decrypt_config.h" -#include "media/base/filters.h" #include "media/base/limits.h" #include "media/base/mock_callback.h" #include "media/base/mock_filters.h" #include "media/base/test_data_util.h" +#include "media/base/video_decoder.h" #include "media/base/video_frame.h" #include "media/ffmpeg/ffmpeg_common.h" #include "media/filters/ffmpeg_decoder_unittest.h" @@ -92,19 +92,8 @@ class FFmpegVideoDecoderTest : public testing::Test { InitializeWithConfigAndStatus(config, PIPELINE_OK); } - void Pause() { - decoder_->Pause(NewExpectedClosure()); - message_loop_.RunAllPending(); - } - - void Flush() { - decoder_->Flush(NewExpectedClosure()); - message_loop_.RunAllPending(); - } - - void Seek(int64 timestamp) { - decoder_->Seek(base::TimeDelta::FromMicroseconds(timestamp), - NewExpectedStatusCB(PIPELINE_OK)); + void Reset() { + decoder_->Reset(NewExpectedClosure()); message_loop_.RunAllPending(); } @@ -453,50 +442,29 @@ TEST_F(FFmpegVideoDecoderTest, DecodeEncryptedFrame_WrongKey) { message_loop_.RunAllPending(); } -// Test pausing when decoder has initialized but not decoded. -TEST_F(FFmpegVideoDecoderTest, Pause_Initialized) { - Initialize(); - Pause(); -} - -// Test pausing when decoder has decoded single frame. -TEST_F(FFmpegVideoDecoderTest, Pause_Decoding) { - Initialize(); - EnterDecodingState(); - Pause(); -} - -// Test pausing when decoder has hit end of stream. -TEST_F(FFmpegVideoDecoderTest, Pause_EndOfStream) { - Initialize(); - EnterDecodingState(); - EnterEndOfStreamState(); - Pause(); -} - -// Test flushing when decoder has initialized but not decoded. -TEST_F(FFmpegVideoDecoderTest, Flush_Initialized) { +// Test resetting when decoder has initialized but not decoded. +TEST_F(FFmpegVideoDecoderTest, Reset_Initialized) { Initialize(); - Flush(); + Reset(); } -// Test flushing when decoder has decoded single frame. -TEST_F(FFmpegVideoDecoderTest, Flush_Decoding) { +// Test resetting when decoder has decoded single frame. +TEST_F(FFmpegVideoDecoderTest, Reset_Decoding) { Initialize(); EnterDecodingState(); - Flush(); + Reset(); } -// Test flushing when decoder has hit end of stream. -TEST_F(FFmpegVideoDecoderTest, Flush_EndOfStream) { +// Test resetting when decoder has hit end of stream. +TEST_F(FFmpegVideoDecoderTest, Reset_EndOfStream) { Initialize(); EnterDecodingState(); EnterEndOfStreamState(); - Flush(); + Reset(); } -// Test flushing when there is a pending read on the demuxer. -TEST_F(FFmpegVideoDecoderTest, Flush_DuringPendingRead) { +// Test resetting when there is a pending read on the demuxer. +TEST_F(FFmpegVideoDecoderTest, Reset_DuringPendingRead) { Initialize(); DemuxerStream::ReadCB read_cb; @@ -510,8 +478,8 @@ TEST_F(FFmpegVideoDecoderTest, Flush_DuringPendingRead) { // the demuxer. EXPECT_FALSE(read_cb.is_null()); - // Flush the decoder. - Flush(); + // Reset the decoder. + Reset(); EXPECT_CALL(*this, FrameReady(VideoDecoder::kOk, scoped_refptr<VideoFrame>())); @@ -520,29 +488,6 @@ TEST_F(FFmpegVideoDecoderTest, Flush_DuringPendingRead) { message_loop_.RunAllPending(); } - - -// Test seeking when decoder has initialized but not decoded. -TEST_F(FFmpegVideoDecoderTest, Seek_Initialized) { - Initialize(); - Seek(1000); -} - -// Test seeking when decoder has decoded single frame. -TEST_F(FFmpegVideoDecoderTest, Seek_Decoding) { - Initialize(); - EnterDecodingState(); - Seek(1000); -} - -// Test seeking when decoder has hit end of stream. -TEST_F(FFmpegVideoDecoderTest, Seek_EndOfStream) { - Initialize(); - EnterDecodingState(); - EnterEndOfStreamState(); - Seek(1000); -} - // Test stopping when decoder has initialized but not decoded. TEST_F(FFmpegVideoDecoderTest, Stop_Initialized) { Initialize(); @@ -595,7 +540,7 @@ TEST_F(FFmpegVideoDecoderTest, AbortPendingReadDuringFlush) { ASSERT_FALSE(read_cb.is_null()); // Flush while there is still an outstanding read on the demuxer. - decoder_->Flush(NewExpectedClosure()); + decoder_->Reset(NewExpectedClosure()); message_loop_.RunAllPending(); // Signal an aborted demuxer read. diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index 547d361..aafa693 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc @@ -74,45 +74,11 @@ GpuVideoDecoder::~GpuVideoDecoder() { bitstream_buffers_in_decoder_.clear(); } -void GpuVideoDecoder::Stop(const base::Closure& callback) { - if (!gvd_loop_proxy_->BelongsToCurrentThread()) { - gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &GpuVideoDecoder::Stop, this, callback)); - return; - } - if (!vda_) { - callback.Run(); - return; - } - vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &VideoDecodeAccelerator::Destroy, vda_)); - vda_ = NULL; - callback.Run(); -} - -void GpuVideoDecoder::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { - if (!gvd_loop_proxy_->BelongsToCurrentThread()) { - gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &GpuVideoDecoder::Seek, this, time, cb)); - return; - } - cb.Run(PIPELINE_OK); -} - -void GpuVideoDecoder::Pause(const base::Closure& callback) { - if (!gvd_loop_proxy_->BelongsToCurrentThread()) { - gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &GpuVideoDecoder::Pause, this, callback)); - return; - } - callback.Run(); -} - -void GpuVideoDecoder::Flush(const base::Closure& callback) { +void GpuVideoDecoder::Reset(const base::Closure& closure) { if (!gvd_loop_proxy_->BelongsToCurrentThread() || state_ == kDrainingDecoder) { gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &GpuVideoDecoder::Flush, this, callback)); + &GpuVideoDecoder::Reset, this, closure)); return; } @@ -120,12 +86,12 @@ void GpuVideoDecoder::Flush(const base::Closure& callback) { ready_video_frames_.clear(); if (!vda_) { - callback.Run(); + closure.Run(); return; } DCHECK(pending_reset_cb_.is_null()); - DCHECK(!callback.is_null()); + DCHECK(!closure.is_null()); if (shutting_down_) { // VideoRendererBase::Flush() can't complete while it has a pending read to @@ -134,32 +100,48 @@ void GpuVideoDecoder::Flush(const base::Closure& callback) { EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame()); // Immediate fire the callback instead of waiting for the reset to complete // (which will happen after PipelineImpl::Stop() completes). - callback.Run(); + closure.Run(); } else { - pending_reset_cb_ = callback; + pending_reset_cb_ = closure; } vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( &VideoDecodeAccelerator::Reset, vda_)); } -void GpuVideoDecoder::Initialize(DemuxerStream* demuxer_stream, +void GpuVideoDecoder::Stop(const base::Closure& closure) { + if (!gvd_loop_proxy_->BelongsToCurrentThread()) { + gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( + &GpuVideoDecoder::Stop, this, closure)); + return; + } + if (!vda_) { + closure.Run(); + return; + } + vda_loop_proxy_->PostTask(FROM_HERE, base::Bind( + &VideoDecodeAccelerator::Destroy, vda_)); + vda_ = NULL; + closure.Run(); +} + +void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, const PipelineStatusCB& status_cb, const StatisticsCB& statistics_cb) { if (!gvd_loop_proxy_->BelongsToCurrentThread()) { gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind( - &GpuVideoDecoder::Initialize, this, - make_scoped_refptr(demuxer_stream), status_cb, statistics_cb)); + &GpuVideoDecoder::Initialize, + this, stream, status_cb, statistics_cb)); return; } DCHECK(!demuxer_stream_); - if (!demuxer_stream) { + if (!stream) { status_cb.Run(PIPELINE_ERROR_DECODE); return; } - const VideoDecoderConfig& config = demuxer_stream->video_decoder_config(); + const VideoDecoderConfig& config = stream->video_decoder_config(); // TODO(scherkus): this check should go in Pipeline prior to creating // decoder objects. if (!config.IsValidConfig()) { @@ -174,7 +156,7 @@ void GpuVideoDecoder::Initialize(DemuxerStream* demuxer_stream, return; } - demuxer_stream_ = demuxer_stream; + demuxer_stream_ = stream; statistics_cb_ = statistics_cb; demuxer_stream_->EnableBitstreamConverter(); diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h index 7e48980..894cf3c 100644 --- a/media/filters/gpu_video_decoder.h +++ b/media/filters/gpu_video_decoder.h @@ -9,10 +9,9 @@ #include <list> #include <map> -#include "media/base/filters.h" #include "media/base/pipeline_status.h" +#include "media/base/video_decoder.h" #include "media/video/video_decode_accelerator.h" -#include "ui/gfx/size.h" class MessageLoop; template <class T> class scoped_refptr; @@ -58,17 +57,13 @@ class MEDIA_EXPORT GpuVideoDecoder const scoped_refptr<Factories>& factories); virtual ~GpuVideoDecoder(); - // Filter implementation. - virtual void Stop(const base::Closure& callback) OVERRIDE; - virtual void Seek(base::TimeDelta time, const PipelineStatusCB& cb) OVERRIDE; - virtual void Pause(const base::Closure& callback) OVERRIDE; - virtual void Flush(const base::Closure& callback) OVERRIDE; - // VideoDecoder implementation. - virtual void Initialize(DemuxerStream* demuxer_stream, + virtual void Initialize(const scoped_refptr<DemuxerStream>& stream, const PipelineStatusCB& status_cb, const StatisticsCB& statistics_cb) OVERRIDE; virtual void Read(const ReadCB& read_cb) OVERRIDE; + virtual void Reset(const base::Closure& closure) OVERRIDE; + virtual void Stop(const base::Closure& closure) OVERRIDE; virtual const gfx::Size& natural_size() OVERRIDE; virtual bool HasAlpha() const OVERRIDE; virtual void PrepareForShutdownHack() OVERRIDE; diff --git a/media/filters/video_frame_generator.cc b/media/filters/video_frame_generator.cc index 38dbdec..ece499c 100644 --- a/media/filters/video_frame_generator.cc +++ b/media/filters/video_frame_generator.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/message_loop.h" #include "media/base/demuxer_stream.h" +#include "media/base/video_frame.h" namespace media { @@ -23,14 +24,13 @@ VideoFrameGenerator::VideoFrameGenerator( VideoFrameGenerator::~VideoFrameGenerator() {} void VideoFrameGenerator::Initialize( - DemuxerStream* demuxer_stream, + const scoped_refptr<DemuxerStream>& stream, const PipelineStatusCB& status_cb, const StatisticsCB& statistics_cb) { message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&VideoFrameGenerator::InitializeOnDecoderThread, - this, make_scoped_refptr(demuxer_stream), - status_cb, statistics_cb)); + this, stream, status_cb, statistics_cb)); } void VideoFrameGenerator::Read(const ReadCB& read_cb) { @@ -39,22 +39,24 @@ void VideoFrameGenerator::Read(const ReadCB& read_cb) { base::Bind(&VideoFrameGenerator::ReadOnDecoderThread, this, read_cb)); } -void VideoFrameGenerator::Flush(const base::Closure& flush_cb) { - message_loop_proxy_->PostTask(FROM_HERE, flush_cb); -} - -const gfx::Size& VideoFrameGenerator::natural_size() { - return natural_size_; +void VideoFrameGenerator::Reset(const base::Closure& closure) { + message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&VideoFrameGenerator::ResetOnDecoderThread, this, closure)); } -void VideoFrameGenerator::Stop(const base::Closure& callback) { +void VideoFrameGenerator::Stop(const base::Closure& closure) { message_loop_proxy_->PostTask( FROM_HERE, - base::Bind(&VideoFrameGenerator::StopOnDecoderThread, this, callback)); + base::Bind(&VideoFrameGenerator::StopOnDecoderThread, this, closure)); +} + +const gfx::Size& VideoFrameGenerator::natural_size() { + return natural_size_; } void VideoFrameGenerator::InitializeOnDecoderThread( - DemuxerStream* demuxer_stream, + const scoped_refptr<DemuxerStream>& /* stream */, const PipelineStatusCB& status_cb, const StatisticsCB& statistics_cb) { DVLOG(1) << "InitializeOnDecoderThread"; @@ -87,12 +89,19 @@ void VideoFrameGenerator::ReadOnDecoderThread(const ReadCB& read_cb) { read_cb.Run(kOk, video_frame); } -void VideoFrameGenerator::StopOnDecoderThread(const base::Closure& callback) { +void VideoFrameGenerator::ResetOnDecoderThread(const base::Closure& closure) { + DVLOG(1) << "ResetOnDecoderThread"; + DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + current_time_ = base::TimeDelta(); + closure.Run(); +} + +void VideoFrameGenerator::StopOnDecoderThread(const base::Closure& closure) { DVLOG(1) << "StopOnDecoderThread"; DCHECK(message_loop_proxy_->BelongsToCurrentThread()); stopped_ = true; current_time_ = base::TimeDelta(); - callback.Run(); + closure.Run(); } } // namespace media diff --git a/media/filters/video_frame_generator.h b/media/filters/video_frame_generator.h index 94778e5..faf50fc 100644 --- a/media/filters/video_frame_generator.h +++ b/media/filters/video_frame_generator.h @@ -5,7 +5,8 @@ #ifndef MEDIA_FILTERS_VIDEO_FRAME_GENERATOR_H_ #define MEDIA_FILTERS_VIDEO_FRAME_GENERATOR_H_ -#include "media/base/filters.h" +#include "base/time.h" +#include "media/base/video_decoder.h" #include "media/base/pipeline_status.h" namespace base { @@ -19,8 +20,7 @@ class VideoFrame; // A filter generates raw frames and passes them to media engine as a video // decoder filter. -class MEDIA_EXPORT VideoFrameGenerator - : public VideoDecoder { +class MEDIA_EXPORT VideoFrameGenerator : public VideoDecoder { public: VideoFrameGenerator( base::MessageLoopProxy* message_loop_proxy, @@ -28,26 +28,24 @@ class MEDIA_EXPORT VideoFrameGenerator const base::TimeDelta& frame_duration); virtual ~VideoFrameGenerator(); - // Filter implementation. - virtual void Stop(const base::Closure& callback) OVERRIDE; - - // Decoder implementation. + // VideoDecoder implementation. virtual void Initialize( - DemuxerStream* demuxer_stream, + const scoped_refptr<DemuxerStream>& stream, const PipelineStatusCB& status_cb, const StatisticsCB& statistics_cb) OVERRIDE; virtual void Read(const ReadCB& read_cb) OVERRIDE; - virtual void Flush(const base::Closure& flush_cb) OVERRIDE; + virtual void Reset(const base::Closure& closure) OVERRIDE; + virtual void Stop(const base::Closure& closure) OVERRIDE; virtual const gfx::Size& natural_size() OVERRIDE; private: - void StopOnDecoderThread(const base::Closure& callback); - void InitializeOnDecoderThread( - DemuxerStream* demuxer_stream, + const scoped_refptr<DemuxerStream>& stream, const PipelineStatusCB& status_cb, const StatisticsCB& statistics_cb); void ReadOnDecoderThread(const ReadCB& read_cb); + void ResetOnDecoderThread(const base::Closure& closure); + void StopOnDecoderThread(const base::Closure& closure); scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; gfx::Size natural_size_; diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc index a9b0a5c..e3a5fe0 100644 --- a/media/filters/video_renderer_base.cc +++ b/media/filters/video_renderer_base.cc @@ -60,7 +60,7 @@ void VideoRendererBase::Flush(const base::Closure& callback) { // call. // TODO: Remove this line when fixing http://crbug.com/125020 base::AutoUnlock auto_unlock(lock_); - decoder_->Flush(base::Bind(&VideoRendererBase::OnDecoderFlushDone, this)); + decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderFlushDone, this)); } void VideoRendererBase::Stop(const base::Closure& callback) { @@ -122,7 +122,6 @@ void VideoRendererBase::Initialize(const scoped_refptr<VideoDecoder>& decoder, DCHECK(!time_cb.is_null()); DCHECK_EQ(kUninitialized, state_); decoder_ = decoder; - decoder_->set_host(host()); statistics_cb_ = statistics_cb; time_cb_ = time_cb; diff --git a/media/filters/video_renderer_base.h b/media/filters/video_renderer_base.h index c710e1c..f83a977 100644 --- a/media/filters/video_renderer_base.h +++ b/media/filters/video_renderer_base.h @@ -13,6 +13,7 @@ #include "base/threading/platform_thread.h" #include "media/base/filters.h" #include "media/base/pipeline_status.h" +#include "media/base/video_decoder.h" #include "media/base/video_frame.h" namespace media { diff --git a/media/filters/video_renderer_base_unittest.cc b/media/filters/video_renderer_base_unittest.cc index b033eeb..5e95ac9 100644 --- a/media/filters/video_renderer_base_unittest.cc +++ b/media/filters/video_renderer_base_unittest.cc @@ -36,10 +36,6 @@ static const int64 kVideoDuration = kFrameDuration * 100; static const int64 kEndOfStream = kint64min; static const gfx::Size kNaturalSize(16u, 16u); -ACTION(OnStop) { - arg0.Run(); -} - class VideoRendererBaseTest : public ::testing::Test { public: VideoRendererBaseTest() @@ -66,7 +62,7 @@ class VideoRendererBaseTest : public ::testing::Test { EXPECT_CALL(*this, SetOpaqueCBWasCalled(_)) .WillRepeatedly(::testing::Return()); EXPECT_CALL(*decoder_, Stop(_)) - .WillRepeatedly(OnStop()); + .WillRepeatedly(Invoke(RunClosure)); EXPECT_CALL(*this, TimeCBWasCalled(_)) .WillRepeatedly(::testing::Return()); } @@ -98,7 +94,7 @@ class VideoRendererBaseTest : public ::testing::Test { EXPECT_CALL(*decoder_, Read(_)) .WillRepeatedly(Invoke(this, &VideoRendererBaseTest::FrameRequested)); - EXPECT_CALL(*decoder_, Flush(_)) + EXPECT_CALL(*decoder_, Reset(_)) .WillRepeatedly(Invoke(this, &VideoRendererBaseTest::FlushRequested)); InSequence s; diff --git a/media/media.gyp b/media/media.gyp index d762c50..05cae9e 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -180,6 +180,8 @@ 'base/stream_parser.h', 'base/stream_parser_buffer.cc', 'base/stream_parser_buffer.h', + 'base/video_decoder.cc', + 'base/video_decoder.h', 'base/video_decoder_config.cc', 'base/video_decoder_config.h', 'base/video_frame.cc', |