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_impl.h" | 5 #include "media/base/pipeline_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/callback.h" | 12 #include "base/callback.h" |
13 #include "base/callback_helpers.h" | 13 #include "base/callback_helpers.h" |
14 #include "base/command_line.h" | 14 #include "base/command_line.h" |
15 #include "base/compiler_specific.h" | 15 #include "base/compiler_specific.h" |
16 #include "base/location.h" | 16 #include "base/location.h" |
17 #include "base/memory/ptr_util.h" | 17 #include "base/memory/ptr_util.h" |
18 #include "base/metrics/histogram.h" | 18 #include "base/metrics/histogram.h" |
19 #include "base/single_thread_task_runner.h" | 19 #include "base/single_thread_task_runner.h" |
20 #include "base/stl_util.h" | 20 #include "base/stl_util.h" |
21 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
22 #include "base/strings/string_util.h" | 22 #include "base/strings/string_util.h" |
23 #include "base/synchronization/condition_variable.h" | 23 #include "base/synchronization/waitable_event.h" |
24 #include "base/thread_task_runner_handle.h" | |
25 #include "media/base/bind_to_current_loop.h" | |
24 #include "media/base/media_log.h" | 26 #include "media/base/media_log.h" |
25 #include "media/base/media_switches.h" | 27 #include "media/base/media_switches.h" |
26 #include "media/base/renderer.h" | 28 #include "media/base/renderer.h" |
27 #include "media/base/text_renderer.h" | 29 #include "media/base/text_renderer.h" |
28 #include "media/base/text_track_config.h" | 30 #include "media/base/text_track_config.h" |
29 #include "media/base/timestamp_constants.h" | 31 #include "media/base/timestamp_constants.h" |
30 #include "media/base/video_decoder_config.h" | 32 #include "media/base/video_decoder_config.h" |
31 | 33 |
32 using base::TimeDelta; | 34 using base::TimeDelta; |
33 | 35 |
34 namespace media { | 36 namespace media { |
35 | 37 |
36 PipelineImpl::PipelineImpl( | 38 PipelineImpl::PipelineImpl( |
37 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 39 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
38 MediaLog* media_log) | 40 MediaLog* media_log) |
39 : task_runner_(task_runner), | 41 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
sandersd (OOO until July 31)
2016/05/02 18:37:47
Perhaps this should be explicitly passed, since |c
xhwang
2016/05/02 20:58:35
+1
alokp
2016/05/02 22:25:17
I disagree. IMO passing a task runner makes sense
sandersd (OOO until July 31)
2016/05/02 22:45:52
This is reasonable, although I would feel better a
alokp
2016/05/02 23:00:59
I agree. In fact initial patches passed client in
sandersd (OOO until July 31)
2016/05/02 23:20:47
That's true, but the reason to do so was also remo
alokp
2016/05/03 05:22:18
How do you propose doing that? It will be weird to
sandersd (OOO until July 31)
2016/05/03 19:28:55
A fair point, I'll accept that.
alokp
2016/05/03 20:15:23
One way to add Client in the base class interface
| |
42 media_task_runner_(media_task_runner), | |
40 media_log_(media_log), | 43 media_log_(media_log), |
41 running_(false), | 44 running_(false), |
42 did_loading_progress_(false), | 45 did_loading_progress_(false), |
43 volume_(1.0f), | 46 volume_(1.0f), |
44 playback_rate_(0.0), | 47 playback_rate_(0.0), |
45 status_(PIPELINE_OK), | 48 status_(PIPELINE_OK), |
46 state_(kCreated), | 49 state_(kCreated), |
47 suspend_timestamp_(kNoTimestamp()), | 50 suspend_timestamp_(kNoTimestamp()), |
48 renderer_ended_(false), | 51 renderer_ended_(false), |
49 text_renderer_ended_(false), | 52 text_renderer_ended_(false), |
50 demuxer_(NULL), | 53 demuxer_(NULL), |
54 client_(nullptr), | |
51 cdm_context_(nullptr), | 55 cdm_context_(nullptr), |
52 weak_factory_(this) { | 56 weak_factory_(this) { |
57 DVLOG(2) << __FUNCTION__; | |
53 weak_this_ = weak_factory_.GetWeakPtr(); | 58 weak_this_ = weak_factory_.GetWeakPtr(); |
54 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 59 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
55 } | 60 } |
56 | 61 |
57 PipelineImpl::~PipelineImpl() { | 62 PipelineImpl::~PipelineImpl() { |
58 DCHECK(thread_checker_.CalledOnValidThread()) | 63 DVLOG(2) << __FUNCTION__; |
64 DCHECK(main_task_runner_->BelongsToCurrentThread()) | |
59 << "Pipeline must be destroyed on same thread that created it"; | 65 << "Pipeline must be destroyed on same thread that created it"; |
60 DCHECK(!running_) << "Stop() must complete before destroying object"; | 66 DCHECK(!running_) << "Stop() must complete before destroying object"; |
61 DCHECK(stop_cb_.is_null()); | |
62 DCHECK(seek_cb_.is_null()); | 67 DCHECK(seek_cb_.is_null()); |
63 } | 68 } |
64 | 69 |
65 void PipelineImpl::Start(Demuxer* demuxer, | 70 void PipelineImpl::Start(Demuxer* demuxer, |
66 std::unique_ptr<Renderer> renderer, | 71 std::unique_ptr<Renderer> renderer, |
67 const base::Closure& ended_cb, | 72 Client* client, |
68 const PipelineStatusCB& error_cb, | 73 const PipelineStatusCB& seek_cb) { |
69 const PipelineStatusCB& seek_cb, | 74 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
70 const PipelineMetadataCB& metadata_cb, | 75 DCHECK(client); |
71 const BufferingStateCB& buffering_state_cb, | |
72 const base::Closure& duration_change_cb, | |
73 const AddTextTrackCB& add_text_track_cb, | |
74 const base::Closure& waiting_for_decryption_key_cb) { | |
75 DCHECK(!ended_cb.is_null()); | |
76 DCHECK(!error_cb.is_null()); | |
77 DCHECK(!seek_cb.is_null()); | 76 DCHECK(!seek_cb.is_null()); |
78 DCHECK(!metadata_cb.is_null()); | |
79 DCHECK(!buffering_state_cb.is_null()); | |
80 | 77 |
81 base::AutoLock auto_lock(lock_); | 78 base::AutoLock auto_lock(lock_); |
82 CHECK(!running_) << "Media pipeline is already running"; | 79 CHECK(!running_) << "Media pipeline is already running"; |
83 running_ = true; | 80 running_ = true; |
84 | 81 |
85 demuxer_ = demuxer; | 82 demuxer_ = demuxer; |
86 renderer_ = std::move(renderer); | 83 renderer_ = std::move(renderer); |
87 ended_cb_ = ended_cb; | 84 client_ = client; |
88 error_cb_ = error_cb; | 85 seek_cb_ = media::BindToCurrentLoop(seek_cb); |
89 seek_cb_ = seek_cb; | 86 media_task_runner_->PostTask( |
90 metadata_cb_ = metadata_cb; | 87 FROM_HERE, base::Bind(&PipelineImpl::StartTask, weak_this_)); |
91 buffering_state_cb_ = buffering_state_cb; | |
92 duration_change_cb_ = duration_change_cb; | |
93 add_text_track_cb_ = add_text_track_cb; | |
94 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; | |
95 | |
96 task_runner_->PostTask(FROM_HERE, | |
97 base::Bind(&PipelineImpl::StartTask, weak_this_)); | |
98 } | 88 } |
99 | 89 |
100 void PipelineImpl::Stop(const base::Closure& stop_cb) { | 90 void PipelineImpl::Stop() { |
91 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
101 DVLOG(2) << __FUNCTION__; | 92 DVLOG(2) << __FUNCTION__; |
102 task_runner_->PostTask( | 93 |
103 FROM_HERE, base::Bind(&PipelineImpl::StopTask, weak_this_, stop_cb)); | 94 if (media_task_runner_ != main_task_runner_) { |
95 // This path is executed by production code where the two task runners - | |
96 // main and media - live on different threads. | |
97 base::WaitableEvent waiter(false, false); | |
98 media_task_runner_->PostTask( | |
99 FROM_HERE, base::Bind(&PipelineImpl::StopTask, weak_this_, &waiter)); | |
sandersd (OOO until July 31)
2016/05/02 18:37:47
I'm not a fan of this pattern; it was bad in WMPI
xhwang
2016/05/02 20:58:35
We already have a waiter in WMPI when Pipeline::St
alokp
2016/05/02 22:25:17
This is not a new waiter. The one in WMPI is simpl
| |
100 waiter.Wait(); | |
101 } else { | |
102 // This path is executed by unittests that share media and main threads. | |
103 StopTask(nullptr); | |
104 } | |
105 client_ = nullptr; | |
104 } | 106 } |
105 | 107 |
106 void PipelineImpl::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { | 108 void PipelineImpl::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { |
107 base::AutoLock auto_lock(lock_); | 109 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
108 if (!running_) { | 110 |
111 if (!IsRunning()) { | |
109 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; | 112 DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek()."; |
110 return; | 113 return; |
111 } | 114 } |
112 | 115 |
113 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SeekTask, | 116 media_task_runner_->PostTask( |
114 weak_this_, time, seek_cb)); | 117 FROM_HERE, base::Bind(&PipelineImpl::SeekTask, weak_this_, time, |
118 media::BindToCurrentLoop(seek_cb))); | |
115 } | 119 } |
116 | 120 |
117 bool PipelineImpl::IsRunning() const { | 121 bool PipelineImpl::IsRunning() const { |
122 // TODO(alokp): Add thread DCHECK after removing the internal usage on | |
123 // media thread. | |
118 base::AutoLock auto_lock(lock_); | 124 base::AutoLock auto_lock(lock_); |
119 return running_; | 125 return running_; |
120 } | 126 } |
121 | 127 |
122 double PipelineImpl::GetPlaybackRate() const { | 128 double PipelineImpl::GetPlaybackRate() const { |
129 // TODO(alokp): Add thread DCHECK after removing the internal usage on | |
130 // media thread. | |
123 base::AutoLock auto_lock(lock_); | 131 base::AutoLock auto_lock(lock_); |
124 return playback_rate_; | 132 return playback_rate_; |
125 } | 133 } |
126 | 134 |
127 void PipelineImpl::SetPlaybackRate(double playback_rate) { | 135 void PipelineImpl::SetPlaybackRate(double playback_rate) { |
136 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
137 | |
128 if (playback_rate < 0.0) | 138 if (playback_rate < 0.0) |
129 return; | 139 return; |
130 | 140 |
131 base::AutoLock auto_lock(lock_); | 141 base::AutoLock auto_lock(lock_); |
132 playback_rate_ = playback_rate; | 142 playback_rate_ = playback_rate; |
133 if (running_) { | 143 if (running_) { |
134 task_runner_->PostTask(FROM_HERE, | 144 media_task_runner_->PostTask( |
135 base::Bind(&PipelineImpl::PlaybackRateChangedTask, | 145 FROM_HERE, base::Bind(&PipelineImpl::PlaybackRateChangedTask, |
136 weak_this_, playback_rate)); | 146 weak_this_, playback_rate)); |
137 } | 147 } |
138 } | 148 } |
139 | 149 |
140 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { | 150 void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) { |
141 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SuspendTask, | 151 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
142 weak_this_, suspend_cb)); | 152 |
153 media_task_runner_->PostTask( | |
154 FROM_HERE, base::Bind(&PipelineImpl::SuspendTask, weak_this_, | |
155 media::BindToCurrentLoop(suspend_cb))); | |
143 } | 156 } |
144 | 157 |
145 void PipelineImpl::Resume(std::unique_ptr<Renderer> renderer, | 158 void PipelineImpl::Resume(std::unique_ptr<Renderer> renderer, |
146 base::TimeDelta timestamp, | 159 base::TimeDelta timestamp, |
147 const PipelineStatusCB& seek_cb) { | 160 const PipelineStatusCB& seek_cb) { |
148 task_runner_->PostTask( | 161 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
149 FROM_HERE, base::Bind(&PipelineImpl::ResumeTask, weak_this_, | 162 |
150 base::Passed(&renderer), timestamp, seek_cb)); | 163 media_task_runner_->PostTask( |
164 FROM_HERE, | |
165 base::Bind(&PipelineImpl::ResumeTask, weak_this_, base::Passed(&renderer), | |
166 timestamp, media::BindToCurrentLoop(seek_cb))); | |
151 } | 167 } |
152 | 168 |
153 float PipelineImpl::GetVolume() const { | 169 float PipelineImpl::GetVolume() const { |
170 // TODO(alokp): Add thread DCHECK after removing the internal usage on | |
171 // media thread. | |
154 base::AutoLock auto_lock(lock_); | 172 base::AutoLock auto_lock(lock_); |
155 return volume_; | 173 return volume_; |
156 } | 174 } |
157 | 175 |
158 void PipelineImpl::SetVolume(float volume) { | 176 void PipelineImpl::SetVolume(float volume) { |
177 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
178 | |
159 if (volume < 0.0f || volume > 1.0f) | 179 if (volume < 0.0f || volume > 1.0f) |
160 return; | 180 return; |
161 | 181 |
162 base::AutoLock auto_lock(lock_); | 182 base::AutoLock auto_lock(lock_); |
163 volume_ = volume; | 183 volume_ = volume; |
164 if (running_) { | 184 if (running_) { |
165 task_runner_->PostTask( | 185 media_task_runner_->PostTask( |
166 FROM_HERE, | 186 FROM_HERE, |
167 base::Bind(&PipelineImpl::VolumeChangedTask, weak_this_, volume)); | 187 base::Bind(&PipelineImpl::VolumeChangedTask, weak_this_, volume)); |
168 } | 188 } |
169 } | 189 } |
170 | 190 |
171 TimeDelta PipelineImpl::GetMediaTime() const { | 191 TimeDelta PipelineImpl::GetMediaTime() const { |
192 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
193 | |
172 base::AutoLock auto_lock(lock_); | 194 base::AutoLock auto_lock(lock_); |
173 if (suspend_timestamp_ != kNoTimestamp()) | 195 if (suspend_timestamp_ != kNoTimestamp()) |
174 return suspend_timestamp_; | 196 return suspend_timestamp_; |
175 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_) | 197 return renderer_ ? std::min(renderer_->GetMediaTime(), duration_) |
176 : TimeDelta(); | 198 : TimeDelta(); |
177 } | 199 } |
178 | 200 |
179 Ranges<TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { | 201 Ranges<TimeDelta> PipelineImpl::GetBufferedTimeRanges() const { |
202 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
203 | |
180 base::AutoLock auto_lock(lock_); | 204 base::AutoLock auto_lock(lock_); |
181 return buffered_time_ranges_; | 205 return buffered_time_ranges_; |
182 } | 206 } |
183 | 207 |
184 TimeDelta PipelineImpl::GetMediaDuration() const { | 208 TimeDelta PipelineImpl::GetMediaDuration() const { |
209 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
210 | |
185 base::AutoLock auto_lock(lock_); | 211 base::AutoLock auto_lock(lock_); |
186 return duration_; | 212 return duration_; |
187 } | 213 } |
188 | 214 |
189 bool PipelineImpl::DidLoadingProgress() { | 215 bool PipelineImpl::DidLoadingProgress() { |
216 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
217 | |
190 base::AutoLock auto_lock(lock_); | 218 base::AutoLock auto_lock(lock_); |
191 bool ret = did_loading_progress_; | 219 bool ret = did_loading_progress_; |
192 did_loading_progress_ = false; | 220 did_loading_progress_ = false; |
193 return ret; | 221 return ret; |
194 } | 222 } |
195 | 223 |
196 PipelineStatistics PipelineImpl::GetStatistics() const { | 224 PipelineStatistics PipelineImpl::GetStatistics() const { |
225 // TODO(alokp): Add thread DCHECK after removing the internal usage on | |
226 // media thread. | |
197 base::AutoLock auto_lock(lock_); | 227 base::AutoLock auto_lock(lock_); |
198 return statistics_; | 228 return statistics_; |
199 } | 229 } |
200 | 230 |
201 void PipelineImpl::SetCdm(CdmContext* cdm_context, | 231 void PipelineImpl::SetCdm(CdmContext* cdm_context, |
202 const CdmAttachedCB& cdm_attached_cb) { | 232 const CdmAttachedCB& cdm_attached_cb) { |
203 task_runner_->PostTask( | 233 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
234 | |
235 media_task_runner_->PostTask( | |
204 FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask, weak_this_, cdm_context, | 236 FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask, weak_this_, cdm_context, |
205 cdm_attached_cb)); | 237 cdm_attached_cb)); |
206 } | 238 } |
207 | 239 |
208 void PipelineImpl::SetErrorForTesting(PipelineStatus status) { | 240 void PipelineImpl::SetErrorForTesting(PipelineStatus status) { |
209 OnError(status); | 241 OnError(status); |
210 } | 242 } |
211 | 243 |
212 bool PipelineImpl::HasWeakPtrsForTesting() const { | 244 bool PipelineImpl::HasWeakPtrsForTesting() const { |
213 DCHECK(task_runner_->BelongsToCurrentThread()); | 245 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
214 return weak_factory_.HasWeakPtrs(); | 246 return weak_factory_.HasWeakPtrs(); |
215 } | 247 } |
216 | 248 |
217 void PipelineImpl::SetState(State next_state) { | 249 void PipelineImpl::SetState(State next_state) { |
250 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
218 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); | 251 DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state); |
219 | 252 |
220 state_ = next_state; | 253 state_ = next_state; |
221 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); | 254 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state)); |
222 } | 255 } |
223 | 256 |
224 #define RETURN_STRING(state) \ | 257 #define RETURN_STRING(state) \ |
225 case state: \ | 258 case state: \ |
226 return #state; | 259 return #state; |
227 | 260 |
(...skipping 10 matching lines...) Expand all Loading... | |
238 RETURN_STRING(kSuspended); | 271 RETURN_STRING(kSuspended); |
239 RETURN_STRING(kResuming); | 272 RETURN_STRING(kResuming); |
240 } | 273 } |
241 NOTREACHED(); | 274 NOTREACHED(); |
242 return "INVALID"; | 275 return "INVALID"; |
243 } | 276 } |
244 | 277 |
245 #undef RETURN_STRING | 278 #undef RETURN_STRING |
246 | 279 |
247 PipelineImpl::State PipelineImpl::GetNextState() const { | 280 PipelineImpl::State PipelineImpl::GetNextState() const { |
248 DCHECK(task_runner_->BelongsToCurrentThread()); | 281 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
249 DCHECK(stop_cb_.is_null()) << "State transitions don't happen when stopping"; | |
250 DCHECK_EQ(status_, PIPELINE_OK) | 282 DCHECK_EQ(status_, PIPELINE_OK) |
251 << "State transitions don't happen when there's an error: " << status_; | 283 << "State transitions don't happen when there's an error: " << status_; |
252 | 284 |
253 switch (state_) { | 285 switch (state_) { |
254 case kCreated: | 286 case kCreated: |
255 return kInitDemuxer; | 287 return kInitDemuxer; |
256 | 288 |
257 case kInitDemuxer: | 289 case kInitDemuxer: |
258 return kInitRenderer; | 290 return kInitRenderer; |
259 | 291 |
(...skipping 13 matching lines...) Expand all Loading... | |
273 case kPlaying: | 305 case kPlaying: |
274 case kStopping: | 306 case kStopping: |
275 case kStopped: | 307 case kStopped: |
276 break; | 308 break; |
277 } | 309 } |
278 NOTREACHED() << "State has no transition: " << state_; | 310 NOTREACHED() << "State has no transition: " << state_; |
279 return state_; | 311 return state_; |
280 } | 312 } |
281 | 313 |
282 void PipelineImpl::OnDemuxerError(PipelineStatus error) { | 314 void PipelineImpl::OnDemuxerError(PipelineStatus error) { |
283 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::ErrorChangedTask, | 315 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer |
284 weak_this_, error)); | 316 // implementations call DemuxerHost on the media thread. |
317 media_task_runner_->PostTask( | |
318 FROM_HERE, | |
319 base::Bind(&PipelineImpl::ErrorChangedTask, weak_this_, error)); | |
285 } | 320 } |
286 | 321 |
287 void PipelineImpl::AddTextStream(DemuxerStream* text_stream, | 322 void PipelineImpl::AddTextStream(DemuxerStream* text_stream, |
288 const TextTrackConfig& config) { | 323 const TextTrackConfig& config) { |
289 task_runner_->PostTask( | 324 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer |
325 // implementations call DemuxerHost on the media thread. | |
326 media_task_runner_->PostTask( | |
290 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, weak_this_, | 327 FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask, weak_this_, |
291 text_stream, config)); | 328 text_stream, config)); |
292 } | 329 } |
293 | 330 |
294 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) { | 331 void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) { |
295 task_runner_->PostTask( | 332 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer |
333 // implementations call DemuxerHost on the media thread. | |
334 media_task_runner_->PostTask( | |
296 FROM_HERE, | 335 FROM_HERE, |
297 base::Bind(&PipelineImpl::RemoveTextStreamTask, weak_this_, text_stream)); | 336 base::Bind(&PipelineImpl::RemoveTextStreamTask, weak_this_, text_stream)); |
298 } | 337 } |
299 | 338 |
300 void PipelineImpl::OnError(PipelineStatus error) { | 339 void PipelineImpl::OnError(PipelineStatus error) { |
301 DCHECK(task_runner_->BelongsToCurrentThread()); | 340 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
302 DCHECK(IsRunning()); | 341 DCHECK(IsRunning()); |
303 DCHECK_NE(PIPELINE_OK, error); | 342 DCHECK_NE(PIPELINE_OK, error); |
304 VLOG(1) << "Media pipeline error: " << error; | 343 VLOG(1) << "Media pipeline error: " << error; |
305 | 344 |
306 task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::ErrorChangedTask, | 345 media_task_runner_->PostTask( |
307 weak_this_, error)); | 346 FROM_HERE, |
347 base::Bind(&PipelineImpl::ErrorChangedTask, weak_this_, error)); | |
308 } | 348 } |
309 | 349 |
310 void PipelineImpl::SetDuration(TimeDelta duration) { | 350 void PipelineImpl::SetDuration(TimeDelta duration) { |
351 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer | |
352 // implementations call DemuxerHost on the media thread. | |
311 DCHECK(IsRunning()); | 353 DCHECK(IsRunning()); |
312 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, | 354 media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET, |
313 "duration", duration)); | 355 "duration", duration)); |
314 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 356 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
315 | 357 |
316 base::AutoLock auto_lock(lock_); | 358 base::AutoLock auto_lock(lock_); |
317 duration_ = duration; | 359 duration_ = duration; |
318 if (!duration_change_cb_.is_null()) | 360 main_task_runner_->PostTask(FROM_HERE, |
319 duration_change_cb_.Run(); | 361 base::Bind(&Pipeline::Client::OnDurationChange, |
362 base::Unretained(client_))); | |
xhwang
2016/05/02 20:58:35
Could you explain why base::Unretained is safe her
alokp
2016/05/02 22:25:17
It is not safe. The latest patch uses weak pointer
| |
320 } | 363 } |
321 | 364 |
322 void PipelineImpl::StateTransitionTask(PipelineStatus status) { | 365 void PipelineImpl::StateTransitionTask(PipelineStatus status) { |
323 DCHECK(task_runner_->BelongsToCurrentThread()); | 366 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
324 | 367 |
325 // No-op any state transitions if we're stopping. | 368 // No-op any state transitions if we're stopping. |
326 if (state_ == kStopping || state_ == kStopped) | 369 if (state_ == kStopping || state_ == kStopped) |
327 return; | 370 return; |
328 | 371 |
329 // Preserve existing abnormal status, otherwise update based on the result of | 372 // Report error from the previous operation. |
330 // the previous operation. | 373 if (status != PIPELINE_OK) { |
331 status_ = (status_ != PIPELINE_OK ? status_ : status); | 374 ErrorChangedTask(status); |
332 | |
333 if (status_ != PIPELINE_OK) { | |
334 ErrorChangedTask(status_); | |
335 return; | 375 return; |
336 } | 376 } |
337 | 377 |
338 // Guard against accidentally clearing |pending_callbacks_| for states that | 378 // Guard against accidentally clearing |pending_callbacks_| for states that |
339 // use it as well as states that should not be using it. | 379 // use it as well as states that should not be using it. |
340 DCHECK_EQ(pending_callbacks_.get() != NULL, | 380 DCHECK_EQ(pending_callbacks_.get() != NULL, |
341 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); | 381 state_ == kSeeking || state_ == kSuspending || state_ == kResuming); |
342 | 382 |
343 pending_callbacks_.reset(); | 383 pending_callbacks_.reset(); |
344 | 384 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
397 } | 437 } |
398 } | 438 } |
399 | 439 |
400 // Note that the usage of base::Unretained() with the renderers is considered | 440 // Note that the usage of base::Unretained() with the renderers is considered |
401 // safe as they are owned by |pending_callbacks_| and share the same lifetime. | 441 // safe as they are owned by |pending_callbacks_| and share the same lifetime. |
402 // | 442 // |
403 // That being said, deleting the renderers while keeping |pending_callbacks_| | 443 // That being said, deleting the renderers while keeping |pending_callbacks_| |
404 // running on the media thread would result in crashes. | 444 // running on the media thread would result in crashes. |
405 void PipelineImpl::DoSeek(TimeDelta seek_timestamp, | 445 void PipelineImpl::DoSeek(TimeDelta seek_timestamp, |
406 const PipelineStatusCB& done_cb) { | 446 const PipelineStatusCB& done_cb) { |
407 DCHECK(task_runner_->BelongsToCurrentThread()); | 447 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
408 DCHECK(!pending_callbacks_.get()); | 448 DCHECK(!pending_callbacks_.get()); |
409 DCHECK_EQ(state_, kSeeking); | 449 DCHECK_EQ(state_, kSeeking); |
410 SerialRunner::Queue bound_fns; | 450 SerialRunner::Queue bound_fns; |
411 | 451 |
412 // Pause. | 452 // Pause. |
413 if (text_renderer_) { | 453 if (text_renderer_) { |
414 bound_fns.Push(base::Bind(&TextRenderer::Pause, | 454 bound_fns.Push(base::Bind(&TextRenderer::Pause, |
415 base::Unretained(text_renderer_.get()))); | 455 base::Unretained(text_renderer_.get()))); |
416 } | 456 } |
417 | 457 |
418 // Flush. | 458 // Flush. |
419 DCHECK(renderer_); | 459 DCHECK(renderer_); |
420 bound_fns.Push( | 460 bound_fns.Push( |
421 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); | 461 base::Bind(&Renderer::Flush, base::Unretained(renderer_.get()))); |
422 | 462 |
423 if (text_renderer_) { | 463 if (text_renderer_) { |
424 bound_fns.Push(base::Bind(&TextRenderer::Flush, | 464 bound_fns.Push(base::Bind(&TextRenderer::Flush, |
425 base::Unretained(text_renderer_.get()))); | 465 base::Unretained(text_renderer_.get()))); |
426 } | 466 } |
427 | 467 |
428 // Seek demuxer. | 468 // Seek demuxer. |
429 bound_fns.Push( | 469 bound_fns.Push( |
430 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); | 470 base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp)); |
431 | 471 |
432 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); | 472 pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); |
433 } | 473 } |
434 | 474 |
435 void PipelineImpl::DoStop(const PipelineStatusCB& done_cb) { | 475 void PipelineImpl::DoStop(base::WaitableEvent* waiter) { |
436 DVLOG(2) << __FUNCTION__; | 476 DVLOG(2) << __FUNCTION__; |
437 DCHECK(task_runner_->BelongsToCurrentThread()); | 477 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
478 DCHECK_EQ(state_, kStopping); | |
438 DCHECK(!pending_callbacks_.get()); | 479 DCHECK(!pending_callbacks_.get()); |
439 | 480 |
440 // TODO(scherkus): Enforce that Renderer is only called on a single thread, | 481 // TODO(scherkus): Enforce that Renderer is only called on a single thread, |
441 // even for accessing media time http://crbug.com/370634 | 482 // even for accessing media time http://crbug.com/370634 |
442 std::unique_ptr<Renderer> renderer; | 483 std::unique_ptr<Renderer> renderer; |
443 { | 484 { |
444 base::AutoLock auto_lock(lock_); | 485 base::AutoLock auto_lock(lock_); |
445 renderer.swap(renderer_); | 486 renderer.swap(renderer_); |
446 } | 487 } |
447 renderer.reset(); | 488 renderer.reset(); |
448 text_renderer_.reset(); | 489 text_renderer_.reset(); |
449 | 490 |
450 if (demuxer_) { | 491 if (demuxer_) { |
451 demuxer_->Stop(); | 492 demuxer_->Stop(); |
452 demuxer_ = NULL; | 493 demuxer_ = NULL; |
453 } | 494 } |
454 | 495 |
455 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 496 // If we stop during initialization/seeking/suspending we don't want to leave |
456 } | 497 // outstanding callbacks around. The callbacks also do not get run if the |
498 // pipeline is stopped before it had a chance to complete outstanding tasks. | |
499 seek_cb_.Reset(); | |
500 suspend_cb_.Reset(); | |
457 | 501 |
458 void PipelineImpl::OnStopCompleted(PipelineStatus status) { | 502 SetState(kStopped); |
459 DVLOG(2) << __FUNCTION__; | |
460 DCHECK(task_runner_->BelongsToCurrentThread()); | |
461 DCHECK_EQ(state_, kStopping); | |
462 DCHECK(!renderer_); | |
463 DCHECK(!text_renderer_); | |
464 | |
465 { | 503 { |
466 base::AutoLock auto_lock(lock_); | 504 base::AutoLock auto_lock(lock_); |
467 running_ = false; | 505 running_ = false; |
468 } | 506 } |
507 weak_factory_.InvalidateWeakPtrs(); | |
469 | 508 |
470 SetState(kStopped); | 509 if (waiter) |
471 demuxer_ = NULL; | 510 waiter->Signal(); |
472 | |
473 // If we stop during initialization/seeking/suspending we don't want to leave | |
474 // outstanding callbacks around. | |
475 if (!seek_cb_.is_null()) { | |
476 base::ResetAndReturn(&seek_cb_).Run(status_); | |
477 error_cb_.Reset(); | |
478 } | |
479 if (!suspend_cb_.is_null()) { | |
480 base::ResetAndReturn(&suspend_cb_).Run(status_); | |
481 error_cb_.Reset(); | |
482 } | |
483 if (!stop_cb_.is_null()) { | |
484 error_cb_.Reset(); | |
485 | |
486 // Invalid all weak pointers so it's safe to destroy |this| on the render | |
487 // main thread. | |
488 weak_factory_.InvalidateWeakPtrs(); | |
489 | |
490 base::ResetAndReturn(&stop_cb_).Run(); | |
491 | |
492 // NOTE: pipeline may be deleted at this point in time as a result of | |
493 // executing |stop_cb_|. | |
494 return; | |
495 } | |
496 if (!error_cb_.is_null()) { | |
497 DCHECK_NE(status_, PIPELINE_OK); | |
498 base::ResetAndReturn(&error_cb_).Run(status_); | |
499 } | |
500 } | 511 } |
501 | 512 |
502 void PipelineImpl::OnBufferedTimeRangesChanged( | 513 void PipelineImpl::OnBufferedTimeRangesChanged( |
503 const Ranges<base::TimeDelta>& ranges) { | 514 const Ranges<base::TimeDelta>& ranges) { |
515 // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer | |
516 // implementations call DemuxerHost on the media thread. | |
504 base::AutoLock auto_lock(lock_); | 517 base::AutoLock auto_lock(lock_); |
505 buffered_time_ranges_ = ranges; | 518 buffered_time_ranges_ = ranges; |
506 did_loading_progress_ = true; | 519 did_loading_progress_ = true; |
507 } | 520 } |
508 | 521 |
509 // Called from any thread. | 522 // Called from any thread. |
510 void PipelineImpl::OnUpdateStatistics(const PipelineStatistics& stats_delta) { | 523 void PipelineImpl::OnUpdateStatistics(const PipelineStatistics& stats_delta) { |
511 base::AutoLock auto_lock(lock_); | 524 base::AutoLock auto_lock(lock_); |
512 statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded; | 525 statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded; |
513 statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded; | 526 statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded; |
514 statistics_.video_frames_decoded += stats_delta.video_frames_decoded; | 527 statistics_.video_frames_decoded += stats_delta.video_frames_decoded; |
515 statistics_.video_frames_dropped += stats_delta.video_frames_dropped; | 528 statistics_.video_frames_dropped += stats_delta.video_frames_dropped; |
516 statistics_.audio_memory_usage += stats_delta.audio_memory_usage; | 529 statistics_.audio_memory_usage += stats_delta.audio_memory_usage; |
517 statistics_.video_memory_usage += stats_delta.video_memory_usage; | 530 statistics_.video_memory_usage += stats_delta.video_memory_usage; |
518 } | 531 } |
519 | 532 |
533 void PipelineImpl::OnWaitingForDecryptionKey() { | |
534 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
535 | |
536 main_task_runner_->PostTask( | |
537 FROM_HERE, base::Bind(&Pipeline::Client::OnWaitingForDecryptionKey, | |
538 base::Unretained(client_))); | |
539 } | |
540 | |
520 void PipelineImpl::StartTask() { | 541 void PipelineImpl::StartTask() { |
521 DCHECK(task_runner_->BelongsToCurrentThread()); | 542 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
522 | 543 |
523 CHECK_EQ(kCreated, state_) | 544 CHECK_EQ(kCreated, state_) |
524 << "Media pipeline cannot be started more than once"; | 545 << "Media pipeline cannot be started more than once"; |
525 | 546 |
526 text_renderer_ = CreateTextRenderer(); | 547 text_renderer_ = CreateTextRenderer(); |
527 if (text_renderer_) { | 548 if (text_renderer_) { |
528 text_renderer_->Initialize( | 549 text_renderer_->Initialize( |
529 base::Bind(&PipelineImpl::OnTextRendererEnded, weak_this_)); | 550 base::Bind(&PipelineImpl::OnTextRendererEnded, weak_this_)); |
530 } | 551 } |
531 | 552 |
532 StateTransitionTask(PIPELINE_OK); | 553 StateTransitionTask(PIPELINE_OK); |
533 } | 554 } |
534 | 555 |
535 void PipelineImpl::StopTask(const base::Closure& stop_cb) { | 556 void PipelineImpl::StopTask(base::WaitableEvent* waiter) { |
536 DCHECK(task_runner_->BelongsToCurrentThread()); | 557 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
537 DCHECK(stop_cb_.is_null()); | |
538 | 558 |
539 if (state_ == kStopped) { | 559 // We may already be stopping due to a runtime error. |
540 // Invalid all weak pointers so it's safe to destroy |this| on the render | 560 if (state_ == kStopped || state_ == kStopping) { |
541 // main thread. | 561 if (waiter) |
542 weak_factory_.InvalidateWeakPtrs(); | 562 waiter->Signal(); |
543 | |
544 // NOTE: pipeline may be deleted at this point in time as a result of | |
545 // executing |stop_cb|. | |
546 stop_cb.Run(); | |
547 | |
548 return; | 563 return; |
549 } | 564 } |
550 | 565 |
551 stop_cb_ = stop_cb; | |
552 | |
553 // We may already be stopping due to a runtime error. | |
554 if (state_ == kStopping) | |
555 return; | |
556 | |
557 // Do not report statistics if the pipeline is not fully initialized. | 566 // Do not report statistics if the pipeline is not fully initialized. |
558 if (state_ == kSeeking || state_ == kPlaying || state_ == kSuspending || | 567 if (state_ == kSeeking || state_ == kPlaying || state_ == kSuspending || |
559 state_ == kSuspended || state_ == kResuming) { | 568 state_ == kSuspended || state_ == kResuming) { |
560 PipelineStatistics stats = GetStatistics(); | 569 PipelineStatistics stats = GetStatistics(); |
561 if (stats.video_frames_decoded > 0) { | 570 if (stats.video_frames_decoded > 0) { |
562 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", | 571 UMA_HISTOGRAM_COUNTS("Media.DroppedFrameCount", |
563 stats.video_frames_dropped); | 572 stats.video_frames_dropped); |
564 } | 573 } |
565 } | 574 } |
566 | 575 |
567 SetState(kStopping); | 576 SetState(kStopping); |
568 pending_callbacks_.reset(); | 577 pending_callbacks_.reset(); |
569 DoStop(base::Bind(&PipelineImpl::OnStopCompleted, weak_this_)); | 578 DoStop(waiter); |
570 } | 579 } |
571 | 580 |
572 void PipelineImpl::ErrorChangedTask(PipelineStatus error) { | 581 void PipelineImpl::ErrorChangedTask(PipelineStatus error) { |
573 DCHECK(task_runner_->BelongsToCurrentThread()); | 582 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
574 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; | 583 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; |
575 | 584 |
585 // Preserve existing abnormal status. | |
586 if (status_ != PIPELINE_OK) | |
587 return; | |
588 | |
576 // Don't report pipeline error events to the media log here. The embedder will | 589 // Don't report pipeline error events to the media log here. The embedder will |
577 // log this when |error_cb_| is called. If the pipeline is already stopped or | 590 // log this when |error_cb_| is called. If the pipeline is already stopped or |
578 // stopping we also don't want to log any event. In case we are suspending or | 591 // stopping we also don't want to log any event. In case we are suspending or |
579 // suspended, the error may be recoverable, so don't propagate it now, instead | 592 // suspended, the error may be recoverable, so don't propagate it now, instead |
580 // let the subsequent seek during resume propagate it if it's unrecoverable. | 593 // let the subsequent seek during resume propagate it if it's unrecoverable. |
581 | |
582 if (state_ == kStopping || state_ == kStopped || state_ == kSuspending || | 594 if (state_ == kStopping || state_ == kStopped || state_ == kSuspending || |
583 state_ == kSuspended) { | 595 state_ == kSuspended) { |
584 return; | 596 return; |
585 } | 597 } |
586 | 598 |
587 SetState(kStopping); | 599 // Once we enter |kStopping| state, nothing is reported back to the client. |
588 pending_callbacks_.reset(); | 600 // If we encounter an error during initialization/seeking/suspending, |
601 // report the error using the completion callbacks for those tasks. | |
589 status_ = error; | 602 status_ = error; |
603 bool status_reported = false; | |
604 if (!seek_cb_.is_null()) { | |
605 base::ResetAndReturn(&seek_cb_).Run(status_); | |
sandersd (OOO until July 31)
2016/05/02 18:37:47
Are we sure it's safe to drop these from the Stop(
alokp
2016/05/02 22:25:17
It is not possible to call these since Stop is blo
sandersd (OOO until July 31)
2016/05/02 22:45:51
That's fair, but we also can't commit this without
alokp
2016/05/02 23:00:59
PipelineImpl::Seek/Suspend is only called from Pip
sandersd (OOO until July 31)
2016/05/02 23:20:47
PipelineController binds them all to OnPipelineSta
alokp
2016/05/03 05:22:18
Right. I am sorry I do not see a problem there. Ca
sandersd (OOO until July 31)
2016/05/03 19:28:55
I'm not sure if it's a problem, it's probably not,
alokp
2016/05/03 20:15:23
SGTM
| |
606 status_reported = true; | |
607 } | |
608 if (!suspend_cb_.is_null()) { | |
609 base::ResetAndReturn(&suspend_cb_).Run(status_); | |
610 status_reported = true; | |
611 } | |
612 if (!status_reported) { | |
613 DCHECK_NE(status_, PIPELINE_OK); | |
614 main_task_runner_->PostTask(FROM_HERE, | |
615 base::Bind(&Pipeline::Client::OnError, | |
616 base::Unretained(client_), status_)); | |
617 } | |
590 | 618 |
591 DoStop(base::Bind(&PipelineImpl::OnStopCompleted, weak_this_)); | 619 // Stop the pipeline. |
620 StopTask(nullptr); | |
592 } | 621 } |
593 | 622 |
594 void PipelineImpl::PlaybackRateChangedTask(double playback_rate) { | 623 void PipelineImpl::PlaybackRateChangedTask(double playback_rate) { |
595 DCHECK(task_runner_->BelongsToCurrentThread()); | 624 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
596 | 625 |
597 // Playback rate changes are only carried out while playing. | 626 // Playback rate changes are only carried out while playing. |
598 if (state_ != kPlaying) | 627 if (state_ != kPlaying) |
599 return; | 628 return; |
600 | 629 |
601 renderer_->SetPlaybackRate(playback_rate); | 630 renderer_->SetPlaybackRate(playback_rate); |
602 } | 631 } |
603 | 632 |
604 void PipelineImpl::VolumeChangedTask(float volume) { | 633 void PipelineImpl::VolumeChangedTask(float volume) { |
605 DCHECK(task_runner_->BelongsToCurrentThread()); | 634 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
606 | 635 |
607 // Volume changes are only carried out while playing. | 636 // Volume changes are only carried out while playing. |
608 if (state_ != kPlaying) | 637 if (state_ != kPlaying) |
609 return; | 638 return; |
610 | 639 |
611 renderer_->SetVolume(volume); | 640 renderer_->SetVolume(volume); |
612 } | 641 } |
613 | 642 |
614 void PipelineImpl::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { | 643 void PipelineImpl::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
615 DCHECK(task_runner_->BelongsToCurrentThread()); | 644 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
616 DCHECK(stop_cb_.is_null()); | |
617 | 645 |
618 // Suppress seeking if we're not fully started. | 646 // Suppress seeking if we're not fully started. |
619 if (state_ != kPlaying) { | 647 if (state_ != kPlaying) { |
620 DCHECK(state_ == kStopping || state_ == kStopped) | 648 DCHECK(state_ == kStopping || state_ == kStopped) |
621 << "Receive seek in unexpected state: " << state_; | 649 << "Receive seek in unexpected state: " << state_; |
622 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); | 650 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); |
623 return; | 651 return; |
624 } | 652 } |
625 | 653 |
626 DCHECK(seek_cb_.is_null()); | 654 DCHECK(seek_cb_.is_null()); |
627 | 655 |
628 const base::TimeDelta seek_timestamp = | 656 const base::TimeDelta seek_timestamp = |
629 std::max(time, demuxer_->GetStartTime()); | 657 std::max(time, demuxer_->GetStartTime()); |
630 | 658 |
631 SetState(kSeeking); | 659 SetState(kSeeking); |
632 seek_cb_ = seek_cb; | 660 seek_cb_ = seek_cb; |
633 renderer_ended_ = false; | 661 renderer_ended_ = false; |
634 text_renderer_ended_ = false; | 662 text_renderer_ended_ = false; |
635 start_timestamp_ = seek_timestamp; | 663 start_timestamp_ = seek_timestamp; |
636 | 664 |
637 DoSeek(seek_timestamp, | 665 DoSeek(seek_timestamp, |
638 base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); | 666 base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); |
639 } | 667 } |
640 | 668 |
641 void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) { | 669 void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) { |
642 DCHECK(task_runner_->BelongsToCurrentThread()); | 670 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
643 | 671 |
644 // Suppress suspending if we're not playing. | 672 // Suppress suspending if we're not playing. |
645 if (state_ != kPlaying) { | 673 if (state_ != kPlaying) { |
646 DCHECK(state_ == kStopping || state_ == kStopped) | 674 DCHECK(state_ == kStopping || state_ == kStopped) |
647 << "Receive suspend in unexpected state: " << state_; | 675 << "Receive suspend in unexpected state: " << state_; |
648 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE); | 676 suspend_cb.Run(PIPELINE_ERROR_INVALID_STATE); |
649 return; | 677 return; |
650 } | 678 } |
651 DCHECK(renderer_); | 679 DCHECK(renderer_); |
652 DCHECK(!pending_callbacks_.get()); | 680 DCHECK(!pending_callbacks_.get()); |
(...skipping 27 matching lines...) Expand all Loading... | |
680 base::Unretained(text_renderer_.get()))); | 708 base::Unretained(text_renderer_.get()))); |
681 } | 709 } |
682 | 710 |
683 pending_callbacks_ = SerialRunner::Run( | 711 pending_callbacks_ = SerialRunner::Run( |
684 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); | 712 fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this_)); |
685 } | 713 } |
686 | 714 |
687 void PipelineImpl::ResumeTask(std::unique_ptr<Renderer> renderer, | 715 void PipelineImpl::ResumeTask(std::unique_ptr<Renderer> renderer, |
688 base::TimeDelta timestamp, | 716 base::TimeDelta timestamp, |
689 const PipelineStatusCB& seek_cb) { | 717 const PipelineStatusCB& seek_cb) { |
690 DCHECK(task_runner_->BelongsToCurrentThread()); | 718 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
691 | 719 |
692 // Suppress resuming if we're not suspended. | 720 // Suppress resuming if we're not suspended. |
693 if (state_ != kSuspended) { | 721 if (state_ != kSuspended) { |
694 DCHECK(state_ == kStopping || state_ == kStopped) | 722 DCHECK(state_ == kStopping || state_ == kStopped) |
695 << "Receive resume in unexpected state: " << state_; | 723 << "Receive resume in unexpected state: " << state_; |
696 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); | 724 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE); |
697 return; | 725 return; |
698 } | 726 } |
699 DCHECK(!renderer_); | 727 DCHECK(!renderer_); |
700 DCHECK(!pending_callbacks_.get()); | 728 DCHECK(!pending_callbacks_.get()); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
734 } | 762 } |
735 | 763 |
736 renderer_->SetCdm(cdm_context, | 764 renderer_->SetCdm(cdm_context, |
737 base::Bind(&PipelineImpl::OnCdmAttached, weak_this_, | 765 base::Bind(&PipelineImpl::OnCdmAttached, weak_this_, |
738 cdm_attached_cb, cdm_context)); | 766 cdm_attached_cb, cdm_context)); |
739 } | 767 } |
740 | 768 |
741 void PipelineImpl::OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, | 769 void PipelineImpl::OnCdmAttached(const CdmAttachedCB& cdm_attached_cb, |
742 CdmContext* cdm_context, | 770 CdmContext* cdm_context, |
743 bool success) { | 771 bool success) { |
744 DCHECK(task_runner_->BelongsToCurrentThread()); | 772 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
745 if (success) | 773 if (success) |
746 cdm_context_ = cdm_context; | 774 cdm_context_ = cdm_context; |
747 cdm_attached_cb.Run(success); | 775 cdm_attached_cb.Run(success); |
748 } | 776 } |
749 | 777 |
750 void PipelineImpl::OnRendererEnded() { | 778 void PipelineImpl::OnRendererEnded() { |
751 DCHECK(task_runner_->BelongsToCurrentThread()); | 779 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
752 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); | 780 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); |
753 | 781 |
754 if (state_ != kPlaying) | 782 if (state_ != kPlaying) |
755 return; | 783 return; |
756 | 784 |
757 DCHECK(!renderer_ended_); | 785 DCHECK(!renderer_ended_); |
758 renderer_ended_ = true; | 786 renderer_ended_ = true; |
759 | 787 |
760 RunEndedCallbackIfNeeded(); | 788 RunEndedCallbackIfNeeded(); |
761 } | 789 } |
762 | 790 |
763 void PipelineImpl::OnTextRendererEnded() { | 791 void PipelineImpl::OnTextRendererEnded() { |
764 DCHECK(task_runner_->BelongsToCurrentThread()); | 792 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
765 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); | 793 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); |
766 | 794 |
767 if (state_ != kPlaying) | 795 if (state_ != kPlaying) |
768 return; | 796 return; |
769 | 797 |
770 DCHECK(!text_renderer_ended_); | 798 DCHECK(!text_renderer_ended_); |
771 text_renderer_ended_ = true; | 799 text_renderer_ended_ = true; |
772 | 800 |
773 RunEndedCallbackIfNeeded(); | 801 RunEndedCallbackIfNeeded(); |
774 } | 802 } |
775 | 803 |
776 void PipelineImpl::RunEndedCallbackIfNeeded() { | 804 void PipelineImpl::RunEndedCallbackIfNeeded() { |
777 DCHECK(task_runner_->BelongsToCurrentThread()); | 805 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
778 | 806 |
779 if (renderer_ && !renderer_ended_) | 807 if (renderer_ && !renderer_ended_) |
780 return; | 808 return; |
781 | 809 |
782 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) | 810 if (text_renderer_ && text_renderer_->HasTracks() && !text_renderer_ended_) |
783 return; | 811 return; |
784 | 812 |
785 DCHECK_EQ(status_, PIPELINE_OK); | 813 DCHECK_EQ(status_, PIPELINE_OK); |
786 ended_cb_.Run(); | 814 main_task_runner_->PostTask(FROM_HERE, base::Bind(&Pipeline::Client::OnEnded, |
815 base::Unretained(client_))); | |
787 } | 816 } |
788 | 817 |
789 std::unique_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { | 818 std::unique_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() { |
790 DCHECK(task_runner_->BelongsToCurrentThread()); | 819 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
791 | 820 |
792 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 821 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
793 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) | 822 if (!cmd_line->HasSwitch(switches::kEnableInbandTextTracks)) |
794 return nullptr; | 823 return nullptr; |
795 | 824 |
796 return base::WrapUnique(new media::TextRenderer( | 825 return base::WrapUnique(new media::TextRenderer( |
797 task_runner_, base::Bind(&PipelineImpl::OnAddTextTrack, weak_this_))); | 826 media_task_runner_, |
827 base::Bind(&PipelineImpl::OnAddTextTrack, weak_this_))); | |
798 } | 828 } |
799 | 829 |
800 void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream, | 830 void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream, |
801 const TextTrackConfig& config) { | 831 const TextTrackConfig& config) { |
802 DCHECK(task_runner_->BelongsToCurrentThread()); | 832 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
803 // TODO(matthewjheaney): fix up text_ended_ when text stream | 833 // TODO(matthewjheaney): fix up text_ended_ when text stream |
804 // is added (http://crbug.com/321446). | 834 // is added (http://crbug.com/321446). |
805 if (text_renderer_) | 835 if (text_renderer_) |
806 text_renderer_->AddTextStream(text_stream, config); | 836 text_renderer_->AddTextStream(text_stream, config); |
807 } | 837 } |
808 | 838 |
809 void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) { | 839 void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) { |
810 DCHECK(task_runner_->BelongsToCurrentThread()); | 840 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
841 | |
811 if (text_renderer_) | 842 if (text_renderer_) |
812 text_renderer_->RemoveTextStream(text_stream); | 843 text_renderer_->RemoveTextStream(text_stream); |
813 } | 844 } |
814 | 845 |
815 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, | 846 void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config, |
816 const AddTextTrackDoneCB& done_cb) { | 847 const AddTextTrackDoneCB& done_cb) { |
817 DCHECK(task_runner_->BelongsToCurrentThread()); | 848 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
818 add_text_track_cb_.Run(config, done_cb); | 849 |
850 main_task_runner_->PostTask( | |
851 FROM_HERE, base::Bind(&Pipeline::Client::OnAddTextTrack, | |
852 base::Unretained(client_), config, done_cb)); | |
819 } | 853 } |
820 | 854 |
821 void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) { | 855 void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) { |
822 DCHECK(task_runner_->BelongsToCurrentThread()); | 856 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
857 | |
823 demuxer_->Initialize(this, done_cb, !!text_renderer_); | 858 demuxer_->Initialize(this, done_cb, !!text_renderer_); |
824 } | 859 } |
825 | 860 |
826 void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) { | 861 void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) { |
827 DCHECK(task_runner_->BelongsToCurrentThread()); | 862 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
828 | 863 |
829 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && | 864 if (!demuxer_->GetStream(DemuxerStream::AUDIO) && |
830 !demuxer_->GetStream(DemuxerStream::VIDEO)) { | 865 !demuxer_->GetStream(DemuxerStream::VIDEO)) { |
831 { | 866 { |
832 base::AutoLock auto_lock(lock_); | 867 base::AutoLock auto_lock(lock_); |
833 renderer_.reset(); | 868 renderer_.reset(); |
834 } | 869 } |
835 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); | 870 OnError(PIPELINE_ERROR_COULD_NOT_RENDER); |
836 return; | 871 return; |
837 } | 872 } |
838 | 873 |
839 if (cdm_context_) | 874 if (cdm_context_) |
840 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); | 875 renderer_->SetCdm(cdm_context_, base::Bind(&IgnoreCdmAttached)); |
841 | 876 |
842 renderer_->Initialize( | 877 renderer_->Initialize( |
843 demuxer_, done_cb, | 878 demuxer_, done_cb, |
844 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this_), | 879 base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this_), |
845 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this_), | 880 base::Bind(&PipelineImpl::BufferingStateChanged, weak_this_), |
846 base::Bind(&PipelineImpl::OnRendererEnded, weak_this_), | 881 base::Bind(&PipelineImpl::OnRendererEnded, weak_this_), |
847 base::Bind(&PipelineImpl::OnError, weak_this_), | 882 base::Bind(&PipelineImpl::OnError, weak_this_), |
848 waiting_for_decryption_key_cb_); | 883 base::Bind(&PipelineImpl::OnWaitingForDecryptionKey, weak_this_)); |
849 } | 884 } |
850 | 885 |
851 void PipelineImpl::ReportMetadata() { | 886 void PipelineImpl::ReportMetadata() { |
852 DCHECK(task_runner_->BelongsToCurrentThread()); | 887 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
888 | |
853 PipelineMetadata metadata; | 889 PipelineMetadata metadata; |
854 metadata.timeline_offset = demuxer_->GetTimelineOffset(); | 890 metadata.timeline_offset = demuxer_->GetTimelineOffset(); |
855 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); | 891 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
856 if (stream) { | 892 if (stream) { |
857 metadata.has_video = true; | 893 metadata.has_video = true; |
858 metadata.natural_size = stream->video_decoder_config().natural_size(); | 894 metadata.natural_size = stream->video_decoder_config().natural_size(); |
859 metadata.video_rotation = stream->video_rotation(); | 895 metadata.video_rotation = stream->video_rotation(); |
860 } | 896 } |
861 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { | 897 if (demuxer_->GetStream(DemuxerStream::AUDIO)) { |
862 metadata.has_audio = true; | 898 metadata.has_audio = true; |
863 } | 899 } |
864 metadata_cb_.Run(metadata); | 900 |
901 main_task_runner_->PostTask(FROM_HERE, | |
902 base::Bind(&Pipeline::Client::OnMetadata, | |
903 base::Unretained(client_), metadata)); | |
865 } | 904 } |
866 | 905 |
867 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) { | 906 void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) { |
907 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
868 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; | 908 DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") "; |
869 DCHECK(task_runner_->BelongsToCurrentThread()); | 909 |
870 buffering_state_cb_.Run(new_buffering_state); | 910 main_task_runner_->PostTask( |
911 FROM_HERE, base::Bind(&Pipeline::Client::OnBufferingStateChange, | |
912 base::Unretained(client_), new_buffering_state)); | |
871 } | 913 } |
872 | 914 |
873 } // namespace media | 915 } // namespace media |
OLD | NEW |