diff --git a/media/engine/simulcast.cc b/media/engine/simulcast.cc index b7db9bc2c1..656645c0be 100644 --- a/media/engine/simulcast.cc +++ b/media/engine/simulcast.cc @@ -74,7 +74,7 @@ struct SimulcastFormat { const SimulcastFormat kSimulcastFormats[] = { {1920, 1080, 3, 5000, 4000, 800}, {1280, 720, 3, 2500, 2500, 600}, - {960, 540, 3, 900, 900, 450}, + {960, 540, 3, 1200, 1200, 350}, {640, 360, 2, 700, 500, 150}, {480, 270, 2, 450, 350, 150}, {320, 180, 1, 200, 150, 30}, @@ -143,19 +143,46 @@ int NormalizeSimulcastSize(int size, size_t simulcast_layers) { return ((size >> base2_exponent) << base2_exponent); } +SimulcastFormat InterpolateSimulcastFormat(int width, int height) { + const int index = FindSimulcastFormatIndex(width, height); + if (index == 0) + return kSimulcastFormats[index]; + const int total_pixels_up = + kSimulcastFormats[index - 1].width * kSimulcastFormats[index - 1].height; + const int total_pixels_down = + kSimulcastFormats[index].width * kSimulcastFormats[index].height; + const int total_pixels = width * height; + const float rate = (total_pixels_up - total_pixels) / + static_cast(total_pixels_up - total_pixels_down); + SimulcastFormat res; + res.width = width; + res.height = height; + res.max_layers = kSimulcastFormats[index].max_layers; + res.max_bitrate_kbps = + kSimulcastFormats[index - 1].max_bitrate_kbps * (1.0 - rate) + + kSimulcastFormats[index].max_bitrate_kbps * rate; + res.target_bitrate_kbps = + kSimulcastFormats[index - 1].target_bitrate_kbps * (1.0 - rate) + + kSimulcastFormats[index].target_bitrate_kbps * rate; + res.min_bitrate_kbps = + kSimulcastFormats[index - 1].min_bitrate_kbps * (1.0 - rate) + + kSimulcastFormats[index].min_bitrate_kbps * rate; + return res; +} + int FindSimulcastMaxBitrateBps(int width, int height) { - const int format_index = FindSimulcastFormatIndex(width, height); - return kSimulcastFormats[format_index].max_bitrate_kbps * 1000; + const SimulcastFormat format = InterpolateSimulcastFormat(width, height); + return format.max_bitrate_kbps * 1000; } int FindSimulcastTargetBitrateBps(int width, int height) { - const int format_index = FindSimulcastFormatIndex(width, height); - return kSimulcastFormats[format_index].target_bitrate_kbps * 1000; + const SimulcastFormat format = InterpolateSimulcastFormat(width, height); + return format.target_bitrate_kbps * 1000; } int FindSimulcastMinBitrateBps(int width, int height) { - const int format_index = FindSimulcastFormatIndex(width, height); - return kSimulcastFormats[format_index].min_bitrate_kbps * 1000; + const SimulcastFormat format = InterpolateSimulcastFormat(width, height); + return format.min_bitrate_kbps * 1000; } void BoostMaxSimulcastLayer(int max_bitrate_bps, diff --git a/media/engine/simulcast_unittest.cc b/media/engine/simulcast_unittest.cc index 402a556ac6..27b0913429 100644 --- a/media/engine/simulcast_unittest.cc +++ b/media/engine/simulcast_unittest.cc @@ -262,7 +262,7 @@ TEST(SimulcastTest, GetConfigForScreenshareSimulcastWithLimitedMaxLayers) { TEST(SimulcastTest, SimulcastScreenshareMaxBitrateAdjustedForResolution) { constexpr int kScreenshareHighStreamMinBitrateBps = 600000; constexpr int kScreenshareHighStreamMaxBitrateBps = 1250000; - constexpr int kMaxBitrate960_540 = 900000; + constexpr int kMaxBitrate960_540 = 1200000; // Normal case, max bitrate not limited by resolution. const size_t kMaxLayers = 2; @@ -291,4 +291,40 @@ TEST(SimulcastTest, SimulcastScreenshareMaxBitrateAdjustedForResolution) { EXPECT_GE(streams[1].max_bitrate_bps, streams[1].min_bitrate_bps); } +TEST(SimulcastTest, AveragesBitratesForNonStandardResolution) { + const size_t kMaxLayers = 3; + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, 900, 800, kBitratePriority, kQpMax, !kScreenshare); + + 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); +} + +TEST(SimulcastTest, BitratesForCloseToStandardResolution) { + const size_t kMaxLayers = 3; + // Resolution very close to 720p in number of pixels + const size_t kWidth = 1280; + const size_t kHeight = 716; + const std::vector kExpectedNear = GetSimulcastBitrates720p(); + + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, kWidth, kHeight, kBitratePriority, kQpMax, !kScreenshare); + + EXPECT_EQ(kMaxLayers, streams.size()); + EXPECT_EQ(kWidth, streams[2].width); + EXPECT_EQ(kHeight, streams[2].height); + for (size_t i = 0; i < streams.size(); ++i) { + EXPECT_NEAR(kExpectedNear[i].max_bitrate_bps, streams[i].max_bitrate_bps, + 20000); + EXPECT_NEAR(kExpectedNear[i].target_bitrate_bps, + streams[i].target_bitrate_bps, 20000); + EXPECT_NEAR(kExpectedNear[i].min_bitrate_bps, streams[i].min_bitrate_bps, + 20000); + } +} + } // namespace webrtc