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