Commit c4bfb0e6 authored by avayvod's avatar avayvod Committed by Commit bot

[Video] Disable bg optimization if avg keyframe distance is >10s

Just picked 10s arbitratily before we have a way to set this value via
Finch. Sending this out to see if collecting the average keyframe
distance and passing it via PipelineStatistics sounds reasonable.

BUG=663999
TEST=manual

Review-Url: https://codereview.chromium.org/2611333003
Cr-Commit-Position: refs/heads/master@{#443424}
parent c805e129
...@@ -647,6 +647,8 @@ void PipelineImpl::RendererWrapper::OnStatisticsUpdate( ...@@ -647,6 +647,8 @@ void PipelineImpl::RendererWrapper::OnStatisticsUpdate(
shared_state_.statistics.video_frames_dropped += stats.video_frames_dropped; shared_state_.statistics.video_frames_dropped += stats.video_frames_dropped;
shared_state_.statistics.audio_memory_usage += stats.audio_memory_usage; shared_state_.statistics.audio_memory_usage += stats.audio_memory_usage;
shared_state_.statistics.video_memory_usage += stats.video_memory_usage; shared_state_.statistics.video_memory_usage += stats.video_memory_usage;
shared_state_.statistics.video_keyframe_distance_average =
stats.video_keyframe_distance_average;
} }
void PipelineImpl::RendererWrapper::OnBufferingStateChange( void PipelineImpl::RendererWrapper::OnBufferingStateChange(
......
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
#ifndef MEDIA_BASE_PIPELINE_STATUS_H_ #ifndef MEDIA_BASE_PIPELINE_STATUS_H_
#define MEDIA_BASE_PIPELINE_STATUS_H_ #define MEDIA_BASE_PIPELINE_STATUS_H_
#include "base/callback.h"
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include "base/callback.h"
#include "base/time/time.h"
namespace media { namespace media {
// Status states for pipeline. All codes except PIPELINE_OK indicate errors. // Status states for pipeline. All codes except PIPELINE_OK indicate errors.
...@@ -59,6 +59,7 @@ struct PipelineStatistics { ...@@ -59,6 +59,7 @@ struct PipelineStatistics {
uint32_t video_frames_dropped = 0; uint32_t video_frames_dropped = 0;
int64_t audio_memory_usage = 0; int64_t audio_memory_usage = 0;
int64_t video_memory_usage = 0; int64_t video_memory_usage = 0;
base::TimeDelta video_keyframe_distance_average;
}; };
// Used for updating pipeline statistics; the passed value should be a delta // Used for updating pipeline statistics; the passed value should be a delta
......
...@@ -887,28 +887,28 @@ double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const { ...@@ -887,28 +887,28 @@ double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
unsigned WebMediaPlayerImpl::decodedFrameCount() const { unsigned WebMediaPlayerImpl::decodedFrameCount() const {
DCHECK(main_task_runner_->BelongsToCurrentThread()); DCHECK(main_task_runner_->BelongsToCurrentThread());
PipelineStatistics stats = pipeline_.GetStatistics(); PipelineStatistics stats = GetPipelineStatistics();
return stats.video_frames_decoded; return stats.video_frames_decoded;
} }
unsigned WebMediaPlayerImpl::droppedFrameCount() const { unsigned WebMediaPlayerImpl::droppedFrameCount() const {
DCHECK(main_task_runner_->BelongsToCurrentThread()); DCHECK(main_task_runner_->BelongsToCurrentThread());
PipelineStatistics stats = pipeline_.GetStatistics(); PipelineStatistics stats = GetPipelineStatistics();
return stats.video_frames_dropped; return stats.video_frames_dropped;
} }
size_t WebMediaPlayerImpl::audioDecodedByteCount() const { size_t WebMediaPlayerImpl::audioDecodedByteCount() const {
DCHECK(main_task_runner_->BelongsToCurrentThread()); DCHECK(main_task_runner_->BelongsToCurrentThread());
PipelineStatistics stats = pipeline_.GetStatistics(); PipelineStatistics stats = GetPipelineStatistics();
return stats.audio_bytes_decoded; return stats.audio_bytes_decoded;
} }
size_t WebMediaPlayerImpl::videoDecodedByteCount() const { size_t WebMediaPlayerImpl::videoDecodedByteCount() const {
DCHECK(main_task_runner_->BelongsToCurrentThread()); DCHECK(main_task_runner_->BelongsToCurrentThread());
PipelineStatistics stats = pipeline_.GetStatistics(); PipelineStatistics stats = GetPipelineStatistics();
return stats.video_bytes_decoded; return stats.video_bytes_decoded;
} }
...@@ -2005,7 +2005,7 @@ void WebMediaPlayerImpl::ReportMemoryUsage() { ...@@ -2005,7 +2005,7 @@ void WebMediaPlayerImpl::ReportMemoryUsage() {
void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) { void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
DCHECK(main_task_runner_->BelongsToCurrentThread()); DCHECK(main_task_runner_->BelongsToCurrentThread());
const PipelineStatistics stats = pipeline_.GetStatistics(); const PipelineStatistics stats = GetPipelineStatistics();
const int64_t data_source_memory_usage = const int64_t data_source_memory_usage =
data_source_ ? data_source_->GetMemoryUsage() : 0; data_source_ ? data_source_->GetMemoryUsage() : 0;
const int64_t current_memory_usage = const int64_t current_memory_usage =
...@@ -2107,9 +2107,17 @@ bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const { ...@@ -2107,9 +2107,17 @@ bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const {
} }
bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const { bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK(IsHidden()); DCHECK(IsHidden());
return IsBackgroundVideoTrackOptimizationEnabled() && hasVideo() &&
hasAudio() && !IsStreaming(); if (!IsBackgroundVideoTrackOptimizationEnabled() || !hasVideo() ||
!hasAudio() || IsStreaming()) {
return false;
}
PipelineStatistics stats = GetPipelineStatistics();
return stats.video_keyframe_distance_average <
max_keyframe_distance_to_disable_background_video_;
} }
void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() { void WebMediaPlayerImpl::EnableVideoTrackIfNeeded() {
...@@ -2141,4 +2149,15 @@ void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() { ...@@ -2141,4 +2149,15 @@ void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() {
} }
} }
void WebMediaPlayerImpl::SetPipelineStatisticsForTest(
const PipelineStatistics& stats) {
pipeline_statistics_for_test_ = base::make_optional(stats);
}
PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return pipeline_statistics_for_test_.value_or(pipeline_.GetStatistics());
}
} // namespace media } // namespace media
...@@ -17,8 +17,10 @@ ...@@ -17,8 +17,10 @@
#include "base/memory/linked_ptr.h" #include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/time/default_tick_clock.h" #include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h" #include "base/timer/elapsed_timer.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -395,6 +397,12 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl ...@@ -395,6 +397,12 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl
// - right after the pipeline has resumed if the video is not hidden. // - right after the pipeline has resumed if the video is not hidden.
void EnableVideoTrackIfNeeded(); void EnableVideoTrackIfNeeded();
// Overrides the pipeline statistics returned by GetStatistics() for tests.
void SetPipelineStatisticsForTest(const PipelineStatistics& stats);
// Returns the pipeline statistics or the value overridden by tests.
PipelineStatistics GetPipelineStatistics() const;
blink::WebLocalFrame* frame_; blink::WebLocalFrame* frame_;
// The playback state last reported to |delegate_|, to avoid setting duplicate // The playback state last reported to |delegate_|, to avoid setting duplicate
...@@ -623,12 +631,21 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl ...@@ -623,12 +631,21 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl
// Whether the player is currently in autoplay muted state. // Whether the player is currently in autoplay muted state.
bool autoplay_muted_ = false; bool autoplay_muted_ = false;
// The maximum video keyframe distance that allows triggering background
// playback optimizations.
// 10 seconds by default but can be overridden by a Finch experiment.
base::TimeDelta max_keyframe_distance_to_disable_background_video_ =
base::TimeDelta::FromSeconds(10);
// Whether disabled the video track as an optimization. // Whether disabled the video track as an optimization.
bool video_track_disabled_ = false; bool video_track_disabled_ = false;
// Whether the pipeline is being resumed at the moment. // Whether the pipeline is being resumed at the moment.
bool is_pipeline_resuming_ = false; bool is_pipeline_resuming_ = false;
// Pipeline statistics overridden by tests.
base::Optional<PipelineStatistics> pipeline_statistics_for_test_;
DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl); DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
}; };
......
...@@ -263,6 +263,12 @@ class WebMediaPlayerImplTest : public testing::Test { ...@@ -263,6 +263,12 @@ class WebMediaPlayerImplTest : public testing::Test {
return wmpi_->ShouldDisableVideoWhenHidden(); return wmpi_->ShouldDisableVideoWhenHidden();
} }
void SetVideoKeyframeDistanceAverage(base::TimeDelta value) {
PipelineStatistics statistics;
statistics.video_keyframe_distance_average = value;
wmpi_->SetPipelineStatisticsForTest(statistics);
}
// "Renderer" thread. // "Renderer" thread.
base::MessageLoop message_loop_; base::MessageLoop message_loop_;
...@@ -775,6 +781,7 @@ TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHidden) { ...@@ -775,6 +781,7 @@ TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHidden) {
SetBackgroundVideoOptimization(true); SetBackgroundVideoOptimization(true);
SetMetadata(true, true); SetMetadata(true, true);
SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(5));
EXPECT_TRUE(ShouldDisableVideoWhenHidden()); EXPECT_TRUE(ShouldDisableVideoWhenHidden());
SetMetadata(false, true); SetMetadata(false, true);
...@@ -782,6 +789,10 @@ TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHidden) { ...@@ -782,6 +789,10 @@ TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHidden) {
SetMetadata(true, false); SetMetadata(true, false);
EXPECT_FALSE(ShouldDisableVideoWhenHidden()); EXPECT_FALSE(ShouldDisableVideoWhenHidden());
SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(100));
SetMetadata(true, true);
EXPECT_FALSE(ShouldDisableVideoWhenHidden());
} }
TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHiddenFeatureDisabled) { TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHiddenFeatureDisabled) {
......
...@@ -458,7 +458,7 @@ void DecoderStream<StreamType>::OnDecodeDone(int buffer_size, ...@@ -458,7 +458,7 @@ void DecoderStream<StreamType>::OnDecodeDone(int buffer_size,
case DecodeStatus::OK: case DecodeStatus::OK:
// Any successful decode counts! // Any successful decode counts!
if (buffer_size > 0) if (buffer_size > 0)
StreamTraits::ReportStatistics(statistics_cb_, buffer_size); traits_.ReportStatistics(statistics_cb_, buffer_size);
if (state_ == STATE_NORMAL) { if (state_ == STATE_NORMAL) {
if (end_of_stream) { if (end_of_stream) {
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "media/filters/decoder_stream_traits.h" #include "media/filters/decoder_stream_traits.h"
#include <limits>
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "media/base/audio_buffer.h" #include "media/base/audio_buffer.h"
...@@ -27,15 +29,6 @@ bool DecoderStreamTraits<DemuxerStream::AUDIO>::NeedsBitstreamConversion( ...@@ -27,15 +29,6 @@ bool DecoderStreamTraits<DemuxerStream::AUDIO>::NeedsBitstreamConversion(
return decoder->NeedsBitstreamConversion(); return decoder->NeedsBitstreamConversion();
} }
// static
void DecoderStreamTraits<DemuxerStream::AUDIO>::ReportStatistics(
const StatisticsCB& statistics_cb,
int bytes_decoded) {
PipelineStatistics statistics;
statistics.audio_bytes_decoded = bytes_decoded;
statistics_cb.Run(statistics);
}
// static // static
scoped_refptr<DecoderStreamTraits<DemuxerStream::AUDIO>::OutputType> scoped_refptr<DecoderStreamTraits<DemuxerStream::AUDIO>::OutputType>
DecoderStreamTraits<DemuxerStream::AUDIO>::CreateEOSOutput() { DecoderStreamTraits<DemuxerStream::AUDIO>::CreateEOSOutput() {
...@@ -46,6 +39,14 @@ DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderStreamTraits( ...@@ -46,6 +39,14 @@ DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderStreamTraits(
const scoped_refptr<MediaLog>& media_log) const scoped_refptr<MediaLog>& media_log)
: media_log_(media_log) {} : media_log_(media_log) {}
void DecoderStreamTraits<DemuxerStream::AUDIO>::ReportStatistics(
const StatisticsCB& statistics_cb,
int bytes_decoded) {
PipelineStatistics statistics;
statistics.audio_bytes_decoded = bytes_decoded;
statistics_cb.Run(statistics);
}
void DecoderStreamTraits<DemuxerStream::AUDIO>::InitializeDecoder( void DecoderStreamTraits<DemuxerStream::AUDIO>::InitializeDecoder(
DecoderType* decoder, DecoderType* decoder,
DemuxerStream* stream, DemuxerStream* stream,
...@@ -90,18 +91,32 @@ bool DecoderStreamTraits<DemuxerStream::VIDEO>::NeedsBitstreamConversion( ...@@ -90,18 +91,32 @@ bool DecoderStreamTraits<DemuxerStream::VIDEO>::NeedsBitstreamConversion(
} }
// static // static
scoped_refptr<DecoderStreamTraits<DemuxerStream::VIDEO>::OutputType>
DecoderStreamTraits<DemuxerStream::VIDEO>::CreateEOSOutput() {
return OutputType::CreateEOSFrame();
}
DecoderStreamTraits<DemuxerStream::VIDEO>::DecoderStreamTraits(
const scoped_refptr<MediaLog>& media_log)
// Randomly selected number of samples to keep.
: keyframe_distance_average_(16) {}
void DecoderStreamTraits<DemuxerStream::VIDEO>::ReportStatistics( void DecoderStreamTraits<DemuxerStream::VIDEO>::ReportStatistics(
const StatisticsCB& statistics_cb, const StatisticsCB& statistics_cb,
int bytes_decoded) { int bytes_decoded) {
PipelineStatistics statistics; PipelineStatistics statistics;
statistics.video_bytes_decoded = bytes_decoded; statistics.video_bytes_decoded = bytes_decoded;
statistics_cb.Run(statistics);
}
// static // Before we have enough keyframes to calculate the average distance, we will
scoped_refptr<DecoderStreamTraits<DemuxerStream::VIDEO>::OutputType> // assume the average keyframe distance is infinitely large.
DecoderStreamTraits<DemuxerStream::VIDEO>::CreateEOSOutput() { if (keyframe_distance_average_.count() < 3) {
return OutputType::CreateEOSFrame(); statistics.video_keyframe_distance_average = base::TimeDelta::Max();
} else {
statistics.video_keyframe_distance_average =
keyframe_distance_average_.Average();
}
statistics_cb.Run(statistics);
} }
void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder( void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder(
...@@ -120,6 +135,7 @@ void DecoderStreamTraits<DemuxerStream::VIDEO>::OnStreamReset( ...@@ -120,6 +135,7 @@ void DecoderStreamTraits<DemuxerStream::VIDEO>::OnStreamReset(
DemuxerStream* stream) { DemuxerStream* stream) {
DCHECK(stream); DCHECK(stream);
last_keyframe_timestamp_ = base::TimeDelta(); last_keyframe_timestamp_ = base::TimeDelta();
keyframe_distance_average_.Reset();
} }
void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode( void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode(
...@@ -141,10 +157,11 @@ void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode( ...@@ -141,10 +157,11 @@ void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode(
return; return;
} }
UMA_HISTOGRAM_MEDIUM_TIMES( base::TimeDelta frame_distance =
"Media.Video.KeyFrameDistance", current_frame_timestamp - last_keyframe_timestamp_;
current_frame_timestamp - last_keyframe_timestamp_); UMA_HISTOGRAM_MEDIUM_TIMES("Media.Video.KeyFrameDistance", frame_distance);
last_keyframe_timestamp_ = current_frame_timestamp; last_keyframe_timestamp_ = current_frame_timestamp;
keyframe_distance_average_.AddSample(frame_distance);
} }
} // namespace media } // namespace media
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "media/base/cdm_context.h" #include "media/base/cdm_context.h"
#include "media/base/demuxer_stream.h" #include "media/base/demuxer_stream.h"
#include "media/base/moving_average.h"
#include "media/base/pipeline_status.h" #include "media/base/pipeline_status.h"
#include "media/base/video_decoder_config.h" #include "media/base/video_decoder_config.h"
#include "media/filters/audio_timestamp_validator.h" #include "media/filters/audio_timestamp_validator.h"
...@@ -37,12 +38,11 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::AUDIO> { ...@@ -37,12 +38,11 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::AUDIO> {
static std::string ToString(); static std::string ToString();
static bool NeedsBitstreamConversion(DecoderType* decoder); static bool NeedsBitstreamConversion(DecoderType* decoder);
static void ReportStatistics(const StatisticsCB& statistics_cb,
int bytes_decoded);
static scoped_refptr<OutputType> CreateEOSOutput(); static scoped_refptr<OutputType> CreateEOSOutput();
explicit DecoderStreamTraits(const scoped_refptr<MediaLog>& media_log); explicit DecoderStreamTraits(const scoped_refptr<MediaLog>& media_log);
void ReportStatistics(const StatisticsCB& statistics_cb, int bytes_decoded);
void InitializeDecoder(DecoderType* decoder, void InitializeDecoder(DecoderType* decoder,
DemuxerStream* stream, DemuxerStream* stream,
CdmContext* cdm_context, CdmContext* cdm_context,
...@@ -72,12 +72,11 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> { ...@@ -72,12 +72,11 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> {
static std::string ToString(); static std::string ToString();
static bool NeedsBitstreamConversion(DecoderType* decoder); static bool NeedsBitstreamConversion(DecoderType* decoder);
static void ReportStatistics(const StatisticsCB& statistics_cb,
int bytes_decoded);
static scoped_refptr<OutputType> CreateEOSOutput(); static scoped_refptr<OutputType> CreateEOSOutput();
explicit DecoderStreamTraits(const scoped_refptr<MediaLog>& media_log) {} explicit DecoderStreamTraits(const scoped_refptr<MediaLog>& media_log);
void ReportStatistics(const StatisticsCB& statistics_cb, int bytes_decoded);
void InitializeDecoder(DecoderType* decoder, void InitializeDecoder(DecoderType* decoder,
DemuxerStream* stream, DemuxerStream* stream,
CdmContext* cdm_context, CdmContext* cdm_context,
...@@ -89,6 +88,7 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> { ...@@ -89,6 +88,7 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> {
private: private:
base::TimeDelta last_keyframe_timestamp_; base::TimeDelta last_keyframe_timestamp_;
MovingAverage keyframe_distance_average_;
}; };
} // namespace media } // namespace media
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment