| Index: media/base/pipeline.cc
|
| diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc
|
| index 9790c61cb5ca792c12d44a3f7b1b45392892565d..c171e405bf10d4e9c0cfaa246a59b6e2c5073ebf 100644
|
| --- a/media/base/pipeline.cc
|
| +++ b/media/base/pipeline.cc
|
| @@ -21,6 +21,8 @@
|
| #include "media/base/clock.h"
|
| #include "media/base/filter_collection.h"
|
| #include "media/base/media_log.h"
|
| +#include "media/base/text_decoder.h"
|
| +#include "media/base/text_renderer.h"
|
| #include "media/base/video_decoder.h"
|
| #include "media/base/video_decoder_config.h"
|
| #include "media/base/video_renderer.h"
|
| @@ -44,9 +46,11 @@ Pipeline::Pipeline(const scoped_refptr<base::MessageLoopProxy>& message_loop,
|
| status_(PIPELINE_OK),
|
| has_audio_(false),
|
| has_video_(false),
|
| + has_text_(false),
|
| state_(kCreated),
|
| audio_ended_(false),
|
| video_ended_(false),
|
| + text_ended_(false),
|
| audio_disabled_(false),
|
| demuxer_(NULL),
|
| creation_time_(default_tick_clock_.NowTicks()) {
|
| @@ -114,6 +118,11 @@ bool Pipeline::HasVideo() const {
|
| return has_video_;
|
| }
|
|
|
| +bool Pipeline::HasText() const {
|
| + base::AutoLock auto_lock(lock_);
|
| + return has_text_;
|
| +}
|
| +
|
| float Pipeline::GetPlaybackRate() const {
|
| base::AutoLock auto_lock(lock_);
|
| return playback_rate_;
|
| @@ -232,6 +241,7 @@ const char* Pipeline::GetStateString(State state) {
|
| RETURN_STRING(kInitDemuxer);
|
| RETURN_STRING(kInitAudioRenderer);
|
| RETURN_STRING(kInitVideoRenderer);
|
| + RETURN_STRING(kInitTextRenderer);
|
| RETURN_STRING(kInitPrerolling);
|
| RETURN_STRING(kSeeking);
|
| RETURN_STRING(kStarting);
|
| @@ -261,14 +271,23 @@ Pipeline::State Pipeline::GetNextState() const {
|
| return kInitAudioRenderer;
|
| if (demuxer_->GetStream(DemuxerStream::VIDEO))
|
| return kInitVideoRenderer;
|
| + if (demuxer_->GetStream(DemuxerStream::TEXT))
|
| + return kInitTextRenderer;
|
| return kInitPrerolling;
|
|
|
| case kInitAudioRenderer:
|
| if (demuxer_->GetStream(DemuxerStream::VIDEO))
|
| return kInitVideoRenderer;
|
| + if (demuxer_->GetStream(DemuxerStream::TEXT))
|
| + return kInitTextRenderer;
|
| return kInitPrerolling;
|
|
|
| case kInitVideoRenderer:
|
| + if (demuxer_->GetStream(DemuxerStream::TEXT))
|
| + return kInitTextRenderer;
|
| + return kInitPrerolling;
|
| +
|
| + case kInitTextRenderer:
|
| return kInitPrerolling;
|
|
|
| case kInitPrerolling:
|
| @@ -435,6 +454,9 @@ void Pipeline::StateTransitionTask(PipelineStatus status) {
|
| case kInitVideoRenderer:
|
| return InitializeVideoRenderer(done_cb);
|
|
|
| + case kInitTextRenderer:
|
| + return InitializeTextRenderer(done_cb);
|
| +
|
| case kInitPrerolling:
|
| filter_collection_.reset();
|
| {
|
| @@ -449,6 +471,7 @@ void Pipeline::StateTransitionTask(PipelineStatus status) {
|
| // track.
|
| has_audio_ = audio_renderer_ != NULL && !audio_disabled_;
|
| has_video_ = video_renderer_ != NULL;
|
| + has_text_ = text_renderer_ != NULL;
|
| }
|
| if (!audio_renderer_ && !video_renderer_) {
|
| done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER);
|
| @@ -537,6 +560,10 @@ void Pipeline::DoSeek(
|
| bound_fns.Push(base::Bind(
|
| &VideoRenderer::Pause, base::Unretained(video_renderer_.get())));
|
| }
|
| + if (text_renderer_) {
|
| + bound_fns.Push(base::Bind(
|
| + &TextRenderer::Pause, base::Unretained(text_renderer_.get())));
|
| + }
|
|
|
| // Flush.
|
| if (audio_renderer_) {
|
| @@ -586,6 +613,11 @@ void Pipeline::DoPlay(const PipelineStatusCB& done_cb) {
|
| &VideoRenderer::Play, base::Unretained(video_renderer_.get())));
|
| }
|
|
|
| + if (text_renderer_) {
|
| + bound_fns.Push(base::Bind(
|
| + &TextRenderer::Play, base::Unretained(text_renderer_.get())));
|
| + }
|
| +
|
| pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
|
| }
|
|
|
| @@ -609,6 +641,11 @@ void Pipeline::DoStop(const PipelineStatusCB& done_cb) {
|
| &VideoRenderer::Stop, base::Unretained(video_renderer_.get())));
|
| }
|
|
|
| + if (text_renderer_) {
|
| + bound_fns.Push(base::Bind(
|
| + &TextRenderer::Stop, base::Unretained(text_renderer_.get())));
|
| + }
|
| +
|
| pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
|
| }
|
|
|
| @@ -625,6 +662,7 @@ void Pipeline::OnStopCompleted(PipelineStatus status) {
|
| filter_collection_.reset();
|
| audio_renderer_.reset();
|
| video_renderer_.reset();
|
| + text_renderer_.reset();
|
| demuxer_ = NULL;
|
|
|
| // If we stop during initialization/seeking we want to run |seek_cb_|
|
| @@ -685,6 +723,13 @@ void Pipeline::OnVideoRendererEnded() {
|
| media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::VIDEO_ENDED));
|
| }
|
|
|
| +void Pipeline::OnTextRendererEnded() {
|
| + // Force post to process ended messages after current execution frame.
|
| + message_loop_->PostTask(FROM_HERE, base::Bind(
|
| + &Pipeline::DoTextRendererEnded, base::Unretained(this)));
|
| + media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED));
|
| +}
|
| +
|
| // Called from any thread.
|
| void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) {
|
| base::AutoLock auto_lock(lock_);
|
| @@ -802,6 +847,7 @@ void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) {
|
| seek_cb_ = seek_cb;
|
| audio_ended_ = false;
|
| video_ended_ = false;
|
| + text_ended_ = false;
|
|
|
| // Kick off seeking!
|
| {
|
| @@ -845,6 +891,18 @@ void Pipeline::DoVideoRendererEnded() {
|
| RunEndedCallbackIfNeeded();
|
| }
|
|
|
| +void Pipeline::DoTextRendererEnded() {
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| +
|
| + if (state_ != kStarted)
|
| + return;
|
| +
|
| + DCHECK(!text_ended_);
|
| + text_ended_ = true;
|
| +
|
| + RunEndedCallbackIfNeeded();
|
| +}
|
| +
|
| void Pipeline::RunEndedCallbackIfNeeded() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
|
|
| @@ -854,6 +912,9 @@ void Pipeline::RunEndedCallbackIfNeeded() {
|
| if (video_renderer_ && !video_ended_)
|
| return;
|
|
|
| + if (text_renderer_ && !text_ended_)
|
| + return;
|
| +
|
| {
|
| base::AutoLock auto_lock(lock_);
|
| clock_->EndOfStream();
|
| @@ -925,6 +986,16 @@ void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) {
|
| base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this)));
|
| }
|
|
|
| +void Pipeline::InitializeTextRenderer(const PipelineStatusCB& done_cb) {
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| +
|
| + text_renderer_ = filter_collection_->GetTextRenderer();
|
| + text_renderer_->Initialize(
|
| + demuxer_,
|
| + done_cb,
|
| + base::Bind(&Pipeline::OnTextRendererEnded, base::Unretained(this)));
|
| +}
|
| +
|
| void Pipeline::OnAudioUnderflow() {
|
| if (!message_loop_->BelongsToCurrentThread()) {
|
| message_loop_->PostTask(FROM_HERE, base::Bind(
|
|
|