Change forced software encoder fallback for VP8 to be only based on resolution and not bitrate.

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 <asapersson@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20646}
This commit is contained in:
Åsa Persson 2017-11-13 10:16:47 +01:00 committed by Commit Bot
parent b577d5e4c3
commit 45bbc8ac19
19 changed files with 283 additions and 452 deletions

View File

@ -18,7 +18,7 @@ extern const int kVideoRtpBufferSize;
extern const char kH264CodecName[];
extern const int kMinVideoBitrateKbps;
extern const int kMinVideoBitrateBps;
} // namespace cricket

View File

@ -209,7 +209,7 @@ std::vector<webrtc::VideoStream> 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();

View File

@ -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<FrameType>* 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.

View File

@ -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<int64_t> 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<webrtc::VideoEncoder> encoder_;
std::unique_ptr<webrtc::VideoEncoder> fallback_encoder_;
std::string fallback_implementation_name_;
EncodedImageCallback* callback_;
bool forced_fallback_possible_;

View File

@ -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

View File

@ -317,11 +317,41 @@ int GetDefaultVp9TemporalLayers() {
}
return 1;
}
const char kForcedFallbackFieldTrial[] =
"WebRTC-VP8-Forced-Fallback-Encoder-v2";
rtc::Optional<int> GetFallbackMinBpsFromFieldTrial() {
if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial))
return rtc::Optional<int>();
std::string group =
webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial);
if (group.empty())
return rtc::Optional<int>();
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<int>();
}
if (min_bps <= 0)
return rtc::Optional<int>();
return rtc::Optional<int>(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<webrtc::VideoStream> 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_;

View File

@ -2216,6 +2216,20 @@ TEST_F(Vp9SettingsTestWith2SL3TLFlag, VerifySettings) {
VerifySettings(kNumSpatialLayers, kNumTemporalLayers);
}
TEST_F(WebRtcVideoChannelTest, VerifyMinBitrate) {
std::vector<webrtc::VideoStream> 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<webrtc::VideoStream> 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;

View File

@ -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<RateProfile> 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<RateControlThresholds> 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

View File

@ -295,7 +295,8 @@ std::vector<TemporalLayers::FrameConfig> 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

View File

@ -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

View File

@ -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<bool>& streams) {
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) {
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);
}

View File

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

View File

@ -130,7 +130,7 @@ PayloadRouter::PayloadRouter(const std::vector<RtpRtcp*>& 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) {

View File

@ -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) {

View File

@ -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 {

View File

@ -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<int> GetFallbackIntervalFromFieldTrial() {
rtc::Optional<int> GetFallbackMaxPixelsFromFieldTrial() {
if (!webrtc::field_trial::IsEnabled(kVp8ForcedFallbackEncoderFieldTrial))
return rtc::Optional<int>();
@ -94,20 +94,19 @@ rtc::Optional<int> GetFallbackIntervalFromFieldTrial() {
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) {
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<int>();
}
if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 ||
high_kbps <= low_kbps) {
return rtc::Optional<int>();
if (min_pixels <= 0 || max_pixels <= 0 || max_pixels < min_pixels ||
min_bps <= 0) {
return rtc::Optional<int>(); // Do not log stats.
}
return rtc::Optional<int>(min_low_ms);
return rtc::Optional<int>(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;
}
}

View File

@ -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<int> min_first_fallback_interval_ms_;
const rtc::Optional<int> fallback_max_pixels_;
rtc::CriticalSection crit_;
VideoEncoderConfig::ContentType content_type_ RTC_GUARDED_BY(crit_);
const int64_t start_ms_;

View File

@ -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);

View File

@ -153,6 +153,38 @@ bool TransportSeqNumExtensionConfigured(const VideoSendStream::Config& config) {
}) != extensions.end();
}
const char kForcedFallbackFieldTrial[] =
"WebRTC-VP8-Forced-Fallback-Encoder-v2";
rtc::Optional<int> GetFallbackMinBpsFromFieldTrial() {
if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial))
return rtc::Optional<int>();
std::string group =
webrtc::field_trial::FindFullName(kForcedFallbackFieldTrial);
if (group.empty())
return rtc::Optional<int>();
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<int>();
}
if (min_bps <= 0)
return rtc::Optional<int>();
return rtc::Optional<int>(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;