OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/renderers/renderer_impl.h" | 5 #include "media/renderers/renderer_impl.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
14 #include "base/location.h" | 14 #include "base/location.h" |
15 #include "base/single_thread_task_runner.h" | 15 #include "base/single_thread_task_runner.h" |
16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
| 17 #include "media/base/audio_decoder_config.h" |
17 #include "media/base/audio_renderer.h" | 18 #include "media/base/audio_renderer.h" |
18 #include "media/base/bind_to_current_loop.h" | 19 #include "media/base/bind_to_current_loop.h" |
19 #include "media/base/demuxer_stream_provider.h" | 20 #include "media/base/demuxer_stream_provider.h" |
20 #include "media/base/media_switches.h" | 21 #include "media/base/media_switches.h" |
21 #include "media/base/time_source.h" | 22 #include "media/base/time_source.h" |
| 23 #include "media/base/video_decoder_config.h" |
22 #include "media/base/video_renderer.h" | 24 #include "media/base/video_renderer.h" |
23 #include "media/base/wall_clock_time_source.h" | 25 #include "media/base/wall_clock_time_source.h" |
24 | 26 |
25 namespace media { | 27 namespace media { |
26 | 28 |
27 // See |video_underflow_threshold_|. | 29 // See |video_underflow_threshold_|. |
28 static const int kDefaultVideoUnderflowThresholdMs = 3000; | 30 static const int kDefaultVideoUnderflowThresholdMs = 3000; |
29 | 31 |
30 RendererImpl::RendererImpl( | 32 RendererImpl::RendererImpl( |
31 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 33 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 | 67 |
66 RendererImpl::~RendererImpl() { | 68 RendererImpl::~RendererImpl() { |
67 DVLOG(1) << __FUNCTION__; | 69 DVLOG(1) << __FUNCTION__; |
68 DCHECK(task_runner_->BelongsToCurrentThread()); | 70 DCHECK(task_runner_->BelongsToCurrentThread()); |
69 | 71 |
70 // Tear down in opposite order of construction as |video_renderer_| can still | 72 // Tear down in opposite order of construction as |video_renderer_| can still |
71 // need |time_source_| (which can be |audio_renderer_|) to be alive. | 73 // need |time_source_| (which can be |audio_renderer_|) to be alive. |
72 video_renderer_.reset(); | 74 video_renderer_.reset(); |
73 audio_renderer_.reset(); | 75 audio_renderer_.reset(); |
74 | 76 |
75 if (!init_cb_.is_null()) | 77 if (!init_cb_.is_null()) { |
76 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); | 78 FinishInitialization(PIPELINE_ERROR_ABORT); |
77 else if (!flush_cb_.is_null()) | 79 } else if (!flush_cb_.is_null()) { |
78 base::ResetAndReturn(&flush_cb_).Run(); | 80 base::ResetAndReturn(&flush_cb_).Run(); |
| 81 } |
79 } | 82 } |
80 | 83 |
81 void RendererImpl::Initialize( | 84 void RendererImpl::Initialize( |
82 DemuxerStreamProvider* demuxer_stream_provider, | 85 DemuxerStreamProvider* demuxer_stream_provider, |
83 const PipelineStatusCB& init_cb, | 86 const PipelineStatusCB& init_cb, |
84 const StatisticsCB& statistics_cb, | 87 const StatisticsCB& statistics_cb, |
85 const BufferingStateCB& buffering_state_cb, | 88 const BufferingStateCB& buffering_state_cb, |
86 const base::Closure& ended_cb, | 89 const base::Closure& ended_cb, |
87 const PipelineStatusCB& error_cb, | 90 const PipelineStatusCB& error_cb, |
88 const base::Closure& waiting_for_decryption_key_cb) { | 91 const base::Closure& waiting_for_decryption_key_cb) { |
89 DVLOG(1) << __FUNCTION__; | 92 DVLOG(1) << __FUNCTION__; |
90 DCHECK(task_runner_->BelongsToCurrentThread()); | 93 DCHECK(task_runner_->BelongsToCurrentThread()); |
91 DCHECK_EQ(state_, STATE_UNINITIALIZED); | 94 DCHECK_EQ(state_, STATE_UNINITIALIZED); |
92 DCHECK(!init_cb.is_null()); | 95 DCHECK(!init_cb.is_null()); |
93 DCHECK(!statistics_cb.is_null()); | 96 DCHECK(!statistics_cb.is_null()); |
94 DCHECK(!buffering_state_cb.is_null()); | 97 DCHECK(!buffering_state_cb.is_null()); |
95 DCHECK(!ended_cb.is_null()); | 98 DCHECK(!ended_cb.is_null()); |
96 DCHECK(!error_cb.is_null()); | 99 DCHECK(!error_cb.is_null()); |
97 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || | 100 DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || |
98 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO)); | 101 demuxer_stream_provider->GetStream(DemuxerStream::VIDEO)); |
99 | 102 |
100 demuxer_stream_provider_ = demuxer_stream_provider; | 103 demuxer_stream_provider_ = demuxer_stream_provider; |
101 statistics_cb_ = statistics_cb; | 104 statistics_cb_ = statistics_cb; |
102 buffering_state_cb_ = buffering_state_cb; | 105 buffering_state_cb_ = buffering_state_cb; |
103 ended_cb_ = ended_cb; | 106 ended_cb_ = ended_cb; |
104 error_cb_ = error_cb; | 107 error_cb_ = error_cb; |
105 init_cb_ = init_cb; | 108 init_cb_ = init_cb; |
106 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; | 109 waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; |
107 | 110 |
| 111 if (HasEncryptedStream() && !cdm_context_) { |
| 112 state_ = STATE_INIT_PENDING_CDM; |
| 113 return; |
| 114 } |
| 115 |
108 state_ = STATE_INITIALIZING; | 116 state_ = STATE_INITIALIZING; |
109 InitializeAudioRenderer(); | 117 InitializeAudioRenderer(); |
110 } | 118 } |
111 | 119 |
112 void RendererImpl::SetCdm(CdmContext* cdm_context, | 120 void RendererImpl::SetCdm(CdmContext* cdm_context, |
113 const CdmAttachedCB& cdm_attached_cb) { | 121 const CdmAttachedCB& cdm_attached_cb) { |
114 DVLOG(1) << __FUNCTION__; | 122 DVLOG(1) << __FUNCTION__; |
115 DCHECK(task_runner_->BelongsToCurrentThread()); | 123 DCHECK(task_runner_->BelongsToCurrentThread()); |
116 DCHECK(cdm_context); | 124 DCHECK(cdm_context); |
117 | 125 |
118 if (cdm_context_) { | 126 if (cdm_context_) { |
119 DVLOG(1) << "Switching CDM not supported."; | 127 DVLOG(1) << "Switching CDM not supported."; |
120 cdm_attached_cb.Run(false); | 128 cdm_attached_cb.Run(false); |
121 return; | 129 return; |
122 } | 130 } |
123 | 131 |
124 cdm_context_ = cdm_context; | 132 cdm_context_ = cdm_context; |
125 | 133 |
126 if (cdm_ready_cb_.is_null()) { | 134 if (state_ != STATE_INIT_PENDING_CDM) { |
127 cdm_attached_cb.Run(true); | 135 cdm_attached_cb.Run(true); |
128 return; | 136 return; |
129 } | 137 } |
130 | 138 |
131 base::ResetAndReturn(&cdm_ready_cb_).Run(cdm_context, cdm_attached_cb); | 139 DCHECK(!init_cb_.is_null()); |
| 140 state_ = STATE_INITIALIZING; |
| 141 // |cdm_attached_cb| will be fired after initialization finishes. |
| 142 pending_cdm_attached_cb_ = cdm_attached_cb; |
| 143 |
| 144 InitializeAudioRenderer(); |
132 } | 145 } |
133 | 146 |
134 void RendererImpl::Flush(const base::Closure& flush_cb) { | 147 void RendererImpl::Flush(const base::Closure& flush_cb) { |
135 DVLOG(1) << __FUNCTION__; | 148 DVLOG(1) << __FUNCTION__; |
136 DCHECK(task_runner_->BelongsToCurrentThread()); | 149 DCHECK(task_runner_->BelongsToCurrentThread()); |
137 DCHECK(flush_cb_.is_null()); | 150 DCHECK(flush_cb_.is_null()); |
138 | 151 |
139 if (state_ != STATE_PLAYING) { | 152 if (state_ != STATE_PLAYING) { |
140 DCHECK_EQ(state_, STATE_ERROR); | 153 DCHECK_EQ(state_, STATE_ERROR); |
141 return; | 154 return; |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 for (auto const &media_time : media_timestamps) { | 260 for (auto const &media_time : media_timestamps) { |
248 wall_clock_times->push_back(base::TimeTicks() + media_time); | 261 wall_clock_times->push_back(base::TimeTicks() + media_time); |
249 } | 262 } |
250 } | 263 } |
251 return true; | 264 return true; |
252 } | 265 } |
253 | 266 |
254 return time_source_->GetWallClockTimes(media_timestamps, wall_clock_times); | 267 return time_source_->GetWallClockTimes(media_timestamps, wall_clock_times); |
255 } | 268 } |
256 | 269 |
257 void RendererImpl::SetCdmReadyCallback(const CdmReadyCB& cdm_ready_cb) { | 270 bool RendererImpl::HasEncryptedStream() { |
258 // Cancels the previous CDM request. | 271 DemuxerStream* audio_stream = |
259 if (cdm_ready_cb.is_null()) { | 272 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); |
260 if (!cdm_ready_cb_.is_null()) { | 273 if (audio_stream && audio_stream->audio_decoder_config().is_encrypted()) |
261 base::ResetAndReturn(&cdm_ready_cb_) | 274 return true; |
262 .Run(nullptr, base::Bind(IgnoreCdmAttached)); | |
263 } | |
264 return; | |
265 } | |
266 | 275 |
267 // We initialize audio and video decoders in sequence. | 276 DemuxerStream* video_stream = |
268 DCHECK(cdm_ready_cb_.is_null()); | 277 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); |
| 278 if (video_stream && video_stream->video_decoder_config().is_encrypted()) |
| 279 return true; |
269 | 280 |
270 if (cdm_context_) { | 281 return false; |
271 cdm_ready_cb.Run(cdm_context_, base::Bind(IgnoreCdmAttached)); | 282 } |
272 return; | |
273 } | |
274 | 283 |
275 cdm_ready_cb_ = cdm_ready_cb; | 284 void RendererImpl::FinishInitialization(PipelineStatus status) { |
| 285 DCHECK(!init_cb_.is_null()); |
| 286 |
| 287 if (!pending_cdm_attached_cb_.is_null()) |
| 288 base::ResetAndReturn(&pending_cdm_attached_cb_).Run(status == PIPELINE_OK); |
| 289 |
| 290 base::ResetAndReturn(&init_cb_).Run(status); |
276 } | 291 } |
277 | 292 |
278 void RendererImpl::InitializeAudioRenderer() { | 293 void RendererImpl::InitializeAudioRenderer() { |
279 DVLOG(1) << __FUNCTION__; | 294 DVLOG(1) << __FUNCTION__; |
280 DCHECK(task_runner_->BelongsToCurrentThread()); | 295 DCHECK(task_runner_->BelongsToCurrentThread()); |
281 DCHECK_EQ(state_, STATE_INITIALIZING); | 296 DCHECK_EQ(state_, STATE_INITIALIZING); |
282 DCHECK(!init_cb_.is_null()); | 297 DCHECK(!init_cb_.is_null()); |
283 | 298 |
284 PipelineStatusCB done_cb = | 299 PipelineStatusCB done_cb = |
285 base::Bind(&RendererImpl::OnAudioRendererInitializeDone, weak_this_); | 300 base::Bind(&RendererImpl::OnAudioRendererInitializeDone, weak_this_); |
286 | 301 |
287 if (!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)) { | 302 if (!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO)) { |
288 audio_renderer_.reset(); | 303 audio_renderer_.reset(); |
289 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 304 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); |
290 return; | 305 return; |
291 } | 306 } |
292 | 307 |
293 // Note: After the initialization of a renderer, error events from it may | 308 // Note: After the initialization of a renderer, error events from it may |
294 // happen at any time and all future calls must guard against STATE_ERROR. | 309 // happen at any time and all future calls must guard against STATE_ERROR. |
295 audio_renderer_->Initialize( | 310 audio_renderer_->Initialize( |
296 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO), done_cb, | 311 demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO), done_cb, |
297 base::Bind(&RendererImpl::SetCdmReadyCallback, weak_this_), | 312 cdm_context_, base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_), |
298 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_), | |
299 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_, | 313 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_, |
300 &audio_buffering_state_), | 314 &audio_buffering_state_), |
301 base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_), | 315 base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_), |
302 base::Bind(&RendererImpl::OnError, weak_this_), | 316 base::Bind(&RendererImpl::OnError, weak_this_), |
303 waiting_for_decryption_key_cb_); | 317 waiting_for_decryption_key_cb_); |
304 } | 318 } |
305 | 319 |
306 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { | 320 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { |
307 DVLOG(1) << __FUNCTION__ << ": " << status; | 321 DVLOG(1) << __FUNCTION__ << ": " << status; |
308 DCHECK(task_runner_->BelongsToCurrentThread()); | 322 DCHECK(task_runner_->BelongsToCurrentThread()); |
309 | 323 |
310 // OnError() may be fired at any time by the renderers, even if they thought | 324 // OnError() may be fired at any time by the renderers, even if they thought |
311 // they initialized successfully (due to delayed output device setup). | 325 // they initialized successfully (due to delayed output device setup). |
312 if (state_ != STATE_INITIALIZING) { | 326 if (state_ != STATE_INITIALIZING) { |
313 DCHECK(init_cb_.is_null()); | 327 DCHECK(init_cb_.is_null()); |
314 audio_renderer_.reset(); | 328 audio_renderer_.reset(); |
315 return; | 329 return; |
316 } | 330 } |
317 | 331 |
318 if (status != PIPELINE_OK) { | 332 if (status != PIPELINE_OK) { |
319 base::ResetAndReturn(&init_cb_).Run(status); | 333 FinishInitialization(status); |
320 return; | 334 return; |
321 } | 335 } |
322 | 336 |
323 DCHECK(!init_cb_.is_null()); | 337 DCHECK(!init_cb_.is_null()); |
324 InitializeVideoRenderer(); | 338 InitializeVideoRenderer(); |
325 } | 339 } |
326 | 340 |
327 void RendererImpl::InitializeVideoRenderer() { | 341 void RendererImpl::InitializeVideoRenderer() { |
328 DVLOG(1) << __FUNCTION__; | 342 DVLOG(1) << __FUNCTION__; |
329 DCHECK(task_runner_->BelongsToCurrentThread()); | 343 DCHECK(task_runner_->BelongsToCurrentThread()); |
330 DCHECK_EQ(state_, STATE_INITIALIZING); | 344 DCHECK_EQ(state_, STATE_INITIALIZING); |
331 DCHECK(!init_cb_.is_null()); | 345 DCHECK(!init_cb_.is_null()); |
332 | 346 |
333 PipelineStatusCB done_cb = | 347 PipelineStatusCB done_cb = |
334 base::Bind(&RendererImpl::OnVideoRendererInitializeDone, weak_this_); | 348 base::Bind(&RendererImpl::OnVideoRendererInitializeDone, weak_this_); |
335 | 349 |
336 if (!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO)) { | 350 if (!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO)) { |
337 video_renderer_.reset(); | 351 video_renderer_.reset(); |
338 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); | 352 task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK)); |
339 return; | 353 return; |
340 } | 354 } |
341 | 355 |
342 video_renderer_->Initialize( | 356 video_renderer_->Initialize( |
343 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO), done_cb, | 357 demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO), done_cb, |
344 base::Bind(&RendererImpl::SetCdmReadyCallback, weak_this_), | 358 cdm_context_, base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_), |
345 base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_), | |
346 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_, | 359 base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_, |
347 &video_buffering_state_), | 360 &video_buffering_state_), |
348 base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_), | 361 base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_), |
349 base::Bind(&RendererImpl::OnError, weak_this_), | 362 base::Bind(&RendererImpl::OnError, weak_this_), |
350 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)), | 363 base::Bind(&RendererImpl::GetWallClockTimes, base::Unretained(this)), |
351 waiting_for_decryption_key_cb_); | 364 waiting_for_decryption_key_cb_); |
352 } | 365 } |
353 | 366 |
354 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) { | 367 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) { |
355 DVLOG(1) << __FUNCTION__ << ": " << status; | 368 DVLOG(1) << __FUNCTION__ << ": " << status; |
356 DCHECK(task_runner_->BelongsToCurrentThread()); | 369 DCHECK(task_runner_->BelongsToCurrentThread()); |
357 | 370 |
358 // OnError() may be fired at any time by the renderers, even if they thought | 371 // OnError() may be fired at any time by the renderers, even if they thought |
359 // they initialized successfully (due to delayed output device setup). | 372 // they initialized successfully (due to delayed output device setup). |
360 if (state_ != STATE_INITIALIZING) { | 373 if (state_ != STATE_INITIALIZING) { |
361 DCHECK(init_cb_.is_null()); | 374 DCHECK(init_cb_.is_null()); |
362 audio_renderer_.reset(); | 375 audio_renderer_.reset(); |
363 video_renderer_.reset(); | 376 video_renderer_.reset(); |
364 return; | 377 return; |
365 } | 378 } |
366 | 379 |
367 DCHECK(!init_cb_.is_null()); | 380 DCHECK(!init_cb_.is_null()); |
368 | 381 |
369 if (status != PIPELINE_OK) { | 382 if (status != PIPELINE_OK) { |
370 base::ResetAndReturn(&init_cb_).Run(status); | 383 FinishInitialization(status); |
371 return; | 384 return; |
372 } | 385 } |
373 | 386 |
374 if (audio_renderer_) { | 387 if (audio_renderer_) { |
375 time_source_ = audio_renderer_->GetTimeSource(); | 388 time_source_ = audio_renderer_->GetTimeSource(); |
376 } else if (!time_source_) { | 389 } else if (!time_source_) { |
377 wall_clock_time_source_.reset(new WallClockTimeSource()); | 390 wall_clock_time_source_.reset(new WallClockTimeSource()); |
378 time_source_ = wall_clock_time_source_.get(); | 391 time_source_ = wall_clock_time_source_.get(); |
379 } | 392 } |
380 | 393 |
381 state_ = STATE_PLAYING; | 394 state_ = STATE_PLAYING; |
382 DCHECK(time_source_); | 395 DCHECK(time_source_); |
383 DCHECK(audio_renderer_ || video_renderer_); | 396 DCHECK(audio_renderer_ || video_renderer_); |
384 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 397 |
| 398 FinishInitialization(PIPELINE_OK); |
385 } | 399 } |
386 | 400 |
387 void RendererImpl::FlushAudioRenderer() { | 401 void RendererImpl::FlushAudioRenderer() { |
388 DVLOG(1) << __FUNCTION__; | 402 DVLOG(1) << __FUNCTION__; |
389 DCHECK(task_runner_->BelongsToCurrentThread()); | 403 DCHECK(task_runner_->BelongsToCurrentThread()); |
390 DCHECK_EQ(state_, STATE_FLUSHING); | 404 DCHECK_EQ(state_, STATE_FLUSHING); |
391 DCHECK(!flush_cb_.is_null()); | 405 DCHECK(!flush_cb_.is_null()); |
392 | 406 |
393 if (!audio_renderer_) { | 407 if (!audio_renderer_) { |
394 OnAudioRendererFlushDone(); | 408 OnAudioRendererFlushDone(); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 case STATE_PLAYING: | 552 case STATE_PLAYING: |
539 DCHECK(PlaybackHasEnded() || WaitingForEnoughData()) | 553 DCHECK(PlaybackHasEnded() || WaitingForEnoughData()) |
540 << "Playback should only pause due to ending or underflowing"; | 554 << "Playback should only pause due to ending or underflowing"; |
541 break; | 555 break; |
542 | 556 |
543 case STATE_FLUSHING: | 557 case STATE_FLUSHING: |
544 // It's OK to pause playback when flushing. | 558 // It's OK to pause playback when flushing. |
545 break; | 559 break; |
546 | 560 |
547 case STATE_UNINITIALIZED: | 561 case STATE_UNINITIALIZED: |
| 562 case STATE_INIT_PENDING_CDM: |
548 case STATE_INITIALIZING: | 563 case STATE_INITIALIZING: |
549 NOTREACHED() << "Invalid state: " << state_; | 564 NOTREACHED() << "Invalid state: " << state_; |
550 break; | 565 break; |
551 | 566 |
552 case STATE_ERROR: | 567 case STATE_ERROR: |
553 // An error state may occur at any time. | 568 // An error state may occur at any time. |
554 break; | 569 break; |
555 } | 570 } |
556 | 571 |
557 time_ticking_ = false; | 572 time_ticking_ = false; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 DCHECK(task_runner_->BelongsToCurrentThread()); | 645 DCHECK(task_runner_->BelongsToCurrentThread()); |
631 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; | 646 DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!"; |
632 | 647 |
633 // An error has already been delivered. | 648 // An error has already been delivered. |
634 if (state_ == STATE_ERROR) | 649 if (state_ == STATE_ERROR) |
635 return; | 650 return; |
636 | 651 |
637 const State old_state = state_; | 652 const State old_state = state_; |
638 state_ = STATE_ERROR; | 653 state_ = STATE_ERROR; |
639 | 654 |
640 if (old_state == STATE_INITIALIZING) { | 655 if (!init_cb_.is_null()) { |
641 base::ResetAndReturn(&init_cb_).Run(error); | 656 DCHECK(old_state == STATE_INITIALIZING || |
| 657 old_state == STATE_INIT_PENDING_CDM); |
| 658 FinishInitialization(error); |
642 return; | 659 return; |
643 } | 660 } |
644 | 661 |
645 // After OnError() returns, the pipeline may destroy |this|. | 662 // After OnError() returns, the pipeline may destroy |this|. |
646 base::ResetAndReturn(&error_cb_).Run(error); | 663 base::ResetAndReturn(&error_cb_).Run(error); |
647 | 664 |
648 if (!flush_cb_.is_null()) | 665 if (!flush_cb_.is_null()) |
649 base::ResetAndReturn(&flush_cb_).Run(); | 666 base::ResetAndReturn(&flush_cb_).Run(); |
650 } | 667 } |
651 | 668 |
652 } // namespace media | 669 } // namespace media |
OLD | NEW |