OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |