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