From 2899b3bc3da018822ff34196b706d69c808fdb93 Mon Sep 17 00:00:00 2001 From: Ilya Nikolaevskiy Date: Thu, 11 Jun 2020 14:01:56 +0200 Subject: [PATCH] Allow HVGA Vp9 SVC to have 2 spatial layers and remove excessive rounding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: webrtc:11652 Change-Id: I8bfa91c3115d6ebb17beefbb2a5e51efbbd599e0 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/177000 Commit-Queue: Ilya Nikolaevskiy Reviewed-by: Erik Språng Cr-Commit-Position: refs/heads/master@{#31502} --- modules/video_coding/BUILD.gn | 1 + .../codecs/vp9/include/vp9_globals.h | 4 +-- modules/video_coding/codecs/vp9/svc_config.cc | 14 +++++++--- .../codecs/vp9/svc_config_unittest.cc | 26 +++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index 296ab8b6d0..faff336202 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -536,6 +536,7 @@ rtc_library("webrtc_vp9_helpers") { "../../api/video_codecs:video_codecs_api", "../../common_video", "../../rtc_base:checks", + "../../rtc_base:logging", "../../rtc_base/experiments:stable_target_rate_experiment", ] absl_deps = [ "//third_party/abseil-cpp/absl/container:inlined_vector" ] diff --git a/modules/video_coding/codecs/vp9/include/vp9_globals.h b/modules/video_coding/codecs/vp9/include/vp9_globals.h index c6853127ac..6f9d09933f 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 = 320; -const size_t kMinVp9SpatialLayerHeight = 180; +const size_t kMinVp9SpatialLayerWidth = 240; +const size_t kMinVp9SpatialLayerHeight = 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 b73661c48a..118d8a77c1 100644 --- a/modules/video_coding/codecs/vp9/svc_config.cc +++ b/modules/video_coding/codecs/vp9/svc_config.cc @@ -16,6 +16,7 @@ #include "modules/video_coding/codecs/vp9/include/vp9_globals.h" #include "rtc_base/checks.h" +#include "rtc_base/logging.h" namespace webrtc { @@ -74,13 +75,20 @@ std::vector ConfigureSvcNormalVideo(size_t input_width, const size_t num_layers_fit_vert = static_cast( std::floor(1 + std::max(0.0f, std::log2(1.0f * input_height / kMinVp9SpatialLayerHeight)))); - num_spatial_layers = - std::min({num_spatial_layers, num_layers_fit_horz, num_layers_fit_vert}); + 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) { + RTC_LOG(LS_WARNING) << "Reducing number of spatial layers from " + << num_spatial_layers << " to " + << limited_num_spatial_layers + << " due to low input resolution."; + num_spatial_layers = limited_num_spatial_layers; + } // First active layer must be configured. num_spatial_layers = std::max(num_spatial_layers, first_active_layer + 1); // Ensure top layer is even enough. - int required_divisiblity = 1 << num_spatial_layers; + int required_divisiblity = 1 << (num_spatial_layers - first_active_layer - 1); input_width = input_width - input_width % required_divisiblity; input_height = input_height - input_height % required_divisiblity; diff --git a/modules/video_coding/codecs/vp9/svc_config_unittest.cc b/modules/video_coding/codecs/vp9/svc_config_unittest.cc index abc67a22ff..1891628921 100644 --- a/modules/video_coding/codecs/vp9/svc_config_unittest.cc +++ b/modules/video_coding/codecs/vp9/svc_config_unittest.cc @@ -41,6 +41,32 @@ TEST(SvcConfig, AlwaysSendsAtLeastOneLayer) { EXPECT_EQ(spatial_layers.back().width, kMinVp9SpatialLayerWidth); } +TEST(SvcConfig, EnforcesMinimalRequiredParity) { + const size_t max_num_spatial_layers = 3; + const size_t kOddSize = 1023; + + std::vector spatial_layers = + GetSvcConfig(kOddSize, kOddSize, 30, + /*first_active_layer=*/1, max_num_spatial_layers, 1, false); + // Since there are 2 layers total (1, 2), divisiblity by 2 is required. + EXPECT_EQ(spatial_layers.back().width, kOddSize - 1); + EXPECT_EQ(spatial_layers.back().width, kOddSize - 1); + + spatial_layers = + GetSvcConfig(kOddSize, kOddSize, 30, + /*first_active_layer=*/0, max_num_spatial_layers, 1, false); + // Since there are 3 layers total (0, 1, 2), divisiblity by 4 is required. + EXPECT_EQ(spatial_layers.back().width, kOddSize - 3); + EXPECT_EQ(spatial_layers.back().width, kOddSize - 3); + + spatial_layers = + GetSvcConfig(kOddSize, kOddSize, 30, + /*first_active_layer=*/2, max_num_spatial_layers, 1, false); + // Since there is only 1 layer active (2), divisiblity by 1 is required. + EXPECT_EQ(spatial_layers.back().width, kOddSize); + EXPECT_EQ(spatial_layers.back().width, kOddSize); +} + TEST(SvcConfig, SkipsInactiveLayers) { const size_t num_spatial_layers = 4; const size_t first_active_layer = 2;