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