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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/command_line.h" |
10 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
11 #include "base/location.h" | 12 #include "base/location.h" |
12 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
| 14 #include "base/strings/string_number_conversions.h" |
13 #include "media/base/audio_renderer.h" | 15 #include "media/base/audio_renderer.h" |
14 #include "media/base/bind_to_current_loop.h" | 16 #include "media/base/bind_to_current_loop.h" |
15 #include "media/base/demuxer_stream_provider.h" | 17 #include "media/base/demuxer_stream_provider.h" |
| 18 #include "media/base/media_switches.h" |
16 #include "media/base/time_source.h" | 19 #include "media/base/time_source.h" |
17 #include "media/base/video_renderer.h" | 20 #include "media/base/video_renderer.h" |
18 #include "media/base/wall_clock_time_source.h" | 21 #include "media/base/wall_clock_time_source.h" |
19 | 22 |
20 namespace media { | 23 namespace media { |
21 | 24 |
| 25 // See |video_underflow_threshold_|. |
| 26 static const int kDefaultVideoUnderflowThresholdMs = 3000; |
| 27 |
22 RendererImpl::RendererImpl( | 28 RendererImpl::RendererImpl( |
23 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 29 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
24 scoped_ptr<AudioRenderer> audio_renderer, | 30 scoped_ptr<AudioRenderer> audio_renderer, |
25 scoped_ptr<VideoRenderer> video_renderer) | 31 scoped_ptr<VideoRenderer> video_renderer) |
26 : state_(STATE_UNINITIALIZED), | 32 : state_(STATE_UNINITIALIZED), |
27 task_runner_(task_runner), | 33 task_runner_(task_runner), |
28 audio_renderer_(audio_renderer.Pass()), | 34 audio_renderer_(audio_renderer.Pass()), |
29 video_renderer_(video_renderer.Pass()), | 35 video_renderer_(video_renderer.Pass()), |
30 time_source_(NULL), | 36 time_source_(NULL), |
31 time_ticking_(false), | 37 time_ticking_(false), |
32 audio_buffering_state_(BUFFERING_HAVE_NOTHING), | 38 audio_buffering_state_(BUFFERING_HAVE_NOTHING), |
33 video_buffering_state_(BUFFERING_HAVE_NOTHING), | 39 video_buffering_state_(BUFFERING_HAVE_NOTHING), |
34 audio_ended_(false), | 40 audio_ended_(false), |
35 video_ended_(false), | 41 video_ended_(false), |
36 cdm_context_(nullptr), | 42 cdm_context_(nullptr), |
37 underflow_disabled_for_testing_(false), | 43 underflow_disabled_for_testing_(false), |
38 clockless_video_playback_enabled_for_testing_(false), | 44 clockless_video_playback_enabled_for_testing_(false), |
| 45 video_underflow_threshold_( |
| 46 base::TimeDelta::FromMilliseconds(kDefaultVideoUnderflowThresholdMs)), |
39 weak_factory_(this) { | 47 weak_factory_(this) { |
40 weak_this_ = weak_factory_.GetWeakPtr(); | 48 weak_this_ = weak_factory_.GetWeakPtr(); |
41 DVLOG(1) << __FUNCTION__; | 49 DVLOG(1) << __FUNCTION__; |
| 50 |
| 51 // TODO(dalecurtis): Remove once experiments for http://crbug.com/470940 are |
| 52 // complete. |
| 53 int threshold_ms = 0; |
| 54 std::string threshold_ms_str( |
| 55 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 56 switches::kVideoUnderflowThresholdMs)); |
| 57 if (base::StringToInt(threshold_ms_str, &threshold_ms) && threshold_ms > 0) { |
| 58 video_underflow_threshold_ = |
| 59 base::TimeDelta::FromMilliseconds(threshold_ms); |
| 60 } |
42 } | 61 } |
43 | 62 |
44 RendererImpl::~RendererImpl() { | 63 RendererImpl::~RendererImpl() { |
45 DVLOG(1) << __FUNCTION__; | 64 DVLOG(1) << __FUNCTION__; |
46 DCHECK(task_runner_->BelongsToCurrentThread()); | 65 DCHECK(task_runner_->BelongsToCurrentThread()); |
47 | 66 |
48 // Tear down in opposite order of construction as |video_renderer_| can still | 67 // Tear down in opposite order of construction as |video_renderer_| can still |
49 // need |time_source_| (which can be |audio_renderer_|) to be alive. | 68 // need |time_source_| (which can be |audio_renderer_|) to be alive. |
50 video_renderer_.reset(); | 69 video_renderer_.reset(); |
51 audio_renderer_.reset(); | 70 audio_renderer_.reset(); |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 | 348 |
330 DCHECK(!init_cb_.is_null()); | 349 DCHECK(!init_cb_.is_null()); |
331 | 350 |
332 if (status != PIPELINE_OK) { | 351 if (status != PIPELINE_OK) { |
333 base::ResetAndReturn(&init_cb_).Run(status); | 352 base::ResetAndReturn(&init_cb_).Run(status); |
334 return; | 353 return; |
335 } | 354 } |
336 | 355 |
337 if (audio_renderer_) { | 356 if (audio_renderer_) { |
338 time_source_ = audio_renderer_->GetTimeSource(); | 357 time_source_ = audio_renderer_->GetTimeSource(); |
339 } else { | 358 } else if (!time_source_) { |
340 wall_clock_time_source_.reset(new WallClockTimeSource()); | 359 wall_clock_time_source_.reset(new WallClockTimeSource()); |
341 time_source_ = wall_clock_time_source_.get(); | 360 time_source_ = wall_clock_time_source_.get(); |
342 } | 361 } |
343 | 362 |
344 state_ = STATE_PLAYING; | 363 state_ = STATE_PLAYING; |
345 DCHECK(time_source_); | 364 DCHECK(time_source_); |
346 DCHECK(audio_renderer_ || video_renderer_); | 365 DCHECK(audio_renderer_ || video_renderer_); |
347 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 366 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
348 } | 367 } |
349 | 368 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 base::ResetAndReturn(&flush_cb_).Run(); | 431 base::ResetAndReturn(&flush_cb_).Run(); |
413 } | 432 } |
414 | 433 |
415 void RendererImpl::OnUpdateStatistics(const PipelineStatistics& stats) { | 434 void RendererImpl::OnUpdateStatistics(const PipelineStatistics& stats) { |
416 DCHECK(task_runner_->BelongsToCurrentThread()); | 435 DCHECK(task_runner_->BelongsToCurrentThread()); |
417 statistics_cb_.Run(stats); | 436 statistics_cb_.Run(stats); |
418 } | 437 } |
419 | 438 |
420 void RendererImpl::OnBufferingStateChanged(BufferingState* buffering_state, | 439 void RendererImpl::OnBufferingStateChanged(BufferingState* buffering_state, |
421 BufferingState new_buffering_state) { | 440 BufferingState new_buffering_state) { |
| 441 const bool is_audio = buffering_state == &audio_buffering_state_; |
422 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " | 442 DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " |
423 << new_buffering_state << ") " | 443 << new_buffering_state << ") " << (is_audio ? "audio" : "video"); |
424 << (buffering_state == &audio_buffering_state_ ? "audio" : "video"); | |
425 DCHECK(task_runner_->BelongsToCurrentThread()); | 444 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 445 |
426 bool was_waiting_for_enough_data = WaitingForEnoughData(); | 446 bool was_waiting_for_enough_data = WaitingForEnoughData(); |
427 | 447 |
| 448 // When audio is present, defer underflow callbacks for some time to avoid |
| 449 // unnecessary glitches in audio; see http://crbug.com/144683#c53. |
| 450 if (audio_renderer_ && !is_audio && state_ == STATE_PLAYING) { |
| 451 if (video_buffering_state_ == BUFFERING_HAVE_ENOUGH && |
| 452 new_buffering_state == BUFFERING_HAVE_NOTHING && |
| 453 deferred_underflow_cb_.IsCancelled()) { |
| 454 deferred_underflow_cb_.Reset(base::Bind( |
| 455 &RendererImpl::OnBufferingStateChanged, weak_factory_.GetWeakPtr(), |
| 456 buffering_state, new_buffering_state)); |
| 457 task_runner_->PostDelayedTask(FROM_HERE, |
| 458 deferred_underflow_cb_.callback(), |
| 459 video_underflow_threshold_); |
| 460 return; |
| 461 } |
| 462 |
| 463 deferred_underflow_cb_.Cancel(); |
| 464 } else if (!deferred_underflow_cb_.IsCancelled() && is_audio && |
| 465 new_buffering_state == BUFFERING_HAVE_NOTHING) { |
| 466 // If audio underflows while we have a deferred video underflow in progress |
| 467 // we want to mark video as underflowed immediately and cancel the deferral. |
| 468 deferred_underflow_cb_.Cancel(); |
| 469 video_buffering_state_ = BUFFERING_HAVE_NOTHING; |
| 470 } |
| 471 |
428 *buffering_state = new_buffering_state; | 472 *buffering_state = new_buffering_state; |
429 | 473 |
430 // Disable underflow by ignoring updates that renderers have ran out of data. | 474 // Disable underflow by ignoring updates that renderers have ran out of data. |
431 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ && | 475 if (state_ == STATE_PLAYING && underflow_disabled_for_testing_ && |
432 time_ticking_) { | 476 time_ticking_) { |
433 DVLOG(1) << "Update ignored because underflow is disabled for testing."; | 477 DVLOG(1) << "Update ignored because underflow is disabled for testing."; |
434 return; | 478 return; |
435 } | 479 } |
436 | 480 |
437 // Renderer underflowed. | 481 // Renderer underflowed. |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
571 } | 615 } |
572 | 616 |
573 // After OnError() returns, the pipeline may destroy |this|. | 617 // After OnError() returns, the pipeline may destroy |this|. |
574 base::ResetAndReturn(&error_cb_).Run(error); | 618 base::ResetAndReturn(&error_cb_).Run(error); |
575 | 619 |
576 if (!flush_cb_.is_null()) | 620 if (!flush_cb_.is_null()) |
577 base::ResetAndReturn(&flush_cb_).Run(); | 621 base::ResetAndReturn(&flush_cb_).Run(); |
578 } | 622 } |
579 | 623 |
580 } // namespace media | 624 } // namespace media |
OLD | NEW |