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/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
17 #include "base/synchronization/condition_variable.h" | 17 #include "base/synchronization/condition_variable.h" |
18 #include "media/base/audio_decoder.h" | 18 #include "media/base/audio_decoder.h" |
19 #include "media/base/audio_renderer.h" | 19 #include "media/base/audio_renderer.h" |
| 20 #include "media/base/callback_util.h" |
20 #include "media/base/clock.h" | 21 #include "media/base/clock.h" |
21 #include "media/base/composite_filter.h" | 22 #include "media/base/composite_filter.h" |
22 #include "media/base/filter_collection.h" | 23 #include "media/base/filter_collection.h" |
23 #include "media/base/media_log.h" | 24 #include "media/base/media_log.h" |
24 #include "media/base/video_decoder.h" | 25 #include "media/base/video_decoder.h" |
25 #include "media/base/video_renderer.h" | 26 #include "media/base/video_renderer.h" |
26 | 27 |
27 using base::TimeDelta; | 28 using base::TimeDelta; |
28 | 29 |
29 namespace media { | 30 namespace media { |
(...skipping 27 matching lines...) Expand all Loading... |
57 | 58 |
58 media::PipelineStatus PipelineStatusNotification::status() { | 59 media::PipelineStatus PipelineStatusNotification::status() { |
59 base::AutoLock auto_lock(lock_); | 60 base::AutoLock auto_lock(lock_); |
60 DCHECK(notified_); | 61 DCHECK(notified_); |
61 return status_; | 62 return status_; |
62 } | 63 } |
63 | 64 |
64 struct Pipeline::PipelineInitState { | 65 struct Pipeline::PipelineInitState { |
65 scoped_refptr<AudioDecoder> audio_decoder; | 66 scoped_refptr<AudioDecoder> audio_decoder; |
66 scoped_refptr<VideoDecoder> video_decoder; | 67 scoped_refptr<VideoDecoder> video_decoder; |
67 scoped_refptr<AudioRenderer> audio_renderer; | |
68 scoped_refptr<VideoRenderer> video_renderer; | 68 scoped_refptr<VideoRenderer> video_renderer; |
69 scoped_refptr<CompositeFilter> composite; | 69 scoped_refptr<CompositeFilter> composite; |
70 }; | 70 }; |
71 | 71 |
72 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) | 72 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) |
73 : message_loop_(message_loop->message_loop_proxy()), | 73 : message_loop_(message_loop->message_loop_proxy()), |
74 media_log_(media_log), | 74 media_log_(media_log), |
75 clock_(new Clock(&base::Time::Now)), | 75 clock_(new Clock(&base::Time::Now)), |
76 waiting_for_clock_update_(false), | 76 waiting_for_clock_update_(false), |
77 state_(kCreated), | 77 state_(kCreated), |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 DCHECK(message_loop_->BelongsToCurrentThread()); | 310 DCHECK(message_loop_->BelongsToCurrentThread()); |
311 if (!seek_pending_) | 311 if (!seek_pending_) |
312 return false; | 312 return false; |
313 DCHECK(kSeeking == state_ || kPausing == state_ || | 313 DCHECK(kSeeking == state_ || kPausing == state_ || |
314 kFlushing == state_ || kStarting == state_) | 314 kFlushing == state_ || kStarting == state_) |
315 << "Current state : " << state_; | 315 << "Current state : " << state_; |
316 return true; | 316 return true; |
317 } | 317 } |
318 | 318 |
319 void Pipeline::ReportStatus(const PipelineStatusCB& cb, PipelineStatus status) { | 319 void Pipeline::ReportStatus(const PipelineStatusCB& cb, PipelineStatus status) { |
| 320 DCHECK(message_loop_->BelongsToCurrentThread()); |
320 if (cb.is_null()) | 321 if (cb.is_null()) |
321 return; | 322 return; |
322 cb.Run(status); | 323 cb.Run(status); |
323 // Prevent double-reporting of errors to clients. | 324 // Prevent double-reporting of errors to clients. |
324 if (status != PIPELINE_OK) | 325 if (status != PIPELINE_OK) |
325 error_cb_.Reset(); | 326 error_cb_.Reset(); |
326 } | 327 } |
327 | 328 |
328 void Pipeline::FinishInitialization() { | 329 void Pipeline::FinishInitialization() { |
329 DCHECK(message_loop_->BelongsToCurrentThread()); | 330 DCHECK(message_loop_->BelongsToCurrentThread()); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 TimeDelta Pipeline::GetTime() const { | 384 TimeDelta Pipeline::GetTime() const { |
384 DCHECK(IsRunning()); | 385 DCHECK(IsRunning()); |
385 return GetCurrentTime(); | 386 return GetCurrentTime(); |
386 } | 387 } |
387 | 388 |
388 TimeDelta Pipeline::GetDuration() const { | 389 TimeDelta Pipeline::GetDuration() const { |
389 DCHECK(IsRunning()); | 390 DCHECK(IsRunning()); |
390 return GetMediaDuration(); | 391 return GetMediaDuration(); |
391 } | 392 } |
392 | 393 |
| 394 void Pipeline::OnAudioDisabled() { |
| 395 DCHECK(IsRunning()); |
| 396 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 397 &Pipeline::AudioDisabledTask, this)); |
| 398 media_log_->AddEvent( |
| 399 media_log_->CreateEvent(MediaLogEvent::AUDIO_RENDERER_DISABLED)); |
| 400 } |
| 401 |
393 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { | 402 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { |
394 DCHECK(time <= max_time); | 403 DCHECK(time <= max_time); |
395 DCHECK(IsRunning()); | 404 DCHECK(IsRunning()); |
396 base::AutoLock auto_lock(lock_); | 405 base::AutoLock auto_lock(lock_); |
397 | 406 |
398 if (!has_audio_) | 407 if (!has_audio_) |
399 return; | 408 return; |
400 if (waiting_for_clock_update_ && time < clock_->Elapsed()) | 409 if (waiting_for_clock_update_ && time < clock_->Elapsed()) |
401 return; | 410 return; |
402 | 411 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 // Since the byte->time calculation is approximate, fudge the beginning & | 462 // Since the byte->time calculation is approximate, fudge the beginning & |
454 // ending areas to look better. | 463 // ending areas to look better. |
455 TimeDelta epsilon = clock_->Duration() / 100; | 464 TimeDelta epsilon = clock_->Duration() / 100; |
456 if (time_offset < epsilon) | 465 if (time_offset < epsilon) |
457 return TimeDelta(); | 466 return TimeDelta(); |
458 if (time_offset + epsilon > clock_->Duration()) | 467 if (time_offset + epsilon > clock_->Duration()) |
459 return clock_->Duration(); | 468 return clock_->Duration(); |
460 return time_offset; | 469 return time_offset; |
461 } | 470 } |
462 | 471 |
| 472 void Pipeline::DoPause(const base::Closure& done_cb) { |
| 473 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 474 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
| 475 |
| 476 if (audio_renderer_) |
| 477 closures->push(base::Bind(&AudioRenderer::Pause, audio_renderer_)); |
| 478 |
| 479 if (pipeline_filter_) |
| 480 closures->push(base::Bind(&Filter::Pause, pipeline_filter_)); |
| 481 |
| 482 RunInSeries(closures.Pass(), done_cb); |
| 483 } |
| 484 |
| 485 void Pipeline::DoFlush(const base::Closure& done_cb) { |
| 486 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 487 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
| 488 |
| 489 if (audio_renderer_) |
| 490 closures->push(base::Bind(&AudioRenderer::Flush, audio_renderer_)); |
| 491 |
| 492 if (pipeline_filter_) |
| 493 closures->push(base::Bind(&Filter::Flush, pipeline_filter_)); |
| 494 |
| 495 RunInParallel(closures.Pass(), done_cb); |
| 496 } |
| 497 |
| 498 void Pipeline::DoPlay(const base::Closure& done_cb) { |
| 499 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 500 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
| 501 |
| 502 if (audio_renderer_) |
| 503 closures->push(base::Bind(&AudioRenderer::Play, audio_renderer_)); |
| 504 |
| 505 if (pipeline_filter_) |
| 506 closures->push(base::Bind(&Filter::Play, pipeline_filter_)); |
| 507 |
| 508 RunInSeries(closures.Pass(), done_cb); |
| 509 } |
| 510 |
| 511 void Pipeline::DoStop(const base::Closure& done_cb) { |
| 512 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 513 scoped_ptr<std::queue<ClosureFunc> > closures(new std::queue<ClosureFunc>); |
| 514 |
| 515 if (demuxer_) |
| 516 closures->push(base::Bind(&Demuxer::Stop, demuxer_)); |
| 517 |
| 518 if (audio_renderer_) |
| 519 closures->push(base::Bind(&AudioRenderer::Stop, audio_renderer_)); |
| 520 |
| 521 if (pipeline_filter_) |
| 522 closures->push(base::Bind(&Filter::Stop, pipeline_filter_)); |
| 523 |
| 524 RunInSeries(closures.Pass(), done_cb); |
| 525 } |
| 526 |
463 void Pipeline::AddBufferedByteRange(int64 start, int64 end) { | 527 void Pipeline::AddBufferedByteRange(int64 start, int64 end) { |
464 DCHECK(IsRunning()); | 528 DCHECK(IsRunning()); |
465 base::AutoLock auto_lock(lock_); | 529 base::AutoLock auto_lock(lock_); |
466 buffered_byte_ranges_.Add(start, end); | 530 buffered_byte_ranges_.Add(start, end); |
467 did_loading_progress_ = true; | 531 did_loading_progress_ = true; |
468 } | 532 } |
469 | 533 |
470 void Pipeline::AddBufferedTimeRange(base::TimeDelta start, | 534 void Pipeline::AddBufferedTimeRange(base::TimeDelta start, |
471 base::TimeDelta end) { | 535 base::TimeDelta end) { |
472 DCHECK(IsRunning()); | 536 DCHECK(IsRunning()); |
(...skipping 11 matching lines...) Expand all Loading... |
484 natural_size_ = size; | 548 natural_size_ = size; |
485 } | 549 } |
486 | 550 |
487 void Pipeline::NotifyEnded() { | 551 void Pipeline::NotifyEnded() { |
488 DCHECK(IsRunning()); | 552 DCHECK(IsRunning()); |
489 message_loop_->PostTask(FROM_HERE, base::Bind( | 553 message_loop_->PostTask(FROM_HERE, base::Bind( |
490 &Pipeline::NotifyEndedTask, this)); | 554 &Pipeline::NotifyEndedTask, this)); |
491 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); | 555 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); |
492 } | 556 } |
493 | 557 |
494 void Pipeline::DisableAudioRenderer() { | |
495 DCHECK(IsRunning()); | |
496 | |
497 // Disable renderer on the message loop. | |
498 message_loop_->PostTask(FROM_HERE, base::Bind( | |
499 &Pipeline::DisableAudioRendererTask, this)); | |
500 media_log_->AddEvent( | |
501 media_log_->CreateEvent(MediaLogEvent::AUDIO_RENDERER_DISABLED)); | |
502 } | |
503 | |
504 // Called from any thread. | 558 // Called from any thread. |
505 void Pipeline::OnFilterInitialize(PipelineStatus status) { | 559 void Pipeline::OnFilterInitialize(PipelineStatus status) { |
506 // Continue the initialize task by proceeding to the next stage. | 560 // Continue the initialize task by proceeding to the next stage. |
507 message_loop_->PostTask(FROM_HERE, base::Bind( | 561 message_loop_->PostTask(FROM_HERE, base::Bind( |
508 &Pipeline::InitializeTask, this, status)); | 562 &Pipeline::InitializeTask, this, status)); |
509 } | 563 } |
510 | 564 |
511 // Called from any thread. | 565 // Called from any thread. |
512 void Pipeline::OnFilterStateTransition() { | 566 void Pipeline::OnFilterStateTransition() { |
513 message_loop_->PostTask(FROM_HERE, base::Bind( | 567 message_loop_->PostTask(FROM_HERE, base::Bind( |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 pipeline_filter_ = pipeline_init_state_->composite; | 705 pipeline_filter_ = pipeline_init_state_->composite; |
652 | 706 |
653 // Clear init state since we're done initializing. | 707 // Clear init state since we're done initializing. |
654 pipeline_init_state_.reset(); | 708 pipeline_init_state_.reset(); |
655 | 709 |
656 // Initialization was successful, we are now considered paused, so it's safe | 710 // Initialization was successful, we are now considered paused, so it's safe |
657 // to set the initial playback rate and volume. | 711 // to set the initial playback rate and volume. |
658 PlaybackRateChangedTask(GetPlaybackRate()); | 712 PlaybackRateChangedTask(GetPlaybackRate()); |
659 VolumeChangedTask(GetVolume()); | 713 VolumeChangedTask(GetVolume()); |
660 | 714 |
661 // Fire a seek request to get the renderers to preroll. We don't need to | 715 // Fire a seek request to get the renderers to preroll. We can skip a seek |
662 // tell the demuxer to seek since it should already be at the start. | 716 // here as the demuxer should be at the start of the stream. |
663 seek_pending_ = true; | 717 seek_pending_ = true; |
664 SetState(kSeeking); | 718 SetState(kSeeking); |
665 seek_timestamp_ = demuxer_->GetStartTime(); | 719 seek_timestamp_ = demuxer_->GetStartTime(); |
666 OnDemuxerSeekDone(seek_timestamp_, PIPELINE_OK); | 720 DoSeek(seek_timestamp_, true, |
| 721 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this)); |
667 } | 722 } |
668 } | 723 } |
669 | 724 |
670 // This method is called as a result of the client calling Pipeline::Stop() or | 725 // This method is called as a result of the client calling Pipeline::Stop() or |
671 // as the result of an error condition. | 726 // as the result of an error condition. |
672 // We stop the filters in the reverse order. | 727 // We stop the filters in the reverse order. |
673 // | 728 // |
674 // TODO(scherkus): beware! this can get posted multiple times since we post | 729 // TODO(scherkus): beware! this can get posted multiple times since we post |
675 // Stop() tasks even if we've already stopped. Perhaps this should no-op for | 730 // Stop() tasks even if we've already stopped. Perhaps this should no-op for |
676 // additional calls, however most of this logic will be changing. | 731 // additional calls, however most of this logic will be changing. |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 | 800 |
746 { | 801 { |
747 base::AutoLock auto_lock(lock_); | 802 base::AutoLock auto_lock(lock_); |
748 clock_->SetPlaybackRate(playback_rate); | 803 clock_->SetPlaybackRate(playback_rate); |
749 } | 804 } |
750 | 805 |
751 // Notify |pipeline_filter_| if it has been initialized. If initialization | 806 // Notify |pipeline_filter_| if it has been initialized. If initialization |
752 // hasn't completed yet, the playback rate will be set when initialization | 807 // hasn't completed yet, the playback rate will be set when initialization |
753 // completes. | 808 // completes. |
754 if (pipeline_filter_) { | 809 if (pipeline_filter_) { |
755 DCHECK(demuxer_); | |
756 demuxer_->SetPlaybackRate(playback_rate); | 810 demuxer_->SetPlaybackRate(playback_rate); |
757 pipeline_filter_->SetPlaybackRate(playback_rate); | 811 pipeline_filter_->SetPlaybackRate(playback_rate); |
| 812 |
| 813 if (audio_renderer_) |
| 814 audio_renderer_->SetPlaybackRate(playback_rate_); |
758 } | 815 } |
759 } | 816 } |
760 | 817 |
761 void Pipeline::VolumeChangedTask(float volume) { | 818 void Pipeline::VolumeChangedTask(float volume) { |
762 DCHECK(message_loop_->BelongsToCurrentThread()); | 819 DCHECK(message_loop_->BelongsToCurrentThread()); |
763 if (!running_ || tearing_down_) | 820 if (!running_ || tearing_down_) |
764 return; | 821 return; |
765 | 822 |
766 if (audio_renderer_) | 823 if (audio_renderer_) |
767 audio_renderer_->SetVolume(volume); | 824 audio_renderer_->SetVolume(volume); |
(...skipping 25 matching lines...) Expand all Loading... |
793 SetState(kPausing); | 850 SetState(kPausing); |
794 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); | 851 seek_timestamp_ = std::max(time, demuxer_->GetStartTime()); |
795 seek_cb_ = seek_cb; | 852 seek_cb_ = seek_cb; |
796 | 853 |
797 // Kick off seeking! | 854 // Kick off seeking! |
798 { | 855 { |
799 base::AutoLock auto_lock(lock_); | 856 base::AutoLock auto_lock(lock_); |
800 if (clock_->IsPlaying()) | 857 if (clock_->IsPlaying()) |
801 clock_->Pause(); | 858 clock_->Pause(); |
802 } | 859 } |
803 pipeline_filter_->Pause( | 860 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
804 base::Bind(&Pipeline::OnFilterStateTransition, this)); | |
805 } | 861 } |
806 | 862 |
807 void Pipeline::NotifyEndedTask() { | 863 void Pipeline::NotifyEndedTask() { |
808 DCHECK(message_loop_->BelongsToCurrentThread()); | 864 DCHECK(message_loop_->BelongsToCurrentThread()); |
809 | 865 |
810 // We can only end if we were actually playing. | 866 // We can only end if we were actually playing. |
811 if (state_ != kStarted) { | 867 if (state_ != kStarted) { |
812 return; | 868 return; |
813 } | 869 } |
814 | 870 |
(...skipping 19 matching lines...) Expand all Loading... |
834 // Transition to ended, executing the callback if present. | 890 // Transition to ended, executing the callback if present. |
835 SetState(kEnded); | 891 SetState(kEnded); |
836 { | 892 { |
837 base::AutoLock auto_lock(lock_); | 893 base::AutoLock auto_lock(lock_); |
838 clock_->EndOfStream(); | 894 clock_->EndOfStream(); |
839 } | 895 } |
840 | 896 |
841 ReportStatus(ended_cb_, status_); | 897 ReportStatus(ended_cb_, status_); |
842 } | 898 } |
843 | 899 |
844 void Pipeline::DisableAudioRendererTask() { | 900 void Pipeline::AudioDisabledTask() { |
845 DCHECK(message_loop_->BelongsToCurrentThread()); | 901 DCHECK(message_loop_->BelongsToCurrentThread()); |
846 | 902 |
847 base::AutoLock auto_lock(lock_); | 903 base::AutoLock auto_lock(lock_); |
848 has_audio_ = false; | 904 has_audio_ = false; |
849 audio_disabled_ = true; | 905 audio_disabled_ = true; |
850 | 906 |
851 // Notify our demuxer that we're no longer rendering audio. | 907 // Notify our demuxer that we're no longer rendering audio. |
852 demuxer_->OnAudioRendererDisabled(); | 908 demuxer_->OnAudioRendererDisabled(); |
853 | 909 |
854 // Start clock since there is no more audio to | 910 // Start clock since there is no more audio to |
(...skipping 26 matching lines...) Expand all Loading... |
881 // to the next state if needed. | 937 // to the next state if needed. |
882 SetState(FindNextState(state_)); | 938 SetState(FindNextState(state_)); |
883 if (state_ == kSeeking) { | 939 if (state_ == kSeeking) { |
884 base::AutoLock auto_lock(lock_); | 940 base::AutoLock auto_lock(lock_); |
885 clock_->SetTime(seek_timestamp_, seek_timestamp_); | 941 clock_->SetTime(seek_timestamp_, seek_timestamp_); |
886 } | 942 } |
887 | 943 |
888 // Carry out the action for the current state. | 944 // Carry out the action for the current state. |
889 if (TransientState(state_)) { | 945 if (TransientState(state_)) { |
890 if (state_ == kPausing) { | 946 if (state_ == kPausing) { |
891 pipeline_filter_->Pause( | 947 DoPause(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
892 base::Bind(&Pipeline::OnFilterStateTransition, this)); | |
893 } else if (state_ == kFlushing) { | 948 } else if (state_ == kFlushing) { |
894 pipeline_filter_->Flush( | 949 DoFlush(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
895 base::Bind(&Pipeline::OnFilterStateTransition, this)); | |
896 } else if (state_ == kSeeking) { | 950 } else if (state_ == kSeeking) { |
897 DoSeek(seek_timestamp_); | 951 DoSeek(seek_timestamp_, false, |
| 952 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this)); |
898 } else if (state_ == kStarting) { | 953 } else if (state_ == kStarting) { |
899 pipeline_filter_->Play( | 954 DoPlay(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
900 base::Bind(&Pipeline::OnFilterStateTransition, this)); | |
901 } else if (state_ == kStopping) { | 955 } else if (state_ == kStopping) { |
902 DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this)); | 956 DoStop(base::Bind(&Pipeline::OnFilterStateTransition, this)); |
903 } else { | 957 } else { |
904 NOTREACHED() << "Unexpected state: " << state_; | 958 NOTREACHED() << "Unexpected state: " << state_; |
905 } | 959 } |
906 } else if (state_ == kStarted) { | 960 } else if (state_ == kStarted) { |
907 FinishInitialization(); | 961 FinishInitialization(); |
908 | 962 |
909 // Finally, complete the seek. | 963 // Finally, complete the seek. |
910 seek_pending_ = false; | 964 seek_pending_ = false; |
(...skipping 25 matching lines...) Expand all Loading... |
936 | 990 |
937 void Pipeline::TeardownStateTransitionTask() { | 991 void Pipeline::TeardownStateTransitionTask() { |
938 DCHECK(IsPipelineTearingDown()); | 992 DCHECK(IsPipelineTearingDown()); |
939 switch (state_) { | 993 switch (state_) { |
940 case kStopping: | 994 case kStopping: |
941 SetState(error_caused_teardown_ ? kError : kStopped); | 995 SetState(error_caused_teardown_ ? kError : kStopped); |
942 FinishDestroyingFiltersTask(); | 996 FinishDestroyingFiltersTask(); |
943 break; | 997 break; |
944 case kPausing: | 998 case kPausing: |
945 SetState(kFlushing); | 999 SetState(kFlushing); |
946 pipeline_filter_->Flush( | 1000 DoFlush(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
947 base::Bind(&Pipeline::OnTeardownStateTransition, this)); | |
948 break; | 1001 break; |
949 case kFlushing: | 1002 case kFlushing: |
950 SetState(kStopping); | 1003 SetState(kStopping); |
951 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 1004 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
952 break; | 1005 break; |
953 | 1006 |
954 case kCreated: | 1007 case kCreated: |
955 case kError: | 1008 case kError: |
956 case kInitDemuxer: | 1009 case kInitDemuxer: |
957 case kInitAudioDecoder: | 1010 case kInitAudioDecoder: |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1085 } | 1138 } |
1086 | 1139 |
1087 bool Pipeline::InitializeAudioRenderer( | 1140 bool Pipeline::InitializeAudioRenderer( |
1088 const scoped_refptr<AudioDecoder>& decoder) { | 1141 const scoped_refptr<AudioDecoder>& decoder) { |
1089 DCHECK(message_loop_->BelongsToCurrentThread()); | 1142 DCHECK(message_loop_->BelongsToCurrentThread()); |
1090 DCHECK(IsPipelineOk()); | 1143 DCHECK(IsPipelineOk()); |
1091 | 1144 |
1092 if (!decoder) | 1145 if (!decoder) |
1093 return false; | 1146 return false; |
1094 | 1147 |
1095 filter_collection_->SelectAudioRenderer( | 1148 filter_collection_->SelectAudioRenderer(&audio_renderer_); |
1096 &pipeline_init_state_->audio_renderer); | 1149 if (!audio_renderer_) { |
1097 if (!pipeline_init_state_->audio_renderer) { | |
1098 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); | 1150 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); |
1099 return false; | 1151 return false; |
1100 } | 1152 } |
1101 | 1153 |
1102 pipeline_init_state_->composite->AddFilter( | 1154 audio_renderer_->Initialize( |
1103 pipeline_init_state_->audio_renderer); | |
1104 | |
1105 pipeline_init_state_->audio_renderer->Initialize( | |
1106 decoder, | 1155 decoder, |
1107 base::Bind(&Pipeline::OnFilterInitialize, this), | 1156 base::Bind(&Pipeline::OnFilterInitialize, this), |
1108 base::Bind(&Pipeline::OnAudioUnderflow, this), | 1157 base::Bind(&Pipeline::OnAudioUnderflow, this), |
1109 base::Bind(&Pipeline::OnAudioTimeUpdate, this)); | 1158 base::Bind(&Pipeline::OnAudioTimeUpdate, this), |
1110 | 1159 base::Bind(&Pipeline::NotifyEnded, this), |
1111 audio_renderer_ = pipeline_init_state_->audio_renderer; | 1160 base::Bind(&Pipeline::OnAudioDisabled, this), |
| 1161 base::Bind(&Pipeline::SetError, this)); |
1112 return true; | 1162 return true; |
1113 } | 1163 } |
1114 | 1164 |
1115 bool Pipeline::InitializeVideoRenderer( | 1165 bool Pipeline::InitializeVideoRenderer( |
1116 const scoped_refptr<VideoDecoder>& decoder) { | 1166 const scoped_refptr<VideoDecoder>& decoder) { |
1117 DCHECK(message_loop_->BelongsToCurrentThread()); | 1167 DCHECK(message_loop_->BelongsToCurrentThread()); |
1118 DCHECK(IsPipelineOk()); | 1168 DCHECK(IsPipelineOk()); |
1119 | 1169 |
1120 if (!decoder) | 1170 if (!decoder) |
1121 return false; | 1171 return false; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1187 if (seek_pending_) { | 1237 if (seek_pending_) { |
1188 seek_pending_ = false; | 1238 seek_pending_ = false; |
1189 FinishInitialization(); | 1239 FinishInitialization(); |
1190 } | 1240 } |
1191 | 1241 |
1192 break; | 1242 break; |
1193 | 1243 |
1194 case kStarted: | 1244 case kStarted: |
1195 case kEnded: | 1245 case kEnded: |
1196 SetState(kPausing); | 1246 SetState(kPausing); |
1197 pipeline_filter_->Pause( | 1247 DoPause(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
1198 base::Bind(&Pipeline::OnTeardownStateTransition, this)); | |
1199 break; | 1248 break; |
1200 | 1249 |
1201 case kStopping: | 1250 case kStopping: |
1202 case kStopped: | 1251 case kStopped: |
1203 NOTREACHED() << "Unexpected state for teardown: " << state_; | 1252 NOTREACHED() << "Unexpected state for teardown: " << state_; |
1204 break; | 1253 break; |
1205 // default: intentionally left out to force new states to cause compiler | 1254 // default: intentionally left out to force new states to cause compiler |
1206 // errors. | 1255 // errors. |
1207 }; | 1256 }; |
1208 } | 1257 } |
1209 | 1258 |
1210 void Pipeline::DoStop(const base::Closure& callback) { | 1259 void Pipeline::DoSeek(base::TimeDelta seek_timestamp, |
1211 if (demuxer_) { | 1260 bool skip_demuxer_seek, |
1212 demuxer_->Stop(base::Bind( | 1261 const PipelineStatusCB& done_cb) { |
1213 &Pipeline::OnDemuxerStopDone, this, callback)); | 1262 DCHECK(message_loop_->BelongsToCurrentThread()); |
1214 return; | 1263 scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs( |
1215 } | 1264 new std::queue<PipelineStatusCBFunc>()); |
1216 | 1265 |
1217 OnDemuxerStopDone(callback); | 1266 if (!skip_demuxer_seek) |
1218 } | 1267 status_cbs->push(base::Bind(&Demuxer::Seek, demuxer_, seek_timestamp)); |
1219 | 1268 |
1220 void Pipeline::OnDemuxerStopDone(const base::Closure& callback) { | 1269 if (audio_renderer_) |
1221 if (!message_loop_->BelongsToCurrentThread()) { | 1270 status_cbs->push(base::Bind( |
1222 message_loop_->PostTask(FROM_HERE, base::Bind( | 1271 &AudioRenderer::Seek, audio_renderer_, seek_timestamp)); |
1223 &Pipeline::OnDemuxerStopDone, this, callback)); | |
1224 return; | |
1225 } | |
1226 | 1272 |
1227 if (pipeline_filter_) { | 1273 if (pipeline_filter_) |
1228 pipeline_filter_->Stop(callback); | 1274 status_cbs->push(base::Bind( |
1229 return; | 1275 &Filter::Seek, pipeline_filter_, seek_timestamp)); |
1230 } | |
1231 | 1276 |
1232 callback.Run(); | 1277 RunInSeriesWithStatus(status_cbs.Pass(), base::Bind( |
1233 } | 1278 &Pipeline::ReportStatus, this, done_cb)); |
1234 | |
1235 void Pipeline::DoSeek(TimeDelta seek_timestamp) { | |
1236 demuxer_->Seek(seek_timestamp, base::Bind( | |
1237 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp)); | |
1238 } | |
1239 | |
1240 void Pipeline::OnDemuxerSeekDone(TimeDelta seek_timestamp, | |
1241 PipelineStatus status) { | |
1242 if (!message_loop_->BelongsToCurrentThread()) { | |
1243 message_loop_->PostTask(FROM_HERE, base::Bind( | |
1244 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp, status)); | |
1245 return; | |
1246 } | |
1247 | |
1248 PipelineStatusCB done_cb = | |
1249 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this); | |
1250 | |
1251 if (status == PIPELINE_OK && pipeline_filter_) { | |
1252 pipeline_filter_->Seek(seek_timestamp, done_cb); | |
1253 return; | |
1254 } | |
1255 | |
1256 ReportStatus(done_cb, status); | |
1257 } | 1279 } |
1258 | 1280 |
1259 void Pipeline::OnAudioUnderflow() { | 1281 void Pipeline::OnAudioUnderflow() { |
1260 if (!message_loop_->BelongsToCurrentThread()) { | 1282 if (!message_loop_->BelongsToCurrentThread()) { |
1261 message_loop_->PostTask(FROM_HERE, base::Bind( | 1283 message_loop_->PostTask(FROM_HERE, base::Bind( |
1262 &Pipeline::OnAudioUnderflow, this)); | 1284 &Pipeline::OnAudioUnderflow, this)); |
1263 return; | 1285 return; |
1264 } | 1286 } |
1265 | 1287 |
1266 if (state_ != kStarted) | 1288 if (state_ != kStarted) |
1267 return; | 1289 return; |
1268 | 1290 |
1269 if (audio_renderer_) | 1291 if (audio_renderer_) |
1270 audio_renderer_->ResumeAfterUnderflow(true); | 1292 audio_renderer_->ResumeAfterUnderflow(true); |
1271 } | 1293 } |
1272 | 1294 |
1273 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1295 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
1274 lock_.AssertAcquired(); | 1296 lock_.AssertAcquired(); |
1275 if (!waiting_for_clock_update_) | 1297 if (!waiting_for_clock_update_) |
1276 return; | 1298 return; |
1277 | 1299 |
1278 waiting_for_clock_update_ = false; | 1300 waiting_for_clock_update_ = false; |
1279 clock_->Play(); | 1301 clock_->Play(); |
1280 } | 1302 } |
1281 | 1303 |
1282 } // namespace media | 1304 } // namespace media |
OLD | NEW |