Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: media/base/pipeline.cc

Issue 23702007: Render inband text tracks in the media pipeline (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/pipeline.h" 5 #include "media/base/pipeline.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
12 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
13 #include "base/message_loop/message_loop.h" 13 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/stl_util.h" 15 #include "base/stl_util.h"
16 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
18 #include "base/synchronization/condition_variable.h" 18 #include "base/synchronization/condition_variable.h"
19 #include "media/base/audio_decoder.h" 19 #include "media/base/audio_decoder.h"
20 #include "media/base/audio_renderer.h" 20 #include "media/base/audio_renderer.h"
21 #include "media/base/clock.h" 21 #include "media/base/clock.h"
22 #include "media/base/filter_collection.h" 22 #include "media/base/filter_collection.h"
23 #include "media/base/media_log.h" 23 #include "media/base/media_log.h"
24 #include "media/base/text_decoder.h"
25 #include "media/base/text_renderer.h"
24 #include "media/base/video_decoder.h" 26 #include "media/base/video_decoder.h"
25 #include "media/base/video_decoder_config.h" 27 #include "media/base/video_decoder_config.h"
26 #include "media/base/video_renderer.h" 28 #include "media/base/video_renderer.h"
27 29
28 using base::TimeDelta; 30 using base::TimeDelta;
29 31
30 namespace media { 32 namespace media {
31 33
32 Pipeline::Pipeline(const scoped_refptr<base::MessageLoopProxy>& message_loop, 34 Pipeline::Pipeline(const scoped_refptr<base::MessageLoopProxy>& message_loop,
33 MediaLog* media_log) 35 MediaLog* media_log)
34 : message_loop_(message_loop), 36 : message_loop_(message_loop),
35 media_log_(media_log), 37 media_log_(media_log),
36 running_(false), 38 running_(false),
37 did_loading_progress_(false), 39 did_loading_progress_(false),
38 total_bytes_(0), 40 total_bytes_(0),
39 natural_size_(0, 0), 41 natural_size_(0, 0),
40 volume_(1.0f), 42 volume_(1.0f),
41 playback_rate_(0.0f), 43 playback_rate_(0.0f),
42 clock_(new Clock(&default_tick_clock_)), 44 clock_(new Clock(&default_tick_clock_)),
43 waiting_for_clock_update_(false), 45 waiting_for_clock_update_(false),
44 status_(PIPELINE_OK), 46 status_(PIPELINE_OK),
45 has_audio_(false), 47 has_audio_(false),
46 has_video_(false), 48 has_video_(false),
49 has_text_(false),
47 state_(kCreated), 50 state_(kCreated),
48 audio_ended_(false), 51 audio_ended_(false),
49 video_ended_(false), 52 video_ended_(false),
53 text_ended_(false),
50 audio_disabled_(false), 54 audio_disabled_(false),
51 demuxer_(NULL), 55 demuxer_(NULL),
52 creation_time_(default_tick_clock_.NowTicks()) { 56 creation_time_(default_tick_clock_.NowTicks()) {
53 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); 57 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
54 media_log_->AddEvent( 58 media_log_->AddEvent(
55 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); 59 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED));
56 } 60 }
57 61
58 Pipeline::~Pipeline() { 62 Pipeline::~Pipeline() {
59 DCHECK(thread_checker_.CalledOnValidThread()) 63 DCHECK(thread_checker_.CalledOnValidThread())
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 bool Pipeline::HasAudio() const { 111 bool Pipeline::HasAudio() const {
108 base::AutoLock auto_lock(lock_); 112 base::AutoLock auto_lock(lock_);
109 return has_audio_; 113 return has_audio_;
110 } 114 }
111 115
112 bool Pipeline::HasVideo() const { 116 bool Pipeline::HasVideo() const {
113 base::AutoLock auto_lock(lock_); 117 base::AutoLock auto_lock(lock_);
114 return has_video_; 118 return has_video_;
115 } 119 }
116 120
121 bool Pipeline::HasText() const {
122 base::AutoLock auto_lock(lock_);
123 return has_text_;
124 }
125
117 float Pipeline::GetPlaybackRate() const { 126 float Pipeline::GetPlaybackRate() const {
118 base::AutoLock auto_lock(lock_); 127 base::AutoLock auto_lock(lock_);
119 return playback_rate_; 128 return playback_rate_;
120 } 129 }
121 130
122 void Pipeline::SetPlaybackRate(float playback_rate) { 131 void Pipeline::SetPlaybackRate(float playback_rate) {
123 if (playback_rate < 0.0f) 132 if (playback_rate < 0.0f)
124 return; 133 return;
125 134
126 base::AutoLock auto_lock(lock_); 135 base::AutoLock auto_lock(lock_);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 } 234 }
226 235
227 #define RETURN_STRING(state) case state: return #state; 236 #define RETURN_STRING(state) case state: return #state;
228 237
229 const char* Pipeline::GetStateString(State state) { 238 const char* Pipeline::GetStateString(State state) {
230 switch (state) { 239 switch (state) {
231 RETURN_STRING(kCreated); 240 RETURN_STRING(kCreated);
232 RETURN_STRING(kInitDemuxer); 241 RETURN_STRING(kInitDemuxer);
233 RETURN_STRING(kInitAudioRenderer); 242 RETURN_STRING(kInitAudioRenderer);
234 RETURN_STRING(kInitVideoRenderer); 243 RETURN_STRING(kInitVideoRenderer);
244 RETURN_STRING(kInitTextRenderer);
235 RETURN_STRING(kInitPrerolling); 245 RETURN_STRING(kInitPrerolling);
236 RETURN_STRING(kSeeking); 246 RETURN_STRING(kSeeking);
237 RETURN_STRING(kStarting); 247 RETURN_STRING(kStarting);
238 RETURN_STRING(kStarted); 248 RETURN_STRING(kStarted);
239 RETURN_STRING(kStopping); 249 RETURN_STRING(kStopping);
240 RETURN_STRING(kStopped); 250 RETURN_STRING(kStopped);
241 } 251 }
242 NOTREACHED(); 252 NOTREACHED();
243 return "INVALID"; 253 return "INVALID";
244 } 254 }
245 255
246 #undef RETURN_STRING 256 #undef RETURN_STRING
247 257
248 Pipeline::State Pipeline::GetNextState() const { 258 Pipeline::State Pipeline::GetNextState() const {
249 DCHECK(message_loop_->BelongsToCurrentThread()); 259 DCHECK(message_loop_->BelongsToCurrentThread());
250 DCHECK(stop_cb_.is_null()) 260 DCHECK(stop_cb_.is_null())
251 << "State transitions don't happen when stopping"; 261 << "State transitions don't happen when stopping";
252 DCHECK_EQ(status_, PIPELINE_OK) 262 DCHECK_EQ(status_, PIPELINE_OK)
253 << "State transitions don't happen when there's an error: " << status_; 263 << "State transitions don't happen when there's an error: " << status_;
254 264
255 switch (state_) { 265 switch (state_) {
256 case kCreated: 266 case kCreated:
257 return kInitDemuxer; 267 return kInitDemuxer;
258 268
259 case kInitDemuxer: 269 case kInitDemuxer:
260 if (demuxer_->GetStream(DemuxerStream::AUDIO)) 270 if (demuxer_->GetStream(DemuxerStream::AUDIO))
261 return kInitAudioRenderer; 271 return kInitAudioRenderer;
262 if (demuxer_->GetStream(DemuxerStream::VIDEO)) 272 if (demuxer_->GetStream(DemuxerStream::VIDEO))
263 return kInitVideoRenderer; 273 return kInitVideoRenderer;
274 if (demuxer_->GetStream(DemuxerStream::TEXT))
275 return kInitTextRenderer;
264 return kInitPrerolling; 276 return kInitPrerolling;
265 277
266 case kInitAudioRenderer: 278 case kInitAudioRenderer:
267 if (demuxer_->GetStream(DemuxerStream::VIDEO)) 279 if (demuxer_->GetStream(DemuxerStream::VIDEO))
268 return kInitVideoRenderer; 280 return kInitVideoRenderer;
281 if (demuxer_->GetStream(DemuxerStream::TEXT))
282 return kInitTextRenderer;
269 return kInitPrerolling; 283 return kInitPrerolling;
270 284
271 case kInitVideoRenderer: 285 case kInitVideoRenderer:
286 if (demuxer_->GetStream(DemuxerStream::TEXT))
287 return kInitTextRenderer;
288 return kInitPrerolling;
289
290 case kInitTextRenderer:
272 return kInitPrerolling; 291 return kInitPrerolling;
273 292
274 case kInitPrerolling: 293 case kInitPrerolling:
275 return kStarting; 294 return kStarting;
276 295
277 case kSeeking: 296 case kSeeking:
278 return kStarting; 297 return kStarting;
279 298
280 case kStarting: 299 case kStarting:
281 return kStarted; 300 return kStarted;
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 switch (state_) { 447 switch (state_) {
429 case kInitDemuxer: 448 case kInitDemuxer:
430 return InitializeDemuxer(done_cb); 449 return InitializeDemuxer(done_cb);
431 450
432 case kInitAudioRenderer: 451 case kInitAudioRenderer:
433 return InitializeAudioRenderer(done_cb); 452 return InitializeAudioRenderer(done_cb);
434 453
435 case kInitVideoRenderer: 454 case kInitVideoRenderer:
436 return InitializeVideoRenderer(done_cb); 455 return InitializeVideoRenderer(done_cb);
437 456
457 case kInitTextRenderer:
458 return InitializeTextRenderer(done_cb);
459
438 case kInitPrerolling: 460 case kInitPrerolling:
439 filter_collection_.reset(); 461 filter_collection_.reset();
440 { 462 {
441 base::AutoLock l(lock_); 463 base::AutoLock l(lock_);
442 // We do not want to start the clock running. We only want to set the 464 // We do not want to start the clock running. We only want to set the
443 // base media time so our timestamp calculations will be correct. 465 // base media time so our timestamp calculations will be correct.
444 clock_->SetTime(demuxer_->GetStartTime(), demuxer_->GetStartTime()); 466 clock_->SetTime(demuxer_->GetStartTime(), demuxer_->GetStartTime());
445 467
446 // TODO(scherkus): |has_audio_| should be true no matter what -- 468 // TODO(scherkus): |has_audio_| should be true no matter what --
447 // otherwise people with muted/disabled sound cards will make our 469 // otherwise people with muted/disabled sound cards will make our
448 // default controls look as if every video doesn't contain an audio 470 // default controls look as if every video doesn't contain an audio
449 // track. 471 // track.
450 has_audio_ = audio_renderer_ != NULL && !audio_disabled_; 472 has_audio_ = audio_renderer_ != NULL && !audio_disabled_;
451 has_video_ = video_renderer_ != NULL; 473 has_video_ = video_renderer_ != NULL;
474 has_text_ = text_renderer_ != NULL;
452 } 475 }
453 if (!audio_renderer_ && !video_renderer_) { 476 if (!audio_renderer_ && !video_renderer_) {
454 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); 477 done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER);
455 return; 478 return;
456 } 479 }
457 480
458 buffering_state_cb_.Run(kHaveMetadata); 481 buffering_state_cb_.Run(kHaveMetadata);
459 482
460 return DoInitialPreroll(done_cb); 483 return DoInitialPreroll(done_cb);
461 484
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 553
531 // Pause. 554 // Pause.
532 if (audio_renderer_) { 555 if (audio_renderer_) {
533 bound_fns.Push(base::Bind( 556 bound_fns.Push(base::Bind(
534 &AudioRenderer::Pause, base::Unretained(audio_renderer_.get()))); 557 &AudioRenderer::Pause, base::Unretained(audio_renderer_.get())));
535 } 558 }
536 if (video_renderer_) { 559 if (video_renderer_) {
537 bound_fns.Push(base::Bind( 560 bound_fns.Push(base::Bind(
538 &VideoRenderer::Pause, base::Unretained(video_renderer_.get()))); 561 &VideoRenderer::Pause, base::Unretained(video_renderer_.get())));
539 } 562 }
563 if (text_renderer_) {
564 bound_fns.Push(base::Bind(
565 &TextRenderer::Pause, base::Unretained(text_renderer_.get())));
566 }
540 567
541 // Flush. 568 // Flush.
542 if (audio_renderer_) { 569 if (audio_renderer_) {
543 bound_fns.Push(base::Bind( 570 bound_fns.Push(base::Bind(
544 &AudioRenderer::Flush, base::Unretained(audio_renderer_.get()))); 571 &AudioRenderer::Flush, base::Unretained(audio_renderer_.get())));
545 } 572 }
546 if (video_renderer_) { 573 if (video_renderer_) {
547 bound_fns.Push(base::Bind( 574 bound_fns.Push(base::Bind(
548 &VideoRenderer::Flush, base::Unretained(video_renderer_.get()))); 575 &VideoRenderer::Flush, base::Unretained(video_renderer_.get())));
549 } 576 }
(...skipping 29 matching lines...) Expand all
579 if (audio_renderer_) { 606 if (audio_renderer_) {
580 bound_fns.Push(base::Bind( 607 bound_fns.Push(base::Bind(
581 &AudioRenderer::Play, base::Unretained(audio_renderer_.get()))); 608 &AudioRenderer::Play, base::Unretained(audio_renderer_.get())));
582 } 609 }
583 610
584 if (video_renderer_) { 611 if (video_renderer_) {
585 bound_fns.Push(base::Bind( 612 bound_fns.Push(base::Bind(
586 &VideoRenderer::Play, base::Unretained(video_renderer_.get()))); 613 &VideoRenderer::Play, base::Unretained(video_renderer_.get())));
587 } 614 }
588 615
616 if (text_renderer_) {
617 bound_fns.Push(base::Bind(
618 &TextRenderer::Play, base::Unretained(text_renderer_.get())));
619 }
620
589 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 621 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
590 } 622 }
591 623
592 void Pipeline::DoStop(const PipelineStatusCB& done_cb) { 624 void Pipeline::DoStop(const PipelineStatusCB& done_cb) {
593 DCHECK(message_loop_->BelongsToCurrentThread()); 625 DCHECK(message_loop_->BelongsToCurrentThread());
594 DCHECK(!pending_callbacks_.get()); 626 DCHECK(!pending_callbacks_.get());
595 SerialRunner::Queue bound_fns; 627 SerialRunner::Queue bound_fns;
596 628
597 if (demuxer_) { 629 if (demuxer_) {
598 bound_fns.Push(base::Bind( 630 bound_fns.Push(base::Bind(
599 &Demuxer::Stop, base::Unretained(demuxer_))); 631 &Demuxer::Stop, base::Unretained(demuxer_)));
600 } 632 }
601 633
602 if (audio_renderer_) { 634 if (audio_renderer_) {
603 bound_fns.Push(base::Bind( 635 bound_fns.Push(base::Bind(
604 &AudioRenderer::Stop, base::Unretained(audio_renderer_.get()))); 636 &AudioRenderer::Stop, base::Unretained(audio_renderer_.get())));
605 } 637 }
606 638
607 if (video_renderer_) { 639 if (video_renderer_) {
608 bound_fns.Push(base::Bind( 640 bound_fns.Push(base::Bind(
609 &VideoRenderer::Stop, base::Unretained(video_renderer_.get()))); 641 &VideoRenderer::Stop, base::Unretained(video_renderer_.get())));
610 } 642 }
611 643
644 if (text_renderer_) {
645 bound_fns.Push(base::Bind(
646 &TextRenderer::Stop, base::Unretained(text_renderer_.get())));
647 }
648
612 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); 649 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
613 } 650 }
614 651
615 void Pipeline::OnStopCompleted(PipelineStatus status) { 652 void Pipeline::OnStopCompleted(PipelineStatus status) {
616 DCHECK(message_loop_->BelongsToCurrentThread()); 653 DCHECK(message_loop_->BelongsToCurrentThread());
617 DCHECK_EQ(state_, kStopping); 654 DCHECK_EQ(state_, kStopping);
618 { 655 {
619 base::AutoLock l(lock_); 656 base::AutoLock l(lock_);
620 running_ = false; 657 running_ = false;
621 } 658 }
622 659
623 SetState(kStopped); 660 SetState(kStopped);
624 pending_callbacks_.reset(); 661 pending_callbacks_.reset();
625 filter_collection_.reset(); 662 filter_collection_.reset();
626 audio_renderer_.reset(); 663 audio_renderer_.reset();
627 video_renderer_.reset(); 664 video_renderer_.reset();
665 text_renderer_.reset();
628 demuxer_ = NULL; 666 demuxer_ = NULL;
629 667
630 // If we stop during initialization/seeking we want to run |seek_cb_| 668 // If we stop during initialization/seeking we want to run |seek_cb_|
631 // followed by |stop_cb_| so we don't leave outstanding callbacks around. 669 // followed by |stop_cb_| so we don't leave outstanding callbacks around.
632 if (!seek_cb_.is_null()) { 670 if (!seek_cb_.is_null()) {
633 base::ResetAndReturn(&seek_cb_).Run(status_); 671 base::ResetAndReturn(&seek_cb_).Run(status_);
634 error_cb_.Reset(); 672 error_cb_.Reset();
635 } 673 }
636 if (!stop_cb_.is_null()) { 674 if (!stop_cb_.is_null()) {
637 error_cb_.Reset(); 675 error_cb_.Reset();
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::AUDIO_ENDED)); 716 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::AUDIO_ENDED));
679 } 717 }
680 718
681 void Pipeline::OnVideoRendererEnded() { 719 void Pipeline::OnVideoRendererEnded() {
682 // Force post to process ended messages after current execution frame. 720 // Force post to process ended messages after current execution frame.
683 message_loop_->PostTask(FROM_HERE, base::Bind( 721 message_loop_->PostTask(FROM_HERE, base::Bind(
684 &Pipeline::DoVideoRendererEnded, base::Unretained(this))); 722 &Pipeline::DoVideoRendererEnded, base::Unretained(this)));
685 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::VIDEO_ENDED)); 723 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::VIDEO_ENDED));
686 } 724 }
687 725
726 void Pipeline::OnTextRendererEnded() {
727 // Force post to process ended messages after current execution frame.
728 message_loop_->PostTask(FROM_HERE, base::Bind(
729 &Pipeline::DoTextRendererEnded, base::Unretained(this)));
730 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED));
731 }
732
688 // Called from any thread. 733 // Called from any thread.
689 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) { 734 void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) {
690 base::AutoLock auto_lock(lock_); 735 base::AutoLock auto_lock(lock_);
691 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded; 736 statistics_.audio_bytes_decoded += stats.audio_bytes_decoded;
692 statistics_.video_bytes_decoded += stats.video_bytes_decoded; 737 statistics_.video_bytes_decoded += stats.video_bytes_decoded;
693 statistics_.video_frames_decoded += stats.video_frames_decoded; 738 statistics_.video_frames_decoded += stats.video_frames_decoded;
694 statistics_.video_frames_dropped += stats.video_frames_dropped; 739 statistics_.video_frames_dropped += stats.video_frames_dropped;
695 } 740 }
696 741
697 void Pipeline::StartTask(scoped_ptr<FilterCollection> filter_collection, 742 void Pipeline::StartTask(scoped_ptr<FilterCollection> filter_collection,
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 return; 840 return;
796 } 841 }
797 842
798 DCHECK(seek_cb_.is_null()); 843 DCHECK(seek_cb_.is_null());
799 844
800 SetState(kSeeking); 845 SetState(kSeeking);
801 base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime()); 846 base::TimeDelta seek_timestamp = std::max(time, demuxer_->GetStartTime());
802 seek_cb_ = seek_cb; 847 seek_cb_ = seek_cb;
803 audio_ended_ = false; 848 audio_ended_ = false;
804 video_ended_ = false; 849 video_ended_ = false;
850 text_ended_ = false;
805 851
806 // Kick off seeking! 852 // Kick off seeking!
807 { 853 {
808 base::AutoLock auto_lock(lock_); 854 base::AutoLock auto_lock(lock_);
809 if (clock_->IsPlaying()) 855 if (clock_->IsPlaying())
810 clock_->Pause(); 856 clock_->Pause();
811 clock_->SetTime(seek_timestamp, seek_timestamp); 857 clock_->SetTime(seek_timestamp, seek_timestamp);
812 } 858 }
813 DoSeek(seek_timestamp, base::Bind( 859 DoSeek(seek_timestamp, base::Bind(
814 &Pipeline::OnStateTransition, base::Unretained(this))); 860 &Pipeline::OnStateTransition, base::Unretained(this)));
(...skipping 23 matching lines...) Expand all
838 884
839 if (state_ != kStarted) 885 if (state_ != kStarted)
840 return; 886 return;
841 887
842 DCHECK(!video_ended_); 888 DCHECK(!video_ended_);
843 video_ended_ = true; 889 video_ended_ = true;
844 890
845 RunEndedCallbackIfNeeded(); 891 RunEndedCallbackIfNeeded();
846 } 892 }
847 893
894 void Pipeline::DoTextRendererEnded() {
895 DCHECK(message_loop_->BelongsToCurrentThread());
896
897 if (state_ != kStarted)
898 return;
899
900 DCHECK(!text_ended_);
901 text_ended_ = true;
902
903 RunEndedCallbackIfNeeded();
904 }
905
848 void Pipeline::RunEndedCallbackIfNeeded() { 906 void Pipeline::RunEndedCallbackIfNeeded() {
849 DCHECK(message_loop_->BelongsToCurrentThread()); 907 DCHECK(message_loop_->BelongsToCurrentThread());
850 908
851 if (audio_renderer_ && !audio_ended_ && !audio_disabled_) 909 if (audio_renderer_ && !audio_ended_ && !audio_disabled_)
852 return; 910 return;
853 911
854 if (video_renderer_ && !video_ended_) 912 if (video_renderer_ && !video_ended_)
855 return; 913 return;
856 914
915 if (text_renderer_ && !text_ended_)
916 return;
917
857 { 918 {
858 base::AutoLock auto_lock(lock_); 919 base::AutoLock auto_lock(lock_);
859 clock_->EndOfStream(); 920 clock_->EndOfStream();
860 } 921 }
861 922
862 DCHECK_EQ(status_, PIPELINE_OK); 923 DCHECK_EQ(status_, PIPELINE_OK);
863 ended_cb_.Run(); 924 ended_cb_.Run();
864 } 925 }
865 926
866 void Pipeline::AudioDisabledTask() { 927 void Pipeline::AudioDisabledTask() {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
918 done_cb, 979 done_cb,
919 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), 980 base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)),
920 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)), 981 base::Bind(&Pipeline::OnVideoTimeUpdate, base::Unretained(this)),
921 base::Bind(&Pipeline::OnNaturalVideoSizeChanged, base::Unretained(this)), 982 base::Bind(&Pipeline::OnNaturalVideoSizeChanged, base::Unretained(this)),
922 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)), 983 base::Bind(&Pipeline::OnVideoRendererEnded, base::Unretained(this)),
923 base::Bind(&Pipeline::SetError, base::Unretained(this)), 984 base::Bind(&Pipeline::SetError, base::Unretained(this)),
924 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)), 985 base::Bind(&Pipeline::GetMediaTime, base::Unretained(this)),
925 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); 986 base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this)));
926 } 987 }
927 988
989 void Pipeline::InitializeTextRenderer(const PipelineStatusCB& done_cb) {
990 DCHECK(message_loop_->BelongsToCurrentThread());
991
992 text_renderer_ = filter_collection_->GetTextRenderer();
993 text_renderer_->Initialize(
994 demuxer_,
995 done_cb,
996 base::Bind(&Pipeline::OnTextRendererEnded, base::Unretained(this)));
997 }
998
928 void Pipeline::OnAudioUnderflow() { 999 void Pipeline::OnAudioUnderflow() {
929 if (!message_loop_->BelongsToCurrentThread()) { 1000 if (!message_loop_->BelongsToCurrentThread()) {
930 message_loop_->PostTask(FROM_HERE, base::Bind( 1001 message_loop_->PostTask(FROM_HERE, base::Bind(
931 &Pipeline::OnAudioUnderflow, base::Unretained(this))); 1002 &Pipeline::OnAudioUnderflow, base::Unretained(this)));
932 return; 1003 return;
933 } 1004 }
934 1005
935 if (state_ != kStarted) 1006 if (state_ != kStarted)
936 return; 1007 return;
937 1008
938 if (audio_renderer_) 1009 if (audio_renderer_)
939 audio_renderer_->ResumeAfterUnderflow(); 1010 audio_renderer_->ResumeAfterUnderflow();
940 } 1011 }
941 1012
942 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { 1013 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() {
943 lock_.AssertAcquired(); 1014 lock_.AssertAcquired();
944 if (!waiting_for_clock_update_) 1015 if (!waiting_for_clock_update_)
945 return; 1016 return;
946 1017
947 waiting_for_clock_update_ = false; 1018 waiting_for_clock_update_ = false;
948 clock_->Play(); 1019 clock_->Play();
949 } 1020 }
950 1021
951 } // namespace media 1022 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698