Move kMinPixelsPerFrame constant in VideoStreamEncoder to VideoEncoder::ScalingSettings.

Make it possible for forced VP8 SW fallback encoder to set min_pixels_per_frame via GetScalingSettings().

Add a min required resolution (in addition to bitrate) before releasing forced SW fallback.

BUG=webrtc:6634

Review-Url: https://codereview.webrtc.org/3000693003
Cr-Commit-Position: refs/heads/master@{#19390}
This commit is contained in:
asapersson
2017-08-17 08:58:54 -07:00
committed by Commit Bot
parent b5c319ad8b
commit 142fcc96d6
11 changed files with 213 additions and 35 deletions

View File

@ -64,6 +64,17 @@ VideoEncoder::ScalingSettings::ScalingSettings(bool on, int low, int high)
: enabled(on), : enabled(on),
thresholds(rtc::Optional<QpThresholds>(QpThresholds(low, high))) {} thresholds(rtc::Optional<QpThresholds>(QpThresholds(low, high))) {}
VideoEncoder::ScalingSettings::ScalingSettings(bool on,
int low,
int high,
int min_pixels)
: enabled(on),
thresholds(rtc::Optional<QpThresholds>(QpThresholds(low, high))),
min_pixels_per_frame(min_pixels) {}
VideoEncoder::ScalingSettings::ScalingSettings(bool on, int min_pixels)
: enabled(on), min_pixels_per_frame(min_pixels) {}
VideoEncoder::ScalingSettings::ScalingSettings(bool on) : enabled(on) {} VideoEncoder::ScalingSettings::ScalingSettings(bool on) : enabled(on) {}
VideoEncoder::ScalingSettings::~ScalingSettings() {} VideoEncoder::ScalingSettings::~ScalingSettings() {}

View File

@ -75,12 +75,20 @@ class VideoEncoder {
}; };
struct ScalingSettings { struct ScalingSettings {
ScalingSettings(bool on, int low, int high); ScalingSettings(bool on, int low, int high);
ScalingSettings(bool on, int low, int high, int min_pixels);
ScalingSettings(bool on, int min_pixels);
explicit ScalingSettings(bool on); explicit ScalingSettings(bool on);
ScalingSettings(const ScalingSettings&); ScalingSettings(const ScalingSettings&);
~ScalingSettings(); ~ScalingSettings();
const bool enabled; const bool enabled;
const rtc::Optional<QpThresholds> thresholds; const rtc::Optional<QpThresholds> thresholds;
// We will never ask for a resolution lower than this.
// TODO(kthelgason): Lower this limit when better testing
// on MediaCodec and fallback implementations are in place.
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206
const int min_pixels_per_frame = 320 * 180;
}; };
static VideoCodecVP8 GetDefaultVp8Settings(); static VideoCodecVP8 GetDefaultVp8Settings();

View File

