Commit dd6a406a authored by Yuri Wiitala's avatar Yuri Wiitala Committed by Commit Bot

Require consumer feedback signal before activating auto-throttling.

VideoCaptureOracle, which is used by viz::FrameSinkVideoCapturer
includes logic to suggest capture size changes in response to
bottlenecks in an end-to-end screen mirroring pipeline. This change
prevents the oracle from reducing the capture size until after it
confirms a downstream consumer of the video capture is providing the
necessary feedback signals.

Bug: 1092854
Change-Id: Iadf059548cc1ae705cbcf1e40283fd115563a8bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2298579
Commit-Queue: Takumi Fujimoto <takumif@chromium.org>
Reviewed-by: default avatarTakumi Fujimoto <takumif@chromium.org>
Auto-Submit: Yuri Wiitala <miu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790003}
parent 70c537ae
......@@ -5,6 +5,8 @@
#include "media/capture/content/video_capture_oracle.h"
#include <algorithm>
#include <limits>
#include <utility>
#include "base/callback.h"
#include "base/compiler_specific.h"
......@@ -79,7 +81,8 @@ constexpr base::TimeDelta VideoCaptureOracle::kDefaultMinCapturePeriod;
constexpr base::TimeDelta VideoCaptureOracle::kDefaultMinSizeChangePeriod;
VideoCaptureOracle::VideoCaptureOracle(bool enable_auto_throttling)
: auto_throttling_enabled_(enable_auto_throttling),
: capture_size_throttling_mode_(
enable_auto_throttling ? kThrottlingEnabled : kThrottlingDisabled),
min_size_change_period_(kDefaultMinSizeChangePeriod),
next_frame_number_(0),
last_successfully_delivered_frame_number_(-1),
......@@ -90,8 +93,8 @@ VideoCaptureOracle::VideoCaptureOracle(bool enable_auto_throttling)
kBufferUtilizationEvaluationMicros)),
estimated_capable_area_(base::TimeDelta::FromMicroseconds(
kConsumerCapabilityEvaluationMicros)) {
VLOG(1) << "Auto-throttling is "
<< (auto_throttling_enabled_ ? "enabled." : "disabled.");
VLOG(1) << "Capture size auto-throttling is now "
<< (enable_auto_throttling ? "enabled." : "disabled.");
}
VideoCaptureOracle::~VideoCaptureOracle() = default;
......@@ -111,9 +114,14 @@ void VideoCaptureOracle::SetCaptureSizeConstraints(
}
void VideoCaptureOracle::SetAutoThrottlingEnabled(bool enabled) {
if (auto_throttling_enabled_ == enabled)
const bool was_enabled =
(capture_size_throttling_mode_ != kThrottlingDisabled);
if (was_enabled == enabled)
return;
auto_throttling_enabled_ = enabled;
capture_size_throttling_mode_ =
enabled ? kThrottlingEnabled : kThrottlingDisabled;
VLOG(1) << "Capture size auto-throttling is now "
<< (enabled ? "enabled." : "disabled.");
// When not auto-throttling, have the CaptureResolutionChooser target the max
// resolution within constraints.
......@@ -225,7 +233,7 @@ void VideoCaptureOracle::RecordCapture(double pool_utilization) {
const base::TimeTicks timestamp = GetFrameTimestamp(next_frame_number_);
content_sampler_.RecordSample(timestamp);
if (auto_throttling_enabled_) {
if (capture_size_throttling_mode_ == kThrottlingActive) {
buffer_pool_utilization_.Update(pool_utilization, timestamp);
AnalyzeAndAdjust(timestamp);
}
......@@ -238,7 +246,7 @@ void VideoCaptureOracle::RecordWillNotCapture(double pool_utilization) {
VLOG(1) << "Client rejects proposal to capture frame (at #"
<< next_frame_number_ << ").";
if (auto_throttling_enabled_) {
if (capture_size_throttling_mode_ == kThrottlingActive) {
DCHECK(std::isfinite(pool_utilization) && pool_utilization >= 0.0);
const base::TimeTicks timestamp = GetFrameTimestamp(next_frame_number_);
buffer_pool_utilization_.Update(pool_utilization, timestamp);
......@@ -326,7 +334,7 @@ void VideoCaptureOracle::CancelAllCaptures() {
void VideoCaptureOracle::RecordConsumerFeedback(int frame_number,
double resource_utilization) {
if (!auto_throttling_enabled_)
if (capture_size_throttling_mode_ == kThrottlingDisabled)
return;
if (!std::isfinite(resource_utilization)) {
......@@ -337,6 +345,12 @@ void VideoCaptureOracle::RecordConsumerFeedback(int frame_number,
if (resource_utilization <= 0.0)
return; // Non-positive values are normal, meaning N/A.
if (capture_size_throttling_mode_ != kThrottlingActive) {
VLOG(1) << "Received consumer feedback at frame #" << frame_number
<< "; activating capture size auto-throttling.";
capture_size_throttling_mode_ = kThrottlingActive;
}
if (!IsFrameInRecentHistory(frame_number)) {
VLOG(1) << "Very old frame feedback being ignored: frame #" << frame_number;
return;
......@@ -409,7 +423,7 @@ void VideoCaptureOracle::CommitCaptureSizeAndReset(
}
void VideoCaptureOracle::AnalyzeAndAdjust(const base::TimeTicks analyze_time) {
DCHECK(auto_throttling_enabled_);
DCHECK(capture_size_throttling_mode_ == kThrottlingActive);
const int decreased_area = AnalyzeForDecreasedArea(analyze_time);
if (decreased_area > 0) {
......
......@@ -5,6 +5,8 @@
#ifndef MEDIA_CAPTURE_CONTENT_VIDEO_CAPTURE_ORACLE_H_
#define MEDIA_CAPTURE_CONTENT_VIDEO_CAPTURE_ORACLE_H_
#include <string>
#include "base/callback.h"
#include "base/time/time.h"
#include "media/base/feedback_signal_accumulator.h"
......@@ -30,10 +32,9 @@ class CAPTURE_EXPORT VideoCaptureOracle {
// Constructs a VideoCaptureOracle with a default min capture period and
// capture size constraints. Clients should call SetMinCapturePeriod() and
// SetCaptureSizeConstraints() to provide more-accurate hard limits. If
// |enable_auto_throttling| is true, enable realtime analysis of system
// performance and auto-adjust the capture resolution and sampling decisions
// to provide the best user experience.
// SetCaptureSizeConstraints() to provide more-accurate hard limits.
//
// See SetAutoThrottlingEnabled() for |enable_auto_throttling| semantics.
explicit VideoCaptureOracle(bool enable_auto_throttling);
virtual ~VideoCaptureOracle();
......@@ -51,8 +52,11 @@ class CAPTURE_EXPORT VideoCaptureOracle {
const gfx::Size& max_size,
bool use_fixed_aspect_ratio);
// Specifies whether the oracle should automatically adjust the capture size
// in response to end-to-end utilization.
// Specifies whether the oracle should propose varying capture sizes, in
// response to consumer feedback. If not |enabled|, capture_size() will always
// return the source_size().
//
// See: SetMinSizeChangePeriod().
void SetAutoThrottlingEnabled(bool enabled);
// Get/Update the source content size. Changes may not have an immediate
......@@ -161,7 +165,7 @@ class CAPTURE_EXPORT VideoCaptureOracle {
void CommitCaptureSizeAndReset(base::TimeTicks last_frame_time);
// Called after a capture or no-capture decision was recorded. This analyzes
// current state and may result in a future change to the capture frame size.
// current state and may result in a future change to the capture size.
void AnalyzeAndAdjust(base::TimeTicks analyze_time);
// Analyzes current feedback signal accumulators for an indication that the
......@@ -188,9 +192,15 @@ class CAPTURE_EXPORT VideoCaptureOracle {
const FeedbackSignalAccumulator<base::TimeTicks>& accumulator,
base::TimeTicks now);
// Set to false to prevent the oracle from automatically adjusting the capture
// size in response to end-to-end utilization.
bool auto_throttling_enabled_;
// Set to disabled/enabled via SetAutoThrottlingEnabled(). Data collection and
// analysis for capture size changes only occurs while in "active" mode, which
// is only engaged when in "enabled" mode and consumer feedback is received
// for the first time.
enum {
kThrottlingDisabled,
kThrottlingEnabled,
kThrottlingActive
} capture_size_throttling_mode_;
// The minimum amount of time that must pass between changes to the capture
// size.
......
......@@ -11,43 +11,27 @@ namespace media {
namespace {
base::TimeTicks InitialTestTimeTicks() {
return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
}
base::TimeDelta Get30HzPeriod() {
return base::TimeDelta::FromSeconds(1) / 30;
}
gfx::Size Get1080pSize() {
return gfx::Size(1920, 1080);
}
gfx::Size Get720pSize() {
return gfx::Size(1280, 720);
}
gfx::Size Get360pSize() {
return gfx::Size(640, 360);
}
gfx::Size GetSmallestNonEmptySize() {
return gfx::Size(2, 2);
}
constexpr base::TimeTicks kInitialTestTimeTicks =
base::TimeTicks() + base::TimeDelta::FromSeconds(1);
constexpr base::TimeDelta k30HzPeriod = base::TimeDelta::FromSeconds(1) / 30;
constexpr gfx::Size k1080pSize = gfx::Size(1920, 1080);
constexpr gfx::Size k720pSize = gfx::Size(1280, 720);
constexpr gfx::Size k360pSize = gfx::Size(640, 360);
constexpr gfx::Size kSmallestNonEmptySize = gfx::Size(2, 2);
} // namespace
// Tests that VideoCaptureOracle filters out events whose timestamps are
// decreasing.
TEST(VideoCaptureOracleTest, EnforcesEventTimeMonotonicity) {
const gfx::Rect damage_rect(Get720pSize());
const base::TimeDelta event_increment = Get30HzPeriod() * 2;
const gfx::Rect damage_rect(k720pSize);
const base::TimeDelta event_increment = k30HzPeriod * 2;
VideoCaptureOracle oracle(false);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetCaptureSizeConstraints(Get720pSize(), Get720pSize(), false);
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(k720pSize, k720pSize, false);
base::TimeTicks t = InitialTestTimeTicks();
base::TimeTicks t = kInitialTestTimeTicks;
for (int i = 0; i < 10; ++i) {
t += event_increment;
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
......@@ -73,16 +57,16 @@ TEST(VideoCaptureOracleTest, EnforcesEventTimeMonotonicity) {
// successfully captured frames are delivered in order. Otherwise, downstream
// consumers could be tripped-up by out-of-order frames or frame timestamps.
TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
const gfx::Rect damage_rect(Get720pSize());
const base::TimeDelta event_increment = Get30HzPeriod() * 2;
const gfx::Rect damage_rect(k720pSize);
const base::TimeDelta event_increment = k30HzPeriod * 2;
VideoCaptureOracle oracle(false);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetCaptureSizeConstraints(Get720pSize(), Get720pSize(), false);
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(k720pSize, k720pSize, false);
// Most basic scenario: Frames delivered one at a time, with no additional
// captures in-between deliveries.
base::TimeTicks t = InitialTestTimeTicks();
base::TimeTicks t = kInitialTestTimeTicks;
int last_frame_number;
base::TimeTicks ignored;
for (int i = 0; i < 10; ++i) {
......@@ -151,17 +135,17 @@ TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
// Tests that VideoCaptureOracle transitions between using its two samplers in a
// way that does not introduce severe jank, pauses, etc.
TEST(VideoCaptureOracleTest, TransitionsSmoothlyBetweenSamplers) {
const gfx::Rect animation_damage_rect(Get720pSize());
const base::TimeDelta event_increment = Get30HzPeriod() * 2;
const gfx::Rect animation_damage_rect(k720pSize);
const base::TimeDelta event_increment = k30HzPeriod * 2;
VideoCaptureOracle oracle(false);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetCaptureSizeConstraints(Get720pSize(), Get720pSize(), false);
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(k720pSize, k720pSize, false);
// Run sequences of animation events and non-animation events through the
// oracle. As the oracle transitions between each sampler, make sure the
// frame timestamps won't trip-up downstream consumers.
base::TimeTicks t = InitialTestTimeTicks();
base::TimeTicks t = kInitialTestTimeTicks;
base::TimeTicks last_frame_timestamp;
for (int i = 0; i < 1000; ++i) {
t += event_increment;
......@@ -218,12 +202,12 @@ TEST(VideoCaptureOracleTest, SamplesAtCorrectTimesAroundRefreshRequests) {
base::TimeDelta::FromMilliseconds(125); // 8 FPS
VideoCaptureOracle oracle(false);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetCaptureSizeConstraints(Get720pSize(), Get720pSize(), false);
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(k720pSize, k720pSize, false);
// Have the oracle observe some compositor events. Simulate that each capture
// completes successfully.
base::TimeTicks t = InitialTestTimeTicks();
base::TimeTicks t = kInitialTestTimeTicks;
base::TimeTicks ignored;
bool did_complete_a_capture = false;
for (int i = 0; i < 10; ++i) {
......@@ -312,29 +296,29 @@ TEST(VideoCaptureOracleTest, SamplesAtCorrectTimesAroundRefreshRequests) {
// stabilize.
TEST(VideoCaptureOracleTest, DoesNotRapidlyChangeCaptureSize) {
VideoCaptureOracle oracle(true);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetCaptureSizeConstraints(GetSmallestNonEmptySize(), Get720pSize(),
false);
oracle.SetSourceSize(Get1080pSize());
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(kSmallestNonEmptySize, k720pSize, false);
oracle.SetSourceSize(k1080pSize);
// Run 30 seconds of frame captures without any source size changes.
base::TimeTicks t = InitialTestTimeTicks();
const base::TimeDelta event_increment = Get30HzPeriod() * 2;
base::TimeTicks t = kInitialTestTimeTicks;
const base::TimeDelta event_increment = k30HzPeriod * 2;
base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(30);
for (; t < end_t; t += event_increment) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t));
ASSERT_EQ(Get720pSize(), oracle.capture_size());
ASSERT_EQ(k720pSize, oracle.capture_size());
base::TimeTicks ignored;
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(0.0);
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, 0.0);
}
// Now run 30 seconds of frame captures with lots of random source size
// changes. Check that there was no more than one size change per second.
gfx::Size source_size = oracle.capture_size();
base::TimeTicks time_of_last_size_change = InitialTestTimeTicks();
base::TimeTicks time_of_last_size_change = kInitialTestTimeTicks;
gfx::Size last_capture_size = oracle.capture_size();
end_t = t + base::TimeDelta::FromSeconds(30);
for (; t < end_t; t += event_increment) {
......@@ -358,6 +342,7 @@ TEST(VideoCaptureOracleTest, DoesNotRapidlyChangeCaptureSize) {
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(0.0);
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, 0.0);
}
}
......@@ -365,16 +350,15 @@ TEST(VideoCaptureOracleTest, DoesNotRapidlyChangeCaptureSize) {
// size if resize throttling is disabled.
TEST(VideoCaptureOracleTest, ResizeThrottlingDisabled) {
VideoCaptureOracle oracle(true);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetMinSizeChangePeriod(base::TimeDelta());
oracle.SetCaptureSizeConstraints(GetSmallestNonEmptySize(), Get720pSize(),
false);
oracle.SetSourceSize(Get1080pSize());
oracle.SetCaptureSizeConstraints(kSmallestNonEmptySize, k720pSize, false);
oracle.SetSourceSize(k1080pSize);
// Run 30 seconds of frame captures with lots of random source size
// changes. The capture size should be different every time.
base::TimeTicks t = InitialTestTimeTicks();
const base::TimeDelta event_increment = Get30HzPeriod() * 2;
base::TimeTicks t = kInitialTestTimeTicks;
const base::TimeDelta event_increment = k30HzPeriod * 2;
base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(30);
gfx::Size source_size = oracle.capture_size();
gfx::Size last_capture_size = oracle.capture_size();
......@@ -396,6 +380,7 @@ TEST(VideoCaptureOracleTest, ResizeThrottlingDisabled) {
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(0.0);
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, 0.0);
}
}
......@@ -416,29 +401,34 @@ void RunAutoThrottleTest(bool is_content_animating,
<< ", with_consumer_feedback=" << with_consumer_feedback << ")");
VideoCaptureOracle oracle(true);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetCaptureSizeConstraints(GetSmallestNonEmptySize(), Get720pSize(),
false);
oracle.SetSourceSize(Get1080pSize());
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(kSmallestNonEmptySize, k720pSize, false);
oracle.SetSourceSize(k1080pSize);
// Run 10 seconds of frame captures with 90% utilization expect no capture
// size changes.
base::TimeTicks t = InitialTestTimeTicks();
base::TimeTicks t = kInitialTestTimeTicks;
base::TimeTicks time_of_last_size_change = t;
const base::TimeDelta event_increment = Get30HzPeriod() * 2;
const base::TimeDelta event_increment = k30HzPeriod * 2;
base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(10);
for (; t < end_t; t += event_increment) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate,
is_content_animating ? gfx::Rect(Get720pSize()) : gfx::Rect(), t));
ASSERT_EQ(Get720pSize(), oracle.capture_size());
is_content_animating ? gfx::Rect(k720pSize) : gfx::Rect(), t));
ASSERT_EQ(k720pSize, oracle.capture_size());
const double utilization = 0.9;
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(with_consumer_feedback ? 0.25 : utilization);
base::TimeTicks ignored;
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
if (with_consumer_feedback)
if (with_consumer_feedback) {
oracle.RecordConsumerFeedback(frame_number, utilization);
} else if (t == kInitialTestTimeTicks) {
// Provide feedback with the very first capture to activate the capture
// size auto-throttling logic. After this, no consumer feedback applies
// and the buffer utilization will be the only consideration.
oracle.RecordConsumerFeedback(frame_number, 0.0);
}
}
// Cause two downward steppings in resolution. First, indicate overload
......@@ -455,7 +445,7 @@ void RunAutoThrottleTest(bool is_content_animating,
for (; t < end_t; t += event_increment) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate,
is_content_animating ? gfx::Rect(Get720pSize()) : gfx::Rect(), t));
is_content_animating ? gfx::Rect(k720pSize) : gfx::Rect(), t));
if (stepped_down_size.IsEmpty()) {
if (oracle.capture_size() != starting_size) {
......@@ -492,7 +482,7 @@ void RunAutoThrottleTest(bool is_content_animating,
for (; t < end_t; t += event_increment) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate,
is_content_animating ? gfx::Rect(Get720pSize()) : gfx::Rect(), t));
is_content_animating ? gfx::Rect(k720pSize) : gfx::Rect(), t));
if (stepped_up_size.IsEmpty()) {
if (oracle.capture_size() != starting_size) {
......@@ -526,55 +516,95 @@ void RunAutoThrottleTest(bool is_content_animating,
// up or down, using utilization feedback signals from either the buffer pool or
// the consumer, and with slightly different behavior depending on whether
// content is animating.
TEST(VideoCaptureOracleTest, AutoThrottlesBasedOnUtilizationFeedback) {
TEST(VideoCaptureOracleTest,
AutoThrottlesCaptureSizeBasedOnUtilizationFeedback) {
RunAutoThrottleTest(false, false);
RunAutoThrottleTest(false, true);
RunAutoThrottleTest(true, false);
RunAutoThrottleTest(true, true);
}
// Test that the capture size is not auto-throttled if consumer feedback is
// never provided. This represents VideoCaptureOracle being stuck in the
// kThrottlingEnabled mode, but never having entered the kThrottlingActive mode.
TEST(VideoCaptureOracleTest,
DoesNotAutoThrottleCaptureSizeWithoutConsumerFeedback) {
VideoCaptureOracle oracle(true);
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(kSmallestNonEmptySize, k720pSize, false);
oracle.SetSourceSize(k1080pSize);
// Run 10 seconds of frame captures with 90% utilization expect no capture
// size changes.
base::TimeTicks t = kInitialTestTimeTicks;
const base::TimeDelta event_increment = k30HzPeriod * 2;
base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(10);
for (; t < end_t; t += event_increment) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(k720pSize), t));
ASSERT_EQ(k720pSize, oracle.capture_size());
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(0.9);
base::TimeTicks ignored;
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
// Important: Not calling oracle.RecordConsumerFeedback(frame_number, ...);
}
// Increase utilization to 1000%, but expect no capture size change because
// there has never been any consumer feedback.
const gfx::Size starting_size = oracle.capture_size();
end_t = t + base::TimeDelta::FromSeconds(10);
for (; t < end_t; t += event_increment) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(k720pSize), t));
ASSERT_EQ(starting_size, oracle.capture_size());
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(10.0);
base::TimeTicks ignored;
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
}
}
// Tests that, while content is animating, VideoCaptureOracle can make frequent
// capture size increases only just after the source size has changed.
// Otherwise, capture size increases should only be made cautiously, after a
// long "proving period of under-utilization" has elapsed.
TEST(VideoCaptureOracleTest, IncreasesFrequentlyOnlyAfterSourceSizeChange) {
VideoCaptureOracle oracle(true);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetCaptureSizeConstraints(GetSmallestNonEmptySize(), Get720pSize(),
false);
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(kSmallestNonEmptySize, k720pSize, false);
// Start out the source size at 360p, so there is room to grow to the 720p
// maximum.
oracle.SetSourceSize(Get360pSize());
oracle.SetSourceSize(k360pSize);
// Run 10 seconds of frame captures with under-utilization to represent a
// machine that can do more, but won't because the source size is small.
base::TimeTicks t = InitialTestTimeTicks();
const base::TimeDelta event_increment = Get30HzPeriod() * 2;
base::TimeTicks t = kInitialTestTimeTicks;
const base::TimeDelta event_increment = k30HzPeriod * 2;
base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(10);
for (; t < end_t; t += event_increment) {
if (!oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(Get360pSize()),
t)) {
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(k360pSize), t)) {
continue;
}
ASSERT_EQ(Get360pSize(), oracle.capture_size());
ASSERT_EQ(k360pSize, oracle.capture_size());
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(0.25);
base::TimeTicks ignored;
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, 0.25);
}
// Now, set the source size to 720p, continuing to report under-utilization,
// and expect the capture size increases to reach a full 720p within 15
// seconds.
oracle.SetSourceSize(Get720pSize());
oracle.SetSourceSize(k720pSize);
gfx::Size last_capture_size = oracle.capture_size();
end_t = t + base::TimeDelta::FromSeconds(15);
for (; t < end_t; t += event_increment) {
if (!oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(Get720pSize()),
t)) {
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(k720pSize), t)) {
continue;
}
ASSERT_LE(last_capture_size.width(), oracle.capture_size().width());
......@@ -584,27 +614,27 @@ TEST(VideoCaptureOracleTest, IncreasesFrequentlyOnlyAfterSourceSizeChange) {
oracle.RecordCapture(0.25);
base::TimeTicks ignored;
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, 0.25);
}
ASSERT_EQ(Get720pSize(), oracle.capture_size());
ASSERT_EQ(k720pSize, oracle.capture_size());
// Now, change the source size again, but report over-utilization so the
// capture size will decrease. Once it decreases one step, report 90%
// utilization to achieve a steady-state.
oracle.SetSourceSize(Get1080pSize());
oracle.SetSourceSize(k1080pSize);
gfx::Size stepped_down_size;
end_t = t + base::TimeDelta::FromSeconds(10);
for (; t < end_t; t += event_increment) {
if (!oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(Get1080pSize()),
t)) {
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(k1080pSize), t)) {
continue;
}
if (stepped_down_size.IsEmpty()) {
if (oracle.capture_size() != Get720pSize()) {
if (oracle.capture_size() != k720pSize) {
stepped_down_size = oracle.capture_size();
ASSERT_GT(Get720pSize().width(), stepped_down_size.width());
ASSERT_GT(Get720pSize().height(), stepped_down_size.height());
ASSERT_GT(k720pSize.width(), stepped_down_size.width());
ASSERT_GT(k720pSize.height(), stepped_down_size.height());
}
} else {
ASSERT_EQ(stepped_down_size, oracle.capture_size());
......@@ -615,6 +645,7 @@ TEST(VideoCaptureOracleTest, IncreasesFrequentlyOnlyAfterSourceSizeChange) {
oracle.RecordCapture(utilization);
base::TimeTicks ignored;
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, utilization);
}
ASSERT_FALSE(stepped_down_size.IsEmpty());
......@@ -627,8 +658,7 @@ TEST(VideoCaptureOracleTest, IncreasesFrequentlyOnlyAfterSourceSizeChange) {
end_t = t + base::TimeDelta::FromSeconds(60);
for (; t < end_t; t += event_increment) {
if (!oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(Get1080pSize()),
t)) {
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(k1080pSize), t)) {
continue;
}
......@@ -648,6 +678,7 @@ TEST(VideoCaptureOracleTest, IncreasesFrequentlyOnlyAfterSourceSizeChange) {
oracle.RecordCapture(utilization);
base::TimeTicks ignored;
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, utilization);
}
ASSERT_FALSE(stepped_up_size.IsEmpty());
}
......@@ -656,23 +687,24 @@ TEST(VideoCaptureOracleTest, IncreasesFrequentlyOnlyAfterSourceSizeChange) {
// auto-throttling is enabled when using a fixed resolution policy.
TEST(VideoCaptureOracleTest, DoesNotAutoThrottleWhenResolutionIsFixed) {
VideoCaptureOracle oracle(true);
oracle.SetMinCapturePeriod(Get30HzPeriod());
oracle.SetCaptureSizeConstraints(Get720pSize(), Get720pSize(), false);
oracle.SetSourceSize(Get1080pSize());
oracle.SetMinCapturePeriod(k30HzPeriod);
oracle.SetCaptureSizeConstraints(k720pSize, k720pSize, false);
oracle.SetSourceSize(k1080pSize);
// Run 10 seconds of frame captures with 90% utilization expect no capture
// size changes.
base::TimeTicks t = InitialTestTimeTicks();
const base::TimeDelta event_increment = Get30HzPeriod() * 2;
base::TimeTicks t = kInitialTestTimeTicks;
const base::TimeDelta event_increment = k30HzPeriod * 2;
base::TimeTicks end_t = t + base::TimeDelta::FromSeconds(10);
for (; t < end_t; t += event_increment) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t));
ASSERT_EQ(Get720pSize(), oracle.capture_size());
ASSERT_EQ(k720pSize, oracle.capture_size());
base::TimeTicks ignored;
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(0.9);
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, 0.9);
}
// Now run 10 seconds with overload indicated. Still, expect no capture size
......@@ -681,11 +713,12 @@ TEST(VideoCaptureOracleTest, DoesNotAutoThrottleWhenResolutionIsFixed) {
for (; t < end_t; t += event_increment) {
ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
VideoCaptureOracle::kCompositorUpdate, gfx::Rect(), t));
ASSERT_EQ(Get720pSize(), oracle.capture_size());
ASSERT_EQ(k720pSize, oracle.capture_size());
base::TimeTicks ignored;
const int frame_number = oracle.next_frame_number();
oracle.RecordCapture(2.0);
ASSERT_TRUE(oracle.CompleteCapture(frame_number, true, &ignored));
oracle.RecordConsumerFeedback(frame_number, 2.0);
}
}
......
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