From 45bbc8ac1968acd606c8bc68cf8454986df4c647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85sa=20Persson?= Date: Mon, 13 Nov 2017 10:16:47 +0100 Subject: [PATCH] Change forced software encoder fallback for VP8 to be only based on resolution and not bitrate. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switches from VP8 HW to VP8 SW for resolutions <= max_pixels. |<- min_pixels VP8 SW max_pixels ->| VP8 HW | Bug: webrtc:6634 Change-Id: Ib324df2b8418659c29d999259c0ed47448310696 Reviewed-on: https://webrtc-review.googlesource.com/7362 Commit-Queue: Åsa Persson Reviewed-by: Rasmus Brandt Reviewed-by: Magnus Jedvert Cr-Commit-Position: refs/heads/master@{#20646} --- media/engine/constants.h | 2 +- media/engine/simulcast.cc | 2 +- .../videoencodersoftwarefallbackwrapper.cc | 157 ++++----- .../videoencodersoftwarefallbackwrapper.h | 28 +- ...encodersoftwarefallbackwrapper_unittest.cc | 298 ++++++------------ media/engine/webrtcvideoengine.cc | 34 +- media/engine/webrtcvideoengine_unittest.cc | 16 +- ...deoprocessor_integrationtest_mediacodec.cc | 30 -- .../codecs/vp8/default_temporal_layers.cc | 3 +- .../codecs/vp8/test/vp8_impl_unittest.cc | 19 -- modules/video_coding/codecs/vp8/vp8_impl.cc | 32 -- modules/video_coding/codecs/vp8/vp8_impl.h | 1 - video/payload_router.cc | 2 +- video/payload_router_unittest.cc | 4 +- video/picture_id_tests.cc | 2 +- video/send_statistics_proxy.cc | 47 ++- video/send_statistics_proxy.h | 5 +- video/send_statistics_proxy_unittest.cc | 18 +- video/video_send_stream.cc | 35 +- 19 files changed, 283 insertions(+), 452 deletions(-) diff --git a/media/engine/constants.h b/media/engine/constants.h index cd4c0a2c74..ea6c0754a6 100644 --- a/media/engine/constants.h +++ b/media/engine/constants.h @@ -18,7 +18,7 @@ extern const int kVideoRtpBufferSize; extern const char kH264CodecName[]; -extern const int kMinVideoBitrateKbps; +extern const int kMinVideoBitrateBps; } // namespace cricket diff --git a/media/engine/simulcast.cc b/media/engine/simulcast.cc index c2ac2d58d2..4ec4afa71f 100644 --- a/media/engine/simulcast.cc +++ b/media/engine/simulcast.cc @@ -209,7 +209,7 @@ std::vector GetSimulcastConfig(size_t max_streams, streams[0].height = height; streams[0].max_qp = max_qp; streams[0].max_framerate = 5; - streams[0].min_bitrate_bps = kMinVideoBitrateKbps * 1000; + streams[0].min_bitrate_bps = kMinVideoBitrateBps; streams[0].target_bitrate_bps = config.tl0_bitrate_kbps * 1000; streams[0].max_bitrate_bps = config.tl1_bitrate_kbps * 1000; streams[0].temporal_layer_thresholds_bps.clear(); diff --git a/media/engine/videoencodersoftwarefallbackwrapper.cc b/media/engine/videoencodersoftwarefallbackwrapper.cc index 1a07cd80c8..5e57c557f2 100644 --- a/media/engine/videoencodersoftwarefallbackwrapper.cc +++ b/media/engine/videoencodersoftwarefallbackwrapper.cc @@ -23,7 +23,7 @@ namespace webrtc { namespace { const char kVp8ForceFallbackEncoderFieldTrial[] = - "WebRTC-VP8-Forced-Fallback-Encoder"; + "WebRTC-VP8-Forced-Fallback-Encoder-v2"; bool EnableForcedFallback(const cricket::VideoCodec& codec) { if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial)) @@ -38,35 +38,32 @@ bool IsForcedFallbackPossible(const VideoCodec& codec_settings) { codec_settings.VP8().numberOfTemporalLayers == 1; } -void GetForcedFallbackParamsFromFieldTrialGroup(uint32_t* param_low_kbps, - uint32_t* param_high_kbps, - int64_t* param_min_low_ms) { - RTC_DCHECK(param_low_kbps); - RTC_DCHECK(param_high_kbps); - RTC_DCHECK(param_min_low_ms); +void GetForcedFallbackParamsFromFieldTrialGroup(int* param_min_pixels, + int* param_max_pixels, + int minimum_max_pixels) { + RTC_DCHECK(param_min_pixels); + RTC_DCHECK(param_max_pixels); std::string group = webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial); if (group.empty()) return; - 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) { + int max_pixels; + int min_bps; + if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, + &min_bps) != 3) { RTC_LOG(LS_WARNING) << "Invalid number of forced fallback parameters provided."; return; } - if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 || - high_kbps <= low_kbps) { + if (min_pixels <= 0 || max_pixels < minimum_max_pixels || + max_pixels < min_pixels || min_bps <= 0) { RTC_LOG(LS_WARNING) << "Invalid forced fallback parameter value provided."; return; } - *param_low_kbps = low_kbps; - *param_high_kbps = high_kbps; - *param_min_low_ms = min_low_ms; + *param_min_pixels = min_pixels; + *param_max_pixels = max_pixels; } } // namespace @@ -85,9 +82,10 @@ VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( callback_(nullptr), forced_fallback_possible_(EnableForcedFallback(codec)) { if (forced_fallback_possible_) { - GetForcedFallbackParamsFromFieldTrialGroup(&forced_fallback_.low_kbps, - &forced_fallback_.high_kbps, - &forced_fallback_.min_low_ms); + GetForcedFallbackParamsFromFieldTrialGroup( + &forced_fallback_.min_pixels_, &forced_fallback_.max_pixels_, + encoder_->GetScalingSettings().min_pixels_per_frame - + 1); // No HW below. } } @@ -117,9 +115,6 @@ bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { if (channel_parameters_set_) fallback_encoder_->SetChannelParameters(packet_loss_, rtt_); - fallback_implementation_name_ = - std::string(fallback_encoder_->ImplementationName()) + - " (fallback from: " + encoder_->ImplementationName() + ")"; // Since we're switching to the fallback encoder, Release the real encoder. It // may be re-initialized via InitEncode later, and it will continue to get // Set calls for rates and channel parameters in the meantime. @@ -145,7 +140,11 @@ int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode( if (TryReInitForcedFallbackEncoder()) { return WEBRTC_VIDEO_CODEC_OK; } - forced_fallback_.Reset(); + // Try to init forced software codec if it should be used. + if (TryInitForcedFallbackEncoder()) { + return WEBRTC_VIDEO_CODEC_OK; + } + forced_fallback_.active_ = false; int32_t ret = encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); @@ -190,27 +189,12 @@ int32_t VideoEncoderSoftwareFallbackWrapper::Encode( const VideoFrame& frame, const CodecSpecificInfo* codec_specific_info, const std::vector* frame_types) { - if (TryReleaseForcedFallbackEncoder()) { - // Frame may have been converted from kNative to kI420 during fallback. - if (encoder_->SupportsNativeHandle() && - frame.video_frame_buffer()->type() != VideoFrameBuffer::Type::kNative) { - RTC_LOG(LS_WARNING) - << "Encoder supports native frames, dropping one frame " - << "to avoid possible reconfig due to format change."; - return WEBRTC_VIDEO_CODEC_ERROR; - } - } if (fallback_encoder_) return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types); // If requested, try a software fallback. - bool fallback_requested = - (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) || - (ret == WEBRTC_VIDEO_CODEC_OK && RequestForcedFallback()); + bool fallback_requested = (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE); if (fallback_requested && InitFallbackEncoder()) { - // Fallback was successful. - if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) - forced_fallback_.Reset(); // Not a forced fallback. if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && !fallback_encoder_->SupportsNativeHandle()) { RTC_LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " @@ -256,8 +240,21 @@ bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const { VideoEncoder::ScalingSettings VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { - if (forced_fallback_possible_ && fallback_encoder_) - return fallback_encoder_->GetScalingSettings(); + if (forced_fallback_possible_) { + if (forced_fallback_.active_) { + return VideoEncoder::ScalingSettings( + codec_settings_.VP8().automaticResizeOn, + forced_fallback_.min_pixels_); + } + const auto settings = encoder_->GetScalingSettings(); + if (settings.thresholds) { + return VideoEncoder::ScalingSettings( + settings.enabled, settings.thresholds->low, settings.thresholds->high, + forced_fallback_.min_pixels_); + } + return VideoEncoder::ScalingSettings(settings.enabled, + forced_fallback_.min_pixels_); + } return encoder_->GetScalingSettings(); } @@ -269,45 +266,32 @@ const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { bool VideoEncoderSoftwareFallbackWrapper::IsForcedFallbackActive() const { return (forced_fallback_possible_ && fallback_encoder_ && - forced_fallback_.start_ms); + forced_fallback_.active_); } -bool VideoEncoderSoftwareFallbackWrapper::RequestForcedFallback() { - if (!forced_fallback_possible_ || fallback_encoder_ || !rates_set_) - return false; - - // No fallback encoder. - return forced_fallback_.ShouldStart(bitrate_allocation_.get_sum_kbps(), - codec_settings_); -} - -bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() { - if (!IsForcedFallbackActive()) - return false; - - if (!forced_fallback_.ShouldStop(bitrate_allocation_.get_sum_kbps(), - codec_settings_)) { +bool VideoEncoderSoftwareFallbackWrapper::TryInitForcedFallbackEncoder() { + if (!forced_fallback_possible_ || fallback_encoder_) { return false; } - - // Release the forced fallback encoder. - if (encoder_->InitEncode(&codec_settings_, number_of_cores_, - max_payload_size_) == WEBRTC_VIDEO_CODEC_OK) { - RTC_LOG(LS_INFO) - << "Stop forced SW encoder fallback, max bitrate exceeded."; - fallback_encoder_->Release(); - fallback_encoder_.reset(); - forced_fallback_.Reset(); - return true; + // Fallback not active. + if (!forced_fallback_.IsValid(codec_settings_)) { + return false; } - return false; + // Settings valid, try to instantiate software codec. + RTC_LOG(LS_INFO) << "Request forced SW encoder fallback: " + << codec_settings_.width << "x" << codec_settings_.height; + if (!InitFallbackEncoder()) { + return false; + } + forced_fallback_.active_ = true; + return true; } bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() { - if (!IsForcedFallbackActive()) + if (!IsForcedFallbackActive()) { return false; - - // Encoder reconfigured. + } + // Forced fallback active. if (!forced_fallback_.IsValid(codec_settings_)) { RTC_LOG(LS_INFO) << "Stop forced SW encoder fallback, max pixels exceeded."; return false; @@ -336,35 +320,6 @@ void VideoEncoderSoftwareFallbackWrapper::ValidateSettingsForForcedFallback() { } } -bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStart( - uint32_t bitrate_kbps, - const VideoCodec& codec) { - if (bitrate_kbps > low_kbps || !IsValid(codec)) { - start_ms.reset(); - return false; - } - - // Has bitrate been below |low_kbps| for long enough duration. - int64_t now_ms = rtc::TimeMillis(); - if (!start_ms) - start_ms.emplace(now_ms); - - if ((now_ms - *start_ms) >= min_low_ms) { - RTC_LOG(LS_INFO) << "Request forced SW encoder fallback."; - // In case the request fails, update time to avoid too frequent requests. - start_ms.emplace(now_ms); - return true; - } - return false; -} - -bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStop( - uint32_t bitrate_kbps, - const VideoCodec& codec) const { - return bitrate_kbps >= high_kbps && - (codec.width * codec.height >= kMinPixelsStop); -} - void VideoEncoderSoftwareFallbackWrapper::MaybeModifyCodecForFallback() { // We have a specific case for H264 ConstrainedBaseline because that is the // only supported profile in Sw fallback. diff --git a/media/engine/videoencodersoftwarefallbackwrapper.h b/media/engine/videoencodersoftwarefallbackwrapper.h index bd7560df20..632298281b 100644 --- a/media/engine/videoencodersoftwarefallbackwrapper.h +++ b/media/engine/videoencodersoftwarefallbackwrapper.h @@ -51,30 +51,21 @@ class VideoEncoderSoftwareFallbackWrapper : public VideoEncoder { bool InitFallbackEncoder(); // 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 |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. + // The forced fallback is requested if the resolution is less than or equal to + // |max_pixels_|. The resolution is allowed to be scaled down to + // |min_pixels_|. class ForcedFallbackParams { public: - bool ShouldStart(uint32_t bitrate_kbps, const VideoCodec& codec); - 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 <= kMaxPixelsStart; + return codec.width * codec.height <= max_pixels_; } - 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 kMaxPixelsStart = 320 * 240; - const int kMinPixelsStop = 320 * 180; + + bool active_ = false; + int min_pixels_ = 320 * 180; + int max_pixels_ = 320 * 240; }; - bool RequestForcedFallback(); - bool TryReleaseForcedFallbackEncoder(); + bool TryInitForcedFallbackEncoder(); bool TryReInitForcedFallbackEncoder(); void ValidateSettingsForForcedFallback(); bool IsForcedFallbackActive() const; @@ -100,7 +91,6 @@ class VideoEncoderSoftwareFallbackWrapper : public VideoEncoder { std::unique_ptr encoder_; std::unique_ptr fallback_encoder_; - std::string fallback_implementation_name_; EncodedImageCallback* callback_; bool forced_fallback_possible_; diff --git a/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc b/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc index a261ecfc65..1ec325d844 100644 --- a/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc +++ b/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc @@ -30,6 +30,8 @@ const int kNumCores = 2; const uint32_t kFramerate = 30; const size_t kMaxPayloadSize = 800; const int kDefaultMinPixelsPerFrame = 320 * 180; +const int kLowThreshold = 10; +const int kHighThreshold = 20; } // namespace class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { @@ -97,7 +99,7 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { } VideoEncoder::ScalingSettings GetScalingSettings() const override { - return VideoEncoder::ScalingSettings(true); + return VideoEncoder::ScalingSettings(true, kLowThreshold, kHighThreshold); } int init_encode_count_ = 0; @@ -325,12 +327,9 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest, } namespace { -const int kLowKbps = 220; -const int kHighKbps = 300; -const int kMinLowDurationMs = 4000; +const int kBitrateKbps = 200; const int kMinPixelsPerFrame = 1; -const int kMinPixelsStop = 320 * 180; -const char kFieldTrial[] = "WebRTC-VP8-Forced-Fallback-Encoder"; +const char kFieldTrial[] = "WebRTC-VP8-Forced-Fallback-Encoder-v2"; } // namespace class ForcedFallbackTest : public VideoEncoderSoftwareFallbackWrapperTest { @@ -344,9 +343,6 @@ class ForcedFallbackTest : public VideoEncoderSoftwareFallbackWrapperTest { void SetUp() override { clock_.SetTimeMicros(1234); ConfigureVp8Codec(); - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.InitEncode( - &codec_, kNumCores, kMaxPayloadSize)); - EXPECT_EQ(1, fake_encoder_->init_encode_count_); } void TearDown() override { @@ -369,6 +365,14 @@ class ForcedFallbackTest : public VideoEncoderSoftwareFallbackWrapperTest { new SimulcastRateAllocator(codec_, std::move(tl_factory))); } + void InitEncode(int width, int height) { + codec_.width = width; + codec_.height = height; + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.InitEncode( + &codec_, kNumCores, kMaxPayloadSize)); + SetRateAllocation(kBitrateKbps); + } + void SetRateAllocation(uint32_t bitrate_kbps) { EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.SetRateAllocation( rate_allocator_->GetAllocation( @@ -393,10 +397,8 @@ class ForcedFallbackTestEnabled : public ForcedFallbackTest { public: ForcedFallbackTestEnabled() : ForcedFallbackTest(std::string(kFieldTrial) + "/Enabled-" + - std::to_string(kLowKbps) + "," + - std::to_string(kHighKbps) + "," + - std::to_string(kMinLowDurationMs) + "," + - std::to_string(kMinPixelsPerFrame) + "/") {} + std::to_string(kMinPixelsPerFrame) + "," + + std::to_string(kWidth * kHeight) + ",30000/") {} }; class ForcedFallbackTestDisabled : public ForcedFallbackTest { @@ -406,242 +408,136 @@ class ForcedFallbackTestDisabled : public ForcedFallbackTest { }; TEST_F(ForcedFallbackTestDisabled, NoFallbackWithoutFieldTrial) { - // Bitrate at low threshold. - SetRateAllocation(kLowKbps); + // Resolution above max threshold. + InitEncode(kWidth + 1, kHeight); + EXPECT_EQ(1, fake_encoder_->init_encode_count_); EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect no fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); + + // Resolution at max threshold. + InitEncode(kWidth, kHeight); EncodeFrameAndVerifyLastName("fake-encoder"); } -TEST_F(ForcedFallbackTestEnabled, FallbackIfAtLowLimit) { - // Bitrate at low threshold. - SetRateAllocation(kLowKbps); +TEST_F(ForcedFallbackTestEnabled, FallbackIfAtMaxResolutionLimit) { + // Resolution above max threshold. + InitEncode(kWidth + 1, kHeight); + EXPECT_EQ(1, fake_encoder_->init_encode_count_); EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); + + // Resolution at max threshold. + InitEncode(kWidth, kHeight); EncodeFrameAndVerifyLastName("libvpx"); } -TEST_F(ForcedFallbackTestEnabled, NoFallbackIfNotAtLowLimit) { - // Bitrate above low threshold. - SetRateAllocation(kLowKbps + 1); +TEST_F(ForcedFallbackTestEnabled, FallbackIsKeptWhenInitEncodeIsCalled) { + // Resolution above max threshold. + InitEncode(kWidth + 1, kHeight); + EXPECT_EQ(1, fake_encoder_->init_encode_count_); EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect no fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); - EncodeFrameAndVerifyLastName("fake-encoder"); -} -TEST_F(ForcedFallbackTestEnabled, NoFallbackIfResolutionIsTooLarge) { - // Resolution above max pixels. - codec_.width += 1; - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize)); - // Bitrate at low threshold. - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect no fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); - EncodeFrameAndVerifyLastName("fake-encoder"); -} + // Resolution at max threshold. + InitEncode(kWidth, kHeight); + EncodeFrameAndVerifyLastName("libvpx"); -TEST_F(ForcedFallbackTestEnabled, FallbackIfMinDurationPassed) { - // Bitrate at low threshold. - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration not passed, expect no fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs - 1)); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); + // Re-initialize encoder, still expect fallback. + InitEncode(kWidth / 2, kHeight / 2); + EXPECT_EQ(1, fake_encoder_->init_encode_count_); // No change. EncodeFrameAndVerifyLastName("libvpx"); } -TEST_F(ForcedFallbackTestEnabled, FallbackStartTimeResetIfAboveLowLimit) { - // Bitrate at low threshold, start time set. - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration not passed, expect no fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs - 1)); +TEST_F(ForcedFallbackTestEnabled, FallbackIsEndedWhenResolutionIsTooLarge) { + // Resolution above max threshold. + InitEncode(kWidth + 1, kHeight); + EXPECT_EQ(1, fake_encoder_->init_encode_count_); EncodeFrameAndVerifyLastName("fake-encoder"); - // Bitrate above low threshold, start time reset. - SetRateAllocation(kLowKbps + 1); - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); - EncodeFrameAndVerifyLastName("fake-encoder"); - - // Bitrate at low threshold, start time set. - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration not passed, expect no fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs - 1)); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); + // Resolution at max threshold. + InitEncode(kWidth, kHeight); EncodeFrameAndVerifyLastName("libvpx"); + + // Re-initialize encoder with a larger resolution, expect no fallback. + InitEncode(kWidth + 1, kHeight); + EXPECT_EQ(2, fake_encoder_->init_encode_count_); + EncodeFrameAndVerifyLastName("fake-encoder"); } -TEST_F(ForcedFallbackTestEnabled, FallbackEndsIfAtHighLimit) { - // Bitrate at low threshold. - SetRateAllocation(kLowKbps); +TEST_F(ForcedFallbackTestEnabled, FallbackIsEndedForNonValidSettings) { + // Resolution at max threshold. + InitEncode(kWidth, kHeight); + EncodeFrameAndVerifyLastName("libvpx"); + + // Re-initialize encoder with invalid setting, expect no fallback. + codec_.VP8()->numberOfTemporalLayers = 2; + InitEncode(kWidth, kHeight); + EXPECT_EQ(1, fake_encoder_->init_encode_count_); EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); - EncodeFrameAndVerifyLastName("libvpx"); - // Bitrate below high threshold, expect fallback. - SetRateAllocation(kHighKbps - 1); - EncodeFrameAndVerifyLastName("libvpx"); - // Bitrate at high threshold, expect fallback ended. - SetRateAllocation(kHighKbps); + + // Re-initialize encoder with valid setting but fallback disabled from now on. + codec_.VP8()->numberOfTemporalLayers = 1; + InitEncode(kWidth, kHeight); + EXPECT_EQ(2, fake_encoder_->init_encode_count_); EncodeFrameAndVerifyLastName("fake-encoder"); } TEST_F(ForcedFallbackTestEnabled, MultipleStartEndFallback) { const int kNumRuns = 5; - for (int i = 0; i < kNumRuns; ++i) { - // Bitrate at low threshold. - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); + for (int i = 1; i <= kNumRuns; ++i) { + // Resolution at max threshold. + InitEncode(kWidth, kHeight); EncodeFrameAndVerifyLastName("libvpx"); - // Bitrate at high threshold, expect fallback ended. - SetRateAllocation(kHighKbps); + // Resolution above max threshold. + InitEncode(kWidth + 1, kHeight); + EXPECT_EQ(i, fake_encoder_->init_encode_count_); EncodeFrameAndVerifyLastName("fake-encoder"); } } -TEST_F(ForcedFallbackTestEnabled, DropsFirstNonNativeFrameAfterFallbackEnds) { - fake_encoder_->supports_native_handle_ = true; - - // Bitrate at low threshold. - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); - EncodeFrameAndVerifyLastName("libvpx"); - // Bitrate at high threshold, fallback should be ended but first non-native - // frame dropped (i.e. frame not encoded). - SetRateAllocation(kHighKbps); - EncodeFrameAndVerifyLastName("libvpx", WEBRTC_VIDEO_CODEC_ERROR); - // Next frame should be encoded. - EncodeFrameAndVerifyLastName("fake-encoder"); -} - -TEST_F(ForcedFallbackTestEnabled, FallbackIsKeptWhenInitEncodeIsCalled) { - // Bitrate below low threshold. - SetRateAllocation(kLowKbps - 1); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); - EncodeFrameAndVerifyLastName("libvpx"); - - // Re-initialize encoder, still expect fallback. - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize)); - EXPECT_EQ(1, fake_encoder_->init_encode_count_); // No change. - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("libvpx"); -} - -TEST_F(ForcedFallbackTestEnabled, FallbackIsEndedWhenResolutionIsTooLarge) { - // Bitrate below low threshold. - SetRateAllocation(kLowKbps - 1); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); - EncodeFrameAndVerifyLastName("libvpx"); - - // Re-initialize encoder with a larger resolution, expect no fallback. - codec_.width += 1; - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize)); - EXPECT_EQ(2, fake_encoder_->init_encode_count_); - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("fake-encoder"); -} - -TEST_F(ForcedFallbackTestEnabled, FallbackIsEndedForNonValidSettings) { - // Bitrate below low threshold. - SetRateAllocation(kLowKbps - 1); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); - EncodeFrameAndVerifyLastName("libvpx"); - - // Re-initialize encoder with invalid setting, expect no fallback. - codec_.VP8()->numberOfTemporalLayers = 2; - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize)); - EXPECT_EQ(2, fake_encoder_->init_encode_count_); - SetRateAllocation(kLowKbps); +TEST_F(ForcedFallbackTestDisabled, GetScaleSettings) { + // Resolution above max threshold. + InitEncode(kWidth + 1, kHeight); + EXPECT_EQ(1, fake_encoder_->init_encode_count_); EncodeFrameAndVerifyLastName("fake-encoder"); - // Re-initialize encoder with valid setting but fallback disabled from now on. - codec_.VP8()->numberOfTemporalLayers = 1; - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize)); - EXPECT_EQ(3, fake_encoder_->init_encode_count_); - // Bitrate at low threshold. - SetRateAllocation(kLowKbps); - EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect no fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); - 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); +TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithNoFallback) { + // Resolution above max threshold. + InitEncode(kWidth + 1, kHeight); EncodeFrameAndVerifyLastName("fake-encoder"); - // Duration passed, expect fallback. - clock_.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kMinLowDurationMs)); + + // 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); + ASSERT_TRUE(settings.thresholds); + EXPECT_EQ(kLowThreshold, settings.thresholds->low); + EXPECT_EQ(kHighThreshold, settings.thresholds->high); +} + +TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithFallback) { + // Resolution at max threshold. + InitEncode(kWidth, kHeight); 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)); +TEST_F(ForcedFallbackTestEnabled, ScalingDisabledIfResizeOff) { + // Resolution at max threshold. + codec_.VP8()->automaticResizeOn = false; + InitEncode(kWidth, kHeight); 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"); + // Should be disabled for automatic resize off. + const auto settings = fallback_wrapper_.GetScalingSettings(); + EXPECT_FALSE(settings.enabled); } } // namespace webrtc diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc index a4448e3d9f..19f3426486 100644 --- a/media/engine/webrtcvideoengine.cc +++ b/media/engine/webrtcvideoengine.cc @@ -317,11 +317,41 @@ int GetDefaultVp9TemporalLayers() { } return 1; } + +const char kForcedFallbackFieldTrial[] = + "WebRTC-VP8-Forced-Fallback-Encoder-v2"; + +rtc::Optional GetFallbackMinBpsFromFieldTrial() { + if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) + return rtc::Optional(); + + std::string group = + webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial); + if (group.empty()) + return rtc::Optional(); + + int min_pixels; + int max_pixels; + int min_bps; + if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, + &min_bps) != 3) { + return rtc::Optional(); + } + + if (min_bps <= 0) + return rtc::Optional(); + + return rtc::Optional(min_bps); +} + +int GetMinVideoBitrateBps() { + return GetFallbackMinBpsFromFieldTrial().value_or(kMinVideoBitrateBps); +} } // namespace // Constants defined in webrtc/media/engine/constants.h // TODO(pbos): Move these to a separate constants.cc file. -const int kMinVideoBitrateKbps = 30; +const int kMinVideoBitrateBps = 30000; const int kVideoMtu = 1200; const int kVideoRtpBufferSize = 65536; @@ -2569,7 +2599,7 @@ std::vector EncoderStreamFactory::CreateEncoderStreams( stream.width = width; stream.height = height; stream.max_framerate = max_framerate_; - stream.min_bitrate_bps = kMinVideoBitrateKbps * 1000; + stream.min_bitrate_bps = GetMinVideoBitrateBps(); stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate_bps; stream.max_qp = max_qp_; diff --git a/media/engine/webrtcvideoengine_unittest.cc b/media/engine/webrtcvideoengine_unittest.cc index ecde12997a..c3542a2018 100644 --- a/media/engine/webrtcvideoengine_unittest.cc +++ b/media/engine/webrtcvideoengine_unittest.cc @@ -2216,6 +2216,20 @@ TEST_F(Vp9SettingsTestWith2SL3TLFlag, VerifySettings) { VerifySettings(kNumSpatialLayers, kNumTemporalLayers); } +TEST_F(WebRtcVideoChannelTest, VerifyMinBitrate) { + std::vector streams = AddSendStream()->GetVideoStreams(); + ASSERT_EQ(1u, streams.size()); + EXPECT_EQ(cricket::kMinVideoBitrateBps, streams[0].min_bitrate_bps); +} + +TEST_F(WebRtcVideoChannelTest, VerifyMinBitrateWithForcedFallbackFieldTrial) { + webrtc::test::ScopedFieldTrials override_field_trials_( + "WebRTC-VP8-Forced-Fallback-Encoder-v2/Enabled-1,2,34567/"); + std::vector streams = AddSendStream()->GetVideoStreams(); + ASSERT_EQ(1u, streams.size()); + EXPECT_EQ(34567, streams[0].min_bitrate_bps); +} + TEST_F(WebRtcVideoChannelTest, BalancedDegradationPreferenceNotSupportedWithoutFieldtrial) { webrtc::test::ScopedFieldTrials override_field_trials_( @@ -4679,7 +4693,7 @@ class WebRtcVideoChannelSimulcastTest : public testing::Test { stream.width = capture_width; stream.height = capture_height; stream.max_framerate = kDefaultVideoMaxFramerate; - stream.min_bitrate_bps = cricket::kMinVideoBitrateKbps * 1000; + stream.min_bitrate_bps = cricket::kMinVideoBitrateBps; int max_bitrate_kbps; if (capture_width * capture_height <= 320 * 240) { max_bitrate_kbps = 600; diff --git a/modules/video_coding/codecs/test/videoprocessor_integrationtest_mediacodec.cc b/modules/video_coding/codecs/test/videoprocessor_integrationtest_mediacodec.cc index 8155fc5755..7f6b40b0b9 100644 --- a/modules/video_coding/codecs/test/videoprocessor_integrationtest_mediacodec.cc +++ b/modules/video_coding/codecs/test/videoprocessor_integrationtest_mediacodec.cc @@ -104,36 +104,6 @@ TEST_F(VideoProcessorIntegrationTestMediaCodec, kNoVisualizationParams); } -TEST_F(VideoProcessorIntegrationTestMediaCodec, - Foreman240p100kbpsVp8WithForcedSwFallback) { - ScopedFieldTrials override_field_trials( - "WebRTC-VP8-Forced-Fallback-Encoder/Enabled-150,175,10000,1/"); - - config_.filename = "foreman_320x240"; - config_.input_filename = ResourcePath(config_.filename, "yuv"); - config_.sw_fallback_encoder = true; - config_.SetCodecSettings(kVideoCodecVP8, 1, false, false, false, false, false, - 320, 240); - - std::vector rate_profiles = { - {100, 10, 80}, // Start below |low_kbps|. - {100, 10, 200}, // Fallback in this bucket. - {200, 10, kForemanNumFrames + 1}}; // Switch back here. - - // The thresholds below may have to be tweaked to let even poor MediaCodec - // implementations pass. If this test fails on the bots, disable it and - // ping brandtr@. - std::vector rc_thresholds = {{0, 50, 75, 70, 10, 0, 1}, - {0, 50, 25, 12, 60, 0, 1}, - {0, 65, 15, 5, 5, 0, 1}}; - - QualityThresholds quality_thresholds(33.0, 30.0, 0.90, 0.85); - - ProcessFramesAndMaybeVerify(rate_profiles, &rc_thresholds, - &quality_thresholds, nullptr, - kNoVisualizationParams); -} - #endif // defined(WEBRTC_ANDROID) } // namespace test diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.cc b/modules/video_coding/codecs/vp8/default_temporal_layers.cc index 5b1ccb9941..f070750e7b 100644 --- a/modules/video_coding/codecs/vp8/default_temporal_layers.cc +++ b/modules/video_coding/codecs/vp8/default_temporal_layers.cc @@ -295,7 +295,8 @@ std::vector GetTemporalPattern(size_t num_layers) { // deregistred when deleted by SW codec (tl factory might not exist, owned by // SimulcastRateAllocator). bool ExcludeOnTemporalLayersCreated(int num_temporal_layers) { - return webrtc::field_trial::IsEnabled("WebRTC-VP8-Forced-Fallback-Encoder") && + return webrtc::field_trial::IsEnabled( + "WebRTC-VP8-Forced-Fallback-Encoder-v2") && num_temporal_layers == 1; } } // namespace diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index 7214d537dc..015485f23e 100644 --- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -35,7 +35,6 @@ constexpr int64_t kInitialTimestampMs = 789; constexpr uint32_t kTimestampIncrement = 3000; constexpr int kNumCores = 1; constexpr size_t kMaxPayloadSize = 1440; -constexpr int kMinPixelsPerFrame = 12345; constexpr int kDefaultMinPixelsPerFrame = 320 * 180; constexpr int kWidth = 172; constexpr int kHeight = 144; @@ -504,22 +503,4 @@ TEST_F(TestVp8Impl, ScalingEnabledIfAutomaticResizeOn) { 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) { - codec_settings_.VP8()->frameDroppingOn = true; - 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/modules/video_coding/codecs/vp8/vp8_impl.cc b/modules/video_coding/codecs/vp8/vp8_impl.cc index b97ef2275e..f687d359ff 100644 --- a/modules/video_coding/codecs/vp8/vp8_impl.cc +++ b/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -42,8 +42,6 @@ namespace { const char kVp8PostProcArmFieldTrial[] = "WebRTC-VP8-Postproc-Config-Arm"; const char kVp8GfBoostFieldTrial[] = "WebRTC-VP8-GfBoost"; -const char kVp8ForceFallbackEncoderFieldTrial[] = - "WebRTC-VP8-Forced-Fallback-Encoder"; const int kTokenPartitions = VP8_ONE_TOKENPARTITION; enum { kVp8ErrorPropagationTh = 30 }; @@ -127,31 +125,6 @@ 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()) @@ -223,7 +196,6 @@ 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), @@ -999,10 +971,6 @@ 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/modules/video_coding/codecs/vp8/vp8_impl.h b/modules/video_coding/codecs/vp8/vp8_impl.h index 6964760cd5..e5d5d81e35 100644 --- a/modules/video_coding/codecs/vp8/vp8_impl.h +++ b/modules/video_coding/codecs/vp8/vp8_impl.h @@ -94,7 +94,6 @@ 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/video/payload_router.cc b/video/payload_router.cc index 4147d71aff..496186c069 100644 --- a/video/payload_router.cc +++ b/video/payload_router.cc @@ -130,7 +130,7 @@ PayloadRouter::PayloadRouter(const std::vector& rtp_modules, rtp_modules_(rtp_modules), payload_type_(payload_type), forced_fallback_enabled_((webrtc::field_trial::IsEnabled( - "WebRTC-VP8-Forced-Fallback-Encoder"))) { + "WebRTC-VP8-Forced-Fallback-Encoder-v2"))) { RTC_DCHECK_EQ(ssrcs.size(), rtp_modules.size()); // SSRCs are assumed to be sorted in the same order as |rtp_modules|. for (uint32_t ssrc : ssrcs) { diff --git a/video/payload_router_unittest.cc b/video/payload_router_unittest.cc index fe4ea12bda..d670124ddf 100644 --- a/video/payload_router_unittest.cc +++ b/video/payload_router_unittest.cc @@ -347,14 +347,14 @@ class PayloadRouterTest : public ::testing::Test { class TestWithForcedFallbackDisabled : public PayloadRouterTest { public: TestWithForcedFallbackDisabled() - : PayloadRouterTest("WebRTC-VP8-Forced-Fallback-Encoder/Disabled/") {} + : PayloadRouterTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Disabled/") {} }; class TestWithForcedFallbackEnabled : public PayloadRouterTest { public: TestWithForcedFallbackEnabled() : PayloadRouterTest( - "WebRTC-VP8-Forced-Fallback-Encoder/Enabled-1,2,3,4/") {} + "WebRTC-VP8-Forced-Fallback-Encoder-v2/Enabled-1,2,3/") {} }; TEST_F(TestWithForcedFallbackDisabled, PictureIdIsNotChangedForVp8) { diff --git a/video/picture_id_tests.cc b/video/picture_id_tests.cc index b23e073de7..cfe4332bb7 100644 --- a/video/picture_id_tests.cc +++ b/video/picture_id_tests.cc @@ -26,7 +26,7 @@ const int kEncoderBitrateBps = 100000; const uint32_t kPictureIdWraparound = (1 << 15); const char kVp8ForcedFallbackEncoderEnabled[] = - "WebRTC-VP8-Forced-Fallback-Encoder/Enabled/"; + "WebRTC-VP8-Forced-Fallback-Encoder-v2/Enabled/"; } // namespace class PictureIdObserver : public test::RtpRtcpObserver { diff --git a/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc index 233cbb6d51..cc7d034db1 100644 --- a/video/send_statistics_proxy.cc +++ b/video/send_statistics_proxy.cc @@ -31,7 +31,7 @@ const int64_t kBucketSizeMs = 100; const size_t kBucketCount = 10; const char kVp8ForcedFallbackEncoderFieldTrial[] = - "WebRTC-VP8-Forced-Fallback-Encoder"; + "WebRTC-VP8-Forced-Fallback-Encoder-v2"; const char kVp8SwCodecName[] = "libvpx"; // Used by histograms. Values of entries should not be changed. @@ -85,7 +85,7 @@ bool IsForcedFallbackPossible(const CodecSpecificInfo* codec_info) { codec_info->codecSpecific.VP8.temporalIdx == kNoTemporalIdx); } -rtc::Optional GetFallbackIntervalFromFieldTrial() { +rtc::Optional GetFallbackMaxPixelsFromFieldTrial() { if (!webrtc::field_trial::IsEnabled(kVp8ForcedFallbackEncoderFieldTrial)) return rtc::Optional(); @@ -94,20 +94,19 @@ rtc::Optional GetFallbackIntervalFromFieldTrial() { 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) { + int max_pixels; + int min_bps; + if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, + &min_bps) != 3) { return rtc::Optional(); } - if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 || - high_kbps <= low_kbps) { - return rtc::Optional(); + if (min_pixels <= 0 || max_pixels <= 0 || max_pixels < min_pixels || + min_bps <= 0) { + return rtc::Optional(); // Do not log stats. } - return rtc::Optional(min_low_ms); + return rtc::Optional(max_pixels); } } // namespace @@ -121,7 +120,7 @@ SendStatisticsProxy::SendStatisticsProxy( : clock_(clock), payload_name_(config.encoder_settings.payload_name), rtp_config_(config.rtp), - min_first_fallback_interval_ms_(GetFallbackIntervalFromFieldTrial()), + fallback_max_pixels_(GetFallbackMaxPixelsFromFieldTrial()), content_type_(content_type), start_ms_(clock->TimeInMilliseconds()), encode_time_(kEncodeTimeWeigthFactor), @@ -728,9 +727,9 @@ void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) { } void SendStatisticsProxy::UpdateEncoderFallbackStats( - const CodecSpecificInfo* codec_info) { - if (!min_first_fallback_interval_ms_ || - !uma_container_->fallback_info_.is_possible) { + const CodecSpecificInfo* codec_info, + int pixels) { + if (!fallback_max_pixels_ || !uma_container_->fallback_info_.is_possible) { return; } @@ -750,16 +749,11 @@ void SendStatisticsProxy::UpdateEncoderFallbackStats( // First or not a VP8 SW change, update stats on next call. return; } - if (is_active && fallback_info->on_off_events == 0) { - // The minimum set time should have passed for the first fallback (else - // skip to avoid fallback due to failure). - int64_t elapsed_ms = fallback_info->elapsed_ms; - if (fallback_info->last_update_ms) - elapsed_ms += now_ms - *(fallback_info->last_update_ms); - if (elapsed_ms < *min_first_fallback_interval_ms_) { - fallback_info->is_possible = false; - return; - } + if (is_active && (pixels > *fallback_max_pixels_)) { + // Pixels should not be above |fallback_max_pixels_|. If above skip to + // avoid fallbacks due to failure. + fallback_info->is_possible = false; + return; } ++fallback_info->on_off_events; } @@ -792,7 +786,8 @@ void SendStatisticsProxy::OnSendEncodedImage( simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx; } if (codec_info->codec_name) { - UpdateEncoderFallbackStats(codec_info); + UpdateEncoderFallbackStats(codec_info, encoded_image._encodedWidth * + encoded_image._encodedHeight); stats_.encoder_implementation_name = codec_info->codec_name; } } diff --git a/video/send_statistics_proxy.h b/video/send_statistics_proxy.h index 19c8ca7d62..a543d92643 100644 --- a/video/send_statistics_proxy.h +++ b/video/send_statistics_proxy.h @@ -205,13 +205,14 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, const VideoStreamEncoder::AdaptCounts& quality_counts) RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); - void UpdateEncoderFallbackStats(const CodecSpecificInfo* codec_info) + void UpdateEncoderFallbackStats(const CodecSpecificInfo* codec_info, + int pixels) RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); Clock* const clock_; const std::string payload_name_; const VideoSendStream::Config::Rtp rtp_config_; - const rtc::Optional min_first_fallback_interval_ms_; + const rtc::Optional fallback_max_pixels_; rtc::CriticalSection crit_; VideoEncoderConfig::ContentType content_type_ RTC_GUARDED_BY(crit_); const int64_t start_ms_; diff --git a/video/send_statistics_proxy_unittest.cc b/video/send_statistics_proxy_unittest.cc index 56184b948a..881aa7c158 100644 --- a/video/send_statistics_proxy_unittest.cc +++ b/video/send_statistics_proxy_unittest.cc @@ -32,7 +32,6 @@ const int kWidth = 640; const int kHeight = 480; const int kQpIdx0 = 21; const int kQpIdx1 = 39; -const int kMinFirstFallbackIntervalMs = 1500; const CodecSpecificInfo kDefaultCodecInfo = []() { CodecSpecificInfo codec_info; codec_info.codecType = kVideoCodecVP8; @@ -1838,6 +1837,8 @@ class ForcedFallbackTest : public SendStatisticsProxyTest { codec_info_.codecSpecific.VP8.simulcastIdx = 0; codec_info_.codecSpecific.VP8.temporalIdx = 0; codec_info_.codec_name = "fake_codec"; + encoded_image_._encodedWidth = kWidth; + encoded_image_._encodedHeight = kHeight; } ~ForcedFallbackTest() override {} @@ -1866,15 +1867,14 @@ class ForcedFallbackTest : public SendStatisticsProxyTest { class ForcedFallbackDisabled : public ForcedFallbackTest { public: ForcedFallbackDisabled() - : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder/Disabled/") {} + : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Disabled/") {} }; class ForcedFallbackEnabled : public ForcedFallbackTest { public: ForcedFallbackEnabled() - : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder/Enabled-1,2," + - std::to_string(kMinFirstFallbackIntervalMs) + - ",4/") {} + : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Enabled-1," + + std::to_string(kWidth * kHeight) + ",3/") {} }; TEST_F(ForcedFallbackEnabled, StatsNotUpdatedIfMinRunTimeHasNotPassed) { @@ -1961,8 +1961,8 @@ TEST_F(ForcedFallbackEnabled, ThreeFallbackEvents) { EXPECT_EQ(1, metrics::NumEvents(kPrefix + "FallbackChangesPerMinute.Vp8", 3)); } -TEST_F(ForcedFallbackEnabled, NoFallbackIfMinIntervalHasNotPassed) { - InsertEncodedFrames(1, kMinFirstFallbackIntervalMs - 1); +TEST_F(ForcedFallbackEnabled, NoFallbackIfAboveMaxPixels) { + encoded_image_._encodedWidth = kWidth + 1; codec_info_.codec_name = "libvpx"; InsertEncodedFrames(kMinFrames, kFrameIntervalMs); @@ -1971,8 +1971,8 @@ TEST_F(ForcedFallbackEnabled, NoFallbackIfMinIntervalHasNotPassed) { EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8")); } -TEST_F(ForcedFallbackEnabled, FallbackIfMinIntervalPassed) { - InsertEncodedFrames(1, kMinFirstFallbackIntervalMs); +TEST_F(ForcedFallbackEnabled, FallbackIfAtMaxPixels) { + encoded_image_._encodedWidth = kWidth; codec_info_.codec_name = "libvpx"; InsertEncodedFrames(kMinFrames, kFrameIntervalMs); diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc index d161025438..d0d91257ab 100644 --- a/video/video_send_stream.cc +++ b/video/video_send_stream.cc @@ -153,6 +153,38 @@ bool TransportSeqNumExtensionConfigured(const VideoSendStream::Config& config) { }) != extensions.end(); } +const char kForcedFallbackFieldTrial[] = + "WebRTC-VP8-Forced-Fallback-Encoder-v2"; + +rtc::Optional GetFallbackMinBpsFromFieldTrial() { + if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) + return rtc::Optional(); + + std::string group = + webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial); + if (group.empty()) + return rtc::Optional(); + + int min_pixels; + int max_pixels; + int min_bps; + if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, + &min_bps) != 3) { + return rtc::Optional(); + } + + if (min_bps <= 0) + return rtc::Optional(); + + return rtc::Optional(min_bps); +} + +int GetEncoderMinBitrateBps() { + const int kDefaultEncoderMinBitrateBps = 30000; + return GetFallbackMinBpsFromFieldTrial().value_or( + kDefaultEncoderMinBitrateBps); +} + bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) { const VideoCodecType codecType = PayloadStringToCodecType(payload_name); if (codecType == kVideoCodecVP8 || codecType == kVideoCodecVP9) { @@ -922,9 +954,8 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged( RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size()); RTC_DCHECK_RUN_ON(worker_queue_); - const int kEncoderMinBitrateBps = 30000; encoder_min_bitrate_bps_ = - std::max(streams[0].min_bitrate_bps, kEncoderMinBitrateBps); + std::max(streams[0].min_bitrate_bps, GetEncoderMinBitrateBps()); encoder_max_bitrate_bps_ = 0; for (const auto& stream : streams) encoder_max_bitrate_bps_ += stream.max_bitrate_bps;