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; | |
alokp
2016/06/03 19:55:28
Add "Ms" suffix to make the unit clear.
ejason
2016/06/03 21:18:31
Done.
| |
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 13 matching lines...) Expand all Loading... | |
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), |
90 last_media_time_(::media::kNoTimestamp()), | |
87 statistics_rolling_counter_(0), | 91 statistics_rolling_counter_(0), |
88 audio_bytes_for_bitrate_estimation_(0), | 92 audio_bytes_for_bitrate_estimation_(0), |
89 video_bytes_for_bitrate_estimation_(0), | 93 video_bytes_for_bitrate_estimation_(0), |
94 playback_stalled_(false), | |
95 playback_stalled_notification_sent_(false), | |
90 weak_factory_(this) { | 96 weak_factory_(this) { |
91 CMALOG(kLogControl) << __FUNCTION__; | 97 CMALOG(kLogControl) << __FUNCTION__; |
92 weak_this_ = weak_factory_.GetWeakPtr(); | 98 weak_this_ = weak_factory_.GetWeakPtr(); |
93 thread_checker_.DetachFromThread(); | 99 thread_checker_.DetachFromThread(); |
94 } | 100 } |
95 | 101 |
96 MediaPipelineImpl::~MediaPipelineImpl() { | 102 MediaPipelineImpl::~MediaPipelineImpl() { |
97 CMALOG(kLogControl) << __FUNCTION__; | 103 CMALOG(kLogControl) << __FUNCTION__; |
98 DCHECK(thread_checker_.CalledOnValidThread()); | 104 DCHECK(thread_checker_.CalledOnValidThread()); |
99 | 105 |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
416 metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent( | 422 metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent( |
417 "Cast.Platform.Pause"); | 423 "Cast.Platform.Pause"); |
418 } else if (!is_buffering && (backend_state_ == BACKEND_STATE_PAUSED)) { | 424 } else if (!is_buffering && (backend_state_ == BACKEND_STATE_PAUSED)) { |
419 // Once we finish buffering, we need to honour the desired playback rate | 425 // Once we finish buffering, we need to honour the desired playback rate |
420 // (rather than just resuming). This way, if playback was paused while | 426 // (rather than just resuming). This way, if playback was paused while |
421 // buffering, it will remain paused rather than incorrectly resuming. | 427 // buffering, it will remain paused rather than incorrectly resuming. |
422 SetPlaybackRate(playback_rate_); | 428 SetPlaybackRate(playback_rate_); |
423 } | 429 } |
424 } | 430 } |
425 | 431 |
432 void MediaPipelineImpl::CheckForPlaybackStall(base::TimeDelta media_time, | |
433 base::TimeTicks current_stc) { | |
434 DCHECK(media_time != ::media::kNoTimestamp()); | |
435 | |
436 // A playback stall is defined as a scenario where the underlying media | |
437 // pipeline has unexpectedly stopped making forward progress. The pipeline is | |
438 // NOT stalled if: | |
439 // | |
440 // 1. Media time is progressing | |
441 // 2. The backend is paused | |
442 // 3. We are currently buffering (this is captured in a separate event) | |
443 if (media_time != last_media_time_ || | |
444 backend_state_ != BACKEND_STATE_PLAYING || | |
445 (buffering_controller_ && buffering_controller_->IsBuffering())) { | |
446 if (playback_stalled_) { | |
447 // Transition out of the stalled condition. | |
448 base::TimeDelta stall_duration = current_stc - playback_stalled_time_; | |
449 CMALOG(kLogControl) | |
450 << "Transitioning out of stalled state. Stall duration was " | |
451 << stall_duration.InMilliseconds() << " ms"; | |
452 playback_stalled_ = false; | |
453 playback_stalled_notification_sent_ = false; | |
454 } | |
455 return; | |
456 } | |
457 | |
458 // Check to see if this is a new stall condition. | |
459 if (!playback_stalled_) { | |
460 playback_stalled_ = true; | |
461 playback_stalled_time_ = current_stc; | |
462 return; | |
463 } | |
464 | |
465 // If we are in an existing stall, check to see if we've been stalled for more | |
466 // than 2.5 s. If so, send a single notification of the stall event. | |
467 if (!playback_stalled_notification_sent_) { | |
468 base::TimeDelta current_stall_duration = | |
469 current_stc - playback_stalled_time_; | |
470 if (current_stall_duration.InMilliseconds() >= | |
471 kPlaybackStallEventThreshold) { | |
472 CMALOG(kLogControl) << "Playback stalled"; | |
473 metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent( | |
474 "Cast.Platform.PlaybackStall"); | |
475 playback_stalled_notification_sent_ = true; | |
476 } | |
477 return; | |
478 } | |
479 } | |
480 | |
426 void MediaPipelineImpl::UpdateMediaTime() { | 481 void MediaPipelineImpl::UpdateMediaTime() { |
427 pending_time_update_task_ = false; | 482 pending_time_update_task_ = false; |
428 if ((backend_state_ != BACKEND_STATE_PLAYING) && | 483 if ((backend_state_ != BACKEND_STATE_PLAYING) && |
429 (backend_state_ != BACKEND_STATE_PAUSED)) | 484 (backend_state_ != BACKEND_STATE_PAUSED)) |
430 return; | 485 return; |
431 | 486 |
432 if (statistics_rolling_counter_ == 0) { | 487 if (statistics_rolling_counter_ == 0) { |
433 if (audio_pipeline_) | 488 if (audio_pipeline_) |
434 audio_pipeline_->UpdateStatistics(); | 489 audio_pipeline_->UpdateStatistics(); |
435 if (video_pipeline_) | 490 if (video_pipeline_) |
(...skipping 30 matching lines...) Expand all Loading... | |
466 media_pipeline_backend_->GetCurrentPts()); | 521 media_pipeline_backend_->GetCurrentPts()); |
467 if (media_time == ::media::kNoTimestamp()) { | 522 if (media_time == ::media::kNoTimestamp()) { |
468 pending_time_update_task_ = true; | 523 pending_time_update_task_ = true; |
469 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 524 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
470 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_), | 525 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_), |
471 kTimeUpdateInterval); | 526 kTimeUpdateInterval); |
472 return; | 527 return; |
473 } | 528 } |
474 base::TimeTicks stc = base::TimeTicks::Now(); | 529 base::TimeTicks stc = base::TimeTicks::Now(); |
475 | 530 |
531 CheckForPlaybackStall(media_time, stc); | |
532 | |
476 base::TimeDelta max_rendering_time = media_time; | 533 base::TimeDelta max_rendering_time = media_time; |
477 if (buffering_controller_) { | 534 if (buffering_controller_) { |
478 buffering_controller_->SetMediaTime(media_time); | 535 buffering_controller_->SetMediaTime(media_time); |
479 | 536 |
480 // Receiving the same time twice in a row means playback isn't moving, | 537 // Receiving the same time twice in a row means playback isn't moving, |
481 // so don't interpolate ahead. | 538 // so don't interpolate ahead. |
482 if (media_time != last_media_time_) { | 539 if (media_time != last_media_time_) { |
483 max_rendering_time = buffering_controller_->GetMaxRenderingTime(); | 540 max_rendering_time = buffering_controller_->GetMaxRenderingTime(); |
484 if (max_rendering_time == ::media::kNoTimestamp()) | 541 if (max_rendering_time == ::media::kNoTimestamp()) |
485 max_rendering_time = media_time; | 542 max_rendering_time = media_time; |
(...skipping 27 matching lines...) Expand all Loading... | |
513 | 570 |
514 void MediaPipelineImpl::ResetBitrateState() { | 571 void MediaPipelineImpl::ResetBitrateState() { |
515 elapsed_time_delta_ = base::TimeDelta::FromSeconds(0); | 572 elapsed_time_delta_ = base::TimeDelta::FromSeconds(0); |
516 audio_bytes_for_bitrate_estimation_ = 0; | 573 audio_bytes_for_bitrate_estimation_ = 0; |
517 video_bytes_for_bitrate_estimation_ = 0; | 574 video_bytes_for_bitrate_estimation_ = 0; |
518 last_sample_time_ = base::TimeTicks::Now(); | 575 last_sample_time_ = base::TimeTicks::Now(); |
519 } | 576 } |
520 | 577 |
521 } // namespace media | 578 } // namespace media |
522 } // namespace chromecast | 579 } // namespace chromecast |
OLD | NEW |