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