From d2cd8722cda42356f9ab4f85c89ae2932748725c Mon Sep 17 00:00:00 2001 From: Konrad Hofbauer Date: Thu, 9 Dec 2021 09:43:56 +0100 Subject: [PATCH] Consider frame orientation for number of spatial layers in VP9. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses case where 540*960 would not get a 135*240 layer. Bug: webrtc:13469 Change-Id: Icc291c65114fb400cc71659d76a786e359e5996c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/239820 Reviewed-by: Sergey Silkin Reviewed-by: Erik Språng Commit-Queue: Konrad Hofbauer Cr-Commit-Position: refs/heads/main@{#35507} --- .../codecs/vp9/include/vp9_globals.h | 4 +- modules/video_coding/codecs/vp9/svc_config.cc | 13 +++-- .../codecs/vp9/svc_config_unittest.cc | 58 +++++++++++++------ .../video_codec_initializer_unittest.cc | 4 +- video/video_send_stream_tests.cc | 4 +- 5 files changed, 55 insertions(+), 28 deletions(-) diff --git a/modules/video_coding/codecs/vp9/include/vp9_globals.h b/modules/video_coding/codecs/vp9/include/vp9_globals.h index bbd83f30a9..87dafe4cdf 100644 --- a/modules/video_coding/codecs/vp9/include/vp9_globals.h +++ b/modules/video_coding/codecs/vp9/include/vp9_globals.h @@ -30,8 +30,8 @@ const size_t kMaxVp9RefPics = 3; const size_t kMaxVp9FramesInGof = 0xFF; // 8 bits const size_t kMaxVp9NumberOfSpatialLayers = 8; -const size_t kMinVp9SpatialLayerWidth = 240; -const size_t kMinVp9SpatialLayerHeight = 135; +const size_t kMinVp9SpatialLayerLongSideLength = 240; +const size_t kMinVp9SpatialLayerShortSideLength = 135; enum TemporalStructureMode { kTemporalStructureMode1, // 1 temporal layer structure - i.e., IPPP... diff --git a/modules/video_coding/codecs/vp9/svc_config.cc b/modules/video_coding/codecs/vp9/svc_config.cc index cc7743ad25..92818eb4f9 100644 --- a/modules/video_coding/codecs/vp9/svc_config.cc +++ b/modules/video_coding/codecs/vp9/svc_config.cc @@ -69,12 +69,15 @@ std::vector ConfigureSvcNormalVideo(size_t input_width, std::vector spatial_layers; // Limit number of layers for given resolution. + const bool is_landscape = input_width >= input_height; + const size_t min_width = is_landscape ? kMinVp9SpatialLayerLongSideLength + : kMinVp9SpatialLayerShortSideLength; + const size_t min_height = is_landscape ? kMinVp9SpatialLayerShortSideLength + : kMinVp9SpatialLayerLongSideLength; const size_t num_layers_fit_horz = static_cast(std::floor( - 1 + std::max(0.0f, - std::log2(1.0f * input_width / kMinVp9SpatialLayerWidth)))); - const size_t num_layers_fit_vert = static_cast( - std::floor(1 + std::max(0.0f, std::log2(1.0f * input_height / - kMinVp9SpatialLayerHeight)))); + 1 + std::max(0.0f, std::log2(1.0f * input_width / min_width)))); + const size_t num_layers_fit_vert = static_cast(std::floor( + 1 + std::max(0.0f, std::log2(1.0f * input_height / min_height)))); const size_t limited_num_spatial_layers = std::min(num_layers_fit_horz, num_layers_fit_vert); if (limited_num_spatial_layers < num_spatial_layers) { diff --git a/modules/video_coding/codecs/vp9/svc_config_unittest.cc b/modules/video_coding/codecs/vp9/svc_config_unittest.cc index 1891628921..77d75ee8bc 100644 --- a/modules/video_coding/codecs/vp9/svc_config_unittest.cc +++ b/modules/video_coding/codecs/vp9/svc_config_unittest.cc @@ -22,10 +22,23 @@ TEST(SvcConfig, NumSpatialLayers) { const size_t first_active_layer = 0; const size_t num_spatial_layers = 2; - std::vector spatial_layers = - GetSvcConfig(kMinVp9SpatialLayerWidth << (num_spatial_layers - 1), - kMinVp9SpatialLayerHeight << (num_spatial_layers - 1), 30, - first_active_layer, max_num_spatial_layers, 1, false); + std::vector spatial_layers = GetSvcConfig( + kMinVp9SpatialLayerLongSideLength << (num_spatial_layers - 1), + kMinVp9SpatialLayerShortSideLength << (num_spatial_layers - 1), 30, + first_active_layer, max_num_spatial_layers, 1, false); + + EXPECT_EQ(spatial_layers.size(), num_spatial_layers); +} + +TEST(SvcConfig, NumSpatialLayersPortrait) { + const size_t max_num_spatial_layers = 6; + const size_t first_active_layer = 0; + const size_t num_spatial_layers = 2; + + std::vector spatial_layers = GetSvcConfig( + kMinVp9SpatialLayerShortSideLength << (num_spatial_layers - 1), + kMinVp9SpatialLayerLongSideLength << (num_spatial_layers - 1), 30, + first_active_layer, max_num_spatial_layers, 1, false); EXPECT_EQ(spatial_layers.size(), num_spatial_layers); } @@ -34,11 +47,22 @@ TEST(SvcConfig, AlwaysSendsAtLeastOneLayer) { const size_t max_num_spatial_layers = 6; const size_t first_active_layer = 5; - std::vector spatial_layers = - GetSvcConfig(kMinVp9SpatialLayerWidth, kMinVp9SpatialLayerHeight, 30, - first_active_layer, max_num_spatial_layers, 1, false); + std::vector spatial_layers = GetSvcConfig( + kMinVp9SpatialLayerLongSideLength, kMinVp9SpatialLayerShortSideLength, 30, + first_active_layer, max_num_spatial_layers, 1, false); EXPECT_EQ(spatial_layers.size(), 1u); - EXPECT_EQ(spatial_layers.back().width, kMinVp9SpatialLayerWidth); + EXPECT_EQ(spatial_layers.back().width, kMinVp9SpatialLayerLongSideLength); +} + +TEST(SvcConfig, AlwaysSendsAtLeastOneLayerPortrait) { + const size_t max_num_spatial_layers = 6; + const size_t first_active_layer = 5; + + std::vector spatial_layers = GetSvcConfig( + kMinVp9SpatialLayerShortSideLength, kMinVp9SpatialLayerLongSideLength, 30, + first_active_layer, max_num_spatial_layers, 1, false); + EXPECT_EQ(spatial_layers.size(), 1u); + EXPECT_EQ(spatial_layers.back().width, kMinVp9SpatialLayerShortSideLength); } TEST(SvcConfig, EnforcesMinimalRequiredParity) { @@ -71,22 +95,22 @@ TEST(SvcConfig, SkipsInactiveLayers) { const size_t num_spatial_layers = 4; const size_t first_active_layer = 2; - std::vector spatial_layers = - GetSvcConfig(kMinVp9SpatialLayerWidth << (num_spatial_layers - 1), - kMinVp9SpatialLayerHeight << (num_spatial_layers - 1), 30, - first_active_layer, num_spatial_layers, 1, false); + std::vector spatial_layers = GetSvcConfig( + kMinVp9SpatialLayerLongSideLength << (num_spatial_layers - 1), + kMinVp9SpatialLayerShortSideLength << (num_spatial_layers - 1), 30, + first_active_layer, num_spatial_layers, 1, false); EXPECT_EQ(spatial_layers.size(), 2u); EXPECT_EQ(spatial_layers.back().width, - kMinVp9SpatialLayerWidth << (num_spatial_layers - 1)); + kMinVp9SpatialLayerLongSideLength << (num_spatial_layers - 1)); } TEST(SvcConfig, BitrateThresholds) { const size_t first_active_layer = 0; const size_t num_spatial_layers = 3; - std::vector spatial_layers = - GetSvcConfig(kMinVp9SpatialLayerWidth << (num_spatial_layers - 1), - kMinVp9SpatialLayerHeight << (num_spatial_layers - 1), 30, - first_active_layer, num_spatial_layers, 1, false); + std::vector spatial_layers = GetSvcConfig( + kMinVp9SpatialLayerLongSideLength << (num_spatial_layers - 1), + kMinVp9SpatialLayerShortSideLength << (num_spatial_layers - 1), 30, + first_active_layer, num_spatial_layers, 1, false); EXPECT_EQ(spatial_layers.size(), num_spatial_layers); diff --git a/modules/video_coding/video_codec_initializer_unittest.cc b/modules/video_coding/video_codec_initializer_unittest.cc index 6c1c2e7a38..902f991f29 100644 --- a/modules/video_coding/video_codec_initializer_unittest.cc +++ b/modules/video_coding/video_codec_initializer_unittest.cc @@ -302,8 +302,8 @@ TEST_F(VideoCodecInitializerTest, Vp9SvcAdjustedLayering) { VideoStream stream = DefaultStream(); stream.num_temporal_layers = 3; // Set resolution which is only enough to produce 2 spatial layers. - stream.width = kMinVp9SpatialLayerWidth * 2; - stream.height = kMinVp9SpatialLayerHeight * 2; + stream.width = kMinVp9SpatialLayerLongSideLength * 2; + stream.height = kMinVp9SpatialLayerShortSideLength * 2; streams_.push_back(stream); diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc index 3db0ae7147..23f9faa1fa 100644 --- a/video/video_send_stream_tests.cc +++ b/video/video_send_stream_tests.cc @@ -3316,8 +3316,8 @@ void VideoSendStreamTest::TestVp9NonFlexMode(uint8_t num_temporal_layers, // structures to verify temporal id reset on key frame. static const int kKeyFrameInterval = 31; - static const int kWidth = kMinVp9SpatialLayerWidth; - static const int kHeight = kMinVp9SpatialLayerHeight; + static const int kWidth = kMinVp9SpatialLayerLongSideLength; + static const int kHeight = kMinVp9SpatialLayerShortSideLength; static const float kGoodBitsPerPixel = 0.1f; class NonFlexibleMode : public Vp9HeaderObserver { public: