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 "chromecast/media/cma/pipeline/media_pipeline_impl.h" | 5 #include "chromecast/media/cma/pipeline/media_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" |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
44 base::TimeDelta::FromMilliseconds(300)); | 44 base::TimeDelta::FromMilliseconds(300)); |
45 | 45 |
46 // Interval between two updates of the media time. | 46 // Interval between two updates of the media time. |
47 const base::TimeDelta kTimeUpdateInterval( | 47 const base::TimeDelta kTimeUpdateInterval( |
48 base::TimeDelta::FromMilliseconds(250)); | 48 base::TimeDelta::FromMilliseconds(250)); |
49 | 49 |
50 // Interval between two updates of the statistics is equal to: | 50 // Interval between two updates of the statistics is equal to: |
51 // kTimeUpdateInterval * kStatisticsUpdatePeriod. | 51 // kTimeUpdateInterval * kStatisticsUpdatePeriod. |
52 const int kStatisticsUpdatePeriod = 4; | 52 const int kStatisticsUpdatePeriod = 4; |
53 | 53 |
54 // Stall duration threshold that triggers a playback stall event. | |
55 constexpr int kPlaybackStallEventThreshold = 2500; | |
56 | |
54 void LogEstimatedBitrate(int decoded_bytes, | 57 void LogEstimatedBitrate(int decoded_bytes, |
55 base::TimeDelta elapsed_time, | 58 base::TimeDelta elapsed_time, |
56 const char* tag, | 59 const char* tag, |
57 const char* metric) { | 60 const char* metric) { |
58 int estimated_bitrate_in_kbps = | 61 int estimated_bitrate_in_kbps = |
59 8 * decoded_bytes / elapsed_time.InMilliseconds(); | 62 8 * decoded_bytes / elapsed_time.InMilliseconds(); |
60 | 63 |
61 if (estimated_bitrate_in_kbps <= 0) | 64 if (estimated_bitrate_in_kbps <= 0) |
62 return; | 65 return; |
63 | 66 |
(...skipping 12 matching lines...) Expand all Loading... | |
76 bool video_flushed; | 79 bool video_flushed; |
77 base::Closure done_cb; | 80 base::Closure done_cb; |
78 }; | 81 }; |
79 | 82 |
80 MediaPipelineImpl::MediaPipelineImpl() | 83 MediaPipelineImpl::MediaPipelineImpl() |
81 : cdm_(nullptr), | 84 : cdm_(nullptr), |
82 backend_state_(BACKEND_STATE_UNINITIALIZED), | 85 backend_state_(BACKEND_STATE_UNINITIALIZED), |
83 playback_rate_(1.0f), | 86 playback_rate_(1.0f), |
84 audio_decoder_(nullptr), | 87 audio_decoder_(nullptr), |
85 video_decoder_(nullptr), | 88 video_decoder_(nullptr), |
86 pending_time_update_task_(false), | 89 pending_time_update_task_(false), |
kmackay
2016/06/03 17:37:05
initialize last_media_time_ to kNoTimestamp
ejason
2016/06/03 19:20:15
Done.
| |
87 statistics_rolling_counter_(0), | 90 statistics_rolling_counter_(0), |
88 audio_bytes_for_bitrate_estimation_(0), | 91 audio_bytes_for_bitrate_estimation_(0), |
89 video_bytes_for_bitrate_estimation_(0), | 92 video_bytes_for_bitrate_estimation_(0), |
93 playback_stalled_(false), | |
94 playback_stalled_notification_sent_(false), | |
90 weak_factory_(this) { | 95 weak_factory_(this) { |
91 CMALOG(kLogControl) << __FUNCTION__; | 96 CMALOG(kLogControl) << __FUNCTION__; |
92 weak_this_ = weak_factory_.GetWeakPtr(); | 97 weak_this_ = weak_factory_.GetWeakPtr(); |
93 thread_checker_.DetachFromThread(); | 98 thread_checker_.DetachFromThread(); |
94 } | 99 } |
95 | 100 |
96 MediaPipelineImpl::~MediaPipelineImpl() { | 101 MediaPipelineImpl::~MediaPipelineImpl() { |
97 CMALOG(kLogControl) << __FUNCTION__; | 102 CMALOG(kLogControl) << __FUNCTION__; |
98 DCHECK(thread_checker_.CalledOnValidThread()); | 103 DCHECK(thread_checker_.CalledOnValidThread()); |
99 | 104 |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
416 metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent( | 421 metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent( |
417 "Cast.Platform.Pause"); | 422 "Cast.Platform.Pause"); |
418 } else if (!is_buffering && (backend_state_ == BACKEND_STATE_PAUSED)) { | 423 } else if (!is_buffering && (backend_state_ == BACKEND_STATE_PAUSED)) { |
419 // Once we finish buffering, we need to honour the desired playback rate | 424 // Once we finish buffering, we need to honour the desired playback rate |
420 // (rather than just resuming). This way, if playback was paused while | 425 // (rather than just resuming). This way, if playback was paused while |
421 // buffering, it will remain paused rather than incorrectly resuming. | 426 // buffering, it will remain paused rather than incorrectly resuming. |
422 SetPlaybackRate(playback_rate_); | 427 SetPlaybackRate(playback_rate_); |
423 } | 428 } |
424 } | 429 } |
425 | 430 |
431 void MediaPipelineImpl::CheckForPlaybackStall(base::TimeDelta media_time, | |
432 base::TimeTicks current_stc) { | |
kmackay
2016/06/03 17:37:05
what does 'stc' stand for?
ejason
2016/06/03 19:20:15
System time clock. I simply re-used the existing n
| |
433 DCHECK(media_time != ::media::kNoTimestamp()); | |
434 | |
435 // A playback stall is defined as a scenario where the underlying media | |
436 // pipeline has unexpectedly stopped making forward progress. The pipeline is | |
437 // NOT stalled if: | |
438 // | |
439 // 1. Media time is progressing | |
440 // 2. The backend is paused | |
441 // 3. We are currently buffering (this is captured in a separate event) | |
442 if (media_time != last_media_time_ || | |
443 backend_state_ != BACKEND_STATE_PLAYING || | |
444 (buffering_controller_ && buffering_controller_->IsBuffering())) { | |
445 if (playback_stalled_) { | |
446 // Transition out of the stalled condition. | |
447 base::TimeDelta stall_duration = current_stc - playback_stalled_time_; | |
448 CMALOG(kLogControl) | |
449 << "Transitioning out of stalled state. Stall duration was " | |
450 << stall_duration.InMilliseconds() << " ms"; | |
451 playback_stalled_ = false; | |
452 playback_stalled_notification_sent_ = false; | |
453 } | |
454 return; | |
455 } | |
456 | |
457 // Check to see if this is a new stall condition. | |
458 if (!playback_stalled_) { | |
459 playback_stalled_ = true; | |
460 playback_stalled_time_ = current_stc; | |
461 return; | |
462 } | |
463 | |
464 // If we are in an existing stall, check to see if we've been stalled for more | |
465 // than 2.5 s. If so, send a single notification of the stall event. | |
466 if (!playback_stalled_notification_sent_) { | |
467 base::TimeDelta current_stall_duration = | |
468 current_stc - playback_stalled_time_; | |
469 if (current_stall_duration.InMilliseconds() >= | |
470 kPlaybackStallEventThreshold) { | |
471 CMALOG(kLogControl) << "Playback stalled"; | |
472 metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent( | |
473 "Cast.Platform.PlaybackStall"); | |
474 playback_stalled_notification_sent_ = true; | |
475 } | |
476 return; | |
477 } | |
478 } | |
479 | |
426 void MediaPipelineImpl::UpdateMediaTime() { | 480 void MediaPipelineImpl::UpdateMediaTime() { |
427 pending_time_update_task_ = false; | 481 pending_time_update_task_ = false; |
428 if ((backend_state_ != BACKEND_STATE_PLAYING) && | 482 if ((backend_state_ != BACKEND_STATE_PLAYING) && |
429 (backend_state_ != BACKEND_STATE_PAUSED)) | 483 (backend_state_ != BACKEND_STATE_PAUSED)) |
430 return; | 484 return; |
431 | 485 |
432 if (statistics_rolling_counter_ == 0) { | 486 if (statistics_rolling_counter_ == 0) { |
433 if (audio_pipeline_) | 487 if (audio_pipeline_) |
434 audio_pipeline_->UpdateStatistics(); | 488 audio_pipeline_->UpdateStatistics(); |
435 if (video_pipeline_) | 489 if (video_pipeline_) |
(...skipping 30 matching lines...) Expand all Loading... | |
466 media_pipeline_backend_->GetCurrentPts()); | 520 media_pipeline_backend_->GetCurrentPts()); |
467 if (media_time == ::media::kNoTimestamp()) { | 521 if (media_time == ::media::kNoTimestamp()) { |
468 pending_time_update_task_ = true; | 522 pending_time_update_task_ = true; |
469 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 523 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
470 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_), | 524 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_), |
471 kTimeUpdateInterval); | 525 kTimeUpdateInterval); |
472 return; | 526 return; |
473 } | 527 } |
474 base::TimeTicks stc = base::TimeTicks::Now(); | 528 base::TimeTicks stc = base::TimeTicks::Now(); |
475 | 529 |
530 CheckForPlaybackStall(media_time, stc); | |
531 | |
476 base::TimeDelta max_rendering_time = media_time; | 532 base::TimeDelta max_rendering_time = media_time; |
477 if (buffering_controller_) { | 533 if (buffering_controller_) { |
478 buffering_controller_->SetMediaTime(media_time); | 534 buffering_controller_->SetMediaTime(media_time); |
479 | 535 |
480 // Receiving the same time twice in a row means playback isn't moving, | 536 // Receiving the same time twice in a row means playback isn't moving, |
481 // so don't interpolate ahead. | 537 // so don't interpolate ahead. |
482 if (media_time != last_media_time_) { | 538 if (media_time != last_media_time_) { |
483 max_rendering_time = buffering_controller_->GetMaxRenderingTime(); | 539 max_rendering_time = buffering_controller_->GetMaxRenderingTime(); |
484 if (max_rendering_time == ::media::kNoTimestamp()) | 540 if (max_rendering_time == ::media::kNoTimestamp()) |
485 max_rendering_time = media_time; | 541 max_rendering_time = media_time; |
(...skipping 27 matching lines...) Expand all Loading... | |
513 | 569 |
514 void MediaPipelineImpl::ResetBitrateState() { | 570 void MediaPipelineImpl::ResetBitrateState() { |
515 elapsed_time_delta_ = base::TimeDelta::FromSeconds(0); | 571 elapsed_time_delta_ = base::TimeDelta::FromSeconds(0); |
516 audio_bytes_for_bitrate_estimation_ = 0; | 572 audio_bytes_for_bitrate_estimation_ = 0; |
517 video_bytes_for_bitrate_estimation_ = 0; | 573 video_bytes_for_bitrate_estimation_ = 0; |
518 last_sample_time_ = base::TimeTicks::Now(); | 574 last_sample_time_ = base::TimeTicks::Now(); |
519 } | 575 } |
520 | 576 |
521 } // namespace media | 577 } // namespace media |
522 } // namespace chromecast | 578 } // namespace chromecast |
OLD | NEW |