OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 // TODO(scherkus): clean up PipelineImpl... too many crazy function names, | 5 // TODO(scherkus): clean up PipelineImpl... too many crazy function names, |
6 // potential deadlocks, etc... | 6 // potential deadlocks, etc... |
7 | 7 |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/condition_variable.h" | 10 #include "base/condition_variable.h" |
11 #include "base/stl_util-inl.h" | 11 #include "base/stl_util-inl.h" |
12 #include "media/base/clock_impl.h" | 12 #include "media/base/clock_impl.h" |
13 #include "media/base/filter_collection.h" | 13 #include "media/base/filter_collection.h" |
14 #include "media/base/media_format.h" | 14 #include "media/base/media_format.h" |
15 #include "media/base/pipeline_impl.h" | 15 #include "media/base/pipeline_impl.h" |
16 | 16 |
17 namespace media { | 17 namespace media { |
18 | 18 |
19 class PipelineImpl::PipelineInitState { | 19 class PipelineImpl::PipelineInitState { |
20 public: | 20 public: |
21 scoped_refptr<DataSource> data_source_; | 21 scoped_refptr<DataSource> data_source_; |
22 scoped_refptr<Demuxer> demuxer_; | 22 scoped_refptr<Demuxer> demuxer_; |
23 scoped_refptr<AudioDecoder> audio_decoder_; | 23 scoped_refptr<AudioDecoder> audio_decoder_; |
24 scoped_refptr<VideoDecoder> video_decoder_; | 24 scoped_refptr<VideoDecoder> video_decoder_; |
25 scoped_refptr<CompositeFilter> composite_; | |
26 }; | 25 }; |
27 | 26 |
28 PipelineImpl::PipelineImpl(MessageLoop* message_loop) | 27 PipelineImpl::PipelineImpl(MessageLoop* message_loop) |
29 : message_loop_(message_loop), | 28 : message_loop_(message_loop), |
30 clock_(new ClockImpl(&base::Time::Now)), | 29 clock_(new ClockImpl(&base::Time::Now)), |
31 waiting_for_clock_update_(false), | 30 waiting_for_clock_update_(false), |
32 state_(kCreated), | 31 state_(kCreated), |
| 32 remaining_transitions_(0), |
33 current_bytes_(0) { | 33 current_bytes_(0) { |
34 ResetState(); | 34 ResetState(); |
35 } | 35 } |
36 | 36 |
37 PipelineImpl::~PipelineImpl() { | 37 PipelineImpl::~PipelineImpl() { |
38 AutoLock auto_lock(lock_); | 38 AutoLock auto_lock(lock_); |
39 DCHECK(!running_) << "Stop() must complete before destroying object"; | 39 DCHECK(!running_) << "Stop() must complete before destroying object"; |
40 DCHECK(!stop_pending_); | 40 DCHECK(!stop_pending_); |
41 DCHECK(!seek_pending_); | 41 DCHECK(!seek_pending_); |
42 } | 42 } |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 video_height_ = 0; | 310 video_height_ = 0; |
311 volume_ = 1.0f; | 311 volume_ = 1.0f; |
312 playback_rate_ = 0.0f; | 312 playback_rate_ = 0.0f; |
313 error_ = PIPELINE_OK; | 313 error_ = PIPELINE_OK; |
314 waiting_for_clock_update_ = false; | 314 waiting_for_clock_update_ = false; |
315 audio_disabled_ = false; | 315 audio_disabled_ = false; |
316 clock_->SetTime(kZero); | 316 clock_->SetTime(kZero); |
317 rendered_mime_types_.clear(); | 317 rendered_mime_types_.clear(); |
318 } | 318 } |
319 | 319 |
320 void PipelineImpl::set_state(State next_state) { | |
321 state_ = next_state; | |
322 } | |
323 | |
324 bool PipelineImpl::IsPipelineOk() { | 320 bool PipelineImpl::IsPipelineOk() { |
325 return PIPELINE_OK == GetError(); | 321 return PIPELINE_OK == GetError(); |
326 } | 322 } |
327 | 323 |
328 bool PipelineImpl::IsPipelineInitializing() { | 324 bool PipelineImpl::IsPipelineInitializing() { |
329 DCHECK_EQ(MessageLoop::current(), message_loop_); | 325 DCHECK_EQ(MessageLoop::current(), message_loop_); |
330 return state_ == kInitDataSource || | 326 return state_ == kInitDataSource || |
331 state_ == kInitDemuxer || | 327 state_ == kInitDemuxer || |
332 state_ == kInitAudioDecoder || | 328 state_ == kInitAudioDecoder || |
333 state_ == kInitAudioRenderer || | 329 state_ == kInitAudioRenderer || |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 if (IsPipelineStopPending() || | 565 if (IsPipelineStopPending() || |
570 IsPipelineStopped() || | 566 IsPipelineStopped() || |
571 PIPELINE_OK != GetError()) { | 567 PIPELINE_OK != GetError()) { |
572 return; | 568 return; |
573 } | 569 } |
574 | 570 |
575 DCHECK(state_ == kCreated || IsPipelineInitializing()); | 571 DCHECK(state_ == kCreated || IsPipelineInitializing()); |
576 | 572 |
577 // Just created, create data source. | 573 // Just created, create data source. |
578 if (state_ == kCreated) { | 574 if (state_ == kCreated) { |
579 set_state(kInitDataSource); | 575 state_ = kInitDataSource; |
580 pipeline_init_state_.reset(new PipelineInitState()); | 576 pipeline_init_state_.reset(new PipelineInitState()); |
581 pipeline_init_state_->composite_ = new CompositeFilter(message_loop_); | |
582 pipeline_init_state_->composite_->set_host(this); | |
583 | |
584 InitializeDataSource(); | 577 InitializeDataSource(); |
585 return; | 578 return; |
586 } | 579 } |
587 | 580 |
588 // Data source created, create demuxer. | 581 // Data source created, create demuxer. |
589 if (state_ == kInitDataSource) { | 582 if (state_ == kInitDataSource) { |
590 set_state(kInitDemuxer); | 583 state_ = kInitDemuxer; |
591 InitializeDemuxer(pipeline_init_state_->data_source_); | 584 InitializeDemuxer(pipeline_init_state_->data_source_); |
592 return; | 585 return; |
593 } | 586 } |
594 | 587 |
595 // Demuxer created, create audio decoder. | 588 // Demuxer created, create audio decoder. |
596 if (state_ == kInitDemuxer) { | 589 if (state_ == kInitDemuxer) { |
597 set_state(kInitAudioDecoder); | 590 state_ = kInitAudioDecoder; |
598 // If this method returns false, then there's no audio stream. | 591 // If this method returns false, then there's no audio stream. |
599 if (InitializeAudioDecoder(pipeline_init_state_->demuxer_)) | 592 if (InitializeAudioDecoder(pipeline_init_state_->demuxer_)) |
600 return; | 593 return; |
601 } | 594 } |
602 | 595 |
603 // Assuming audio decoder was created, create audio renderer. | 596 // Assuming audio decoder was created, create audio renderer. |
604 if (state_ == kInitAudioDecoder) { | 597 if (state_ == kInitAudioDecoder) { |
605 set_state(kInitAudioRenderer); | 598 state_ = kInitAudioRenderer; |
606 // Returns false if there's no audio stream. | 599 // Returns false if there's no audio stream. |
607 if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder_)) { | 600 if (InitializeAudioRenderer(pipeline_init_state_->audio_decoder_)) { |
608 InsertRenderedMimeType(mime_type::kMajorTypeAudio); | 601 InsertRenderedMimeType(mime_type::kMajorTypeAudio); |
609 return; | 602 return; |
610 } | 603 } |
611 } | 604 } |
612 | 605 |
613 // Assuming audio renderer was created, create video decoder. | 606 // Assuming audio renderer was created, create video decoder. |
614 if (state_ == kInitAudioRenderer) { | 607 if (state_ == kInitAudioRenderer) { |
615 // Then perform the stage of initialization, i.e. initialize video decoder. | 608 // Then perform the stage of initialization, i.e. initialize video decoder. |
616 set_state(kInitVideoDecoder); | 609 state_ = kInitVideoDecoder; |
617 if (InitializeVideoDecoder(pipeline_init_state_->demuxer_)) | 610 if (InitializeVideoDecoder(pipeline_init_state_->demuxer_)) |
618 return; | 611 return; |
619 } | 612 } |
620 | 613 |
621 // Assuming video decoder was created, create video renderer. | 614 // Assuming video decoder was created, create video renderer. |
622 if (state_ == kInitVideoDecoder) { | 615 if (state_ == kInitVideoDecoder) { |
623 set_state(kInitVideoRenderer); | 616 state_ = kInitVideoRenderer; |
624 if (InitializeVideoRenderer(pipeline_init_state_->video_decoder_)) { | 617 if (InitializeVideoRenderer(pipeline_init_state_->video_decoder_)) { |
625 InsertRenderedMimeType(mime_type::kMajorTypeVideo); | 618 InsertRenderedMimeType(mime_type::kMajorTypeVideo); |
626 return; | 619 return; |
627 } | 620 } |
628 } | 621 } |
629 | 622 |
630 if (state_ == kInitVideoRenderer) { | 623 if (state_ == kInitVideoRenderer) { |
631 if (!IsPipelineOk() || !HasRenderedMimeTypes()) { | 624 if (!IsPipelineOk() || !HasRenderedMimeTypes()) { |
632 SetError(PIPELINE_ERROR_COULD_NOT_RENDER); | 625 SetError(PIPELINE_ERROR_COULD_NOT_RENDER); |
633 return; | 626 return; |
634 } | 627 } |
635 | 628 |
636 // Clear the collection of filters. | 629 // Clear the collection of filters. |
637 filter_collection_->Clear(); | 630 filter_collection_->Clear(); |
638 | 631 |
639 pipeline_filter_ = pipeline_init_state_->composite_; | |
640 | |
641 // Clear init state since we're done initializing. | 632 // Clear init state since we're done initializing. |
642 pipeline_init_state_.reset(); | 633 pipeline_init_state_.reset(); |
643 | 634 |
644 // Initialization was successful, we are now considered paused, so it's safe | 635 // Initialization was successful, we are now considered paused, so it's safe |
645 // to set the initial playback rate and volume. | 636 // to set the initial playback rate and volume. |
646 PlaybackRateChangedTask(GetPlaybackRate()); | 637 PlaybackRateChangedTask(GetPlaybackRate()); |
647 VolumeChangedTask(GetVolume()); | 638 VolumeChangedTask(GetVolume()); |
648 | 639 |
649 // Fire the seek request to get the filters to preroll. | 640 // Fire the initial seek request to get the filters to preroll. |
650 seek_pending_ = true; | 641 seek_pending_ = true; |
651 set_state(kSeeking); | 642 state_ = kSeeking; |
| 643 remaining_transitions_ = filters_.size(); |
652 seek_timestamp_ = base::TimeDelta(); | 644 seek_timestamp_ = base::TimeDelta(); |
653 pipeline_filter_->Seek(seek_timestamp_, | 645 filters_.front()->Seek(seek_timestamp_, |
654 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); | 646 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
655 } | 647 } |
656 } | 648 } |
657 | 649 |
658 // This method is called as a result of the client calling Pipeline::Stop() or | 650 // This method is called as a result of the client calling Pipeline::Stop() or |
659 // as the result of an error condition. | 651 // as the result of an error condition. |
660 // We stop the filters in the reverse order. | 652 // We stop the filters in the reverse order. |
661 // | 653 // |
662 // TODO(scherkus): beware! this can get posted multiple times since we post | 654 // TODO(scherkus): beware! this can get posted multiple times since we post |
663 // Stop() tasks even if we've already stopped. Perhaps this should no-op for | 655 // Stop() tasks even if we've already stopped. Perhaps this should no-op for |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
706 | 698 |
707 TearDownPipeline(); | 699 TearDownPipeline(); |
708 } | 700 } |
709 | 701 |
710 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { | 702 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { |
711 DCHECK_EQ(MessageLoop::current(), message_loop_); | 703 DCHECK_EQ(MessageLoop::current(), message_loop_); |
712 { | 704 { |
713 AutoLock auto_lock(lock_); | 705 AutoLock auto_lock(lock_); |
714 clock_->SetPlaybackRate(playback_rate); | 706 clock_->SetPlaybackRate(playback_rate); |
715 } | 707 } |
716 pipeline_filter_->SetPlaybackRate(playback_rate); | 708 for (FilterVector::iterator iter = filters_.begin(); |
| 709 iter != filters_.end(); |
| 710 ++iter) { |
| 711 (*iter)->SetPlaybackRate(playback_rate); |
| 712 } |
717 } | 713 } |
718 | 714 |
719 void PipelineImpl::VolumeChangedTask(float volume) { | 715 void PipelineImpl::VolumeChangedTask(float volume) { |
720 DCHECK_EQ(MessageLoop::current(), message_loop_); | 716 DCHECK_EQ(MessageLoop::current(), message_loop_); |
721 | 717 |
722 if (audio_renderer_) { | 718 if (audio_renderer_) { |
723 audio_renderer_->SetVolume(volume); | 719 audio_renderer_->SetVolume(volume); |
724 } | 720 } |
725 } | 721 } |
726 | 722 |
(...skipping 15 matching lines...) Expand all Loading... |
742 DCHECK(!seek_pending_); | 738 DCHECK(!seek_pending_); |
743 seek_pending_ = true; | 739 seek_pending_ = true; |
744 | 740 |
745 // We'll need to pause every filter before seeking. The state transition | 741 // We'll need to pause every filter before seeking. The state transition |
746 // is as follows: | 742 // is as follows: |
747 // kStarted/kEnded | 743 // kStarted/kEnded |
748 // kPausing (for each filter) | 744 // kPausing (for each filter) |
749 // kSeeking (for each filter) | 745 // kSeeking (for each filter) |
750 // kStarting (for each filter) | 746 // kStarting (for each filter) |
751 // kStarted | 747 // kStarted |
752 set_state(kPausing); | 748 state_ = kPausing; |
753 seek_timestamp_ = time; | 749 seek_timestamp_ = time; |
754 seek_callback_.reset(seek_callback); | 750 seek_callback_.reset(seek_callback); |
| 751 remaining_transitions_ = filters_.size(); |
755 | 752 |
756 // Kick off seeking! | 753 // Kick off seeking! |
757 { | 754 { |
758 AutoLock auto_lock(lock_); | 755 AutoLock auto_lock(lock_); |
759 // If we are waiting for a clock update, the clock hasn't been played yet. | 756 // If we are waiting for a clock update, the clock hasn't been played yet. |
760 if (!waiting_for_clock_update_) | 757 if (!waiting_for_clock_update_) |
761 clock_->Pause(); | 758 clock_->Pause(); |
762 } | 759 } |
763 pipeline_filter_->Pause( | 760 filters_.front()->Pause( |
764 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); | 761 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
765 } | 762 } |
766 | 763 |
767 void PipelineImpl::NotifyEndedTask() { | 764 void PipelineImpl::NotifyEndedTask() { |
768 DCHECK_EQ(MessageLoop::current(), message_loop_); | 765 DCHECK_EQ(MessageLoop::current(), message_loop_); |
769 | 766 |
770 // We can only end if we were actually playing. | 767 // We can only end if we were actually playing. |
771 if (state_ != kStarted) { | 768 if (state_ != kStarted) { |
772 return; | 769 return; |
773 } | 770 } |
(...skipping 12 matching lines...) Expand all Loading... |
786 waiting_for_clock_update_ = false; | 783 waiting_for_clock_update_ = false; |
787 clock_->Play(); | 784 clock_->Play(); |
788 } | 785 } |
789 } | 786 } |
790 | 787 |
791 if (video_renderer_ && !video_renderer_->HasEnded()) { | 788 if (video_renderer_ && !video_renderer_->HasEnded()) { |
792 return; | 789 return; |
793 } | 790 } |
794 | 791 |
795 // Transition to ended, executing the callback if present. | 792 // Transition to ended, executing the callback if present. |
796 set_state(kEnded); | 793 state_ = kEnded; |
797 if (ended_callback_.get()) { | 794 if (ended_callback_.get()) { |
798 ended_callback_->Run(); | 795 ended_callback_->Run(); |
799 } | 796 } |
800 } | 797 } |
801 | 798 |
802 void PipelineImpl::NotifyNetworkEventTask() { | 799 void PipelineImpl::NotifyNetworkEventTask() { |
803 DCHECK_EQ(MessageLoop::current(), message_loop_); | 800 DCHECK_EQ(MessageLoop::current(), message_loop_); |
804 if (network_callback_.get()) { | 801 if (network_callback_.get()) { |
805 network_callback_->Run(); | 802 network_callback_->Run(); |
806 } | 803 } |
807 } | 804 } |
808 | 805 |
809 void PipelineImpl::DisableAudioRendererTask() { | 806 void PipelineImpl::DisableAudioRendererTask() { |
810 DCHECK_EQ(MessageLoop::current(), message_loop_); | 807 DCHECK_EQ(MessageLoop::current(), message_loop_); |
811 | 808 |
812 // |rendered_mime_types_| is read through public methods so we need to lock | 809 // |rendered_mime_types_| is read through public methods so we need to lock |
813 // this variable. | 810 // this variable. |
814 AutoLock auto_lock(lock_); | 811 AutoLock auto_lock(lock_); |
815 rendered_mime_types_.erase(mime_type::kMajorTypeAudio); | 812 rendered_mime_types_.erase(mime_type::kMajorTypeAudio); |
816 | 813 |
817 audio_disabled_ = true; | 814 audio_disabled_ = true; |
818 | 815 |
819 // Notify all filters of disabled audio renderer. | 816 // Notify all filters of disabled audio renderer. |
820 pipeline_filter_->OnAudioRendererDisabled(); | 817 for (FilterVector::iterator iter = filters_.begin(); |
| 818 iter != filters_.end(); |
| 819 ++iter) { |
| 820 (*iter)->OnAudioRendererDisabled(); |
| 821 } |
821 } | 822 } |
822 | 823 |
823 void PipelineImpl::FilterStateTransitionTask() { | 824 void PipelineImpl::FilterStateTransitionTask() { |
824 DCHECK_EQ(MessageLoop::current(), message_loop_); | 825 DCHECK_EQ(MessageLoop::current(), message_loop_); |
825 | 826 |
826 // No reason transitioning if we've errored or have stopped. | 827 // No reason transitioning if we've errored or have stopped. |
827 if (IsPipelineStopped()) { | 828 if (IsPipelineStopped()) { |
828 return; | 829 return; |
829 } | 830 } |
830 | 831 |
831 if (!TransientState(state_)) { | 832 if (!TransientState(state_)) { |
832 NOTREACHED() << "Invalid current state: " << state_; | 833 NOTREACHED() << "Invalid current state: " << state_; |
833 SetError(PIPELINE_ERROR_ABORT); | 834 SetError(PIPELINE_ERROR_ABORT); |
834 return; | 835 return; |
835 } | 836 } |
836 | 837 |
837 // Decrement the number of remaining transitions, making sure to transition | 838 // Decrement the number of remaining transitions, making sure to transition |
838 // to the next state if needed. | 839 // to the next state if needed. |
839 set_state(FindNextState(state_)); | 840 DCHECK(remaining_transitions_ <= filters_.size()); |
840 if (state_ == kSeeking) { | 841 DCHECK(remaining_transitions_ > 0u); |
841 AutoLock auto_lock(lock_); | 842 if (--remaining_transitions_ == 0) { |
842 clock_->SetTime(seek_timestamp_); | 843 state_ = FindNextState(state_); |
| 844 if (state_ == kSeeking) { |
| 845 AutoLock auto_lock(lock_); |
| 846 clock_->SetTime(seek_timestamp_); |
| 847 } |
| 848 |
| 849 if (TransientState(state_)) { |
| 850 remaining_transitions_ = filters_.size(); |
| 851 } |
843 } | 852 } |
844 | 853 |
845 // Carry out the action for the current state. | 854 // Carry out the action for the current state. |
846 if (TransientState(state_)) { | 855 if (TransientState(state_)) { |
| 856 Filter* filter = filters_[filters_.size() - remaining_transitions_]; |
847 if (state_ == kPausing) { | 857 if (state_ == kPausing) { |
848 pipeline_filter_->Pause( | 858 filter->Pause(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
849 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); | |
850 } else if (state_ == kFlushing) { | 859 } else if (state_ == kFlushing) { |
851 pipeline_filter_->Flush( | 860 // We had to use parallel flushing all filters. |
852 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); | 861 if (remaining_transitions_ == filters_.size()) { |
| 862 for (size_t i = 0; i < filters_.size(); i++) { |
| 863 filters_[i]->Flush( |
| 864 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
| 865 } |
| 866 } |
853 } else if (state_ == kSeeking) { | 867 } else if (state_ == kSeeking) { |
854 pipeline_filter_->Seek(seek_timestamp_, | 868 filter->Seek(seek_timestamp_, |
855 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); | 869 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
856 } else if (state_ == kStarting) { | 870 } else if (state_ == kStarting) { |
857 pipeline_filter_->Play( | 871 filter->Play(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
858 NewCallback(this,&PipelineImpl::OnFilterStateTransition)); | |
859 } else if (state_ == kStopping) { | 872 } else if (state_ == kStopping) { |
860 pipeline_filter_->Stop( | 873 filter->Stop(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
861 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); | |
862 } else { | 874 } else { |
863 NOTREACHED() << "Unexpected state: " << state_; | 875 NOTREACHED(); |
864 } | 876 } |
865 } else if (state_ == kStarted) { | 877 } else if (state_ == kStarted) { |
866 FinishInitialization(); | 878 FinishInitialization(); |
867 | 879 |
868 // Finally, reset our seeking timestamp back to zero. | 880 // Finally, reset our seeking timestamp back to zero. |
869 seek_timestamp_ = base::TimeDelta(); | 881 seek_timestamp_ = base::TimeDelta(); |
870 seek_pending_ = false; | 882 seek_pending_ = false; |
871 | 883 |
872 AutoLock auto_lock(lock_); | 884 AutoLock auto_lock(lock_); |
873 // We use audio stream to update the clock. So if there is such a stream, | 885 // We use audio stream to update the clock. So if there is such a stream, |
874 // we pause the clock until we receive a valid timestamp. | 886 // we pause the clock until we receive a valid timestamp. |
875 waiting_for_clock_update_ = | 887 waiting_for_clock_update_ = |
876 rendered_mime_types_.find(mime_type::kMajorTypeAudio) != | 888 rendered_mime_types_.find(mime_type::kMajorTypeAudio) != |
877 rendered_mime_types_.end(); | 889 rendered_mime_types_.end(); |
878 if (!waiting_for_clock_update_) | 890 if (!waiting_for_clock_update_) |
879 clock_->Play(); | 891 clock_->Play(); |
880 | 892 |
881 if (IsPipelineStopPending()) { | 893 if (IsPipelineStopPending()) { |
882 // We had a pending stop request need to be honored right now. | 894 // We had a pending stop request need to be honored right now. |
883 TearDownPipeline(); | 895 TearDownPipeline(); |
884 } | 896 } |
885 } else if (IsPipelineStopped()) { | 897 } else if (IsPipelineStopped()) { |
886 FinishDestroyingFiltersTask(); | 898 FinishDestroyingFiltersTask(); |
887 } else { | 899 } else { |
888 NOTREACHED() << "Unexpected state: " << state_; | 900 NOTREACHED(); |
889 } | 901 } |
890 } | 902 } |
891 | 903 |
892 void PipelineImpl::FinishDestroyingFiltersTask() { | 904 void PipelineImpl::FinishDestroyingFiltersTask() { |
893 DCHECK_EQ(MessageLoop::current(), message_loop_); | 905 DCHECK_EQ(MessageLoop::current(), message_loop_); |
894 DCHECK(IsPipelineStopped()); | 906 DCHECK(IsPipelineStopped()); |
895 | 907 |
| 908 // Stop every running filter thread. |
| 909 // |
| 910 // TODO(scherkus): can we watchdog this section to detect wedged threads? |
| 911 for (FilterThreadVector::iterator iter = filter_threads_.begin(); |
| 912 iter != filter_threads_.end(); |
| 913 ++iter) { |
| 914 (*iter)->Stop(); |
| 915 } |
| 916 |
896 // Clear renderer references. | 917 // Clear renderer references. |
897 audio_renderer_ = NULL; | 918 audio_renderer_ = NULL; |
898 video_renderer_ = NULL; | 919 video_renderer_ = NULL; |
899 | 920 |
900 pipeline_filter_ = NULL; | 921 // Reset the pipeline, which will decrement a reference to this object. |
| 922 // We will get destroyed as soon as the remaining tasks finish executing. |
| 923 // To be safe, we'll set our pipeline reference to NULL. |
| 924 filters_.clear(); |
| 925 STLDeleteElements(&filter_threads_); |
901 | 926 |
902 stop_pending_ = false; | 927 stop_pending_ = false; |
903 tearing_down_ = false; | 928 tearing_down_ = false; |
904 | 929 |
905 if (PIPELINE_OK == GetError()) { | 930 if (PIPELINE_OK == GetError()) { |
906 // Destroying filters due to Stop(). | 931 // Destroying filters due to Stop(). |
907 ResetState(); | 932 ResetState(); |
908 | 933 |
909 // Notify the client that stopping has finished. | 934 // Notify the client that stopping has finished. |
910 if (stop_callback_.get()) { | 935 if (stop_callback_.get()) { |
911 stop_callback_->Run(); | 936 stop_callback_->Run(); |
912 stop_callback_.reset(); | 937 stop_callback_.reset(); |
913 } | 938 } |
914 } else { | 939 } else { |
915 // Destroying filters due to SetError(). | 940 // Destroying filters due to SetError(). |
916 set_state(kError); | 941 state_ = kError; |
917 // If our owner has requested to be notified of an error. | 942 // If our owner has requested to be notified of an error. |
918 if (error_callback_.get()) { | 943 if (error_callback_.get()) { |
919 error_callback_->Run(); | 944 error_callback_->Run(); |
920 } | 945 } |
921 } | 946 } |
922 } | 947 } |
923 | 948 |
924 bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { | 949 bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { |
925 bool ret = pipeline_init_state_->composite_->AddFilter(filter.get()); | 950 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 951 DCHECK(IsPipelineOk()); |
926 | 952 |
927 if (!ret) { | 953 // Create a dedicated thread for this filter if applicable. |
928 SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); | 954 if (filter->requires_message_loop()) { |
| 955 scoped_ptr<base::Thread> thread( |
| 956 new base::Thread(filter->message_loop_name())); |
| 957 if (!thread.get() || !thread->Start()) { |
| 958 NOTREACHED() << "Could not start filter thread"; |
| 959 SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 960 return false; |
| 961 } |
| 962 |
| 963 filter->set_message_loop(thread->message_loop()); |
| 964 filter_threads_.push_back(thread.release()); |
929 } | 965 } |
930 return ret; | 966 |
| 967 // Register ourselves as the filter's host. |
| 968 DCHECK(IsPipelineOk()); |
| 969 filter->set_host(this); |
| 970 filters_.push_back(make_scoped_refptr(filter.get())); |
| 971 return true; |
931 } | 972 } |
932 | 973 |
933 void PipelineImpl::InitializeDataSource() { | 974 void PipelineImpl::InitializeDataSource() { |
934 DCHECK_EQ(MessageLoop::current(), message_loop_); | 975 DCHECK_EQ(MessageLoop::current(), message_loop_); |
935 DCHECK(IsPipelineOk()); | 976 DCHECK(IsPipelineOk()); |
936 | 977 |
937 scoped_refptr<DataSource> data_source; | 978 scoped_refptr<DataSource> data_source; |
938 while (true) { | 979 while (true) { |
939 filter_collection_->SelectDataSource(&data_source); | 980 filter_collection_->SelectDataSource(&data_source); |
940 if (!data_source || data_source->IsUrlSupported(url_)) | 981 if (!data_source || data_source->IsUrlSupported(url_)) |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1097 } | 1138 } |
1098 | 1139 |
1099 void PipelineImpl::TearDownPipeline() { | 1140 void PipelineImpl::TearDownPipeline() { |
1100 DCHECK_EQ(MessageLoop::current(), message_loop_); | 1141 DCHECK_EQ(MessageLoop::current(), message_loop_); |
1101 DCHECK_NE(kStopped, state_); | 1142 DCHECK_NE(kStopped, state_); |
1102 | 1143 |
1103 // Mark that we already start tearing down operation. | 1144 // Mark that we already start tearing down operation. |
1104 tearing_down_ = true; | 1145 tearing_down_ = true; |
1105 | 1146 |
1106 if (IsPipelineInitializing()) { | 1147 if (IsPipelineInitializing()) { |
1107 // Make it look like initialization was successful. | 1148 // Notify the client that starting did not complete, if necessary. |
1108 pipeline_filter_ = pipeline_init_state_->composite_; | 1149 FinishInitialization(); |
1109 pipeline_init_state_.reset(); | 1150 } |
1110 | 1151 |
1111 set_state(kStopping); | 1152 remaining_transitions_ = filters_.size(); |
1112 pipeline_filter_->Stop(NewCallback( | 1153 if (remaining_transitions_ > 0) { |
1113 this, &PipelineImpl::OnFilterStateTransition)); | 1154 if (IsPipelineInitializing()) { |
1114 | 1155 state_ = kStopping; |
1115 FinishInitialization(); | 1156 filters_.front()->Stop(NewCallback( |
1116 } else if (pipeline_filter_.get()) { | 1157 this, &PipelineImpl::OnFilterStateTransition)); |
1117 set_state(kPausing); | 1158 } else { |
1118 pipeline_filter_->Pause(NewCallback( | 1159 state_ = kPausing; |
1119 this, &PipelineImpl::OnFilterStateTransition)); | 1160 filters_.front()->Pause(NewCallback( |
| 1161 this, &PipelineImpl::OnFilterStateTransition)); |
| 1162 } |
1120 } else { | 1163 } else { |
1121 set_state(kStopped); | 1164 state_ = kStopped; |
1122 message_loop_->PostTask(FROM_HERE, | 1165 message_loop_->PostTask(FROM_HERE, |
1123 NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); | 1166 NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); |
1124 } | 1167 } |
1125 } | 1168 } |
1126 | 1169 |
1127 } // namespace media | 1170 } // namespace media |
OLD | NEW |