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 bool PipelineImpl::IsPipelineInitializing() { |
scherkus (not reviewing)
2011/01/13 00:47:38
I wonder if we still need this method given the on
acolwell GONE FROM CHROMIUM
2011/01/13 01:39:16
Moved method body to DCHECK()and removed method.
| |
329 DCHECK_EQ(MessageLoop::current(), message_loop_); | 330 DCHECK_EQ(MessageLoop::current(), message_loop_); |
330 return state_ == kInitDataSource || | 331 return state_ == kInitDataSource || |
331 state_ == kInitDemuxer || | 332 state_ == kInitDemuxer || |
332 state_ == kInitAudioDecoder || | 333 state_ == kInitAudioDecoder || |
333 state_ == kInitAudioRenderer || | 334 state_ == kInitAudioRenderer || |
334 state_ == kInitVideoDecoder || | 335 state_ == kInitVideoDecoder || |
335 state_ == kInitVideoRenderer; | 336 state_ == kInitVideoRenderer; |
336 } | 337 } |
337 | 338 |
338 bool PipelineImpl::IsPipelineStopped() { | 339 bool PipelineImpl::IsPipelineStopped() { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
386 } else if (current == kFlushing) { | 387 } else if (current == kFlushing) { |
387 // We will always honor Seek() before Stop(). This is based on the | 388 // We will always honor Seek() before Stop(). This is based on the |
388 // assumption that we never accept Seek() after Stop(). | 389 // assumption that we never accept Seek() after Stop(). |
389 DCHECK(IsPipelineSeeking() || IsPipelineStopPending()); | 390 DCHECK(IsPipelineSeeking() || IsPipelineStopPending()); |
390 return IsPipelineSeeking() ? kSeeking : kStopping; | 391 return IsPipelineSeeking() ? kSeeking : kStopping; |
391 } else if (current == kSeeking) { | 392 } else if (current == kSeeking) { |
392 return kStarting; | 393 return kStarting; |
393 } else if (current == kStarting) { | 394 } else if (current == kStarting) { |
394 return kStarted; | 395 return kStarted; |
395 } else if (current == kStopping) { | 396 } else if (current == kStopping) { |
396 return kStopped; | 397 return error_caused_teardown_ ? kError : kStopped; |
397 } else { | 398 } else { |
398 return current; | 399 return current; |
399 } | 400 } |
400 } | 401 } |
401 | 402 |
402 void PipelineImpl::SetError(PipelineError error) { | 403 void PipelineImpl::SetError(PipelineError error) { |
403 DCHECK(IsRunning()); | 404 DCHECK(IsRunning()); |
404 DCHECK(error != PIPELINE_OK) << "PIPELINE_OK isn't an error!"; | 405 DCHECK(error != PIPELINE_OK) << "PIPELINE_OK isn't an error!"; |
405 VLOG(1) << "Media pipeline error: " << error; | 406 VLOG(1) << "Media pipeline error: " << error; |
406 | 407 |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
663 | 664 |
664 // This method is called as a result of the client calling Pipeline::Stop() or | 665 // This method is called as a result of the client calling Pipeline::Stop() or |
665 // as the result of an error condition. | 666 // as the result of an error condition. |
666 // We stop the filters in the reverse order. | 667 // We stop the filters in the reverse order. |
667 // | 668 // |
668 // TODO(scherkus): beware! this can get posted multiple times since we post | 669 // 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 | 670 // 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. | 671 // additional calls, however most of this logic will be changing. |
671 void PipelineImpl::StopTask(PipelineCallback* stop_callback) { | 672 void PipelineImpl::StopTask(PipelineCallback* stop_callback) { |
672 DCHECK_EQ(MessageLoop::current(), message_loop_); | 673 DCHECK_EQ(MessageLoop::current(), message_loop_); |
673 PipelineError error = GetError(); | 674 DCHECK(!IsPipelineStopPending()); |
675 DCHECK_NE(state_, kStopped); | |
674 | 676 |
675 if (state_ == kStopped || (IsPipelineStopPending() && error == PIPELINE_OK)) { | 677 if (state_ == kStopped) { |
676 // If we are already stopped or stopping normally, return immediately. | 678 // Already stopped so just run callback. |
679 stop_callback->Run(); | |
677 delete stop_callback; | 680 delete stop_callback; |
678 return; | 681 return; |
679 } else if (state_ == kError || | 682 } |
680 (IsPipelineStopPending() && error != PIPELINE_OK)) { | 683 |
684 if (IsPipelineTearingDown() && error_caused_teardown_) { | |
scherkus (not reviewing)
2011/01/13 00:47:38
to confirm: this happens in the case someone calls
acolwell GONE FROM CHROMIUM
2011/01/13 01:39:16
This happens in the case where an error occurs tha
| |
681 // If we are stopping due to SetError(), stop normally instead of | 685 // If we are stopping due to SetError(), stop normally instead of |
682 // going to error state. | 686 // going to error state and calling |error_callback_|. This converts |
687 // the teardown in progress from an error teardown into one that acts | |
688 // like the error never occurred. | |
683 AutoLock auto_lock(lock_); | 689 AutoLock auto_lock(lock_); |
684 error_ = PIPELINE_OK; | 690 error_ = PIPELINE_OK; |
691 error_caused_teardown_ = false; | |
685 } | 692 } |
686 | 693 |
687 stop_callback_.reset(stop_callback); | 694 stop_callback_.reset(stop_callback); |
688 | 695 |
689 stop_pending_ = true; | 696 stop_pending_ = true; |
690 if (!IsPipelineSeeking()) { | 697 if (!IsPipelineSeeking() && !IsPipelineTearingDown()) { |
691 // We will tear down pipeline immediately when there is no seek operation | 698 // We will tear down pipeline immediately when there is no seek operation |
692 // pending. This should include the case where we are partially initialized. | 699 // 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. | 700 // we are partially initialized. |
694 DCHECK(!IsPipelineTearingDown()); | |
695 TearDownPipeline(); | 701 TearDownPipeline(); |
696 } | 702 } |
697 } | 703 } |
698 | 704 |
699 void PipelineImpl::ErrorChangedTask(PipelineError error) { | 705 void PipelineImpl::ErrorChangedTask(PipelineError error) { |
700 DCHECK_EQ(MessageLoop::current(), message_loop_); | 706 DCHECK_EQ(MessageLoop::current(), message_loop_); |
701 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; | 707 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; |
702 | 708 |
703 // Suppress executing additional error logic. Note that if we are currently | 709 // Suppress executing additional error logic. Note that if we are currently |
704 // performing a normal stop, then we return immediately and continue the | 710 // performing a normal stop, then we return immediately and continue the |
705 // normal stop. | 711 // normal stop. |
706 if (IsPipelineStopped() || IsPipelineTearingDown()) { | 712 if (IsPipelineStopped() || IsPipelineTearingDown()) { |
707 return; | 713 return; |
708 } | 714 } |
709 | 715 |
710 AutoLock auto_lock(lock_); | 716 AutoLock auto_lock(lock_); |
711 error_ = error; | 717 error_ = error; |
712 | 718 |
719 error_caused_teardown_ = true; | |
713 TearDownPipeline(); | 720 TearDownPipeline(); |
714 } | 721 } |
715 | 722 |
716 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { | 723 void PipelineImpl::PlaybackRateChangedTask(float playback_rate) { |
717 DCHECK_EQ(MessageLoop::current(), message_loop_); | 724 DCHECK_EQ(MessageLoop::current(), message_loop_); |
718 { | 725 { |
719 AutoLock auto_lock(lock_); | 726 AutoLock auto_lock(lock_); |
720 clock_->SetPlaybackRate(playback_rate); | 727 clock_->SetPlaybackRate(playback_rate); |
721 } | 728 } |
722 | 729 |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
908 void PipelineImpl::FinishDestroyingFiltersTask() { | 915 void PipelineImpl::FinishDestroyingFiltersTask() { |
909 DCHECK_EQ(MessageLoop::current(), message_loop_); | 916 DCHECK_EQ(MessageLoop::current(), message_loop_); |
910 DCHECK(IsPipelineStopped()); | 917 DCHECK(IsPipelineStopped()); |
911 | 918 |
912 // Clear renderer references. | 919 // Clear renderer references. |
913 audio_renderer_ = NULL; | 920 audio_renderer_ = NULL; |
914 video_renderer_ = NULL; | 921 video_renderer_ = NULL; |
915 | 922 |
916 pipeline_filter_ = NULL; | 923 pipeline_filter_ = NULL; |
917 | 924 |
918 stop_pending_ = false; | 925 if (error_caused_teardown_ && GetError() != PIPELINE_OK && |
scherkus (not reviewing)
2011/01/13 00:47:38
nit: get rid of extra space between error_caused_t
acolwell GONE FROM CHROMIUM
2011/01/13 01:39:16
Done.
| |
919 tearing_down_ = false; | 926 error_callback_.get()) { |
927 error_callback_->Run(); | |
928 } | |
920 | 929 |
921 if (PIPELINE_OK == GetError()) { | 930 if (stop_pending_) { |
922 // Destroying filters due to Stop(). | |
923 ResetState(); | 931 ResetState(); |
924 | 932 |
925 // Notify the client that stopping has finished. | 933 // Notify the client that stopping has finished. |
926 if (stop_callback_.get()) { | 934 if (stop_callback_.get()) { |
927 stop_callback_->Run(); | 935 stop_callback_->Run(); |
928 stop_callback_.reset(); | 936 stop_callback_.reset(); |
929 } | 937 } |
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 } | 938 } |
939 | |
940 stop_pending_ = false; | |
941 tearing_down_ = false; | |
942 error_caused_teardown_ = false; | |
938 } | 943 } |
939 | 944 |
940 bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { | 945 bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { |
941 bool ret = pipeline_init_state_->composite_->AddFilter(filter.get()); | 946 bool ret = pipeline_init_state_->composite_->AddFilter(filter.get()); |
942 | 947 |
943 if (!ret) { | 948 if (!ret) { |
944 SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); | 949 SetError(PIPELINE_ERROR_INITIALIZATION_FAILED); |
945 } | 950 } |
946 return ret; | 951 return ret; |
947 } | 952 } |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1112 return NULL; | 1117 return NULL; |
1113 } | 1118 } |
1114 | 1119 |
1115 void PipelineImpl::TearDownPipeline() { | 1120 void PipelineImpl::TearDownPipeline() { |
1116 DCHECK_EQ(MessageLoop::current(), message_loop_); | 1121 DCHECK_EQ(MessageLoop::current(), message_loop_); |
1117 DCHECK_NE(kStopped, state_); | 1122 DCHECK_NE(kStopped, state_); |
1118 | 1123 |
1119 // Mark that we already start tearing down operation. | 1124 // Mark that we already start tearing down operation. |
1120 tearing_down_ = true; | 1125 tearing_down_ = true; |
1121 | 1126 |
1122 if (IsPipelineInitializing()) { | 1127 switch(state_) { |
1123 // Make it look like initialization was successful. | 1128 case kCreated: |
1124 pipeline_filter_ = pipeline_init_state_->composite_; | 1129 case kError: |
1125 pipeline_init_state_.reset(); | 1130 set_state(kStopped); |
1131 message_loop_->PostTask(FROM_HERE, | |
1132 NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); | |
1133 break; | |
1126 | 1134 |
1127 set_state(kStopping); | 1135 case kInitDataSource: |
1128 pipeline_filter_->Stop(NewCallback( | 1136 case kInitDemuxer: |
1129 this, &PipelineImpl::OnFilterStateTransition)); | 1137 case kInitAudioDecoder: |
1138 case kInitAudioRenderer: | |
1139 case kInitVideoDecoder: | |
1140 case kInitVideoRenderer: | |
1141 // Make it look like initialization was successful. | |
1142 pipeline_filter_ = pipeline_init_state_->composite_; | |
1143 pipeline_init_state_.reset(); | |
1130 | 1144 |
1131 FinishInitialization(); | 1145 set_state(kStopping); |
1132 } else if (pipeline_filter_.get()) { | 1146 pipeline_filter_->Stop( |
1133 set_state(kPausing); | 1147 NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
1134 pipeline_filter_->Pause(NewCallback( | 1148 |
1135 this, &PipelineImpl::OnFilterStateTransition)); | 1149 FinishInitialization(); |
1136 } else { | 1150 break; |
1137 set_state(kStopped); | 1151 |
1138 message_loop_->PostTask(FROM_HERE, | 1152 case kPausing: |
1139 NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); | 1153 case kSeeking: |
1140 } | 1154 case kFlushing: |
1155 case kStarting: | |
1156 set_state(kStopping); | |
1157 pipeline_filter_->Stop(NewCallback( | |
scherkus (not reviewing)
2011/01/13 00:47:38
drop NewCallback to next line
acolwell GONE FROM CHROMIUM
2011/01/13 01:39:16
Done.
| |
1158 this, &PipelineImpl::OnFilterStateTransition)); | |
1159 break; | |
1160 | |
1161 case kStarted: | |
1162 case kEnded: | |
1163 set_state(kPausing); | |
1164 pipeline_filter_->Pause(NewCallback( | |
scherkus (not reviewing)
2011/01/13 00:47:38
drop NewCallback to next line
acolwell GONE FROM CHROMIUM
2011/01/13 01:39:16
Done.
| |
1165 this, &PipelineImpl::OnFilterStateTransition)); | |
1166 break; | |
1167 | |
1168 case kStopping: | |
1169 case kStopped: | |
1170 NOTREACHED() << "Unexpected state for teardown: " << state_; | |
1171 break; | |
1172 // default: intentionally left out to force new states to cause compiler | |
1173 // errors. | |
1174 }; | |
1141 } | 1175 } |
1142 | 1176 |
1143 } // namespace media | 1177 } // namespace media |
OLD | NEW |