@ -50,12 +50,14 @@ void GetForcedFallbackParamsFromFieldTrialGroup(uint32_t* param_low_kbps,
int low_kbps; int low_kbps;
int high_kbps; int high_kbps;
int min_low_ms; int min_low_ms;
if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &low_kbps, &high_kbps, int min_pixels;
&min_low_ms) != 3) { if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d", &low_kbps, &high_kbps,
&min_low_ms, &min_pixels) != 4) {
LOG(LS_WARNING) << "Invalid number of forced fallback parameters provided."; LOG(LS_WARNING) << "Invalid number of forced fallback parameters provided.";
return; return;
} }
if (min_low_ms <= 0 || low_kbps <= 0 || high_kbps <= low_kbps) { if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 ||
high_kbps <= low_kbps) {
LOG(LS_WARNING) << "Invalid forced fallback parameter value provided."; LOG(LS_WARNING) << "Invalid forced fallback parameter value provided.";
return; return;
} }
@ -245,6 +247,8 @@ bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
VideoEncoder::ScalingSettings VideoEncoder::ScalingSettings
VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const {
if (forced_fallback_possible_ && fallback_encoder_)
return fallback_encoder_->GetScalingSettings();
return encoder_->GetScalingSettings(); return encoder_->GetScalingSettings();
} }
@ -272,8 +276,10 @@ bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() {
if (!IsForcedFallbackActive()) if (!IsForcedFallbackActive())
return false; return false;
if (!forced_fallback_.ShouldStop(bitrate_allocation_.get_sum_kbps())) if (!forced_fallback_.ShouldStop(bitrate_allocation_.get_sum_kbps(),
codec_settings_)) {
return false; return false;
}
// Release the forced fallback encoder. // Release the forced fallback encoder.
if (encoder_->InitEncode(&codec_settings_, number_of_cores_, if (encoder_->InitEncode(&codec_settings_, number_of_cores_,
@ -343,8 +349,10 @@ bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStart(
} }
bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStop( bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStop(
uint32_t bitrate_kbps) const { uint32_t bitrate_kbps,
return bitrate_kbps >= high_kbps; const VideoCodec& codec) const {
return bitrate_kbps >= high_kbps &&
(codec.width * codec.height >= kMinPixelsStop);
} }
} // namespace webrtc } // namespace webrtc

View File

@ -52,22 +52,24 @@ class VideoEncoderSoftwareFallbackWrapper : public VideoEncoder {
// If |forced_fallback_possible_| is true: // If |forced_fallback_possible_| is true:
// The forced fallback is requested if the target bitrate is below |low_kbps| // The forced fallback is requested if the target bitrate is below |low_kbps|
// for more than |min_low_ms| and the input video resolution is not larger // for more than |min_low_ms| and the input video resolution is not larger
// than |kMaxPixels|. // than |kMaxPixelsStart|.
// If the bitrate is above |high_kbps|, the forced fallback is requested to // If the bitrate is above |high_kbps| and the resolution is not smaller than
// immediately be stopped. // |kMinPixelsStop|, the forced fallback is requested to immediately be
// stopped.
class ForcedFallbackParams { class ForcedFallbackParams {
public: public:
bool ShouldStart(uint32_t bitrate_kbps, const VideoCodec& codec); bool ShouldStart(uint32_t bitrate_kbps, const VideoCodec& codec);
bool ShouldStop(uint32_t bitrate_kbps) const; bool ShouldStop(uint32_t bitrate_kbps, const VideoCodec& codec) const;
void Reset() { start_ms.reset(); } void Reset() { start_ms.reset(); }
bool IsValid(const VideoCodec& codec) const { bool IsValid(const VideoCodec& codec) const {
return codec.width * codec.height <= kMaxPixels; return codec.width * codec.height <= kMaxPixelsStart;
} }
rtc::Optional<int64_t> start_ms; // Set when bitrate is below |low_kbps|. rtc::Optional<int64_t> start_ms; // Set when bitrate is below |low_kbps|.
uint32_t low_kbps = 100; uint32_t low_kbps = 100;
uint32_t high_kbps = 150; uint32_t high_kbps = 150;
int64_t min_low_ms = 10000; int64_t min_low_ms = 10000;
const int kMaxPixels = 320 * 240; const int kMaxPixelsStart = 320 * 240;
const int kMinPixelsStop = 320 * 180;
}; };
bool RequestForcedFallback(); bool RequestForcedFallback();

View File

@ -29,6 +29,7 @@ const int kHeight = 240;
const int kNumCores = 2; const int kNumCores = 2;
const uint32_t kFramerate = 30; const uint32_t kFramerate = 30;
const size_t kMaxPayloadSize = 800; const size_t kMaxPayloadSize = 800;
const int kDefaultMinPixelsPerFrame = 320 * 180;
} // namespace } // namespace
class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
@ -93,6 +94,10 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
return "fake-encoder"; return "fake-encoder";
} }
VideoEncoder::ScalingSettings GetScalingSettings() const override {
return VideoEncoder::ScalingSettings(true);
}
int init_encode_count_ = 0; int init_encode_count_ = 0;
int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK; int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK; int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
@ -141,7 +146,8 @@ void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame() {
} }
void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame(int expected_ret) { void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame(int expected_ret) {
rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create(kWidth, kHeight); rtc::scoped_refptr<I420Buffer> buffer =
I420Buffer::Create(codec_.width, codec_.height);
I420Buffer::SetBlack(buffer); I420Buffer::SetBlack(buffer);
std::vector<FrameType> types(1, kVideoFrameKey); std::vector<FrameType> types(1, kVideoFrameKey);
@ -299,9 +305,10 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
} }
TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) { TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) {
VideoCodec codec = {}; codec_.width = kWidth;
codec_.height = kHeight;
fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_); fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
fallback_wrapper_.InitEncode(&codec, kNumCores, kMaxPayloadSize); fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize);
EncodeFrame(); EncodeFrame();
CheckLastEncoderName("fake-encoder"); CheckLastEncoderName("fake-encoder");
} }
@ -318,6 +325,8 @@ namespace {
const int kLowKbps = 220; const int kLowKbps = 220;
const int kHighKbps = 300; const int kHighKbps = 300;
const int kMinLowDurationMs = 4000; const int kMinLowDurationMs = 4000;
const int kMinPixelsPerFrame = 1;
const int kMinPixelsStop = 320 * 180;
const std::string kFieldTrial = "WebRTC-VP8-Forced-Fallback-Encoder"; const std::string kFieldTrial = "WebRTC-VP8-Forced-Fallback-Encoder";
} // namespace } // namespace
@ -350,6 +359,8 @@ class ForcedFallbackTest : public VideoEncoderSoftwareFallbackWrapperTest {
codec_.width = kWidth; codec_.width = kWidth;
codec_.height = kHeight; codec_.height = kHeight;
codec_.VP8()->numberOfTemporalLayers = 1; codec_.VP8()->numberOfTemporalLayers = 1;
codec_.VP8()->automaticResizeOn = true;
codec_.VP8()->frameDroppingOn = true;
codec_.VP8()->tl_factory = tl_factory.get(); codec_.VP8()->tl_factory = tl_factory.get();
rate_allocator_.reset( rate_allocator_.reset(
new SimulcastRateAllocator(codec_, std::move(tl_factory))); new SimulcastRateAllocator(codec_, std::move(tl_factory)));
@ -381,7 +392,8 @@ class ForcedFallbackTestEnabled : public ForcedFallbackTest {
: ForcedFallbackTest(kFieldTrial + "/Enabled-" + : ForcedFallbackTest(kFieldTrial + "/Enabled-" +
std::to_string(kLowKbps) + "," + std::to_string(kLowKbps) + "," +
std::to_string(kHighKbps) + "," + std::to_string(kHighKbps) + "," +
std::to_string(kMinLowDurationMs) + "/") {} std::to_string(kMinLowDurationMs) + "," +
std::to_string(kMinPixelsPerFrame) + "/") {}
}; };
class ForcedFallbackTestDisabled : public ForcedFallbackTest { class ForcedFallbackTestDisabled : public ForcedFallbackTest {
@ -575,4 +587,58 @@ TEST_F(ForcedFallbackTestEnabled, FallbackIsEndedForNonValidSettings) {
EncodeFrameAndVerifyLastName("fake-encoder"); EncodeFrameAndVerifyLastName("fake-encoder");
} }
TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithoutFallback) {
// Bitrate at low threshold.
SetRateAllocation(kLowKbps);
EncodeFrameAndVerifyLastName("fake-encoder");
// Default min pixels per frame should be used.
const auto settings = fallback_wrapper_.GetScalingSettings();
EXPECT_TRUE(settings.enabled);
EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
}
TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithFallback) {
// Bitrate at low threshold.
SetRateAllocation(kLowKbps);
EncodeFrameAndVerifyLastName("fake-encoder");
// Duration passed, expect fallback.
clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs));
EncodeFrameAndVerifyLastName("libvpx");
// Configured min pixels per frame should be used.
const auto settings = fallback_wrapper_.GetScalingSettings();
EXPECT_TRUE(settings.enabled);
EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);
}
TEST_F(ForcedFallbackTestEnabled, FallbackIsKeptIfResolutionIsTooSmall) {
// Bitrate at low threshold.
SetRateAllocation(kLowKbps);
EncodeFrameAndVerifyLastName("fake-encoder");
// Duration passed, expect fallback.
clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs));
EncodeFrameAndVerifyLastName("libvpx");
// Re-initialize encoder with a resolution less than |kMinPixelsStop|.
codec_.height = kMinPixelsStop / codec_.width - 1;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize));
EXPECT_EQ(1, fake_encoder_.init_encode_count_); // No change
SetRateAllocation(kHighKbps - 1);
EncodeFrameAndVerifyLastName("libvpx");
// Bitrate at high threshold but resolution too small for fallback to end.
SetRateAllocation(kHighKbps);
EncodeFrameAndVerifyLastName("libvpx");
// Re-initialize encoder with a resolution equal to |kMinPixelsStop|.
codec_.height++;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize));
EXPECT_EQ(1, fake_encoder_.init_encode_count_); // No change
SetRateAllocation(kHighKbps - 1);
EncodeFrameAndVerifyLastName("libvpx");
// Bitrate at high threshold and resolution large enough for fallback to end.
SetRateAllocation(kHighKbps);
EncodeFrameAndVerifyLastName("fake-encoder");
}
} // namespace webrtc } // namespace webrtc

