blob: 00990847a05a48a0ca2e8d4b3f22da3d25dbe8b2 [file] [log] [blame]
Stefan Holmerf7044682018-07-17 08:16:411/*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 17:08:3311#include "call/rtp_payload_params.h"
12
Yves Gerey3e707812018-11-28 15:47:4913#include <string.h>
Jonas Olssona4d87372019-07-05 17:08:3314
Yves Gerey3e707812018-11-28 15:47:4915#include <map>
philipelbf2b6202018-08-27 12:33:1816#include <set>
Stefan Holmerf7044682018-07-17 08:16:4117
Yves Gerey3e707812018-11-28 15:47:4918#include "absl/container/inlined_vector.h"
19#include "absl/types/optional.h"
20#include "absl/types/variant.h"
Erik Språngcbc0cba2020-04-18 12:36:5921#include "api/transport/field_trial_based_config.h"
Yves Gerey3e707812018-11-28 15:47:4922#include "api/video/video_content_type.h"
23#include "api/video/video_rotation.h"
Yves Gerey3e707812018-11-28 15:47:4924#include "modules/video_coding/codecs/h264/include/h264_globals.h"
25#include "modules/video_coding/codecs/interface/common_constants.h"
26#include "modules/video_coding/codecs/vp8/include/vp8_globals.h"
27#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Stefan Holmerf7044682018-07-17 08:16:4128#include "modules/video_coding/include/video_codec_interface.h"
Danil Chapovalovaf366442021-04-22 13:20:2829#include "test/explicit_key_value_config.h"
philipel8aba8fe2019-06-13 13:13:1630#include "test/gmock.h"
Stefan Holmerf7044682018-07-17 08:16:4131#include "test/gtest.h"
Jonas Orelandc7f691a2022-03-09 14:12:0732#include "test/scoped_key_value_config.h"
Stefan Holmerf7044682018-07-17 08:16:4133
Emil Lundmark6c81a422022-05-18 15:13:3434namespace webrtc {
35namespace {
36
37using ::testing::AllOf;
Danil Chapovalovaf366442021-04-22 13:20:2838using ::testing::Each;
Danil Chapovalovdc7fe402019-12-13 11:23:5839using ::testing::ElementsAre;
philipel5b231de2021-09-01 13:21:1640using ::testing::Eq;
Emil Lundmark6c81a422022-05-18 15:13:3441using ::testing::Field;
Danil Chapovalovdc7fe402019-12-13 11:23:5842using ::testing::IsEmpty;
Emil Lundmark6c81a422022-05-18 15:13:3443using ::testing::Optional;
Danil Chapovalov4b860c12020-05-19 12:48:1944using ::testing::SizeIs;
Danil Chapovalovdc7fe402019-12-13 11:23:5845
Emil Lundmark6c81a422022-05-18 15:13:3446using GenericDescriptorInfo = RTPVideoHeader::GenericDescriptorInfo;
47
Stefan Holmerf7044682018-07-17 08:16:4148const uint32_t kSsrc1 = 12345;
49const uint32_t kSsrc2 = 23456;
50const int16_t kPictureId = 123;
51const int16_t kTl0PicIdx = 20;
52const uint8_t kTemporalIdx = 1;
53const int16_t kInitialPictureId1 = 222;
54const int16_t kInitialTl0PicIdx1 = 99;
philipelbf2b6202018-08-27 12:33:1855const int64_t kDontCare = 0;
Stefan Holmerf7044682018-07-17 08:16:4156
57TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp8) {
58 RtpPayloadState state2;
59 state2.picture_id = kPictureId;
60 state2.tl0_pic_idx = kTl0PicIdx;
61 std::map<uint32_t, RtpPayloadState> states = {{kSsrc2, state2}};
62
Erik Språngcbc0cba2020-04-18 12:36:5963 RtpPayloadParams params(kSsrc2, &state2, FieldTrialBasedConfig());
Stefan Holmerf7044682018-07-17 08:16:4164 EncodedImage encoded_image;
65 encoded_image.rotation_ = kVideoRotation_90;
66 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
Henrik Boström2e540a22023-02-15 13:48:0967 encoded_image.SetSimulcastIndex(1);
Stefan Holmerf7044682018-07-17 08:16:4168
69 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 08:16:4170 codec_info.codecType = kVideoCodecVP8;
philipelbf2b6202018-08-27 12:33:1871 codec_info.codecSpecific.VP8.temporalIdx = 0;
Stefan Holmerf7044682018-07-17 08:16:4172 codec_info.codecSpecific.VP8.keyIdx = kNoKeyIdx;
philipelbf2b6202018-08-27 12:33:1873 codec_info.codecSpecific.VP8.layerSync = false;
Stefan Holmerf7044682018-07-17 08:16:4174 codec_info.codecSpecific.VP8.nonReference = true;
75
philipelbf2b6202018-08-27 12:33:1876 RTPVideoHeader header =
77 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
78
79 codec_info.codecType = kVideoCodecVP8;
philipelbf2b6202018-08-27 12:33:1880 codec_info.codecSpecific.VP8.temporalIdx = 1;
81 codec_info.codecSpecific.VP8.layerSync = true;
82
83 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 1);
Stefan Holmerf7044682018-07-17 08:16:4184
85 EXPECT_EQ(kVideoRotation_90, header.rotation);
86 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
87 EXPECT_EQ(1, header.simulcastIdx);
88 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:5589 const auto& vp8_header =
90 absl::get<RTPVideoHeaderVP8>(header.video_type_header);
91 EXPECT_EQ(kPictureId + 2, vp8_header.pictureId);
92 EXPECT_EQ(kTemporalIdx, vp8_header.temporalIdx);
93 EXPECT_EQ(kTl0PicIdx + 1, vp8_header.tl0PicIdx);
94 EXPECT_EQ(kNoKeyIdx, vp8_header.keyIdx);
95 EXPECT_TRUE(vp8_header.layerSync);
96 EXPECT_TRUE(vp8_header.nonReference);
Stefan Holmerf7044682018-07-17 08:16:4197}
98
99TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp9) {
100 RtpPayloadState state;
101 state.picture_id = kPictureId;
102 state.tl0_pic_idx = kTl0PicIdx;
Erik Språngcbc0cba2020-04-18 12:36:59103 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
Stefan Holmerf7044682018-07-17 08:16:41104
105 EncodedImage encoded_image;
106 encoded_image.rotation_ = kVideoRotation_90;
107 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
Niels Möllerd3b8c632018-08-27 13:33:42108 encoded_image.SetSpatialIndex(0);
Stefan Holmerf7044682018-07-17 08:16:41109 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 08:16:41110 codec_info.codecType = kVideoCodecVP9;
111 codec_info.codecSpecific.VP9.num_spatial_layers = 3;
112 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
Stefan Holmerf7044682018-07-17 08:16:41113 codec_info.codecSpecific.VP9.temporal_idx = 2;
Danil Chapovalov06bbeb32020-11-11 11:42:56114 codec_info.end_of_picture = false;
Stefan Holmerf7044682018-07-17 08:16:41115
philipelbf2b6202018-08-27 12:33:18116 RTPVideoHeader header =
117 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41118
119 EXPECT_EQ(kVideoRotation_90, header.rotation);
120 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
121 EXPECT_EQ(kVideoCodecVP9, header.codec);
Johannes Krond0b69a82018-12-03 13:18:53122 EXPECT_FALSE(header.color_space);
philipel29d88462018-08-08 12:26:00123 const auto& vp9_header =
124 absl::get<RTPVideoHeaderVP9>(header.video_type_header);
125 EXPECT_EQ(kPictureId + 1, vp9_header.picture_id);
126 EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx);
127 EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx);
Niels Möllerd3b8c632018-08-27 13:33:42128 EXPECT_EQ(vp9_header.spatial_idx, encoded_image.SpatialIndex());
philipel29d88462018-08-08 12:26:00129 EXPECT_EQ(vp9_header.num_spatial_layers,
Stefan Holmerf7044682018-07-17 08:16:41130 codec_info.codecSpecific.VP9.num_spatial_layers);
Danil Chapovalov06bbeb32020-11-11 11:42:56131 EXPECT_EQ(vp9_header.end_of_picture, codec_info.end_of_picture);
Stefan Holmerf7044682018-07-17 08:16:41132
133 // Next spatial layer.
134 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
Danil Chapovalov06bbeb32020-11-11 11:42:56135 codec_info.end_of_picture = true;
Stefan Holmerf7044682018-07-17 08:16:41136
Niels Möllerd3b8c632018-08-27 13:33:42137 encoded_image.SetSpatialIndex(1);
Johannes Krond0b69a82018-12-03 13:18:53138 ColorSpace color_space(
139 ColorSpace::PrimaryID::kSMPTE170M, ColorSpace::TransferID::kSMPTE170M,
140 ColorSpace::MatrixID::kSMPTE170M, ColorSpace::RangeID::kFull);
Danil Chapovalovb7698942019-02-05 10:32:19141 encoded_image.SetColorSpace(color_space);
philipelbf2b6202018-08-27 12:33:18142 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41143
144 EXPECT_EQ(kVideoRotation_90, header.rotation);
145 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
146 EXPECT_EQ(kVideoCodecVP9, header.codec);
Johannes Krond0b69a82018-12-03 13:18:53147 EXPECT_EQ(absl::make_optional(color_space), header.color_space);
philipel29d88462018-08-08 12:26:00148 EXPECT_EQ(kPictureId + 1, vp9_header.picture_id);
149 EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx);
150 EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx);
Niels Möllerd3b8c632018-08-27 13:33:42151 EXPECT_EQ(vp9_header.spatial_idx, encoded_image.SpatialIndex());
philipel29d88462018-08-08 12:26:00152 EXPECT_EQ(vp9_header.num_spatial_layers,
Stefan Holmerf7044682018-07-17 08:16:41153 codec_info.codecSpecific.VP9.num_spatial_layers);
Danil Chapovalov06bbeb32020-11-11 11:42:56154 EXPECT_EQ(vp9_header.end_of_picture, codec_info.end_of_picture);
Stefan Holmerf7044682018-07-17 08:16:41155}
156
Stefan Holmerf7044682018-07-17 08:16:41157TEST(RtpPayloadParamsTest, PictureIdIsSetForVp8) {
158 RtpPayloadState state;
159 state.picture_id = kInitialPictureId1;
160 state.tl0_pic_idx = kInitialTl0PicIdx1;
161
162 EncodedImage encoded_image;
163 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 08:16:41164 codec_info.codecType = kVideoCodecVP8;
Stefan Holmerf7044682018-07-17 08:16:41165
Erik Språngcbc0cba2020-04-18 12:36:59166 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 12:33:18167 RTPVideoHeader header =
168 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41169 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55170 EXPECT_EQ(kInitialPictureId1 + 1,
171 absl::get<RTPVideoHeaderVP8>(header.video_type_header).pictureId);
Stefan Holmerf7044682018-07-17 08:16:41172
173 // State should hold latest used picture id and tl0_pic_idx.
174 state = params.state();
175 EXPECT_EQ(kInitialPictureId1 + 1, state.picture_id);
176 EXPECT_EQ(kInitialTl0PicIdx1 + 1, state.tl0_pic_idx);
177}
178
179TEST(RtpPayloadParamsTest, PictureIdWraps) {
180 RtpPayloadState state;
181 state.picture_id = kMaxTwoBytePictureId;
182 state.tl0_pic_idx = kInitialTl0PicIdx1;
183
184 EncodedImage encoded_image;
185 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 08:16:41186 codec_info.codecType = kVideoCodecVP8;
187 codec_info.codecSpecific.VP8.temporalIdx = kNoTemporalIdx;
188
Erik Språngcbc0cba2020-04-18 12:36:59189 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 12:33:18190 RTPVideoHeader header =
191 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41192 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55193 EXPECT_EQ(0,
194 absl::get<RTPVideoHeaderVP8>(header.video_type_header).pictureId);
Stefan Holmerf7044682018-07-17 08:16:41195
196 // State should hold latest used picture id and tl0_pic_idx.
197 EXPECT_EQ(0, params.state().picture_id); // Wrapped.
198 EXPECT_EQ(kInitialTl0PicIdx1, params.state().tl0_pic_idx);
199}
200
Emil Lundmark6c81a422022-05-18 15:13:34201TEST(RtpPayloadParamsTest, CreatesGenericDescriptorForVp8) {
202 constexpr auto kSwitch = DecodeTargetIndication::kSwitch;
203 constexpr auto kNotPresent = DecodeTargetIndication::kNotPresent;
204
205 RtpPayloadState state;
206 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
207
208 EncodedImage key_frame_image;
209 key_frame_image._frameType = VideoFrameType::kVideoFrameKey;
210 CodecSpecificInfo key_frame_info;
211 key_frame_info.codecType = kVideoCodecVP8;
212 key_frame_info.codecSpecific.VP8.temporalIdx = 0;
213 RTPVideoHeader key_frame_header = params.GetRtpVideoHeader(
214 key_frame_image, &key_frame_info, /*shared_frame_id=*/123);
215
216 EncodedImage delta_t1_image;
217 delta_t1_image._frameType = VideoFrameType::kVideoFrameDelta;
218 CodecSpecificInfo delta_t1_info;
219 delta_t1_info.codecType = kVideoCodecVP8;
220 delta_t1_info.codecSpecific.VP8.temporalIdx = 1;
221 RTPVideoHeader delta_t1_header = params.GetRtpVideoHeader(
222 delta_t1_image, &delta_t1_info, /*shared_frame_id=*/124);
223
224 EncodedImage delta_t0_image;
225 delta_t0_image._frameType = VideoFrameType::kVideoFrameDelta;
226 CodecSpecificInfo delta_t0_info;
227 delta_t0_info.codecType = kVideoCodecVP8;
228 delta_t0_info.codecSpecific.VP8.temporalIdx = 0;
229 RTPVideoHeader delta_t0_header = params.GetRtpVideoHeader(
230 delta_t0_image, &delta_t0_info, /*shared_frame_id=*/125);
231
232 EXPECT_THAT(
233 key_frame_header,
234 AllOf(Field(&RTPVideoHeader::codec, kVideoCodecVP8),
235 Field(&RTPVideoHeader::frame_type, VideoFrameType::kVideoFrameKey),
236 Field(&RTPVideoHeader::generic,
237 Optional(AllOf(
238 Field(&GenericDescriptorInfo::frame_id, 123),
239 Field(&GenericDescriptorInfo::spatial_index, 0),
240 Field(&GenericDescriptorInfo::temporal_index, 0),
241 Field(&GenericDescriptorInfo::decode_target_indications,
242 ElementsAre(kSwitch, kSwitch, kSwitch, kSwitch)),
243 Field(&GenericDescriptorInfo::dependencies, IsEmpty()),
244 Field(&GenericDescriptorInfo::chain_diffs,
245 ElementsAre(0)))))));
246
247 EXPECT_THAT(
248 delta_t1_header,
249 AllOf(
250 Field(&RTPVideoHeader::codec, kVideoCodecVP8),
251 Field(&RTPVideoHeader::frame_type, VideoFrameType::kVideoFrameDelta),
252 Field(
253 &RTPVideoHeader::generic,
254 Optional(AllOf(
255 Field(&GenericDescriptorInfo::frame_id, 124),
256 Field(&GenericDescriptorInfo::spatial_index, 0),
257 Field(&GenericDescriptorInfo::temporal_index, 1),
258 Field(&GenericDescriptorInfo::decode_target_indications,
259 ElementsAre(kNotPresent, kSwitch, kSwitch, kSwitch)),
260 Field(&GenericDescriptorInfo::dependencies, ElementsAre(123)),
261 Field(&GenericDescriptorInfo::chain_diffs,
262 ElementsAre(1)))))));
263
264 EXPECT_THAT(
265 delta_t0_header,
266 AllOf(
267 Field(&RTPVideoHeader::codec, kVideoCodecVP8),
268 Field(&RTPVideoHeader::frame_type, VideoFrameType::kVideoFrameDelta),
269 Field(
270 &RTPVideoHeader::generic,
271 Optional(AllOf(
272 Field(&GenericDescriptorInfo::frame_id, 125),
273 Field(&GenericDescriptorInfo::spatial_index, 0),
274 Field(&GenericDescriptorInfo::temporal_index, 0),
275 Field(&GenericDescriptorInfo::decode_target_indications,
276 ElementsAre(kSwitch, kSwitch, kSwitch, kSwitch)),
277 Field(&GenericDescriptorInfo::dependencies, ElementsAre(123)),
278 Field(&GenericDescriptorInfo::chain_diffs,
279 ElementsAre(2)))))));
280}
281
Stefan Holmerf7044682018-07-17 08:16:41282TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp8) {
283 RtpPayloadState state;
284 state.picture_id = kInitialPictureId1;
285 state.tl0_pic_idx = kInitialTl0PicIdx1;
286
287 EncodedImage encoded_image;
288 // Modules are sending for this test.
289 // OnEncodedImage, temporalIdx: 1.
290 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 08:16:41291 codec_info.codecType = kVideoCodecVP8;
292 codec_info.codecSpecific.VP8.temporalIdx = 1;
293
Erik Språngcbc0cba2020-04-18 12:36:59294 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 12:33:18295 RTPVideoHeader header =
296 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41297
298 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55299 const auto& vp8_header =
300 absl::get<RTPVideoHeaderVP8>(header.video_type_header);
301 EXPECT_EQ(kInitialPictureId1 + 1, vp8_header.pictureId);
302 EXPECT_EQ(kInitialTl0PicIdx1, vp8_header.tl0PicIdx);
Stefan Holmerf7044682018-07-17 08:16:41303
304 // OnEncodedImage, temporalIdx: 0.
305 codec_info.codecSpecific.VP8.temporalIdx = 0;
306
philipelbf2b6202018-08-27 12:33:18307 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41308 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55309 EXPECT_EQ(kInitialPictureId1 + 2, vp8_header.pictureId);
310 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp8_header.tl0PicIdx);
Stefan Holmerf7044682018-07-17 08:16:41311
312 // State should hold latest used picture id and tl0_pic_idx.
313 EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id);
314 EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx);
315}
316
317TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp9) {
318 RtpPayloadState state;
319 state.picture_id = kInitialPictureId1;
320 state.tl0_pic_idx = kInitialTl0PicIdx1;
321
322 EncodedImage encoded_image;
323 // Modules are sending for this test.
324 // OnEncodedImage, temporalIdx: 1.
325 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 08:16:41326 codec_info.codecType = kVideoCodecVP9;
327 codec_info.codecSpecific.VP9.temporal_idx = 1;
328 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
329
Erik Språngcbc0cba2020-04-18 12:36:59330 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 12:33:18331 RTPVideoHeader header =
332 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41333
334 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 12:26:00335 const auto& vp9_header =
336 absl::get<RTPVideoHeaderVP9>(header.video_type_header);
337 EXPECT_EQ(kInitialPictureId1 + 1, vp9_header.picture_id);
338 EXPECT_EQ(kInitialTl0PicIdx1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 08:16:41339
340 // OnEncodedImage, temporalIdx: 0.
341 codec_info.codecSpecific.VP9.temporal_idx = 0;
342
philipelbf2b6202018-08-27 12:33:18343 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41344
345 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 12:26:00346 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
347 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 08:16:41348
349 // OnEncodedImage, first_frame_in_picture = false
350 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
351
philipelbf2b6202018-08-27 12:33:18352 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 08:16:41353
354 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 12:26:00355 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
356 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 08:16:41357
358 // State should hold latest used picture id and tl0_pic_idx.
359 EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id);
360 EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx);
361}
philipelbf2b6202018-08-27 12:33:18362
philipel626edea2024-03-19 08:38:01363TEST(RtpPayloadParamsTest, GenerateFrameIdWhenExternalFrameIdsAreNotProvided) {
364 RtpPayloadState state;
365 state.frame_id = 123;
366
367 EncodedImage encoded_image;
368 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
369 CodecSpecificInfo codec_info;
370 codec_info.codecType = kVideoCodecGeneric;
371
372 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
373 RTPVideoHeader header =
374 params.GetRtpVideoHeader(encoded_image, &codec_info, absl::nullopt);
375
376 EXPECT_THAT(header.codec, Eq(kVideoCodecGeneric));
377
378 ASSERT_TRUE(header.generic);
379 EXPECT_THAT(header.generic->frame_id, Eq(123));
380
381 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
382 header = params.GetRtpVideoHeader(encoded_image, &codec_info, absl::nullopt);
383 ASSERT_TRUE(header.generic);
384 EXPECT_THAT(header.generic->frame_id, Eq(124));
385}
386
philipelbf2b6202018-08-27 12:33:18387TEST(RtpPayloadParamsTest, PictureIdForOldGenericFormat) {
Jonas Orelandc7f691a2022-03-09 14:12:07388 test::ScopedKeyValueConfig field_trials("WebRTC-GenericPictureId/Enabled/");
philipelbf2b6202018-08-27 12:33:18389 RtpPayloadState state{};
390
391 EncodedImage encoded_image;
philipeld1d03592019-03-01 12:53:55392 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 12:33:18393 codec_info.codecType = kVideoCodecGeneric;
Markus Handellc1cbf6b2020-02-17 19:03:57394 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
philipelbf2b6202018-08-27 12:33:18395
Jonas Orelandc7f691a2022-03-09 14:12:07396 RtpPayloadParams params(kSsrc1, &state, field_trials);
philipelbf2b6202018-08-27 12:33:18397 RTPVideoHeader header =
Markus Handellc1cbf6b2020-02-17 19:03:57398 params.GetRtpVideoHeader(encoded_image, &codec_info, 10);
philipelbf2b6202018-08-27 12:33:18399
400 EXPECT_EQ(kVideoCodecGeneric, header.codec);
Danil Chapovalovb6bf0b22020-01-28 17:36:57401 const auto* generic =
402 absl::get_if<RTPVideoHeaderLegacyGeneric>(&header.video_type_header);
403 ASSERT_TRUE(generic);
404 EXPECT_EQ(0, generic->picture_id);
philipelbf2b6202018-08-27 12:33:18405
Markus Handellc1cbf6b2020-02-17 19:03:57406 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
407 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 20);
Danil Chapovalovb6bf0b22020-01-28 17:36:57408 generic =
409 absl::get_if<RTPVideoHeaderLegacyGeneric>(&header.video_type_header);
410 ASSERT_TRUE(generic);
411 EXPECT_EQ(1, generic->picture_id);
philipelbf2b6202018-08-27 12:33:18412}
413
philipel8aba8fe2019-06-13 13:13:16414TEST(RtpPayloadParamsTest, GenericDescriptorForGenericCodec) {
philipel5b231de2021-09-01 13:21:16415 RtpPayloadState state;
philipel8aba8fe2019-06-13 13:13:16416
417 EncodedImage encoded_image;
418 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
419 CodecSpecificInfo codec_info;
420 codec_info.codecType = kVideoCodecGeneric;
421
Erik Språngcbc0cba2020-04-18 12:36:59422 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipel8aba8fe2019-06-13 13:13:16423 RTPVideoHeader header =
424 params.GetRtpVideoHeader(encoded_image, &codec_info, 0);
425
philipel5b231de2021-09-01 13:21:16426 EXPECT_THAT(header.codec, Eq(kVideoCodecGeneric));
427
philipel8aba8fe2019-06-13 13:13:16428 ASSERT_TRUE(header.generic);
philipel5b231de2021-09-01 13:21:16429 EXPECT_THAT(header.generic->frame_id, Eq(0));
430 EXPECT_THAT(header.generic->spatial_index, Eq(0));
431 EXPECT_THAT(header.generic->temporal_index, Eq(0));
432 EXPECT_THAT(header.generic->decode_target_indications,
433 ElementsAre(DecodeTargetIndication::kSwitch));
philipel8aba8fe2019-06-13 13:13:16434 EXPECT_THAT(header.generic->dependencies, IsEmpty());
philipel5b231de2021-09-01 13:21:16435 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(0));
philipel8aba8fe2019-06-13 13:13:16436
437 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
philipel5b231de2021-09-01 13:21:16438 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 3);
philipel8aba8fe2019-06-13 13:13:16439 ASSERT_TRUE(header.generic);
philipel5b231de2021-09-01 13:21:16440 EXPECT_THAT(header.generic->frame_id, Eq(3));
441 EXPECT_THAT(header.generic->spatial_index, Eq(0));
442 EXPECT_THAT(header.generic->temporal_index, Eq(0));
philipel8aba8fe2019-06-13 13:13:16443 EXPECT_THAT(header.generic->dependencies, ElementsAre(0));
philipel5b231de2021-09-01 13:21:16444 EXPECT_THAT(header.generic->decode_target_indications,
445 ElementsAre(DecodeTargetIndication::kSwitch));
446 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(3));
philipel8aba8fe2019-06-13 13:13:16447}
448
Danil Chapovalov02d71fb2020-02-10 15:22:57449TEST(RtpPayloadParamsTest, SetsGenericFromGenericFrameInfo) {
Danil Chapovalov02d71fb2020-02-10 15:22:57450 RtpPayloadState state;
451 EncodedImage encoded_image;
452 CodecSpecificInfo codec_info;
453
Erik Språngcbc0cba2020-04-18 12:36:59454 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
Danil Chapovalov02d71fb2020-02-10 15:22:57455
456 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
457 codec_info.generic_frame_info =
458 GenericFrameInfo::Builder().S(1).T(0).Dtis("S").Build();
459 codec_info.generic_frame_info->encoder_buffers = {
460 {/*id=*/0, /*referenced=*/false, /*updated=*/true}};
Danil Chapovalov4b860c12020-05-19 12:48:19461 codec_info.generic_frame_info->part_of_chain = {true, false};
Danil Chapovalov02d71fb2020-02-10 15:22:57462 RTPVideoHeader key_header =
463 params.GetRtpVideoHeader(encoded_image, &codec_info, /*frame_id=*/1);
464
465 ASSERT_TRUE(key_header.generic);
466 EXPECT_EQ(key_header.generic->spatial_index, 1);
467 EXPECT_EQ(key_header.generic->temporal_index, 0);
468 EXPECT_EQ(key_header.generic->frame_id, 1);
469 EXPECT_THAT(key_header.generic->dependencies, IsEmpty());
470 EXPECT_THAT(key_header.generic->decode_target_indications,
471 ElementsAre(DecodeTargetIndication::kSwitch));
Danil Chapovalov4b860c12020-05-19 12:48:19472 EXPECT_THAT(key_header.generic->chain_diffs, SizeIs(2));
Danil Chapovalov02d71fb2020-02-10 15:22:57473
474 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
475 codec_info.generic_frame_info =
476 GenericFrameInfo::Builder().S(2).T(3).Dtis("D").Build();
477 codec_info.generic_frame_info->encoder_buffers = {
478 {/*id=*/0, /*referenced=*/true, /*updated=*/false}};
Danil Chapovalov4b860c12020-05-19 12:48:19479 codec_info.generic_frame_info->part_of_chain = {false, false};
Danil Chapovalov02d71fb2020-02-10 15:22:57480 RTPVideoHeader delta_header =
481 params.GetRtpVideoHeader(encoded_image, &codec_info, /*frame_id=*/3);
482
483 ASSERT_TRUE(delta_header.generic);
484 EXPECT_EQ(delta_header.generic->spatial_index, 2);
485 EXPECT_EQ(delta_header.generic->temporal_index, 3);
486 EXPECT_EQ(delta_header.generic->frame_id, 3);
487 EXPECT_THAT(delta_header.generic->dependencies, ElementsAre(1));
488 EXPECT_THAT(delta_header.generic->decode_target_indications,
489 ElementsAre(DecodeTargetIndication::kDiscardable));
Danil Chapovalov4b860c12020-05-19 12:48:19490 EXPECT_THAT(delta_header.generic->chain_diffs, SizeIs(2));
Danil Chapovalov02d71fb2020-02-10 15:22:57491}
492
philipelbf2b6202018-08-27 12:33:18493class RtpPayloadParamsVp8ToGenericTest : public ::testing::Test {
494 public:
495 enum LayerSync { kNoSync, kSync };
496
philipel569397f2018-09-26 10:25:31497 RtpPayloadParamsVp8ToGenericTest()
Danil Chapovalov636865e2020-06-03 12:11:26498 : state_(), params_(123, &state_, trials_config_) {}
philipelbf2b6202018-08-27 12:33:18499
500 void ConvertAndCheck(int temporal_index,
501 int64_t shared_frame_id,
Qingsi Wang1c1b99e2020-01-07 19:16:33502 VideoFrameType frame_type,
philipelbf2b6202018-08-27 12:33:18503 LayerSync layer_sync,
philipelfab91292018-10-17 12:36:08504 const std::set<int64_t>& expected_deps,
505 uint16_t width = 0,
506 uint16_t height = 0) {
philipelbf2b6202018-08-27 12:33:18507 EncodedImage encoded_image;
Qingsi Wang1c1b99e2020-01-07 19:16:33508 encoded_image._frameType = frame_type;
philipelfab91292018-10-17 12:36:08509 encoded_image._encodedWidth = width;
510 encoded_image._encodedHeight = height;
philipelbf2b6202018-08-27 12:33:18511
philipeld1d03592019-03-01 12:53:55512 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 12:33:18513 codec_info.codecType = kVideoCodecVP8;
Qingsi Wang1c1b99e2020-01-07 19:16:33514 codec_info.codecSpecific.VP8.temporalIdx = temporal_index;
515 codec_info.codecSpecific.VP8.layerSync = layer_sync == kSync;
philipelbf2b6202018-08-27 12:33:18516
517 RTPVideoHeader header =
518 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
519
520 ASSERT_TRUE(header.generic);
philipelbf2b6202018-08-27 12:33:18521 EXPECT_EQ(header.generic->spatial_index, 0);
522
523 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
524 EXPECT_EQ(header.generic->temporal_index, temporal_index);
Qingsi Wang1c1b99e2020-01-07 19:16:33525 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
526 header.generic->dependencies.end());
527 EXPECT_EQ(expected_deps, actual_deps);
philipelfab91292018-10-17 12:36:08528
529 EXPECT_EQ(header.width, width);
530 EXPECT_EQ(header.height, height);
philipelbf2b6202018-08-27 12:33:18531 }
532
533 protected:
Erik Språngcbc0cba2020-04-18 12:36:59534 FieldTrialBasedConfig trials_config_;
philipelbf2b6202018-08-27 12:33:18535 RtpPayloadState state_;
536 RtpPayloadParams params_;
537};
538
539TEST_F(RtpPayloadParamsVp8ToGenericTest, Keyframe) {
Qingsi Wang1c1b99e2020-01-07 19:16:33540 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
541 ConvertAndCheck(0, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
542 ConvertAndCheck(0, 2, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
philipelbf2b6202018-08-27 12:33:18543}
544
545TEST_F(RtpPayloadParamsVp8ToGenericTest, TooHighTemporalIndex) {
Qingsi Wang1c1b99e2020-01-07 19:16:33546 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
philipelbf2b6202018-08-27 12:33:18547
548 EncodedImage encoded_image;
Niels Möller8f7ce222019-03-21 14:43:58549 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
philipeld1d03592019-03-01 12:53:55550 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 12:33:18551 codec_info.codecType = kVideoCodecVP8;
552 codec_info.codecSpecific.VP8.temporalIdx =
553 RtpGenericFrameDescriptor::kMaxTemporalLayers;
554 codec_info.codecSpecific.VP8.layerSync = false;
555
556 RTPVideoHeader header =
557 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
558 EXPECT_FALSE(header.generic);
559}
560
Qingsi Wang1c1b99e2020-01-07 19:16:33561TEST_F(RtpPayloadParamsVp8ToGenericTest, LayerSync) {
562 // 02120212 pattern
563 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
564 ConvertAndCheck(2, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
565 ConvertAndCheck(1, 2, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
566 ConvertAndCheck(2, 3, VideoFrameType::kVideoFrameDelta, kNoSync, {0, 1, 2});
philipelbf2b6202018-08-27 12:33:18567
Qingsi Wang1c1b99e2020-01-07 19:16:33568 ConvertAndCheck(0, 4, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
569 ConvertAndCheck(2, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {2, 3, 4});
570 ConvertAndCheck(1, 6, VideoFrameType::kVideoFrameDelta, kSync,
571 {4}); // layer sync
572 ConvertAndCheck(2, 7, VideoFrameType::kVideoFrameDelta, kNoSync, {4, 5, 6});
philipelbf2b6202018-08-27 12:33:18573}
574
575TEST_F(RtpPayloadParamsVp8ToGenericTest, FrameIdGaps) {
576 // 0101 pattern
Qingsi Wang1c1b99e2020-01-07 19:16:33577 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
578 ConvertAndCheck(1, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
philipelbf2b6202018-08-27 12:33:18579
Qingsi Wang1c1b99e2020-01-07 19:16:33580 ConvertAndCheck(0, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
581 ConvertAndCheck(1, 10, VideoFrameType::kVideoFrameDelta, kNoSync, {1, 5});
philipelbf2b6202018-08-27 12:33:18582
Qingsi Wang1c1b99e2020-01-07 19:16:33583 ConvertAndCheck(0, 15, VideoFrameType::kVideoFrameDelta, kNoSync, {5});
584 ConvertAndCheck(1, 20, VideoFrameType::kVideoFrameDelta, kNoSync, {10, 15});
philipelbf2b6202018-08-27 12:33:18585}
586
Emil Lundmarkb01e6452021-09-14 09:46:44587TEST(RtpPayloadParamsVp9ToGenericTest, NoScalability) {
588 RtpPayloadState state;
589 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 13:20:28590
591 EncodedImage encoded_image;
592 CodecSpecificInfo codec_info;
593 codec_info.codecType = kVideoCodecVP9;
philipel4e0bf2e2023-06-20 08:29:20594 codec_info.codecSpecific.VP9.flexible_mode = true;
Danil Chapovalovaf366442021-04-22 13:20:28595 codec_info.codecSpecific.VP9.num_spatial_layers = 1;
596 codec_info.codecSpecific.VP9.temporal_idx = kNoTemporalIdx;
597 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
598 codec_info.end_of_picture = true;
599
600 // Key frame.
601 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
602 codec_info.codecSpecific.VP9.inter_pic_predicted = false;
603 codec_info.codecSpecific.VP9.num_ref_pics = 0;
604 RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info,
605 /*shared_frame_id=*/1);
606
607 ASSERT_TRUE(header.generic);
608 EXPECT_EQ(header.generic->spatial_index, 0);
609 EXPECT_EQ(header.generic->temporal_index, 0);
610 EXPECT_EQ(header.generic->frame_id, 1);
611 ASSERT_THAT(header.generic->decode_target_indications, Not(IsEmpty()));
612 EXPECT_EQ(header.generic->decode_target_indications[0],
613 DecodeTargetIndication::kSwitch);
614 EXPECT_THAT(header.generic->dependencies, IsEmpty());
Danil Chapovalov5b298ab2022-06-08 09:18:51615 ASSERT_THAT(header.generic->chain_diffs, Not(IsEmpty()));
616 EXPECT_EQ(header.generic->chain_diffs[0], 0);
Danil Chapovalovaf366442021-04-22 13:20:28617
618 // Delta frame.
619 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
620 codec_info.codecSpecific.VP9.inter_pic_predicted = true;
621 codec_info.codecSpecific.VP9.num_ref_pics = 1;
622 codec_info.codecSpecific.VP9.p_diff[0] = 1;
623 header = params.GetRtpVideoHeader(encoded_image, &codec_info,
624 /*shared_frame_id=*/3);
625
626 ASSERT_TRUE(header.generic);
627 EXPECT_EQ(header.generic->spatial_index, 0);
628 EXPECT_EQ(header.generic->temporal_index, 0);
629 EXPECT_EQ(header.generic->frame_id, 3);
630 ASSERT_THAT(header.generic->decode_target_indications, Not(IsEmpty()));
631 EXPECT_EQ(header.generic->decode_target_indications[0],
632 DecodeTargetIndication::kSwitch);
633 EXPECT_THAT(header.generic->dependencies, ElementsAre(1));
Danil Chapovalov5b298ab2022-06-08 09:18:51634 ASSERT_THAT(header.generic->chain_diffs, Not(IsEmpty()));
Danil Chapovalovaf366442021-04-22 13:20:28635 // previous frame in the chain was frame#1,
Danil Chapovalov5b298ab2022-06-08 09:18:51636 EXPECT_EQ(header.generic->chain_diffs[0], 3 - 1);
Danil Chapovalovaf366442021-04-22 13:20:28637}
638
philipel4e0bf2e2023-06-20 08:29:20639TEST(RtpPayloadParamsVp9ToGenericTest, NoScalabilityNonFlexibleMode) {
640 RtpPayloadState state;
641 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
642
643 EncodedImage encoded_image;
644 CodecSpecificInfo codec_info;
645 codec_info.codecType = kVideoCodecVP9;
646 codec_info.codecSpecific.VP9.flexible_mode = false;
647 codec_info.codecSpecific.VP9.num_spatial_layers = 1;
648 codec_info.codecSpecific.VP9.temporal_idx = kNoTemporalIdx;
649 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
650 codec_info.end_of_picture = true;
651
652 // Key frame.
653 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
654 codec_info.codecSpecific.VP9.inter_pic_predicted = false;
655 RTPVideoHeader key_header =
656 params.GetRtpVideoHeader(encoded_image, &codec_info,
657 /*shared_frame_id=*/1);
658
659 ASSERT_TRUE(key_header.generic);
660 EXPECT_EQ(key_header.generic->spatial_index, 0);
661 EXPECT_EQ(key_header.generic->temporal_index, 0);
662 EXPECT_EQ(key_header.generic->frame_id, 1);
663 ASSERT_THAT(key_header.generic->decode_target_indications, Not(IsEmpty()));
664 EXPECT_EQ(key_header.generic->decode_target_indications[0],
665 DecodeTargetIndication::kSwitch);
666 EXPECT_THAT(key_header.generic->dependencies, IsEmpty());
667 ASSERT_THAT(key_header.generic->chain_diffs, Not(IsEmpty()));
668 EXPECT_EQ(key_header.generic->chain_diffs[0], 0);
669
670 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
671 codec_info.codecSpecific.VP9.inter_pic_predicted = true;
672 RTPVideoHeader delta_header =
673 params.GetRtpVideoHeader(encoded_image, &codec_info,
674 /*shared_frame_id=*/3);
675
676 ASSERT_TRUE(delta_header.generic);
677 EXPECT_EQ(delta_header.generic->spatial_index, 0);
678 EXPECT_EQ(delta_header.generic->temporal_index, 0);
679 EXPECT_EQ(delta_header.generic->frame_id, 3);
680 ASSERT_THAT(delta_header.generic->decode_target_indications, Not(IsEmpty()));
681 EXPECT_EQ(delta_header.generic->decode_target_indications[0],
682 DecodeTargetIndication::kSwitch);
683 EXPECT_THAT(delta_header.generic->dependencies, ElementsAre(1));
684 ASSERT_THAT(delta_header.generic->chain_diffs, Not(IsEmpty()));
685 EXPECT_EQ(delta_header.generic->chain_diffs[0], 3 - 1);
686}
687
Emil Lundmarkb01e6452021-09-14 09:46:44688TEST(RtpPayloadParamsVp9ToGenericTest, TemporalScalabilityWith2Layers) {
Danil Chapovalovaf366442021-04-22 13:20:28689 // Test with 2 temporal layers structure that is not used by webrtc:
690 // 1---3 5
691 // / / / ...
692 // 0---2---4---
Emil Lundmarkb01e6452021-09-14 09:46:44693 RtpPayloadState state;
694 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 13:20:28695
696 EncodedImage image;
697 CodecSpecificInfo info;
698 info.codecType = kVideoCodecVP9;
philipel4e0bf2e2023-06-20 08:29:20699 info.codecSpecific.VP9.flexible_mode = true;
Danil Chapovalovaf366442021-04-22 13:20:28700 info.codecSpecific.VP9.num_spatial_layers = 1;
701 info.codecSpecific.VP9.first_frame_in_picture = true;
702 info.end_of_picture = true;
703
704 RTPVideoHeader headers[6];
705 // Key frame.
706 image._frameType = VideoFrameType::kVideoFrameKey;
707 info.codecSpecific.VP9.inter_pic_predicted = false;
708 info.codecSpecific.VP9.num_ref_pics = 0;
709 info.codecSpecific.VP9.temporal_up_switch = true;
710 info.codecSpecific.VP9.temporal_idx = 0;
711 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
712
713 // Delta frames.
714 info.codecSpecific.VP9.inter_pic_predicted = true;
715 image._frameType = VideoFrameType::kVideoFrameDelta;
716
717 info.codecSpecific.VP9.temporal_up_switch = true;
718 info.codecSpecific.VP9.temporal_idx = 1;
719 info.codecSpecific.VP9.num_ref_pics = 1;
720 info.codecSpecific.VP9.p_diff[0] = 1;
721 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
722
723 info.codecSpecific.VP9.temporal_up_switch = false;
724 info.codecSpecific.VP9.temporal_idx = 0;
725 info.codecSpecific.VP9.num_ref_pics = 1;
726 info.codecSpecific.VP9.p_diff[0] = 2;
727 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
728
729 info.codecSpecific.VP9.temporal_up_switch = false;
730 info.codecSpecific.VP9.temporal_idx = 1;
731 info.codecSpecific.VP9.num_ref_pics = 2;
732 info.codecSpecific.VP9.p_diff[0] = 1;
733 info.codecSpecific.VP9.p_diff[1] = 2;
734 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
735
736 info.codecSpecific.VP9.temporal_up_switch = true;
737 info.codecSpecific.VP9.temporal_idx = 0;
738 info.codecSpecific.VP9.num_ref_pics = 1;
739 info.codecSpecific.VP9.p_diff[0] = 2;
740 headers[4] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/9);
741
742 info.codecSpecific.VP9.temporal_up_switch = true;
743 info.codecSpecific.VP9.temporal_idx = 1;
744 info.codecSpecific.VP9.num_ref_pics = 1;
745 info.codecSpecific.VP9.p_diff[0] = 1;
746 headers[5] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/11);
747
748 ASSERT_TRUE(headers[0].generic);
749 int num_decode_targets = headers[0].generic->decode_target_indications.size();
Danil Chapovalov5b298ab2022-06-08 09:18:51750 int num_chains = headers[0].generic->chain_diffs.size();
Danil Chapovalovaf366442021-04-22 13:20:28751 ASSERT_GE(num_decode_targets, 2);
Danil Chapovalov5b298ab2022-06-08 09:18:51752 ASSERT_GE(num_chains, 1);
Danil Chapovalovaf366442021-04-22 13:20:28753
754 for (int frame_idx = 0; frame_idx < 6; ++frame_idx) {
755 const RTPVideoHeader& header = headers[frame_idx];
756 ASSERT_TRUE(header.generic);
757 EXPECT_EQ(header.generic->spatial_index, 0);
758 EXPECT_EQ(header.generic->temporal_index, frame_idx % 2);
759 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
760 ASSERT_THAT(header.generic->decode_target_indications,
761 SizeIs(num_decode_targets));
Danil Chapovalov5b298ab2022-06-08 09:18:51762 ASSERT_THAT(header.generic->chain_diffs, SizeIs(num_chains));
Danil Chapovalovaf366442021-04-22 13:20:28763 // Expect only T0 frames are needed for the 1st decode target.
764 if (header.generic->temporal_index == 0) {
765 EXPECT_NE(header.generic->decode_target_indications[0],
766 DecodeTargetIndication::kNotPresent);
767 } else {
768 EXPECT_EQ(header.generic->decode_target_indications[0],
769 DecodeTargetIndication::kNotPresent);
770 }
771 // Expect all frames are needed for the 2nd decode target.
772 EXPECT_NE(header.generic->decode_target_indications[1],
773 DecodeTargetIndication::kNotPresent);
774 }
775
776 // Expect switch at every beginning of the pattern.
Danil Chapovalov5b298ab2022-06-08 09:18:51777 EXPECT_THAT(headers[0].generic->decode_target_indications[0],
778 DecodeTargetIndication::kSwitch);
779 EXPECT_THAT(headers[0].generic->decode_target_indications[1],
780 DecodeTargetIndication::kSwitch);
781 EXPECT_THAT(headers[4].generic->decode_target_indications[0],
782 DecodeTargetIndication::kSwitch);
783 EXPECT_THAT(headers[4].generic->decode_target_indications[1],
784 DecodeTargetIndication::kSwitch);
Danil Chapovalovaf366442021-04-22 13:20:28785
786 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // T0, 1
787 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // T1, 3
788 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // T0, 5
789 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(5, 3)); // T1, 7
790 EXPECT_THAT(headers[4].generic->dependencies, ElementsAre(5)); // T0, 9
791 EXPECT_THAT(headers[5].generic->dependencies, ElementsAre(9)); // T1, 11
792
Danil Chapovalov5b298ab2022-06-08 09:18:51793 EXPECT_THAT(headers[0].generic->chain_diffs[0], Eq(0));
794 EXPECT_THAT(headers[1].generic->chain_diffs[0], Eq(2));
795 EXPECT_THAT(headers[2].generic->chain_diffs[0], Eq(4));
796 EXPECT_THAT(headers[3].generic->chain_diffs[0], Eq(2));
797 EXPECT_THAT(headers[4].generic->chain_diffs[0], Eq(4));
798 EXPECT_THAT(headers[5].generic->chain_diffs[0], Eq(2));
Danil Chapovalovaf366442021-04-22 13:20:28799}
800
Emil Lundmarkb01e6452021-09-14 09:46:44801TEST(RtpPayloadParamsVp9ToGenericTest, TemporalScalabilityWith3Layers) {
Danil Chapovalovaf366442021-04-22 13:20:28802 // Test with 3 temporal layers structure that is not used by webrtc, but used
803 // by chromium: https://imgur.com/pURAGvp
Emil Lundmarkb01e6452021-09-14 09:46:44804 RtpPayloadState state;
805 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 13:20:28806
807 EncodedImage image;
808 CodecSpecificInfo info;
809 info.codecType = kVideoCodecVP9;
philipel4e0bf2e2023-06-20 08:29:20810 info.codecSpecific.VP9.flexible_mode = true;
Danil Chapovalovaf366442021-04-22 13:20:28811 info.codecSpecific.VP9.num_spatial_layers = 1;
812 info.codecSpecific.VP9.first_frame_in_picture = true;
813 info.end_of_picture = true;
814
815 RTPVideoHeader headers[9];
816 // Key frame.
817 image._frameType = VideoFrameType::kVideoFrameKey;
818 info.codecSpecific.VP9.inter_pic_predicted = false;
819 info.codecSpecific.VP9.num_ref_pics = 0;
820 info.codecSpecific.VP9.temporal_up_switch = true;
821 info.codecSpecific.VP9.temporal_idx = 0;
822 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
823
824 // Delta frames.
825 info.codecSpecific.VP9.inter_pic_predicted = true;
826 image._frameType = VideoFrameType::kVideoFrameDelta;
827
828 info.codecSpecific.VP9.temporal_up_switch = true;
829 info.codecSpecific.VP9.temporal_idx = 2;
830 info.codecSpecific.VP9.num_ref_pics = 1;
831 info.codecSpecific.VP9.p_diff[0] = 1;
832 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
833
834 info.codecSpecific.VP9.temporal_up_switch = true;
835 info.codecSpecific.VP9.temporal_idx = 1;
836 info.codecSpecific.VP9.num_ref_pics = 1;
837 info.codecSpecific.VP9.p_diff[0] = 2;
838 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
839
840 info.codecSpecific.VP9.temporal_up_switch = true;
841 info.codecSpecific.VP9.temporal_idx = 2;
842 info.codecSpecific.VP9.num_ref_pics = 1;
843 info.codecSpecific.VP9.p_diff[0] = 1;
844 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
845
846 info.codecSpecific.VP9.temporal_up_switch = false;
847 info.codecSpecific.VP9.temporal_idx = 0;
848 info.codecSpecific.VP9.num_ref_pics = 1;
849 info.codecSpecific.VP9.p_diff[0] = 4;
850 headers[4] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/9);
851
852 info.codecSpecific.VP9.temporal_up_switch = true;
853 info.codecSpecific.VP9.temporal_idx = 2;
854 info.codecSpecific.VP9.num_ref_pics = 2;
855 info.codecSpecific.VP9.p_diff[0] = 1;
856 info.codecSpecific.VP9.p_diff[1] = 3;
857 headers[5] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/11);
858
859 info.codecSpecific.VP9.temporal_up_switch = false;
860 info.codecSpecific.VP9.temporal_idx = 1;
861 info.codecSpecific.VP9.num_ref_pics = 2;
862 info.codecSpecific.VP9.p_diff[0] = 2;
863 info.codecSpecific.VP9.p_diff[1] = 4;
864 headers[6] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/13);
865
866 info.codecSpecific.VP9.temporal_up_switch = true;
867 info.codecSpecific.VP9.temporal_idx = 2;
868 info.codecSpecific.VP9.num_ref_pics = 1;
869 info.codecSpecific.VP9.p_diff[0] = 1;
870 headers[7] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/15);
871
872 info.codecSpecific.VP9.temporal_up_switch = true;
873 info.codecSpecific.VP9.temporal_idx = 0;
874 info.codecSpecific.VP9.num_ref_pics = 1;
875 info.codecSpecific.VP9.p_diff[0] = 4;
876 headers[8] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/17);
877
878 ASSERT_TRUE(headers[0].generic);
879 int num_decode_targets = headers[0].generic->decode_target_indications.size();
Danil Chapovalov5b298ab2022-06-08 09:18:51880 int num_chains = headers[0].generic->chain_diffs.size();
Danil Chapovalovaf366442021-04-22 13:20:28881 ASSERT_GE(num_decode_targets, 3);
Danil Chapovalov5b298ab2022-06-08 09:18:51882 ASSERT_GE(num_chains, 1);
Danil Chapovalovaf366442021-04-22 13:20:28883
884 for (int frame_idx = 0; frame_idx < 9; ++frame_idx) {
885 const RTPVideoHeader& header = headers[frame_idx];
886 ASSERT_TRUE(header.generic);
887 EXPECT_EQ(header.generic->spatial_index, 0);
888 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
889 ASSERT_THAT(header.generic->decode_target_indications,
890 SizeIs(num_decode_targets));
Danil Chapovalov5b298ab2022-06-08 09:18:51891 ASSERT_THAT(header.generic->chain_diffs, SizeIs(num_chains));
Danil Chapovalovaf366442021-04-22 13:20:28892 // Expect only T0 frames are needed for the 1st decode target.
893 if (header.generic->temporal_index == 0) {
894 EXPECT_NE(header.generic->decode_target_indications[0],
895 DecodeTargetIndication::kNotPresent);
896 } else {
897 EXPECT_EQ(header.generic->decode_target_indications[0],
898 DecodeTargetIndication::kNotPresent);
899 }
900 // Expect only T0 and T1 frames are needed for the 2nd decode target.
901 if (header.generic->temporal_index <= 1) {
902 EXPECT_NE(header.generic->decode_target_indications[1],
903 DecodeTargetIndication::kNotPresent);
904 } else {
905 EXPECT_EQ(header.generic->decode_target_indications[1],
906 DecodeTargetIndication::kNotPresent);
907 }
908 // Expect all frames are needed for the 3rd decode target.
909 EXPECT_NE(header.generic->decode_target_indications[2],
910 DecodeTargetIndication::kNotPresent);
911 }
912
913 EXPECT_EQ(headers[0].generic->temporal_index, 0);
914 EXPECT_EQ(headers[1].generic->temporal_index, 2);
915 EXPECT_EQ(headers[2].generic->temporal_index, 1);
916 EXPECT_EQ(headers[3].generic->temporal_index, 2);
917 EXPECT_EQ(headers[4].generic->temporal_index, 0);
918 EXPECT_EQ(headers[5].generic->temporal_index, 2);
919 EXPECT_EQ(headers[6].generic->temporal_index, 1);
920 EXPECT_EQ(headers[7].generic->temporal_index, 2);
921 EXPECT_EQ(headers[8].generic->temporal_index, 0);
922
923 // Expect switch at every beginning of the pattern.
924 EXPECT_THAT(headers[0].generic->decode_target_indications,
925 Each(DecodeTargetIndication::kSwitch));
Danil Chapovalov5b298ab2022-06-08 09:18:51926 EXPECT_THAT(headers[8].generic->decode_target_indications[0],
927 DecodeTargetIndication::kSwitch);
928 EXPECT_THAT(headers[8].generic->decode_target_indications[1],
929 DecodeTargetIndication::kSwitch);
930 EXPECT_THAT(headers[8].generic->decode_target_indications[2],
931 DecodeTargetIndication::kSwitch);
Danil Chapovalovaf366442021-04-22 13:20:28932
933 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // T0, 1
934 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // T2, 3
935 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // T1, 5
936 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(5)); // T2, 7
937 EXPECT_THAT(headers[4].generic->dependencies, ElementsAre(1)); // T0, 9
938 EXPECT_THAT(headers[5].generic->dependencies, ElementsAre(9, 5)); // T2, 11
939 EXPECT_THAT(headers[6].generic->dependencies, ElementsAre(9, 5)); // T1, 13
940 EXPECT_THAT(headers[7].generic->dependencies, ElementsAre(13)); // T2, 15
941 EXPECT_THAT(headers[8].generic->dependencies, ElementsAre(9)); // T0, 17
942
Danil Chapovalov5b298ab2022-06-08 09:18:51943 EXPECT_THAT(headers[0].generic->chain_diffs[0], Eq(0));
944 EXPECT_THAT(headers[1].generic->chain_diffs[0], Eq(2));
945 EXPECT_THAT(headers[2].generic->chain_diffs[0], Eq(4));
946 EXPECT_THAT(headers[3].generic->chain_diffs[0], Eq(6));
947 EXPECT_THAT(headers[4].generic->chain_diffs[0], Eq(8));
948 EXPECT_THAT(headers[5].generic->chain_diffs[0], Eq(2));
949 EXPECT_THAT(headers[6].generic->chain_diffs[0], Eq(4));
950 EXPECT_THAT(headers[7].generic->chain_diffs[0], Eq(6));
951 EXPECT_THAT(headers[8].generic->chain_diffs[0], Eq(8));
Danil Chapovalovaf366442021-04-22 13:20:28952}
953
Emil Lundmarkb01e6452021-09-14 09:46:44954TEST(RtpPayloadParamsVp9ToGenericTest, SpatialScalabilityKSvc) {
Danil Chapovalovaf366442021-04-22 13:20:28955 // 1---3--
956 // | ...
957 // 0---2--
Emil Lundmarkb01e6452021-09-14 09:46:44958 RtpPayloadState state;
959 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 13:20:28960
961 EncodedImage image;
962 CodecSpecificInfo info;
963 info.codecType = kVideoCodecVP9;
philipel4e0bf2e2023-06-20 08:29:20964 info.codecSpecific.VP9.flexible_mode = true;
Danil Chapovalovaf366442021-04-22 13:20:28965 info.codecSpecific.VP9.num_spatial_layers = 2;
966 info.codecSpecific.VP9.first_frame_in_picture = true;
967
968 RTPVideoHeader headers[4];
969 // Key frame.
970 image._frameType = VideoFrameType::kVideoFrameKey;
971 image.SetSpatialIndex(0);
972 info.codecSpecific.VP9.inter_pic_predicted = false;
973 info.codecSpecific.VP9.inter_layer_predicted = false;
974 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = false;
975 info.codecSpecific.VP9.num_ref_pics = 0;
976 info.codecSpecific.VP9.first_frame_in_picture = true;
977 info.end_of_picture = false;
978 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
979
980 image.SetSpatialIndex(1);
981 info.codecSpecific.VP9.inter_layer_predicted = true;
982 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
983 info.codecSpecific.VP9.first_frame_in_picture = false;
984 info.end_of_picture = true;
985 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
986
987 // Delta frames.
988 info.codecSpecific.VP9.inter_pic_predicted = true;
989 image._frameType = VideoFrameType::kVideoFrameDelta;
990 info.codecSpecific.VP9.num_ref_pics = 1;
991 info.codecSpecific.VP9.p_diff[0] = 1;
992
993 image.SetSpatialIndex(0);
994 info.codecSpecific.VP9.inter_layer_predicted = false;
995 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
996 info.codecSpecific.VP9.first_frame_in_picture = true;
997 info.end_of_picture = false;
998 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
999
1000 image.SetSpatialIndex(1);
1001 info.codecSpecific.VP9.inter_layer_predicted = false;
1002 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
1003 info.codecSpecific.VP9.first_frame_in_picture = false;
1004 info.end_of_picture = true;
1005 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
1006
1007 ASSERT_TRUE(headers[0].generic);
1008 int num_decode_targets = headers[0].generic->decode_target_indications.size();
1009 // Rely on implementation detail there are always kMaxTemporalStreams temporal
1010 // layers assumed, in particular assume Decode Target#0 matches layer S0T0,
1011 // and Decode Target#kMaxTemporalStreams matches layer S1T0.
Danil Chapovalov5b298ab2022-06-08 09:18:511012 ASSERT_GE(num_decode_targets, kMaxTemporalStreams * 2);
1013 int num_chains = headers[0].generic->chain_diffs.size();
1014 ASSERT_GE(num_chains, 2);
Danil Chapovalovaf366442021-04-22 13:20:281015
1016 for (int frame_idx = 0; frame_idx < 4; ++frame_idx) {
1017 const RTPVideoHeader& header = headers[frame_idx];
1018 ASSERT_TRUE(header.generic);
1019 EXPECT_EQ(header.generic->spatial_index, frame_idx % 2);
1020 EXPECT_EQ(header.generic->temporal_index, 0);
1021 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
1022 ASSERT_THAT(header.generic->decode_target_indications,
1023 SizeIs(num_decode_targets));
Danil Chapovalov5b298ab2022-06-08 09:18:511024 ASSERT_THAT(header.generic->chain_diffs, SizeIs(num_chains));
Danil Chapovalovaf366442021-04-22 13:20:281025 }
1026
1027 // Expect S0 key frame is switch for both Decode Targets.
1028 EXPECT_EQ(headers[0].generic->decode_target_indications[0],
1029 DecodeTargetIndication::kSwitch);
1030 EXPECT_EQ(headers[0].generic->decode_target_indications[kMaxTemporalStreams],
1031 DecodeTargetIndication::kSwitch);
1032 // S1 key frame is only needed for the 2nd Decode Targets.
1033 EXPECT_EQ(headers[1].generic->decode_target_indications[0],
1034 DecodeTargetIndication::kNotPresent);
1035 EXPECT_NE(headers[1].generic->decode_target_indications[kMaxTemporalStreams],
1036 DecodeTargetIndication::kNotPresent);
1037 // Delta frames are only needed for their own Decode Targets.
1038 EXPECT_NE(headers[2].generic->decode_target_indications[0],
1039 DecodeTargetIndication::kNotPresent);
1040 EXPECT_EQ(headers[2].generic->decode_target_indications[kMaxTemporalStreams],
1041 DecodeTargetIndication::kNotPresent);
1042 EXPECT_EQ(headers[3].generic->decode_target_indications[0],
1043 DecodeTargetIndication::kNotPresent);
1044 EXPECT_NE(headers[3].generic->decode_target_indications[kMaxTemporalStreams],
1045 DecodeTargetIndication::kNotPresent);
1046
1047 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // S0, 1
1048 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // S1, 3
1049 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // S0, 5
1050 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(3)); // S1, 7
1051
Danil Chapovalov5b298ab2022-06-08 09:18:511052 EXPECT_THAT(headers[0].generic->chain_diffs[0], Eq(0));
1053 EXPECT_THAT(headers[0].generic->chain_diffs[1], Eq(0));
1054 EXPECT_THAT(headers[1].generic->chain_diffs[0], Eq(2));
1055 EXPECT_THAT(headers[1].generic->chain_diffs[1], Eq(2));
1056 EXPECT_THAT(headers[2].generic->chain_diffs[0], Eq(4));
1057 EXPECT_THAT(headers[2].generic->chain_diffs[1], Eq(2));
1058 EXPECT_THAT(headers[3].generic->chain_diffs[0], Eq(2));
1059 EXPECT_THAT(headers[3].generic->chain_diffs[1], Eq(4));
1060}
1061
1062TEST(RtpPayloadParamsVp9ToGenericTest,
1063 IncreaseNumberOfSpatialLayersOnDeltaFrame) {
1064 // S1 5--
1065 // | ...
1066 // S0 1---3--
1067 RtpPayloadState state;
1068 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
1069
1070 EncodedImage image;
1071 CodecSpecificInfo info;
1072 info.codecType = kVideoCodecVP9;
philipel4e0bf2e2023-06-20 08:29:201073 info.codecSpecific.VP9.flexible_mode = true;
Danil Chapovalov5b298ab2022-06-08 09:18:511074 info.codecSpecific.VP9.num_spatial_layers = 1;
1075 info.codecSpecific.VP9.first_frame_in_picture = true;
1076
1077 RTPVideoHeader headers[3];
1078 // Key frame.
1079 image._frameType = VideoFrameType::kVideoFrameKey;
1080 image.SetSpatialIndex(0);
1081 info.codecSpecific.VP9.inter_pic_predicted = false;
1082 info.codecSpecific.VP9.inter_layer_predicted = false;
1083 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
1084 info.codecSpecific.VP9.num_ref_pics = 0;
1085 info.codecSpecific.VP9.first_frame_in_picture = true;
1086 info.end_of_picture = true;
1087 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
1088
1089 // S0 delta frame.
1090 image._frameType = VideoFrameType::kVideoFrameDelta;
1091 info.codecSpecific.VP9.num_spatial_layers = 2;
1092 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = false;
1093 info.codecSpecific.VP9.first_frame_in_picture = true;
1094 info.codecSpecific.VP9.inter_pic_predicted = true;
1095 info.codecSpecific.VP9.num_ref_pics = 1;
1096 info.codecSpecific.VP9.p_diff[0] = 1;
1097 info.end_of_picture = false;
1098 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
1099
1100 // S1 delta frame.
1101 image.SetSpatialIndex(1);
1102 info.codecSpecific.VP9.inter_layer_predicted = true;
1103 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
1104 info.codecSpecific.VP9.first_frame_in_picture = false;
1105 info.codecSpecific.VP9.inter_pic_predicted = false;
1106 info.end_of_picture = true;
1107 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
1108
1109 ASSERT_TRUE(headers[0].generic);
1110 int num_decode_targets = headers[0].generic->decode_target_indications.size();
1111 int num_chains = headers[0].generic->chain_diffs.size();
1112 // Rely on implementation detail there are always kMaxTemporalStreams temporal
1113 // layers. In particular assume Decode Target#0 matches layer S0T0, and
1114 // Decode Target#kMaxTemporalStreams matches layer S1T0.
1115 static constexpr int kS0T0 = 0;
1116 static constexpr int kS1T0 = kMaxTemporalStreams;
1117 ASSERT_GE(num_decode_targets, 2);
1118 ASSERT_GE(num_chains, 2);
1119
1120 for (int frame_idx = 0; frame_idx < 3; ++frame_idx) {
1121 const RTPVideoHeader& header = headers[frame_idx];
1122 ASSERT_TRUE(header.generic);
1123 EXPECT_EQ(header.generic->temporal_index, 0);
1124 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
1125 ASSERT_THAT(header.generic->decode_target_indications,
1126 SizeIs(num_decode_targets));
1127 ASSERT_THAT(header.generic->chain_diffs, SizeIs(num_chains));
1128 }
1129
1130 EXPECT_TRUE(headers[0].generic->active_decode_targets[kS0T0]);
1131 EXPECT_FALSE(headers[0].generic->active_decode_targets[kS1T0]);
1132
1133 EXPECT_TRUE(headers[1].generic->active_decode_targets[kS0T0]);
1134 EXPECT_TRUE(headers[1].generic->active_decode_targets[kS1T0]);
1135
1136 EXPECT_TRUE(headers[2].generic->active_decode_targets[kS0T0]);
1137 EXPECT_TRUE(headers[2].generic->active_decode_targets[kS1T0]);
1138
1139 EXPECT_EQ(headers[0].generic->decode_target_indications[kS0T0],
1140 DecodeTargetIndication::kSwitch);
1141
1142 EXPECT_EQ(headers[1].generic->decode_target_indications[kS0T0],
1143 DecodeTargetIndication::kSwitch);
1144
1145 EXPECT_EQ(headers[2].generic->decode_target_indications[kS0T0],
1146 DecodeTargetIndication::kNotPresent);
1147 EXPECT_EQ(headers[2].generic->decode_target_indications[kS1T0],
1148 DecodeTargetIndication::kSwitch);
1149
1150 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // S0, 1
1151 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // S0, 3
1152 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(3)); // S1, 5
1153
1154 EXPECT_EQ(headers[0].generic->chain_diffs[0], 0);
1155
1156 EXPECT_EQ(headers[1].generic->chain_diffs[0], 2);
1157 EXPECT_EQ(headers[1].generic->chain_diffs[1], 0);
1158
1159 EXPECT_EQ(headers[2].generic->chain_diffs[0], 2);
1160 EXPECT_EQ(headers[2].generic->chain_diffs[1], 2);
Danil Chapovalovaf366442021-04-22 13:20:281161}
1162
Danil Chapovalov7f41b0b2023-08-03 11:29:291163TEST(RtpPayloadParamsVp9ToGenericTest, ChangeFirstActiveLayer) {
1164 // S2 4---5
1165 //
1166 // S1 1---3 7
1167 //
1168 // S0 0---2 6
1169 RtpPayloadState state;
1170 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
1171
1172 EncodedImage image;
1173 CodecSpecificInfo info;
1174 info.codecType = kVideoCodecVP9;
1175 info.codecSpecific.VP9.flexible_mode = true;
1176 info.codecSpecific.VP9.first_frame_in_picture = true;
1177 info.codecSpecific.VP9.inter_layer_predicted = false;
1178 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
1179 info.codecSpecific.VP9.first_frame_in_picture = true;
1180 info.end_of_picture = true;
1181
1182 RTPVideoHeader headers[8];
1183 // S0 key frame.
1184 info.codecSpecific.VP9.num_spatial_layers = 2;
1185 info.codecSpecific.VP9.first_active_layer = 0;
1186 image._frameType = VideoFrameType::kVideoFrameKey;
1187 image.SetSpatialIndex(0);
1188 info.codecSpecific.VP9.inter_pic_predicted = false;
1189 info.codecSpecific.VP9.num_ref_pics = 0;
1190 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/0);
1191
1192 // S1 key frame.
1193 image._frameType = VideoFrameType::kVideoFrameKey;
1194 image.SetSpatialIndex(1);
1195 info.codecSpecific.VP9.inter_pic_predicted = false;
1196 info.codecSpecific.VP9.num_ref_pics = 0;
1197 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
1198
1199 // S0 delta frame.
1200 image._frameType = VideoFrameType::kVideoFrameDelta;
1201 image.SetSpatialIndex(0);
1202 info.codecSpecific.VP9.inter_pic_predicted = true;
1203 info.codecSpecific.VP9.num_ref_pics = 1;
1204 info.codecSpecific.VP9.p_diff[0] = 1;
1205 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/2);
1206
1207 // S1 delta frame.
1208 image._frameType = VideoFrameType::kVideoFrameDelta;
1209 info.codecSpecific.VP9.inter_pic_predicted = true;
1210 info.codecSpecific.VP9.num_ref_pics = 1;
1211 info.codecSpecific.VP9.p_diff[0] = 1;
1212 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
1213
1214 // S2 key frame
1215 info.codecSpecific.VP9.num_spatial_layers = 3;
1216 info.codecSpecific.VP9.first_active_layer = 2;
1217 image._frameType = VideoFrameType::kVideoFrameKey;
1218 image.SetSpatialIndex(2);
1219 info.codecSpecific.VP9.inter_pic_predicted = false;
1220 info.codecSpecific.VP9.num_ref_pics = 0;
1221 headers[4] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/4);
1222
1223 // S2 delta frame.
1224 image._frameType = VideoFrameType::kVideoFrameDelta;
1225 info.codecSpecific.VP9.inter_pic_predicted = true;
1226 info.codecSpecific.VP9.num_ref_pics = 1;
1227 info.codecSpecific.VP9.p_diff[0] = 1;
1228 headers[5] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
1229
1230 // S0 key frame after pause.
1231 info.codecSpecific.VP9.num_spatial_layers = 2;
1232 info.codecSpecific.VP9.first_active_layer = 0;
1233 image._frameType = VideoFrameType::kVideoFrameKey;
1234 image.SetSpatialIndex(0);
1235 info.codecSpecific.VP9.inter_pic_predicted = false;
1236 info.codecSpecific.VP9.num_ref_pics = 0;
1237 headers[6] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/6);
1238
1239 // S1 key frame.
1240 image._frameType = VideoFrameType::kVideoFrameKey;
1241 image.SetSpatialIndex(1);
1242 info.codecSpecific.VP9.inter_pic_predicted = false;
1243 info.codecSpecific.VP9.num_ref_pics = 0;
1244 headers[7] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
1245
1246 ASSERT_TRUE(headers[0].generic);
1247 int num_decode_targets = headers[0].generic->decode_target_indications.size();
1248 int num_chains = headers[0].generic->chain_diffs.size();
1249 // Rely on implementation detail there are always kMaxTemporalStreams temporal
1250 // layers. In particular assume Decode Target#0 matches layer S0T0, and
1251 // Decode Target#kMaxTemporalStreams matches layer S1T0.
1252 static constexpr int kS0T0 = 0;
1253 static constexpr int kS1T0 = kMaxTemporalStreams;
1254 static constexpr int kS2T0 = 2 * kMaxTemporalStreams;
1255 ASSERT_GE(num_decode_targets, 3);
1256 ASSERT_GE(num_chains, 3);
1257
1258 for (int frame_idx = 0; frame_idx < int{std::size(headers)}; ++frame_idx) {
1259 const RTPVideoHeader& header = headers[frame_idx];
1260 ASSERT_TRUE(header.generic);
1261 EXPECT_EQ(header.generic->temporal_index, 0);
1262 ASSERT_THAT(header.generic->decode_target_indications,
1263 SizeIs(num_decode_targets));
1264 ASSERT_THAT(header.generic->chain_diffs, SizeIs(num_chains));
1265 EXPECT_EQ(header.generic->frame_id, frame_idx);
1266 }
1267
1268 EXPECT_TRUE(headers[0].generic->active_decode_targets[kS0T0]);
1269 EXPECT_TRUE(headers[0].generic->active_decode_targets[kS1T0]);
1270 EXPECT_FALSE(headers[0].generic->active_decode_targets[kS2T0]);
1271
1272 EXPECT_FALSE(headers[4].generic->active_decode_targets[kS0T0]);
1273 EXPECT_FALSE(headers[4].generic->active_decode_targets[kS1T0]);
1274 EXPECT_TRUE(headers[4].generic->active_decode_targets[kS2T0]);
1275
1276 EXPECT_EQ(headers[1].generic->active_decode_targets,
1277 headers[0].generic->active_decode_targets);
1278
1279 EXPECT_EQ(headers[2].generic->active_decode_targets,
1280 headers[0].generic->active_decode_targets);
1281
1282 EXPECT_EQ(headers[3].generic->active_decode_targets,
1283 headers[0].generic->active_decode_targets);
1284
1285 EXPECT_EQ(headers[5].generic->active_decode_targets,
1286 headers[4].generic->active_decode_targets);
1287
1288 EXPECT_EQ(headers[6].generic->active_decode_targets,
1289 headers[0].generic->active_decode_targets);
1290
1291 EXPECT_EQ(headers[7].generic->active_decode_targets,
1292 headers[0].generic->active_decode_targets);
1293
1294 EXPECT_EQ(headers[0].generic->chain_diffs[0], 0);
1295 EXPECT_EQ(headers[0].generic->chain_diffs[1], 0);
1296 EXPECT_EQ(headers[0].generic->chain_diffs[2], 0);
1297
1298 EXPECT_EQ(headers[1].generic->chain_diffs[0], 1);
1299 EXPECT_EQ(headers[1].generic->chain_diffs[1], 0);
1300 EXPECT_EQ(headers[1].generic->chain_diffs[2], 0);
1301
1302 EXPECT_EQ(headers[2].generic->chain_diffs[0], 2);
1303 EXPECT_EQ(headers[2].generic->chain_diffs[1], 1);
1304 EXPECT_EQ(headers[2].generic->chain_diffs[2], 0);
1305
1306 EXPECT_EQ(headers[3].generic->chain_diffs[0], 1);
1307 EXPECT_EQ(headers[3].generic->chain_diffs[1], 2);
1308 EXPECT_EQ(headers[3].generic->chain_diffs[2], 0);
1309
1310 EXPECT_EQ(headers[4].generic->chain_diffs[0], 0);
1311 EXPECT_EQ(headers[4].generic->chain_diffs[1], 0);
1312 EXPECT_EQ(headers[4].generic->chain_diffs[2], 0);
1313
1314 EXPECT_EQ(headers[5].generic->chain_diffs[0], 0);
1315 EXPECT_EQ(headers[5].generic->chain_diffs[1], 0);
1316 EXPECT_EQ(headers[5].generic->chain_diffs[2], 1);
1317
1318 EXPECT_EQ(headers[6].generic->chain_diffs[0], 0);
1319 EXPECT_EQ(headers[6].generic->chain_diffs[1], 0);
1320 EXPECT_EQ(headers[6].generic->chain_diffs[2], 0);
1321
1322 EXPECT_EQ(headers[7].generic->chain_diffs[0], 1);
1323 EXPECT_EQ(headers[7].generic->chain_diffs[1], 0);
1324 EXPECT_EQ(headers[7].generic->chain_diffs[2], 0);
1325}
1326
philipel8aba8fe2019-06-13 13:13:161327class RtpPayloadParamsH264ToGenericTest : public ::testing::Test {
1328 public:
1329 enum LayerSync { kNoSync, kSync };
1330
1331 RtpPayloadParamsH264ToGenericTest()
Danil Chapovalov636865e2020-06-03 12:11:261332 : state_(), params_(123, &state_, trials_config_) {}
philipel8aba8fe2019-06-13 13:13:161333
1334 void ConvertAndCheck(int temporal_index,
1335 int64_t shared_frame_id,
1336 VideoFrameType frame_type,
1337 LayerSync layer_sync,
1338 const std::set<int64_t>& expected_deps,
1339 uint16_t width = 0,
1340 uint16_t height = 0) {
1341 EncodedImage encoded_image;
1342 encoded_image._frameType = frame_type;
1343 encoded_image._encodedWidth = width;
1344 encoded_image._encodedHeight = height;
1345
1346 CodecSpecificInfo codec_info;
1347 codec_info.codecType = kVideoCodecH264;
1348 codec_info.codecSpecific.H264.temporal_idx = temporal_index;
1349 codec_info.codecSpecific.H264.base_layer_sync = layer_sync == kSync;
1350
1351 RTPVideoHeader header =
1352 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
1353
1354 ASSERT_TRUE(header.generic);
philipel8aba8fe2019-06-13 13:13:161355 EXPECT_EQ(header.generic->spatial_index, 0);
1356
1357 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
1358 EXPECT_EQ(header.generic->temporal_index, temporal_index);
1359 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
1360 header.generic->dependencies.end());
1361 EXPECT_EQ(expected_deps, actual_deps);
1362
1363 EXPECT_EQ(header.width, width);
1364 EXPECT_EQ(header.height, height);
1365 }
1366
1367 protected:
Erik Språngcbc0cba2020-04-18 12:36:591368 FieldTrialBasedConfig trials_config_;
philipel8aba8fe2019-06-13 13:13:161369 RtpPayloadState state_;
1370 RtpPayloadParams params_;
1371};
1372
1373TEST_F(RtpPayloadParamsH264ToGenericTest, Keyframe) {
1374 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1375 ConvertAndCheck(0, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1376 ConvertAndCheck(0, 2, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1377}
1378
1379TEST_F(RtpPayloadParamsH264ToGenericTest, TooHighTemporalIndex) {
1380 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1381
1382 EncodedImage encoded_image;
1383 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
1384 CodecSpecificInfo codec_info;
1385 codec_info.codecType = kVideoCodecH264;
1386 codec_info.codecSpecific.H264.temporal_idx =
1387 RtpGenericFrameDescriptor::kMaxTemporalLayers;
1388 codec_info.codecSpecific.H264.base_layer_sync = false;
1389
1390 RTPVideoHeader header =
1391 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
1392 EXPECT_FALSE(header.generic);
1393}
1394
1395TEST_F(RtpPayloadParamsH264ToGenericTest, LayerSync) {
1396 // 02120212 pattern
1397 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1398 ConvertAndCheck(2, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1399 ConvertAndCheck(1, 2, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1400 ConvertAndCheck(2, 3, VideoFrameType::kVideoFrameDelta, kNoSync, {0, 1, 2});
1401
1402 ConvertAndCheck(0, 4, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1403 ConvertAndCheck(2, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {2, 3, 4});
1404 ConvertAndCheck(1, 6, VideoFrameType::kVideoFrameDelta, kSync,
1405 {4}); // layer sync
1406 ConvertAndCheck(2, 7, VideoFrameType::kVideoFrameDelta, kNoSync, {4, 5, 6});
1407}
1408
1409TEST_F(RtpPayloadParamsH264ToGenericTest, FrameIdGaps) {
1410 // 0101 pattern
1411 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1412 ConvertAndCheck(1, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1413
1414 ConvertAndCheck(0, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1415 ConvertAndCheck(1, 10, VideoFrameType::kVideoFrameDelta, kNoSync, {1, 5});
1416
1417 ConvertAndCheck(0, 15, VideoFrameType::kVideoFrameDelta, kNoSync, {5});
1418 ConvertAndCheck(1, 20, VideoFrameType::kVideoFrameDelta, kNoSync, {10, 15});
1419}
1420
Emil Lundmark6c81a422022-05-18 15:13:341421} // namespace
Stefan Holmerf7044682018-07-17 08:16:411422} // namespace webrtc