Ensure that the first active layer isn't disabled by too low input resolution
If e.g. CPU adaptation reduces input video size too much, video pipeline would
reduce the number of used simulcast streams/spatial layers. This may result in
disabled video if some streams are disabled by Rtp encoding parameters API.
Bug: webrtc:11319
Change-Id: Id7f157255599dcb6f494129b83477cda4bea982a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168480
Reviewed-by: Evan Shrubsole <eshr@google.com>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30498}
diff --git a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
index 0eb256e..fe42039 100644
--- a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
+++ b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
@@ -62,8 +62,8 @@
void ConfigureSimulcast(VideoCodec* codec_settings) {
const std::vector<webrtc::VideoStream> streams = cricket::GetSimulcastConfig(
- codec_settings->numberOfSimulcastStreams, codec_settings->width,
- codec_settings->height, kBitratePriority, kMaxQp,
+ /*min_layer=*/1, codec_settings->numberOfSimulcastStreams,
+ codec_settings->width, codec_settings->height, kBitratePriority, kMaxQp,
/* is_screenshare = */ false, true);
for (size_t i = 0; i < streams.size(); ++i) {
@@ -85,7 +85,7 @@
const std::vector<SpatialLayer> layers = GetSvcConfig(
codec_settings->width, codec_settings->height, kMaxFramerateFps,
- codec_settings->VP9()->numberOfSpatialLayers,
+ /*min_spatial_layers=*/1, codec_settings->VP9()->numberOfSpatialLayers,
codec_settings->VP9()->numberOfTemporalLayers,
/* is_screen_sharing = */ false);
ASSERT_EQ(codec_settings->VP9()->numberOfSpatialLayers, layers.size())
diff --git a/modules/video_coding/codecs/vp9/svc_config.cc b/modules/video_coding/codecs/vp9/svc_config.cc
index a3bf56d..764c1a2 100644
--- a/modules/video_coding/codecs/vp9/svc_config.cc
+++ b/modules/video_coding/codecs/vp9/svc_config.cc
@@ -61,8 +61,10 @@
std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
size_t input_height,
float max_framerate_fps,
+ size_t min_spatial_layers,
size_t num_spatial_layers,
size_t num_temporal_layers) {
+ RTC_DCHECK_LE(min_spatial_layers, num_spatial_layers);
std::vector<SpatialLayer> spatial_layers;
// Limit number of layers for given resolution.
@@ -74,6 +76,7 @@
kMinVp9SpatialLayerHeight))));
num_spatial_layers =
std::min({num_spatial_layers, num_layers_fit_horz, num_layers_fit_vert});
+ num_spatial_layers = std::max(num_spatial_layers, min_spatial_layers);
for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
SpatialLayer spatial_layer = {0};
@@ -109,6 +112,7 @@
std::vector<SpatialLayer> GetSvcConfig(size_t input_width,
size_t input_height,
float max_framerate_fps,
+ size_t min_spatial_layers,
size_t num_spatial_layers,
size_t num_temporal_layers,
bool is_screen_sharing) {
@@ -122,7 +126,8 @@
max_framerate_fps, num_spatial_layers);
} else {
return ConfigureSvcNormalVideo(input_width, input_height, max_framerate_fps,
- num_spatial_layers, num_temporal_layers);
+ min_spatial_layers, num_spatial_layers,
+ num_temporal_layers);
}
}
diff --git a/modules/video_coding/codecs/vp9/svc_config.h b/modules/video_coding/codecs/vp9/svc_config.h
index 6e9ae9b..3bc9ba7 100644
--- a/modules/video_coding/codecs/vp9/svc_config.h
+++ b/modules/video_coding/codecs/vp9/svc_config.h
@@ -21,6 +21,7 @@
std::vector<SpatialLayer> GetSvcConfig(size_t input_width,
size_t input_height,
float max_framerate_fps,
+ size_t min_spatial_layers,
size_t num_spatial_layers,
size_t num_temporal_layers,
bool is_screen_sharing);
diff --git a/modules/video_coding/codecs/vp9/svc_config_unittest.cc b/modules/video_coding/codecs/vp9/svc_config_unittest.cc
index bda6a55..07a2ebe 100644
--- a/modules/video_coding/codecs/vp9/svc_config_unittest.cc
+++ b/modules/video_coding/codecs/vp9/svc_config_unittest.cc
@@ -19,22 +19,35 @@
namespace webrtc {
TEST(SvcConfig, NumSpatialLayers) {
const size_t max_num_spatial_layers = 6;
+ const size_t min_spatial_layers = 1;
const size_t num_spatial_layers = 2;
std::vector<SpatialLayer> spatial_layers =
GetSvcConfig(kMinVp9SpatialLayerWidth << (num_spatial_layers - 1),
kMinVp9SpatialLayerHeight << (num_spatial_layers - 1), 30,
- max_num_spatial_layers, 1, false);
+ min_spatial_layers, max_num_spatial_layers, 1, false);
EXPECT_EQ(spatial_layers.size(), num_spatial_layers);
}
+TEST(SvcConfig, NumSpatialLayersRespectsMinNumberOfLayers) {
+ const size_t max_num_spatial_layers = 6;
+ const size_t min_spatial_layers = 2;
+
+ std::vector<SpatialLayer> spatial_layers =
+ GetSvcConfig(kMinVp9SpatialLayerWidth, kMinVp9SpatialLayerHeight, 30,
+ min_spatial_layers, max_num_spatial_layers, 1, false);
+
+ EXPECT_EQ(spatial_layers.size(), 2u);
+}
+
TEST(SvcConfig, BitrateThresholds) {
+ const size_t min_spatial_layers = 1;
const size_t num_spatial_layers = 3;
std::vector<SpatialLayer> spatial_layers =
GetSvcConfig(kMinVp9SpatialLayerWidth << (num_spatial_layers - 1),
kMinVp9SpatialLayerHeight << (num_spatial_layers - 1), 30,
- num_spatial_layers, 1, false);
+ min_spatial_layers, num_spatial_layers, 1, false);
EXPECT_EQ(spatial_layers.size(), num_spatial_layers);
@@ -47,7 +60,7 @@
TEST(SvcConfig, ScreenSharing) {
std::vector<SpatialLayer> spatial_layers =
- GetSvcConfig(1920, 1080, 30, 3, 3, true);
+ GetSvcConfig(1920, 1080, 30, 1, 3, 3, true);
EXPECT_EQ(spatial_layers.size(), 3UL);
diff --git a/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc b/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc
index 6a677a2..9635eae 100644
--- a/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc
+++ b/modules/video_coding/codecs/vp9/svc_rate_allocator_unittest.cc
@@ -34,8 +34,8 @@
: VideoCodecMode::kRealtimeVideo;
std::vector<SpatialLayer> spatial_layers =
- GetSvcConfig(width, height, 30, num_spatial_layers, num_temporal_layers,
- is_screen_sharing);
+ GetSvcConfig(width, height, 30, /*min_spatial_layers=*/1,
+ num_spatial_layers, num_temporal_layers, is_screen_sharing);
RTC_CHECK_LE(spatial_layers.size(), kMaxSpatialLayers);
codec.VP9()->numberOfSpatialLayers =
diff --git a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
index ed15ee0..1a237ca 100644
--- a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
+++ b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
@@ -114,8 +114,8 @@
std::vector<SpatialLayer> layers =
GetSvcConfig(codec_settings_.width, codec_settings_.height,
- codec_settings_.maxFramerate, num_spatial_layers,
- num_temporal_layers, false);
+ codec_settings_.maxFramerate, /*min_spatial_layers=*/1,
+ num_spatial_layers, num_temporal_layers, false);
for (size_t i = 0; i < layers.size(); ++i) {
codec_settings_.spatialLayers[i] = layers[i];
}
diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc
index 46d055f..bd40385 100644
--- a/modules/video_coding/video_codec_initializer.cc
+++ b/modules/video_coding/video_codec_initializer.cc
@@ -179,9 +179,19 @@
// Layering is set explicitly.
spatial_layers = config.spatial_layers;
} else {
+ size_t min_required_layers = 0;
+ // Need at least enough layers for the first active one to be present.
+ for (size_t spatial_idx = 0;
+ spatial_idx < config.simulcast_layers.size(); ++spatial_idx) {
+ if (config.simulcast_layers[spatial_idx].active) {
+ min_required_layers = spatial_idx + 1;
+ break;
+ }
+ }
+
spatial_layers = GetSvcConfig(
video_codec.width, video_codec.height, video_codec.maxFramerate,
- video_codec.VP9()->numberOfSpatialLayers,
+ min_required_layers, video_codec.VP9()->numberOfSpatialLayers,
video_codec.VP9()->numberOfTemporalLayers,
video_codec.mode == VideoCodecMode::kScreensharing);