From 31cb8f9a50f6d9930dffcf61548408683a10966f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85sa=20Persson?= Date: Wed, 27 Jun 2018 10:44:56 +0200 Subject: [PATCH] Add unit tests for simulcast layer configurations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: webrtc:9341 Change-Id: I82b164bd1faca2042be6176463c930b693d951eb Reviewed-on: https://webrtc-review.googlesource.com/83321 Reviewed-by: Magnus Jedvert Reviewed-by: Rasmus Brandt Commit-Queue: Åsa Persson Cr-Commit-Position: refs/heads/master@{#23922} --- media/BUILD.gn | 1 + media/engine/simulcast.h | 4 - media/engine/simulcast_unittest.cc | 189 +++++++++++++++++++++ media/engine/webrtcvideoengine_unittest.cc | 30 ++-- 4 files changed, 201 insertions(+), 23 deletions(-) create mode 100644 media/engine/simulcast_unittest.cc diff --git a/media/BUILD.gn b/media/BUILD.gn index 91d1441d51..af72a83941 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -518,6 +518,7 @@ if (rtc_include_tests) { "engine/nullwebrtcvideoengine_unittest.cc", "engine/payload_type_mapper_unittest.cc", "engine/simulcast_encoder_adapter_unittest.cc", + "engine/simulcast_unittest.cc", "engine/vp8_encoder_simulcast_proxy_unittest.cc", "engine/webrtcmediaengine_unittest.cc", "engine/webrtcvideocapturer_unittest.cc", diff --git a/media/engine/simulcast.h b/media/engine/simulcast.h index 4b160e7539..7a396a45fa 100644 --- a/media/engine/simulcast.h +++ b/media/engine/simulcast.h @@ -11,16 +11,12 @@ #ifndef MEDIA_ENGINE_SIMULCAST_H_ #define MEDIA_ENGINE_SIMULCAST_H_ -#include #include #include "api/video_codecs/video_encoder_config.h" namespace cricket { -// TODO(pthatcher): Write unit tests just for these functions, -// independent of WebrtcVideoEngine. - // Gets the total maximum bitrate for the |streams|. int GetTotalMaxBitrateBps(const std::vector& streams); diff --git a/media/engine/simulcast_unittest.cc b/media/engine/simulcast_unittest.cc new file mode 100644 index 0000000000..f36ac035e0 --- /dev/null +++ b/media/engine/simulcast_unittest.cc @@ -0,0 +1,189 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "media/engine/simulcast.h" + +#include "media/engine/constants.h" +#include "test/field_trial.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { +constexpr int kQpMax = 55; +constexpr double kBitratePriority = 2.0; +constexpr int kMaxFps = 33; +constexpr int kMaxBitrateBps = 0; +constexpr bool kScreenshare = true; +constexpr int kDefaultTemporalLayers = 3; // Value from simulcast.cc. + +// Values from kSimulcastConfigs in simulcast.cc. +const std::vector GetSimulcastBitrates720p() { + std::vector streams(3); + streams[0].min_bitrate_bps = 30000; + streams[0].target_bitrate_bps = 150000; + streams[0].max_bitrate_bps = 200000; + streams[1].min_bitrate_bps = 150000; + streams[1].target_bitrate_bps = 500000; + streams[1].max_bitrate_bps = 700000; + streams[2].min_bitrate_bps = 600000; + streams[2].target_bitrate_bps = 2500000; + streams[2].max_bitrate_bps = 2500000; + return streams; +} +} // namespace + +TEST(SimulcastTest, TotalMaxBitrateIsZeroForNoStreams) { + std::vector streams; + EXPECT_EQ(0, cricket::GetTotalMaxBitrateBps(streams)); +} + +TEST(SimulcastTest, GetTotalMaxBitrateForSingleStream) { + std::vector streams(1); + streams[0].max_bitrate_bps = 100000; + EXPECT_EQ(100000, cricket::GetTotalMaxBitrateBps(streams)); +} + +TEST(SimulcastTest, GetTotalMaxBitrateForMultipleStreams) { + std::vector streams(3); + streams[0].target_bitrate_bps = 100000; + streams[1].target_bitrate_bps = 200000; + streams[2].max_bitrate_bps = 400000; + EXPECT_EQ(700000, cricket::GetTotalMaxBitrateBps(streams)); +} + +TEST(SimulcastTest, BandwidthAboveTotalMaxBitrateGivenToHighestStream) { + std::vector streams(3); + streams[0].target_bitrate_bps = 100000; + streams[1].target_bitrate_bps = 200000; + streams[2].max_bitrate_bps = 400000; + + // No bitrate above the total max to give to the highest stream. + const int kMaxTotalBps = cricket::GetTotalMaxBitrateBps(streams); + cricket::BoostMaxSimulcastLayer(kMaxTotalBps, &streams); + EXPECT_EQ(400000, streams[2].max_bitrate_bps); + EXPECT_EQ(kMaxTotalBps, cricket::GetTotalMaxBitrateBps(streams)); + + // The bitrate above the total max should be given to the highest stream. + cricket::BoostMaxSimulcastLayer(kMaxTotalBps + 1, &streams); + EXPECT_EQ(400000 + 1, streams[2].max_bitrate_bps); + EXPECT_EQ(kMaxTotalBps + 1, cricket::GetTotalMaxBitrateBps(streams)); +} + +TEST(SimulcastTest, GetConfig) { + const std::vector kExpected = GetSimulcastBitrates720p(); + + const size_t kMaxLayers = 3; + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, 1280, 720, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, + !kScreenshare); + + 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); + EXPECT_EQ(1280u, streams[2].width); + EXPECT_EQ(720u, streams[2].height); + + for (size_t i = 0; i < streams.size(); ++i) { + EXPECT_EQ(kDefaultTemporalLayers, streams[i].num_temporal_layers); + EXPECT_EQ(kMaxFps, streams[i].max_framerate); + EXPECT_EQ(kQpMax, streams[i].max_qp); + EXPECT_EQ(kExpected[i].min_bitrate_bps, streams[i].min_bitrate_bps); + EXPECT_EQ(kExpected[i].target_bitrate_bps, streams[i].target_bitrate_bps); + EXPECT_EQ(kExpected[i].max_bitrate_bps, streams[i].max_bitrate_bps); + EXPECT_TRUE(streams[i].active); + } + // Currently set on lowest stream. + EXPECT_EQ(kBitratePriority, streams[0].bitrate_priority); + EXPECT_FALSE(streams[1].bitrate_priority); + EXPECT_FALSE(streams[2].bitrate_priority); +} + +TEST(SimulcastTest, GetConfigWithLimitedMaxLayers) { + const size_t kMaxLayers = 2; + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, 1280, 720, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, + !kScreenshare); + + 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, GetConfigWithNormalizedResolution) { + const size_t kMaxLayers = 2; + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, 640 + 1, 360 + 1, kMaxBitrateBps, kBitratePriority, kQpMax, + kMaxFps, !kScreenshare); + + // Must be dividable 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, GetConfigForScreenshare) { + const size_t kMaxLayers = 3; + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, 1400, 800, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, + kScreenshare); + + EXPECT_EQ(1u, streams.size()) << "No simulcast."; + EXPECT_EQ(1400u, streams[0].width); + EXPECT_EQ(800u, streams[0].height); + EXPECT_EQ(kQpMax, streams[0].max_qp); + EXPECT_EQ(kBitratePriority, streams[0].bitrate_priority); + EXPECT_TRUE(streams[0].active); + EXPECT_GT(streams[0].num_temporal_layers, 1); + EXPECT_GT(streams[0].max_framerate, 0); + EXPECT_EQ(cricket::kMinVideoBitrateBps, streams[0].min_bitrate_bps); + EXPECT_GT(streams[0].target_bitrate_bps, streams[0].min_bitrate_bps); + EXPECT_GT(streams[0].max_bitrate_bps, streams[0].target_bitrate_bps); +} + +TEST(SimulcastTest, GetConfigForScreenshareSimulcast) { + test::ScopedFieldTrials field_trials("WebRTC-SimulcastScreenshare/Enabled/"); + + const size_t kMaxLayers = 3; + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, 1400, 800, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, + kScreenshare); + + EXPECT_GT(streams.size(), 1u); + 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."; + EXPECT_EQ(kQpMax, streams[i].max_qp); + EXPECT_TRUE(streams[i].active); + EXPECT_GT(streams[i].num_temporal_layers, 1); + EXPECT_GT(streams[i].max_framerate, 0); + EXPECT_GT(streams[i].min_bitrate_bps, 0); + EXPECT_GT(streams[i].target_bitrate_bps, streams[i].min_bitrate_bps); + EXPECT_GE(streams[i].max_bitrate_bps, streams[i].target_bitrate_bps); + } +} + +TEST(SimulcastTest, GetConfigForScreenshareSimulcastWithLimitedMaxLayers) { + test::ScopedFieldTrials field_trials("WebRTC-SimulcastScreenshare/Enabled/"); + + const size_t kMaxLayers = 1; + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, 1400, 800, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, + kScreenshare); + + EXPECT_EQ(kMaxLayers, streams.size()); +} + +} // namespace webrtc diff --git a/media/engine/webrtcvideoengine_unittest.cc b/media/engine/webrtcvideoengine_unittest.cc index 7e80e27095..9314ba5518 100644 --- a/media/engine/webrtcvideoengine_unittest.cc +++ b/media/engine/webrtcvideoengine_unittest.cc @@ -5344,7 +5344,7 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersPriorityOneStream) { // streams. TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersPrioritySimulcastStreams) { // Create the stream params with multiple ssrcs for simulcast. - const int kNumSimulcastStreams = 3; + const size_t kNumSimulcastStreams = 3; std::vector ssrcs = MAKE_VECTOR(kSsrcs3); StreamParams stream_params = CreateSimStreamParams("cname", ssrcs); AddSendStream(stream_params); @@ -5365,8 +5365,7 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersPrioritySimulcastStreams) { // Get and set the rtp encoding parameters. webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(primary_ssrc); - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), - parameters.encodings.size()); + EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size()); EXPECT_EQ(webrtc::kDefaultBitratePriority, parameters.encodings[0].bitrate_priority); // Change the value and set it on the VideoChannel. @@ -5376,8 +5375,7 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersPrioritySimulcastStreams) { // Verify that the encoding parameters priority is set on the VideoChannel. parameters = channel_->GetRtpSendParameters(primary_ssrc); - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), - parameters.encodings.size()); + EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size()); EXPECT_EQ(new_bitrate_priority, parameters.encodings[0].bitrate_priority); // Verify that the new value propagated down to the encoder. @@ -5387,15 +5385,14 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersPrioritySimulcastStreams) { FakeVideoSendStream* video_send_stream = video_send_streams.front(); // Check that the WebRtcVideoSendStream updated the VideoEncoderConfig // appropriately. - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), + EXPECT_EQ(kNumSimulcastStreams, video_send_stream->GetEncoderConfig().number_of_streams); EXPECT_EQ(new_bitrate_priority, video_send_stream->GetEncoderConfig().bitrate_priority); // Check that the vector of VideoStreams also propagated correctly. The // FakeVideoSendStream calls CreateEncoderStreams, and we are testing that // these are created appropriately for the simulcast case. - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), - video_send_stream->GetVideoStreams().size()); + EXPECT_EQ(kNumSimulcastStreams, video_send_stream->GetVideoStreams().size()); EXPECT_EQ(absl::optional(new_bitrate_priority), video_send_stream->GetVideoStreams()[0].bitrate_priority); // Since we are only setting bitrate priority per-sender, the other @@ -5807,7 +5804,7 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersOneEncodingActive) { // new appropriate active simulcast streams. TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersMultipleEncodingsActive) { // Create the stream params with multiple ssrcs for simulcast. - const int kNumSimulcastStreams = 3; + const size_t kNumSimulcastStreams = 3; std::vector ssrcs = MAKE_VECTOR(kSsrcs3); StreamParams stream_params = CreateSimStreamParams("cname", ssrcs); FakeVideoSendStream* fake_video_send_stream = AddSendStream(stream_params); @@ -5829,8 +5826,7 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersMultipleEncodingsActive) { // Check that all encodings are initially active. webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(primary_ssrc); - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), - parameters.encodings.size()); + EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size()); EXPECT_TRUE(parameters.encodings[0].active); EXPECT_TRUE(parameters.encodings[1].active); EXPECT_TRUE(parameters.encodings[2].active); @@ -5843,8 +5839,7 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersMultipleEncodingsActive) { EXPECT_TRUE(channel_->SetRtpSendParameters(primary_ssrc, parameters).ok()); // Verify that the active fields are set on the VideoChannel. parameters = channel_->GetRtpSendParameters(primary_ssrc); - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), - parameters.encodings.size()); + EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size()); EXPECT_FALSE(parameters.encodings[0].active); EXPECT_TRUE(parameters.encodings[1].active); EXPECT_FALSE(parameters.encodings[2].active); @@ -5853,8 +5848,7 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersMultipleEncodingsActive) { EXPECT_TRUE(fake_video_send_stream->IsSending()); std::vector simulcast_streams = fake_video_send_stream->GetVideoStreams(); - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), - simulcast_streams.size()); + EXPECT_EQ(kNumSimulcastStreams, simulcast_streams.size()); EXPECT_FALSE(simulcast_streams[0].active); EXPECT_TRUE(simulcast_streams[1].active); EXPECT_FALSE(simulcast_streams[2].active); @@ -5866,16 +5860,14 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersMultipleEncodingsActive) { EXPECT_TRUE(channel_->SetRtpSendParameters(primary_ssrc, parameters).ok()); // Verify that the active fields are set on the VideoChannel. parameters = channel_->GetRtpSendParameters(primary_ssrc); - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), - parameters.encodings.size()); + EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size()); EXPECT_FALSE(parameters.encodings[0].active); EXPECT_FALSE(parameters.encodings[1].active); EXPECT_FALSE(parameters.encodings[2].active); // Check that the VideoSendStream is off. EXPECT_FALSE(fake_video_send_stream->IsSending()); simulcast_streams = fake_video_send_stream->GetVideoStreams(); - EXPECT_EQ(rtc::checked_cast(kNumSimulcastStreams), - simulcast_streams.size()); + EXPECT_EQ(kNumSimulcastStreams, simulcast_streams.size()); EXPECT_FALSE(simulcast_streams[0].active); EXPECT_FALSE(simulcast_streams[1].active); EXPECT_FALSE(simulcast_streams[2].active);