View File

@ -464,6 +464,7 @@ if (rtc_include_tests) {
"../../api:video_frame_api", "../../api:video_frame_api",
"../../common_video:common_video", "../../common_video:common_video",
"../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_approved",
"../../test:field_trial",
"../../test:test_support", "../../test:test_support",
"../../test:video_test_common", "../../test:video_test_common",
"../video_capture", "../video_capture",

View File

@ -20,9 +20,11 @@
#include "webrtc/rtc_base/checks.h" #include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/optional.h" #include "webrtc/rtc_base/optional.h"
#include "webrtc/rtc_base/timeutils.h" #include "webrtc/rtc_base/timeutils.h"
#include "webrtc/test/field_trial.h"
#include "webrtc/test/frame_utils.h" #include "webrtc/test/frame_utils.h"
#include "webrtc/test/gtest.h" #include "webrtc/test/gtest.h"
#include "webrtc/test/testsupport/fileutils.h" #include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/test/video_codec_settings.h"
namespace webrtc { namespace webrtc {
@ -39,6 +41,10 @@ enum { kMaxWaitDecTimeMs = 25 };
constexpr uint32_t kTestTimestamp = 123; constexpr uint32_t kTestTimestamp = 123;
constexpr int64_t kTestNtpTimeMs = 456; constexpr int64_t kTestNtpTimeMs = 456;
constexpr uint32_t kTimestampIncrementPerFrame = 3000; constexpr uint32_t kTimestampIncrementPerFrame = 3000;
constexpr int kNumCores = 1;
constexpr size_t kMaxPayloadSize = 1440;
constexpr int kMinPixelsPerFrame = 12345;
constexpr int kDefaultMinPixelsPerFrame = 320 * 180;
} // namespace } // namespace
@ -143,6 +149,10 @@ void Vp8UnitTestDecodeCompleteCallback::Decoded(
class TestVp8Impl : public ::testing::Test { class TestVp8Impl : public ::testing::Test {
protected: protected:
TestVp8Impl() : TestVp8Impl("") {}
explicit TestVp8Impl(const std::string& field_trials)
: override_field_trials_(field_trials) {}
virtual void SetUp() { virtual void SetUp() {
encoder_.reset(VP8Encoder::Create()); encoder_.reset(VP8Encoder::Create());
decoder_.reset(VP8Decoder::Create()); decoder_.reset(VP8Decoder::Create());
@ -190,9 +200,11 @@ class TestVp8Impl : public ::testing::Test {
codec_settings_.VP8()->tl_factory = &tl_factory_; codec_settings_.VP8()->tl_factory = &tl_factory_;
codec_settings_.VP8()->numberOfTemporalLayers = 1; codec_settings_.VP8()->numberOfTemporalLayers = 1;
EXPECT_EQ(
WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, 1, 1440)); decoder_->InitDecode(&codec_settings_, kNumCores));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_settings_, 1));
} }
size_t WaitForEncodedFrame() const { size_t WaitForEncodedFrame() const {
@ -228,6 +240,7 @@ class TestVp8Impl : public ::testing::Test {
const int kWidth = 172; const int kWidth = 172;
const int kHeight = 144; const int kHeight = 144;
test::ScopedFieldTrials override_field_trials_;
std::unique_ptr<Vp8UnitTestEncodeCompleteCallback> encode_complete_callback_; std::unique_ptr<Vp8UnitTestEncodeCompleteCallback> encode_complete_callback_;
std::unique_ptr<Vp8UnitTestDecodeCompleteCallback> decode_complete_callback_; std::unique_ptr<Vp8UnitTestDecodeCompleteCallback> decode_complete_callback_;
std::unique_ptr<uint8_t[]> source_buffer_; std::unique_ptr<uint8_t[]> source_buffer_;
@ -266,12 +279,13 @@ TEST_F(TestVp8Impl, EncoderParameterTest) {
codec_settings_.maxFramerate)); codec_settings_.maxFramerate));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, 1, 1440)); encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
// Decoder parameter tests. // Decoder parameter tests.
// Calls before InitDecode(). // Calls before InitDecode().
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release()); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release());
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_settings_, 1)); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
decoder_->InitDecode(&codec_settings_, kNumCores));
} }
// We only test the encoder here, since the decoded frame rotation is set based // We only test the encoder here, since the decoded frame rotation is set based
@ -374,7 +388,7 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) {
// Override default settings. // Override default settings.
codec_settings_.VP8()->numberOfTemporalLayers = 2; codec_settings_.VP8()->numberOfTemporalLayers = 2;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, 1, 1440)); encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
// Temporal layer 0. // Temporal layer 0.
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
@ -410,7 +424,7 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) {
// Reinit. // Reinit.
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release());
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, 1, 1440)); encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
// Temporal layer 0. // Temporal layer 0.
input_frame_->set_timestamp(input_frame_->timestamp() + input_frame_->set_timestamp(input_frame_->timestamp() +
@ -445,4 +459,46 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) {
1); 1);
} }
TEST_F(TestVp8Impl, ScalingDisabledIfAutomaticResizeOff) {
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_);
codec_settings_.VP8()->tl_factory = &tl_factory_;
codec_settings_.VP8()->automaticResizeOn = false;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
EXPECT_FALSE(settings.enabled);
}
TEST_F(TestVp8Impl, ScalingEnabledIfAutomaticResizeOn) {
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_);
codec_settings_.VP8()->tl_factory = &tl_factory_;
codec_settings_.VP8()->automaticResizeOn = true;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
EXPECT_TRUE(settings.enabled);
EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
}
class TestVp8ImplWithForcedFallbackEnabled : public TestVp8Impl {
public:
TestVp8ImplWithForcedFallbackEnabled()
: TestVp8Impl("WebRTC-VP8-Forced-Fallback-Encoder/Enabled-1,2,3," +
std::to_string(kMinPixelsPerFrame) + "/") {}
};
TEST_F(TestVp8ImplWithForcedFallbackEnabled, MinPixelsPerFrameConfigured) {
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_);
codec_settings_.VP8()->tl_factory = &tl_factory_;
codec_settings_.VP8()->automaticResizeOn = true;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
EXPECT_TRUE(settings.enabled);
EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);
}
} // namespace webrtc } // namespace webrtc

