| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/pipeline.h" | 5 #include "media/base/pipeline.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 scoped_refptr<AudioDecoder> audio_decoder; | 65 scoped_refptr<AudioDecoder> audio_decoder; |
| 66 scoped_refptr<VideoDecoder> video_decoder; | 66 scoped_refptr<VideoDecoder> video_decoder; |
| 67 }; | 67 }; |
| 68 | 68 |
| 69 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) | 69 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) |
| 70 : message_loop_(message_loop->message_loop_proxy()), | 70 : message_loop_(message_loop->message_loop_proxy()), |
| 71 media_log_(media_log), | 71 media_log_(media_log), |
| 72 running_(false), | 72 running_(false), |
| 73 seek_pending_(false), | 73 seek_pending_(false), |
| 74 tearing_down_(false), | 74 tearing_down_(false), |
| 75 error_caused_teardown_(false), | |
| 76 playback_rate_change_pending_(false), | 75 playback_rate_change_pending_(false), |
| 77 did_loading_progress_(false), | 76 did_loading_progress_(false), |
| 78 total_bytes_(0), | 77 total_bytes_(0), |
| 79 natural_size_(0, 0), | 78 natural_size_(0, 0), |
| 80 volume_(1.0f), | 79 volume_(1.0f), |
| 81 playback_rate_(0.0f), | 80 playback_rate_(0.0f), |
| 82 pending_playback_rate_(0.0f), | 81 pending_playback_rate_(0.0f), |
| 83 clock_(new Clock(&base::Time::Now)), | 82 clock_(new Clock(&base::Time::Now)), |
| 84 waiting_for_clock_update_(false), | 83 waiting_for_clock_update_(false), |
| 85 status_(PIPELINE_OK), | 84 status_(PIPELINE_OK), |
| (...skipping 28 matching lines...) Expand all Loading... |
| 114 CHECK(!running_) << "Media pipeline is already running"; | 113 CHECK(!running_) << "Media pipeline is already running"; |
| 115 | 114 |
| 116 running_ = true; | 115 running_ = true; |
| 117 message_loop_->PostTask(FROM_HERE, base::Bind( | 116 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 118 &Pipeline::StartTask, this, base::Passed(&collection), | 117 &Pipeline::StartTask, this, base::Passed(&collection), |
| 119 ended_cb, error_cb, start_cb)); | 118 ended_cb, error_cb, start_cb)); |
| 120 } | 119 } |
| 121 | 120 |
| 122 void Pipeline::Stop(const base::Closure& stop_cb) { | 121 void Pipeline::Stop(const base::Closure& stop_cb) { |
| 123 base::AutoLock auto_lock(lock_); | 122 base::AutoLock auto_lock(lock_); |
| 124 CHECK(running_) << "Media pipeline isn't running"; | |
| 125 | |
| 126 // Stop the pipeline, which will set |running_| to false on our behalf. | |
| 127 message_loop_->PostTask(FROM_HERE, base::Bind( | 123 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 128 &Pipeline::StopTask, this, stop_cb)); | 124 &Pipeline::StopTask, this, stop_cb)); |
| 129 } | 125 } |
| 130 | 126 |
| 131 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { | 127 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { |
| 132 base::AutoLock auto_lock(lock_); | 128 base::AutoLock auto_lock(lock_); |
| 133 CHECK(running_) << "Media pipeline isn't running"; | 129 CHECK(running_) << "Media pipeline isn't running"; |
| 134 | 130 |
| 135 message_loop_->PostTask(FROM_HERE, base::Bind( | 131 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 136 &Pipeline::SeekTask, this, time, seek_cb)); | 132 &Pipeline::SeekTask, this, time, seek_cb)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 155 base::AutoLock auto_lock(lock_); | 151 base::AutoLock auto_lock(lock_); |
| 156 return playback_rate_; | 152 return playback_rate_; |
| 157 } | 153 } |
| 158 | 154 |
| 159 void Pipeline::SetPlaybackRate(float playback_rate) { | 155 void Pipeline::SetPlaybackRate(float playback_rate) { |
| 160 if (playback_rate < 0.0f) | 156 if (playback_rate < 0.0f) |
| 161 return; | 157 return; |
| 162 | 158 |
| 163 base::AutoLock auto_lock(lock_); | 159 base::AutoLock auto_lock(lock_); |
| 164 playback_rate_ = playback_rate; | 160 playback_rate_ = playback_rate; |
| 165 if (running_ && !tearing_down_) { | 161 if (running_) { |
| 166 message_loop_->PostTask(FROM_HERE, base::Bind( | 162 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 167 &Pipeline::PlaybackRateChangedTask, this, playback_rate)); | 163 &Pipeline::PlaybackRateChangedTask, this, playback_rate)); |
| 168 } | 164 } |
| 169 } | 165 } |
| 170 | 166 |
| 171 float Pipeline::GetVolume() const { | 167 float Pipeline::GetVolume() const { |
| 172 base::AutoLock auto_lock(lock_); | 168 base::AutoLock auto_lock(lock_); |
| 173 return volume_; | 169 return volume_; |
| 174 } | 170 } |
| 175 | 171 |
| 176 void Pipeline::SetVolume(float volume) { | 172 void Pipeline::SetVolume(float volume) { |
| 177 if (volume < 0.0f || volume > 1.0f) | 173 if (volume < 0.0f || volume > 1.0f) |
| 178 return; | 174 return; |
| 179 | 175 |
| 180 base::AutoLock auto_lock(lock_); | 176 base::AutoLock auto_lock(lock_); |
| 181 volume_ = volume; | 177 volume_ = volume; |
| 182 if (running_ && !tearing_down_) { | 178 if (running_) { |
| 183 message_loop_->PostTask(FROM_HERE, base::Bind( | 179 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 184 &Pipeline::VolumeChangedTask, this, volume)); | 180 &Pipeline::VolumeChangedTask, this, volume)); |
| 185 } | 181 } |
| 186 } | 182 } |
| 187 | 183 |
| 188 TimeDelta Pipeline::GetMediaTime() const { | 184 TimeDelta Pipeline::GetMediaTime() const { |
| 189 base::AutoLock auto_lock(lock_); | 185 base::AutoLock auto_lock(lock_); |
| 190 return clock_->Elapsed(); | 186 return clock_->Elapsed(); |
| 191 } | 187 } |
| 192 | 188 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 bool ret = did_loading_progress_; | 227 bool ret = did_loading_progress_; |
| 232 did_loading_progress_ = false; | 228 did_loading_progress_ = false; |
| 233 return ret; | 229 return ret; |
| 234 } | 230 } |
| 235 | 231 |
| 236 PipelineStatistics Pipeline::GetStatistics() const { | 232 PipelineStatistics Pipeline::GetStatistics() const { |
| 237 base::AutoLock auto_lock(lock_); | 233 base::AutoLock auto_lock(lock_); |
| 238 return statistics_; | 234 return statistics_; |
| 239 } | 235 } |
| 240 | 236 |
| 241 bool Pipeline::IsInitializedForTesting() { | |
| 242 DCHECK(message_loop_->BelongsToCurrentThread()) | |
| 243 << "Tests should run on the same thread as Pipeline"; | |
| 244 switch (state_) { | |
| 245 case kPausing: | |
| 246 case kFlushing: | |
| 247 case kSeeking: | |
| 248 case kStarting: | |
| 249 case kStarted: | |
| 250 return true; | |
| 251 default: | |
| 252 return false; | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 void Pipeline::SetClockForTesting(Clock* clock) { | 237 void Pipeline::SetClockForTesting(Clock* clock) { |
| 257 clock_.reset(clock); | 238 clock_.reset(clock); |
| 258 } | 239 } |
| 259 | 240 |
| 260 void Pipeline::SetErrorForTesting(PipelineStatus status) { | 241 void Pipeline::SetErrorForTesting(PipelineStatus status) { |
| 261 SetError(status); | 242 SetError(status); |
| 262 } | 243 } |
| 263 | 244 |
| 264 void Pipeline::SetState(State next_state) { | 245 void Pipeline::SetState(State next_state) { |
| 265 if (state_ != kStarted && next_state == kStarted && | 246 if (state_ != kStarted && next_state == kStarted && |
| 266 !creation_time_.is_null()) { | 247 !creation_time_.is_null()) { |
| 267 UMA_HISTOGRAM_TIMES( | 248 UMA_HISTOGRAM_TIMES( |
| 268 "Media.TimeToPipelineStarted", base::Time::Now() - creation_time_); | 249 "Media.TimeToPipelineStarted", base::Time::Now() - creation_time_); |
| 269 creation_time_ = base::Time(); | 250 creation_time_ = base::Time(); |
| 270 } | 251 } |
| 271 state_ = next_state; | 252 state_ = next_state; |
| 272 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); | 253 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); |
| 273 } | 254 } |
| 274 | 255 |
| 275 bool Pipeline::IsPipelineOk() { | 256 bool Pipeline::IsPipelineOk() { |
| 276 base::AutoLock auto_lock(lock_); | 257 base::AutoLock auto_lock(lock_); |
| 277 return status_ == PIPELINE_OK; | 258 return status_ == PIPELINE_OK; |
| 278 } | 259 } |
| 279 | 260 |
| 280 bool Pipeline::IsPipelineStopped() { | |
| 281 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 282 return state_ == kStopped || state_ == kError; | |
| 283 } | |
| 284 | |
| 285 bool Pipeline::IsPipelineTearingDown() { | |
| 286 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 287 return tearing_down_; | |
| 288 } | |
| 289 | |
| 290 bool Pipeline::IsPipelineSeeking() { | 261 bool Pipeline::IsPipelineSeeking() { |
| 291 DCHECK(message_loop_->BelongsToCurrentThread()); | 262 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 292 if (!seek_pending_) | 263 if (!seek_pending_) |
| 293 return false; | 264 return false; |
| 294 DCHECK(kSeeking == state_ || kPausing == state_ || | 265 DCHECK(kSeeking == state_ || kPausing == state_ || |
| 295 kFlushing == state_ || kStarting == state_) | 266 kFlushing == state_ || kStarting == state_) |
| 296 << "Current state : " << state_; | 267 << "Current state : " << state_; |
| 297 return true; | 268 return true; |
| 298 } | 269 } |
| 299 | 270 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 328 // static | 299 // static |
| 329 Pipeline::State Pipeline::FindNextState(State current) { | 300 Pipeline::State Pipeline::FindNextState(State current) { |
| 330 // TODO(scherkus): refactor InitializeTask() to make use of this function. | 301 // TODO(scherkus): refactor InitializeTask() to make use of this function. |
| 331 if (current == kPausing) { | 302 if (current == kPausing) { |
| 332 return kFlushing; | 303 return kFlushing; |
| 333 } else if (current == kFlushing) { | 304 } else if (current == kFlushing) { |
| 334 // We will always honor Seek() before Stop(). This is based on the | 305 // We will always honor Seek() before Stop(). This is based on the |
| 335 // assumption that we never accept Seek() after Stop(). | 306 // assumption that we never accept Seek() after Stop(). |
| 336 DCHECK(IsPipelineSeeking() || | 307 DCHECK(IsPipelineSeeking() || |
| 337 !stop_cb_.is_null() || | 308 !stop_cb_.is_null() || |
| 338 IsPipelineTearingDown()); | 309 tearing_down_); |
| 339 return IsPipelineSeeking() ? kSeeking : kStopping; | 310 return IsPipelineSeeking() ? kSeeking : kStopping; |
| 340 } else if (current == kSeeking) { | 311 } else if (current == kSeeking) { |
| 341 return kStarting; | 312 return kStarting; |
| 342 } else if (current == kStarting) { | 313 } else if (current == kStarting) { |
| 343 return kStarted; | 314 return kStarted; |
| 344 } else if (current == kStopping) { | 315 } else if (current == kStopping) { |
| 345 return error_caused_teardown_ ? kError : kStopped; | 316 return kStopped; |
| 346 } else { | 317 } else { |
| 347 return current; | 318 return current; |
| 348 } | 319 } |
| 349 } | 320 } |
| 350 | 321 |
| 351 void Pipeline::OnDemuxerError(PipelineStatus error) { | 322 void Pipeline::OnDemuxerError(PipelineStatus error) { |
| 352 SetError(error); | 323 SetError(error); |
| 353 } | 324 } |
| 354 | 325 |
| 355 void Pipeline::SetError(PipelineStatus error) { | 326 void Pipeline::SetError(PipelineStatus error) { |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 if (state_ == kInitVideoDecoder && | 588 if (state_ == kInitVideoDecoder && |
| 618 last_stage_status == DECODER_ERROR_NOT_SUPPORTED) { | 589 last_stage_status == DECODER_ERROR_NOT_SUPPORTED) { |
| 619 state_ = kInitAudioRenderer; | 590 state_ = kInitAudioRenderer; |
| 620 } else { | 591 } else { |
| 621 SetError(last_stage_status); | 592 SetError(last_stage_status); |
| 622 return; | 593 return; |
| 623 } | 594 } |
| 624 } | 595 } |
| 625 | 596 |
| 626 // If we have received the stop or error signal, return immediately. | 597 // If we have received the stop or error signal, return immediately. |
| 627 if (!stop_cb_.is_null() || IsPipelineStopped() || !IsPipelineOk()) | 598 if (!stop_cb_.is_null() || state_ == kStopped || !IsPipelineOk()) |
| 628 return; | 599 return; |
| 629 | 600 |
| 630 DCHECK(state_ == kInitDemuxer || | 601 DCHECK(state_ == kInitDemuxer || |
| 631 state_ == kInitAudioDecoder || | 602 state_ == kInitAudioDecoder || |
| 632 state_ == kInitAudioRenderer || | 603 state_ == kInitAudioRenderer || |
| 633 state_ == kInitVideoDecoder || | 604 state_ == kInitVideoDecoder || |
| 634 state_ == kInitVideoRenderer); | 605 state_ == kInitVideoRenderer); |
| 635 | 606 |
| 636 // Demuxer created, create audio decoder. | 607 // Demuxer created, create audio decoder. |
| 637 if (state_ == kInitDemuxer) { | 608 if (state_ == kInitDemuxer) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 // This method is called as a result of the client calling Pipeline::Stop() or | 670 // This method is called as a result of the client calling Pipeline::Stop() or |
| 700 // as the result of an error condition. | 671 // as the result of an error condition. |
| 701 // We stop the filters in the reverse order. | 672 // We stop the filters in the reverse order. |
| 702 // | 673 // |
| 703 // TODO(scherkus): beware! this can get posted multiple times since we post | 674 // TODO(scherkus): beware! this can get posted multiple times since we post |
| 704 // Stop() tasks even if we've already stopped. Perhaps this should no-op for | 675 // Stop() tasks even if we've already stopped. Perhaps this should no-op for |
| 705 // additional calls, however most of this logic will be changing. | 676 // additional calls, however most of this logic will be changing. |
| 706 void Pipeline::StopTask(const base::Closure& stop_cb) { | 677 void Pipeline::StopTask(const base::Closure& stop_cb) { |
| 707 DCHECK(message_loop_->BelongsToCurrentThread()); | 678 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 708 DCHECK(stop_cb_.is_null()); | 679 DCHECK(stop_cb_.is_null()); |
| 709 DCHECK_NE(state_, kStopped); | 680 |
| 681 if (state_ == kStopped) { |
| 682 stop_cb.Run(); |
| 683 return; |
| 684 } |
| 710 | 685 |
| 711 if (video_decoder_) { | 686 if (video_decoder_) { |
| 712 video_decoder_->PrepareForShutdownHack(); | 687 video_decoder_->PrepareForShutdownHack(); |
| 713 video_decoder_ = NULL; | 688 video_decoder_ = NULL; |
| 714 } | 689 } |
| 715 | 690 |
| 716 if (IsPipelineTearingDown() && error_caused_teardown_) { | 691 if (tearing_down_ && status_ != PIPELINE_OK) { |
| 717 // If we are stopping due to SetError(), stop normally instead of | 692 // If we are stopping due to SetError(), stop normally instead of |
| 718 // going to error state and calling |error_cb_|. This converts | 693 // going to error state and calling |error_cb_|. This converts |
| 719 // the teardown in progress from an error teardown into one that acts | 694 // the teardown in progress from an error teardown into one that acts |
| 720 // like the error never occurred. | 695 // like the error never occurred. |
| 721 base::AutoLock auto_lock(lock_); | 696 base::AutoLock auto_lock(lock_); |
| 722 status_ = PIPELINE_OK; | 697 status_ = PIPELINE_OK; |
| 723 error_caused_teardown_ = false; | |
| 724 } | 698 } |
| 725 | 699 |
| 726 stop_cb_ = stop_cb; | 700 stop_cb_ = stop_cb; |
| 727 | 701 |
| 728 if (!IsPipelineSeeking() && !IsPipelineTearingDown()) { | 702 if (!IsPipelineSeeking() && !tearing_down_) { |
| 729 // We will tear down pipeline immediately when there is no seek operation | 703 // We will tear down pipeline immediately when there is no seek operation |
| 730 // pending and no teardown in progress. This should include the case where | 704 // pending and no teardown in progress. This should include the case where |
| 731 // we are partially initialized. | 705 // we are partially initialized. |
| 732 TearDownPipeline(); | 706 TearDownPipeline(); |
| 733 } | 707 } |
| 734 } | 708 } |
| 735 | 709 |
| 736 void Pipeline::ErrorChangedTask(PipelineStatus error) { | 710 void Pipeline::ErrorChangedTask(PipelineStatus error) { |
| 737 DCHECK(message_loop_->BelongsToCurrentThread()); | 711 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 738 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; | 712 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; |
| 739 | 713 |
| 740 // Suppress executing additional error logic. Note that if we are currently | 714 // Suppress executing additional error logic. Note that if we are currently |
| 741 // performing a normal stop, then we return immediately and continue the | 715 // performing a normal stop, then we return immediately and continue the |
| 742 // normal stop. | 716 // normal stop. |
| 743 if (IsPipelineStopped() || IsPipelineTearingDown()) { | 717 if (state_ == kStopped || tearing_down_) { |
| 744 return; | 718 return; |
| 745 } | 719 } |
| 746 | 720 |
| 747 base::AutoLock auto_lock(lock_); | 721 base::AutoLock auto_lock(lock_); |
| 748 status_ = error; | 722 status_ = error; |
| 749 | 723 |
| 750 error_caused_teardown_ = true; | |
| 751 | |
| 752 // Posting TearDownPipeline() to message loop so that we can make sure | 724 // Posting TearDownPipeline() to message loop so that we can make sure |
| 753 // it runs after any pending callbacks that are already queued. | 725 // it runs after any pending callbacks that are already queued. |
| 754 // |tearing_down_| is set early here to make sure that pending callbacks | 726 // |tearing_down_| is set early here to make sure that pending callbacks |
| 755 // don't modify the state before TeadDownPipeline() can run. | 727 // don't modify the state before TearDownPipeline() can run. |
| 756 tearing_down_ = true; | 728 tearing_down_ = true; |
| 757 message_loop_->PostTask(FROM_HERE, base::Bind( | 729 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 758 &Pipeline::TearDownPipeline, this)); | 730 &Pipeline::TearDownPipeline, this)); |
| 759 } | 731 } |
| 760 | 732 |
| 761 void Pipeline::PlaybackRateChangedTask(float playback_rate) { | 733 void Pipeline::PlaybackRateChangedTask(float playback_rate) { |
| 762 DCHECK(message_loop_->BelongsToCurrentThread()); | 734 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 763 | 735 |
| 764 if (!running_ || tearing_down_) | 736 if (state_ == kStopped || tearing_down_) |
| 765 return; | 737 return; |
| 766 | 738 |
| 767 // Suppress rate change until after seeking. | 739 // Suppress rate change until after seeking. |
| 768 if (IsPipelineSeeking()) { | 740 if (IsPipelineSeeking()) { |
| 769 pending_playback_rate_ = playback_rate; | 741 pending_playback_rate_ = playback_rate; |
| 770 playback_rate_change_pending_ = true; | 742 playback_rate_change_pending_ = true; |
| 771 return; | 743 return; |
| 772 } | 744 } |
| 773 | 745 |
| 774 { | 746 { |
| 775 base::AutoLock auto_lock(lock_); | 747 base::AutoLock auto_lock(lock_); |
| 776 clock_->SetPlaybackRate(playback_rate); | 748 clock_->SetPlaybackRate(playback_rate); |
| 777 } | 749 } |
| 778 | 750 |
| 779 // These will get set after initialization completes in case playback rate is | 751 // These will get set after initialization completes in case playback rate is |
| 780 // set prior to initialization. | 752 // set prior to initialization. |
| 781 if (demuxer_) | 753 if (demuxer_) |
| 782 demuxer_->SetPlaybackRate(playback_rate); | 754 demuxer_->SetPlaybackRate(playback_rate); |
| 783 if (audio_renderer_) | 755 if (audio_renderer_) |
| 784 audio_renderer_->SetPlaybackRate(playback_rate_); | 756 audio_renderer_->SetPlaybackRate(playback_rate_); |
| 785 if (video_renderer_) | 757 if (video_renderer_) |
| 786 video_renderer_->SetPlaybackRate(playback_rate_); | 758 video_renderer_->SetPlaybackRate(playback_rate_); |
| 787 } | 759 } |
| 788 | 760 |
| 789 void Pipeline::VolumeChangedTask(float volume) { | 761 void Pipeline::VolumeChangedTask(float volume) { |
| 790 DCHECK(message_loop_->BelongsToCurrentThread()); | 762 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 791 if (!running_ || tearing_down_) | 763 |
| 764 if (state_ == kStopped || tearing_down_) |
| 792 return; | 765 return; |
| 793 | 766 |
| 794 if (audio_renderer_) | 767 if (audio_renderer_) |
| 795 audio_renderer_->SetVolume(volume); | 768 audio_renderer_->SetVolume(volume); |
| 796 } | 769 } |
| 797 | 770 |
| 798 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { | 771 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
| 799 DCHECK(message_loop_->BelongsToCurrentThread()); | 772 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 800 DCHECK(stop_cb_.is_null()); | 773 DCHECK(stop_cb_.is_null()); |
| 801 | 774 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 896 clock_->SetMaxTime(clock_->Duration()); | 869 clock_->SetMaxTime(clock_->Duration()); |
| 897 StartClockIfWaitingForTimeUpdate_Locked(); | 870 StartClockIfWaitingForTimeUpdate_Locked(); |
| 898 } | 871 } |
| 899 | 872 |
| 900 void Pipeline::FilterStateTransitionTask() { | 873 void Pipeline::FilterStateTransitionTask() { |
| 901 DCHECK(message_loop_->BelongsToCurrentThread()); | 874 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 902 DCHECK(pending_callbacks_.get()) | 875 DCHECK(pending_callbacks_.get()) |
| 903 << "Filter state transitions must be completed via pending_callbacks_"; | 876 << "Filter state transitions must be completed via pending_callbacks_"; |
| 904 pending_callbacks_.reset(); | 877 pending_callbacks_.reset(); |
| 905 | 878 |
| 906 // No reason transitioning if we've errored or have stopped. | 879 // State transitions while tearing down are handled via |
| 907 if (IsPipelineStopped()) { | 880 // TeardownStateTransitionTask(). |
| 881 // |
| 882 // TODO(scherkus): Merge all state machinery! |
| 883 if (state_ == kStopped || tearing_down_) { |
| 908 return; | 884 return; |
| 909 } | 885 } |
| 910 | 886 |
| 911 // If we are tearing down, don't allow any state changes. Teardown | |
| 912 // state changes will come in via TeardownStateTransitionTask(). | |
| 913 if (IsPipelineTearingDown()) { | |
| 914 return; | |
| 915 } | |
| 916 | |
| 917 if (!TransientState(state_)) { | 887 if (!TransientState(state_)) { |
| 918 NOTREACHED() << "Invalid current state: " << state_; | 888 NOTREACHED() << "Invalid current state: " << state_; |
| 919 SetError(PIPELINE_ERROR_ABORT); | 889 SetError(PIPELINE_ERROR_ABORT); |
| 920 return; | 890 return; |
| 921 } | 891 } |
| 922 | 892 |
| 923 // Decrement the number of remaining transitions, making sure to transition | 893 // Decrement the number of remaining transitions, making sure to transition |
| 924 // to the next state if needed. | 894 // to the next state if needed. |
| 925 SetState(FindNextState(state_)); | 895 SetState(FindNextState(state_)); |
| 926 if (state_ == kSeeking) { | 896 if (state_ == kSeeking) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 970 // Check if we have a pending stop request that needs to be honored. | 940 // Check if we have a pending stop request that needs to be honored. |
| 971 if (!stop_cb_.is_null()) { | 941 if (!stop_cb_.is_null()) { |
| 972 TearDownPipeline(); | 942 TearDownPipeline(); |
| 973 } | 943 } |
| 974 } else { | 944 } else { |
| 975 NOTREACHED() << "Unexpected state: " << state_; | 945 NOTREACHED() << "Unexpected state: " << state_; |
| 976 } | 946 } |
| 977 } | 947 } |
| 978 | 948 |
| 979 void Pipeline::TeardownStateTransitionTask() { | 949 void Pipeline::TeardownStateTransitionTask() { |
| 980 DCHECK(IsPipelineTearingDown()); | 950 DCHECK(tearing_down_); |
| 981 DCHECK(pending_callbacks_.get()) | 951 DCHECK(pending_callbacks_.get()) |
| 982 << "Teardown state transitions must be completed via pending_callbacks_"; | 952 << "Teardown state transitions must be completed via pending_callbacks_"; |
| 983 pending_callbacks_.reset(); | 953 pending_callbacks_.reset(); |
| 984 | 954 |
| 985 switch (state_) { | 955 switch (state_) { |
| 986 case kStopping: | 956 case kStopping: |
| 987 SetState(error_caused_teardown_ ? kError : kStopped); | 957 SetState(kStopped); |
| 988 FinishDestroyingFiltersTask(); | 958 FinishDestroyingFiltersTask(); |
| 989 break; | 959 break; |
| 990 case kPausing: | 960 case kPausing: |
| 991 SetState(kFlushing); | 961 SetState(kFlushing); |
| 992 DoFlush(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 962 DoFlush(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
| 993 break; | 963 break; |
| 994 case kFlushing: | 964 case kFlushing: |
| 995 SetState(kStopping); | 965 SetState(kStopping); |
| 996 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); | 966 DoStop(base::Bind(&Pipeline::OnTeardownStateTransition, this)); |
| 997 break; | 967 break; |
| 998 | 968 |
| 999 case kCreated: | 969 case kCreated: |
| 1000 case kError: | |
| 1001 case kInitDemuxer: | 970 case kInitDemuxer: |
| 1002 case kInitAudioDecoder: | 971 case kInitAudioDecoder: |
| 1003 case kInitAudioRenderer: | 972 case kInitAudioRenderer: |
| 1004 case kInitVideoDecoder: | 973 case kInitVideoDecoder: |
| 1005 case kInitVideoRenderer: | 974 case kInitVideoRenderer: |
| 1006 case kSeeking: | 975 case kSeeking: |
| 1007 case kStarting: | 976 case kStarting: |
| 1008 case kStopped: | 977 case kStopped: |
| 1009 case kStarted: | 978 case kStarted: |
| 1010 NOTREACHED() << "Unexpected state for teardown: " << state_; | 979 NOTREACHED() << "Unexpected state for teardown: " << state_; |
| 1011 break; | 980 break; |
| 1012 // default: intentionally left out to force new states to cause compiler | 981 // default: intentionally left out to force new states to cause compiler |
| 1013 // errors. | 982 // errors. |
| 1014 }; | 983 }; |
| 1015 } | 984 } |
| 1016 | 985 |
| 1017 void Pipeline::FinishDestroyingFiltersTask() { | 986 void Pipeline::FinishDestroyingFiltersTask() { |
| 1018 DCHECK(message_loop_->BelongsToCurrentThread()); | 987 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1019 DCHECK(IsPipelineStopped()); | 988 DCHECK_EQ(state_, kStopped); |
| 1020 | 989 |
| 1021 audio_renderer_ = NULL; | 990 audio_renderer_ = NULL; |
| 1022 video_renderer_ = NULL; | 991 video_renderer_ = NULL; |
| 1023 demuxer_ = NULL; | 992 demuxer_ = NULL; |
| 993 tearing_down_ = false; |
| 994 { |
| 995 base::AutoLock l(lock_); |
| 996 running_ = false; |
| 997 } |
| 1024 | 998 |
| 1025 if (error_caused_teardown_ && !IsPipelineOk() && !error_cb_.is_null()) | 999 if (!IsPipelineOk() && !error_cb_.is_null()) |
| 1026 error_cb_.Run(status_); | 1000 error_cb_.Run(status_); |
| 1027 | 1001 |
| 1028 if (!stop_cb_.is_null()) { | 1002 if (!stop_cb_.is_null()) |
| 1029 { | |
| 1030 base::AutoLock l(lock_); | |
| 1031 running_ = false; | |
| 1032 } | |
| 1033 | |
| 1034 // Notify the client that stopping has finished. | |
| 1035 base::ResetAndReturn(&stop_cb_).Run(); | 1003 base::ResetAndReturn(&stop_cb_).Run(); |
| 1036 } | |
| 1037 | |
| 1038 tearing_down_ = false; | |
| 1039 error_caused_teardown_ = false; | |
| 1040 } | 1004 } |
| 1041 | 1005 |
| 1042 void Pipeline::InitializeDemuxer() { | 1006 void Pipeline::InitializeDemuxer() { |
| 1043 DCHECK(message_loop_->BelongsToCurrentThread()); | 1007 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1044 DCHECK(IsPipelineOk()); | 1008 DCHECK(IsPipelineOk()); |
| 1045 | 1009 |
| 1046 demuxer_ = filter_collection_->GetDemuxer(); | 1010 demuxer_ = filter_collection_->GetDemuxer(); |
| 1047 if (!demuxer_) { | 1011 if (!demuxer_) { |
| 1048 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); | 1012 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); |
| 1049 return; | 1013 return; |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1182 | 1146 |
| 1183 void Pipeline::TearDownPipeline() { | 1147 void Pipeline::TearDownPipeline() { |
| 1184 DCHECK(message_loop_->BelongsToCurrentThread()); | 1148 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 1185 DCHECK_NE(kStopped, state_); | 1149 DCHECK_NE(kStopped, state_); |
| 1186 | 1150 |
| 1187 // We're either... | 1151 // We're either... |
| 1188 // 1) ...tearing down due to Stop() (it doesn't set tearing_down_) | 1152 // 1) ...tearing down due to Stop() (it doesn't set tearing_down_) |
| 1189 // 2) ...tearing down due to an error (it does set tearing_down_) | 1153 // 2) ...tearing down due to an error (it does set tearing_down_) |
| 1190 // 3) ...tearing down due to an error and Stop() was called during that time | 1154 // 3) ...tearing down due to an error and Stop() was called during that time |
| 1191 DCHECK(!tearing_down_ || | 1155 DCHECK(!tearing_down_ || |
| 1192 (tearing_down_ && error_caused_teardown_) || | 1156 (tearing_down_ && status_ != PIPELINE_OK) || |
| 1193 (tearing_down_ && !stop_cb_.is_null())); | 1157 (tearing_down_ && !stop_cb_.is_null())); |
| 1194 | 1158 |
| 1195 // Mark that we already start tearing down operation. | 1159 // Mark that we already start tearing down operation. |
| 1196 tearing_down_ = true; | 1160 tearing_down_ = true; |
| 1197 | 1161 |
| 1198 // Cancel any pending operation so we can proceed with teardown. | 1162 // Cancel any pending operation so we can proceed with teardown. |
| 1199 pending_callbacks_.reset(); | 1163 pending_callbacks_.reset(); |
| 1200 | 1164 |
| 1201 switch (state_) { | 1165 switch (state_) { |
| 1202 case kCreated: | 1166 case kCreated: |
| 1203 case kError: | |
| 1204 SetState(kStopped); | 1167 SetState(kStopped); |
| 1205 // Need to put this in the message loop to make sure that it comes | 1168 // Need to put this in the message loop to make sure that it comes |
| 1206 // after any pending callback tasks that are already queued. | 1169 // after any pending callback tasks that are already queued. |
| 1207 message_loop_->PostTask(FROM_HERE, base::Bind( | 1170 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 1208 &Pipeline::FinishDestroyingFiltersTask, this)); | 1171 &Pipeline::FinishDestroyingFiltersTask, this)); |
| 1209 break; | 1172 break; |
| 1210 | 1173 |
| 1211 case kInitDemuxer: | 1174 case kInitDemuxer: |
| 1212 case kInitAudioDecoder: | 1175 case kInitAudioDecoder: |
| 1213 case kInitAudioRenderer: | 1176 case kInitAudioRenderer: |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1293 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1256 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
| 1294 lock_.AssertAcquired(); | 1257 lock_.AssertAcquired(); |
| 1295 if (!waiting_for_clock_update_) | 1258 if (!waiting_for_clock_update_) |
| 1296 return; | 1259 return; |
| 1297 | 1260 |
| 1298 waiting_for_clock_update_ = false; | 1261 waiting_for_clock_update_ = false; |
| 1299 clock_->Play(); | 1262 clock_->Play(); |
| 1300 } | 1263 } |
| 1301 | 1264 |
| 1302 } // namespace media | 1265 } // namespace media |
| OLD | NEW |