Add resolution_bitrate_limits to EncoderInfo field trial.

Added class EncoderInfoSettings for parsing settings.
Added use of class to SimulcastEncoderAdapter.

Bug: none
Change-Id: I8182b2ab43f0c330ebdf077e9f7cbc79247da90e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/202246
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33050}
This commit is contained in:
Åsa Persson 2021-01-20 15:36:13 +01:00 committed by Commit Bot
parent 026ad9ac22
commit a7e34d33fe
10 changed files with 586 additions and 62 deletions

View File

@ -193,7 +193,7 @@ rtc_library("rtc_simulcast_encoder_adapter") {
"../modules/video_coding:video_coding_utility",
"../rtc_base:checks",
"../rtc_base:rtc_base_approved",
"../rtc_base/experiments:field_trial_parser",
"../rtc_base/experiments:encoder_info_settings",
"../rtc_base/experiments:rate_control_settings",
"../rtc_base/synchronization:sequence_checker",
"../rtc_base/system:no_unique_address",

View File

@ -228,11 +228,6 @@ SimulcastEncoderAdapter::SimulcastEncoderAdapter(
"WebRTC-Video-PreferTemporalSupportOnBaseLayer")) {
RTC_DCHECK(primary_factory);
ParseFieldTrial({&requested_resolution_alignment_override_,
&apply_alignment_to_all_simulcast_layers_override_},
field_trial::FindFullName(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride"));
// The adapter is typically created on the worker thread, but operated on
// the encoder task queue.
encoder_queue_.Detach();
@ -430,8 +425,9 @@ int SimulcastEncoderAdapter::Encode(
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (requested_resolution_alignment_override_) {
const int alignment = *requested_resolution_alignment_override_;
if (encoder_info_override_.requested_resolution_alignment()) {
const int alignment =
*encoder_info_override_.requested_resolution_alignment();
if (input_image.width() % alignment != 0 ||
input_image.height() % alignment != 0) {
RTC_LOG(LS_WARNING) << "Frame " << input_image.width() << "x"
@ -439,7 +435,7 @@ int SimulcastEncoderAdapter::Encode(
<< alignment;
return WEBRTC_VIDEO_CODEC_ERROR;
}
if (apply_alignment_to_all_simulcast_layers_override_.Get()) {
if (encoder_info_override_.apply_alignment_to_all_simulcast_layers()) {
for (const auto& layer : encoder_contexts_) {
if (layer.width() % alignment != 0 || layer.height() % alignment != 0) {
RTC_LOG(LS_WARNING)
@ -741,11 +737,15 @@ void SimulcastEncoderAdapter::DestroyStoredEncoders() {
void SimulcastEncoderAdapter::OverrideFromFieldTrial(
VideoEncoder::EncoderInfo* info) const {
if (requested_resolution_alignment_override_) {
if (encoder_info_override_.requested_resolution_alignment()) {
info->requested_resolution_alignment =
*requested_resolution_alignment_override_;
*encoder_info_override_.requested_resolution_alignment();
info->apply_alignment_to_all_simulcast_layers =
apply_alignment_to_all_simulcast_layers_override_.Get();
encoder_info_override_.apply_alignment_to_all_simulcast_layers();
}
if (!encoder_info_override_.resolution_bitrate_limits().empty()) {
info->resolution_bitrate_limits =
encoder_info_override_.resolution_bitrate_limits();
}
}

View File

@ -26,7 +26,7 @@
#include "modules/video_coding/include/video_codec_interface.h"
#include "modules/video_coding/utility/framerate_controller.h"
#include "rtc_base/atomic_ops.h"
#include "rtc_base/experiments/field_trial_parser.h"
#include "rtc_base/experiments/encoder_info_settings.h"
#include "rtc_base/synchronization/sequence_checker.h"
#include "rtc_base/system/no_unique_address.h"
#include "rtc_base/system/rtc_export.h"
@ -162,13 +162,7 @@ class RTC_EXPORT SimulcastEncoderAdapter : public VideoEncoder {
const bool boost_base_layer_quality_;
const bool prefer_temporal_support_on_base_layer_;
// Overrides from field trial.
// EncoderInfo::requested_resolution_alignment.
FieldTrialOptional<int> requested_resolution_alignment_override_{
"requested_resolution_alignment"};
// EncoderInfo::apply_alignment_to_all_simulcast_layers.
FieldTrialFlag apply_alignment_to_all_simulcast_layers_override_{
"apply_alignment_to_all_simulcast_layers"};
const SimulcastEncoderAdapterEncoderInfoSettings encoder_info_override_;
};
} // namespace webrtc

View File

@ -1292,7 +1292,7 @@ TEST_F(TestSimulcastEncoderAdapterFake,
adapter_->GetEncoderInfo().apply_alignment_to_all_simulcast_layers);
}
TEST_F(TestSimulcastEncoderAdapterFake, AlignmentFromFieldTrial) {
TEST_F(TestSimulcastEncoderAdapterFake, EncoderInfoFromFieldTrial) {
test::ScopedFieldTrials field_trials(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/"
"requested_resolution_alignment:8,"
@ -1308,13 +1308,18 @@ TEST_F(TestSimulcastEncoderAdapterFake, AlignmentFromFieldTrial) {
EXPECT_EQ(8, adapter_->GetEncoderInfo().requested_resolution_alignment);
EXPECT_TRUE(
adapter_->GetEncoderInfo().apply_alignment_to_all_simulcast_layers);
EXPECT_TRUE(adapter_->GetEncoderInfo().resolution_bitrate_limits.empty());
}
TEST_F(TestSimulcastEncoderAdapterFake,
AlignmentFromFieldTrialForSingleStream) {
EncoderInfoFromFieldTrialForSingleStream) {
test::ScopedFieldTrials field_trials(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/"
"requested_resolution_alignment:9/");
"requested_resolution_alignment:9,"
"frame_size_pixels:123|456|789,"
"min_start_bitrate_bps:11000|22000|33000,"
"min_bitrate_bps:44000|55000|66000,"
"max_bitrate_bps:77000|88000|99000/");
SetUp();
SimulcastTestFixtureImpl::DefaultSettings(
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
@ -1326,6 +1331,12 @@ TEST_F(TestSimulcastEncoderAdapterFake,
EXPECT_EQ(9, adapter_->GetEncoderInfo().requested_resolution_alignment);
EXPECT_FALSE(
adapter_->GetEncoderInfo().apply_alignment_to_all_simulcast_layers);
EXPECT_THAT(
adapter_->GetEncoderInfo().resolution_bitrate_limits,
::testing::ElementsAre(
VideoEncoder::ResolutionBitrateLimits{123, 11000, 44000, 77000},
VideoEncoder::ResolutionBitrateLimits{456, 22000, 55000, 88000},
VideoEncoder::ResolutionBitrateLimits{789, 33000, 66000, 99000}));
}
TEST_F(TestSimulcastEncoderAdapterFake, ReportsInternalSource) {

View File

@ -130,6 +130,20 @@ rtc_library("cpu_speed_experiment") {
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
rtc_library("encoder_info_settings") {
sources = [
"encoder_info_settings.cc",
"encoder_info_settings.h",
]
deps = [
":field_trial_parser",
"../:rtc_base_approved",
"../../api/video_codecs:video_codecs_api",
"../../system_wrappers:field_trial",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
rtc_library("rtt_mult_experiment") {
sources = [
"rtt_mult_experiment.cc",
@ -224,6 +238,7 @@ if (rtc_include_tests) {
sources = [
"balanced_degradation_settings_unittest.cc",
"cpu_speed_experiment_unittest.cc",
"encoder_info_settings_unittest.cc",
"field_trial_list_unittest.cc",
"field_trial_parser_unittest.cc",
"field_trial_units_unittest.cc",
@ -241,6 +256,7 @@ if (rtc_include_tests) {
deps = [
":balanced_degradation_settings",
":cpu_speed_experiment",
":encoder_info_settings",
":field_trial_parser",
":keyframe_interval_settings_experiment",
":min_video_bitrate_experiment",

View File

@ -0,0 +1,78 @@
/*
* Copyright 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/experiments/encoder_info_settings.h"
#include <stdio.h>
#include "rtc_base/experiments/field_trial_list.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
std::vector<VideoEncoder::ResolutionBitrateLimits> ToResolutionBitrateLimits(
const std::vector<EncoderInfoSettings::BitrateLimit>& limits) {
std::vector<VideoEncoder::ResolutionBitrateLimits> result;
for (const auto& limit : limits) {
result.push_back(VideoEncoder::ResolutionBitrateLimits(
limit.frame_size_pixels, limit.min_start_bitrate_bps,
limit.min_bitrate_bps, limit.max_bitrate_bps));
}
return result;
}
} // namespace
EncoderInfoSettings::EncoderInfoSettings(std::string name)
: requested_resolution_alignment_("requested_resolution_alignment"),
apply_alignment_to_all_simulcast_layers_(
"apply_alignment_to_all_simulcast_layers") {
FieldTrialStructList<BitrateLimit> bitrate_limits(
{FieldTrialStructMember(
"frame_size_pixels",
[](BitrateLimit* b) { return &b->frame_size_pixels; }),
FieldTrialStructMember(
"min_start_bitrate_bps",
[](BitrateLimit* b) { return &b->min_start_bitrate_bps; }),
FieldTrialStructMember(
"min_bitrate_bps",
[](BitrateLimit* b) { return &b->min_bitrate_bps; }),
FieldTrialStructMember(
"max_bitrate_bps",
[](BitrateLimit* b) { return &b->max_bitrate_bps; })},
{});
ParseFieldTrial({&bitrate_limits, &requested_resolution_alignment_,
&apply_alignment_to_all_simulcast_layers_},
field_trial::FindFullName(name));
resolution_bitrate_limits_ = ToResolutionBitrateLimits(bitrate_limits.Get());
}
absl::optional<int> EncoderInfoSettings::requested_resolution_alignment()
const {
if (requested_resolution_alignment_ &&
requested_resolution_alignment_.Value() < 1) {
RTC_LOG(LS_WARNING) << "Unsupported alignment value, ignored.";
return absl::nullopt;
}
return requested_resolution_alignment_.GetOptional();
}
EncoderInfoSettings::~EncoderInfoSettings() {}
SimulcastEncoderAdapterEncoderInfoSettings::
SimulcastEncoderAdapterEncoderInfoSettings()
: EncoderInfoSettings(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride") {}
} // namespace webrtc

View File

@ -0,0 +1,62 @@
/*
* Copyright 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_
#define RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_
#include <string>
#include <vector>
#include "absl/types/optional.h"
#include "api/video_codecs/video_encoder.h"
#include "rtc_base/experiments/field_trial_parser.h"
namespace webrtc {
class EncoderInfoSettings {
public:
virtual ~EncoderInfoSettings();
// Bitrate limits per resolution.
struct BitrateLimit {
int frame_size_pixels = 0; // The video frame size.
int min_start_bitrate_bps = 0; // The minimum bitrate to start encoding.
int min_bitrate_bps = 0; // The minimum bitrate.
int max_bitrate_bps = 0; // The maximum bitrate.
};
absl::optional<int> requested_resolution_alignment() const;
bool apply_alignment_to_all_simulcast_layers() const {
return apply_alignment_to_all_simulcast_layers_.Get();
}
std::vector<VideoEncoder::ResolutionBitrateLimits> resolution_bitrate_limits()
const {
return resolution_bitrate_limits_;
}
protected:
explicit EncoderInfoSettings(std::string name);
private:
FieldTrialOptional<int> requested_resolution_alignment_;
FieldTrialFlag apply_alignment_to_all_simulcast_layers_;
std::vector<VideoEncoder::ResolutionBitrateLimits> resolution_bitrate_limits_;
};
// EncoderInfo settings for SimulcastEncoderAdapter.
class SimulcastEncoderAdapterEncoderInfoSettings : public EncoderInfoSettings {
public:
SimulcastEncoderAdapterEncoderInfoSettings();
~SimulcastEncoderAdapterEncoderInfoSettings() override {}
};
} // namespace webrtc
#endif // RTC_BASE_EXPERIMENTS_ENCODER_INFO_SETTINGS_H_

View File

@ -0,0 +1,91 @@
/*
* Copyright 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/experiments/encoder_info_settings.h"
#include "rtc_base/gunit.h"
#include "test/field_trial.h"
#include "test/gmock.h"
namespace webrtc {
TEST(SimulcastEncoderAdapterSettingsTest, NoValuesWithoutFieldTrial) {
SimulcastEncoderAdapterEncoderInfoSettings settings;
EXPECT_EQ(absl::nullopt, settings.requested_resolution_alignment());
EXPECT_FALSE(settings.apply_alignment_to_all_simulcast_layers());
EXPECT_TRUE(settings.resolution_bitrate_limits().empty());
}
TEST(SimulcastEncoderAdapterSettingsTest, NoValueForInvalidAlignment) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/"
"requested_resolution_alignment:0/");
SimulcastEncoderAdapterEncoderInfoSettings settings;
EXPECT_EQ(absl::nullopt, settings.requested_resolution_alignment());
}
TEST(SimulcastEncoderAdapterSettingsTest, GetResolutionAlignment) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/"
"requested_resolution_alignment:2/");
SimulcastEncoderAdapterEncoderInfoSettings settings;
EXPECT_EQ(2, settings.requested_resolution_alignment());
EXPECT_FALSE(settings.apply_alignment_to_all_simulcast_layers());
EXPECT_TRUE(settings.resolution_bitrate_limits().empty());
}
TEST(SimulcastEncoderAdapterSettingsTest, GetApplyAlignment) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/"
"requested_resolution_alignment:3,"
"apply_alignment_to_all_simulcast_layers/");
SimulcastEncoderAdapterEncoderInfoSettings settings;
EXPECT_EQ(3, settings.requested_resolution_alignment());
EXPECT_TRUE(settings.apply_alignment_to_all_simulcast_layers());
EXPECT_TRUE(settings.resolution_bitrate_limits().empty());
}
TEST(SimulcastEncoderAdapterSettingsTest, GetResolutionBitrateLimits) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/"
"frame_size_pixels:123,"
"min_start_bitrate_bps:11000,"
"min_bitrate_bps:44000,"
"max_bitrate_bps:77000/");
SimulcastEncoderAdapterEncoderInfoSettings settings;
EXPECT_EQ(absl::nullopt, settings.requested_resolution_alignment());
EXPECT_FALSE(settings.apply_alignment_to_all_simulcast_layers());
EXPECT_THAT(settings.resolution_bitrate_limits(),
::testing::ElementsAre(VideoEncoder::ResolutionBitrateLimits{
123, 11000, 44000, 77000}));
}
TEST(SimulcastEncoderAdapterSettingsTest, GetResolutionBitrateLimitsWithList) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-SimulcastEncoderAdapter-GetEncoderInfoOverride/"
"frame_size_pixels:123|456|789,"
"min_start_bitrate_bps:11000|22000|33000,"
"min_bitrate_bps:44000|55000|66000,"
"max_bitrate_bps:77000|88000|99000/");
SimulcastEncoderAdapterEncoderInfoSettings settings;
EXPECT_THAT(
settings.resolution_bitrate_limits(),
::testing::ElementsAre(
VideoEncoder::ResolutionBitrateLimits{123, 11000, 44000, 77000},
VideoEncoder::ResolutionBitrateLimits{456, 22000, 55000, 88000},
VideoEncoder::ResolutionBitrateLimits{789, 33000, 66000, 99000}));
}
} // namespace webrtc

View File

@ -337,6 +337,78 @@ VideoLayersAllocation CreateVideoLayersAllocation(
return layers_allocation;
}
int NumActiveStreams(const std::vector<VideoStream>& streams) {
int num_active = 0;
for (const auto& stream : streams) {
if (stream.active)
++num_active;
}
return num_active;
}
void ApplyEncoderBitrateLimitsIfSingleActiveStream(
const VideoEncoder::EncoderInfo& encoder_info,
const std::vector<VideoStream>& encoder_config_layers,
std::vector<VideoStream>* streams) {
// Apply limits if simulcast with one active stream (expect lowest).
bool single_active_stream =
streams->size() > 1 && NumActiveStreams(*streams) == 1 &&
!streams->front().active && NumActiveStreams(encoder_config_layers) == 1;
if (!single_active_stream) {
return;
}
// Index for the active stream.
size_t index = 0;
for (size_t i = 0; i < encoder_config_layers.size(); ++i) {
if (encoder_config_layers[i].active)
index = i;
}
if (streams->size() < (index + 1) || !(*streams)[index].active) {
return;
}
// Get bitrate limits for active stream.
absl::optional<VideoEncoder::ResolutionBitrateLimits> encoder_bitrate_limits =
encoder_info.GetEncoderBitrateLimitsForResolution(
(*streams)[index].width * (*streams)[index].height);
if (!encoder_bitrate_limits) {
return;
}
// If bitrate limits are set by RtpEncodingParameters, use intersection.
int min_bitrate_bps;
if (encoder_config_layers[index].min_bitrate_bps <= 0) {
min_bitrate_bps = encoder_bitrate_limits->min_bitrate_bps;
} else {
min_bitrate_bps = std::max(encoder_bitrate_limits->min_bitrate_bps,
(*streams)[index].min_bitrate_bps);
}
int max_bitrate_bps;
if (encoder_config_layers[index].max_bitrate_bps <= 0) {
max_bitrate_bps = encoder_bitrate_limits->max_bitrate_bps;
} else {
max_bitrate_bps = std::min(encoder_bitrate_limits->max_bitrate_bps,
(*streams)[index].max_bitrate_bps);
}
if (min_bitrate_bps >= max_bitrate_bps) {
RTC_LOG(LS_WARNING) << "Encoder bitrate limits"
<< " (min=" << encoder_bitrate_limits->min_bitrate_bps
<< ", max=" << encoder_bitrate_limits->max_bitrate_bps
<< ") do not intersect with stream limits"
<< " (min=" << (*streams)[index].min_bitrate_bps
<< ", max=" << (*streams)[index].max_bitrate_bps
<< "). Encoder bitrate limits not used.";
return;
}
(*streams)[index].min_bitrate_bps = min_bitrate_bps;
(*streams)[index].max_bitrate_bps = max_bitrate_bps;
(*streams)[index].target_bitrate_bps =
std::min((*streams)[index].target_bitrate_bps,
encoder_bitrate_limits->max_bitrate_bps);
}
} // namespace
VideoStreamEncoder::EncoderRateSettings::EncoderRateSettings()
@ -769,46 +841,51 @@ void VideoStreamEncoder::ReconfigureEncoder() {
encoder_->GetEncoderInfo().GetEncoderBitrateLimitsForResolution(
last_frame_info_->width * last_frame_info_->height);
if (streams.size() == 1 && encoder_bitrate_limits_) {
// Bitrate limits can be set by app (in SDP or RtpEncodingParameters) or/and
// can be provided by encoder. In presence of both set of limits, the final
// set is derived as their intersection.
int min_bitrate_bps;
if (encoder_config_.simulcast_layers.empty() ||
encoder_config_.simulcast_layers[0].min_bitrate_bps <= 0) {
min_bitrate_bps = encoder_bitrate_limits_->min_bitrate_bps;
} else {
min_bitrate_bps = std::max(encoder_bitrate_limits_->min_bitrate_bps,
streams.back().min_bitrate_bps);
}
if (encoder_bitrate_limits_) {
if (streams.size() == 1 && encoder_config_.simulcast_layers.size() == 1) {
// Bitrate limits can be set by app (in SDP or RtpEncodingParameters)
// or/and can be provided by encoder. In presence of both set of limits,
// the final set is derived as their intersection.
int min_bitrate_bps;
if (encoder_config_.simulcast_layers.empty() ||
encoder_config_.simulcast_layers[0].min_bitrate_bps <= 0) {
min_bitrate_bps = encoder_bitrate_limits_->min_bitrate_bps;
} else {
min_bitrate_bps = std::max(encoder_bitrate_limits_->min_bitrate_bps,
streams.back().min_bitrate_bps);
}
int max_bitrate_bps;
// We don't check encoder_config_.simulcast_layers[0].max_bitrate_bps
// here since encoder_config_.max_bitrate_bps is derived from it (as
// well as from other inputs).
if (encoder_config_.max_bitrate_bps <= 0) {
max_bitrate_bps = encoder_bitrate_limits_->max_bitrate_bps;
} else {
max_bitrate_bps = std::min(encoder_bitrate_limits_->max_bitrate_bps,
streams.back().max_bitrate_bps);
}
int max_bitrate_bps;
// We don't check encoder_config_.simulcast_layers[0].max_bitrate_bps
// here since encoder_config_.max_bitrate_bps is derived from it (as
// well as from other inputs).
if (encoder_config_.max_bitrate_bps <= 0) {
max_bitrate_bps = encoder_bitrate_limits_->max_bitrate_bps;
} else {
max_bitrate_bps = std::min(encoder_bitrate_limits_->max_bitrate_bps,
streams.back().max_bitrate_bps);
}
if (min_bitrate_bps < max_bitrate_bps) {
streams.back().min_bitrate_bps = min_bitrate_bps;
streams.back().max_bitrate_bps = max_bitrate_bps;
streams.back().target_bitrate_bps =
std::min(streams.back().target_bitrate_bps,
encoder_bitrate_limits_->max_bitrate_bps);
if (min_bitrate_bps < max_bitrate_bps) {
streams.back().min_bitrate_bps = min_bitrate_bps;
streams.back().max_bitrate_bps = max_bitrate_bps;
streams.back().target_bitrate_bps =
std::min(streams.back().target_bitrate_bps,
encoder_bitrate_limits_->max_bitrate_bps);
} else {
RTC_LOG(LS_WARNING)
<< "Bitrate limits provided by encoder"
<< " (min=" << encoder_bitrate_limits_->min_bitrate_bps
<< ", max=" << encoder_bitrate_limits_->min_bitrate_bps
<< ") do not intersect with limits set by app"
<< " (min=" << streams.back().min_bitrate_bps
<< ", max=" << encoder_config_.max_bitrate_bps
<< "). The app bitrate limits will be used.";
}
} else {
RTC_LOG(LS_WARNING) << "Bitrate limits provided by encoder"
<< " (min="
<< encoder_bitrate_limits_->min_bitrate_bps
<< ", max="
<< encoder_bitrate_limits_->min_bitrate_bps
<< ") do not intersect with limits set by app"
<< " (min=" << streams.back().min_bitrate_bps
<< ", max=" << encoder_config_.max_bitrate_bps
<< "). The app bitrate limits will be used.";
ApplyEncoderBitrateLimitsIfSingleActiveStream(
encoder_->GetEncoderInfo(), encoder_config_.simulcast_layers,
&streams);
}
}

View File

@ -2009,6 +2009,201 @@ TEST_F(VideoStreamEncoderTest, EncoderRecommendedMaxBitrateCapsTargetBitrate) {
video_stream_encoder_->Stop();
}
TEST_F(VideoStreamEncoderTest,
EncoderMaxAndMinBitratesUsedForTwoStreamsHighestActive) {
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits270p(
480 * 270, 34 * 1000, 12 * 1000, 1234 * 1000);
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits360p(
640 * 360, 43 * 1000, 21 * 1000, 2345 * 1000);
fake_encoder_.SetResolutionBitrateLimits(
{kEncoderLimits270p, kEncoderLimits360p});
// Two streams, highest stream active.
VideoEncoderConfig config;
const int kNumStreams = 2;
test::FillEncoderConfiguration(kVideoCodecVP8, kNumStreams, &config);
config.max_bitrate_bps = 0;
config.simulcast_layers[0].active = false;
config.simulcast_layers[1].active = true;
config.video_stream_factory =
new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
"VP8", /*max qp*/ 56, /*screencast*/ false,
/*screenshare enabled*/ false);
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
// The encoder bitrate limits for 270p should be used.
video_source_.IncomingCapturedFrame(CreateFrame(1, 480, 270));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(fake_encoder_.video_codec().numberOfSimulcastStreams, kNumStreams);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits270p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits270p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
// The encoder bitrate limits for 360p should be used.
video_source_.IncomingCapturedFrame(CreateFrame(2, 640, 360));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits360p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits360p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
// Resolution b/w 270p and 360p. The encoder limits for 360p should be used.
video_source_.IncomingCapturedFrame(
CreateFrame(3, (640 + 480) / 2, (360 + 270) / 2));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits360p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits360p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
// Resolution higher than 360p. Encoder limits should be ignored.
video_source_.IncomingCapturedFrame(CreateFrame(4, 960, 540));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_NE(static_cast<uint32_t>(kEncoderLimits270p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_NE(static_cast<uint32_t>(kEncoderLimits270p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
EXPECT_NE(static_cast<uint32_t>(kEncoderLimits360p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_NE(static_cast<uint32_t>(kEncoderLimits360p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
// Resolution lower than 270p. The encoder limits for 270p should be used.
video_source_.IncomingCapturedFrame(CreateFrame(5, 320, 180));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits270p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits270p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
video_stream_encoder_->Stop();
}
TEST_F(VideoStreamEncoderTest,
EncoderMaxAndMinBitratesUsedForThreeStreamsMiddleActive) {
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits270p(
480 * 270, 34 * 1000, 12 * 1000, 1234 * 1000);
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits360p(
640 * 360, 43 * 1000, 21 * 1000, 2345 * 1000);
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits720p(
1280 * 720, 54 * 1000, 31 * 1000, 3456 * 1000);
fake_encoder_.SetResolutionBitrateLimits(
{kEncoderLimits270p, kEncoderLimits360p, kEncoderLimits720p});
// Three streams, middle stream active.
VideoEncoderConfig config;
const int kNumStreams = 3;
test::FillEncoderConfiguration(kVideoCodecVP8, kNumStreams, &config);
config.simulcast_layers[0].active = false;
config.simulcast_layers[1].active = true;
config.simulcast_layers[2].active = false;
config.video_stream_factory =
new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
"VP8", /*max qp*/ 56, /*screencast*/ false,
/*screenshare enabled*/ false);
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
// The encoder bitrate limits for 360p should be used.
video_source_.IncomingCapturedFrame(CreateFrame(1, 1280, 720));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(fake_encoder_.video_codec().numberOfSimulcastStreams, kNumStreams);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits360p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits360p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
// The encoder bitrate limits for 270p should be used.
video_source_.IncomingCapturedFrame(CreateFrame(2, 960, 540));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits270p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits270p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
video_stream_encoder_->Stop();
}
TEST_F(VideoStreamEncoderTest,
EncoderMaxAndMinBitratesNotUsedForThreeStreamsLowestActive) {
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits270p(
480 * 270, 34 * 1000, 12 * 1000, 1234 * 1000);
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits360p(
640 * 360, 43 * 1000, 21 * 1000, 2345 * 1000);
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits720p(
1280 * 720, 54 * 1000, 31 * 1000, 3456 * 1000);
fake_encoder_.SetResolutionBitrateLimits(
{kEncoderLimits270p, kEncoderLimits360p, kEncoderLimits720p});
// Three streams, lowest stream active.
VideoEncoderConfig config;
const int kNumStreams = 3;
test::FillEncoderConfiguration(kVideoCodecVP8, kNumStreams, &config);
config.simulcast_layers[0].active = true;
config.simulcast_layers[1].active = false;
config.simulcast_layers[2].active = false;
config.video_stream_factory =
new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
"VP8", /*max qp*/ 56, /*screencast*/ false,
/*screenshare enabled*/ false);
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
// Resolution on lowest stream lower than 270p. The encoder limits not applied
// on lowest stream, limits for 270p should not be used
video_source_.IncomingCapturedFrame(CreateFrame(1, 1280, 720));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(fake_encoder_.video_codec().numberOfSimulcastStreams, kNumStreams);
EXPECT_NE(static_cast<uint32_t>(kEncoderLimits270p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_NE(static_cast<uint32_t>(kEncoderLimits270p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
video_stream_encoder_->Stop();
}
TEST_F(VideoStreamEncoderTest,
EncoderMaxBitrateCappedByConfigForTwoStreamsHighestActive) {
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits270p(
480 * 270, 34 * 1000, 12 * 1000, 1234 * 1000);
const VideoEncoder::ResolutionBitrateLimits kEncoderLimits360p(
640 * 360, 43 * 1000, 21 * 1000, 2345 * 1000);
fake_encoder_.SetResolutionBitrateLimits(
{kEncoderLimits270p, kEncoderLimits360p});
const int kMaxBitrateBps = kEncoderLimits360p.max_bitrate_bps - 100 * 1000;
// Two streams, highest stream active.
VideoEncoderConfig config;
const int kNumStreams = 2;
test::FillEncoderConfiguration(kVideoCodecVP8, kNumStreams, &config);
config.simulcast_layers[0].active = false;
config.simulcast_layers[1].active = true;
config.simulcast_layers[1].max_bitrate_bps = kMaxBitrateBps;
config.video_stream_factory =
new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
"VP8", /*max qp*/ 56, /*screencast*/ false,
/*screenshare enabled*/ false);
video_stream_encoder_->ConfigureEncoder(config.Copy(), kMaxPayloadLength);
// The encoder bitrate limits for 270p should be used.
video_source_.IncomingCapturedFrame(CreateFrame(1, 480, 270));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(fake_encoder_.video_codec().numberOfSimulcastStreams, kNumStreams);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits270p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits270p.max_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
// The max configured bitrate is less than the encoder limit for 360p.
video_source_.IncomingCapturedFrame(CreateFrame(2, 640, 360));
EXPECT_FALSE(WaitForFrame(1000));
EXPECT_EQ(static_cast<uint32_t>(kEncoderLimits360p.min_bitrate_bps),
fake_encoder_.video_codec().simulcastStream[1].minBitrate * 1000);
EXPECT_EQ(static_cast<uint32_t>(kMaxBitrateBps),
fake_encoder_.video_codec().simulcastStream[1].maxBitrate * 1000);
video_stream_encoder_->Stop();
}
TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
EXPECT_TRUE(video_source_.has_sinks());
test::FrameForwarder new_video_source;
@ -4091,7 +4286,7 @@ TEST_F(VideoStreamEncoderTest, ReportsVideoLayersAllocationForVP8Simulcast) {
}
TEST_F(VideoStreamEncoderTest,
ReportsVideoLayersAllocationForVP8WithMidleLayerDisabled) {
ReportsVideoLayersAllocationForVP8WithMiddleLayerDisabled) {
fake_encoder_.SetTemporalLayersSupported(/*spatial_idx=*/0, true);
fake_encoder_.SetTemporalLayersSupported(/*spatial_idx*/ 1, true);
fake_encoder_.SetTemporalLayersSupported(/*spatial_idx*/ 2, true);
@ -4136,7 +4331,7 @@ TEST_F(VideoStreamEncoderTest,
}
TEST_F(VideoStreamEncoderTest,
ReportsVideoLayersAllocationForVP8WithMidleAndHighestLayerDisabled) {
ReportsVideoLayersAllocationForVP8WithMiddleAndHighestLayerDisabled) {
fake_encoder_.SetTemporalLayersSupported(/*spatial_idx=*/0, true);
fake_encoder_.SetTemporalLayersSupported(/*spatial_idx*/ 1, true);
fake_encoder_.SetTemporalLayersSupported(/*spatial_idx*/ 2, true);