Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: chromecast/media/cma/pipeline/media_pipeline_impl.cc

Issue 1776353006: [Chromecast] Add metrics for logging platform A/V bitrate estimates. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add const qualifier to bytes_decoded accessor Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/callback_helpers.h" 12 #include "base/callback_helpers.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/single_thread_task_runner.h" 15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_piece.h"
16 #include "base/thread_task_runner_handle.h" 17 #include "base/thread_task_runner_handle.h"
17 #include "base/time/time.h"
18 #include "chromecast/base/metrics/cast_metrics_helper.h" 18 #include "chromecast/base/metrics/cast_metrics_helper.h"
19 #include "chromecast/media/cdm/browser_cdm_cast.h" 19 #include "chromecast/media/cdm/browser_cdm_cast.h"
20 #include "chromecast/media/cma/base/buffering_controller.h" 20 #include "chromecast/media/cma/base/buffering_controller.h"
21 #include "chromecast/media/cma/base/buffering_state.h" 21 #include "chromecast/media/cma/base/buffering_state.h"
22 #include "chromecast/media/cma/base/cma_logging.h" 22 #include "chromecast/media/cma/base/cma_logging.h"
23 #include "chromecast/media/cma/base/coded_frame_provider.h" 23 #include "chromecast/media/cma/base/coded_frame_provider.h"
24 #include "chromecast/media/cma/pipeline/audio_decoder_software_wrapper.h" 24 #include "chromecast/media/cma/pipeline/audio_decoder_software_wrapper.h"
25 #include "chromecast/media/cma/pipeline/audio_pipeline_impl.h" 25 #include "chromecast/media/cma/pipeline/audio_pipeline_impl.h"
26 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h" 26 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h"
27 #include "chromecast/public/media/media_pipeline_backend.h" 27 #include "chromecast/public/media/media_pipeline_backend.h"
(...skipping 17 matching lines...) Expand all
45 base::TimeDelta::FromMilliseconds(300)); 45 base::TimeDelta::FromMilliseconds(300));
46 46
47 // Interval between two updates of the media time. 47 // Interval between two updates of the media time.
48 const base::TimeDelta kTimeUpdateInterval( 48 const base::TimeDelta kTimeUpdateInterval(
49 base::TimeDelta::FromMilliseconds(250)); 49 base::TimeDelta::FromMilliseconds(250));
50 50
51 // Interval between two updates of the statistics is equal to: 51 // Interval between two updates of the statistics is equal to:
52 // kTimeUpdateInterval * kStatisticsUpdatePeriod. 52 // kTimeUpdateInterval * kStatisticsUpdatePeriod.
53 const int kStatisticsUpdatePeriod = 4; 53 const int kStatisticsUpdatePeriod = 4;
54 54
55 void LogEstimatedBitrate(int decoded_bytes,
56 base::TimeDelta elapsed_time,
57 base::StringPiece tag,
58 base::StringPiece metric) {
halliwell 2016/03/11 18:12:46 + a nit: No need to use StringPiece here - just pa
ejason 2016/03/11 20:18:07 Done.
59 int estimated_bitrate_in_kbps =
60 8 * decoded_bytes / elapsed_time.InMilliseconds();
61 if (estimated_bitrate_in_kbps > 0) {
kmackay 2016/03/11 17:47:40 nit: invert logic if (bitrate <= 0) return;
ejason 2016/03/11 20:18:07 Done.
62 CMALOG(kLogControl) << "Estimated " << tag.as_string() << " bitrate is "
63 << estimated_bitrate_in_kbps << " kbps";
64 metrics::CastMetricsHelper* metrics_helper =
65 metrics::CastMetricsHelper::GetInstance();
66 metrics_helper->RecordSimpleActionWithValue(metric.as_string(),
67 estimated_bitrate_in_kbps);
68 }
69 }
70
55 } // namespace 71 } // namespace
56 72
57 struct MediaPipelineImpl::FlushTask { 73 struct MediaPipelineImpl::FlushTask {
58 bool audio_flushed; 74 bool audio_flushed;
59 bool video_flushed; 75 bool video_flushed;
60 base::Closure done_cb; 76 base::Closure done_cb;
61 }; 77 };
62 78
63 MediaPipelineImpl::MediaPipelineImpl() 79 MediaPipelineImpl::MediaPipelineImpl()
64 : cdm_(nullptr), 80 : cdm_(nullptr),
65 backend_state_(BACKEND_STATE_UNINITIALIZED), 81 backend_state_(BACKEND_STATE_UNINITIALIZED),
66 playback_rate_(1.0f), 82 playback_rate_(1.0f),
67 audio_decoder_(nullptr), 83 audio_decoder_(nullptr),
68 video_decoder_(nullptr), 84 video_decoder_(nullptr),
69 pending_time_update_task_(false), 85 pending_time_update_task_(false),
70 statistics_rolling_counter_(0), 86 statistics_rolling_counter_(0),
87 last_sample_time_(base::Time::FromInternalValue(0)),
88 elapsed_time_delta_(base::TimeDelta()),
89 video_bytes_for_bitrate_estimation_(0),
71 weak_factory_(this) { 90 weak_factory_(this) {
72 CMALOG(kLogControl) << __FUNCTION__; 91 CMALOG(kLogControl) << __FUNCTION__;
73 weak_this_ = weak_factory_.GetWeakPtr(); 92 weak_this_ = weak_factory_.GetWeakPtr();
74 thread_checker_.DetachFromThread(); 93 thread_checker_.DetachFromThread();
75 } 94 }
76 95
77 MediaPipelineImpl::~MediaPipelineImpl() { 96 MediaPipelineImpl::~MediaPipelineImpl() {
78 CMALOG(kLogControl) << __FUNCTION__; 97 CMALOG(kLogControl) << __FUNCTION__;
79 DCHECK(thread_checker_.CalledOnValidThread()); 98 DCHECK(thread_checker_.CalledOnValidThread());
80 99
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 pending_flush_task_->video_flushed = !video_pipeline_; 286 pending_flush_task_->video_flushed = !video_pipeline_;
268 pending_flush_task_->done_cb = flush_cb; 287 pending_flush_task_->done_cb = flush_cb;
269 if (audio_pipeline_) { 288 if (audio_pipeline_) {
270 audio_pipeline_->Flush( 289 audio_pipeline_->Flush(
271 base::Bind(&MediaPipelineImpl::OnFlushDone, weak_this_, true)); 290 base::Bind(&MediaPipelineImpl::OnFlushDone, weak_this_, true));
272 } 291 }
273 if (video_pipeline_) { 292 if (video_pipeline_) {
274 video_pipeline_->Flush( 293 video_pipeline_->Flush(
275 base::Bind(&MediaPipelineImpl::OnFlushDone, weak_this_, false)); 294 base::Bind(&MediaPipelineImpl::OnFlushDone, weak_this_, false));
276 } 295 }
296 // 4. Invalidate bitrate statistics.
297 ResetBitrateState();
kmackay 2016/03/11 17:47:40 I would rather call this on transition to the "pla
ejason 2016/03/11 20:18:07 Thanks this is a really good idea. Done.
277 } 298 }
278 299
279 void MediaPipelineImpl::Stop() { 300 void MediaPipelineImpl::Stop() {
280 CMALOG(kLogControl) << __FUNCTION__; 301 CMALOG(kLogControl) << __FUNCTION__;
281 DCHECK(thread_checker_.CalledOnValidThread()); 302 DCHECK(thread_checker_.CalledOnValidThread());
282 DCHECK(audio_pipeline_ || video_pipeline_); 303 DCHECK(audio_pipeline_ || video_pipeline_);
283 if (backend_state_ != BACKEND_STATE_UNINITIALIZED) 304 if (backend_state_ != BACKEND_STATE_UNINITIALIZED)
284 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( 305 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction(
285 "Cast.Platform.Ended"); 306 "Cast.Platform.Ended");
286 307
287 // Cancel pending flush callbacks since we are about to stop/shutdown 308 // Cancel pending flush callbacks since we are about to stop/shutdown
288 // audio/video pipelines. This will ensure A/V Flush won't happen in 309 // audio/video pipelines. This will ensure A/V Flush won't happen in
289 // stopped state. 310 // stopped state.
290 pending_flush_task_.reset(); 311 pending_flush_task_.reset();
291 312
292 // Stop both the audio and video pipeline. 313 // Stop both the audio and video pipeline.
293 if (audio_pipeline_) 314 if (audio_pipeline_)
294 audio_pipeline_->Stop(); 315 audio_pipeline_->Stop();
295 if (video_pipeline_) 316 if (video_pipeline_)
296 video_pipeline_->Stop(); 317 video_pipeline_->Stop();
297 318
298 // Release hardware resources on Stop. 319 // Release hardware resources on Stop.
299 audio_pipeline_ = nullptr; 320 audio_pipeline_ = nullptr;
300 video_pipeline_ = nullptr; 321 video_pipeline_ = nullptr;
301 audio_decoder_.reset(); 322 audio_decoder_.reset();
302 media_pipeline_backend_.reset(); 323 media_pipeline_backend_.reset();
324 ResetBitrateState();
303 backend_state_ = BACKEND_STATE_UNINITIALIZED; 325 backend_state_ = BACKEND_STATE_UNINITIALIZED;
304 } 326 }
305 327
306 void MediaPipelineImpl::SetPlaybackRate(double rate) { 328 void MediaPipelineImpl::SetPlaybackRate(double rate) {
307 CMALOG(kLogControl) << __FUNCTION__ << " rate=" << rate; 329 CMALOG(kLogControl) << __FUNCTION__ << " rate=" << rate;
308 DCHECK(thread_checker_.CalledOnValidThread()); 330 DCHECK(thread_checker_.CalledOnValidThread());
309 DCHECK((backend_state_ == BACKEND_STATE_PLAYING) || 331 DCHECK((backend_state_ == BACKEND_STATE_PLAYING) ||
310 (backend_state_ == BACKEND_STATE_PAUSED)); 332 (backend_state_ == BACKEND_STATE_PAUSED));
311 333
312 playback_rate_ = rate; 334 playback_rate_ = rate;
313 if (buffering_controller_ && buffering_controller_->IsBuffering()) 335 if (buffering_controller_ && buffering_controller_->IsBuffering())
314 return; 336 return;
315 337
316 if (rate != 0.0f) { 338 if (rate != 0.0f) {
317 media_pipeline_backend_->SetPlaybackRate(rate); 339 media_pipeline_backend_->SetPlaybackRate(rate);
318 if (backend_state_ == BACKEND_STATE_PAUSED) { 340 if (backend_state_ == BACKEND_STATE_PAUSED) {
319 media_pipeline_backend_->Resume(); 341 media_pipeline_backend_->Resume();
320 backend_state_ = BACKEND_STATE_PLAYING; 342 backend_state_ = BACKEND_STATE_PLAYING;
321 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( 343 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction(
322 "Cast.Platform.Playing"); 344 "Cast.Platform.Playing");
323 } 345 }
324 } else if (backend_state_ == BACKEND_STATE_PLAYING) { 346 } else if (backend_state_ == BACKEND_STATE_PLAYING) {
325 media_pipeline_backend_->Pause(); 347 media_pipeline_backend_->Pause();
348 ResetBitrateState();
326 backend_state_ = BACKEND_STATE_PAUSED; 349 backend_state_ = BACKEND_STATE_PAUSED;
327 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( 350 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction(
328 "Cast.Platform.Pause"); 351 "Cast.Platform.Pause");
329 } 352 }
330 } 353 }
331 354
332 void MediaPipelineImpl::SetVolume(float volume) { 355 void MediaPipelineImpl::SetVolume(float volume) {
333 CMALOG(kLogControl) << __FUNCTION__ << " vol=" << volume; 356 CMALOG(kLogControl) << __FUNCTION__ << " vol=" << volume;
334 DCHECK(thread_checker_.CalledOnValidThread()); 357 DCHECK(thread_checker_.CalledOnValidThread());
335 if (audio_pipeline_) 358 if (audio_pipeline_)
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 // http://crbug.com/144683. 410 // http://crbug.com/144683.
388 LOG(WARNING) << "Ignoring buffering notification."; 411 LOG(WARNING) << "Ignoring buffering notification.";
389 } else { 412 } else {
390 client_.buffering_state_cb.Run(::media::BUFFERING_HAVE_ENOUGH); 413 client_.buffering_state_cb.Run(::media::BUFFERING_HAVE_ENOUGH);
391 } 414 }
392 } 415 }
393 416
394 if (is_buffering && (backend_state_ == BACKEND_STATE_PLAYING)) { 417 if (is_buffering && (backend_state_ == BACKEND_STATE_PLAYING)) {
395 media_pipeline_backend_->Pause(); 418 media_pipeline_backend_->Pause();
396 backend_state_ = BACKEND_STATE_PAUSED; 419 backend_state_ = BACKEND_STATE_PAUSED;
420 ResetBitrateState();
397 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( 421 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction(
398 "Cast.Platform.Pause"); 422 "Cast.Platform.Pause");
399 } else if (!is_buffering && (backend_state_ == BACKEND_STATE_PAUSED)) { 423 } else if (!is_buffering && (backend_state_ == BACKEND_STATE_PAUSED)) {
400 // 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
401 // (rather than just resuming). This way, if playback was paused while 425 // (rather than just resuming). This way, if playback was paused while
402 // buffering, it will remain paused rather than incorrectly resuming. 426 // buffering, it will remain paused rather than incorrectly resuming.
403 SetPlaybackRate(playback_rate_); 427 SetPlaybackRate(playback_rate_);
404 } 428 }
405 } 429 }
406 430
407 void MediaPipelineImpl::UpdateMediaTime() { 431 void MediaPipelineImpl::UpdateMediaTime() {
408 pending_time_update_task_ = false; 432 pending_time_update_task_ = false;
409 if ((backend_state_ != BACKEND_STATE_PLAYING) && 433 if ((backend_state_ != BACKEND_STATE_PLAYING) &&
410 (backend_state_ != BACKEND_STATE_PAUSED)) 434 (backend_state_ != BACKEND_STATE_PAUSED))
411 return; 435 return;
412 436
413 if (statistics_rolling_counter_ == 0) { 437 if (statistics_rolling_counter_ == 0) {
414 if (audio_pipeline_) 438 if (audio_pipeline_)
415 audio_pipeline_->UpdateStatistics(); 439 audio_pipeline_->UpdateStatistics();
416 if (video_pipeline_) 440 if (video_pipeline_)
417 video_pipeline_->UpdateStatistics(); 441 video_pipeline_->UpdateStatistics();
442
443 base::Time current_time = base::Time::Now();
kmackay 2016/03/11 17:47:40 Get the current time within the if statement
ejason 2016/03/11 20:18:07 Done.
444 if (!last_sample_time_.is_null() &&
kmackay 2016/03/11 17:47:40 If you change it to reset just when we enter the p
ejason 2016/03/11 20:18:07 Done.
445 backend_state_ == BACKEND_STATE_PLAYING) {
446 audio_bytes_for_bitrate_estimation_ +=
447 audio_pipeline_->bytes_decoded_since_last_update();
448 video_bytes_for_bitrate_estimation_ +=
449 video_pipeline_->bytes_decoded_since_last_update();
450 elapsed_time_delta_ += current_time - last_sample_time_;
451 if (elapsed_time_delta_.InMilliseconds() > 5000) {
452 LogEstimatedBitrate(audio_bytes_for_bitrate_estimation_,
453 elapsed_time_delta_, "audio",
454 "Cast.Platform.AudioBitrate");
455 LogEstimatedBitrate(video_bytes_for_bitrate_estimation_,
456 elapsed_time_delta_, "video",
457 "Cast.Platform.VideoBitrate");
458 ResetBitrateState();
459 }
460 }
461 if (backend_state_ == BACKEND_STATE_PLAYING) {
462 last_sample_time_ = current_time;
463 }
418 } 464 }
465
419 statistics_rolling_counter_ = 466 statistics_rolling_counter_ =
420 (statistics_rolling_counter_ + 1) % kStatisticsUpdatePeriod; 467 (statistics_rolling_counter_ + 1) % kStatisticsUpdatePeriod;
421 468
422 base::TimeDelta media_time = base::TimeDelta::FromMicroseconds( 469 base::TimeDelta media_time = base::TimeDelta::FromMicroseconds(
423 media_pipeline_backend_->GetCurrentPts()); 470 media_pipeline_backend_->GetCurrentPts());
424 if (media_time == ::media::kNoTimestamp()) { 471 if (media_time == ::media::kNoTimestamp()) {
425 pending_time_update_task_ = true; 472 pending_time_update_task_ = true;
426 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 473 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
427 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_), 474 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_),
428 kTimeUpdateInterval); 475 kTimeUpdateInterval);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 DCHECK(thread_checker_.CalledOnValidThread()); 508 DCHECK(thread_checker_.CalledOnValidThread());
462 DCHECK_NE(error, ::media::PIPELINE_OK) << "PIPELINE_OK is not an error!"; 509 DCHECK_NE(error, ::media::PIPELINE_OK) << "PIPELINE_OK is not an error!";
463 510
464 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( 511 metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction(
465 "Cast.Platform.Error"); 512 "Cast.Platform.Error");
466 513
467 if (!client_.error_cb.is_null()) 514 if (!client_.error_cb.is_null())
468 client_.error_cb.Run(error); 515 client_.error_cb.Run(error);
469 } 516 }
470 517
518 void MediaPipelineImpl::ResetBitrateState() {
519 elapsed_time_delta_ = base::TimeDelta::FromSeconds(0);
520 audio_bytes_for_bitrate_estimation_ = 0;
521 video_bytes_for_bitrate_estimation_ = 0;
522 last_sample_time_ = base::Time::FromInternalValue(0);
523 }
524
471 } // namespace media 525 } // namespace media
472 } // namespace chromecast 526 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698