Introduce VideoDecodeStatsReporter for Media Capabilities
Each WebMediaPlayer will create a VideoDecodeStatsReporter to send
smoothness (and eventually power) statistics across to the browser-side
VideoDecodeStatsRecorder.
The statistics will be "finalized" upon
- player destruction
- significant media property changes (e.g. resolution, codec, fps)
- tab close
Follow up CLs will implement the browser-side recording of the stats
and add a UMA to "grade" the media capabilites API by comparing the
observed stats against the API's claims of smoothness.
Bug: 695264
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_site_isolation;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I78ca453fa936c9a48813fbc92dc67714f9956f63
Reviewed-on: https://chromium-review.googlesource.com/570920
Commit-Queue: Chrome Cunningham <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Dale Curtis <[email protected]>
Reviewed-by: Charlie Reis <[email protected]>
Cr-Commit-Position: refs/heads/master@{#497948}
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 8bdd7ee..637c89d 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -41,6 +41,7 @@
#include "media/base/timestamp_constants.h"
#include "media/base/video_frame.h"
#include "media/blink/texttrack_impl.h"
+#include "media/blink/video_decode_stats_reporter.h"
#include "media/blink/watch_time_reporter.h"
#include "media/blink/webaudiosourceprovider_impl.h"
#include "media/blink/webcontentdecryptionmodule_impl.h"
@@ -254,7 +255,9 @@
base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo)),
request_routing_token_cb_(params->request_routing_token_cb()),
overlay_routing_token_(OverlayInfo::RoutingToken()),
- watch_time_recorder_provider_(params->watch_time_recorder_provider()) {
+ watch_time_recorder_provider_(params->watch_time_recorder_provider()),
+ create_decode_stats_recorder_cb_(
+ params->create_capabilities_recorder_cb()) {
DVLOG(1) << __func__;
DCHECK(!adjust_allocated_memory_cb_.is_null());
DCHECK(renderer_factory_selector_);
@@ -550,6 +553,9 @@
watch_time_reporter_->OnPlaying();
}
+ if (video_decode_stats_reporter_)
+ video_decode_stats_reporter_->OnPlaying();
+
media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
UpdatePlayState();
}
@@ -585,6 +591,10 @@
DCHECK(watch_time_reporter_);
watch_time_reporter_->OnPaused();
+
+ if (video_decode_stats_reporter_)
+ video_decode_stats_reporter_->OnPaused();
+
media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
UpdatePlayState();
@@ -1103,6 +1113,9 @@
if (!was_encrypted && watch_time_reporter_)
CreateWatchTimeReporter();
+ // For now MediaCapabilities only handles clear content.
+ video_decode_stats_reporter_.reset();
+
SetCdm(cdm);
}
@@ -1120,6 +1133,9 @@
if (!was_encrypted && watch_time_reporter_)
CreateWatchTimeReporter();
+ // For now MediaCapabilities only handles clear content.
+ video_decode_stats_reporter_.reset();
+
encrypted_client_->Encrypted(
ConvertToWebInitDataType(init_data_type), init_data.data(),
base::saturated_cast<unsigned int>(init_data.size()));
@@ -1415,9 +1431,44 @@
observer_->OnMetadataChanged(pipeline_metadata_);
CreateWatchTimeReporter();
+ CreateVideoDecodeStatsReporter();
UpdatePlayState();
}
+void WebMediaPlayerImpl::CreateVideoDecodeStatsReporter() {
+ // TODO(chcunningham): destroy reporter if we initially have video but the
+ // track gets disabled. Currently not possible in default desktop Chrome.
+ if (!HasVideo())
+ return;
+
+ // Stats reporter requires a valid config. We may not have one for HLS cases
+ // where URL demuxer doesn't know details of the stream.
+ if (!pipeline_metadata_.video_decoder_config.IsValidConfig())
+ return;
+
+ // For now MediaCapabilities only handles clear content.
+ // TODO(chcunningham): Report encrypted stats.
+ if (is_encrypted_)
+ return;
+
+ // Create capabilities reporter and synchronize its initial state.
+ video_decode_stats_reporter_.reset(new VideoDecodeStatsReporter(
+ create_decode_stats_recorder_cb_.Run(),
+ base::Bind(&WebMediaPlayerImpl::GetPipelineStatistics,
+ base::Unretained(this)),
+ pipeline_metadata_.video_decoder_config));
+
+ if (delegate_->IsFrameHidden())
+ video_decode_stats_reporter_->OnHidden();
+ else
+ video_decode_stats_reporter_->OnShown();
+
+ if (paused_)
+ video_decode_stats_reporter_->OnPaused();
+ else
+ video_decode_stats_reporter_->OnPlaying();
+}
+
void WebMediaPlayerImpl::OnProgress() {
DVLOG(4) << __func__;
if (highest_ready_state_ < ReadyState::kReadyStateHaveFutureData) {
@@ -1576,6 +1627,9 @@
if (!watch_time_reporter_->IsSizeLargeEnoughToReportWatchTime())
CreateWatchTimeReporter();
+ if (video_decode_stats_reporter_)
+ video_decode_stats_reporter_->OnNaturalSizeChanged(rotated_size);
+
if (overlay_enabled_ && surface_manager_ &&
overlay_mode_ == OverlayMode::kUseContentVideoView) {
surface_manager_->NaturalSizeChanged(rotated_size);
@@ -1624,6 +1678,9 @@
if (observer_)
observer_->OnMetadataChanged(pipeline_metadata_);
+
+ if (video_decode_stats_reporter_)
+ video_decode_stats_reporter_->OnVideoConfigChanged(config);
}
void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
@@ -1643,6 +1700,9 @@
if (watch_time_reporter_)
watch_time_reporter_->OnHidden();
+ if (video_decode_stats_reporter_)
+ video_decode_stats_reporter_->OnHidden();
+
UpdateBackgroundVideoOptimizationState();
UpdatePlayState();
@@ -1674,6 +1734,9 @@
if (watch_time_reporter_)
watch_time_reporter_->OnShown();
+ if (video_decode_stats_reporter_)
+ video_decode_stats_reporter_->OnShown();
+
// Only track the time to the first frame if playing or about to play because
// of being shown and only for videos we would optimize background playback
// for.
@@ -1778,6 +1841,9 @@
void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) {
DoSeek(base::TimeDelta::FromSecondsD(t), false);
+ // Capabilities reporting can resume now that playback is local.
+ CreateVideoDecodeStatsReporter();
+
// |client_| might destroy us in methods below.
UpdatePlayState();
@@ -1787,6 +1853,9 @@
}
void WebMediaPlayerImpl::SuspendForRemote() {
+ // Capabilities reporting should only be performed for local playbacks.
+ video_decode_stats_reporter_.reset();
+
if (pipeline_controller_.IsPipelineSuspended() &&
!IsNewRemotePlaybackPipelineEnabled()) {
scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner();
@@ -1993,6 +2062,10 @@
// TODO(tguilbert/avayvod): Update this flag when removing |cast_impl_|.
using_media_player_renderer_ = true;
+ // MediaPlayerRenderer does not provide pipeline stats, so nuke capabilities
+ // reporter.
+ video_decode_stats_reporter_.reset();
+
demuxer_.reset(new MediaUrlDemuxer(media_task_runner_, loaded_url_,
frame_->GetDocument().SiteForCookies()));
pipeline_controller_.Start(demuxer_.get(), this, false, false);
@@ -2670,6 +2743,10 @@
const std::string& remote_device_friendly_name) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
disable_pipeline_auto_suspend_ = true;
+
+ // Capabilities reporting should only be performed for local playbacks.
+ video_decode_stats_reporter_.reset();
+
// Requests to restart media pipeline. A remote renderer will be created via
// the |renderer_factory_selector_|.
ScheduleRestart();
@@ -2682,6 +2759,10 @@
void WebMediaPlayerImpl::SwitchToLocalRenderer() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
disable_pipeline_auto_suspend_ = false;
+
+ // Capabilities reporting may resume now that playback is local.
+ CreateVideoDecodeStatsReporter();
+
// Requests to restart media pipeline. A local renderer will be created via
// the |renderer_factory_selector_|.
ScheduleRestart();