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 |