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

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

Issue 5744002: Refactor PipelineImpl to use CompositeFilter to manage Filter state transitions. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix CR nits & remove dead code. Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/base/pipeline_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/stl_util-inl.h" 10 #include "base/stl_util-inl.h"
11 #include "base/synchronization/condition_variable.h" 11 #include "base/synchronization/condition_variable.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
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
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
644 if (audio_disabled_) {
645 // Audio was disabled at some point during initialization. Notify
646 // the pipeline filter now that it has been initialized.
647 pipeline_filter_->OnAudioRendererDisabled();
648 }
649
635 // Initialization was successful, we are now considered paused, so it's safe 650 // Initialization was successful, we are now considered paused, so it's safe
636 // to set the initial playback rate and volume. 651 // to set the initial playback rate and volume.
637 PlaybackRateChangedTask(GetPlaybackRate()); 652 PlaybackRateChangedTask(GetPlaybackRate());
638 VolumeChangedTask(GetVolume()); 653 VolumeChangedTask(GetVolume());
639 654
640 // Fire the initial seek request to get the filters to preroll. 655 // Fire the seek request to get the filters to preroll.
641 seek_pending_ = true; 656 seek_pending_ = true;
642 state_ = kSeeking; 657 set_state(kSeeking);
643 remaining_transitions_ = filters_.size();
644 seek_timestamp_ = base::TimeDelta(); 658 seek_timestamp_ = base::TimeDelta();
645 filters_.front()->Seek(seek_timestamp_, 659 pipeline_filter_->Seek(seek_timestamp_,
646 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 660 NewCallback(this, &PipelineImpl::OnFilterStateTransition));
647 } 661 }
648 } 662 }
649 663
650 // This method is called as a result of the client calling Pipeline::Stop() or 664 // This method is called as a result of the client calling Pipeline::Stop() or
651 // as the result of an error condition. 665 // as the result of an error condition.
652 // We stop the filters in the reverse order. 666 // We stop the filters in the reverse order.
653 // 667 //
654 // TODO(scherkus): beware! this can get posted multiple times since we post 668 // 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 669 // 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
698 712
699 TearDownPipeline(); 713 TearDownPipeline();
700 } 714 }
701 715
702 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { 716 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) {
703 DCHECK_EQ(MessageLoop::current(), message_loop_); 717 DCHECK_EQ(MessageLoop::current(), message_loop_);
704 { 718 {
705 AutoLock auto_lock(lock_); 719 AutoLock auto_lock(lock_);
706 clock_->SetPlaybackRate(playback_rate); 720 clock_->SetPlaybackRate(playback_rate);
707 } 721 }
708 for (FilterVector::iterator iter = filters_.begin(); 722
709 iter != filters_.end(); 723 // Notify |pipeline_filter_| if it has been initialized. If initialization
710 ++iter) { 724 // hasn't completed yet, the playback rate will be set when initialization
711 (*iter)->SetPlaybackRate(playback_rate); 725 // completes.
726 if (pipeline_filter_) {
727 pipeline_filter_->SetPlaybackRate(playback_rate);
712 } 728 }
713 } 729 }
714 730
715 void PipelineImpl::VolumeChangedTask(float volume) { 731 void PipelineImpl::VolumeChangedTask(float volume) {
716 DCHECK_EQ(MessageLoop::current(), message_loop_); 732 DCHECK_EQ(MessageLoop::current(), message_loop_);
717 733
718 if (audio_renderer_) { 734 if (audio_renderer_) {
719 audio_renderer_->SetVolume(volume); 735 audio_renderer_->SetVolume(volume);
720 } 736 }
721 } 737 }
(...skipping 16 matching lines...) Expand all
738 DCHECK(!seek_pending_); 754 DCHECK(!seek_pending_);
739 seek_pending_ = true; 755 seek_pending_ = true;
740 756
741 // We'll need to pause every filter before seeking. The state transition 757 // We'll need to pause every filter before seeking. The state transition
742 // is as follows: 758 // is as follows:
743 // kStarted/kEnded 759 // kStarted/kEnded
744 // kPausing (for each filter) 760 // kPausing (for each filter)
745 // kSeeking (for each filter) 761 // kSeeking (for each filter)
746 // kStarting (for each filter) 762 // kStarting (for each filter)
747 // kStarted 763 // kStarted
748 state_ = kPausing; 764 set_state(kPausing);
749 seek_timestamp_ = time; 765 seek_timestamp_ = time;
750 seek_callback_.reset(seek_callback); 766 seek_callback_.reset(seek_callback);
751 remaining_transitions_ = filters_.size();
752 767
753 // Kick off seeking! 768 // Kick off seeking!
754 { 769 {
755 AutoLock auto_lock(lock_); 770 AutoLock auto_lock(lock_);
756 // If we are waiting for a clock update, the clock hasn't been played yet. 771 // If we are waiting for a clock update, the clock hasn't been played yet.
757 if (!waiting_for_clock_update_) 772 if (!waiting_for_clock_update_)
758 clock_->Pause(); 773 clock_->Pause();
759 } 774 }
760 filters_.front()->Pause( 775 pipeline_filter_->Pause(
761 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 776 NewCallback(this, &PipelineImpl::OnFilterStateTransition));
762 } 777 }
763 778
764 void PipelineImpl::NotifyEndedTask() { 779 void PipelineImpl::NotifyEndedTask() {
765 DCHECK_EQ(MessageLoop::current(), message_loop_); 780 DCHECK_EQ(MessageLoop::current(), message_loop_);
766 781
767 // We can only end if we were actually playing. 782 // We can only end if we were actually playing.
768 if (state_ != kStarted) { 783 if (state_ != kStarted) {
769 return; 784 return;
770 } 785 }
(...skipping 12 matching lines...) Expand all
783 waiting_for_clock_update_ = false; 798 waiting_for_clock_update_ = false;
784 clock_->Play(); 799 clock_->Play();
785 } 800 }
786 } 801 }
787 802
788 if (video_renderer_ && !video_renderer_->HasEnded()) { 803 if (video_renderer_ && !video_renderer_->HasEnded()) {
789 return; 804 return;
790 } 805 }
791 806
792 // Transition to ended, executing the callback if present. 807 // Transition to ended, executing the callback if present.
793 state_ = kEnded; 808 set_state(kEnded);
794 if (ended_callback_.get()) { 809 if (ended_callback_.get()) {
795 ended_callback_->Run(); 810 ended_callback_->Run();
796 } 811 }
797 } 812 }
798 813
799 void PipelineImpl::NotifyNetworkEventTask() { 814 void PipelineImpl::NotifyNetworkEventTask() {
800 DCHECK_EQ(MessageLoop::current(), message_loop_); 815 DCHECK_EQ(MessageLoop::current(), message_loop_);
801 if (network_callback_.get()) { 816 if (network_callback_.get()) {
802 network_callback_->Run(); 817 network_callback_->Run();
803 } 818 }
804 } 819 }
805 820
806 void PipelineImpl::DisableAudioRendererTask() { 821 void PipelineImpl::DisableAudioRendererTask() {
807 DCHECK_EQ(MessageLoop::current(), message_loop_); 822 DCHECK_EQ(MessageLoop::current(), message_loop_);
808 823
809 // |rendered_mime_types_| is read through public methods so we need to lock 824 // |rendered_mime_types_| is read through public methods so we need to lock
810 // this variable. 825 // this variable.
811 AutoLock auto_lock(lock_); 826 AutoLock auto_lock(lock_);
812 rendered_mime_types_.erase(mime_type::kMajorTypeAudio); 827 rendered_mime_types_.erase(mime_type::kMajorTypeAudio);
813 828
814 audio_disabled_ = true; 829 audio_disabled_ = true;
815 830
816 // Notify all filters of disabled audio renderer. 831 // Notify all filters of disabled audio renderer. If the filter isn't
817 for (FilterVector::iterator iter = filters_.begin(); 832 // initialized yet, OnAudioRendererDisabled() will be called when
818 iter != filters_.end(); 833 // initialization is complete.
819 ++iter) { 834 if (pipeline_filter_) {
820 (*iter)->OnAudioRendererDisabled(); 835 pipeline_filter_->OnAudioRendererDisabled();
821 } 836 }
822 } 837 }
823 838
824 void PipelineImpl::FilterStateTransitionTask() { 839 void PipelineImpl::FilterStateTransitionTask() {
825 DCHECK_EQ(MessageLoop::current(), message_loop_); 840 DCHECK_EQ(MessageLoop::current(), message_loop_);
826 841
827 // No reason transitioning if we've errored or have stopped. 842 // No reason transitioning if we've errored or have stopped.
828 if (IsPipelineStopped()) { 843 if (IsPipelineStopped()) {
829 return; 844 return;
830 } 845 }
831 846
832 if (!TransientState(state_)) { 847 if (!TransientState(state_)) {
833 NOTREACHED() << "Invalid current state: " << state_; 848 NOTREACHED() << "Invalid current state: " << state_;
834 SetError(PIPELINE_ERROR_ABORT); 849 SetError(PIPELINE_ERROR_ABORT);
835 return; 850 return;
836 } 851 }
837 852
838 // Decrement the number of remaining transitions, making sure to transition 853 // Decrement the number of remaining transitions, making sure to transition
839 // to the next state if needed. 854 // to the next state if needed.
840 DCHECK(remaining_transitions_ <= filters_.size()); 855 set_state(FindNextState(state_));
841 DCHECK(remaining_transitions_ > 0u); 856 if (state_ == kSeeking) {
842 if (--remaining_transitions_ == 0) { 857 AutoLock auto_lock(lock_);
843 state_ = FindNextState(state_); 858 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 } 859 }
853 860
854 // Carry out the action for the current state. 861 // Carry out the action for the current state.
855 if (TransientState(state_)) { 862 if (TransientState(state_)) {
856 Filter* filter = filters_[filters_.size() - remaining_transitions_];
857 if (state_ == kPausing) { 863 if (state_ == kPausing) {
858 filter->Pause(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 864 pipeline_filter_->Pause(
865 NewCallback(this, &PipelineImpl::OnFilterStateTransition));
859 } else if (state_ == kFlushing) { 866 } else if (state_ == kFlushing) {
860 // We had to use parallel flushing all filters. 867 pipeline_filter_->Flush(
861 if (remaining_transitions_ == filters_.size()) { 868 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) { 869 } else if (state_ == kSeeking) {
868 filter->Seek(seek_timestamp_, 870 pipeline_filter_->Seek(seek_timestamp_,
869 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 871 NewCallback(this, &PipelineImpl::OnFilterStateTransition));
870 } else if (state_ == kStarting) { 872 } else if (state_ == kStarting) {
871 filter->Play(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 873 pipeline_filter_->Play(
874 NewCallback(this,&PipelineImpl::OnFilterStateTransition));
872 } else if (state_ == kStopping) { 875 } else if (state_ == kStopping) {
873 filter->Stop(NewCallback(this, &PipelineImpl::OnFilterStateTransition)); 876 pipeline_filter_->Stop(
877 NewCallback(this, &PipelineImpl::OnFilterStateTransition));
874 } else { 878 } else {
875 NOTREACHED(); 879 NOTREACHED() << "Unexpected state: " << state_;
876 } 880 }
877 } else if (state_ == kStarted) { 881 } else if (state_ == kStarted) {
878 FinishInitialization(); 882 FinishInitialization();
879 883
880 // Finally, reset our seeking timestamp back to zero. 884 // Finally, reset our seeking timestamp back to zero.
881 seek_timestamp_ = base::TimeDelta(); 885 seek_timestamp_ = base::TimeDelta();
882 seek_pending_ = false; 886 seek_pending_ = false;
883 887
884 AutoLock auto_lock(lock_); 888 AutoLock auto_lock(lock_);
885 // We use audio stream to update the clock. So if there is such a stream, 889 // 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. 890 // we pause the clock until we receive a valid timestamp.
887 waiting_for_clock_update_ = 891 waiting_for_clock_update_ =
888 rendered_mime_types_.find(mime_type::kMajorTypeAudio) != 892 rendered_mime_types_.find(mime_type::kMajorTypeAudio) !=
889 rendered_mime_types_.end(); 893 rendered_mime_types_.end();
890 if (!waiting_for_clock_update_) 894 if (!waiting_for_clock_update_)
891 clock_->Play(); 895 clock_->Play();
892 896
893 if (IsPipelineStopPending()) { 897 if (IsPipelineStopPending()) {
894 // We had a pending stop request need to be honored right now. 898 // We had a pending stop request need to be honored right now.
895 TearDownPipeline(); 899 TearDownPipeline();
896 } 900 }
897 } else if (IsPipelineStopped()) { 901 } else if (IsPipelineStopped()) {
898 FinishDestroyingFiltersTask(); 902 FinishDestroyingFiltersTask();
899 } else { 903 } else {
900 NOTREACHED(); 904 NOTREACHED() << "Unexpected state: " << state_;
901 } 905 }
902 } 906 }
903 907
904 void PipelineImpl::FinishDestroyingFiltersTask() { 908 void PipelineImpl::FinishDestroyingFiltersTask() {
905 DCHECK_EQ(MessageLoop::current(), message_loop_); 909 DCHECK_EQ(MessageLoop::current(), message_loop_);
906 DCHECK(IsPipelineStopped()); 910 DCHECK(IsPipelineStopped());
907 911
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. 912 // Clear renderer references.
918 audio_renderer_ = NULL; 913 audio_renderer_ = NULL;
919 video_renderer_ = NULL; 914 video_renderer_ = NULL;
920 915
921 // Reset the pipeline, which will decrement a reference to this object. 916 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 917
927 stop_pending_ = false; 918 stop_pending_ = false;
928 tearing_down_ = false; 919 tearing_down_ = false;
929 920
930 if (PIPELINE_OK == GetError()) { 921 if (PIPELINE_OK == GetError()) {
931 // Destroying filters due to Stop(). 922 // Destroying filters due to Stop().
932 ResetState(); 923 ResetState();
933 924
934 // Notify the client that stopping has finished. 925 // Notify the client that stopping has finished.
935 if (stop_callback_.get()) { 926 if (stop_callback_.get()) {
936 stop_callback_->Run(); 927 stop_callback_->Run();
937 stop_callback_.reset(); 928 stop_callback_.reset();
938 } 929 }
939 } else { 930 } else {
940 // Destroying filters due to SetError(). 931 // Destroying filters due to SetError().
941 state_ = kError; 932 set_state(kError);
942 // If our owner has requested to be notified of an error. 933 // If our owner has requested to be notified of an error.
943 if (error_callback_.get()) { 934 if (error_callback_.get()) {
944 error_callback_->Run(); 935 error_callback_->Run();
945 } 936 }
946 } 937 }
947 } 938 }
948 939
949 bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { 940 bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) {
950 DCHECK_EQ(MessageLoop::current(), message_loop_); 941 bool ret = pipeline_init_state_->composite_->AddFilter(filter.get());
951 DCHECK(IsPipelineOk());
952 942
953 // Create a dedicated thread for this filter if applicable. 943 if (!ret) {
954 if (filter->requires_message_loop()) { 944 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 } 945 }
966 946 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 } 947 }
973 948
974 void PipelineImpl::InitializeDataSource() { 949 void PipelineImpl::InitializeDataSource() {
975 DCHECK_EQ(MessageLoop::current(), message_loop_); 950 DCHECK_EQ(MessageLoop::current(), message_loop_);
976 DCHECK(IsPipelineOk()); 951 DCHECK(IsPipelineOk());
977 952
978 scoped_refptr<DataSource> data_source; 953 scoped_refptr<DataSource> data_source;
979 while (true) { 954 while (true) {
980 filter_collection_->SelectDataSource(&data_source); 955 filter_collection_->SelectDataSource(&data_source);
981 if (!data_source || data_source->IsUrlSupported(url_)) 956 if (!data_source || data_source->IsUrlSupported(url_))
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
1138 } 1113 }
1139 1114
1140 void PipelineImpl::TearDownPipeline() { 1115 void PipelineImpl::TearDownPipeline() {
1141 DCHECK_EQ(MessageLoop::current(), message_loop_); 1116 DCHECK_EQ(MessageLoop::current(), message_loop_);
1142 DCHECK_NE(kStopped, state_); 1117 DCHECK_NE(kStopped, state_);
1143 1118
1144 // Mark that we already start tearing down operation. 1119 // Mark that we already start tearing down operation.
1145 tearing_down_ = true; 1120 tearing_down_ = true;
1146 1121
1147 if (IsPipelineInitializing()) { 1122 if (IsPipelineInitializing()) {
1148 // Notify the client that starting did not complete, if necessary. 1123 // Make it look like initialization was successful.
1124 pipeline_filter_ = pipeline_init_state_->composite_;
1125 pipeline_init_state_.reset();
1126
1127 set_state(kStopping);
1128 pipeline_filter_->Stop(NewCallback(
1129 this, &PipelineImpl::OnFilterStateTransition));
1130
1149 FinishInitialization(); 1131 FinishInitialization();
1150 } 1132 } else if (pipeline_filter_.get()) {
1151 1133 set_state(kPausing);
1152 remaining_transitions_ = filters_.size(); 1134 pipeline_filter_->Pause(NewCallback(
1153 if (remaining_transitions_ > 0) { 1135 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 { 1136 } else {
1164 state_ = kStopped; 1137 set_state(kStopped);
1165 message_loop_->PostTask(FROM_HERE, 1138 message_loop_->PostTask(FROM_HERE,
1166 NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); 1139 NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask));
1167 } 1140 }
1168 } 1141 }
1169 1142
1170 } // namespace media 1143 } // namespace media
OLDNEW
« no previous file with comments | « media/base/pipeline_impl.h ('k') | media/base/pipeline_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698