summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-19 15:28:33 +0000
committerscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-19 15:28:33 +0000
commitddbc6ff92d9389a92033ced2bfc5b341a2218fc9 (patch)
treeff8b000cb6d7964fc248160b4f18f94cc77b5a86
parentf4f40a05cea2c55011677d70bf0cada2fa876017 (diff)
downloadchromium_src-ddbc6ff92d9389a92033ced2bfc5b341a2218fc9.zip
chromium_src-ddbc6ff92d9389a92033ced2bfc5b341a2218fc9.tar.gz
chromium_src-ddbc6ff92d9389a92033ced2bfc5b341a2218fc9.tar.bz2
Reland: Remove reference counting from media::VideoDecoder and friends.
In addition: * VideoRenderer is now passed a list of decoders via constructor instead of Initialize() * WebMediaPlayerImpl's FilterCollection is now built in one shot instead of incrementally BUG=173313 Review URL: https://chromiumcodereview.appspot.com/14348007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195212 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/base/filter_collection.cc5
-rw-r--r--media/base/filter_collection.h8
-rw-r--r--media/base/mock_filters.h19
-rw-r--r--media/base/pipeline.cc2
-rw-r--r--media/base/pipeline_unittest.cc27
-rw-r--r--media/base/video_decoder.h12
-rw-r--r--media/base/video_renderer.h9
-rw-r--r--media/filters/decrypting_video_decoder.cc14
-rw-r--r--media/filters/decrypting_video_decoder.h8
-rw-r--r--media/filters/decrypting_video_decoder_unittest.cc2
-rw-r--r--media/filters/ffmpeg_video_decoder.cc5
-rw-r--r--media/filters/ffmpeg_video_decoder.h8
-rw-r--r--media/filters/ffmpeg_video_decoder_unittest.cc6
-rw-r--r--media/filters/gpu_video_decoder.cc224
-rw-r--r--media/filters/gpu_video_decoder.h19
-rw-r--r--media/filters/pipeline_integration_test_base.cc13
-rw-r--r--media/filters/video_decoder_selector.cc79
-rw-r--r--media/filters/video_decoder_selector.h20
-rw-r--r--media/filters/video_decoder_selector_unittest.cc56
-rw-r--r--media/filters/video_frame_stream.cc31
-rw-r--r--media/filters/video_frame_stream.h17
-rw-r--r--media/filters/video_frame_stream_unittest.cc31
-rw-r--r--media/filters/video_renderer_base.cc8
-rw-r--r--media/filters/video_renderer_base.h10
-rw-r--r--media/filters/video_renderer_base_unittest.cc9
-rw-r--r--media/filters/vpx_video_decoder.cc4
-rw-r--r--media/filters/vpx_video_decoder.h8
-rw-r--r--media/tools/player_x11/player_x11.cc7
-rw-r--r--webkit/media/filter_helpers.cc81
-rw-r--r--webkit/media/filter_helpers.h49
-rw-r--r--webkit/media/webkit_media.gypi2
-rw-r--r--webkit/media/webmediaplayer_impl.cc134
-rw-r--r--webkit/media/webmediaplayer_impl.h10
33 files changed, 463 insertions, 474 deletions
diff --git a/media/base/filter_collection.cc b/media/base/filter_collection.cc
index 148a192..911edd5 100644
--- a/media/base/filter_collection.cc
+++ b/media/base/filter_collection.cc
@@ -7,7 +7,6 @@
#include "base/logging.h"
#include "media/base/audio_renderer.h"
#include "media/base/demuxer.h"
-#include "media/base/video_decoder.h"
#include "media/base/video_renderer.h"
namespace media {
@@ -42,8 +41,4 @@ scoped_ptr<VideoRenderer> FilterCollection::GetVideoRenderer() {
return video_renderer_.Pass();
}
-FilterCollection::VideoDecoderList* FilterCollection::GetVideoDecoders() {
- return &video_decoders_;
-}
-
} // namespace media
diff --git a/media/base/filter_collection.h b/media/base/filter_collection.h
index e8b62f8..07266c6 100644
--- a/media/base/filter_collection.h
+++ b/media/base/filter_collection.h
@@ -5,8 +5,6 @@
#ifndef MEDIA_BASE_FILTER_COLLECTION_H_
#define MEDIA_BASE_FILTER_COLLECTION_H_
-#include <list>
-
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/media_export.h"
@@ -15,7 +13,6 @@ namespace media {
class AudioRenderer;
class Demuxer;
-class VideoDecoder;
class VideoRenderer;
// Represents a set of uninitialized demuxer and audio/video decoders and
@@ -25,8 +22,6 @@ class VideoRenderer;
// http://crbug.com/110800
class MEDIA_EXPORT FilterCollection {
public:
- typedef std::list<scoped_refptr<VideoDecoder> > VideoDecoderList;
-
FilterCollection();
~FilterCollection();
@@ -39,11 +34,8 @@ class MEDIA_EXPORT FilterCollection {
void SetVideoRenderer(scoped_ptr<VideoRenderer> video_renderer);
scoped_ptr<VideoRenderer> GetVideoRenderer();
- VideoDecoderList* GetVideoDecoders();
-
private:
scoped_refptr<Demuxer> demuxer_;
- VideoDecoderList video_decoders_;
scoped_ptr<AudioRenderer> audio_renderer_;
scoped_ptr<VideoRenderer> video_renderer_;
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index d0430a6..56b523a 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -109,16 +109,15 @@ class MockVideoRenderer : public VideoRenderer {
virtual ~MockVideoRenderer();
// VideoRenderer implementation.
- MOCK_METHOD10(Initialize, void(const scoped_refptr<DemuxerStream>& stream,
- const VideoDecoderList& decoders,
- const PipelineStatusCB& init_cb,
- const StatisticsCB& statistics_cb,
- const TimeCB& time_cb,
- const NaturalSizeChangedCB& size_changed_cb,
- const base::Closure& ended_cb,
- const PipelineStatusCB& error_cb,
- const TimeDeltaCB& get_time_cb,
- const TimeDeltaCB& get_duration_cb));
+ MOCK_METHOD9(Initialize, void(const scoped_refptr<DemuxerStream>& stream,
+ const PipelineStatusCB& init_cb,
+ const StatisticsCB& statistics_cb,
+ const TimeCB& time_cb,
+ const NaturalSizeChangedCB& size_changed_cb,
+ const base::Closure& ended_cb,
+ const PipelineStatusCB& error_cb,
+ const TimeDeltaCB& get_time_cb,
+ const TimeDeltaCB& get_duration_cb));
MOCK_METHOD1(Play, void(const base::Closure& callback));
MOCK_METHOD1(Pause, void(const base::Closure& callback));
MOCK_METHOD1(Flush, void(const base::Closure& callback));
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc
index e656ef3..5ee835b 100644
--- a/media/base/pipeline.cc
+++ b/media/base/pipeline.cc
@@ -946,7 +946,6 @@ void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) {
video_renderer_ = filter_collection_->GetVideoRenderer();
video_renderer_->Initialize(
stream,
- *filter_collection_->GetVideoDecoders(),
done_cb,
base::Bind(&Pipeline::OnUpdateStatistics, this),
base::Bind(&Pipeline::OnVideoTimeUpdate, this),
@@ -955,7 +954,6 @@ void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) {
base::Bind(&Pipeline::SetError, this),
base::Bind(&Pipeline::GetMediaTime, this),
base::Bind(&Pipeline::GetMediaDuration, this));
- filter_collection_->GetVideoDecoders()->clear();
}
void Pipeline::OnAudioUnderflow() {
diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc
index 59d768b..988bb80 100644
--- a/media/base/pipeline_unittest.cc
+++ b/media/base/pipeline_unittest.cc
@@ -87,9 +87,6 @@ class PipelineTest : public ::testing::Test {
demuxer_ = new MockDemuxer();
filter_collection_->SetDemuxer(demuxer_);
- video_decoder_ = new MockVideoDecoder();
- filter_collection_->GetVideoDecoders()->push_back(video_decoder_);
-
video_renderer_ = new MockVideoRenderer();
scoped_ptr<VideoRenderer> video_renderer(video_renderer_);
filter_collection_->SetVideoRenderer(video_renderer.Pass());
@@ -166,14 +163,12 @@ class PipelineTest : public ::testing::Test {
// Sets up expectations to allow the video renderer to initialize.
void InitializeVideoRenderer(const scoped_refptr<DemuxerStream>& stream) {
- EXPECT_CALL(*video_renderer_,
- Initialize(stream, _, _, _, _, _, _, _, _, _))
- .WillOnce(RunCallback<2>(PIPELINE_OK));
+ EXPECT_CALL(*video_renderer_, Initialize(stream, _, _, _, _, _, _, _, _))
+ .WillOnce(RunCallback<1>(PIPELINE_OK));
EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
// Startup sequence.
- EXPECT_CALL(*video_renderer_,
- Preroll(demuxer_->GetStartTime(), _))
+ EXPECT_CALL(*video_renderer_, Preroll(demuxer_->GetStartTime(), _))
.WillOnce(RunCallback<1>(PIPELINE_OK));
EXPECT_CALL(*video_renderer_, Play(_))
.WillOnce(RunClosure<0>());
@@ -301,7 +296,6 @@ class PipelineTest : public ::testing::Test {
scoped_ptr<FilterCollection> filter_collection_;
scoped_refptr<MockDemuxer> demuxer_;
- scoped_refptr<MockVideoDecoder> video_decoder_;
MockVideoRenderer* video_renderer_;
MockAudioRenderer* audio_renderer_;
scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream_;
@@ -1016,16 +1010,14 @@ class PipelineTeardownTest : public PipelineTest {
if (state == kInitVideoRenderer) {
if (stop_or_error == kStop) {
- EXPECT_CALL(*video_renderer_,
- Initialize(_, _, _, _, _, _, _, _, _, _))
+ EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
.WillOnce(DoAll(Stop(pipeline_, stop_cb),
- RunCallback<2>(PIPELINE_OK)));
+ RunCallback<1>(PIPELINE_OK)));
EXPECT_CALL(callbacks_, OnStop());
} else {
status = PIPELINE_ERROR_INITIALIZATION_FAILED;
- EXPECT_CALL(*video_renderer_,
- Initialize(_, _, _, _, _, _, _, _, _, _))
- .WillOnce(RunCallback<2>(status));
+ EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
+ .WillOnce(RunCallback<1>(status));
}
EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
@@ -1034,9 +1026,8 @@ class PipelineTeardownTest : public PipelineTest {
return status;
}
- EXPECT_CALL(*video_renderer_,
- Initialize(_, _, _, _, _, _, _, _, _, _))
- .WillOnce(RunCallback<2>(PIPELINE_OK));
+ EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
+ .WillOnce(RunCallback<1>(PIPELINE_OK));
EXPECT_CALL(callbacks_, OnBufferingState(Pipeline::kHaveMetadata));
diff --git a/media/base/video_decoder.h b/media/base/video_decoder.h
index 97566da..4611645 100644
--- a/media/base/video_decoder.h
+++ b/media/base/video_decoder.h
@@ -16,8 +16,7 @@ namespace media {
class DemuxerStream;
class VideoFrame;
-class MEDIA_EXPORT VideoDecoder
- : public base::RefCountedThreadSafe<VideoDecoder> {
+class MEDIA_EXPORT VideoDecoder {
public:
// Status codes for read operations on VideoDecoder.
enum Status {
@@ -26,6 +25,9 @@ class MEDIA_EXPORT VideoDecoder
kDecryptError // Decrypting error happened.
};
+ VideoDecoder();
+ virtual ~VideoDecoder();
+
// Initializes a VideoDecoder with the given DemuxerStream, executing the
// |status_cb| upon completion.
// |statistics_cb| is used to update the global pipeline statistics.
@@ -77,11 +79,7 @@ class MEDIA_EXPORT VideoDecoder
// use a fixed set of VideoFrames for decoding.
virtual bool HasOutputFrameAvailable() const;
- protected:
- friend class base::RefCountedThreadSafe<VideoDecoder>;
- virtual ~VideoDecoder();
- VideoDecoder();
-
+ private:
DISALLOW_COPY_AND_ASSIGN(VideoDecoder);
};
diff --git a/media/base/video_renderer.h b/media/base/video_renderer.h
index c609b68..9d42d14 100644
--- a/media/base/video_renderer.h
+++ b/media/base/video_renderer.h
@@ -5,8 +5,6 @@
#ifndef MEDIA_BASE_VIDEO_RENDERER_H_
#define MEDIA_BASE_VIDEO_RENDERER_H_
-#include <list>
-
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/time.h"
@@ -24,8 +22,6 @@ class VideoDecoder;
class MEDIA_EXPORT VideoRenderer {
public:
- typedef std::list<scoped_refptr<VideoDecoder> > VideoDecoderList;
-
// Used to update the pipeline's clock time. The parameter is the time that
// the clock should not exceed.
typedef base::Callback<void(base::TimeDelta)> TimeCB;
@@ -39,8 +35,8 @@ class MEDIA_EXPORT VideoRenderer {
VideoRenderer();
virtual ~VideoRenderer();
- // Initialize a VideoRenderer with the given DemuxerStream and
- // VideoDecoderList, executing |init_cb| callback upon completion.
+ // Initialize a VideoRenderer with |stream|, executing |init_cb| upon
+ // completion.
//
// |statistics_cb| is executed periodically with video rendering stats, such
// as dropped frames.
@@ -58,7 +54,6 @@ class MEDIA_EXPORT VideoRenderer {
//
// |get_duration_cb| is used to query the media duration.
virtual void Initialize(const scoped_refptr<DemuxerStream>& stream,
- const VideoDecoderList& decoders,
const PipelineStatusCB& init_cb,
const StatisticsCB& statistics_cb,
const TimeCB& time_cb,
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc
index 6fe6e69..6179fd7 100644
--- a/media/filters/decrypting_video_decoder.cc
+++ b/media/filters/decrypting_video_decoder.cc
@@ -24,6 +24,7 @@ DecryptingVideoDecoder::DecryptingVideoDecoder(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
const SetDecryptorReadyCB& set_decryptor_ready_cb)
: message_loop_(message_loop),
+ weak_factory_(this),
state_(kUninitialized),
set_decryptor_ready_cb_(set_decryptor_ready_cb),
decryptor_(NULL),
@@ -40,6 +41,7 @@ void DecryptingVideoDecoder::Initialize(
DCHECK_EQ(state_, kUninitialized) << state_;
DCHECK(stream);
init_cb_ = BindToCurrentLoop(status_cb);
+ weak_this_ = weak_factory_.GetWeakPtr();
const VideoDecoderConfig& config = stream->video_decoder_config();
if (!config.IsValidConfig()) {
@@ -61,7 +63,7 @@ void DecryptingVideoDecoder::Initialize(
state_ = kDecryptorRequested;
set_decryptor_ready_cb_.Run(BindToCurrentLoop(base::Bind(
- &DecryptingVideoDecoder::SetDecryptor, this)));
+ &DecryptingVideoDecoder::SetDecryptor, weak_this_)));
}
void DecryptingVideoDecoder::Read(const ReadCB& read_cb) {
@@ -166,7 +168,7 @@ void DecryptingVideoDecoder::SetDecryptor(Decryptor* decryptor) {
state_ = kPendingDecoderInit;
decryptor_->InitializeVideoDecoder(
demuxer_stream_->video_decoder_config(), BindToCurrentLoop(base::Bind(
- &DecryptingVideoDecoder::FinishInitialization, this)));
+ &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
}
void DecryptingVideoDecoder::FinishInitialization(bool success) {
@@ -188,7 +190,7 @@ void DecryptingVideoDecoder::FinishInitialization(bool success) {
}
decryptor_->RegisterNewKeyCB(Decryptor::kVideo, BindToCurrentLoop(
- base::Bind(&DecryptingVideoDecoder::OnKeyAdded, this)));
+ base::Bind(&DecryptingVideoDecoder::OnKeyAdded, weak_this_)));
// Success!
state_ = kIdle;
@@ -230,7 +232,7 @@ void DecryptingVideoDecoder::ReadFromDemuxerStream() {
DCHECK(!read_cb_.is_null());
demuxer_stream_->Read(
- base::Bind(&DecryptingVideoDecoder::DecryptAndDecodeBuffer, this));
+ base::Bind(&DecryptingVideoDecoder::DecryptAndDecodeBuffer, weak_this_));
}
void DecryptingVideoDecoder::DecryptAndDecodeBuffer(
@@ -253,7 +255,7 @@ void DecryptingVideoDecoder::DecryptAndDecodeBuffer(
decryptor_->DeinitializeDecoder(Decryptor::kVideo);
decryptor_->InitializeVideoDecoder(
demuxer_stream_->video_decoder_config(), BindToCurrentLoop(base::Bind(
- &DecryptingVideoDecoder::FinishConfigChange, this)));
+ &DecryptingVideoDecoder::FinishConfigChange, weak_this_)));
return;
}
@@ -289,7 +291,7 @@ void DecryptingVideoDecoder::DecodePendingBuffer() {
decryptor_->DecryptAndDecodeVideo(
pending_buffer_to_decode_, BindToCurrentLoop(base::Bind(
- &DecryptingVideoDecoder::DeliverFrame, this, buffer_size)));
+ &DecryptingVideoDecoder::DeliverFrame, weak_this_, buffer_size)));
}
void DecryptingVideoDecoder::DeliverFrame(
diff --git a/media/filters/decrypting_video_decoder.h b/media/filters/decrypting_video_decoder.h
index 9da57a1..eeb4210 100644
--- a/media/filters/decrypting_video_decoder.h
+++ b/media/filters/decrypting_video_decoder.h
@@ -6,7 +6,7 @@
#define MEDIA_FILTERS_DECRYPTING_VIDEO_DECODER_H_
#include "base/callback.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "media/base/decryptor.h"
#include "media/base/demuxer_stream.h"
#include "media/base/video_decoder.h"
@@ -34,6 +34,7 @@ class MEDIA_EXPORT DecryptingVideoDecoder : public VideoDecoder {
DecryptingVideoDecoder(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
const SetDecryptorReadyCB& set_decryptor_ready_cb);
+ virtual ~DecryptingVideoDecoder();
// VideoDecoder implementation.
virtual void Initialize(const scoped_refptr<DemuxerStream>& stream,
@@ -43,9 +44,6 @@ class MEDIA_EXPORT DecryptingVideoDecoder : public VideoDecoder {
virtual void Reset(const base::Closure& closure) OVERRIDE;
virtual void Stop(const base::Closure& closure) OVERRIDE;
- protected:
- virtual ~DecryptingVideoDecoder();
-
private:
// For a detailed state diagram please see this link: http://goo.gl/8jAok
// TODO(xhwang): Add a ASCII state diagram in this file after this class
@@ -96,6 +94,8 @@ class MEDIA_EXPORT DecryptingVideoDecoder : public VideoDecoder {
void DoStop();
scoped_refptr<base::MessageLoopProxy> message_loop_;
+ base::WeakPtrFactory<DecryptingVideoDecoder> weak_factory_;
+ base::WeakPtr<DecryptingVideoDecoder> weak_this_;
State state_;
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
index 9d8462e..140206f 100644
--- a/media/filters/decrypting_video_decoder_unittest.cc
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -235,7 +235,7 @@ class DecryptingVideoDecoderTest : public testing::Test {
const scoped_refptr<VideoFrame>&));
MessageLoop message_loop_;
- scoped_refptr<DecryptingVideoDecoder> decoder_;
+ scoped_ptr<DecryptingVideoDecoder> decoder_;
scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
scoped_refptr<StrictMock<MockDemuxerStream> > demuxer_;
MockStatisticsCB statistics_cb_;
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 9dd4058..105199f 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -58,6 +58,7 @@ static int GetThreadCount(CodecID codec_id) {
FFmpegVideoDecoder::FFmpegVideoDecoder(
const scoped_refptr<base::MessageLoopProxy>& message_loop)
: message_loop_(message_loop),
+ weak_factory_(this),
state_(kUninitialized),
codec_context_(NULL),
av_frame_(NULL) {
@@ -134,6 +135,7 @@ void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
const StatisticsCB& statistics_cb) {
DCHECK(message_loop_->BelongsToCurrentThread());
PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
+ weak_this_ = weak_factory_.GetWeakPtr();
FFmpegGlue::InitializeFFmpeg();
DCHECK(!demuxer_stream_) << "Already initialized.";
@@ -224,7 +226,8 @@ void FFmpegVideoDecoder::ReturnFrameOrReadFromDemuxerStream() {
DCHECK_NE(state_, kUninitialized);
DCHECK_NE(state_, kDecodeFinished);
DCHECK(!read_cb_.is_null());
- demuxer_stream_->Read(base::Bind(&FFmpegVideoDecoder::BufferReady, this));
+ demuxer_stream_->Read(base::Bind(
+ &FFmpegVideoDecoder::BufferReady, weak_this_));
}
void FFmpegVideoDecoder::BufferReady(
diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h
index 4c6629e..de83814 100644
--- a/media/filters/ffmpeg_video_decoder.h
+++ b/media/filters/ffmpeg_video_decoder.h
@@ -8,7 +8,7 @@
#include <list>
#include "base/callback.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "media/base/demuxer_stream.h"
#include "media/base/video_decoder.h"
@@ -27,6 +27,7 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder {
public:
explicit FFmpegVideoDecoder(
const scoped_refptr<base::MessageLoopProxy>& message_loop);
+ virtual ~FFmpegVideoDecoder();
// VideoDecoder implementation.
virtual void Initialize(const scoped_refptr<DemuxerStream>& stream,
@@ -41,9 +42,6 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder {
// documentation inside FFmpeg.
int GetVideoBuffer(AVCodecContext *codec_context, AVFrame* frame);
- protected:
- virtual ~FFmpegVideoDecoder();
-
private:
enum DecoderState {
kUninitialized,
@@ -74,6 +72,8 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder {
void DoReset();
scoped_refptr<base::MessageLoopProxy> message_loop_;
+ base::WeakPtrFactory<FFmpegVideoDecoder> weak_factory_;
+ base::WeakPtr<FFmpegVideoDecoder> weak_this_;
DecoderState state_;
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 1aa1de33..863c317 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -50,14 +50,12 @@ ACTION_P(ReturnBuffer, buffer) {
class FFmpegVideoDecoderTest : public testing::Test {
public:
FFmpegVideoDecoderTest()
- : decoder_(NULL),
+ : decoder_(new FFmpegVideoDecoder(message_loop_.message_loop_proxy())),
demuxer_(new StrictMock<MockDemuxerStream>()),
read_cb_(base::Bind(&FFmpegVideoDecoderTest::FrameReady,
base::Unretained(this))) {
FFmpegGlue::InitializeFFmpeg();
- decoder_ = new FFmpegVideoDecoder(message_loop_.message_loop_proxy());
-
// Initialize various test buffers.
frame_buffer_.reset(new uint8[kCodedSize.GetArea()]);
end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer();
@@ -201,7 +199,7 @@ class FFmpegVideoDecoderTest : public testing::Test {
const scoped_refptr<VideoFrame>&));
MessageLoop message_loop_;
- scoped_refptr<FFmpegVideoDecoder> decoder_;
+ scoped_ptr<FFmpegVideoDecoder> decoder_;
scoped_refptr<StrictMock<MockDemuxerStream> > demuxer_;
MockStatisticsCB statistics_cb_;
VideoDecoderConfig config_;
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index a2fc662..555164e 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -9,6 +9,7 @@
#include "base/cpu.h"
#include "base/message_loop.h"
#include "base/stl_util.h"
+#include "base/task_runner_util.h"
#include "media/base/bind_to_loop.h"
#include "media/base/decoder_buffer.h"
#include "media/base/demuxer_stream.h"
@@ -18,6 +19,112 @@
namespace media {
+// Proxies calls to a VideoDecodeAccelerator::Client from the calling thread to
+// the client's thread.
+//
+// TODO(scherkus): VDAClientProxy should hold onto GpuVideoDecoder::Factories
+// and take care of some of the work that GpuVideoDecoder does to minimize
+// thread hopping. See following for discussion:
+//
+// https://codereview.chromium.org/12989009/diff/27035/media/filters/gpu_video_decoder.cc#newcode23
+class VDAClientProxy
+ : public base::RefCountedThreadSafe<VDAClientProxy>,
+ public VideoDecodeAccelerator::Client {
+ public:
+ explicit VDAClientProxy(VideoDecodeAccelerator::Client* client);
+
+ // Detaches the proxy. |weak_client_| will no longer be called and can be
+ // safely deleted. Any pending/future calls will be discarded.
+ //
+ // Must be called on |client_loop_|.
+ void Detach();
+
+ // VideoDecodeAccelerator::Client implementation.
+ virtual void NotifyInitializeDone() OVERRIDE;
+ virtual void ProvidePictureBuffers(uint32 count,
+ const gfx::Size& size,
+ uint32 texture_target) OVERRIDE;
+ virtual void DismissPictureBuffer(int32 id) OVERRIDE;
+ virtual void PictureReady(const media::Picture& picture) OVERRIDE;
+ virtual void NotifyEndOfBitstreamBuffer(int32 id) OVERRIDE;
+ virtual void NotifyFlushDone() OVERRIDE;
+ virtual void NotifyResetDone() OVERRIDE;
+ virtual void NotifyError(media::VideoDecodeAccelerator::Error error) OVERRIDE;
+
+ private:
+ friend class base::RefCountedThreadSafe<VDAClientProxy>;
+ virtual ~VDAClientProxy();
+
+ scoped_refptr<base::MessageLoopProxy> client_loop_;
+
+ // Weak pointers are used to invalidate tasks posted to |client_loop_| after
+ // Detach() has been called.
+ base::WeakPtrFactory<VideoDecodeAccelerator::Client> weak_client_factory_;
+ base::WeakPtr<VideoDecodeAccelerator::Client> weak_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(VDAClientProxy);
+};
+
+VDAClientProxy::VDAClientProxy(VideoDecodeAccelerator::Client* client)
+ : client_loop_(base::MessageLoopProxy::current()),
+ weak_client_factory_(client),
+ weak_client_(weak_client_factory_.GetWeakPtr()) {
+ DCHECK(weak_client_);
+}
+
+VDAClientProxy::~VDAClientProxy() {}
+
+void VDAClientProxy::Detach() {
+ DCHECK(client_loop_->BelongsToCurrentThread());
+ DCHECK(weak_client_) << "Detach() already called";
+ weak_client_factory_.InvalidateWeakPtrs();
+}
+
+void VDAClientProxy::NotifyInitializeDone() {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyInitializeDone, weak_client_));
+}
+
+void VDAClientProxy::ProvidePictureBuffers(uint32 count,
+ const gfx::Size& size,
+ uint32 texture_target) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::ProvidePictureBuffers, weak_client_,
+ count, size, texture_target));
+}
+
+void VDAClientProxy::DismissPictureBuffer(int32 id) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::DismissPictureBuffer, weak_client_, id));
+}
+
+void VDAClientProxy::PictureReady(const media::Picture& picture) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::PictureReady, weak_client_, picture));
+}
+
+void VDAClientProxy::NotifyEndOfBitstreamBuffer(int32 id) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyEndOfBitstreamBuffer, weak_client_,
+ id));
+}
+
+void VDAClientProxy::NotifyFlushDone() {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyFlushDone, weak_client_));
+}
+
+void VDAClientProxy::NotifyResetDone() {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyResetDone, weak_client_));
+}
+
+void VDAClientProxy::NotifyError(media::VideoDecodeAccelerator::Error error) {
+ client_loop_->PostTask(FROM_HERE, base::Bind(
+ &VideoDecodeAccelerator::Client::NotifyError, weak_client_, error));
+}
+
+
// Maximum number of concurrent VDA::Decode() operations GVD will maintain.
// Higher values allow better pipelining in the GPU, but also require more
// resources.
@@ -54,6 +161,7 @@ GpuVideoDecoder::GpuVideoDecoder(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
const scoped_refptr<Factories>& factories)
: gvd_loop_proxy_(message_loop),
+ weak_factory_(this),
vda_loop_proxy_(factories->GetMessageLoop()),
factories_(factories),
state_(kNormal),
@@ -71,7 +179,7 @@ void GpuVideoDecoder::Reset(const base::Closure& closure) {
if (state_ == kDrainingDecoder && !factories_->IsAborted()) {
gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::Reset, this, closure));
+ &GpuVideoDecoder::Reset, weak_this_, closure));
// NOTE: if we're deferring Reset() until a Flush() completes, return
// queued pictures to the VDA so they can be used to finish that Flush().
if (pending_read_cb_.is_null())
@@ -113,6 +221,8 @@ void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
const PipelineStatusCB& orig_status_cb,
const StatisticsCB& statistics_cb) {
DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
+ weak_this_ = weak_factory_.GetWeakPtr();
+
PipelineStatusCB status_cb = CreateUMAReportingPipelineCB(
"Media.GpuVideoDecoderInitializeStatus",
BindToCurrentLoop(orig_status_cb));
@@ -150,8 +260,9 @@ void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
}
}
+ client_proxy_ = new VDAClientProxy(this);
VideoDecodeAccelerator* vda =
- factories_->CreateVideoDecodeAccelerator(config.profile(), this);
+ factories_->CreateVideoDecodeAccelerator(config.profile(), client_proxy_);
if (!vda) {
status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
return;
@@ -164,17 +275,21 @@ void GpuVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
statistics_cb_ = statistics_cb;
DVLOG(1) << "GpuVideoDecoder::Initialize() succeeded.";
- vda_loop_proxy_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&GpuVideoDecoder::SetVDA, this, vda),
- base::Bind(status_cb, PIPELINE_OK));
+ PostTaskAndReplyWithResult(
+ vda_loop_proxy_, FROM_HERE,
+ base::Bind(&VideoDecodeAccelerator::AsWeakPtr, base::Unretained(vda)),
+ base::Bind(&GpuVideoDecoder::SetVDA, weak_this_, status_cb, vda));
}
-void GpuVideoDecoder::SetVDA(VideoDecodeAccelerator* vda) {
- DCHECK(vda_loop_proxy_->BelongsToCurrentThread());
+void GpuVideoDecoder::SetVDA(
+ const PipelineStatusCB& status_cb,
+ VideoDecodeAccelerator* vda,
+ base::WeakPtr<VideoDecodeAccelerator> weak_vda) {
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
DCHECK(!vda_.get());
vda_.reset(vda);
- weak_vda_ = vda->AsWeakPtr();
+ weak_vda_ = weak_vda;
+ status_cb.Run(PIPELINE_OK);
}
void GpuVideoDecoder::DestroyTextures() {
@@ -186,17 +301,25 @@ void GpuVideoDecoder::DestroyTextures() {
picture_buffers_in_decoder_.clear();
}
+static void DestroyVDAWithClientProxy(
+ const scoped_refptr<VDAClientProxy>& client_proxy,
+ base::WeakPtr<VideoDecodeAccelerator> weak_vda) {
+ if (weak_vda) {
+ weak_vda->Destroy();
+ DCHECK(!weak_vda); // Check VDA::Destroy() contract.
+ }
+}
+
void GpuVideoDecoder::DestroyVDA() {
DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
+
+ // |client_proxy| must stay alive until |weak_vda_| has been destroyed.
+ vda_loop_proxy_->PostTask(FROM_HERE, base::Bind(
+ &DestroyVDAWithClientProxy, client_proxy_, weak_vda_));
+
VideoDecodeAccelerator* vda ALLOW_UNUSED = vda_.release();
- // Tricky: |this| needs to stay alive until after VDA::Destroy is actually
- // called, not just posted, so we take an artificial ref to |this| and release
- // it as |reply| after VDA::Destroy() returns.
- AddRef();
- vda_loop_proxy_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&VideoDecodeAccelerator::Destroy, weak_vda_),
- base::Bind(&GpuVideoDecoder::Release, this));
+ client_proxy_->Detach();
+ client_proxy_ = NULL;
DestroyTextures();
}
@@ -244,13 +367,9 @@ bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() {
void GpuVideoDecoder::RequestBufferDecode(
DemuxerStream::Status status,
const scoped_refptr<DecoderBuffer>& buffer) {
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status;
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::RequestBufferDecode, this, status, buffer));
- return;
- }
demuxer_read_in_progress_ = false;
if (status != DemuxerStream::kOk) {
@@ -305,7 +424,7 @@ void GpuVideoDecoder::RequestBufferDecode(
if (CanMoreDecodeWorkBeDone()) {
// Force post here to prevent reentrancy into DemuxerStream.
gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::EnsureDemuxOrDecode, this));
+ &GpuVideoDecoder::EnsureDemuxOrDecode, weak_this_));
}
}
@@ -358,12 +477,7 @@ void GpuVideoDecoder::NotifyInitializeDone() {
void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
const gfx::Size& size,
uint32 texture_target) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::ProvidePictureBuffers, this, count, size,
- texture_target));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
std::vector<uint32> texture_ids;
decoder_texture_target_ = texture_target;
@@ -393,11 +507,8 @@ void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
}
void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::DismissPictureBuffer, this, id));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
+
std::map<int32, PictureBuffer>::iterator it =
picture_buffers_in_decoder_.find(id);
if (it == picture_buffers_in_decoder_.end()) {
@@ -409,11 +520,8 @@ void GpuVideoDecoder::DismissPictureBuffer(int32 id) {
}
void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::PictureReady, this, picture));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
+
std::map<int32, PictureBuffer>::iterator it =
picture_buffers_in_decoder_.find(picture.picture_buffer_id());
if (it == picture_buffers_in_decoder_.end()) {
@@ -437,8 +545,9 @@ void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(),
decoder_texture_target_,
gfx::Size(visible_rect.width(), visible_rect.height())),
- base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this,
- picture.picture_buffer_id())));
+ BindToCurrentLoop(base::Bind(
+ &GpuVideoDecoder::ReusePictureBuffer, weak_this_,
+ picture.picture_buffer_id()))));
CHECK_GT(available_pictures_, 0);
available_pictures_--;
@@ -467,11 +576,7 @@ void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery(
}
void GpuVideoDecoder::ReusePictureBuffer(int64 picture_buffer_id) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::ReusePictureBuffer, this, picture_buffer_id));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
CHECK_GE(available_pictures_, 0);
available_pictures_++;
@@ -504,11 +609,7 @@ void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) {
}
void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyEndOfBitstreamBuffer, this, id));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
std::map<int32, BufferPair>::iterator it =
bitstream_buffers_in_decoder_.find(id);
@@ -563,27 +664,18 @@ void GpuVideoDecoder::EnsureDemuxOrDecode() {
demuxer_read_in_progress_ = true;
demuxer_stream_->Read(base::Bind(
- &GpuVideoDecoder::RequestBufferDecode, this));
+ &GpuVideoDecoder::RequestBufferDecode, weak_this_));
}
void GpuVideoDecoder::NotifyFlushDone() {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyFlushDone, this));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
DCHECK_EQ(state_, kDrainingDecoder);
state_ = kDecoderDrained;
EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEmptyFrame());
}
void GpuVideoDecoder::NotifyResetDone() {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyResetDone, this));
- return;
- }
-
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
DCHECK(ready_video_frames_.empty());
// This needs to happen after the Reset() on vda_ is done to ensure pictures
@@ -598,11 +690,7 @@ void GpuVideoDecoder::NotifyResetDone() {
}
void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) {
- if (!gvd_loop_proxy_->BelongsToCurrentThread()) {
- gvd_loop_proxy_->PostTask(FROM_HERE, base::Bind(
- &GpuVideoDecoder::NotifyError, this, error));
- return;
- }
+ DCHECK(gvd_loop_proxy_->BelongsToCurrentThread());
if (!vda_.get())
return;
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h
index 6acc2de..c2defb3 100644
--- a/media/filters/gpu_video_decoder.h
+++ b/media/filters/gpu_video_decoder.h
@@ -10,6 +10,7 @@
#include <utility>
#include <vector>
+#include "base/memory/weak_ptr.h"
#include "media/base/pipeline_status.h"
#include "media/base/demuxer_stream.h"
#include "media/base/video_decoder.h"
@@ -27,6 +28,7 @@ class SkBitmap;
namespace media {
class DecoderBuffer;
+class VDAClientProxy;
// GPU-accelerated video decoder implementation. Relies on
// AcceleratedVideoDecoderMsg_Decode and friends.
@@ -64,7 +66,7 @@ class MEDIA_EXPORT GpuVideoDecoder
// attempts at factory operations
virtual void Abort() = 0;
- // Returns true if Abort has been called.
+ // Returns true if Abort() has been called.
virtual bool IsAborted() = 0;
protected:
@@ -134,9 +136,10 @@ class MEDIA_EXPORT GpuVideoDecoder
void GetBufferData(int32 id, base::TimeDelta* timetamp,
gfx::Rect* visible_rect, gfx::Size* natural_size);
- // Set |vda_| and |weak_vda_| on the VDA thread (in practice the render
- // thread).
- void SetVDA(VideoDecodeAccelerator* vda);
+ // Sets |vda_| and |weak_vda_| on the GVD thread and runs |status_cb|.
+ void SetVDA(const PipelineStatusCB& status_cb,
+ VideoDecodeAccelerator* vda,
+ base::WeakPtr<VideoDecodeAccelerator> weak_vda);
// Call VDA::Destroy() on |vda_loop_proxy_| ensuring that |this| outlives the
// Destroy() call.
@@ -167,6 +170,8 @@ class MEDIA_EXPORT GpuVideoDecoder
// MessageLoop on which to fire callbacks and trampoline calls to this class
// if they arrive on other loops.
scoped_refptr<base::MessageLoopProxy> gvd_loop_proxy_;
+ base::WeakPtrFactory<GpuVideoDecoder> weak_factory_;
+ base::WeakPtr<GpuVideoDecoder> weak_this_;
// Message loop on which to makes all calls to vda_. (beware this loop may be
// paused during the Pause/Flush/Stop dance PipelineImpl::Stop() goes
@@ -175,8 +180,12 @@ class MEDIA_EXPORT GpuVideoDecoder
scoped_refptr<Factories> factories_;
+ // Proxies calls from |vda_| to |gvd_loop_proxy_| and used to safely detach
+ // during shutdown.
+ scoped_refptr<VDAClientProxy> client_proxy_;
+
// Populated during Initialize() via SetVDA() (on success) and unchanged
- // until an error occurs
+ // until an error occurs.
scoped_ptr<VideoDecodeAccelerator> vda_;
// Used to post tasks from the GVD thread to the VDA thread safely.
base::WeakPtr<VideoDecodeAccelerator> weak_vda_;
diff --git a/media/filters/pipeline_integration_test_base.cc b/media/filters/pipeline_integration_test_base.cc
index 1b650d5..0be9861 100644
--- a/media/filters/pipeline_integration_test_base.cc
+++ b/media/filters/pipeline_integration_test_base.cc
@@ -223,16 +223,17 @@ PipelineIntegrationTestBase::CreateFilterCollection(
Decryptor* decryptor) {
scoped_ptr<FilterCollection> collection(new FilterCollection());
collection->SetDemuxer(demuxer);
- scoped_refptr<VideoDecoder> video_decoder = new FFmpegVideoDecoder(
- message_loop_.message_loop_proxy());
- scoped_refptr<VpxVideoDecoder> vpx_decoder = new VpxVideoDecoder(
- message_loop_.message_loop_proxy());
- collection->GetVideoDecoders()->push_back(video_decoder);
- collection->GetVideoDecoders()->push_back(vpx_decoder);
+
+ ScopedVector<VideoDecoder> video_decoders;
+ video_decoders.push_back(
+ new FFmpegVideoDecoder(message_loop_.message_loop_proxy()));
+ video_decoders.push_back(
+ new VpxVideoDecoder(message_loop_.message_loop_proxy()));
// Disable frame dropping if hashing is enabled.
scoped_ptr<VideoRenderer> renderer(new VideoRendererBase(
message_loop_.message_loop_proxy(),
+ video_decoders.Pass(),
base::Bind(&PipelineIntegrationTestBase::SetDecryptor,
base::Unretained(this), decryptor),
base::Bind(&PipelineIntegrationTestBase::OnVideoRendererPaint,
diff --git a/media/filters/video_decoder_selector.cc b/media/filters/video_decoder_selector.cc
index b1f186f..f1aebb26 100644
--- a/media/filters/video_decoder_selector.cc
+++ b/media/filters/video_decoder_selector.cc
@@ -19,10 +19,10 @@ namespace media {
VideoDecoderSelector::VideoDecoderSelector(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
- const VideoDecoderList& decoders,
+ ScopedVector<VideoDecoder> decoders,
const SetDecryptorReadyCB& set_decryptor_ready_cb)
: message_loop_(message_loop),
- decoders_(decoders),
+ decoders_(decoders.Pass()),
set_decryptor_ready_cb_(set_decryptor_ready_cb),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
}
@@ -43,7 +43,8 @@ void VideoDecoderSelector::SelectVideoDecoder(
const VideoDecoderConfig& config = stream->video_decoder_config();
if (!config.IsValidConfig()) {
DLOG(ERROR) << "Invalid video stream config.";
- base::ResetAndReturn(&select_decoder_cb_).Run(NULL, NULL);
+ base::ResetAndReturn(&select_decoder_cb_).Run(
+ scoped_ptr<VideoDecoder>(), NULL);
return;
}
@@ -51,24 +52,19 @@ void VideoDecoderSelector::SelectVideoDecoder(
statistics_cb_ = statistics_cb;
if (!config.is_encrypted()) {
- if (decoders_.empty()) {
- DLOG(ERROR) << "No video decoder can be used to decode the input stream.";
- base::ResetAndReturn(&select_decoder_cb_).Run(NULL, NULL);
- return;
- }
-
- InitializeNextDecoder();
+ InitializeDecoder(decoders_.begin());
return;
}
// This could happen if Encrypted Media Extension (EME) is not enabled.
if (set_decryptor_ready_cb_.is_null()) {
- base::ResetAndReturn(&select_decoder_cb_).Run(NULL, NULL);
+ base::ResetAndReturn(&select_decoder_cb_).Run(
+ scoped_ptr<VideoDecoder>(), NULL);
return;
}
- video_decoder_ = new DecryptingVideoDecoder(message_loop_,
- set_decryptor_ready_cb_);
+ video_decoder_.reset(new DecryptingVideoDecoder(
+ message_loop_, set_decryptor_ready_cb_));
video_decoder_->Initialize(
input_stream_,
@@ -83,16 +79,7 @@ void VideoDecoderSelector::DecryptingVideoDecoderInitDone(
DCHECK(message_loop_->BelongsToCurrentThread());
if (status == PIPELINE_OK) {
- decoders_.clear();
- base::ResetAndReturn(&select_decoder_cb_).Run(video_decoder_, NULL);
- return;
- }
-
- video_decoder_ = NULL;
-
- if (decoders_.empty()) {
- DLOG(ERROR) << "No video decoder can be used to decode the input stream.";
- base::ResetAndReturn(&select_decoder_cb_).Run(NULL, NULL);
+ base::ResetAndReturn(&select_decoder_cb_).Run(video_decoder_.Pass(), NULL);
return;
}
@@ -112,42 +99,48 @@ void VideoDecoderSelector::DecryptingDemuxerStreamInitDone(
if (status != PIPELINE_OK) {
decrypted_stream_ = NULL;
- base::ResetAndReturn(&select_decoder_cb_).Run(NULL, NULL);
+ base::ResetAndReturn(&select_decoder_cb_).Run(
+ scoped_ptr<VideoDecoder>(), NULL);
return;
}
DCHECK(!decrypted_stream_->video_decoder_config().is_encrypted());
input_stream_ = decrypted_stream_;
- InitializeNextDecoder();
+ InitializeDecoder(decoders_.begin());
}
-void VideoDecoderSelector::InitializeNextDecoder() {
+void VideoDecoderSelector::InitializeDecoder(
+ ScopedVector<VideoDecoder>::iterator iter) {
DCHECK(message_loop_->BelongsToCurrentThread());
- DCHECK(!decoders_.empty());
-
- video_decoder_ = decoders_.front();
- decoders_.pop_front();
- DCHECK(video_decoder_);
- video_decoder_->Initialize(input_stream_,
- BindToCurrentLoop(base::Bind(
- &VideoDecoderSelector::DecoderInitDone,
- weak_ptr_factory_.GetWeakPtr())),
- statistics_cb_);
+
+ if (iter == decoders_.end()) {
+ base::ResetAndReturn(&select_decoder_cb_).Run(
+ scoped_ptr<VideoDecoder>(), NULL);
+ return;
+ }
+
+ (*iter)->Initialize(
+ input_stream_,
+ BindToCurrentLoop(base::Bind(
+ &VideoDecoderSelector::DecoderInitDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ iter)),
+ statistics_cb_);
}
-void VideoDecoderSelector::DecoderInitDone(PipelineStatus status) {
+void VideoDecoderSelector::DecoderInitDone(
+ ScopedVector<VideoDecoder>::iterator iter, PipelineStatus status) {
DCHECK(message_loop_->BelongsToCurrentThread());
if (status != PIPELINE_OK) {
- if (!decoders_.empty())
- InitializeNextDecoder();
- else
- base::ResetAndReturn(&select_decoder_cb_).Run(NULL, NULL);
+ InitializeDecoder(++iter);
return;
}
- decoders_.clear();
- base::ResetAndReturn(&select_decoder_cb_).Run(video_decoder_,
+ scoped_ptr<VideoDecoder> video_decoder(*iter);
+ decoders_.weak_erase(iter);
+
+ base::ResetAndReturn(&select_decoder_cb_).Run(video_decoder.Pass(),
decrypted_stream_);
}
diff --git a/media/filters/video_decoder_selector.h b/media/filters/video_decoder_selector.h
index 826bbf8..81a3110 100644
--- a/media/filters/video_decoder_selector.h
+++ b/media/filters/video_decoder_selector.h
@@ -5,10 +5,9 @@
#ifndef MEDIA_FILTERS_VIDEO_DECODER_SELECTOR_H_
#define MEDIA_FILTERS_VIDEO_DECODER_SELECTOR_H_
-#include <list>
-
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "media/base/decryptor.h"
#include "media/base/demuxer_stream.h"
@@ -29,8 +28,6 @@ class Decryptor;
// encrypted, a DecryptingDemuxerStream may also be created.
class MEDIA_EXPORT VideoDecoderSelector {
public:
- typedef std::list<scoped_refptr<VideoDecoder> > VideoDecoderList;
-
// Indicates completion of VideoDecoder selection.
// - First parameter: The initialized VideoDecoder. If it's set to NULL, then
// VideoDecoder initialization failed.
@@ -41,14 +38,16 @@ class MEDIA_EXPORT VideoDecoderSelector {
// The caller should call DecryptingDemuxerStream::Reset() before
// calling VideoDecoder::Reset() to release any pending decryption or read.
typedef base::Callback<
- void(const scoped_refptr<VideoDecoder>&,
+ void(scoped_ptr<VideoDecoder>,
const scoped_refptr<DecryptingDemuxerStream>&)> SelectDecoderCB;
+ // |decoders| contains the VideoDecoders to use when initializing.
+ //
// |set_decryptor_ready_cb| is optional. If |set_decryptor_ready_cb| is null,
// no decryptor will be available to perform decryption.
VideoDecoderSelector(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
- const VideoDecoderList& decoders,
+ ScopedVector<VideoDecoder> decoders,
const SetDecryptorReadyCB& set_decryptor_ready_cb);
~VideoDecoderSelector();
@@ -62,18 +61,19 @@ class MEDIA_EXPORT VideoDecoderSelector {
private:
void DecryptingVideoDecoderInitDone(PipelineStatus status);
void DecryptingDemuxerStreamInitDone(PipelineStatus status);
- void InitializeNextDecoder();
- void DecoderInitDone(PipelineStatus status);
+ void InitializeDecoder(ScopedVector<VideoDecoder>::iterator iter);
+ void DecoderInitDone(ScopedVector<VideoDecoder>::iterator iter,
+ PipelineStatus status);
scoped_refptr<base::MessageLoopProxy> message_loop_;
- VideoDecoderList decoders_;
+ ScopedVector<VideoDecoder> decoders_;
SetDecryptorReadyCB set_decryptor_ready_cb_;
scoped_refptr<DemuxerStream> input_stream_;
StatisticsCB statistics_cb_;
SelectDecoderCB select_decoder_cb_;
- scoped_refptr<VideoDecoder> video_decoder_;
+ scoped_ptr<VideoDecoder> video_decoder_;
scoped_refptr<DecryptingDemuxerStream> decrypted_stream_;
base::WeakPtrFactory<VideoDecoderSelector> weak_ptr_factory_;
diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc
index 8086c62..764a0ba 100644
--- a/media/filters/video_decoder_selector_unittest.cc
+++ b/media/filters/video_decoder_selector_unittest.cc
@@ -18,7 +18,6 @@ using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::ReturnRef;
-using ::testing::SaveArg;
using ::testing::StrictMock;
namespace media {
@@ -52,16 +51,17 @@ class VideoDecoderSelectorTest : public ::testing::Test {
EXPECT_CALL(*demuxer_stream_, type())
.WillRepeatedly(Return(DemuxerStream::VIDEO));
- }
- ~VideoDecoderSelectorTest() {
EXPECT_CALL(*decoder_1_, Stop(_))
.WillRepeatedly(RunClosure<0>());
EXPECT_CALL(*decoder_2_, Stop(_))
.WillRepeatedly(RunClosure<0>());
+ }
- if (selected_decoder_)
+ ~VideoDecoderSelectorTest() {
+ if (selected_decoder_) {
selected_decoder_->Stop(NewExpectedClosure());
+ }
message_loop_.RunUntilIdle();
}
@@ -69,9 +69,16 @@ class VideoDecoderSelectorTest : public ::testing::Test {
MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&));
MOCK_METHOD1(SetDecryptorReadyCallback, void(const media::DecryptorReadyCB&));
MOCK_METHOD2(OnDecoderSelected,
- void(const scoped_refptr<VideoDecoder>&,
+ void(VideoDecoder*,
const scoped_refptr<DecryptingDemuxerStream>&));
+ void MockOnDecoderSelected(
+ scoped_ptr<VideoDecoder> decoder,
+ const scoped_refptr<DecryptingDemuxerStream>& stream) {
+ OnDecoderSelected(decoder.get(), stream);
+ selected_decoder_ = decoder.Pass();
+ }
+
void UseClearStream() {
EXPECT_CALL(*demuxer_stream_, video_decoder_config())
.WillRepeatedly(ReturnRef(clear_video_config_));
@@ -104,12 +111,12 @@ class VideoDecoderSelectorTest : public ::testing::Test {
}
DCHECK_GE(all_decoders_.size(), static_cast<size_t>(num_decoders));
- VideoDecoderSelector::VideoDecoderList decoders(
- all_decoders_.begin(), all_decoders_.begin() + num_decoders);
+ all_decoders_.erase(
+ all_decoders_.begin() + num_decoders, all_decoders_.end());
decoder_selector_.reset(new VideoDecoderSelector(
message_loop_.message_loop_proxy(),
- decoders,
+ all_decoders_.Pass(),
set_decryptor_ready_cb));
}
@@ -118,7 +125,7 @@ class VideoDecoderSelectorTest : public ::testing::Test {
demuxer_stream_,
base::Bind(&VideoDecoderSelectorTest::OnStatistics,
base::Unretained(this)),
- base::Bind(&VideoDecoderSelectorTest::OnDecoderSelected,
+ base::Bind(&VideoDecoderSelectorTest::MockOnDecoderSelected,
base::Unretained(this)));
message_loop_.RunUntilIdle();
}
@@ -131,11 +138,11 @@ class VideoDecoderSelectorTest : public ::testing::Test {
// Use NiceMock since we don't care about most of calls on the decryptor, e.g.
// RegisterNewKeyCB().
scoped_ptr<NiceMock<MockDecryptor> > decryptor_;
- scoped_refptr<StrictMock<MockVideoDecoder> > decoder_1_;
- scoped_refptr<StrictMock<MockVideoDecoder> > decoder_2_;
- std::vector<scoped_refptr<VideoDecoder> > all_decoders_;
+ StrictMock<MockVideoDecoder>* decoder_1_;
+ StrictMock<MockVideoDecoder>* decoder_2_;
+ ScopedVector<VideoDecoder> all_decoders_;
- scoped_refptr<VideoDecoder> selected_decoder_;
+ scoped_ptr<VideoDecoder> selected_decoder_;
MessageLoop message_loop_;
@@ -162,9 +169,7 @@ TEST_F(VideoDecoderSelectorTest, ClearStream_NoDecryptor_OneClearDecoder) {
EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
.WillOnce(RunCallback<1>(PIPELINE_OK));
- EXPECT_CALL(*this, OnDecoderSelected(scoped_refptr<VideoDecoder>(decoder_1_),
- IsNull()))
- .WillOnce(SaveArg<0>(&selected_decoder_));
+ EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
SelectDecoder();
}
@@ -179,9 +184,7 @@ TEST_F(VideoDecoderSelectorTest, ClearStream_NoDecryptor_MultipleClearDecoder) {
.WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED));
EXPECT_CALL(*decoder_2_, Initialize(_, _, _))
.WillOnce(RunCallback<1>(PIPELINE_OK));
- EXPECT_CALL(*this, OnDecoderSelected(scoped_refptr<VideoDecoder>(decoder_2_),
- IsNull()))
- .WillOnce(SaveArg<0>(&selected_decoder_));
+ EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, IsNull()));
SelectDecoder();
}
@@ -194,9 +197,7 @@ TEST_F(VideoDecoderSelectorTest, ClearStream_HasDecryptor) {
EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
.WillOnce(RunCallback<1>(PIPELINE_OK));
- EXPECT_CALL(*this, OnDecoderSelected(scoped_refptr<VideoDecoder>(decoder_1_),
- IsNull()))
- .WillOnce(SaveArg<0>(&selected_decoder_));
+ EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
SelectDecoder();
}
@@ -230,9 +231,7 @@ TEST_F(VideoDecoderSelectorTest, EncryptedStream_DecryptOnly_OneClearDecoder) {
EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
.WillOnce(RunCallback<1>(PIPELINE_OK));
- EXPECT_CALL(*this, OnDecoderSelected(scoped_refptr<VideoDecoder>(decoder_1_),
- NotNull()))
- .WillOnce(SaveArg<0>(&selected_decoder_));
+ EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, NotNull()));
SelectDecoder();
}
@@ -249,9 +248,7 @@ TEST_F(VideoDecoderSelectorTest,
.WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED));
EXPECT_CALL(*decoder_2_, Initialize(_, _, _))
.WillOnce(RunCallback<1>(PIPELINE_OK));
- EXPECT_CALL(*this, OnDecoderSelected(scoped_refptr<VideoDecoder>(decoder_2_),
- NotNull()))
- .WillOnce(SaveArg<0>(&selected_decoder_));
+ EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, NotNull()));
SelectDecoder();
}
@@ -263,8 +260,7 @@ TEST_F(VideoDecoderSelectorTest, EncryptedStream_DecryptAndDecode) {
UseEncryptedStream();
InitializeDecoderSelector(kDecryptAndDecode, 1);
- EXPECT_CALL(*this, OnDecoderSelected(NotNull(), IsNull()))
- .WillOnce(SaveArg<0>(&selected_decoder_));
+ EXPECT_CALL(*this, OnDecoderSelected(NotNull(), IsNull()));
SelectDecoder();
}
diff --git a/media/filters/video_frame_stream.cc b/media/filters/video_frame_stream.cc
index 72ee20d..93f2a0e 100644
--- a/media/filters/video_frame_stream.cc
+++ b/media/filters/video_frame_stream.cc
@@ -19,10 +19,12 @@ namespace media {
VideoFrameStream::VideoFrameStream(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
+ ScopedVector<VideoDecoder> decoders,
const SetDecryptorReadyCB& set_decryptor_ready_cb)
: message_loop_(message_loop),
weak_factory_(this),
state_(UNINITIALIZED),
+ decoders_(decoders.Pass()),
set_decryptor_ready_cb_(set_decryptor_ready_cb) {
}
@@ -31,7 +33,6 @@ VideoFrameStream::~VideoFrameStream() {
}
void VideoFrameStream::Initialize(const scoped_refptr<DemuxerStream>& stream,
- const VideoDecoderList& decoders,
const StatisticsCB& statistics_cb,
const InitCB& init_cb) {
DCHECK(message_loop_->BelongsToCurrentThread());
@@ -44,20 +45,18 @@ void VideoFrameStream::Initialize(const scoped_refptr<DemuxerStream>& stream,
init_cb_ = init_cb;
stream_ = stream;
- scoped_ptr<VideoDecoderSelector> decoder_selector(
- new VideoDecoderSelector(message_loop_,
- decoders,
- set_decryptor_ready_cb_));
+ // TODO(scherkus): Make |decoder_selector| a member variable after
+ // DemuxerStream is no longer refcounted. Today we're forced to do this
+ // because it creates a refcount loop between |this| and |decoder_selector|.
+ scoped_ptr<VideoDecoderSelector> decoder_selector(new VideoDecoderSelector(
+ message_loop_, decoders_.Pass(), set_decryptor_ready_cb_));
+ set_decryptor_ready_cb_.Reset();
- // To avoid calling |decoder_selector| methods and passing ownership of
- // |decoder_selector| in the same line.
VideoDecoderSelector* decoder_selector_ptr = decoder_selector.get();
- decoder_selector_ptr->SelectVideoDecoder(
- this,
- statistics_cb,
- base::Bind(&VideoFrameStream::OnDecoderSelected, weak_this_,
- base::Passed(&decoder_selector)));
+ decoder_selector_ptr->SelectVideoDecoder(this, statistics_cb, base::Bind(
+ &VideoFrameStream::OnDecoderSelected, weak_this_,
+ base::Passed(&decoder_selector)));
}
void VideoFrameStream::ReadFrame(const VideoDecoder::ReadCB& read_cb) {
@@ -128,7 +127,7 @@ void VideoFrameStream::Stop(const base::Closure& closure) {
// we don't need this here. See: http://crbug.com/173313
stream_ = NULL;
decrypting_demuxer_stream_ = NULL;
- decoder_ = NULL;
+ decoder_.reset();
message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_));
}
@@ -165,7 +164,7 @@ void VideoFrameStream::EnableBitstreamConverter() {
void VideoFrameStream::OnDecoderSelected(
scoped_ptr<VideoDecoderSelector> decoder_selector,
- const scoped_refptr<VideoDecoder>& selected_decoder,
+ scoped_ptr<VideoDecoder> selected_decoder,
const scoped_refptr<DecryptingDemuxerStream>& decrypting_demuxer_stream) {
DCHECK(message_loop_->BelongsToCurrentThread());
DCHECK_EQ(state_, UNINITIALIZED);
@@ -175,7 +174,7 @@ void VideoFrameStream::OnDecoderSelected(
state_ = UNINITIALIZED;
base::ResetAndReturn(&init_cb_).Run(false, false);
} else {
- decoder_ = selected_decoder;
+ decoder_ = selected_decoder.Pass();
decrypting_demuxer_stream_ = decrypting_demuxer_stream;
state_ = NORMAL;
base::ResetAndReturn(&init_cb_).Run(true, decoder_->HasAlpha());
@@ -239,7 +238,7 @@ void VideoFrameStream::OnDecoderStopped() {
// we don't need this here. See: http://crbug.com/173313
stream_ = NULL;
decrypting_demuxer_stream_ = NULL;
- decoder_ = NULL;
+ decoder_.reset();
base::ResetAndReturn(&stop_cb_).Run();
}
diff --git a/media/filters/video_frame_stream.h b/media/filters/video_frame_stream.h
index f815419..10956c6 100644
--- a/media/filters/video_frame_stream.h
+++ b/media/filters/video_frame_stream.h
@@ -11,12 +11,14 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "media/base/decryptor.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_export.h"
#include "media/base/pipeline_status.h"
#include "media/base/video_decoder.h"
+#include "media/filters/video_decoder_selector.h"
namespace base {
class MessageLoopProxy;
@@ -31,18 +33,16 @@ class VideoDecoderSelector;
// VideoFrames to its client (e.g. VideoRendererBase).
class MEDIA_EXPORT VideoFrameStream : public DemuxerStream {
public:
- typedef std::list<scoped_refptr<VideoDecoder> > VideoDecoderList;
-
// Indicates completion of VideoFrameStream initialization.
typedef base::Callback<void(bool success, bool has_alpha)> InitCB;
VideoFrameStream(const scoped_refptr<base::MessageLoopProxy>& message_loop,
+ ScopedVector<VideoDecoder> decoders,
const SetDecryptorReadyCB& set_decryptor_ready_cb);
// Initializes the VideoFrameStream and returns the initialization result
// through |init_cb|. Note that |init_cb| is always called asynchronously.
void Initialize(const scoped_refptr<DemuxerStream>& stream,
- const VideoDecoderList& decoders,
const StatisticsCB& statistics_cb,
const InitCB& init_cb);
@@ -87,14 +87,12 @@ class MEDIA_EXPORT VideoFrameStream : public DemuxerStream {
STOPPED
};
- // Called when |decoder_selector_| selected the |selected_decoder|.
+ // Called when |decoder_selector| selected the |selected_decoder|.
// |decrypting_demuxer_stream| was also populated if a DecryptingDemuxerStream
// is created to help decrypt the encrypted stream.
- // Note: |decoder_selector| is passed here to keep the VideoDecoderSelector
- // alive until OnDecoderSelected() finishes.
void OnDecoderSelected(
scoped_ptr<VideoDecoderSelector> decoder_selector,
- const scoped_refptr<VideoDecoder>& selected_decoder,
+ scoped_ptr<VideoDecoder> selected_decoder,
const scoped_refptr<DecryptingDemuxerStream>& decrypting_demuxer_stream);
// Callback for VideoDecoder::Read().
@@ -118,12 +116,15 @@ class MEDIA_EXPORT VideoFrameStream : public DemuxerStream {
base::Closure reset_cb_;
base::Closure stop_cb_;
+ // TODO(scherkus): Replace these with a VideoDecoderSelector instance after
+ // DemuxerStream is no longer refcounted.
+ ScopedVector<VideoDecoder> decoders_;
SetDecryptorReadyCB set_decryptor_ready_cb_;
scoped_refptr<DemuxerStream> stream_;
// These two will be set by VideoDecoderSelector::SelectVideoDecoder().
- scoped_refptr<VideoDecoder> decoder_;
+ scoped_ptr<VideoDecoder> decoder_;
scoped_refptr<DecryptingDemuxerStream> decrypting_demuxer_stream_;
DISALLOW_COPY_AND_ASSIGN(VideoFrameStream);
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc
index e45c903..729bea7 100644
--- a/media/filters/video_frame_stream_unittest.cc
+++ b/media/filters/video_frame_stream_unittest.cc
@@ -31,18 +31,21 @@ static const gfx::Size kNaturalSize(320, 240);
class VideoFrameStreamTest : public testing::TestWithParam<bool> {
public:
VideoFrameStreamTest()
- : video_frame_stream_(new VideoFrameStream(
- message_loop_.message_loop_proxy(),
- base::Bind(&VideoFrameStreamTest::SetDecryptorReadyCallback,
- base::Unretained(this)))),
- video_config_(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, kVideoFormat,
+ : video_config_(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, kVideoFormat,
kCodedSize, kVisibleRect, kNaturalSize, NULL, 0,
GetParam()),
demuxer_stream_(new StrictMock<MockDemuxerStream>()),
decryptor_(new NiceMock<MockDecryptor>()),
decoder_(new StrictMock<MockVideoDecoder>()),
is_initialized_(false) {
- decoders_.push_back(decoder_);
+ ScopedVector<VideoDecoder> decoders;
+ decoders.push_back(decoder_);
+
+ video_frame_stream_ = new VideoFrameStream(
+ message_loop_.message_loop_proxy(),
+ decoders.Pass(),
+ base::Bind(&VideoFrameStreamTest::SetDecryptorReadyCallback,
+ base::Unretained(this)));
EXPECT_CALL(*demuxer_stream_, type())
.WillRepeatedly(Return(DemuxerStream::VIDEO));
@@ -88,7 +91,6 @@ class VideoFrameStreamTest : public testing::TestWithParam<bool> {
.WillOnce(SaveArg<1>(&decoder_init_cb_));
video_frame_stream_->Initialize(
demuxer_stream_,
- decoders_,
base::Bind(&VideoFrameStreamTest::OnStatistics, base::Unretained(this)),
base::Bind(&VideoFrameStreamTest::OnInitialized,
base::Unretained(this)));
@@ -101,6 +103,10 @@ class VideoFrameStreamTest : public testing::TestWithParam<bool> {
base::ResetAndReturn(&decoder_init_cb_).Run(
success ? PIPELINE_OK : DECODER_ERROR_NOT_SUPPORTED);
message_loop_.RunUntilIdle();
+
+ // Failed initialization will delete unused decoders.
+ if (!success)
+ decoder_ = NULL;
}
void EnterPendingReadFrameState() {
@@ -135,9 +141,11 @@ class VideoFrameStreamTest : public testing::TestWithParam<bool> {
void EnterPendingStopState() {
// If initialization failed, we won't call VideoDecoder::Stop() during
// the stopping process.
- EXPECT_CALL(*decoder_, Stop(_))
- .Times(AtMost(1))
- .WillRepeatedly(SaveArg<0>(&decoder_stop_cb_));
+ if (decoder_) {
+ EXPECT_CALL(*decoder_, Stop(_))
+ .WillRepeatedly(SaveArg<0>(&decoder_stop_cb_));
+ }
+
EXPECT_CALL(*this, OnStopped())
.WillOnce(Assign(&is_initialized_, false));
video_frame_stream_->Stop(base::Bind(&VideoFrameStreamTest::OnStopped,
@@ -188,8 +196,7 @@ class VideoFrameStreamTest : public testing::TestWithParam<bool> {
// Use NiceMock since we don't care about most of calls on the decryptor, e.g.
// RegisterNewKeyCB().
scoped_ptr<NiceMock<MockDecryptor> > decryptor_;
- scoped_refptr<StrictMock<MockVideoDecoder> > decoder_;
- VideoFrameStream::VideoDecoderList decoders_;
+ StrictMock<MockVideoDecoder>* decoder_; // Owned by |video_frame_stream_|.
// Callbacks to simulate pending decoder operations.
PipelineStatusCB decoder_init_cb_;
diff --git a/media/filters/video_renderer_base.cc b/media/filters/video_renderer_base.cc
index 98439c6..c9dee83 100644
--- a/media/filters/video_renderer_base.cc
+++ b/media/filters/video_renderer_base.cc
@@ -23,14 +23,15 @@ base::TimeDelta VideoRendererBase::kMaxLastFrameDuration() {
VideoRendererBase::VideoRendererBase(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
+ ScopedVector<VideoDecoder> decoders,
const SetDecryptorReadyCB& set_decryptor_ready_cb,
const PaintCB& paint_cb,
const SetOpaqueCB& set_opaque_cb,
bool drop_frames)
: message_loop_(message_loop),
weak_factory_(this),
- video_frame_stream_(new VideoFrameStream(message_loop,
- set_decryptor_ready_cb)),
+ video_frame_stream_(new VideoFrameStream(
+ message_loop, decoders.Pass(), set_decryptor_ready_cb)),
received_end_of_stream_(false),
frame_available_(&lock_),
state_(kUninitialized),
@@ -136,7 +137,6 @@ void VideoRendererBase::Preroll(base::TimeDelta time,
}
void VideoRendererBase::Initialize(const scoped_refptr<DemuxerStream>& stream,
- const VideoDecoderList& decoders,
const PipelineStatusCB& init_cb,
const StatisticsCB& statistics_cb,
const TimeCB& max_time_cb,
@@ -148,7 +148,6 @@ void VideoRendererBase::Initialize(const scoped_refptr<DemuxerStream>& stream,
DCHECK(message_loop_->BelongsToCurrentThread());
base::AutoLock auto_lock(lock_);
DCHECK(stream);
- DCHECK(!decoders.empty());
DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
DCHECK(!init_cb.is_null());
DCHECK(!statistics_cb.is_null());
@@ -172,7 +171,6 @@ void VideoRendererBase::Initialize(const scoped_refptr<DemuxerStream>& stream,
video_frame_stream_->Initialize(
stream,
- decoders,
statistics_cb,
base::Bind(&VideoRendererBase::OnVideoFrameStreamInitialized,
weak_this_));
diff --git a/media/filters/video_renderer_base.h b/media/filters/video_renderer_base.h
index 7b01653..94e0730 100644
--- a/media/filters/video_renderer_base.h
+++ b/media/filters/video_renderer_base.h
@@ -8,6 +8,7 @@
#include <deque>
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
@@ -43,6 +44,8 @@ class MEDIA_EXPORT VideoRendererBase
// Maximum duration of the last frame.
static base::TimeDelta kMaxLastFrameDuration();
+ // |decoders| contains the VideoDecoders to use when initializing.
+ //
// |paint_cb| is executed on the video frame timing thread whenever a new
// frame is available for painting.
//
@@ -55,6 +58,7 @@ class MEDIA_EXPORT VideoRendererBase
//
// Setting |drop_frames_| to true causes the renderer to drop expired frames.
VideoRendererBase(const scoped_refptr<base::MessageLoopProxy>& message_loop,
+ ScopedVector<VideoDecoder> decoders,
const SetDecryptorReadyCB& set_decryptor_ready_cb,
const PaintCB& paint_cb,
const SetOpaqueCB& set_opaque_cb,
@@ -63,7 +67,6 @@ class MEDIA_EXPORT VideoRendererBase
// VideoRenderer implementation.
virtual void Initialize(const scoped_refptr<DemuxerStream>& stream,
- const VideoDecoderList& decoders,
const PipelineStatusCB& init_cb,
const StatisticsCB& statistics_cb,
const TimeCB& max_time_cb,
@@ -129,12 +132,17 @@ class MEDIA_EXPORT VideoRendererBase
// A read is scheduled to replace the frame.
void DropNextReadyFrame_Locked();
+ void ResetDecoder();
+ void StopDecoder(const base::Closure& callback);
+
void TransitionToPrerolled_Locked();
scoped_refptr<base::MessageLoopProxy> message_loop_;
base::WeakPtrFactory<VideoRendererBase> weak_factory_;
base::WeakPtr<VideoRendererBase> weak_this_;
+ scoped_ptr<VideoDecoderSelector> decoder_selector_;
+
// Used for accessing data members.
base::Lock lock_;
diff --git a/media/filters/video_renderer_base_unittest.cc b/media/filters/video_renderer_base_unittest.cc
index c498c50..4ce9f08 100644
--- a/media/filters/video_renderer_base_unittest.cc
+++ b/media/filters/video_renderer_base_unittest.cc
@@ -45,8 +45,12 @@ class VideoRendererBaseTest : public ::testing::Test {
demuxer_stream_(new MockDemuxerStream()),
video_config_(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, kVideoFormat,
kCodedSize, kVisibleRect, kNaturalSize, NULL, 0, false) {
+ ScopedVector<VideoDecoder> decoders;
+ decoders.push_back(decoder_);
+
renderer_.reset(new VideoRendererBase(
message_loop_.message_loop_proxy(),
+ decoders.Pass(),
media::SetDecryptorReadyCB(),
base::Bind(&VideoRendererBaseTest::OnPaint, base::Unretained(this)),
base::Bind(&VideoRendererBaseTest::OnSetOpaque, base::Unretained(this)),
@@ -118,11 +122,8 @@ class VideoRendererBaseTest : public ::testing::Test {
}
void CallInitialize(const PipelineStatusCB& status_cb) {
- VideoRendererBase::VideoDecoderList decoders;
- decoders.push_back(decoder_);
renderer_->Initialize(
demuxer_stream_,
- decoders,
status_cb,
base::Bind(&MockStatisticsCB::OnStatistics,
base::Unretained(&statistics_cb_object_)),
@@ -295,7 +296,7 @@ class VideoRendererBaseTest : public ::testing::Test {
protected:
// Fixture members.
scoped_ptr<VideoRendererBase> renderer_;
- scoped_refptr<MockVideoDecoder> decoder_;
+ MockVideoDecoder* decoder_; // Owned by |renderer_|.
scoped_refptr<MockDemuxerStream> demuxer_stream_;
MockStatisticsCB statistics_cb_object_;
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index 0b92a7d..baab017 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -58,6 +58,7 @@ static int GetThreadCount() {
VpxVideoDecoder::VpxVideoDecoder(
const scoped_refptr<base::MessageLoopProxy>& message_loop)
: message_loop_(message_loop),
+ weak_factory_(this),
state_(kUninitialized),
vpx_codec_(NULL) {
}
@@ -73,6 +74,7 @@ void VpxVideoDecoder::Initialize(
const StatisticsCB& statistics_cb) {
DCHECK(message_loop_->BelongsToCurrentThread());
DCHECK(!demuxer_stream_) << "Already initialized.";
+ weak_this_ = weak_factory_.GetWeakPtr();
if (!stream) {
status_cb.Run(PIPELINE_ERROR_DECODE);
@@ -182,7 +184,7 @@ void VpxVideoDecoder::ReadFromDemuxerStream() {
DCHECK(!read_cb_.is_null());
demuxer_stream_->Read(base::Bind(
- &VpxVideoDecoder::DoDecryptOrDecodeBuffer, this));
+ &VpxVideoDecoder::DoDecryptOrDecodeBuffer, weak_this_));
}
void VpxVideoDecoder::DoDecryptOrDecodeBuffer(
diff --git a/media/filters/vpx_video_decoder.h b/media/filters/vpx_video_decoder.h
index 77578fd..aea47bb 100644
--- a/media/filters/vpx_video_decoder.h
+++ b/media/filters/vpx_video_decoder.h
@@ -6,7 +6,7 @@
#define MEDIA_FILTERS_VPX_VIDEO_DECODER_H_
#include "base/callback.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "media/base/demuxer_stream.h"
#include "media/base/video_decoder.h"
@@ -23,6 +23,7 @@ class MEDIA_EXPORT VpxVideoDecoder : public VideoDecoder {
public:
explicit VpxVideoDecoder(
const scoped_refptr<base::MessageLoopProxy>& message_loop);
+ virtual ~VpxVideoDecoder();
// VideoDecoder implementation.
virtual void Initialize(const scoped_refptr<DemuxerStream>& stream,
@@ -32,9 +33,6 @@ class MEDIA_EXPORT VpxVideoDecoder : public VideoDecoder {
virtual void Reset(const base::Closure& closure) OVERRIDE;
virtual void Stop(const base::Closure& closure) OVERRIDE;
- protected:
- virtual ~VpxVideoDecoder();
-
private:
enum DecoderState {
kUninitialized,
@@ -66,6 +64,8 @@ class MEDIA_EXPORT VpxVideoDecoder : public VideoDecoder {
scoped_refptr<VideoFrame>* video_frame);
scoped_refptr<base::MessageLoopProxy> message_loop_;
+ base::WeakPtrFactory<VpxVideoDecoder> weak_factory_;
+ base::WeakPtr<VpxVideoDecoder> weak_this_;
DecoderState state_;
diff --git a/media/tools/player_x11/player_x11.cc b/media/tools/player_x11/player_x11.cc
index e9254e1..7b029fc 100644
--- a/media/tools/player_x11/player_x11.cc
+++ b/media/tools/player_x11/player_x11.cc
@@ -113,12 +113,13 @@ bool InitPipeline(const scoped_refptr<base::MessageLoopProxy>& message_loop,
media::FFmpegNeedKeyCB need_key_cb = base::Bind(&NeedKey);
collection->SetDemuxer(new media::FFmpegDemuxer(message_loop, data_source,
need_key_cb));
- collection->GetVideoDecoders()->push_back(new media::FFmpegVideoDecoder(
- message_loop));
- // Create our video renderer and save a reference to it for painting.
+
+ ScopedVector<media::VideoDecoder> video_decoders;
+ video_decoders.push_back(new media::FFmpegVideoDecoder(message_loop));
scoped_ptr<media::VideoRenderer> video_renderer(new media::VideoRendererBase(
message_loop,
+ video_decoders.Pass(),
media::SetDecryptorReadyCB(),
base::Bind(&Paint, paint_message_loop, paint_cb),
base::Bind(&SetOpaque),
diff --git a/webkit/media/filter_helpers.cc b/webkit/media/filter_helpers.cc
deleted file mode 100644
index c803f69..0000000
--- a/webkit/media/filter_helpers.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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 "webkit/media/filter_helpers.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "media/base/filter_collection.h"
-#include "media/base/media_switches.h"
-#include "media/filters/chunk_demuxer.h"
-#include "media/filters/ffmpeg_audio_decoder.h"
-#include "media/filters/ffmpeg_demuxer.h"
-#include "media/filters/ffmpeg_video_decoder.h"
-#include "media/filters/opus_audio_decoder.h"
-#include "media/filters/vpx_video_decoder.h"
-#include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h"
-
-namespace webkit_media {
-
-void AddDefaultAudioDecoders(
- const scoped_refptr<base::MessageLoopProxy>& message_loop,
- ScopedVector<media::AudioDecoder>* audio_decoders) {
- audio_decoders->push_back(new media::FFmpegAudioDecoder(message_loop));
-
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
- if (cmd_line->HasSwitch(switches::kEnableOpusPlayback)) {
- audio_decoders->push_back(new media::OpusAudioDecoder(message_loop));
- }
-}
-
-// Constructs and adds the default video decoders to |filter_collection|.
-//
-// Note that decoders in the |filter_collection| are initialized in order.
-static void AddDefaultDecodersToCollection(
- const scoped_refptr<base::MessageLoopProxy>& message_loop,
- media::FilterCollection* filter_collection) {
-
- scoped_refptr<media::FFmpegVideoDecoder> ffmpeg_video_decoder =
- new media::FFmpegVideoDecoder(message_loop);
- filter_collection->GetVideoDecoders()->push_back(ffmpeg_video_decoder);
-
- // TODO(phajdan.jr): Remove ifdefs when libvpx with vp9 support is released
- // (http://crbug.com/174287) .
-#if !defined(MEDIA_DISABLE_LIBVPX)
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
- if (cmd_line->HasSwitch(switches::kEnableVp9Playback)) {
- scoped_refptr<media::VpxVideoDecoder> vpx_video_decoder =
- new media::VpxVideoDecoder(message_loop);
- filter_collection->GetVideoDecoders()->push_back(vpx_video_decoder);
- }
-#endif // !defined(MEDIA_DISABLE_LIBVPX)
-}
-
-void BuildMediaSourceCollection(
- const scoped_refptr<media::ChunkDemuxer>& demuxer,
- const scoped_refptr<base::MessageLoopProxy>& message_loop,
- media::FilterCollection* filter_collection) {
- DCHECK(demuxer);
- filter_collection->SetDemuxer(demuxer);
-
- // Remove GPUVideoDecoder until it supports codec config changes.
- // TODO(acolwell): Remove this once http://crbug.com/151045 is fixed.
- DCHECK_LE(filter_collection->GetVideoDecoders()->size(), 1u);
- filter_collection->GetVideoDecoders()->clear();
-
- AddDefaultDecodersToCollection(message_loop, filter_collection);
-}
-
-void BuildDefaultCollection(
- const scoped_refptr<media::DataSource>& data_source,
- const scoped_refptr<base::MessageLoopProxy>& message_loop,
- media::FilterCollection* filter_collection,
- const media::FFmpegNeedKeyCB& need_key_cb) {
- filter_collection->SetDemuxer(new media::FFmpegDemuxer(
- message_loop, data_source, need_key_cb));
-
- AddDefaultDecodersToCollection(message_loop, filter_collection);
-}
-
-} // webkit_media
diff --git a/webkit/media/filter_helpers.h b/webkit/media/filter_helpers.h
deleted file mode 100644
index 29a3e38..0000000
--- a/webkit/media/filter_helpers.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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 WEBKIT_MEDIA_FILTER_HELPERS_H_
-#define WEBKIT_MEDIA_FILTER_HELPERS_H_
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
-// TODO(fgalligan): Remove the dependency on FFmpeg.
-#include "media/filters/ffmpeg_demuxer.h"
-
-namespace base {
-class MessageLoopProxy;
-}
-
-namespace media {
-class AudioDecoder;
-class ChunkDemuxer;
-class DataSource;
-class FilterCollection;
-}
-
-namespace webkit_media {
-
-// Creates and adds the default set of audio decoders to |audio_decoders|.
-void AddDefaultAudioDecoders(
- const scoped_refptr<base::MessageLoopProxy>& message_loop,
- ScopedVector<media::AudioDecoder>* audio_decoders);
-
-// Builds the required filters for handling media source URLs, adds them to
-// |filter_collection|.
-void BuildMediaSourceCollection(
- const scoped_refptr<media::ChunkDemuxer>& demuxer,
- const scoped_refptr<base::MessageLoopProxy>& message_loop,
- media::FilterCollection* filter_collection);
-
-// Builds the required filters for handling regular URLs and adds them to
-// |filter_collection| and fills |video_decoder| returning true if successful.
-void BuildDefaultCollection(
- const scoped_refptr<media::DataSource>& data_source,
- const scoped_refptr<base::MessageLoopProxy>& message_loop,
- media::FilterCollection* filter_collection,
- const media::FFmpegNeedKeyCB& need_key_cb);
-
-} // webkit_media
-
-#endif // WEBKIT_MEDIA_FILTER_HELPERS_H_
diff --git a/webkit/media/webkit_media.gypi b/webkit/media/webkit_media.gypi
index 19e6e23..2d57dfb 100644
--- a/webkit/media/webkit_media.gypi
+++ b/webkit/media/webkit_media.gypi
@@ -74,8 +74,6 @@
'crypto/ppapi_decryptor.h',
'crypto/proxy_decryptor.cc',
'crypto/proxy_decryptor.h',
- 'filter_helpers.cc',
- 'filter_helpers.h',
'media_stream_audio_renderer.cc',
'media_stream_audio_renderer.h',
'media_stream_client.h',
diff --git a/webkit/media/webmediaplayer_impl.cc b/webkit/media/webmediaplayer_impl.cc
index 4c47acd..ce2cbc7 100644
--- a/webkit/media/webmediaplayer_impl.cc
+++ b/webkit/media/webmediaplayer_impl.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/command_line.h"
#include "base/debug/crash_logging.h"
#include "base/message_loop_proxy.h"
#include "base/metrics/histogram.h"
@@ -23,11 +24,17 @@
#include "media/base/filter_collection.h"
#include "media/base/limits.h"
#include "media/base/media_log.h"
+#include "media/base/media_switches.h"
#include "media/base/pipeline.h"
#include "media/base/video_frame.h"
#include "media/filters/audio_renderer_impl.h"
#include "media/filters/chunk_demuxer.h"
+#include "media/filters/ffmpeg_audio_decoder.h"
+#include "media/filters/ffmpeg_demuxer.h"
+#include "media/filters/ffmpeg_video_decoder.h"
+#include "media/filters/opus_audio_decoder.h"
#include "media/filters/video_renderer_base.h"
+#include "media/filters/vpx_video_decoder.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebRect.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
@@ -38,7 +45,6 @@
#include "v8/include/v8.h"
#include "webkit/compositor_bindings/web_layer_impl.h"
#include "webkit/media/buffered_data_source.h"
-#include "webkit/media/filter_helpers.h"
#include "webkit/media/webaudiosourceprovider_impl.h"
#include "webkit/media/webmediaplayer_delegate.h"
#include "webkit/media/webmediaplayer_params.h"
@@ -132,7 +138,6 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
network_state_(WebMediaPlayer::NetworkStateEmpty),
ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
main_loop_(base::MessageLoopProxy::current()),
- filter_collection_(new media::FilterCollection()),
media_thread_("MediaPipeline"),
paused_(true),
seeking_(false),
@@ -144,6 +149,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
media_log_(params.media_log()),
accelerated_compositing_reported_(false),
incremented_externally_allocated_memory_(false),
+ gpu_factories_(params.gpu_factories()),
is_local_source_(false),
supports_save_(true),
starting_(false),
@@ -170,7 +176,6 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
// Also we want to be notified of |main_loop_| destruction.
MessageLoop::current()->AddDestructionObserver(this);
- media::SetDecryptorReadyCB set_decryptor_ready_cb;
if (WebKit::WebRuntimeFeatures::isEncryptedMediaEnabled()) {
decryptor_.reset(new ProxyDecryptor(
client,
@@ -179,44 +184,12 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyError),
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnKeyMessage),
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNeedKey)));
- set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB,
- base::Unretained(decryptor_.get()));
}
- // Create the GPU video decoder if factories were provided.
- if (params.gpu_factories()) {
- filter_collection_->GetVideoDecoders()->push_back(
- new media::GpuVideoDecoder(
- media_thread_.message_loop_proxy(),
- params.gpu_factories()));
- gpu_factories_ = params.gpu_factories();
- }
-
- // Create default video renderer.
- scoped_ptr<media::VideoRenderer> video_renderer(
- new media::VideoRendererBase(
- media_thread_.message_loop_proxy(),
- set_decryptor_ready_cb,
- base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)),
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::SetOpaque),
- true));
- filter_collection_->SetVideoRenderer(video_renderer.Pass());
-
- // Create default audio renderer using the null sink if no sink was provided.
+ // Use the null sink if no sink was provided.
audio_source_provider_ = new WebAudioSourceProviderImpl(
params.audio_renderer_sink() ? params.audio_renderer_sink() :
new media::NullAudioSink(media_thread_.message_loop_proxy()));
-
- ScopedVector<media::AudioDecoder> audio_decoders;
- AddDefaultAudioDecoders(media_thread_.message_loop_proxy(), &audio_decoders);
-
- scoped_ptr<media::AudioRenderer> audio_renderer(
- new media::AudioRendererImpl(
- media_thread_.message_loop_proxy(),
- audio_source_provider_,
- audio_decoders.Pass(),
- set_decryptor_ready_cb));
- filter_collection_->SetAudioRenderer(audio_renderer.Pass());
}
WebMediaPlayerImpl::~WebMediaPlayerImpl() {
@@ -288,12 +261,6 @@ void WebMediaPlayerImpl::load(const WebKit::WebURL& url, CORSMode cors_mode) {
AsWeakPtr(), gurl));
is_local_source_ = !gurl.SchemeIs("http") && !gurl.SchemeIs("https");
-
- BuildDefaultCollection(
- data_source_,
- media_thread_.message_loop_proxy(),
- filter_collection_.get(),
- BIND_TO_RENDER_LOOP_2(&WebMediaPlayerImpl::OnNeedKey, "", ""));
}
void WebMediaPlayerImpl::load(const WebKit::WebURL& url,
@@ -309,9 +276,6 @@ void WebMediaPlayerImpl::load(const WebKit::WebURL& url,
BIND_TO_RENDER_LOOP_2(&WebMediaPlayerImpl::OnNeedKey, "", ""),
base::Bind(&LogMediaSourceError, media_log_));
- BuildMediaSourceCollection(chunk_demuxer_,
- media_thread_.message_loop_proxy(),
- filter_collection_.get());
supports_save_ = false;
StartPipeline();
}
@@ -1175,7 +1139,7 @@ void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
void WebMediaPlayerImpl::StartPipeline() {
starting_ = true;
pipeline_->Start(
- filter_collection_.Pass(),
+ BuildFilterCollection(),
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineEnded),
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineError),
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek),
@@ -1286,4 +1250,82 @@ void WebMediaPlayerImpl::FrameReady(
&WebMediaPlayerImpl::Repaint, AsWeakPtr()));
}
+scoped_ptr<media::FilterCollection>
+WebMediaPlayerImpl::BuildFilterCollection() {
+ const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+
+ scoped_ptr<media::FilterCollection> filter_collection(
+ new media::FilterCollection());
+
+ // Figure out which demuxer to use.
+ if (data_source_) {
+ DCHECK(!chunk_demuxer_);
+ filter_collection->SetDemuxer(new media::FFmpegDemuxer(
+ media_thread_.message_loop_proxy(), data_source_,
+ BIND_TO_RENDER_LOOP_2(&WebMediaPlayerImpl::OnNeedKey, "", "")));
+ } else {
+ DCHECK(chunk_demuxer_);
+ filter_collection->SetDemuxer(chunk_demuxer_);
+
+ // Disable GpuVideoDecoder creation until it supports codec config changes.
+ // TODO(acolwell): Remove this once http://crbug.com/151045 is fixed.
+ gpu_factories_ = NULL;
+ }
+
+ // Figure out if EME is enabled.
+ media::SetDecryptorReadyCB set_decryptor_ready_cb;
+ if (decryptor_) {
+ set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB,
+ base::Unretained(decryptor_.get()));
+ }
+
+ // Create our audio decoders and renderer.
+ ScopedVector<media::AudioDecoder> audio_decoders;
+ audio_decoders.push_back(new media::FFmpegAudioDecoder(
+ media_thread_.message_loop_proxy()));
+ if (cmd_line->HasSwitch(switches::kEnableOpusPlayback)) {
+ audio_decoders.push_back(new media::OpusAudioDecoder(
+ media_thread_.message_loop_proxy()));
+ }
+
+ scoped_ptr<media::AudioRenderer> audio_renderer(
+ new media::AudioRendererImpl(media_thread_.message_loop_proxy(),
+ audio_source_provider_,
+ audio_decoders.Pass(),
+ set_decryptor_ready_cb));
+ filter_collection->SetAudioRenderer(audio_renderer.Pass());
+
+ // Create our video decoders and renderer.
+ ScopedVector<media::VideoDecoder> video_decoders;
+
+ if (gpu_factories_) {
+ video_decoders.push_back(new media::GpuVideoDecoder(
+ media_thread_.message_loop_proxy(), gpu_factories_));
+ }
+
+ video_decoders.push_back(new media::FFmpegVideoDecoder(
+ media_thread_.message_loop_proxy()));
+
+ // TODO(phajdan.jr): Remove ifdefs when libvpx with vp9 support is released
+ // (http://crbug.com/174287) .
+#if !defined(MEDIA_DISABLE_LIBVPX)
+ if (cmd_line->HasSwitch(switches::kEnableVp9Playback)) {
+ video_decoders.push_back(new media::VpxVideoDecoder(
+ media_thread_.message_loop_proxy()));
+ }
+#endif // !defined(MEDIA_DISABLE_LIBVPX)
+
+ scoped_ptr<media::VideoRenderer> video_renderer(
+ new media::VideoRendererBase(
+ media_thread_.message_loop_proxy(),
+ video_decoders.Pass(),
+ set_decryptor_ready_cb,
+ base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)),
+ BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::SetOpaque),
+ true));
+ filter_collection->SetVideoRenderer(video_renderer.Pass());
+
+ return filter_collection.Pass();
+}
+
} // namespace webkit_media
diff --git a/webkit/media/webmediaplayer_impl.h b/webkit/media/webmediaplayer_impl.h
index f733e6f..46f9985 100644
--- a/webkit/media/webmediaplayer_impl.h
+++ b/webkit/media/webmediaplayer_impl.h
@@ -272,6 +272,10 @@ class WebMediaPlayerImpl
// painted.
void FrameReady(const scoped_refptr<media::VideoFrame>& frame);
+ // Builds a FilterCollection based on the current configuration of
+ // WebMediaPlayerImpl.
+ scoped_ptr<media::FilterCollection> BuildFilterCollection();
+
WebKit::WebFrame* frame_;
// TODO(hclam): get rid of these members and read from the pipeline directly.
@@ -285,7 +289,6 @@ class WebMediaPlayerImpl
// for DCHECKs so methods calls won't execute in the wrong thread.
const scoped_refptr<base::MessageLoopProxy> main_loop_;
- scoped_ptr<media::FilterCollection> filter_collection_;
scoped_refptr<media::Pipeline> pipeline_;
base::Thread media_thread_;
@@ -329,6 +332,9 @@ class WebMediaPlayerImpl
bool incremented_externally_allocated_memory_;
+ // Factories for supporting GpuVideoDecoder. May be null.
+ scoped_refptr<media::GpuVideoDecoder::Factories> gpu_factories_;
+
// Routes audio playback to either AudioRendererSink or WebAudio.
scoped_refptr<WebAudioSourceProviderImpl> audio_source_provider_;
@@ -368,8 +374,6 @@ class WebMediaPlayerImpl
// not NULL while the compositor is actively using this webmediaplayer.
cc::VideoFrameProvider::Client* video_frame_provider_client_;
- scoped_refptr<media::GpuVideoDecoder::Factories> gpu_factories_;
-
DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
};