| 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" |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 return current_bytes_; | 293 return current_bytes_; |
| 294 } | 294 } |
| 295 | 295 |
| 296 void PipelineImpl::ResetState() { | 296 void PipelineImpl::ResetState() { |
| 297 AutoLock auto_lock(lock_); | 297 AutoLock auto_lock(lock_); |
| 298 const base::TimeDelta kZero; | 298 const base::TimeDelta kZero; |
| 299 running_ = false; | 299 running_ = false; |
| 300 stop_pending_ = false; | 300 stop_pending_ = false; |
| 301 seek_pending_ = false; | 301 seek_pending_ = false; |
| 302 tearing_down_ = false; | 302 tearing_down_ = false; |
| 303 error_caused_teardown_ = false; |
| 303 duration_ = kZero; | 304 duration_ = kZero; |
| 304 buffered_time_ = kZero; | 305 buffered_time_ = kZero; |
| 305 buffered_bytes_ = 0; | 306 buffered_bytes_ = 0; |
| 306 streaming_ = false; | 307 streaming_ = false; |
| 307 loaded_ = false; | 308 loaded_ = false; |
| 308 total_bytes_ = 0; | 309 total_bytes_ = 0; |
| 309 video_width_ = 0; | 310 video_width_ = 0; |
| 310 video_height_ = 0; | 311 video_height_ = 0; |
| 311 volume_ = 1.0f; | 312 volume_ = 1.0f; |
| 312 playback_rate_ = 0.0f; | 313 playback_rate_ = 0.0f; |
| 313 error_ = PIPELINE_OK; | 314 error_ = PIPELINE_OK; |
| 314 waiting_for_clock_update_ = false; | 315 waiting_for_clock_update_ = false; |
| 315 audio_disabled_ = false; | 316 audio_disabled_ = false; |
| 316 clock_->SetTime(kZero); | 317 clock_->SetTime(kZero); |
| 317 rendered_mime_types_.clear(); | 318 rendered_mime_types_.clear(); |
| 318 } | 319 } |
| 319 | 320 |
| 320 void PipelineImpl::set_state(State next_state) { | 321 void PipelineImpl::set_state(State next_state) { |
| 321 state_ = next_state; | 322 state_ = next_state; |
| 322 } | 323 } |
| 323 | 324 |
| 324 bool PipelineImpl::IsPipelineOk() { | 325 bool PipelineImpl::IsPipelineOk() { |
| 325 return PIPELINE_OK == GetError(); | 326 return PIPELINE_OK == GetError(); |
| 326 } | 327 } |
| 327 | 328 |
| 328 bool PipelineImpl::IsPipelineInitializing() { | |
| 329 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 330 return state_ == kInitDataSource || | |
| 331 state_ == kInitDemuxer || | |
| 332 state_ == kInitAudioDecoder || | |
| 333 state_ == kInitAudioRenderer || | |
| 334 state_ == kInitVideoDecoder || | |
| 335 state_ == kInitVideoRenderer; | |
| 336 } | |
| 337 | |
| 338 bool PipelineImpl::IsPipelineStopped() { | 329 bool PipelineImpl::IsPipelineStopped() { |
| 339 DCHECK_EQ(MessageLoop::current(), message_loop_); | 330 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 340 return state_ == kStopped || state_ == kError; | 331 return state_ == kStopped || state_ == kError; |
| 341 } | 332 } |
| 342 | 333 |
| 343 bool PipelineImpl::IsPipelineTearingDown() { | 334 bool PipelineImpl::IsPipelineTearingDown() { |
| 344 DCHECK_EQ(MessageLoop::current(), message_loop_); | 335 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 345 return tearing_down_; | 336 return tearing_down_; |
| 346 } | 337 } |
| 347 | 338 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 } else if (current == kFlushing) { | 377 } else if (current == kFlushing) { |
| 387 // We will always honor Seek() before Stop(). This is based on the | 378 // We will always honor Seek() before Stop(). This is based on the |
| 388 // assumption that we never accept Seek() after Stop(). | 379 // assumption that we never accept Seek() after Stop(). |
| 389 DCHECK(IsPipelineSeeking() || IsPipelineStopPending()); | 380 DCHECK(IsPipelineSeeking() || IsPipelineStopPending()); |
| 390 return IsPipelineSeeking() ? kSeeking : kStopping; | 381 return IsPipelineSeeking() ? kSeeking : kStopping; |
| 391 } else if (current == kSeeking) { | 382 } else if (current == kSeeking) { |
| 392 return kStarting; | 383 return kStarting; |
| 393 } else if (current == kStarting) { | 384 } else if (current == kStarting) { |
| 394 return kStarted; | 385 return kStarted; |
| 395 } else if (current == kStopping) { | 386 } else if (current == kStopping) { |
| 396 return kStopped; | 387 return error_caused_teardown_ ? kError : kStopped; |
| 397 } else { | 388 } else { |
| 398 return current; | 389 return current; |
| 399 } | 390 } |
| 400 } | 391 } |
| 401 | 392 |
| 402 void PipelineImpl::SetError(PipelineError error) { | 393 void PipelineImpl::SetError(PipelineError error) { |
| 403 DCHECK(IsRunning()); | 394 DCHECK(IsRunning()); |
| 404 DCHECK(error != PIPELINE_OK) << "PIPELINE_OK isn't an error!"; | 395 DCHECK(error != PIPELINE_OK) << "PIPELINE_OK isn't an error!"; |
| 405 VLOG(1) << "Media pipeline error: " << error; | 396 VLOG(1) << "Media pipeline error: " << error; |
| 406 | 397 |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 void PipelineImpl::InitializeTask() { | 556 void PipelineImpl::InitializeTask() { |
| 566 DCHECK_EQ(MessageLoop::current(), message_loop_); | 557 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 567 | 558 |
| 568 // If we have received the stop or error signal, return immediately. | 559 // If we have received the stop or error signal, return immediately. |
| 569 if (IsPipelineStopPending() || | 560 if (IsPipelineStopPending() || |
| 570 IsPipelineStopped() || | 561 IsPipelineStopped() || |
| 571 PIPELINE_OK != GetError()) { | 562 PIPELINE_OK != GetError()) { |
| 572 return; | 563 return; |
| 573 } | 564 } |
| 574 | 565 |
| 575 DCHECK(state_ == kCreated || IsPipelineInitializing()); | 566 DCHECK(state_ == kCreated || |
| 567 state_ == kInitDataSource || |
| 568 state_ == kInitDemuxer || |
| 569 state_ == kInitAudioDecoder || |
| 570 state_ == kInitAudioRenderer || |
| 571 state_ == kInitVideoDecoder || |
| 572 state_ == kInitVideoRenderer); |
| 576 | 573 |
| 577 // Just created, create data source. | 574 // Just created, create data source. |
| 578 if (state_ == kCreated) { | 575 if (state_ == kCreated) { |
| 579 set_state(kInitDataSource); | 576 set_state(kInitDataSource); |
| 580 pipeline_init_state_.reset(new PipelineInitState()); | 577 pipeline_init_state_.reset(new PipelineInitState()); |
| 581 pipeline_init_state_->composite_ = new CompositeFilter(message_loop_); | 578 pipeline_init_state_->composite_ = new CompositeFilter(message_loop_); |
| 582 pipeline_init_state_->composite_->set_host(this); | 579 pipeline_init_state_->composite_->set_host(this); |
| 583 | 580 |
| 584 InitializeDataSource(); | 581 InitializeDataSource(); |
| 585 return; | 582 return; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 | 660 |
| 664 // This method is called as a result of the client calling Pipeline::Stop() or | 661 // This method is called as a result of the client calling Pipeline::Stop() or |
| 665 // as the result of an error condition. | 662 // as the result of an error condition. |
| 666 // We stop the filters in the reverse order. | 663 // We stop the filters in the reverse order. |
| 667 // | 664 // |
| 668 // TODO(scherkus): beware! this can get posted multiple times since we post | 665 // TODO(scherkus): beware! this can get posted multiple times since we post |
| 669 // Stop() tasks even if we've already stopped. Perhaps this should no-op for | 666 // Stop() tasks even if we've already stopped. Perhaps this should no-op for |
| 670 // additional calls, however most of this logic will be changing. | 667 // additional calls, however most of this logic will be changing. |
| 671 void PipelineImpl::StopTask(PipelineCallback* stop_callback) { | 668 void PipelineImpl::StopTask(PipelineCallback* stop_callback) { |
| 672 DCHECK_EQ(MessageLoop::current(), message_loop_); | 669 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 673 PipelineError error = GetError(); | 670 DCHECK(!IsPipelineStopPending()); |
| 671 DCHECK_NE(state_, kStopped); |
| 674 | 672 |
| 675 if (state_ == kStopped || (IsPipelineStopPending() && error == PIPELINE_OK)) { | 673 if (state_ == kStopped) { |
| 676 // If we are already stopped or stopping normally, return immediately. | 674 // Already stopped so just run callback. |
| 675 stop_callback->Run(); |
| 677 delete stop_callback; | 676 delete stop_callback; |
| 678 return; | 677 return; |
| 679 } else if (state_ == kError || | 678 } |
| 680 (IsPipelineStopPending() && error != PIPELINE_OK)) { | 679 |
| 680 if (IsPipelineTearingDown() && error_caused_teardown_) { |
| 681 // If we are stopping due to SetError(), stop normally instead of | 681 // If we are stopping due to SetError(), stop normally instead of |
| 682 // going to error state. | 682 // going to error state and calling |error_callback_|. This converts |
| 683 // the teardown in progress from an error teardown into one that acts |
| 684 // like the error never occurred. |
| 683 AutoLock auto_lock(lock_); | 685 AutoLock auto_lock(lock_); |
| 684 error_ = PIPELINE_OK; | 686 error_ = PIPELINE_OK; |
| 687 error_caused_teardown_ = false; |
| 685 } | 688 } |
| 686 | 689 |
| 687 stop_callback_.reset(stop_callback); | 690 stop_callback_.reset(stop_callback); |
| 688 | 691 |
| 689 stop_pending_ = true; | 692 stop_pending_ = true; |
| 690 if (!IsPipelineSeeking()) { | 693 if (!IsPipelineSeeking() && !IsPipelineTearingDown()) { |
| 691 // We will tear down pipeline immediately when there is no seek operation | 694 // We will tear down pipeline immediately when there is no seek operation |
| 692 // pending. This should include the case where we are partially initialized. | 695 // pending and no teardown in progress. This should include the case where |
| 693 // Ideally this case should use SetError() rather than Stop() to tear down. | 696 // we are partially initialized. |
| 694 DCHECK(!IsPipelineTearingDown()); | |
| 695 TearDownPipeline(); | 697 TearDownPipeline(); |
| 696 } | 698 } |
| 697 } | 699 } |
| 698 | 700 |
| 699 void PipelineImpl::ErrorChangedTask(PipelineError error) { | 701 void PipelineImpl::ErrorChangedTask(PipelineError error) { |
| 700 DCHECK_EQ(MessageLoop::current(), message_loop_); | 702 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 701 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; | 703 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; |
| 702 | 704 |
| 703 // Suppress executing additional error logic. Note that if we are currently | 705 // Suppress executing additional error logic. Note that if we are currently |
| 704 // performing a normal stop, then we return immediately and continue the | 706 // performing a normal stop, then we return immediately and continue the |
| 705 // normal stop. | 707 // normal stop. |
| 706 if (IsPipelineStopped() || IsPipelineTearingDown()) { | 708 if (IsPipelineStopped() || IsPipelineTearingDown()) { |
| 707 return; | 709 return; |
| 708 } | 710 } |
| 709 | 711 |
| 710 AutoLock auto_lock(lock_); | 712 AutoLock auto_lock(lock_); |
| 711 error_ = error; | 713 error_ = error; |
| 712 | 714 |
| 715 error_caused_teardown_ = true; |
| 713 TearDownPipeline(); | 716 TearDownPipeline(); |
| 714 } | 717 } |
| 715 | 718 |
| 716 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { | 719 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { |
| 717 DCHECK_EQ(MessageLoop::current(), message_loop_); | 720 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 718 { | 721 { |
| 719 AutoLock auto_lock(lock_); | 722 AutoLock auto_lock(lock_); |
| 720 clock_->SetPlaybackRate(playback_rate); | 723 clock_->SetPlaybackRate(playback_rate); |
| 721 } | 724 } |
| 722 | 725 |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 908 void PipelineImpl::FinishDestroyingFiltersTask() { | 911 void PipelineImpl::FinishDestroyingFiltersTask() { |
| 909 DCHECK_EQ(MessageLoop::current(), message_loop_); | 912 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 910 DCHECK(IsPipelineStopped()); | 913 DCHECK(IsPipelineStopped()); |
| 911 | 914 |
| 912 // Clear renderer references. | 915 // Clear renderer references. |
| 913 audio_renderer_ = NULL; | 916 audio_renderer_ = NULL; |
| 914 video_renderer_ = NULL; | 917 video_renderer_ = NULL; |
| 915 | 918 |
| 916 pipeline_filter_ = NULL; | 919 pipeline_filter_ = NULL; |
| 917 | 920 |
| 918 stop_pending_ = false; | 921 if (error_caused_teardown_ && GetError() != PIPELINE_OK && |
| 919 tearing_down_ = false; | 922 error_callback_.get()) { |
| 923 error_callback_->Run(); |
| 924 } |
| 920 | 925 |
| 921 if (PIPELINE_OK == GetError()) { | 926 if (stop_pending_) { |
| 922 // Destroying filters due to Stop(). | |
| 923 ResetState(); | 927 ResetState(); |
| 924 | 928 |
| 925 // Notify the client that stopping has finished. | 929 // Notify the client that stopping has finished. |
| 926 if (stop_callback_.get()) { | 930 if (stop_callback_.get()) { |
| 927 stop_callback_->Run(); | 931 stop_callback_->Run(); |
| 928 stop_callback_.reset(); | 932 stop_callback_.reset(); |
| 929 } | 933 } |
| 930 } else { | |
| 931 // Destroying filters due to SetError(). | |
| 932 set_state(kError); | |
| 933 // If our owner has requested to be notified of an error. | |
| 934 if (error_callback_.get()) { | |
| 935 error_callback_->Run(); | |
| 936 } | |
| 937 } | 934 } |
| 935 |
| 936 stop_pending_ = false; |
| 937 tearing_down_ = false; |
| 938 error_caused_teardown_ = false; |
| 938 } | 939 } |
| 939 | 940 |
| 940 bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { | 941 bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { |
| 941 bool ret = pipeline_init_state_->composite_->AddFilter(filter.get()); | 942 bool ret = pipeline_init_state_->composite_->AddFilter(filter.get()); |
| 942 | 943 |
| 943 if (!ret) { | 944 if (!ret) { |
| 944 SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); | 945 SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); |
| 945 } | 946 } |
| 946 return ret; | 947 return ret; |
| 947 } | 948 } |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1112 return NULL; | 1113 return NULL; |
| 1113 } | 1114 } |
| 1114 | 1115 |
| 1115 void PipelineImpl::TearDownPipeline() { | 1116 void PipelineImpl::TearDownPipeline() { |
| 1116 DCHECK_EQ(MessageLoop::current(), message_loop_); | 1117 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 1117 DCHECK_NE(kStopped, state_); | 1118 DCHECK_NE(kStopped, state_); |
| 1118 | 1119 |
| 1119 // Mark that we already start tearing down operation. | 1120 // Mark that we already start tearing down operation. |
| 1120 tearing_down_ = true; | 1121 tearing_down_ = true; |
| 1121 | 1122 |
| 1122 if (IsPipelineInitializing()) { | 1123 switch(state_) { |
| 1123 // Make it look like initialization was successful. | 1124 case kCreated: |
| 1124 pipeline_filter_ = pipeline_init_state_->composite_; | 1125 case kError: |
| 1125 pipeline_init_state_.reset(); | 1126 set_state(kStopped); |
| 1127 message_loop_->PostTask(FROM_HERE, |
| 1128 NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); |
| 1129 break; |
| 1126 | 1130 |
| 1127 set_state(kStopping); | 1131 case kInitDataSource: |
| 1128 pipeline_filter_->Stop(NewCallback( | 1132 case kInitDemuxer: |
| 1129 this, &PipelineImpl::OnFilterStateTransition)); | 1133 case kInitAudioDecoder: |
| 1134 case kInitAudioRenderer: |
| 1135 case kInitVideoDecoder: |
| 1136 case kInitVideoRenderer: |
| 1137 // Make it look like initialization was successful. |
| 1138 pipeline_filter_ = pipeline_init_state_->composite_; |
| 1139 pipeline_init_state_.reset(); |
| 1130 | 1140 |
| 1131 FinishInitialization(); | 1141 set_state(kStopping); |
| 1132 } else if (pipeline_filter_.get()) { | 1142 pipeline_filter_->Stop( |
| 1133 set_state(kPausing); | 1143 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
| 1134 pipeline_filter_->Pause(NewCallback( | 1144 |
| 1135 this, &PipelineImpl::OnFilterStateTransition)); | 1145 FinishInitialization(); |
| 1136 } else { | 1146 break; |
| 1137 set_state(kStopped); | 1147 |
| 1138 message_loop_->PostTask(FROM_HERE, | 1148 case kPausing: |
| 1139 NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); | 1149 case kSeeking: |
| 1140 } | 1150 case kFlushing: |
| 1151 case kStarting: |
| 1152 set_state(kStopping); |
| 1153 pipeline_filter_->Stop( |
| 1154 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
| 1155 break; |
| 1156 |
| 1157 case kStarted: |
| 1158 case kEnded: |
| 1159 set_state(kPausing); |
| 1160 pipeline_filter_->Pause( |
| 1161 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
| 1162 break; |
| 1163 |
| 1164 case kStopping: |
| 1165 case kStopped: |
| 1166 NOTREACHED() << "Unexpected state for teardown: " << state_; |
| 1167 break; |
| 1168 // default: intentionally left out to force new states to cause compiler |
| 1169 // errors. |
| 1170 }; |
| 1141 } | 1171 } |
| 1142 | 1172 |
| 1143 } // namespace media | 1173 } // namespace media |
| OLD | NEW |