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