Improve tests for reconfiguring encoder from 4:2:1 to non-power of two.

More test coverage for previously fixed bug
https://crbug.com/webrtc/369654168.

Two tests are added:
1. LibvpxVp9Encoder unit test that 4:2:1 720p can be reconfigured to
   singlecast (which is what happens for encodings[0] in the bug).
2. Integration test that 4:2:1 720p can change to 180p,360p,540p.
   This is the exact same test as was added in [1] but using
   requested_resolution instead of scale_resolution_down_by.

[1] https://webrtc-review.googlesource.com/c/src/+/363941

Bug: webrtc:369654168
Change-Id: I83456b9254c1c6f647586d340d0fe5864b5515c6
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/364200
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Auto-Submit: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43185}
This commit is contained in:
Henrik Boström 2024-10-07 12:27:19 +02:00 committed by WebRTC LUCI CQ
parent 5680d8199a
commit 1accaf91b5
2 changed files with 157 additions and 3 deletions

View File

@ -490,6 +490,78 @@ TEST_F(TestVp9Impl, EncoderAcceptsSvcLikeSimulcast) {
encoder_->InitEncode(&codec_settings_, kSettings));
}
TEST_F(TestVp9Impl, SvcSimulcastThenSinglecastWithCorrectSimulcastIndex) {
const int kTargetBitrate = 1200;
const int kMaxFramerate = 30;
// Configure 720p 4:2:1
codec_settings_.VP9()->numberOfTemporalLayers = 1;
codec_settings_.VP9()->numberOfSpatialLayers = 1;
codec_settings_.numberOfSimulcastStreams = 3;
codec_settings_.width = 1280;
codec_settings_.height = 720;
codec_settings_.simulcastStream[0].width = codec_settings_.width / 4;
codec_settings_.simulcastStream[0].height = codec_settings_.height / 4;
codec_settings_.simulcastStream[0].maxFramerate = kMaxFramerate;
codec_settings_.simulcastStream[0].minBitrate = kTargetBitrate / 2;
codec_settings_.simulcastStream[0].maxBitrate = kTargetBitrate;
codec_settings_.simulcastStream[0].targetBitrate = kTargetBitrate;
codec_settings_.simulcastStream[0].active = true;
codec_settings_.simulcastStream[1].width = codec_settings_.width / 2;
codec_settings_.simulcastStream[1].height = codec_settings_.height / 2;
codec_settings_.simulcastStream[1].maxFramerate = kMaxFramerate;
codec_settings_.simulcastStream[1].minBitrate = kTargetBitrate / 2;
codec_settings_.simulcastStream[1].maxBitrate = kTargetBitrate;
codec_settings_.simulcastStream[1].targetBitrate = kTargetBitrate;
codec_settings_.simulcastStream[1].active = true;
codec_settings_.simulcastStream[2].width = codec_settings_.width;
codec_settings_.simulcastStream[2].height = codec_settings_.height;
codec_settings_.simulcastStream[2].maxFramerate = kMaxFramerate;
codec_settings_.simulcastStream[2].minBitrate = kTargetBitrate / 2;
codec_settings_.simulcastStream[2].maxBitrate = kTargetBitrate;
codec_settings_.simulcastStream[2].targetBitrate = kTargetBitrate;
codec_settings_.simulcastStream[2].active = true;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, kSettings));
// Bitrate must be set for all layers to be produced.
VideoBitrateAllocation bitrate_allocation;
bitrate_allocation.SetBitrate(0, 0, kTargetBitrate * 1000);
bitrate_allocation.SetBitrate(1, 0, kTargetBitrate * 1000);
bitrate_allocation.SetBitrate(2, 0, kTargetBitrate * 1000);
encoder_->SetRates(
VideoEncoder::RateControlParameters(bitrate_allocation, kMaxFramerate));
// Encode a frame and confirm simulcast index is set for all layers.
{
SetWaitForEncodedFramesThreshold(3);
std::vector<EncodedImage> encoded_frame;
std::vector<CodecSpecificInfo> codec_specific_info;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->Encode(NextInputFrame(), nullptr));
ASSERT_TRUE(WaitForEncodedFrames(&encoded_frame, &codec_specific_info));
EXPECT_EQ(encoded_frame[0].SimulcastIndex().value_or(-1), 0);
EXPECT_EQ(encoded_frame[1].SimulcastIndex().value_or(-1), 1);
EXPECT_EQ(encoded_frame[2].SimulcastIndex().value_or(-1), 2);
}
// Reconfigure 720p singlecast.
codec_settings_.numberOfSimulcastStreams = 1;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, kSettings));
// Encode a frame and confirm simulcast index is not set.
{
SetWaitForEncodedFramesThreshold(1);
std::vector<EncodedImage> encoded_frame;
std::vector<CodecSpecificInfo> codec_specific_info;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->Encode(NextInputFrame(), nullptr));
ASSERT_TRUE(WaitForEncodedFrames(&encoded_frame, &codec_specific_info));
EXPECT_FALSE(encoded_frame[0].SimulcastIndex().has_value());
}
}
TEST_F(TestVp9Impl, EnableDisableSpatialLayers) {
// Configure encoder to produce N spatial layers. Encode frames of layer 0
// then enable layer 1 and encode more frames and so on until layer N-1.

View File

@ -2480,9 +2480,91 @@ TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
Resolution({.width = 960, .height = 540}),
kLongTimeoutForRampingUp.ms());
// Ensure 180p frames continue to be encoded post reconfiguration.
int frames_encoded = EncodedFrames(local_pc_wrapper, "q");
ASSERT_TRUE_WAIT(EncodedFrames(local_pc_wrapper, "q") > frames_encoded,
// Ensure frames continue to be encoded post reconfiguration.
int q_frames_encoded = EncodedFrames(local_pc_wrapper, "q");
ASSERT_TRUE_WAIT(EncodedFrames(local_pc_wrapper, "q") > q_frames_encoded,
kLongTimeoutForRampingUp.ms());
int h_frames_encoded = EncodedFrames(local_pc_wrapper, "h");
ASSERT_TRUE_WAIT(EncodedFrames(local_pc_wrapper, "h") > h_frames_encoded,
kLongTimeoutForRampingUp.ms());
int f_frames_encoded = EncodedFrames(local_pc_wrapper, "f");
ASSERT_TRUE_WAIT(EncodedFrames(local_pc_wrapper, "f") > f_frames_encoded,
kLongTimeoutForRampingUp.ms());
}
// Simulcast starting in 720p 4:2:1 then changing to {180p, 360p, 540p} using
// the `requested_resolution` API.
TEST_P(PeerConnectionEncodingsIntegrationParameterizedTest,
SimulcastRequestedResolutionNoLongerPowerOfTwo) {
rtc::scoped_refptr<PeerConnectionTestWrapper> local_pc_wrapper = CreatePc();
if (SkipTestDueToAv1Missing(local_pc_wrapper)) {
return;
}
rtc::scoped_refptr<PeerConnectionTestWrapper> remote_pc_wrapper = CreatePc();
ExchangeIceCandidates(local_pc_wrapper, remote_pc_wrapper);
std::vector<cricket::SimulcastLayer> layers =
CreateLayers({"q", "h", "f"}, /*active=*/true);
rtc::scoped_refptr<RtpTransceiverInterface> transceiver =
AddTransceiverWithSimulcastLayers(local_pc_wrapper, remote_pc_wrapper,
layers);
std::vector<RtpCodecCapability> codecs =
GetCapabilitiesAndRestrictToCodec(remote_pc_wrapper, codec_name_);
transceiver->SetCodecPreferences(codecs);
rtc::scoped_refptr<RtpSenderInterface> sender = transceiver->sender();
// Configure {180p, 360p, 720p}.
RtpParameters parameters = sender->GetParameters();
ASSERT_THAT(parameters.encodings, SizeIs(3));
parameters.encodings[0].scalability_mode = "L1T1";
parameters.encodings[0].requested_resolution = {.width = 320, .height = 180};
parameters.encodings[1].scalability_mode = "L1T1";
parameters.encodings[1].requested_resolution = {.width = 640, .height = 360};
parameters.encodings[2].scalability_mode = "L1T1";
parameters.encodings[2].requested_resolution = {.width = 1280, .height = 720};
sender->SetParameters(parameters);
NegotiateWithSimulcastTweaks(local_pc_wrapper, remote_pc_wrapper);
local_pc_wrapper->WaitForConnection();
remote_pc_wrapper->WaitForConnection();
// Wait for media to flow on all layers.
// Needed repro step of https://crbug.com/webrtc/369654168: When the same
// LibvpxVp9Encoder instance was used to first produce simulcast and later for
// a single encoding, the previously used simulcast index (= 2) would still be
// set when producing 180p since non-simulcast config does not reset this,
// resulting in the 180p encoding freezing and the 540p encoding having double
// frame rate and toggling between 180p and 540p in resolution.
ASSERT_TRUE_WAIT(HasOutboundRtpBytesSent(local_pc_wrapper, 3u),
kLongTimeoutForRampingUp.ms());
// Configure {180p, 360p, 540p}.
parameters = sender->GetParameters();
parameters.encodings[0].requested_resolution = {.width = 320, .height = 180};
parameters.encodings[1].requested_resolution = {.width = 640, .height = 360};
parameters.encodings[2].requested_resolution = {.width = 960, .height = 540};
sender->SetParameters(parameters);
// Wait for the new resolutions to be produced.
ASSERT_TRUE_WAIT(GetEncodingResolution(local_pc_wrapper, "q") ==
Resolution({.width = 320, .height = 180}),
kLongTimeoutForRampingUp.ms());
ASSERT_TRUE_WAIT(GetEncodingResolution(local_pc_wrapper, "h") ==
Resolution({.width = 640, .height = 360}),
kLongTimeoutForRampingUp.ms());
ASSERT_TRUE_WAIT(GetEncodingResolution(local_pc_wrapper, "f") ==
Resolution({.width = 960, .height = 540}),
kLongTimeoutForRampingUp.ms());
// Ensure frames continue to be encoded post reconfiguration.
int q_frames_encoded = EncodedFrames(local_pc_wrapper, "q");
ASSERT_TRUE_WAIT(EncodedFrames(local_pc_wrapper, "q") > q_frames_encoded,
kLongTimeoutForRampingUp.ms());
int h_frames_encoded = EncodedFrames(local_pc_wrapper, "h");
ASSERT_TRUE_WAIT(EncodedFrames(local_pc_wrapper, "h") > h_frames_encoded,
kLongTimeoutForRampingUp.ms());
int f_frames_encoded = EncodedFrames(local_pc_wrapper, "f");
ASSERT_TRUE_WAIT(EncodedFrames(local_pc_wrapper, "f") > f_frames_encoded,
kLongTimeoutForRampingUp.ms());
}