Reland "Pass true stream resolutions to GetSimulcastConfig()"
This is a reland of commit 09f03be54804e81f626c26e8fde8c86cc952545f Use max_num_layers instead of encoder_config.number_of_streams when calculation stream resolutions in EncoderStreamFactory::GetStreamResolutions(). Original change's description: > Pass true stream resolutions to GetSimulcastConfig() > > Before this change GetSimulcastConfig() received only maximum resolution as an input parameter and derived resolutions for low quality simulcast streams assuming 1/2 scaling factor [1]. These days applications can configure resolution scaling factors via RtpEncodingParameters. If the configured resolution scaling factors were different from 1/2 then we got wrong bitrate limits from GetSimulcastConfig(). Now resolutions are calculated using scaling factor from RtpEncodingParameters (or default 1/2) for all streams in EncoderStreamFactory::CreateEncoderStreams() and then passed to GetSimulcastConfig(). > > Moved tests from simulcast_unittest.cc to encoder_stream_factory_unittest.cc. Mapping of old to new tests: > * GetConfigWithLimitedMaxLayersForResolution -> ReducesStreamCountWhenResolutionIsLow > * GetConfigWithLowResolutionScreenshare -> ReducesLegacyScreencastStreamCountWhenResolutionIsLow > * GetConfigWithNotLimitedMaxLayersForResolution -> KeepsStreamCountUnchangedWhenLegacyLimitIsDisabled > * GetConfigWithNormalizedResolution -> AdjustsResolutionWhenUnaligned > * GetConfigWithNormalizedResolutionDivisibleBy4 -> MakesResolutionDivisibleBy4 > * GetConfigWithNormalizedResolutionDivisibleBy8 -> not needed (MakesResolutionDivisibleBy4 should be enough). > * GetConfigForLegacyLayerLimit -> KeepsStreamCountUnchangedWhenResolutionIsHigh and ReducesStreamCountWhenResolutionIsLow > * GetConfigForLegacyLayerLimitWithRequiredHD -> KeepsStreamCountUnchangedWhenLegacyLimitIsDisabled > > [1] https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/config/simulcast.cc;l=297-298;drc=1b78a7eb3f418460da03672b1d1af1d9488bb544 > > Bug: webrtc:351644568, b/352504711 > Change-Id: I0028904ab0bb1e27b9c1b7cd3fb9a8ccf447fa35 > No-Try: true > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/357280 > Commit-Queue: Sergey Silkin <ssilkin@webrtc.org> > Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#42651} Bug: webrtc:351644568, b/352504711 Change-Id: Ib3fd859257b61c2a5d695b8b8f45c95495117c0e No-Try: true Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/357520 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Sergey Silkin <ssilkin@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42654}
This commit is contained in:
parent
ede05c35e4
commit
5fe85d23a2
@ -18,8 +18,10 @@ rtc_library("streams_config") {
|
||||
|
||||
deps = [
|
||||
":encoder_config",
|
||||
"../../api:array_view",
|
||||
"../../api:field_trials_view",
|
||||
"../../api/units:data_rate",
|
||||
"../../api/video:resolution",
|
||||
"../../api/video:video_codec_constants",
|
||||
"../../api/video_codecs:video_codecs_api",
|
||||
"../../call/adaptation:resource_adaptation",
|
||||
@ -69,6 +71,7 @@ if (rtc_include_tests) {
|
||||
]
|
||||
deps = [
|
||||
":streams_config",
|
||||
"../../api/video_codecs:scalability_mode",
|
||||
"../../call/adaptation:resource_adaptation",
|
||||
"../../media:media_constants",
|
||||
"../../rtc_base/experiments:min_video_bitrate_experiment",
|
||||
|
||||
@ -111,6 +111,22 @@ int GetDefaultMaxQp(webrtc::VideoCodecType codec_type) {
|
||||
}
|
||||
}
|
||||
|
||||
// Round size to nearest simulcast-friendly size.
|
||||
// Simulcast stream width and height must both be dividable by
|
||||
// |2 ^ (simulcast_layers - 1)|.
|
||||
int NormalizeSimulcastSize(const FieldTrialsView& field_trials,
|
||||
int size,
|
||||
size_t simulcast_layers) {
|
||||
int base2_exponent = static_cast<int>(simulcast_layers) - 1;
|
||||
const absl::optional<int> experimental_base2_exponent =
|
||||
webrtc::NormalizeSimulcastSizeExperiment::GetBase2Exponent(field_trials);
|
||||
if (experimental_base2_exponent &&
|
||||
(size > (1 << *experimental_base2_exponent))) {
|
||||
base2_exponent = *experimental_base2_exponent;
|
||||
}
|
||||
return ((size >> base2_exponent) << base2_exponent);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
EncoderStreamFactory::EncoderStreamFactory(
|
||||
@ -322,16 +338,17 @@ EncoderStreamFactory::CreateSimulcastOrConferenceModeScreenshareStreams(
|
||||
webrtc::VideoEncoderConfig::ContentType::kScreen;
|
||||
const bool is_legacy_screencast =
|
||||
webrtc::SimulcastUtility::IsConferenceModeScreenshare(encoder_config);
|
||||
std::vector<webrtc::VideoStream> layers;
|
||||
|
||||
std::vector<webrtc::Resolution> resolutions =
|
||||
GetStreamResolutions(trials, width, height, encoder_config);
|
||||
|
||||
const bool temporal_layers_supported =
|
||||
IsTemporalLayersSupported(encoder_config.codec_type);
|
||||
// Use legacy simulcast screenshare if conference mode is explicitly enabled
|
||||
// or use the regular simulcast configuration path which is generic.
|
||||
layers = GetSimulcastConfig(FindRequiredActiveLayers(encoder_config),
|
||||
encoder_config.number_of_streams, width, height,
|
||||
is_legacy_screencast, temporal_layers_supported,
|
||||
trials, encoder_config.codec_type);
|
||||
std::vector<webrtc::VideoStream> layers = GetSimulcastConfig(
|
||||
resolutions, is_legacy_screencast, temporal_layers_supported, trials,
|
||||
encoder_config.codec_type);
|
||||
// Allow an experiment to override the minimum bitrate for the lowest
|
||||
// spatial layer. The experiment's configuration has the lowest priority.
|
||||
layers[0].min_bitrate_bps = experimental_min_bitrate
|
||||
@ -339,31 +356,6 @@ EncoderStreamFactory::CreateSimulcastOrConferenceModeScreenshareStreams(
|
||||
webrtc::kDefaultMinVideoBitrateBps))
|
||||
.bps<int>();
|
||||
|
||||
const bool has_scale_resolution_down_by = absl::c_any_of(
|
||||
encoder_config.simulcast_layers, [](const webrtc::VideoStream& layer) {
|
||||
return layer.scale_resolution_down_by != -1.;
|
||||
});
|
||||
|
||||
bool default_scale_factors_used = true;
|
||||
if (has_scale_resolution_down_by) {
|
||||
default_scale_factors_used = IsScaleFactorsPowerOfTwo(encoder_config);
|
||||
}
|
||||
const bool norm_size_configured =
|
||||
webrtc::NormalizeSimulcastSizeExperiment::GetBase2Exponent(trials)
|
||||
.has_value();
|
||||
const int normalized_width =
|
||||
(default_scale_factors_used || norm_size_configured) &&
|
||||
(width >= kMinLayerSize)
|
||||
? NormalizeSimulcastSize(trials, width,
|
||||
encoder_config.number_of_streams)
|
||||
: width;
|
||||
const int normalized_height =
|
||||
(default_scale_factors_used || norm_size_configured) &&
|
||||
(height >= kMinLayerSize)
|
||||
? NormalizeSimulcastSize(trials, height,
|
||||
encoder_config.number_of_streams)
|
||||
: height;
|
||||
|
||||
// Update the active simulcast layers and configured bitrates.
|
||||
for (size_t i = 0; i < layers.size(); ++i) {
|
||||
layers[i].active = encoder_config.simulcast_layers[i].active;
|
||||
@ -381,20 +373,6 @@ EncoderStreamFactory::CreateSimulcastOrConferenceModeScreenshareStreams(
|
||||
layers[i].max_framerate =
|
||||
encoder_config.simulcast_layers[i].max_framerate;
|
||||
}
|
||||
if (encoder_config.simulcast_layers[i].requested_resolution.has_value()) {
|
||||
auto res = GetLayerResolutionFromRequestedResolution(
|
||||
normalized_width, normalized_height,
|
||||
*encoder_config.simulcast_layers[i].requested_resolution);
|
||||
layers[i].width = res.width;
|
||||
layers[i].height = res.height;
|
||||
} else if (has_scale_resolution_down_by) {
|
||||
const double scale_resolution_down_by = std::max(
|
||||
encoder_config.simulcast_layers[i].scale_resolution_down_by, 1.0);
|
||||
layers[i].width = ScaleDownResolution(
|
||||
normalized_width, scale_resolution_down_by, kMinLayerSize);
|
||||
layers[i].height = ScaleDownResolution(
|
||||
normalized_height, scale_resolution_down_by, kMinLayerSize);
|
||||
}
|
||||
// Update simulcast bitrates with configured min and max bitrate.
|
||||
if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) {
|
||||
layers[i].min_bitrate_bps =
|
||||
@ -516,4 +494,69 @@ EncoderStreamFactory::GetLayerResolutionFromRequestedResolution(
|
||||
return {.width = out_width, .height = out_height};
|
||||
}
|
||||
|
||||
std::vector<webrtc::Resolution> EncoderStreamFactory::GetStreamResolutions(
|
||||
const webrtc::FieldTrialsView& trials,
|
||||
int width,
|
||||
int height,
|
||||
const webrtc::VideoEncoderConfig& encoder_config) const {
|
||||
std::vector<webrtc::Resolution> resolutions;
|
||||
if (webrtc::SimulcastUtility::IsConferenceModeScreenshare(encoder_config)) {
|
||||
for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
|
||||
resolutions.push_back({.width = width, .height = height});
|
||||
}
|
||||
} else {
|
||||
size_t min_num_layers = FindRequiredActiveLayers(encoder_config);
|
||||
size_t max_num_layers = LimitSimulcastLayerCount(
|
||||
min_num_layers, encoder_config.number_of_streams, width, height, trials,
|
||||
encoder_config.codec_type);
|
||||
RTC_DCHECK_LE(max_num_layers, encoder_config.number_of_streams);
|
||||
|
||||
const bool has_scale_resolution_down_by = absl::c_any_of(
|
||||
encoder_config.simulcast_layers, [](const webrtc::VideoStream& layer) {
|
||||
return layer.scale_resolution_down_by != -1.;
|
||||
});
|
||||
|
||||
bool default_scale_factors_used = true;
|
||||
if (has_scale_resolution_down_by) {
|
||||
default_scale_factors_used = IsScaleFactorsPowerOfTwo(encoder_config);
|
||||
}
|
||||
|
||||
const bool norm_size_configured =
|
||||
webrtc::NormalizeSimulcastSizeExperiment::GetBase2Exponent(trials)
|
||||
.has_value();
|
||||
const int normalized_width =
|
||||
(default_scale_factors_used || norm_size_configured) &&
|
||||
(width >= kMinLayerSize)
|
||||
? NormalizeSimulcastSize(trials, width, max_num_layers)
|
||||
: width;
|
||||
const int normalized_height =
|
||||
(default_scale_factors_used || norm_size_configured) &&
|
||||
(height >= kMinLayerSize)
|
||||
? NormalizeSimulcastSize(trials, height, max_num_layers)
|
||||
: height;
|
||||
|
||||
resolutions.resize(max_num_layers);
|
||||
for (size_t i = 0; i < max_num_layers; i++) {
|
||||
if (encoder_config.simulcast_layers[i].requested_resolution.has_value()) {
|
||||
resolutions[i] = GetLayerResolutionFromRequestedResolution(
|
||||
normalized_width, normalized_height,
|
||||
*encoder_config.simulcast_layers[i].requested_resolution);
|
||||
} else if (has_scale_resolution_down_by) {
|
||||
const double scale_resolution_down_by = std::max(
|
||||
encoder_config.simulcast_layers[i].scale_resolution_down_by, 1.0);
|
||||
resolutions[i].width = ScaleDownResolution(
|
||||
normalized_width, scale_resolution_down_by, kMinLayerSize);
|
||||
resolutions[i].height = ScaleDownResolution(
|
||||
normalized_height, scale_resolution_down_by, kMinLayerSize);
|
||||
} else {
|
||||
// Resolutions with default 1/2 scale factor, from low to high.
|
||||
resolutions[i].width = normalized_width >> (max_num_layers - i - 1);
|
||||
resolutions[i].height = normalized_height >> (max_num_layers - i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolutions;
|
||||
}
|
||||
|
||||
} // namespace cricket
|
||||
|
||||
@ -54,6 +54,12 @@ class EncoderStreamFactory
|
||||
int in_frame_height,
|
||||
webrtc::Resolution requested_resolution) const;
|
||||
|
||||
std::vector<webrtc::Resolution> GetStreamResolutions(
|
||||
const webrtc::FieldTrialsView& trials,
|
||||
int width,
|
||||
int height,
|
||||
const webrtc::VideoEncoderConfig& encoder_config) const;
|
||||
|
||||
const int encoder_info_requested_resolution_alignment_;
|
||||
const absl::optional<webrtc::VideoSourceRestrictions> restrictions_;
|
||||
};
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
#include "video/config/encoder_stream_factory.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "api/video_codecs/scalability_mode.h"
|
||||
#include "call/adaptation/video_source_restrictions.h"
|
||||
#include "rtc_base/experiments/min_video_bitrate_experiment.h"
|
||||
#include "test/explicit_key_value_config.h"
|
||||
@ -20,39 +23,71 @@ namespace webrtc {
|
||||
namespace {
|
||||
using ::cricket::EncoderStreamFactory;
|
||||
using test::ExplicitKeyValueConfig;
|
||||
using ::testing::Combine;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::Not;
|
||||
using ::testing::SizeIs;
|
||||
using ::testing::Values;
|
||||
|
||||
struct CreateVideoStreamParams {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int max_framerate_fps = -1;
|
||||
int min_bitrate_bps = -1;
|
||||
int target_bitrate_bps = -1;
|
||||
int max_bitrate_bps = -1;
|
||||
int scale_resolution_down_by = -1;
|
||||
std::optional<ScalabilityMode> scalability_mode;
|
||||
};
|
||||
|
||||
// A helper function that creates `VideoStream` with given settings.
|
||||
VideoStream CreateVideoStream(const CreateVideoStreamParams& params) {
|
||||
VideoStream stream;
|
||||
stream.width = params.width;
|
||||
stream.height = params.height;
|
||||
stream.max_framerate = params.max_framerate_fps;
|
||||
stream.min_bitrate_bps = params.min_bitrate_bps;
|
||||
stream.target_bitrate_bps = params.target_bitrate_bps;
|
||||
stream.max_bitrate_bps = params.max_bitrate_bps;
|
||||
stream.scale_resolution_down_by = params.scale_resolution_down_by;
|
||||
stream.scalability_mode = params.scalability_mode;
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::vector<Resolution> GetStreamResolutions(
|
||||
const std::vector<VideoStream>& streams) {
|
||||
std::vector<Resolution> res;
|
||||
for (const auto& s : streams) {
|
||||
if (s.active) {
|
||||
res.push_back(
|
||||
{rtc::checked_cast<int>(s.width), rtc::checked_cast<int>(s.height)});
|
||||
}
|
||||
res.push_back(
|
||||
{rtc::checked_cast<int>(s.width), rtc::checked_cast<int>(s.height)});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
VideoStream LayerWithRequestedResolution(Resolution res) {
|
||||
VideoStream s;
|
||||
s.requested_resolution = res;
|
||||
return s;
|
||||
std::vector<VideoStream> CreateEncoderStreams(
|
||||
const FieldTrialsView& field_trials,
|
||||
const Resolution& resolution,
|
||||
const VideoEncoderConfig& encoder_config,
|
||||
absl::optional<VideoSourceRestrictions> restrictions = absl::nullopt) {
|
||||
VideoEncoder::EncoderInfo encoder_info;
|
||||
auto factory =
|
||||
rtc::make_ref_counted<EncoderStreamFactory>(encoder_info, restrictions);
|
||||
return factory->CreateEncoderStreams(field_trials, resolution.width,
|
||||
resolution.height, encoder_config);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(EncoderStreamFactory, SinglecastRequestedResolution) {
|
||||
ExplicitKeyValueConfig field_trials("");
|
||||
VideoEncoder::EncoderInfo encoder_info;
|
||||
auto factory = rtc::make_ref_counted<EncoderStreamFactory>(encoder_info);
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.number_of_streams = 1;
|
||||
encoder_config.simulcast_layers.push_back(
|
||||
LayerWithRequestedResolution({.width = 640, .height = 360}));
|
||||
auto streams =
|
||||
factory->CreateEncoderStreams(field_trials, 1280, 720, encoder_config);
|
||||
encoder_config.simulcast_layers.resize(1);
|
||||
encoder_config.simulcast_layers[0].requested_resolution = {.width = 640,
|
||||
.height = 360};
|
||||
auto streams = CreateEncoderStreams(
|
||||
field_trials, {.width = 1280, .height = 720}, encoder_config);
|
||||
EXPECT_EQ(streams[0].requested_resolution,
|
||||
(Resolution{.width = 640, .height = 360}));
|
||||
EXPECT_EQ(GetStreamResolutions(streams), (std::vector<Resolution>{
|
||||
@ -66,15 +101,14 @@ TEST(EncoderStreamFactory, SinglecastRequestedResolutionWithAdaptation) {
|
||||
/* max_pixels_per_frame= */ (320 * 320),
|
||||
/* target_pixels_per_frame= */ absl::nullopt,
|
||||
/* max_frame_rate= */ absl::nullopt);
|
||||
VideoEncoder::EncoderInfo encoder_info;
|
||||
auto factory =
|
||||
rtc::make_ref_counted<EncoderStreamFactory>(encoder_info, restrictions);
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.number_of_streams = 1;
|
||||
encoder_config.simulcast_layers.push_back(
|
||||
LayerWithRequestedResolution({.width = 640, .height = 360}));
|
||||
encoder_config.simulcast_layers.resize(1);
|
||||
encoder_config.simulcast_layers[0].requested_resolution = {.width = 640,
|
||||
.height = 360};
|
||||
auto streams =
|
||||
factory->CreateEncoderStreams(field_trials, 1280, 720, encoder_config);
|
||||
CreateEncoderStreams(field_trials, {.width = 1280, .height = 720},
|
||||
encoder_config, restrictions);
|
||||
EXPECT_EQ(streams[0].requested_resolution,
|
||||
(Resolution{.width = 640, .height = 360}));
|
||||
EXPECT_EQ(GetStreamResolutions(streams), (std::vector<Resolution>{
|
||||
@ -84,18 +118,14 @@ TEST(EncoderStreamFactory, SinglecastRequestedResolutionWithAdaptation) {
|
||||
|
||||
TEST(EncoderStreamFactory, BitratePriority) {
|
||||
constexpr double kBitratePriority = 0.123;
|
||||
ExplicitKeyValueConfig field_trials("");
|
||||
VideoEncoder::EncoderInfo encoder_info;
|
||||
auto factory = rtc::make_ref_counted<EncoderStreamFactory>(encoder_info);
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.number_of_streams = 2;
|
||||
encoder_config.simulcast_layers.resize(encoder_config.number_of_streams);
|
||||
encoder_config.bitrate_priority = kBitratePriority;
|
||||
encoder_config.simulcast_layers = {
|
||||
LayerWithRequestedResolution({.width = 320, .height = 180}),
|
||||
LayerWithRequestedResolution({.width = 640, .height = 360})};
|
||||
auto streams =
|
||||
factory->CreateEncoderStreams(field_trials, 640, 360, encoder_config);
|
||||
ASSERT_EQ(streams.size(), 2u);
|
||||
auto streams = CreateEncoderStreams(
|
||||
/*field_trials=*/ExplicitKeyValueConfig(""),
|
||||
{.width = 640, .height = 360}, encoder_config);
|
||||
ASSERT_THAT(streams, SizeIs(2));
|
||||
EXPECT_EQ(streams[0].bitrate_priority, kBitratePriority);
|
||||
EXPECT_FALSE(streams[1].bitrate_priority);
|
||||
}
|
||||
@ -125,4 +155,182 @@ TEST(EncoderStreamFactory, SetsMinBitrateToExperimentalValue) {
|
||||
EXPECT_NE(streams[0].min_bitrate_bps, kDefaultMinVideoBitrateBps);
|
||||
EXPECT_EQ(streams[0].min_bitrate_bps, 1000);
|
||||
}
|
||||
|
||||
struct StreamResolutionTestParams {
|
||||
absl::string_view field_trials;
|
||||
size_t number_of_streams = 1;
|
||||
Resolution resolution = {.width = 640, .height = 480};
|
||||
bool is_legacy_screencast = false;
|
||||
size_t first_active_layer_idx = 0;
|
||||
};
|
||||
|
||||
std::vector<Resolution> CreateStreamResolutions(
|
||||
const StreamResolutionTestParams& test_params) {
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.codec_type = VideoCodecType::kVideoCodecVP8;
|
||||
encoder_config.number_of_streams = test_params.number_of_streams;
|
||||
encoder_config.simulcast_layers.resize(test_params.number_of_streams);
|
||||
for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
|
||||
encoder_config.simulcast_layers[i].active =
|
||||
(i >= test_params.first_active_layer_idx);
|
||||
}
|
||||
if (test_params.is_legacy_screencast) {
|
||||
encoder_config.content_type = VideoEncoderConfig::ContentType::kScreen;
|
||||
encoder_config.legacy_conference_mode = true;
|
||||
}
|
||||
return GetStreamResolutions(
|
||||
CreateEncoderStreams(ExplicitKeyValueConfig(test_params.field_trials),
|
||||
test_params.resolution, encoder_config));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, KeepsResolutionUnchangedWhenAligned) {
|
||||
EXPECT_THAT(
|
||||
CreateStreamResolutions({.number_of_streams = 2,
|
||||
.resolution = {.width = 516, .height = 526}}),
|
||||
ElementsAre(Resolution{.width = 516 / 2, .height = 526 / 2},
|
||||
Resolution{.width = 516, .height = 526}));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, AdjustsResolutionWhenUnaligned) {
|
||||
// By default width and height of the smallest simulcast stream are required
|
||||
// to be whole numbers. To achieve that, the resolution of the highest
|
||||
// simulcast stream is adjusted to be multiple of (2 ^ (number_of_streams -
|
||||
// 1)) by rounding down.
|
||||
EXPECT_THAT(
|
||||
CreateStreamResolutions({.number_of_streams = 2,
|
||||
.resolution = {.width = 515, .height = 517}}),
|
||||
ElementsAre(Resolution{.width = 514 / 2, .height = 516 / 2},
|
||||
Resolution{.width = 514, .height = 516}));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, MakesResolutionDivisibleBy4) {
|
||||
EXPECT_THAT(
|
||||
CreateStreamResolutions(
|
||||
{.field_trials = "WebRTC-NormalizeSimulcastResolution/Enabled-2/",
|
||||
.number_of_streams = 2,
|
||||
.resolution = {.width = 515, .height = 517}}),
|
||||
ElementsAre(Resolution{.width = 512 / 2, .height = 516 / 2},
|
||||
Resolution{.width = 512, .height = 516}));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, KeepsStreamCountUnchangedWhenResolutionIsHigh) {
|
||||
EXPECT_THAT(
|
||||
CreateStreamResolutions({.number_of_streams = 3,
|
||||
.resolution = {.width = 1000, .height = 1000}}),
|
||||
SizeIs(3));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, ReducesStreamCountWhenResolutionIsLow) {
|
||||
EXPECT_THAT(
|
||||
CreateStreamResolutions({.number_of_streams = 3,
|
||||
.resolution = {.width = 100, .height = 100}}),
|
||||
SizeIs(1));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, ReducesStreamCountDownToFirstActiveStream) {
|
||||
EXPECT_THAT(
|
||||
CreateStreamResolutions({.number_of_streams = 3,
|
||||
.resolution = {.width = 100, .height = 100},
|
||||
.first_active_layer_idx = 1}),
|
||||
SizeIs(2));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory,
|
||||
ReducesLegacyScreencastStreamCountWhenResolutionIsLow) {
|
||||
// At least 2 streams are expected to be configured in legacy screencast mode.
|
||||
EXPECT_THAT(
|
||||
CreateStreamResolutions({.number_of_streams = 3,
|
||||
.resolution = {.width = 100, .height = 100},
|
||||
.is_legacy_screencast = true}),
|
||||
SizeIs(2));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, KeepsStreamCountUnchangedWhenLegacyLimitIsDisabled) {
|
||||
EXPECT_THAT(CreateStreamResolutions(
|
||||
{.field_trials = "WebRTC-LegacySimulcastLayerLimit/Disabled/",
|
||||
.number_of_streams = 3,
|
||||
.resolution = {.width = 100, .height = 100}}),
|
||||
SizeIs(3));
|
||||
}
|
||||
|
||||
TEST(EncoderStreamFactory, KeepsHighResolutionWhenStreamCountIsReduced) {
|
||||
EXPECT_THAT(
|
||||
CreateStreamResolutions({.number_of_streams = 3,
|
||||
.resolution = {.width = 640, .height = 360}}),
|
||||
ElementsAre(Resolution{.width = 320, .height = 180},
|
||||
Resolution{.width = 640, .height = 360}));
|
||||
}
|
||||
|
||||
struct OverrideStreamSettingsTestParams {
|
||||
std::string field_trials;
|
||||
Resolution input_resolution;
|
||||
VideoEncoderConfig::ContentType content_type;
|
||||
std::vector<VideoStream> requested_streams;
|
||||
std::vector<VideoStream> expected_streams;
|
||||
};
|
||||
|
||||
class EncoderStreamFactoryOverrideStreamSettinsTest
|
||||
: public ::testing::TestWithParam<
|
||||
std::tuple<OverrideStreamSettingsTestParams, VideoCodecType>> {};
|
||||
|
||||
TEST_P(EncoderStreamFactoryOverrideStreamSettinsTest, OverrideStreamSettings) {
|
||||
OverrideStreamSettingsTestParams test_params = std::get<0>(GetParam());
|
||||
VideoEncoderConfig encoder_config;
|
||||
encoder_config.codec_type = std::get<1>(GetParam());
|
||||
encoder_config.number_of_streams = test_params.requested_streams.size();
|
||||
encoder_config.simulcast_layers = test_params.requested_streams;
|
||||
encoder_config.content_type = test_params.content_type;
|
||||
auto streams =
|
||||
CreateEncoderStreams(ExplicitKeyValueConfig(test_params.field_trials),
|
||||
test_params.input_resolution, encoder_config);
|
||||
ASSERT_EQ(streams.size(), test_params.expected_streams.size());
|
||||
for (size_t i = 0; i < streams.size(); ++i) {
|
||||
SCOPED_TRACE(i);
|
||||
const VideoStream& expected = test_params.expected_streams[i];
|
||||
EXPECT_EQ(streams[i].width, expected.width);
|
||||
EXPECT_EQ(streams[i].height, expected.height);
|
||||
EXPECT_EQ(streams[i].max_framerate, expected.max_framerate);
|
||||
EXPECT_EQ(streams[i].min_bitrate_bps, expected.min_bitrate_bps);
|
||||
EXPECT_EQ(streams[i].target_bitrate_bps, expected.target_bitrate_bps);
|
||||
EXPECT_EQ(streams[i].max_bitrate_bps, expected.max_bitrate_bps);
|
||||
EXPECT_EQ(streams[i].scalability_mode, expected.scalability_mode);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Screencast,
|
||||
EncoderStreamFactoryOverrideStreamSettinsTest,
|
||||
Combine(Values(OverrideStreamSettingsTestParams{
|
||||
.input_resolution = {.width = 1920, .height = 1080},
|
||||
.content_type = VideoEncoderConfig::ContentType::kScreen,
|
||||
.requested_streams =
|
||||
{CreateVideoStream(
|
||||
{.max_framerate_fps = 5,
|
||||
.max_bitrate_bps = 420'000,
|
||||
.scale_resolution_down_by = 1,
|
||||
.scalability_mode = ScalabilityMode::kL1T2}),
|
||||
CreateVideoStream(
|
||||
{.max_framerate_fps = 30,
|
||||
.max_bitrate_bps = 2'500'000,
|
||||
.scale_resolution_down_by = 1,
|
||||
.scalability_mode = ScalabilityMode::kL1T2})},
|
||||
.expected_streams =
|
||||
{CreateVideoStream(
|
||||
{.width = 1920,
|
||||
.height = 1080,
|
||||
.max_framerate_fps = 5,
|
||||
.min_bitrate_bps = 30'000,
|
||||
.target_bitrate_bps = 420'000,
|
||||
.max_bitrate_bps = 420'000,
|
||||
.scalability_mode = ScalabilityMode::kL1T2}),
|
||||
CreateVideoStream(
|
||||
{.width = 1920,
|
||||
.height = 1080,
|
||||
.max_framerate_fps = 30,
|
||||
.min_bitrate_bps = 800'000,
|
||||
.target_bitrate_bps = 2'500'000,
|
||||
.max_bitrate_bps = 2'500'000,
|
||||
.scalability_mode = ScalabilityMode::kL1T2})}}),
|
||||
Values(VideoCodecType::kVideoCodecVP8,
|
||||
VideoCodecType::kVideoCodecAV1)));
|
||||
} // namespace webrtc
|
||||
|
||||
@ -229,31 +229,25 @@ SimulcastFormat InterpolateSimulcastFormat(
|
||||
}
|
||||
|
||||
std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
|
||||
size_t layer_count,
|
||||
int width,
|
||||
int height,
|
||||
rtc::ArrayView<const webrtc::Resolution> resolutions,
|
||||
bool temporal_layers_supported,
|
||||
bool base_heavy_tl3_rate_alloc,
|
||||
const webrtc::FieldTrialsView& trials,
|
||||
webrtc::VideoCodecType codec) {
|
||||
std::vector<webrtc::VideoStream> layers(layer_count);
|
||||
const bool enable_lowres_bitrate_interpolation =
|
||||
EnableLowresBitrateInterpolation(trials);
|
||||
const int num_temporal_layers =
|
||||
temporal_layers_supported ? kDefaultNumTemporalLayers : 1;
|
||||
// Format width and height has to be divisible by |2 ^ num_simulcast_layers -
|
||||
// 1|.
|
||||
width = NormalizeSimulcastSize(trials, width, layer_count);
|
||||
height = NormalizeSimulcastSize(trials, height, layer_count);
|
||||
// Add simulcast streams, from highest resolution (`s` = num_simulcast_layers
|
||||
// -1) to lowest resolution at `s` = 0.
|
||||
for (size_t s = layer_count - 1;; --s) {
|
||||
layers[s].width = width;
|
||||
layers[s].height = height;
|
||||
std::vector<webrtc::VideoStream> layers(resolutions.size());
|
||||
for (size_t s = 0; s < resolutions.size(); ++s) {
|
||||
layers[s].width = resolutions[s].width;
|
||||
layers[s].height = resolutions[s].height;
|
||||
layers[s].num_temporal_layers = num_temporal_layers;
|
||||
|
||||
SimulcastFormat interpolated_format = InterpolateSimulcastFormat(
|
||||
width, height, /*max_roundup_rate=*/absl::nullopt,
|
||||
layers[s].width, layers[s].height, /*max_roundup_rate=*/absl::nullopt,
|
||||
enable_lowres_bitrate_interpolation, codec);
|
||||
|
||||
layers[s].max_bitrate_bps = interpolated_format.max_bitrate.bps();
|
||||
@ -293,13 +287,6 @@ std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
|
||||
std::max(layers[s].min_bitrate_bps, layers[s].target_bitrate_bps);
|
||||
|
||||
layers[s].max_framerate = kDefaultVideoMaxFramerate;
|
||||
|
||||
width /= 2;
|
||||
height /= 2;
|
||||
|
||||
if (s == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return layers;
|
||||
@ -362,10 +349,12 @@ std::vector<webrtc::VideoStream> GetScreenshareLayers(
|
||||
return layers;
|
||||
}
|
||||
|
||||
size_t LimitSimulcastLayerCount(int width,
|
||||
} // namespace
|
||||
|
||||
size_t LimitSimulcastLayerCount(size_t min_num_layers,
|
||||
size_t max_num_layers,
|
||||
int width,
|
||||
int height,
|
||||
size_t need_layers,
|
||||
size_t layer_count,
|
||||
const webrtc::FieldTrialsView& trials,
|
||||
webrtc::VideoCodecType codec) {
|
||||
if (!absl::StartsWith(trials.Lookup(kUseLegacySimulcastLayerLimitFieldTrial),
|
||||
@ -378,36 +367,19 @@ size_t LimitSimulcastLayerCount(int width,
|
||||
webrtc::ParseFieldTrial({&max_ratio},
|
||||
trials.Lookup("WebRTC-SimulcastLayerLimitRoundUp"));
|
||||
|
||||
size_t adaptive_layer_count = std::max(
|
||||
need_layers, InterpolateSimulcastFormat(
|
||||
width, height, max_ratio.GetOptional(),
|
||||
/*enable_lowres_bitrate_interpolation=*/false, codec)
|
||||
.max_layers);
|
||||
if (layer_count > adaptive_layer_count) {
|
||||
size_t reduced_num_layers =
|
||||
std::max(min_num_layers,
|
||||
InterpolateSimulcastFormat(
|
||||
width, height, max_ratio.GetOptional(),
|
||||
/*enable_lowres_bitrate_interpolation=*/false, codec)
|
||||
.max_layers);
|
||||
if (max_num_layers > reduced_num_layers) {
|
||||
RTC_LOG(LS_WARNING) << "Reducing simulcast layer count from "
|
||||
<< layer_count << " to " << adaptive_layer_count;
|
||||
layer_count = adaptive_layer_count;
|
||||
<< max_num_layers << " to " << reduced_num_layers;
|
||||
return reduced_num_layers;
|
||||
}
|
||||
}
|
||||
return layer_count;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Round size to nearest simulcast-friendly size.
|
||||
// Simulcast stream width and height must both be dividable by
|
||||
// |2 ^ (simulcast_layers - 1)|.
|
||||
int NormalizeSimulcastSize(const FieldTrialsView& field_trials,
|
||||
int size,
|
||||
size_t simulcast_layers) {
|
||||
int base2_exponent = static_cast<int>(simulcast_layers) - 1;
|
||||
const absl::optional<int> experimental_base2_exponent =
|
||||
webrtc::NormalizeSimulcastSizeExperiment::GetBase2Exponent(field_trials);
|
||||
if (experimental_base2_exponent &&
|
||||
(size > (1 << *experimental_base2_exponent))) {
|
||||
base2_exponent = *experimental_base2_exponent;
|
||||
}
|
||||
return ((size >> base2_exponent) << base2_exponent);
|
||||
return max_num_layers;
|
||||
}
|
||||
|
||||
void BoostMaxSimulcastLayer(webrtc::DataRate max_bitrate,
|
||||
@ -439,32 +411,21 @@ webrtc::DataRate GetTotalMaxBitrate(
|
||||
}
|
||||
|
||||
std::vector<webrtc::VideoStream> GetSimulcastConfig(
|
||||
size_t min_layers,
|
||||
size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
rtc::ArrayView<const webrtc::Resolution> resolutions,
|
||||
bool is_screenshare_with_conference_mode,
|
||||
bool temporal_layers_supported,
|
||||
const webrtc::FieldTrialsView& trials,
|
||||
webrtc::VideoCodecType codec) {
|
||||
RTC_DCHECK_LE(min_layers, max_layers);
|
||||
RTC_DCHECK(max_layers > 1 || is_screenshare_with_conference_mode);
|
||||
RTC_DCHECK(!resolutions.empty());
|
||||
|
||||
const bool base_heavy_tl3_rate_alloc =
|
||||
webrtc::RateControlSettings(trials).Vp8BaseHeavyTl3RateAllocation();
|
||||
if (is_screenshare_with_conference_mode) {
|
||||
return GetScreenshareLayers(max_layers, width, height,
|
||||
temporal_layers_supported,
|
||||
base_heavy_tl3_rate_alloc, trials);
|
||||
return GetScreenshareLayers(
|
||||
resolutions.size(), resolutions[0].width, resolutions[0].height,
|
||||
temporal_layers_supported, base_heavy_tl3_rate_alloc, trials);
|
||||
} else {
|
||||
// Some applications rely on the old behavior limiting the simulcast layer
|
||||
// count based on the resolution automatically, which they can get through
|
||||
// the WebRTC-LegacySimulcastLayerLimit field trial until they update.
|
||||
max_layers = LimitSimulcastLayerCount(width, height, min_layers, max_layers,
|
||||
trials, codec);
|
||||
|
||||
return GetNormalSimulcastLayers(max_layers, width, height,
|
||||
temporal_layers_supported,
|
||||
return GetNormalSimulcastLayers(resolutions, temporal_layers_supported,
|
||||
base_heavy_tl3_rate_alloc, trials, codec);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,8 +15,10 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "api/field_trials_view.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/video/resolution.h"
|
||||
#include "video/config/video_encoder_config.h"
|
||||
|
||||
namespace cricket {
|
||||
@ -30,17 +32,19 @@ webrtc::DataRate GetTotalMaxBitrate(
|
||||
void BoostMaxSimulcastLayer(webrtc::DataRate max_bitrate,
|
||||
std::vector<webrtc::VideoStream>* layers);
|
||||
|
||||
// Round size to nearest simulcast-friendly size
|
||||
int NormalizeSimulcastSize(const webrtc::FieldTrialsView& field_trials,
|
||||
int size,
|
||||
size_t simulcast_layers);
|
||||
// Returns number of simulcast streams. The value depends on the resolution and
|
||||
// is restricted to the range from `min_num_layers` to `max_num_layers`,
|
||||
// inclusive.
|
||||
size_t LimitSimulcastLayerCount(size_t min_num_layers,
|
||||
size_t max_num_layers,
|
||||
int width,
|
||||
int height,
|
||||
const webrtc::FieldTrialsView& trials,
|
||||
webrtc::VideoCodecType codec);
|
||||
|
||||
// Gets simulcast settings.
|
||||
std::vector<webrtc::VideoStream> GetSimulcastConfig(
|
||||
size_t min_layers,
|
||||
size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
rtc::ArrayView<const webrtc::Resolution> resolutions,
|
||||
bool is_screenshare_with_conference_mode,
|
||||
bool temporal_layers_supported,
|
||||
const webrtc::FieldTrialsView& trials,
|
||||
|
||||
@ -12,12 +12,13 @@
|
||||
|
||||
#include "media/base/media_constants.h"
|
||||
#include "test/explicit_key_value_config.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
using test::ExplicitKeyValueConfig;
|
||||
using ::testing::SizeIs;
|
||||
|
||||
constexpr bool kScreenshare = true;
|
||||
constexpr int kDefaultTemporalLayers = 3; // Value from simulcast.cc.
|
||||
@ -36,6 +37,19 @@ const std::vector<VideoStream> GetSimulcastBitrates720p() {
|
||||
streams[2].max_bitrate_bps = 2500000;
|
||||
return streams;
|
||||
}
|
||||
|
||||
// Creates a vector of resolutions scaled down with 1/2 factor ordered from low
|
||||
// to high.
|
||||
std::vector<Resolution> CreateResolutions(int max_width,
|
||||
int max_height,
|
||||
int num_streams) {
|
||||
std::vector<webrtc::Resolution> resolutions(num_streams);
|
||||
for (int i = 0; i < num_streams; ++i) {
|
||||
resolutions[i].width = max_width >> (num_streams - i - 1);
|
||||
resolutions[i].height = max_height >> (num_streams - i - 1);
|
||||
}
|
||||
return resolutions;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(SimulcastTest, TotalMaxBitrateIsZeroForNoStreams) {
|
||||
@ -83,13 +97,12 @@ TEST(SimulcastTest, GetConfig) {
|
||||
|
||||
const std::vector<VideoStream> kExpected = GetSimulcastBitrates720p();
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 1280, 720, !kScreenshare, true, trials,
|
||||
CreateResolutions(1280, 720, kMaxLayers), !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
ASSERT_THAT(streams, SizeIs(kMaxLayers));
|
||||
EXPECT_EQ(320u, streams[0].width);
|
||||
EXPECT_EQ(180u, streams[0].height);
|
||||
EXPECT_EQ(640u, streams[1].width);
|
||||
@ -114,12 +127,12 @@ TEST(SimulcastTest, GetConfigWithBaseHeavyVP8TL3RateAllocation) {
|
||||
|
||||
const std::vector<VideoStream> kExpected = GetSimulcastBitrates720p();
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 1280, 720, !kScreenshare, true, trials,
|
||||
CreateResolutions(1280, 720, kMaxLayers), !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
ASSERT_THAT(streams, SizeIs(kMaxLayers));
|
||||
EXPECT_EQ(kExpected[0].min_bitrate_bps, streams[0].min_bitrate_bps);
|
||||
EXPECT_EQ(static_cast<int>(0.4 * kExpected[0].target_bitrate_bps / 0.6),
|
||||
streams[0].target_bitrate_bps);
|
||||
@ -135,176 +148,27 @@ TEST(SimulcastTest, GetConfigWithBaseHeavyVP8TL3RateAllocation) {
|
||||
TEST(SimulcastTest, GetConfigWithLimitedMaxLayers) {
|
||||
ExplicitKeyValueConfig trials("");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 2;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 1280, 720, !kScreenshare, true, trials,
|
||||
CreateResolutions(1280, 720, kMaxLayers), !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
ASSERT_THAT(streams, SizeIs(kMaxLayers));
|
||||
EXPECT_EQ(640u, streams[0].width);
|
||||
EXPECT_EQ(360u, streams[0].height);
|
||||
EXPECT_EQ(1280u, streams[1].width);
|
||||
EXPECT_EQ(720u, streams[1].height);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigWithLimitedMaxLayersForResolution) {
|
||||
ExplicitKeyValueConfig trials(
|
||||
"WebRTC-LegacySimulcastLayerLimit/Enabled/");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 800, 600, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
EXPECT_EQ(400u, streams[0].width);
|
||||
EXPECT_EQ(300u, streams[0].height);
|
||||
EXPECT_EQ(800u, streams[1].width);
|
||||
EXPECT_EQ(600u, streams[1].height);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigWithLowResolutionScreenshare) {
|
||||
ExplicitKeyValueConfig trials(
|
||||
"WebRTC-LegacySimulcastLayerLimit/Enabled/");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 100, 100, kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
// Simulcast streams number is never decreased for screenshare,
|
||||
// even for very low resolution.
|
||||
EXPECT_GT(streams.size(), 1u);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigWithNotLimitedMaxLayersForResolution) {
|
||||
ExplicitKeyValueConfig trials(
|
||||
"WebRTC-LegacySimulcastLayerLimit/Disabled/");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 800, 600, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
EXPECT_EQ(200u, streams[0].width);
|
||||
EXPECT_EQ(150u, streams[0].height);
|
||||
EXPECT_EQ(400u, streams[1].width);
|
||||
EXPECT_EQ(300u, streams[1].height);
|
||||
EXPECT_EQ(800u, streams[2].width);
|
||||
EXPECT_EQ(600u, streams[2].height);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigWithNormalizedResolution) {
|
||||
ExplicitKeyValueConfig trials("");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 2;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 640 + 1, 360 + 1, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
// Must be divisible by |2 ^ (num_layers - 1)|.
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
EXPECT_EQ(320u, streams[0].width);
|
||||
EXPECT_EQ(180u, streams[0].height);
|
||||
EXPECT_EQ(640u, streams[1].width);
|
||||
EXPECT_EQ(360u, streams[1].height);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigWithNormalizedResolutionDivisibleBy4) {
|
||||
ExplicitKeyValueConfig trials(
|
||||
"WebRTC-NormalizeSimulcastResolution/Enabled-2/");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 2;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 709, 501, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
// Must be divisible by |2 ^ 2|.
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
EXPECT_EQ(354u, streams[0].width);
|
||||
EXPECT_EQ(250u, streams[0].height);
|
||||
EXPECT_EQ(708u, streams[1].width);
|
||||
EXPECT_EQ(500u, streams[1].height);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigWithNormalizedResolutionDivisibleBy8) {
|
||||
ExplicitKeyValueConfig trials(
|
||||
"WebRTC-NormalizeSimulcastResolution/Enabled-3/");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 2;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 709, 501, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
// Must be divisible by |2 ^ 3|.
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
EXPECT_EQ(352u, streams[0].width);
|
||||
EXPECT_EQ(248u, streams[0].height);
|
||||
EXPECT_EQ(704u, streams[1].width);
|
||||
EXPECT_EQ(496u, streams[1].height);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigForLegacyLayerLimit) {
|
||||
ExplicitKeyValueConfig trials(
|
||||
"WebRTC-LegacySimulcastLayerLimit/Enabled/");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const int kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 320, 180, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(1u, streams.size());
|
||||
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 640, 360,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(3u, streams.size());
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigForLegacyLayerLimitWithRequiredHD) {
|
||||
ExplicitKeyValueConfig trials(
|
||||
"WebRTC-LegacySimulcastLayerLimit/Enabled/");
|
||||
|
||||
const size_t kMinLayers = 3; // "HD" layer must be present!
|
||||
const int kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 320, 180, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(3u, streams.size());
|
||||
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 640, 360,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(3u, streams.size());
|
||||
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(3u, streams.size());
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, GetConfigForScreenshareSimulcast) {
|
||||
ExplicitKeyValueConfig trials("");
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 1400, 800, kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
std::vector<Resolution>{{.width = 1400, .height = 800},
|
||||
{.width = 1400, .height = 800},
|
||||
{.width = 1400, .height = 800}},
|
||||
kScreenshare, true, trials, webrtc::kVideoCodecVP8);
|
||||
|
||||
EXPECT_GT(streams.size(), 1u);
|
||||
EXPECT_THAT(streams, SizeIs(2));
|
||||
for (size_t i = 0; i < streams.size(); ++i) {
|
||||
EXPECT_EQ(1400u, streams[i].width) << "Screen content never scaled.";
|
||||
EXPECT_EQ(800u, streams[i].height) << "Screen content never scaled.";
|
||||
@ -320,35 +184,29 @@ TEST(SimulcastTest, GetConfigForScreenshareSimulcast) {
|
||||
|
||||
TEST(SimulcastTest, GetConfigForScreenshareSimulcastWithLimitedMaxLayers) {
|
||||
ExplicitKeyValueConfig trials("");
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 1;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 1400, 800, kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
std::vector<Resolution>{{.width = 1400, .height = 800}}, kScreenshare,
|
||||
true, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_THAT(streams, SizeIs(1));
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, AveragesBitratesForNonStandardResolution) {
|
||||
ExplicitKeyValueConfig trials("");
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, 900, 800, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
std::vector<Resolution>{{.width = 900, .height = 800}}, !kScreenshare,
|
||||
true, trials, webrtc::kVideoCodecVP8);
|
||||
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
EXPECT_EQ(900u, streams[2].width);
|
||||
EXPECT_EQ(800u, streams[2].height);
|
||||
EXPECT_EQ(1850000, streams[2].max_bitrate_bps);
|
||||
EXPECT_EQ(1850000, streams[2].target_bitrate_bps);
|
||||
EXPECT_EQ(475000, streams[2].min_bitrate_bps);
|
||||
ASSERT_THAT(streams, SizeIs(1));
|
||||
EXPECT_EQ(900u, streams[0].width);
|
||||
EXPECT_EQ(800u, streams[0].height);
|
||||
EXPECT_EQ(1850000, streams[0].max_bitrate_bps);
|
||||
EXPECT_EQ(1850000, streams[0].target_bitrate_bps);
|
||||
EXPECT_EQ(475000, streams[0].min_bitrate_bps);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, BitratesForCloseToStandardResolution) {
|
||||
ExplicitKeyValueConfig trials("");
|
||||
|
||||
const size_t kMinLayers = 1;
|
||||
const size_t kMaxLayers = 3;
|
||||
// Resolution very close to 720p in number of pixels
|
||||
const size_t kWidth = 1280;
|
||||
@ -356,10 +214,10 @@ TEST(SimulcastTest, BitratesForCloseToStandardResolution) {
|
||||
const std::vector<VideoStream> kExpectedNear = GetSimulcastBitrates720p();
|
||||
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
kMinLayers, kMaxLayers, kWidth, kHeight, !kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
CreateResolutions(kWidth, kHeight, kMaxLayers), !kScreenshare, true,
|
||||
trials, webrtc::kVideoCodecVP8);
|
||||
|
||||
EXPECT_EQ(kMaxLayers, streams.size());
|
||||
ASSERT_THAT(streams, SizeIs(kMaxLayers));
|
||||
EXPECT_EQ(kWidth, streams[2].width);
|
||||
EXPECT_EQ(kHeight, streams[2].height);
|
||||
for (size_t i = 0; i < streams.size(); ++i) {
|
||||
@ -379,25 +237,20 @@ TEST(SimulcastTest, MaxLayersWithRoundUpDisabled) {
|
||||
const size_t kMinLayers = 1;
|
||||
const int kMaxLayers = 3;
|
||||
|
||||
std::vector<VideoStream> streams;
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 540,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(3u, streams.size());
|
||||
size_t num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 960, 540, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 3u);
|
||||
// <960x540: 2 layers
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 539,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 960, 539, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 2u);
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 480, 270, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 2u);
|
||||
// <480x270: 1 layer
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 269,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(1u, streams.size());
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 480, 269, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 1u);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, MaxLayersWithDefaultRoundUpRatio) {
|
||||
@ -406,33 +259,26 @@ TEST(SimulcastTest, MaxLayersWithDefaultRoundUpRatio) {
|
||||
const size_t kMinLayers = 1;
|
||||
const int kMaxLayers = 3;
|
||||
|
||||
std::vector<VideoStream> streams;
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 540,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(3u, streams.size());
|
||||
size_t num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 960, 540, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 3u);
|
||||
// Lowest cropped height where max layers from higher resolution is used.
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 512,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(3u, streams.size());
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 508,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 960, 512, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 3u);
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 960, 508, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 2u);
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 480, 270, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 2u);
|
||||
// Lowest cropped height where max layers from higher resolution is used.
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 256,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 254,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(1u, streams.size());
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 480, 256, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 2u);
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 480, 254, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 1u);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, MaxLayersWithRoundUpRatio) {
|
||||
@ -442,20 +288,16 @@ TEST(SimulcastTest, MaxLayersWithRoundUpRatio) {
|
||||
const size_t kMinLayers = 1;
|
||||
const int kMaxLayers = 3;
|
||||
|
||||
std::vector<VideoStream> streams;
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
size_t num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 480, 270, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 2u);
|
||||
// Lowest cropped height where max layers from higher resolution is used.
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 252,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(2u, streams.size());
|
||||
streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 250,
|
||||
!kScreenshare, true, trials,
|
||||
webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(1u, streams.size());
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 480, 252, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 2u);
|
||||
num_layers = cricket::LimitSimulcastLayerCount(
|
||||
kMinLayers, kMaxLayers, 480, 250, trials, webrtc::kVideoCodecVP8);
|
||||
EXPECT_EQ(num_layers, 1u);
|
||||
}
|
||||
|
||||
TEST(SimulcastTest, BitratesInterpolatedForResBelow180p) {
|
||||
@ -465,10 +307,10 @@ TEST(SimulcastTest, BitratesInterpolatedForResBelow180p) {
|
||||
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
/* min_layers = */ 1, kMaxLayers, /* width = */ 960, /* height = */ 540,
|
||||
CreateResolutions(/*max_width=*/960, /*max_height=*/540, kMaxLayers),
|
||||
!kScreenshare, true, trials, webrtc::kVideoCodecVP8);
|
||||
|
||||
ASSERT_EQ(streams.size(), kMaxLayers);
|
||||
ASSERT_THAT(streams, SizeIs(kMaxLayers));
|
||||
EXPECT_EQ(240u, streams[0].width);
|
||||
EXPECT_EQ(135u, streams[0].height);
|
||||
EXPECT_EQ(streams[0].max_bitrate_bps, 112500);
|
||||
@ -482,10 +324,10 @@ TEST(SimulcastTest, BitratesConsistentForVerySmallRes) {
|
||||
"WebRTC-LowresSimulcastBitrateInterpolation/Enabled/");
|
||||
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
/* min_layers = */ 1, /* max_layers = */ 3, /* width = */ 1,
|
||||
/* height = */ 1, !kScreenshare, true, trials, webrtc::kVideoCodecVP8);
|
||||
std::vector<Resolution>{{.width = 1, .height = 1}}, !kScreenshare, true,
|
||||
trials, webrtc::kVideoCodecVP8);
|
||||
|
||||
ASSERT_TRUE(!streams.empty());
|
||||
ASSERT_THAT(streams, SizeIs(1));
|
||||
EXPECT_EQ(1u, streams[0].width);
|
||||
EXPECT_EQ(1u, streams[0].height);
|
||||
EXPECT_EQ(streams[0].max_bitrate_bps, 30000);
|
||||
@ -500,10 +342,10 @@ TEST(SimulcastTest,
|
||||
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
/* min_layers = */ 1, kMaxLayers, /* width = */ 960, /* height = */ 540,
|
||||
CreateResolutions(/*max_width=*/960, /*max_height=*/540, kMaxLayers),
|
||||
!kScreenshare, true, trials, webrtc::kVideoCodecVP8);
|
||||
|
||||
ASSERT_EQ(streams.size(), kMaxLayers);
|
||||
ASSERT_THAT(streams, SizeIs(kMaxLayers));
|
||||
EXPECT_EQ(240u, streams[0].width);
|
||||
EXPECT_EQ(135u, streams[0].height);
|
||||
EXPECT_EQ(streams[0].max_bitrate_bps, 200000);
|
||||
@ -516,15 +358,15 @@ TEST(SimulcastTest, BitratesBasedOnCodec) {
|
||||
|
||||
const size_t kMaxLayers = 3;
|
||||
std::vector<VideoStream> streams_vp8 = cricket::GetSimulcastConfig(
|
||||
/* min_layers = */ 1, /* max_layers = */ 3, /* width = */ 1280,
|
||||
/* height = */ 720, !kScreenshare, true, trials, webrtc::kVideoCodecVP8);
|
||||
CreateResolutions(/*max_width=*/1280, /*max_height=*/720, kMaxLayers),
|
||||
!kScreenshare, true, trials, webrtc::kVideoCodecVP8);
|
||||
|
||||
std::vector<VideoStream> streams_vp9 = cricket::GetSimulcastConfig(
|
||||
/* min_layers = */ 1, /* max_layers = */ 3, /* width = */ 1280,
|
||||
/* height = */ 720, !kScreenshare, true, trials, webrtc::kVideoCodecVP9);
|
||||
CreateResolutions(/*max_width=*/1280, /*max_height=*/720, kMaxLayers),
|
||||
!kScreenshare, true, trials, webrtc::kVideoCodecVP9);
|
||||
|
||||
ASSERT_EQ(streams_vp8.size(), kMaxLayers);
|
||||
ASSERT_EQ(streams_vp9.size(), kMaxLayers);
|
||||
ASSERT_THAT(streams_vp8, SizeIs(kMaxLayers));
|
||||
ASSERT_THAT(streams_vp9, SizeIs(kMaxLayers));
|
||||
|
||||
EXPECT_EQ(streams_vp9[0].width, streams_vp8[0].width);
|
||||
EXPECT_EQ(streams_vp9[0].height, streams_vp8[0].height);
|
||||
@ -548,12 +390,11 @@ TEST(SimulcastTest, BitratesForVP9) {
|
||||
ExplicitKeyValueConfig trials("");
|
||||
|
||||
const size_t kMaxLayers = 3;
|
||||
|
||||
std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
|
||||
/* min_layers = */ 1, kMaxLayers, /* width = */ 1280, /* height = */ 720,
|
||||
CreateResolutions(/*max_width=*/1280, /*max_height=*/720, kMaxLayers),
|
||||
!kScreenshare, true, trials, webrtc::kVideoCodecVP9);
|
||||
|
||||
ASSERT_EQ(streams.size(), kMaxLayers);
|
||||
ASSERT_THAT(streams, SizeIs(kMaxLayers));
|
||||
EXPECT_EQ(1280u, streams[2].width);
|
||||
EXPECT_EQ(720u, streams[2].height);
|
||||
EXPECT_EQ(streams[2].max_bitrate_bps, 1524000);
|
||||
@ -561,10 +402,10 @@ TEST(SimulcastTest, BitratesForVP9) {
|
||||
EXPECT_EQ(streams[2].min_bitrate_bps, 481000);
|
||||
|
||||
streams = cricket::GetSimulcastConfig(
|
||||
/* min_layers = */ 1, kMaxLayers, /* width = */ 1276, /* height = */ 716,
|
||||
CreateResolutions(/*max_width=*/1276, /*max_height=*/716, kMaxLayers),
|
||||
!kScreenshare, true, trials, webrtc::kVideoCodecVP9);
|
||||
|
||||
ASSERT_EQ(streams.size(), kMaxLayers);
|
||||
ASSERT_THAT(streams, SizeIs(kMaxLayers));
|
||||
EXPECT_EQ(1276u, streams[2].width);
|
||||
EXPECT_EQ(716u, streams[2].height);
|
||||
EXPECT_NEAR(streams[2].max_bitrate_bps, 1524000, 20000);
|
||||
|
||||
@ -2666,9 +2666,11 @@ TEST_P(ResolutionAlignmentTest, SinkWantsAlignmentApplied) {
|
||||
config.video_stream_factory = nullptr;
|
||||
video_stream_encoder_->ConfigureEncoder(std::move(config), kMaxPayloadLength);
|
||||
|
||||
// We can get up to 3 streams of 1280x720 resolution each in this test. Make
|
||||
// available bitrate large enough to get all streams encoded.
|
||||
const DataRate kAvailableBitrate = 3 * kSimulcastTargetBitrate;
|
||||
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||
kSimulcastTargetBitrate, kSimulcastTargetBitrate, kSimulcastTargetBitrate,
|
||||
0, 0, 0);
|
||||
kAvailableBitrate, kAvailableBitrate, kAvailableBitrate, 0, 0, 0);
|
||||
// Wait for all layers before triggering event.
|
||||
sink_.SetNumExpectedLayers(num_streams);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user