From 142fcc96d60af65e05596925bea0fc9db2fa9c1d Mon Sep 17 00:00:00 2001 From: asapersson Date: Thu, 17 Aug 2017 08:58:54 -0700 Subject: [PATCH] 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} --- webrtc/api/video_codecs/video_encoder.cc | 11 +++ webrtc/api/video_codecs/video_encoder.h | 8 ++ .../videoencodersoftwarefallbackwrapper.cc | 20 +++-- .../videoencodersoftwarefallbackwrapper.h | 14 ++-- ...encodersoftwarefallbackwrapper_unittest.cc | 74 ++++++++++++++++++- webrtc/modules/video_coding/BUILD.gn | 1 + .../codecs/vp8/test/vp8_impl_unittest.cc | 68 +++++++++++++++-- .../video_coding/codecs/vp8/vp8_impl.cc | 32 ++++++++ .../video_coding/codecs/vp8/vp8_impl.h | 1 + webrtc/video/video_stream_encoder.cc | 13 +--- webrtc/video/video_stream_encoder_unittest.cc | 6 +- 11 files changed, 213 insertions(+), 35 deletions(-) diff --git a/webrtc/api/video_codecs/video_encoder.cc b/webrtc/api/video_codecs/video_encoder.cc index 0da0e60c45..f61e4e14f8 100644 --- a/webrtc/api/video_codecs/video_encoder.cc +++ b/webrtc/api/video_codecs/video_encoder.cc @@ -64,6 +64,17 @@ VideoEncoder::ScalingSettings::ScalingSettings(bool on, int low, int high) : enabled(on), thresholds(rtc::Optional(QpThresholds(low, high))) {} +VideoEncoder::ScalingSettings::ScalingSettings(bool on, + int low, + int high, + int min_pixels) + : enabled(on), + thresholds(rtc::Optional(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() {} diff --git a/webrtc/api/video_codecs/video_encoder.h b/webrtc/api/video_codecs/video_encoder.h index 0f21cae13a..7a319d7216 100644 --- a/webrtc/api/video_codecs/video_encoder.h +++ b/webrtc/api/video_codecs/video_encoder.h @@ -75,12 +75,20 @@ class VideoEncoder { }; struct ScalingSettings { 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); ScalingSettings(const ScalingSettings&); ~ScalingSettings(); const bool enabled; const rtc::Optional 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(); diff --git a/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc b/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc index 9f5dedabc0..2bc74a7e72 100644 --- a/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc +++ b/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc @@ -50,12 +50,14 @@ void GetForcedFallbackParamsFromFieldTrialGroup(uint32_t* param_low_kbps, int low_kbps; int high_kbps; int min_low_ms; - if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &low_kbps, &high_kbps, - &min_low_ms) != 3) { + int min_pixels; + 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."; 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."; return; } @@ -245,6 +247,8 @@ bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const { VideoEncoder::ScalingSettings VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { + if (forced_fallback_possible_ && fallback_encoder_) + return fallback_encoder_->GetScalingSettings(); return encoder_->GetScalingSettings(); } @@ -272,8 +276,10 @@ bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() { if (!IsForcedFallbackActive()) return false; - if (!forced_fallback_.ShouldStop(bitrate_allocation_.get_sum_kbps())) + if (!forced_fallback_.ShouldStop(bitrate_allocation_.get_sum_kbps(), + codec_settings_)) { return false; + } // Release the forced fallback encoder. if (encoder_->InitEncode(&codec_settings_, number_of_cores_, @@ -343,8 +349,10 @@ bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStart( } bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStop( - uint32_t bitrate_kbps) const { - return bitrate_kbps >= high_kbps; + uint32_t bitrate_kbps, + const VideoCodec& codec) const { + return bitrate_kbps >= high_kbps && + (codec.width * codec.height >= kMinPixelsStop); } } // namespace webrtc diff --git a/webrtc/media/engine/videoencodersoftwarefallbackwrapper.h b/webrtc/media/engine/videoencodersoftwarefallbackwrapper.h index ea7e13d353..d11a0f678e 100644 --- a/webrtc/media/engine/videoencodersoftwarefallbackwrapper.h +++ b/webrtc/media/engine/videoencodersoftwarefallbackwrapper.h @@ -52,22 +52,24 @@ class VideoEncoderSoftwareFallbackWrapper : public VideoEncoder { // If |forced_fallback_possible_| is true: // 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 - // than |kMaxPixels|. - // If the bitrate is above |high_kbps|, the forced fallback is requested to - // immediately be stopped. + // than |kMaxPixelsStart|. + // If the bitrate is above |high_kbps| and the resolution is not smaller than + // |kMinPixelsStop|, the forced fallback is requested to immediately be + // stopped. class ForcedFallbackParams { public: 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(); } bool IsValid(const VideoCodec& codec) const { - return codec.width * codec.height <= kMaxPixels; + return codec.width * codec.height <= kMaxPixelsStart; } rtc::Optional start_ms; // Set when bitrate is below |low_kbps|. uint32_t low_kbps = 100; uint32_t high_kbps = 150; int64_t min_low_ms = 10000; - const int kMaxPixels = 320 * 240; + const int kMaxPixelsStart = 320 * 240; + const int kMinPixelsStop = 320 * 180; }; bool RequestForcedFallback(); diff --git a/webrtc/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc b/webrtc/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc index f66551958f..ecf719948f 100644 --- a/webrtc/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc +++ b/webrtc/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc @@ -29,6 +29,7 @@ const int kHeight = 240; const int kNumCores = 2; const uint32_t kFramerate = 30; const size_t kMaxPayloadSize = 800; +const int kDefaultMinPixelsPerFrame = 320 * 180; } // namespace class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { @@ -93,6 +94,10 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { return "fake-encoder"; } + VideoEncoder::ScalingSettings GetScalingSettings() const override { + return VideoEncoder::ScalingSettings(true); + } + int init_encode_count_ = 0; int32_t init_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) { - rtc::scoped_refptr buffer = I420Buffer::Create(kWidth, kHeight); + rtc::scoped_refptr buffer = + I420Buffer::Create(codec_.width, codec_.height); I420Buffer::SetBlack(buffer); std::vector types(1, kVideoFrameKey); @@ -299,9 +305,10 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest, } TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) { - VideoCodec codec = {}; + codec_.width = kWidth; + codec_.height = kHeight; fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_); - fallback_wrapper_.InitEncode(&codec, kNumCores, kMaxPayloadSize); + fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize); EncodeFrame(); CheckLastEncoderName("fake-encoder"); } @@ -318,6 +325,8 @@ namespace { const int kLowKbps = 220; const int kHighKbps = 300; const int kMinLowDurationMs = 4000; +const int kMinPixelsPerFrame = 1; +const int kMinPixelsStop = 320 * 180; const std::string kFieldTrial = "WebRTC-VP8-Forced-Fallback-Encoder"; } // namespace @@ -350,6 +359,8 @@ class ForcedFallbackTest : public VideoEncoderSoftwareFallbackWrapperTest { codec_.width = kWidth; codec_.height = kHeight; codec_.VP8()->numberOfTemporalLayers = 1; + codec_.VP8()->automaticResizeOn = true; + codec_.VP8()->frameDroppingOn = true; codec_.VP8()->tl_factory = tl_factory.get(); rate_allocator_.reset( new SimulcastRateAllocator(codec_, std::move(tl_factory))); @@ -381,7 +392,8 @@ class ForcedFallbackTestEnabled : public ForcedFallbackTest { : ForcedFallbackTest(kFieldTrial + "/Enabled-" + std::to_string(kLowKbps) + "," + std::to_string(kHighKbps) + "," + - std::to_string(kMinLowDurationMs) + "/") {} + std::to_string(kMinLowDurationMs) + "," + + std::to_string(kMinPixelsPerFrame) + "/") {} }; class ForcedFallbackTestDisabled : public ForcedFallbackTest { @@ -575,4 +587,58 @@ TEST_F(ForcedFallbackTestEnabled, FallbackIsEndedForNonValidSettings) { 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 diff --git a/webrtc/modules/video_coding/BUILD.gn b/webrtc/modules/video_coding/BUILD.gn index 52d0327bfb..ef6c262011 100644 --- a/webrtc/modules/video_coding/BUILD.gn +++ b/webrtc/modules/video_coding/BUILD.gn @@ -464,6 +464,7 @@ if (rtc_include_tests) { "../../api:video_frame_api", "../../common_video:common_video", "../../rtc_base:rtc_base_approved", + "../../test:field_trial", "../../test:test_support", "../../test:video_test_common", "../video_capture", diff --git a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index 7e04167370..d9871873b8 100644 --- a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -20,9 +20,11 @@ #include "webrtc/rtc_base/checks.h" #include "webrtc/rtc_base/optional.h" #include "webrtc/rtc_base/timeutils.h" +#include "webrtc/test/field_trial.h" #include "webrtc/test/frame_utils.h" #include "webrtc/test/gtest.h" #include "webrtc/test/testsupport/fileutils.h" +#include "webrtc/test/video_codec_settings.h" namespace webrtc { @@ -39,6 +41,10 @@ enum { kMaxWaitDecTimeMs = 25 }; constexpr uint32_t kTestTimestamp = 123; constexpr int64_t kTestNtpTimeMs = 456; constexpr uint32_t kTimestampIncrementPerFrame = 3000; +constexpr int kNumCores = 1; +constexpr size_t kMaxPayloadSize = 1440; +constexpr int kMinPixelsPerFrame = 12345; +constexpr int kDefaultMinPixelsPerFrame = 320 * 180; } // namespace @@ -143,6 +149,10 @@ void Vp8UnitTestDecodeCompleteCallback::Decoded( class TestVp8Impl : public ::testing::Test { protected: + TestVp8Impl() : TestVp8Impl("") {} + explicit TestVp8Impl(const std::string& field_trials) + : override_field_trials_(field_trials) {} + virtual void SetUp() { encoder_.reset(VP8Encoder::Create()); decoder_.reset(VP8Decoder::Create()); @@ -190,9 +200,11 @@ class TestVp8Impl : public ::testing::Test { codec_settings_.VP8()->tl_factory = &tl_factory_; codec_settings_.VP8()->numberOfTemporalLayers = 1; + EXPECT_EQ( + WEBRTC_VIDEO_CODEC_OK, + encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize)); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - encoder_->InitEncode(&codec_settings_, 1, 1440)); - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_settings_, 1)); + decoder_->InitDecode(&codec_settings_, kNumCores)); } size_t WaitForEncodedFrame() const { @@ -228,6 +240,7 @@ class TestVp8Impl : public ::testing::Test { const int kWidth = 172; const int kHeight = 144; + test::ScopedFieldTrials override_field_trials_; std::unique_ptr encode_complete_callback_; std::unique_ptr decode_complete_callback_; std::unique_ptr source_buffer_; @@ -266,12 +279,13 @@ TEST_F(TestVp8Impl, EncoderParameterTest) { codec_settings_.maxFramerate)); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - encoder_->InitEncode(&codec_settings_, 1, 1440)); + encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize)); // Decoder parameter tests. // Calls before InitDecode(). 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 @@ -374,7 +388,7 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) { // Override default settings. codec_settings_.VP8()->numberOfTemporalLayers = 2; EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - encoder_->InitEncode(&codec_settings_, 1, 1440)); + encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize)); // Temporal layer 0. EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, @@ -410,7 +424,7 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) { // Reinit. EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - encoder_->InitEncode(&codec_settings_, 1, 1440)); + encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize)); // Temporal layer 0. input_frame_->set_timestamp(input_frame_->timestamp() + @@ -445,4 +459,46 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) { 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 diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc index 3f9f879bef..5933073a3f 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -42,6 +42,8 @@ namespace { const char kVp8PostProcArmFieldTrial[] = "WebRTC-VP8-Postproc-Arm"; const char kVp8GfBoostFieldTrial[] = "WebRTC-VP8-GfBoost"; +const char kVp8ForceFallbackEncoderFieldTrial[] = + "WebRTC-VP8-Forced-Fallback-Encoder"; const int kTokenPartitions = VP8_ONE_TOKENPARTITION; enum { kVp8ErrorPropagationTh = 30 }; @@ -110,6 +112,31 @@ int NumStreamsDisabled(const std::vector& streams) { return num_disabled; } +rtc::Optional GetForcedFallbackMinPixelsFromFieldTrialGroup() { + if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial)) + return rtc::Optional(); + + std::string group = + webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial); + if (group.empty()) + return rtc::Optional(); + + 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(); + } + + if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 || + high_kbps <= low_kbps) { + return rtc::Optional(); + } + return rtc::Optional(min_pixels); +} + bool GetGfBoostPercentageFromFieldTrialGroup(int* boost_percentage) { std::string group = webrtc::field_trial::FindFullName(kVp8GfBoostFieldTrial); if (group.empty()) @@ -181,6 +208,7 @@ vpx_enc_frame_flags_t VP8EncoderImpl::EncodeFlags( VP8EncoderImpl::VP8EncoderImpl() : use_gf_boost_(webrtc::field_trial::IsEnabled(kVp8GfBoostFieldTrial)), + min_pixels_per_frame_(GetForcedFallbackMinPixelsFromFieldTrialGroup()), encoded_complete_callback_(nullptr), inited_(false), timestamp_(0), @@ -935,6 +963,10 @@ VideoEncoder::ScalingSettings VP8EncoderImpl::GetScalingSettings() const { const bool enable_scaling = encoders_.size() == 1 && configurations_[0].rc_dropframe_thresh > 0 && codec_.VP8().automaticResizeOn; + if (enable_scaling && min_pixels_per_frame_) { + return VideoEncoder::ScalingSettings(enable_scaling, + *min_pixels_per_frame_); + } return VideoEncoder::ScalingSettings(enable_scaling); } diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h index 7b5e000d23..30a4a1a642 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h @@ -94,6 +94,7 @@ class VP8EncoderImpl : public VP8Encoder { uint32_t MaxIntraTarget(uint32_t optimal_buffer_size); const bool use_gf_boost_; + const rtc::Optional min_pixels_per_frame_; EncodedImageCallback* encoded_complete_callback_; VideoCodec codec_; diff --git a/webrtc/video/video_stream_encoder.cc b/webrtc/video/video_stream_encoder.cc index 51fb1d43d6..7e25df09b4 100644 --- a/webrtc/video/video_stream_encoder.cc +++ b/webrtc/video/video_stream_encoder.cc @@ -38,12 +38,6 @@ namespace { // Time interval for logging frame counts. 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 kMaxFramerateFps = 120; @@ -233,7 +227,7 @@ class VideoStreamEncoder::VideoSourceProxy { 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. rtc::CritScope lock(&crit_); 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 // |max_pixel_count| depending on how the source can scale the frame size. 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) { return false; } @@ -990,7 +984,8 @@ void VideoStreamEncoder::AdaptDown(AdaptReason reason) { case VideoSendStream::DegradationPreference::kMaintainFramerate: // Scale down resolution. if (!source_proxy_->RequestResolutionLowerThan( - adaptation_request.input_pixel_count_)) { + adaptation_request.input_pixel_count_, + settings_.encoder->GetScalingSettings().min_pixels_per_frame)) { return; } GetAdaptCounter().IncrementResolution(reason); diff --git a/webrtc/video/video_stream_encoder_unittest.cc b/webrtc/video/video_stream_encoder_unittest.cc index 69b911942e..9e7fa77b8f 100644 --- a/webrtc/video/video_stream_encoder_unittest.cc +++ b/webrtc/video/video_stream_encoder_unittest.cc @@ -29,8 +29,6 @@ #include "webrtc/video/video_stream_encoder.h" namespace { -// TODO(kthelgason): Lower this limit when better testing -// on MediaCodec and fallback implementations are in place. const int kMinPixelsPerFrame = 320 * 180; const int kMinFramerateFps = 2; const int64_t kFrameTimeoutMs = 100; @@ -482,7 +480,7 @@ class VideoStreamEncoderTest : public ::testing::Test { VideoEncoder::ScalingSettings GetScalingSettings() const override { rtc::CritScope lock(&local_crit_sect_); if (quality_scaling_) - return VideoEncoder::ScalingSettings(true, 1, 2); + return VideoEncoder::ScalingSettings(true, 1, 2, kMinPixelsPerFrame); return VideoEncoder::ScalingSettings(false); } @@ -1909,7 +1907,7 @@ TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) { video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); // 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); EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);