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(
shared_state_.statistics.video_frames_dropped += stats.video_frames_dropped;
shared_state_.statistics.audio_memory_usage += stats.audio_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(
......
......@@ -5,12 +5,12 @@
#ifndef MEDIA_BASE_PIPELINE_STATUS_H_
#define MEDIA_BASE_PIPELINE_STATUS_H_
#include "base/callback.h"
#include <stdint.h>
#include <string>
#include "base/callback.h"
#include "base/time/time.h"
namespace media {
// Status states for pipeline. All codes except PIPELINE_OK indicate errors.
......@@ -59,6 +59,7 @@ struct PipelineStatistics {
uint32_t video_frames_dropped = 0;
int64_t audio_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
......
......@@ -887,28 +887,28 @@ double WebMediaPlayerImpl::mediaTimeForTimeValue(double timeValue) const {
unsigned WebMediaPlayerImpl::decodedFrameCount() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
PipelineStatistics stats = pipeline_.GetStatistics();
PipelineStatistics stats = GetPipelineStatistics();
return stats.video_frames_decoded;
}
unsigned WebMediaPlayerImpl::droppedFrameCount() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
PipelineStatistics stats = pipeline_.GetStatistics();
PipelineStatistics stats = GetPipelineStatistics();
return stats.video_frames_dropped;
}
size_t WebMediaPlayerImpl::audioDecodedByteCount() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
PipelineStatistics stats = pipeline_.GetStatistics();
PipelineStatistics stats = GetPipelineStatistics();
return stats.audio_bytes_decoded;
}
size_t WebMediaPlayerImpl::videoDecodedByteCount() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
PipelineStatistics stats = pipeline_.GetStatistics();
PipelineStatistics stats = GetPipelineStatistics();
return stats.video_bytes_decoded;
}
......@@ -2005,7 +2005,7 @@ void WebMediaPlayerImpl::ReportMemoryUsage() {
void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
const PipelineStatistics stats = pipeline_.GetStatistics();
const PipelineStatistics stats = GetPipelineStatistics();
const int64_t data_source_memory_usage =
data_source_ ? data_source_->GetMemoryUsage() : 0;
const int64_t current_memory_usage =
......@@ -2107,9 +2107,17 @@ bool WebMediaPlayerImpl::ShouldPauseWhenHidden() const {
}
bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
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() {
......@@ -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
......@@ -17,8 +17,10 @@
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/threading/thread.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
......@@ -395,6 +397,12 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl
// - right after the pipeline has resumed if the video is not hidden.
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_;
// The playback state last reported to |delegate_|, to avoid setting duplicate
......@@ -623,12 +631,21 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl
// Whether the player is currently in autoplay muted state.
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.
bool video_track_disabled_ = false;
// Whether the pipeline is being resumed at the moment.
bool is_pipeline_resuming_ = false;
// Pipeline statistics overridden by tests.
base::Optional<PipelineStatistics> pipeline_statistics_for_test_;
DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
};
......
......@@ -263,6 +263,12 @@ class WebMediaPlayerImplTest : public testing::Test {
return wmpi_->ShouldDisableVideoWhenHidden();
}
void SetVideoKeyframeDistanceAverage(base::TimeDelta value) {
PipelineStatistics statistics;
statistics.video_keyframe_distance_average = value;
wmpi_->SetPipelineStatisticsForTest(statistics);
}
// "Renderer" thread.
base::MessageLoop message_loop_;
......@@ -775,6 +781,7 @@ TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHidden) {
SetBackgroundVideoOptimization(true);
SetMetadata(true, true);
SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(5));
EXPECT_TRUE(ShouldDisableVideoWhenHidden());
SetMetadata(false, true);
......@@ -782,6 +789,10 @@ TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHidden) {
SetMetadata(true, false);
EXPECT_FALSE(ShouldDisableVideoWhenHidden());
SetVideoKeyframeDistanceAverage(base::TimeDelta::FromSeconds(100));
SetMetadata(true, true);
EXPECT_FALSE(ShouldDisableVideoWhenHidden());
}
TEST_F(WebMediaPlayerImplTest, ShouldDisableVideoWhenHiddenFeatureDisabled) {
......
......@@ -458,7 +458,7 @@ void DecoderStream<StreamType>::OnDecodeDone(int buffer_size,
case DecodeStatus::OK:
// Any successful decode counts!
if (buffer_size > 0)
StreamTraits::ReportStatistics(statistics_cb_, buffer_size);
traits_.ReportStatistics(statistics_cb_, buffer_size);
if (state_ == STATE_NORMAL) {
if (end_of_stream) {
......
......@@ -4,6 +4,8 @@
#include "media/filters/decoder_stream_traits.h"
#include <limits>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "media/base/audio_buffer.h"
......@@ -27,15 +29,6 @@ bool DecoderStreamTraits<DemuxerStream::AUDIO>::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
scoped_refptr<DecoderStreamTraits<DemuxerStream::AUDIO>::OutputType>
DecoderStreamTraits<DemuxerStream::AUDIO>::CreateEOSOutput() {
......@@ -46,6 +39,14 @@ DecoderStreamTraits<DemuxerStream::AUDIO>::DecoderStreamTraits(
const scoped_refptr<MediaLog>& 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(
DecoderType* decoder,
DemuxerStream* stream,
......@@ -90,18 +91,32 @@ bool DecoderStreamTraits<DemuxerStream::VIDEO>::NeedsBitstreamConversion(
}
// 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(
const StatisticsCB& statistics_cb,
int bytes_decoded) {
PipelineStatistics statistics;
statistics.video_bytes_decoded = bytes_decoded;
statistics_cb.Run(statistics);
}
// static
scoped_refptr<DecoderStreamTraits<DemuxerStream::VIDEO>::OutputType>
DecoderStreamTraits<DemuxerStream::VIDEO>::CreateEOSOutput() {
return OutputType::CreateEOSFrame();
// Before we have enough keyframes to calculate the average distance, we will
// assume the average keyframe distance is infinitely large.
if (keyframe_distance_average_.count() < 3) {
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(
......@@ -120,6 +135,7 @@ void DecoderStreamTraits<DemuxerStream::VIDEO>::OnStreamReset(
DemuxerStream* stream) {
DCHECK(stream);
last_keyframe_timestamp_ = base::TimeDelta();
keyframe_distance_average_.Reset();
}
void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode(
......@@ -141,10 +157,11 @@ void DecoderStreamTraits<DemuxerStream::VIDEO>::OnDecode(
return;
}
UMA_HISTOGRAM_MEDIUM_TIMES(
"Media.Video.KeyFrameDistance",
current_frame_timestamp - last_keyframe_timestamp_);
base::TimeDelta frame_distance =
current_frame_timestamp - last_keyframe_timestamp_;
UMA_HISTOGRAM_MEDIUM_TIMES("Media.Video.KeyFrameDistance", frame_distance);
last_keyframe_timestamp_ = current_frame_timestamp;
keyframe_distance_average_.AddSample(frame_distance);
}
} // namespace media
......@@ -8,6 +8,7 @@
#include "base/time/time.h"
#include "media/base/cdm_context.h"
#include "media/base/demuxer_stream.h"
#include "media/base/moving_average.h"
#include "media/base/pipeline_status.h"
#include "media/base/video_decoder_config.h"
#include "media/filters/audio_timestamp_validator.h"
......@@ -37,12 +38,11 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::AUDIO> {
static std::string ToString();
static bool NeedsBitstreamConversion(DecoderType* decoder);
static void ReportStatistics(const StatisticsCB& statistics_cb,
int bytes_decoded);
static scoped_refptr<OutputType> CreateEOSOutput();
explicit DecoderStreamTraits(const scoped_refptr<MediaLog>& media_log);
void ReportStatistics(const StatisticsCB& statistics_cb, int bytes_decoded);
void InitializeDecoder(DecoderType* decoder,
DemuxerStream* stream,
CdmContext* cdm_context,
......@@ -72,12 +72,11 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> {
static std::string ToString();
static bool NeedsBitstreamConversion(DecoderType* decoder);
static void ReportStatistics(const StatisticsCB& statistics_cb,
int bytes_decoded);
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,
DemuxerStream* stream,
CdmContext* cdm_context,
......@@ -89,6 +88,7 @@ class MEDIA_EXPORT DecoderStreamTraits<DemuxerStream::VIDEO> {
private:
base::TimeDelta last_keyframe_timestamp_;
MovingAverage keyframe_distance_average_;
};
} // 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