View File

@ -42,6 +42,8 @@ namespace {
const char kVp8PostProcArmFieldTrial[] = "WebRTC-VP8-Postproc-Arm"; const char kVp8PostProcArmFieldTrial[] = "WebRTC-VP8-Postproc-Arm";
const char kVp8GfBoostFieldTrial[] = "WebRTC-VP8-GfBoost"; const char kVp8GfBoostFieldTrial[] = "WebRTC-VP8-GfBoost";
const char kVp8ForceFallbackEncoderFieldTrial[] =
"WebRTC-VP8-Forced-Fallback-Encoder";
const int kTokenPartitions = VP8_ONE_TOKENPARTITION; const int kTokenPartitions = VP8_ONE_TOKENPARTITION;
enum { kVp8ErrorPropagationTh = 30 }; enum { kVp8ErrorPropagationTh = 30 };
@ -110,6 +112,31 @@ int NumStreamsDisabled(const std::vector<bool>& streams) {
return num_disabled; return num_disabled;
} }
rtc::Optional<int> GetForcedFallbackMinPixelsFromFieldTrialGroup() {
if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial))
return rtc::Optional<int>();
std::string group =
webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial);
if (group.empty())
return rtc::Optional<int>();
int low_kbps;
int high_kbps;
int min_low_ms;
int min_pixels;
if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d", &low_kbps, &high_kbps,
&min_low_ms, &min_pixels) != 4) {
return rtc::Optional<int>();
}
if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 ||
high_kbps <= low_kbps) {
return rtc::Optional<int>();
}
return rtc::Optional<int>(min_pixels);
}
bool GetGfBoostPercentageFromFieldTrialGroup(int* boost_percentage) { bool GetGfBoostPercentageFromFieldTrialGroup(int* boost_percentage) {
std::string group = webrtc::field_trial::FindFullName(kVp8GfBoostFieldTrial); std::string group = webrtc::field_trial::FindFullName(kVp8GfBoostFieldTrial);
if (group.empty()) if (group.empty())
@ -181,6 +208,7 @@ vpx_enc_frame_flags_t VP8EncoderImpl::EncodeFlags(
VP8EncoderImpl::VP8EncoderImpl() VP8EncoderImpl::VP8EncoderImpl()
: use_gf_boost_(webrtc::field_trial::IsEnabled(kVp8GfBoostFieldTrial)), : use_gf_boost_(webrtc::field_trial::IsEnabled(kVp8GfBoostFieldTrial)),
min_pixels_per_frame_(GetForcedFallbackMinPixelsFromFieldTrialGroup()),
encoded_complete_callback_(nullptr), encoded_complete_callback_(nullptr),
inited_(false), inited_(false),
timestamp_(0), timestamp_(0),
@ -935,6 +963,10 @@ VideoEncoder::ScalingSettings VP8EncoderImpl::GetScalingSettings() const {
const bool enable_scaling = encoders_.size() == 1 && const bool enable_scaling = encoders_.size() == 1 &&
configurations_[0].rc_dropframe_thresh > 0 && configurations_[0].rc_dropframe_thresh > 0 &&
codec_.VP8().automaticResizeOn; codec_.VP8().automaticResizeOn;
if (enable_scaling && min_pixels_per_frame_) {
return VideoEncoder::ScalingSettings(enable_scaling,
*min_pixels_per_frame_);
}
return VideoEncoder::ScalingSettings(enable_scaling); return VideoEncoder::ScalingSettings(enable_scaling);
} }

View File

@ -94,6 +94,7 @@ class VP8EncoderImpl : public VP8Encoder {
uint32_t MaxIntraTarget(uint32_t optimal_buffer_size); uint32_t MaxIntraTarget(uint32_t optimal_buffer_size);
const bool use_gf_boost_; const bool use_gf_boost_;
const rtc::Optional<int> min_pixels_per_frame_;
EncodedImageCallback* encoded_complete_callback_; EncodedImageCallback* encoded_complete_callback_;
VideoCodec codec_; VideoCodec codec_;

View File

@ -38,12 +38,6 @@ namespace {
// Time interval for logging frame counts. // Time interval for logging frame counts.
const int64_t kFrameLogIntervalMs = 60000; const int64_t kFrameLogIntervalMs = 60000;
// We will never ask for a resolution lower than this.
// TODO(kthelgason): Lower this limit when better testing
// on MediaCodec and fallback implementations are in place.
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206
const int kMinPixelsPerFrame = 320 * 180;
const int kMinFramerateFps = 2; const int kMinFramerateFps = 2;
const int kMaxFramerateFps = 120; const int kMaxFramerateFps = 120;
@ -233,7 +227,7 @@ class VideoStreamEncoder::VideoSourceProxy {
source_->AddOrUpdateSink(video_stream_encoder_, sink_wants_); source_->AddOrUpdateSink(video_stream_encoder_, sink_wants_);
} }
bool RequestResolutionLowerThan(int pixel_count) { bool RequestResolutionLowerThan(int pixel_count, int min_pixels_per_frame) {
// Called on the encoder task queue. // Called on the encoder task queue.
rtc::CritScope lock(&crit_); rtc::CritScope lock(&crit_);
if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) { if (!source_ || !IsResolutionScalingEnabled(degradation_preference_)) {
@ -244,7 +238,7 @@ class VideoStreamEncoder::VideoSourceProxy {
// The input video frame size will have a resolution less than or equal to // The input video frame size will have a resolution less than or equal to
// |max_pixel_count| depending on how the source can scale the frame size. // |max_pixel_count| depending on how the source can scale the frame size.
const int pixels_wanted = (pixel_count * 3) / 5; const int pixels_wanted = (pixel_count * 3) / 5;
if (pixels_wanted < kMinPixelsPerFrame || if (pixels_wanted < min_pixels_per_frame ||
pixels_wanted >= sink_wants_.max_pixel_count) { pixels_wanted >= sink_wants_.max_pixel_count) {
return false; return false;
} }
@ -990,7 +984,8 @@ void VideoStreamEncoder::AdaptDown(AdaptReason reason) {
case VideoSendStream::DegradationPreference::kMaintainFramerate: case VideoSendStream::DegradationPreference::kMaintainFramerate:
// Scale down resolution. // Scale down resolution.
if (!source_proxy_->RequestResolutionLowerThan( if (!source_proxy_->RequestResolutionLowerThan(
adaptation_request.input_pixel_count_)) { adaptation_request.input_pixel_count_,
settings_.encoder->GetScalingSettings().min_pixels_per_frame)) {
return; return;
} }
GetAdaptCounter().IncrementResolution(reason); GetAdaptCounter().IncrementResolution(reason);

View File

@ -29,8 +29,6 @@
#include "webrtc/video/video_stream_encoder.h" #include "webrtc/video/video_stream_encoder.h"
namespace { namespace {
// TODO(kthelgason): Lower this limit when better testing
// on MediaCodec and fallback implementations are in place.
const int kMinPixelsPerFrame = 320 * 180; const int kMinPixelsPerFrame = 320 * 180;
const int kMinFramerateFps = 2; const int kMinFramerateFps = 2;
const int64_t kFrameTimeoutMs = 100; const int64_t kFrameTimeoutMs = 100;
@ -482,7 +480,7 @@ class VideoStreamEncoderTest : public ::testing::Test {
VideoEncoder::ScalingSettings GetScalingSettings() const override { VideoEncoder::ScalingSettings GetScalingSettings() const override {
rtc::CritScope lock(&local_crit_sect_); rtc::CritScope lock(&local_crit_sect_);
if (quality_scaling_) if (quality_scaling_)
return VideoEncoder::ScalingSettings(true, 1, 2); return VideoEncoder::ScalingSettings(true, 1, 2, kMinPixelsPerFrame);
return VideoEncoder::ScalingSettings(false); return VideoEncoder::ScalingSettings(false);
} }
@ -1909,7 +1907,7 @@ TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
// Enable adapter, expected input resolutions when downscaling: // Enable adapter, expected input resolutions when downscaling:
// 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit) // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
video_source_.set_adaptation_enabled(true); video_source_.set_adaptation_enabled(true);
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution); EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);