 Chromium Code Reviews
 Chromium Code Reviews Issue 423073012:
  Pipeline: Use WeakPtr for DemuxerHost Calls and Tasks.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 423073012:
  Pipeline: Use WeakPtr for DemuxerHost Calls and Tasks.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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 DCHECK(thread_checker_.CalledOnValidThread()) | 65 DCHECK(thread_checker_.CalledOnValidThread()) | 
| 66 << "Pipeline must be destroyed on same thread that created it"; | 66 << "Pipeline must be destroyed on same thread that created it"; | 
| 67 DCHECK(!running_) << "Stop() must complete before destroying object"; | 67 DCHECK(!running_) << "Stop() must complete before destroying object"; | 
| 68 DCHECK(stop_cb_.is_null()); | 68 DCHECK(stop_cb_.is_null()); | 
| 69 DCHECK(seek_cb_.is_null()); | 69 DCHECK(seek_cb_.is_null()); | 
| 70 | 70 | 
| 71 media_log_->AddEvent( | 71 media_log_->AddEvent( | 
| 72 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); | 72 media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED)); | 
| 73 } | 73 } | 
| 74 | 74 | 
| 75 // The base::Unretained(this) in these functions are safe because: | |
| 76 // 1, No public methods (except for the dtor) should be called after Stop(). | |
| 77 // 2, |this| will not be destructed until the stop callback is fired. | |
| 78 // 3, Stop() also posts StopTask(), hence all XxxTask() will be executed before | |
| 79 // StopTask(), and therefore before the dtor. | |
| 80 | |
| 81 void Pipeline::Start(scoped_ptr<FilterCollection> collection, | 75 void Pipeline::Start(scoped_ptr<FilterCollection> collection, | 
| 82 const base::Closure& ended_cb, | 76 const base::Closure& ended_cb, | 
| 83 const PipelineStatusCB& error_cb, | 77 const PipelineStatusCB& error_cb, | 
| 84 const PipelineStatusCB& seek_cb, | 78 const PipelineStatusCB& seek_cb, | 
| 85 const PipelineMetadataCB& metadata_cb, | 79 const PipelineMetadataCB& metadata_cb, | 
| 86 const BufferingStateCB& buffering_state_cb, | 80 const BufferingStateCB& buffering_state_cb, | 
| 87 const base::Closure& duration_change_cb) { | 81 const base::Closure& duration_change_cb) { | 
| 88 DCHECK(!ended_cb.is_null()); | 82 DCHECK(!ended_cb.is_null()); | 
| 89 DCHECK(!error_cb.is_null()); | 83 DCHECK(!error_cb.is_null()); | 
| 90 DCHECK(!seek_cb.is_null()); | 84 DCHECK(!seek_cb.is_null()); | 
| 91 DCHECK(!metadata_cb.is_null()); | 85 DCHECK(!metadata_cb.is_null()); | 
| 92 DCHECK(!buffering_state_cb.is_null()); | 86 DCHECK(!buffering_state_cb.is_null()); | 
| 93 | 87 | 
| 94 base::AutoLock auto_lock(lock_); | 88 base::AutoLock auto_lock(lock_); | 
| 95 CHECK(!running_) << "Media pipeline is already running"; | 89 CHECK(!running_) << "Media pipeline is already running"; | 
| 96 running_ = true; | 90 running_ = true; | 
| 97 | 91 | 
| 98 filter_collection_ = collection.Pass(); | 92 filter_collection_ = collection.Pass(); | 
| 99 ended_cb_ = ended_cb; | 93 ended_cb_ = ended_cb; | 
| 100 error_cb_ = error_cb; | 94 error_cb_ = error_cb; | 
| 101 seek_cb_ = seek_cb; | 95 seek_cb_ = seek_cb; | 
| 102 metadata_cb_ = metadata_cb; | 96 metadata_cb_ = metadata_cb; | 
| 103 buffering_state_cb_ = buffering_state_cb; | 97 buffering_state_cb_ = buffering_state_cb; | 
| 104 duration_change_cb_ = duration_change_cb; | 98 duration_change_cb_ = duration_change_cb; | 
| 105 | 99 | 
| 106 task_runner_->PostTask( | 100 task_runner_->PostTask( | 
| 107 FROM_HERE, base::Bind(&Pipeline::StartTask, base::Unretained(this))); | 101 FROM_HERE, base::Bind(&Pipeline::StartTask, weak_factory_.GetWeakPtr())); | 
| 108 } | 102 } | 
| 109 | 103 | 
| 110 void Pipeline::Stop(const base::Closure& stop_cb) { | 104 void Pipeline::Stop(const base::Closure& stop_cb) { | 
| 111 DVLOG(2) << __FUNCTION__; | 105 DVLOG(2) << __FUNCTION__; | 
| 112 task_runner_->PostTask( | 106 task_runner_->PostTask( | 
| 113 FROM_HERE, | 107 FROM_HERE, | 
| 114 base::Bind(&Pipeline::StopTask, base::Unretained(this), stop_cb)); | 108 base::Bind(&Pipeline::StopTask, weak_factory_.GetWeakPtr(), stop_cb)); | 
| 115 } | 109 } | 
| 116 | 110 | 
| 117 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { | 111 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { | 
| 118 base::AutoLock auto_lock(lock_); | 112 base::AutoLock auto_lock(lock_); | 
| 119 if (!running_) { | 113 if (!running_) { | 
| 120 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; | 114 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; | 
| 121 return; | 115 return; | 
| 122 } | 116 } | 
| 123 | 117 | 
| 124 task_runner_->PostTask( | 118 task_runner_->PostTask( | 
| 125 FROM_HERE, | 119 FROM_HERE, | 
| 126 base::Bind(&Pipeline::SeekTask, base::Unretained(this), time, seek_cb)); | 120 base::Bind( | 
| 121 &Pipeline::SeekTask, weak_factory_.GetWeakPtr(), time, seek_cb)); | |
| 127 } | 122 } | 
| 128 | 123 | 
| 129 bool Pipeline::IsRunning() const { | 124 bool Pipeline::IsRunning() const { | 
| 130 base::AutoLock auto_lock(lock_); | 125 base::AutoLock auto_lock(lock_); | 
| 131 return running_; | 126 return running_; | 
| 132 } | 127 } | 
| 133 | 128 | 
| 134 float Pipeline::GetPlaybackRate() const { | 129 float Pipeline::GetPlaybackRate() const { | 
| 135 base::AutoLock auto_lock(lock_); | 130 base::AutoLock auto_lock(lock_); | 
| 136 return playback_rate_; | 131 return playback_rate_; | 
| 137 } | 132 } | 
| 138 | 133 | 
| 139 void Pipeline::SetPlaybackRate(float playback_rate) { | 134 void Pipeline::SetPlaybackRate(float playback_rate) { | 
| 140 if (playback_rate < 0.0f) | 135 if (playback_rate < 0.0f) | 
| 141 return; | 136 return; | 
| 142 | 137 | 
| 143 base::AutoLock auto_lock(lock_); | 138 base::AutoLock auto_lock(lock_); | 
| 144 playback_rate_ = playback_rate; | 139 playback_rate_ = playback_rate; | 
| 145 if (running_) { | 140 if (running_) { | 
| 146 task_runner_->PostTask(FROM_HERE, | 141 task_runner_->PostTask(FROM_HERE, | 
| 147 base::Bind(&Pipeline::PlaybackRateChangedTask, | 142 base::Bind(&Pipeline::PlaybackRateChangedTask, | 
| 148 base::Unretained(this), | 143 weak_factory_.GetWeakPtr(), | 
| 149 playback_rate)); | 144 playback_rate)); | 
| 150 } | 145 } | 
| 151 } | 146 } | 
| 152 | 147 | 
| 153 float Pipeline::GetVolume() const { | 148 float Pipeline::GetVolume() const { | 
| 154 base::AutoLock auto_lock(lock_); | 149 base::AutoLock auto_lock(lock_); | 
| 155 return volume_; | 150 return volume_; | 
| 156 } | 151 } | 
| 157 | 152 | 
| 158 void Pipeline::SetVolume(float volume) { | 153 void Pipeline::SetVolume(float volume) { | 
| 159 if (volume < 0.0f || volume > 1.0f) | 154 if (volume < 0.0f || volume > 1.0f) | 
| 160 return; | 155 return; | 
| 161 | 156 | 
| 162 base::AutoLock auto_lock(lock_); | 157 base::AutoLock auto_lock(lock_); | 
| 163 volume_ = volume; | 158 volume_ = volume; | 
| 164 if (running_) { | 159 if (running_) { | 
| 165 task_runner_->PostTask( | 160 task_runner_->PostTask( | 
| 166 FROM_HERE, | 161 FROM_HERE, | 
| 167 base::Bind( | 162 base::Bind( | 
| 168 &Pipeline::VolumeChangedTask, base::Unretained(this), volume)); | 163 &Pipeline::VolumeChangedTask, weak_factory_.GetWeakPtr(), volume)); | 
| 169 } | 164 } | 
| 170 } | 165 } | 
| 171 | 166 | 
| 172 TimeDelta Pipeline::GetMediaTime() const { | 167 TimeDelta Pipeline::GetMediaTime() const { | 
| 173 base::AutoLock auto_lock(lock_); | 168 base::AutoLock auto_lock(lock_); | 
| 174 return std::min(interpolator_->GetInterpolatedTime(), duration_); | 169 return std::min(interpolator_->GetInterpolatedTime(), duration_); | 
| 175 } | 170 } | 
| 176 | 171 | 
| 177 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { | 172 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const { | 
| 178 base::AutoLock auto_lock(lock_); | 173 base::AutoLock auto_lock(lock_); | 
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 | 257 | 
| 263 case kPlaying: | 258 case kPlaying: | 
| 264 case kStopping: | 259 case kStopping: | 
| 265 case kStopped: | 260 case kStopped: | 
| 266 break; | 261 break; | 
| 267 } | 262 } | 
| 268 NOTREACHED() << "State has no transition: " << state_; | 263 NOTREACHED() << "State has no transition: " << state_; | 
| 269 return state_; | 264 return state_; | 
| 270 } | 265 } | 
| 271 | 266 | 
| 272 // The use of base::Unretained(this) in the following 3 functions is safe | |
| 273 // because these functions are called by the Demuxer directly, before the stop | |
| 274 // callback is posted by the Demuxer. So the posted tasks will always be | |
| 275 // executed before the stop callback is executed, and hence before the Pipeline | |
| 276 // is destructed. | |
| 277 | |
| 278 void Pipeline::OnDemuxerError(PipelineStatus error) { | 267 void Pipeline::OnDemuxerError(PipelineStatus error) { | 
| 279 task_runner_->PostTask(FROM_HERE, | 268 task_runner_->PostTask(FROM_HERE, | 
| 280 base::Bind(&Pipeline::ErrorChangedTask, | 269 base::Bind(&Pipeline::ErrorChangedTask, | 
| 281 base::Unretained(this), | 270 weak_factory_.GetWeakPtr(), | 
| 282 error)); | 271 error)); | 
| 283 } | 272 } | 
| 284 | 273 | 
| 285 void Pipeline::AddTextStream(DemuxerStream* text_stream, | 274 void Pipeline::AddTextStream(DemuxerStream* text_stream, | 
| 286 const TextTrackConfig& config) { | 275 const TextTrackConfig& config) { | 
| 287 task_runner_->PostTask(FROM_HERE, | 276 task_runner_->PostTask(FROM_HERE, | 
| 288 base::Bind(&Pipeline::AddTextStreamTask, | 277 base::Bind(&Pipeline::AddTextStreamTask, | 
| 289 base::Unretained(this), | 278 weak_factory_.GetWeakPtr(), | 
| 290 text_stream, | 279 text_stream, | 
| 291 config)); | 280 config)); | 
| 292 } | 281 } | 
| 293 | 282 | 
| 294 void Pipeline::RemoveTextStream(DemuxerStream* text_stream) { | 283 void Pipeline::RemoveTextStream(DemuxerStream* text_stream) { | 
| 295 task_runner_->PostTask(FROM_HERE, | 284 task_runner_->PostTask(FROM_HERE, | 
| 296 base::Bind(&Pipeline::RemoveTextStreamTask, | 285 base::Bind(&Pipeline::RemoveTextStreamTask, | 
| 297 base::Unretained(this), | 286 weak_factory_.GetWeakPtr(), | 
| 298 text_stream)); | 287 text_stream)); | 
| 299 } | 288 } | 
| 300 | 289 | 
| 301 void Pipeline::OnError(PipelineStatus error) { | 290 void Pipeline::OnError(PipelineStatus error) { | 
| 302 DCHECK(task_runner_->BelongsToCurrentThread()); | 291 DCHECK(task_runner_->BelongsToCurrentThread()); | 
| 303 DCHECK(IsRunning()); | 292 DCHECK(IsRunning()); | 
| 304 DCHECK_NE(PIPELINE_OK, error); | 293 DCHECK_NE(PIPELINE_OK, error); | 
| 305 VLOG(1) << "Media pipeline error: " << error; | 294 VLOG(1) << "Media pipeline error: " << error; | 
| 306 | 295 | 
| 307 task_runner_->PostTask(FROM_HERE, base::Bind( | 296 task_runner_->PostTask(FROM_HERE, base::Bind( | 
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 551 demuxer_ = NULL; | 540 demuxer_ = NULL; | 
| 552 | 541 | 
| 553 // If we stop during initialization/seeking we want to run |seek_cb_| | 542 // If we stop during initialization/seeking we want to run |seek_cb_| | 
| 554 // followed by |stop_cb_| so we don't leave outstanding callbacks around. | 543 // followed by |stop_cb_| so we don't leave outstanding callbacks around. | 
| 555 if (!seek_cb_.is_null()) { | 544 if (!seek_cb_.is_null()) { | 
| 556 base::ResetAndReturn(&seek_cb_).Run(status_); | 545 base::ResetAndReturn(&seek_cb_).Run(status_); | 
| 557 error_cb_.Reset(); | 546 error_cb_.Reset(); | 
| 558 } | 547 } | 
| 559 if (!stop_cb_.is_null()) { | 548 if (!stop_cb_.is_null()) { | 
| 560 error_cb_.Reset(); | 549 error_cb_.Reset(); | 
| 550 | |
| 551 // Invalid all weak pointers so it's safe to destroy |this| on the render | |
| 552 // main thread. | |
| 553 weak_factory_.InvalidateWeakPtrs(); | |
| 
xhwang
2014/08/05 20:44:47
Move this down here because OnStopComplete() can a
 | |
| 554 | |
| 561 base::ResetAndReturn(&stop_cb_).Run(); | 555 base::ResetAndReturn(&stop_cb_).Run(); | 
| 562 | 556 | 
| 563 // NOTE: pipeline may be deleted at this point in time as a result of | 557 // NOTE: pipeline may be deleted at this point in time as a result of | 
| 564 // executing |stop_cb_|. | 558 // executing |stop_cb_|. | 
| 565 return; | 559 return; | 
| 566 } | 560 } | 
| 567 if (!error_cb_.is_null()) { | 561 if (!error_cb_.is_null()) { | 
| 568 DCHECK_NE(status_, PIPELINE_OK); | 562 DCHECK_NE(status_, PIPELINE_OK); | 
| 569 base::ResetAndReturn(&error_cb_).Run(status_); | 563 base::ResetAndReturn(&error_cb_).Run(status_); | 
| 570 } | 564 } | 
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 917 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 911 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 
| 918 lock_.AssertAcquired(); | 912 lock_.AssertAcquired(); | 
| 919 if (interpolation_state_ != INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE) | 913 if (interpolation_state_ != INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE) | 
| 920 return; | 914 return; | 
| 921 | 915 | 
| 922 interpolation_state_ = INTERPOLATION_STARTED; | 916 interpolation_state_ = INTERPOLATION_STARTED; | 
| 923 interpolator_->StartInterpolating(); | 917 interpolator_->StartInterpolating(); | 
| 924 } | 918 } | 
| 925 | 919 | 
| 926 } // namespace media | 920 } // namespace media | 
| OLD | NEW |