blob: 169a82d1989ecbecb6e436fffed11668b8a72bb7 [file] [log] [blame]
Stefan Holmerf7044682018-07-17 10:16:41 +02001/*
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 19:08:33 +020011#include "call/rtp_payload_params.h"
12
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Yves Gerey3e707812018-11-28 16:47:49 +010015#include <map>
philipelbf2b6202018-08-27 14:33:18 +020016#include <set>
Stefan Holmerf7044682018-07-17 10:16:41 +020017
Yves Gerey3e707812018-11-28 16:47:49 +010018#include "absl/container/inlined_vector.h"
19#include "absl/types/optional.h"
20#include "absl/types/variant.h"
Erik Språngcbc0cba2020-04-18 14:36:59 +020021#include "api/transport/field_trial_based_config.h"
Yves Gerey3e707812018-11-28 16:47:49 +010022#include "api/video/video_content_type.h"
23#include "api/video/video_rotation.h"
Yves Gerey3e707812018-11-28 16:47:49 +010024#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 10:16:41 +020028#include "modules/video_coding/include/video_codec_interface.h"
Danil Chapovalovaf366442021-04-22 15:20:28 +020029#include "test/explicit_key_value_config.h"
philipel8aba8fe2019-06-13 15:13:16 +020030#include "test/gmock.h"
Stefan Holmerf7044682018-07-17 10:16:41 +020031#include "test/gtest.h"
Jonas Orelandc7f691a2022-03-09 15:12:07 +010032#include "test/scoped_key_value_config.h"
Stefan Holmerf7044682018-07-17 10:16:41 +020033
Emil Lundmark6c81a422022-05-18 17:13:34 +020034namespace webrtc {
35namespace {
36
37using ::testing::AllOf;
Danil Chapovalovaf366442021-04-22 15:20:28 +020038using ::testing::Each;
Danil Chapovalovdc7fe402019-12-13 12:23:58 +010039using ::testing::ElementsAre;
philipel5b231de2021-09-01 15:21:16 +020040using ::testing::Eq;
Emil Lundmark6c81a422022-05-18 17:13:34 +020041using ::testing::Field;
Danil Chapovalovdc7fe402019-12-13 12:23:58 +010042using ::testing::IsEmpty;
Emil Lundmark6c81a422022-05-18 17:13:34 +020043using ::testing::Optional;
Danil Chapovalov4b860c12020-05-19 14:48:19 +020044using ::testing::SizeIs;
Danil Chapovalovdc7fe402019-12-13 12:23:58 +010045
Emil Lundmark6c81a422022-05-18 17:13:34 +020046using GenericDescriptorInfo = RTPVideoHeader::GenericDescriptorInfo;
47
Stefan Holmerf7044682018-07-17 10:16:41 +020048const 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 14:33:18 +020055const int64_t kDontCare = 0;
Stefan Holmerf7044682018-07-17 10:16:41 +020056
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 14:36:59 +020063 RtpPayloadParams params(kSsrc2, &state2, FieldTrialBasedConfig());
Stefan Holmerf7044682018-07-17 10:16:41 +020064 EncodedImage encoded_image;
65 encoded_image.rotation_ = kVideoRotation_90;
66 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
Niels Möllerd3b8c632018-08-27 15:33:42 +020067 encoded_image.SetSpatialIndex(1);
Stefan Holmerf7044682018-07-17 10:16:41 +020068
69 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 10:16:41 +020070 codec_info.codecType = kVideoCodecVP8;
philipelbf2b6202018-08-27 14:33:18 +020071 codec_info.codecSpecific.VP8.temporalIdx = 0;
Stefan Holmerf7044682018-07-17 10:16:41 +020072 codec_info.codecSpecific.VP8.keyIdx = kNoKeyIdx;
philipelbf2b6202018-08-27 14:33:18 +020073 codec_info.codecSpecific.VP8.layerSync = false;
Stefan Holmerf7044682018-07-17 10:16:41 +020074 codec_info.codecSpecific.VP8.nonReference = true;
75
philipelbf2b6202018-08-27 14:33:18 +020076 RTPVideoHeader header =
77 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
78
79 codec_info.codecType = kVideoCodecVP8;
philipelbf2b6202018-08-27 14:33:18 +020080 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 10:16:41 +020084
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:55 +000089 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 10:16:41 +020097}
98
99TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp9) {
100 RtpPayloadState state;
101 state.picture_id = kPictureId;
102 state.tl0_pic_idx = kTl0PicIdx;
Erik Språngcbc0cba2020-04-18 14:36:59 +0200103 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
Stefan Holmerf7044682018-07-17 10:16:41 +0200104
105 EncodedImage encoded_image;
106 encoded_image.rotation_ = kVideoRotation_90;
107 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200108 encoded_image.SetSpatialIndex(0);
Stefan Holmerf7044682018-07-17 10:16:41 +0200109 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 10:16:41 +0200110 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 10:16:41 +0200113 codec_info.codecSpecific.VP9.temporal_idx = 2;
Danil Chapovalov06bbeb32020-11-11 12:42:56 +0100114 codec_info.end_of_picture = false;
Stefan Holmerf7044682018-07-17 10:16:41 +0200115
philipelbf2b6202018-08-27 14:33:18 +0200116 RTPVideoHeader header =
117 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200118
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 14:18:53 +0100122 EXPECT_FALSE(header.color_space);
philipel29d88462018-08-08 14:26:00 +0200123 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 15:33:42 +0200128 EXPECT_EQ(vp9_header.spatial_idx, encoded_image.SpatialIndex());
philipel29d88462018-08-08 14:26:00 +0200129 EXPECT_EQ(vp9_header.num_spatial_layers,
Stefan Holmerf7044682018-07-17 10:16:41 +0200130 codec_info.codecSpecific.VP9.num_spatial_layers);
Danil Chapovalov06bbeb32020-11-11 12:42:56 +0100131 EXPECT_EQ(vp9_header.end_of_picture, codec_info.end_of_picture);
Stefan Holmerf7044682018-07-17 10:16:41 +0200132
133 // Next spatial layer.
134 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
Danil Chapovalov06bbeb32020-11-11 12:42:56 +0100135 codec_info.end_of_picture = true;
Stefan Holmerf7044682018-07-17 10:16:41 +0200136
Niels Möllerd3b8c632018-08-27 15:33:42 +0200137 encoded_image.SetSpatialIndex(1);
Johannes Krond0b69a82018-12-03 14:18:53 +0100138 ColorSpace color_space(
139 ColorSpace::PrimaryID::kSMPTE170M, ColorSpace::TransferID::kSMPTE170M,
140 ColorSpace::MatrixID::kSMPTE170M, ColorSpace::RangeID::kFull);
Danil Chapovalovb7698942019-02-05 11:32:19 +0100141 encoded_image.SetColorSpace(color_space);
philipelbf2b6202018-08-27 14:33:18 +0200142 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200143
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 14:18:53 +0100147 EXPECT_EQ(absl::make_optional(color_space), header.color_space);
philipel29d88462018-08-08 14:26:00 +0200148 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 15:33:42 +0200151 EXPECT_EQ(vp9_header.spatial_idx, encoded_image.SpatialIndex());
philipel29d88462018-08-08 14:26:00 +0200152 EXPECT_EQ(vp9_header.num_spatial_layers,
Stefan Holmerf7044682018-07-17 10:16:41 +0200153 codec_info.codecSpecific.VP9.num_spatial_layers);
Danil Chapovalov06bbeb32020-11-11 12:42:56 +0100154 EXPECT_EQ(vp9_header.end_of_picture, codec_info.end_of_picture);
Stefan Holmerf7044682018-07-17 10:16:41 +0200155}
156
Stefan Holmerf7044682018-07-17 10:16:41 +0200157TEST(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 10:16:41 +0200164 codec_info.codecType = kVideoCodecVP8;
Stefan Holmerf7044682018-07-17 10:16:41 +0200165
Erik Språngcbc0cba2020-04-18 14:36:59 +0200166 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 14:33:18 +0200167 RTPVideoHeader header =
168 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200169 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +0000170 EXPECT_EQ(kInitialPictureId1 + 1,
171 absl::get<RTPVideoHeaderVP8>(header.video_type_header).pictureId);
Stefan Holmerf7044682018-07-17 10:16:41 +0200172
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 10:16:41 +0200186 codec_info.codecType = kVideoCodecVP8;
187 codec_info.codecSpecific.VP8.temporalIdx = kNoTemporalIdx;
188
Erik Språngcbc0cba2020-04-18 14:36:59 +0200189 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 14:33:18 +0200190 RTPVideoHeader header =
191 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200192 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +0000193 EXPECT_EQ(0,
194 absl::get<RTPVideoHeaderVP8>(header.video_type_header).pictureId);
Stefan Holmerf7044682018-07-17 10:16:41 +0200195
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 17:13:34 +0200201TEST(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 10:16:41 +0200282TEST(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 10:16:41 +0200291 codec_info.codecType = kVideoCodecVP8;
292 codec_info.codecSpecific.VP8.temporalIdx = 1;
293
Erik Språngcbc0cba2020-04-18 14:36:59 +0200294 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 14:33:18 +0200295 RTPVideoHeader header =
296 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200297
298 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +0000299 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 10:16:41 +0200303
304 // OnEncodedImage, temporalIdx: 0.
305 codec_info.codecSpecific.VP8.temporalIdx = 0;
306
philipelbf2b6202018-08-27 14:33:18 +0200307 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200308 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +0000309 EXPECT_EQ(kInitialPictureId1 + 2, vp8_header.pictureId);
310 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp8_header.tl0PicIdx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200311
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 10:16:41 +0200326 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 14:36:59 +0200330 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 14:33:18 +0200331 RTPVideoHeader header =
332 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200333
334 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200335 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 10:16:41 +0200339
340 // OnEncodedImage, temporalIdx: 0.
341 codec_info.codecSpecific.VP9.temporal_idx = 0;
342
philipelbf2b6202018-08-27 14:33:18 +0200343 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200344
345 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200346 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
347 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200348
349 // OnEncodedImage, first_frame_in_picture = false
350 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
351
philipelbf2b6202018-08-27 14:33:18 +0200352 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200353
354 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200355 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
356 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200357
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 14:33:18 +0200362
363TEST(RtpPayloadParamsTest, PictureIdForOldGenericFormat) {
Jonas Orelandc7f691a2022-03-09 15:12:07 +0100364 test::ScopedKeyValueConfig field_trials("WebRTC-GenericPictureId/Enabled/");
philipelbf2b6202018-08-27 14:33:18 +0200365 RtpPayloadState state{};
366
367 EncodedImage encoded_image;
philipeld1d03592019-03-01 13:53:55 +0100368 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 14:33:18 +0200369 codec_info.codecType = kVideoCodecGeneric;
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100370 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
philipelbf2b6202018-08-27 14:33:18 +0200371
Jonas Orelandc7f691a2022-03-09 15:12:07 +0100372 RtpPayloadParams params(kSsrc1, &state, field_trials);
philipelbf2b6202018-08-27 14:33:18 +0200373 RTPVideoHeader header =
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100374 params.GetRtpVideoHeader(encoded_image, &codec_info, 10);
philipelbf2b6202018-08-27 14:33:18 +0200375
376 EXPECT_EQ(kVideoCodecGeneric, header.codec);
Danil Chapovalovb6bf0b22020-01-28 18:36:57 +0100377 const auto* generic =
378 absl::get_if<RTPVideoHeaderLegacyGeneric>(&header.video_type_header);
379 ASSERT_TRUE(generic);
380 EXPECT_EQ(0, generic->picture_id);
philipelbf2b6202018-08-27 14:33:18 +0200381
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100382 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
383 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 20);
Danil Chapovalovb6bf0b22020-01-28 18:36:57 +0100384 generic =
385 absl::get_if<RTPVideoHeaderLegacyGeneric>(&header.video_type_header);
386 ASSERT_TRUE(generic);
387 EXPECT_EQ(1, generic->picture_id);
philipelbf2b6202018-08-27 14:33:18 +0200388}
389
philipel8aba8fe2019-06-13 15:13:16 +0200390TEST(RtpPayloadParamsTest, GenericDescriptorForGenericCodec) {
philipel5b231de2021-09-01 15:21:16 +0200391 RtpPayloadState state;
philipel8aba8fe2019-06-13 15:13:16 +0200392
393 EncodedImage encoded_image;
394 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
395 CodecSpecificInfo codec_info;
396 codec_info.codecType = kVideoCodecGeneric;
397
Erik Språngcbc0cba2020-04-18 14:36:59 +0200398 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipel8aba8fe2019-06-13 15:13:16 +0200399 RTPVideoHeader header =
400 params.GetRtpVideoHeader(encoded_image, &codec_info, 0);
401
philipel5b231de2021-09-01 15:21:16 +0200402 EXPECT_THAT(header.codec, Eq(kVideoCodecGeneric));
403
philipel8aba8fe2019-06-13 15:13:16 +0200404 ASSERT_TRUE(header.generic);
philipel5b231de2021-09-01 15:21:16 +0200405 EXPECT_THAT(header.generic->frame_id, Eq(0));
406 EXPECT_THAT(header.generic->spatial_index, Eq(0));
407 EXPECT_THAT(header.generic->temporal_index, Eq(0));
408 EXPECT_THAT(header.generic->decode_target_indications,
409 ElementsAre(DecodeTargetIndication::kSwitch));
philipel8aba8fe2019-06-13 15:13:16 +0200410 EXPECT_THAT(header.generic->dependencies, IsEmpty());
philipel5b231de2021-09-01 15:21:16 +0200411 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(0));
philipel8aba8fe2019-06-13 15:13:16 +0200412
413 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
philipel5b231de2021-09-01 15:21:16 +0200414 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 3);
philipel8aba8fe2019-06-13 15:13:16 +0200415 ASSERT_TRUE(header.generic);
philipel5b231de2021-09-01 15:21:16 +0200416 EXPECT_THAT(header.generic->frame_id, Eq(3));
417 EXPECT_THAT(header.generic->spatial_index, Eq(0));
418 EXPECT_THAT(header.generic->temporal_index, Eq(0));
philipel8aba8fe2019-06-13 15:13:16 +0200419 EXPECT_THAT(header.generic->dependencies, ElementsAre(0));
philipel5b231de2021-09-01 15:21:16 +0200420 EXPECT_THAT(header.generic->decode_target_indications,
421 ElementsAre(DecodeTargetIndication::kSwitch));
422 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(3));
philipel8aba8fe2019-06-13 15:13:16 +0200423}
424
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100425TEST(RtpPayloadParamsTest, SetsGenericFromGenericFrameInfo) {
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100426 RtpPayloadState state;
427 EncodedImage encoded_image;
428 CodecSpecificInfo codec_info;
429
Erik Språngcbc0cba2020-04-18 14:36:59 +0200430 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100431
432 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
433 codec_info.generic_frame_info =
434 GenericFrameInfo::Builder().S(1).T(0).Dtis("S").Build();
435 codec_info.generic_frame_info->encoder_buffers = {
436 {/*id=*/0, /*referenced=*/false, /*updated=*/true}};
Danil Chapovalov4b860c12020-05-19 14:48:19 +0200437 codec_info.generic_frame_info->part_of_chain = {true, false};
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100438 RTPVideoHeader key_header =
439 params.GetRtpVideoHeader(encoded_image, &codec_info, /*frame_id=*/1);
440
441 ASSERT_TRUE(key_header.generic);
442 EXPECT_EQ(key_header.generic->spatial_index, 1);
443 EXPECT_EQ(key_header.generic->temporal_index, 0);
444 EXPECT_EQ(key_header.generic->frame_id, 1);
445 EXPECT_THAT(key_header.generic->dependencies, IsEmpty());
446 EXPECT_THAT(key_header.generic->decode_target_indications,
447 ElementsAre(DecodeTargetIndication::kSwitch));
Danil Chapovalov4b860c12020-05-19 14:48:19 +0200448 EXPECT_THAT(key_header.generic->chain_diffs, SizeIs(2));
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100449
450 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
451 codec_info.generic_frame_info =
452 GenericFrameInfo::Builder().S(2).T(3).Dtis("D").Build();
453 codec_info.generic_frame_info->encoder_buffers = {
454 {/*id=*/0, /*referenced=*/true, /*updated=*/false}};
Danil Chapovalov4b860c12020-05-19 14:48:19 +0200455 codec_info.generic_frame_info->part_of_chain = {false, false};
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100456 RTPVideoHeader delta_header =
457 params.GetRtpVideoHeader(encoded_image, &codec_info, /*frame_id=*/3);
458
459 ASSERT_TRUE(delta_header.generic);
460 EXPECT_EQ(delta_header.generic->spatial_index, 2);
461 EXPECT_EQ(delta_header.generic->temporal_index, 3);
462 EXPECT_EQ(delta_header.generic->frame_id, 3);
463 EXPECT_THAT(delta_header.generic->dependencies, ElementsAre(1));
464 EXPECT_THAT(delta_header.generic->decode_target_indications,
465 ElementsAre(DecodeTargetIndication::kDiscardable));
Danil Chapovalov4b860c12020-05-19 14:48:19 +0200466 EXPECT_THAT(delta_header.generic->chain_diffs, SizeIs(2));
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100467}
468
philipelbf2b6202018-08-27 14:33:18 +0200469class RtpPayloadParamsVp8ToGenericTest : public ::testing::Test {
470 public:
471 enum LayerSync { kNoSync, kSync };
472
philipel569397f2018-09-26 12:25:31 +0200473 RtpPayloadParamsVp8ToGenericTest()
Danil Chapovalov636865e2020-06-03 14:11:26 +0200474 : state_(), params_(123, &state_, trials_config_) {}
philipelbf2b6202018-08-27 14:33:18 +0200475
476 void ConvertAndCheck(int temporal_index,
477 int64_t shared_frame_id,
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000478 VideoFrameType frame_type,
philipelbf2b6202018-08-27 14:33:18 +0200479 LayerSync layer_sync,
philipelfab91292018-10-17 14:36:08 +0200480 const std::set<int64_t>& expected_deps,
481 uint16_t width = 0,
482 uint16_t height = 0) {
philipelbf2b6202018-08-27 14:33:18 +0200483 EncodedImage encoded_image;
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000484 encoded_image._frameType = frame_type;
philipelfab91292018-10-17 14:36:08 +0200485 encoded_image._encodedWidth = width;
486 encoded_image._encodedHeight = height;
philipelbf2b6202018-08-27 14:33:18 +0200487
philipeld1d03592019-03-01 13:53:55 +0100488 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 14:33:18 +0200489 codec_info.codecType = kVideoCodecVP8;
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000490 codec_info.codecSpecific.VP8.temporalIdx = temporal_index;
491 codec_info.codecSpecific.VP8.layerSync = layer_sync == kSync;
philipelbf2b6202018-08-27 14:33:18 +0200492
493 RTPVideoHeader header =
494 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
495
496 ASSERT_TRUE(header.generic);
philipelbf2b6202018-08-27 14:33:18 +0200497 EXPECT_EQ(header.generic->spatial_index, 0);
498
499 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
500 EXPECT_EQ(header.generic->temporal_index, temporal_index);
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000501 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
502 header.generic->dependencies.end());
503 EXPECT_EQ(expected_deps, actual_deps);
philipelfab91292018-10-17 14:36:08 +0200504
505 EXPECT_EQ(header.width, width);
506 EXPECT_EQ(header.height, height);
philipelbf2b6202018-08-27 14:33:18 +0200507 }
508
509 protected:
Erik Språngcbc0cba2020-04-18 14:36:59 +0200510 FieldTrialBasedConfig trials_config_;
philipelbf2b6202018-08-27 14:33:18 +0200511 RtpPayloadState state_;
512 RtpPayloadParams params_;
513};
514
515TEST_F(RtpPayloadParamsVp8ToGenericTest, Keyframe) {
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000516 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
517 ConvertAndCheck(0, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
518 ConvertAndCheck(0, 2, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
philipelbf2b6202018-08-27 14:33:18 +0200519}
520
521TEST_F(RtpPayloadParamsVp8ToGenericTest, TooHighTemporalIndex) {
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000522 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
philipelbf2b6202018-08-27 14:33:18 +0200523
524 EncodedImage encoded_image;
Niels Möller8f7ce222019-03-21 15:43:58 +0100525 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
philipeld1d03592019-03-01 13:53:55 +0100526 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 14:33:18 +0200527 codec_info.codecType = kVideoCodecVP8;
528 codec_info.codecSpecific.VP8.temporalIdx =
529 RtpGenericFrameDescriptor::kMaxTemporalLayers;
530 codec_info.codecSpecific.VP8.layerSync = false;
531
532 RTPVideoHeader header =
533 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
534 EXPECT_FALSE(header.generic);
535}
536
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000537TEST_F(RtpPayloadParamsVp8ToGenericTest, LayerSync) {
538 // 02120212 pattern
539 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
540 ConvertAndCheck(2, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
541 ConvertAndCheck(1, 2, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
542 ConvertAndCheck(2, 3, VideoFrameType::kVideoFrameDelta, kNoSync, {0, 1, 2});
philipelbf2b6202018-08-27 14:33:18 +0200543
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000544 ConvertAndCheck(0, 4, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
545 ConvertAndCheck(2, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {2, 3, 4});
546 ConvertAndCheck(1, 6, VideoFrameType::kVideoFrameDelta, kSync,
547 {4}); // layer sync
548 ConvertAndCheck(2, 7, VideoFrameType::kVideoFrameDelta, kNoSync, {4, 5, 6});
philipelbf2b6202018-08-27 14:33:18 +0200549}
550
551TEST_F(RtpPayloadParamsVp8ToGenericTest, FrameIdGaps) {
552 // 0101 pattern
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000553 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
554 ConvertAndCheck(1, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
philipelbf2b6202018-08-27 14:33:18 +0200555
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000556 ConvertAndCheck(0, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
557 ConvertAndCheck(1, 10, VideoFrameType::kVideoFrameDelta, kNoSync, {1, 5});
philipelbf2b6202018-08-27 14:33:18 +0200558
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000559 ConvertAndCheck(0, 15, VideoFrameType::kVideoFrameDelta, kNoSync, {5});
560 ConvertAndCheck(1, 20, VideoFrameType::kVideoFrameDelta, kNoSync, {10, 15});
philipelbf2b6202018-08-27 14:33:18 +0200561}
562
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200563TEST(RtpPayloadParamsVp9ToGenericTest, NoScalability) {
564 RtpPayloadState state;
565 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 15:20:28 +0200566
567 EncodedImage encoded_image;
568 CodecSpecificInfo codec_info;
569 codec_info.codecType = kVideoCodecVP9;
570 codec_info.codecSpecific.VP9.num_spatial_layers = 1;
571 codec_info.codecSpecific.VP9.temporal_idx = kNoTemporalIdx;
572 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
573 codec_info.end_of_picture = true;
574
575 // Key frame.
576 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
577 codec_info.codecSpecific.VP9.inter_pic_predicted = false;
578 codec_info.codecSpecific.VP9.num_ref_pics = 0;
579 RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info,
580 /*shared_frame_id=*/1);
581
582 ASSERT_TRUE(header.generic);
583 EXPECT_EQ(header.generic->spatial_index, 0);
584 EXPECT_EQ(header.generic->temporal_index, 0);
585 EXPECT_EQ(header.generic->frame_id, 1);
586 ASSERT_THAT(header.generic->decode_target_indications, Not(IsEmpty()));
587 EXPECT_EQ(header.generic->decode_target_indications[0],
588 DecodeTargetIndication::kSwitch);
589 EXPECT_THAT(header.generic->dependencies, IsEmpty());
590 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(0));
591
592 // Delta frame.
593 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
594 codec_info.codecSpecific.VP9.inter_pic_predicted = true;
595 codec_info.codecSpecific.VP9.num_ref_pics = 1;
596 codec_info.codecSpecific.VP9.p_diff[0] = 1;
597 header = params.GetRtpVideoHeader(encoded_image, &codec_info,
598 /*shared_frame_id=*/3);
599
600 ASSERT_TRUE(header.generic);
601 EXPECT_EQ(header.generic->spatial_index, 0);
602 EXPECT_EQ(header.generic->temporal_index, 0);
603 EXPECT_EQ(header.generic->frame_id, 3);
604 ASSERT_THAT(header.generic->decode_target_indications, Not(IsEmpty()));
605 EXPECT_EQ(header.generic->decode_target_indications[0],
606 DecodeTargetIndication::kSwitch);
607 EXPECT_THAT(header.generic->dependencies, ElementsAre(1));
608 // previous frame in the chain was frame#1,
609 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(3 - 1));
610}
611
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200612TEST(RtpPayloadParamsVp9ToGenericTest, TemporalScalabilityWith2Layers) {
Danil Chapovalovaf366442021-04-22 15:20:28 +0200613 // Test with 2 temporal layers structure that is not used by webrtc:
614 // 1---3 5
615 // / / / ...
616 // 0---2---4---
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200617 RtpPayloadState state;
618 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 15:20:28 +0200619
620 EncodedImage image;
621 CodecSpecificInfo info;
622 info.codecType = kVideoCodecVP9;
623 info.codecSpecific.VP9.num_spatial_layers = 1;
624 info.codecSpecific.VP9.first_frame_in_picture = true;
625 info.end_of_picture = true;
626
627 RTPVideoHeader headers[6];
628 // Key frame.
629 image._frameType = VideoFrameType::kVideoFrameKey;
630 info.codecSpecific.VP9.inter_pic_predicted = false;
631 info.codecSpecific.VP9.num_ref_pics = 0;
632 info.codecSpecific.VP9.temporal_up_switch = true;
633 info.codecSpecific.VP9.temporal_idx = 0;
634 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
635
636 // Delta frames.
637 info.codecSpecific.VP9.inter_pic_predicted = true;
638 image._frameType = VideoFrameType::kVideoFrameDelta;
639
640 info.codecSpecific.VP9.temporal_up_switch = true;
641 info.codecSpecific.VP9.temporal_idx = 1;
642 info.codecSpecific.VP9.num_ref_pics = 1;
643 info.codecSpecific.VP9.p_diff[0] = 1;
644 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
645
646 info.codecSpecific.VP9.temporal_up_switch = false;
647 info.codecSpecific.VP9.temporal_idx = 0;
648 info.codecSpecific.VP9.num_ref_pics = 1;
649 info.codecSpecific.VP9.p_diff[0] = 2;
650 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
651
652 info.codecSpecific.VP9.temporal_up_switch = false;
653 info.codecSpecific.VP9.temporal_idx = 1;
654 info.codecSpecific.VP9.num_ref_pics = 2;
655 info.codecSpecific.VP9.p_diff[0] = 1;
656 info.codecSpecific.VP9.p_diff[1] = 2;
657 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
658
659 info.codecSpecific.VP9.temporal_up_switch = true;
660 info.codecSpecific.VP9.temporal_idx = 0;
661 info.codecSpecific.VP9.num_ref_pics = 1;
662 info.codecSpecific.VP9.p_diff[0] = 2;
663 headers[4] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/9);
664
665 info.codecSpecific.VP9.temporal_up_switch = true;
666 info.codecSpecific.VP9.temporal_idx = 1;
667 info.codecSpecific.VP9.num_ref_pics = 1;
668 info.codecSpecific.VP9.p_diff[0] = 1;
669 headers[5] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/11);
670
671 ASSERT_TRUE(headers[0].generic);
672 int num_decode_targets = headers[0].generic->decode_target_indications.size();
673 ASSERT_GE(num_decode_targets, 2);
674
675 for (int frame_idx = 0; frame_idx < 6; ++frame_idx) {
676 const RTPVideoHeader& header = headers[frame_idx];
677 ASSERT_TRUE(header.generic);
678 EXPECT_EQ(header.generic->spatial_index, 0);
679 EXPECT_EQ(header.generic->temporal_index, frame_idx % 2);
680 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
681 ASSERT_THAT(header.generic->decode_target_indications,
682 SizeIs(num_decode_targets));
683 // Expect only T0 frames are needed for the 1st decode target.
684 if (header.generic->temporal_index == 0) {
685 EXPECT_NE(header.generic->decode_target_indications[0],
686 DecodeTargetIndication::kNotPresent);
687 } else {
688 EXPECT_EQ(header.generic->decode_target_indications[0],
689 DecodeTargetIndication::kNotPresent);
690 }
691 // Expect all frames are needed for the 2nd decode target.
692 EXPECT_NE(header.generic->decode_target_indications[1],
693 DecodeTargetIndication::kNotPresent);
694 }
695
696 // Expect switch at every beginning of the pattern.
697 EXPECT_THAT(headers[0].generic->decode_target_indications,
698 Each(DecodeTargetIndication::kSwitch));
699 EXPECT_THAT(headers[4].generic->decode_target_indications,
700 Each(DecodeTargetIndication::kSwitch));
701
702 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // T0, 1
703 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // T1, 3
704 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // T0, 5
705 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(5, 3)); // T1, 7
706 EXPECT_THAT(headers[4].generic->dependencies, ElementsAre(5)); // T0, 9
707 EXPECT_THAT(headers[5].generic->dependencies, ElementsAre(9)); // T1, 11
708
709 EXPECT_THAT(headers[0].generic->chain_diffs, ElementsAre(0));
710 EXPECT_THAT(headers[1].generic->chain_diffs, ElementsAre(2));
711 EXPECT_THAT(headers[2].generic->chain_diffs, ElementsAre(4));
712 EXPECT_THAT(headers[3].generic->chain_diffs, ElementsAre(2));
713 EXPECT_THAT(headers[4].generic->chain_diffs, ElementsAre(4));
714 EXPECT_THAT(headers[5].generic->chain_diffs, ElementsAre(2));
715}
716
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200717TEST(RtpPayloadParamsVp9ToGenericTest, TemporalScalabilityWith3Layers) {
Danil Chapovalovaf366442021-04-22 15:20:28 +0200718 // Test with 3 temporal layers structure that is not used by webrtc, but used
719 // by chromium: https://imgur.com/pURAGvp
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200720 RtpPayloadState state;
721 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 15:20:28 +0200722
723 EncodedImage image;
724 CodecSpecificInfo info;
725 info.codecType = kVideoCodecVP9;
726 info.codecSpecific.VP9.num_spatial_layers = 1;
727 info.codecSpecific.VP9.first_frame_in_picture = true;
728 info.end_of_picture = true;
729
730 RTPVideoHeader headers[9];
731 // Key frame.
732 image._frameType = VideoFrameType::kVideoFrameKey;
733 info.codecSpecific.VP9.inter_pic_predicted = false;
734 info.codecSpecific.VP9.num_ref_pics = 0;
735 info.codecSpecific.VP9.temporal_up_switch = true;
736 info.codecSpecific.VP9.temporal_idx = 0;
737 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
738
739 // Delta frames.
740 info.codecSpecific.VP9.inter_pic_predicted = true;
741 image._frameType = VideoFrameType::kVideoFrameDelta;
742
743 info.codecSpecific.VP9.temporal_up_switch = true;
744 info.codecSpecific.VP9.temporal_idx = 2;
745 info.codecSpecific.VP9.num_ref_pics = 1;
746 info.codecSpecific.VP9.p_diff[0] = 1;
747 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
748
749 info.codecSpecific.VP9.temporal_up_switch = true;
750 info.codecSpecific.VP9.temporal_idx = 1;
751 info.codecSpecific.VP9.num_ref_pics = 1;
752 info.codecSpecific.VP9.p_diff[0] = 2;
753 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
754
755 info.codecSpecific.VP9.temporal_up_switch = true;
756 info.codecSpecific.VP9.temporal_idx = 2;
757 info.codecSpecific.VP9.num_ref_pics = 1;
758 info.codecSpecific.VP9.p_diff[0] = 1;
759 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
760
761 info.codecSpecific.VP9.temporal_up_switch = false;
762 info.codecSpecific.VP9.temporal_idx = 0;
763 info.codecSpecific.VP9.num_ref_pics = 1;
764 info.codecSpecific.VP9.p_diff[0] = 4;
765 headers[4] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/9);
766
767 info.codecSpecific.VP9.temporal_up_switch = true;
768 info.codecSpecific.VP9.temporal_idx = 2;
769 info.codecSpecific.VP9.num_ref_pics = 2;
770 info.codecSpecific.VP9.p_diff[0] = 1;
771 info.codecSpecific.VP9.p_diff[1] = 3;
772 headers[5] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/11);
773
774 info.codecSpecific.VP9.temporal_up_switch = false;
775 info.codecSpecific.VP9.temporal_idx = 1;
776 info.codecSpecific.VP9.num_ref_pics = 2;
777 info.codecSpecific.VP9.p_diff[0] = 2;
778 info.codecSpecific.VP9.p_diff[1] = 4;
779 headers[6] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/13);
780
781 info.codecSpecific.VP9.temporal_up_switch = true;
782 info.codecSpecific.VP9.temporal_idx = 2;
783 info.codecSpecific.VP9.num_ref_pics = 1;
784 info.codecSpecific.VP9.p_diff[0] = 1;
785 headers[7] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/15);
786
787 info.codecSpecific.VP9.temporal_up_switch = true;
788 info.codecSpecific.VP9.temporal_idx = 0;
789 info.codecSpecific.VP9.num_ref_pics = 1;
790 info.codecSpecific.VP9.p_diff[0] = 4;
791 headers[8] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/17);
792
793 ASSERT_TRUE(headers[0].generic);
794 int num_decode_targets = headers[0].generic->decode_target_indications.size();
795 ASSERT_GE(num_decode_targets, 3);
796
797 for (int frame_idx = 0; frame_idx < 9; ++frame_idx) {
798 const RTPVideoHeader& header = headers[frame_idx];
799 ASSERT_TRUE(header.generic);
800 EXPECT_EQ(header.generic->spatial_index, 0);
801 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
802 ASSERT_THAT(header.generic->decode_target_indications,
803 SizeIs(num_decode_targets));
804 // Expect only T0 frames are needed for the 1st decode target.
805 if (header.generic->temporal_index == 0) {
806 EXPECT_NE(header.generic->decode_target_indications[0],
807 DecodeTargetIndication::kNotPresent);
808 } else {
809 EXPECT_EQ(header.generic->decode_target_indications[0],
810 DecodeTargetIndication::kNotPresent);
811 }
812 // Expect only T0 and T1 frames are needed for the 2nd decode target.
813 if (header.generic->temporal_index <= 1) {
814 EXPECT_NE(header.generic->decode_target_indications[1],
815 DecodeTargetIndication::kNotPresent);
816 } else {
817 EXPECT_EQ(header.generic->decode_target_indications[1],
818 DecodeTargetIndication::kNotPresent);
819 }
820 // Expect all frames are needed for the 3rd decode target.
821 EXPECT_NE(header.generic->decode_target_indications[2],
822 DecodeTargetIndication::kNotPresent);
823 }
824
825 EXPECT_EQ(headers[0].generic->temporal_index, 0);
826 EXPECT_EQ(headers[1].generic->temporal_index, 2);
827 EXPECT_EQ(headers[2].generic->temporal_index, 1);
828 EXPECT_EQ(headers[3].generic->temporal_index, 2);
829 EXPECT_EQ(headers[4].generic->temporal_index, 0);
830 EXPECT_EQ(headers[5].generic->temporal_index, 2);
831 EXPECT_EQ(headers[6].generic->temporal_index, 1);
832 EXPECT_EQ(headers[7].generic->temporal_index, 2);
833 EXPECT_EQ(headers[8].generic->temporal_index, 0);
834
835 // Expect switch at every beginning of the pattern.
836 EXPECT_THAT(headers[0].generic->decode_target_indications,
837 Each(DecodeTargetIndication::kSwitch));
838 EXPECT_THAT(headers[8].generic->decode_target_indications,
839 Each(DecodeTargetIndication::kSwitch));
840
841 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // T0, 1
842 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // T2, 3
843 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // T1, 5
844 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(5)); // T2, 7
845 EXPECT_THAT(headers[4].generic->dependencies, ElementsAre(1)); // T0, 9
846 EXPECT_THAT(headers[5].generic->dependencies, ElementsAre(9, 5)); // T2, 11
847 EXPECT_THAT(headers[6].generic->dependencies, ElementsAre(9, 5)); // T1, 13
848 EXPECT_THAT(headers[7].generic->dependencies, ElementsAre(13)); // T2, 15
849 EXPECT_THAT(headers[8].generic->dependencies, ElementsAre(9)); // T0, 17
850
851 EXPECT_THAT(headers[0].generic->chain_diffs, ElementsAre(0));
852 EXPECT_THAT(headers[1].generic->chain_diffs, ElementsAre(2));
853 EXPECT_THAT(headers[2].generic->chain_diffs, ElementsAre(4));
854 EXPECT_THAT(headers[3].generic->chain_diffs, ElementsAre(6));
855 EXPECT_THAT(headers[4].generic->chain_diffs, ElementsAre(8));
856 EXPECT_THAT(headers[5].generic->chain_diffs, ElementsAre(2));
857 EXPECT_THAT(headers[6].generic->chain_diffs, ElementsAre(4));
858 EXPECT_THAT(headers[7].generic->chain_diffs, ElementsAre(6));
859 EXPECT_THAT(headers[8].generic->chain_diffs, ElementsAre(8));
860}
861
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200862TEST(RtpPayloadParamsVp9ToGenericTest, SpatialScalabilityKSvc) {
Danil Chapovalovaf366442021-04-22 15:20:28 +0200863 // 1---3--
864 // | ...
865 // 0---2--
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200866 RtpPayloadState state;
867 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 15:20:28 +0200868
869 EncodedImage image;
870 CodecSpecificInfo info;
871 info.codecType = kVideoCodecVP9;
872 info.codecSpecific.VP9.num_spatial_layers = 2;
873 info.codecSpecific.VP9.first_frame_in_picture = true;
874
875 RTPVideoHeader headers[4];
876 // Key frame.
877 image._frameType = VideoFrameType::kVideoFrameKey;
878 image.SetSpatialIndex(0);
879 info.codecSpecific.VP9.inter_pic_predicted = false;
880 info.codecSpecific.VP9.inter_layer_predicted = false;
881 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = false;
882 info.codecSpecific.VP9.num_ref_pics = 0;
883 info.codecSpecific.VP9.first_frame_in_picture = true;
884 info.end_of_picture = false;
885 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
886
887 image.SetSpatialIndex(1);
888 info.codecSpecific.VP9.inter_layer_predicted = true;
889 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
890 info.codecSpecific.VP9.first_frame_in_picture = false;
891 info.end_of_picture = true;
892 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
893
894 // Delta frames.
895 info.codecSpecific.VP9.inter_pic_predicted = true;
896 image._frameType = VideoFrameType::kVideoFrameDelta;
897 info.codecSpecific.VP9.num_ref_pics = 1;
898 info.codecSpecific.VP9.p_diff[0] = 1;
899
900 image.SetSpatialIndex(0);
901 info.codecSpecific.VP9.inter_layer_predicted = false;
902 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
903 info.codecSpecific.VP9.first_frame_in_picture = true;
904 info.end_of_picture = false;
905 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
906
907 image.SetSpatialIndex(1);
908 info.codecSpecific.VP9.inter_layer_predicted = false;
909 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
910 info.codecSpecific.VP9.first_frame_in_picture = false;
911 info.end_of_picture = true;
912 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
913
914 ASSERT_TRUE(headers[0].generic);
915 int num_decode_targets = headers[0].generic->decode_target_indications.size();
916 // Rely on implementation detail there are always kMaxTemporalStreams temporal
917 // layers assumed, in particular assume Decode Target#0 matches layer S0T0,
918 // and Decode Target#kMaxTemporalStreams matches layer S1T0.
919 ASSERT_EQ(num_decode_targets, kMaxTemporalStreams * 2);
920
921 for (int frame_idx = 0; frame_idx < 4; ++frame_idx) {
922 const RTPVideoHeader& header = headers[frame_idx];
923 ASSERT_TRUE(header.generic);
924 EXPECT_EQ(header.generic->spatial_index, frame_idx % 2);
925 EXPECT_EQ(header.generic->temporal_index, 0);
926 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
927 ASSERT_THAT(header.generic->decode_target_indications,
928 SizeIs(num_decode_targets));
929 }
930
931 // Expect S0 key frame is switch for both Decode Targets.
932 EXPECT_EQ(headers[0].generic->decode_target_indications[0],
933 DecodeTargetIndication::kSwitch);
934 EXPECT_EQ(headers[0].generic->decode_target_indications[kMaxTemporalStreams],
935 DecodeTargetIndication::kSwitch);
936 // S1 key frame is only needed for the 2nd Decode Targets.
937 EXPECT_EQ(headers[1].generic->decode_target_indications[0],
938 DecodeTargetIndication::kNotPresent);
939 EXPECT_NE(headers[1].generic->decode_target_indications[kMaxTemporalStreams],
940 DecodeTargetIndication::kNotPresent);
941 // Delta frames are only needed for their own Decode Targets.
942 EXPECT_NE(headers[2].generic->decode_target_indications[0],
943 DecodeTargetIndication::kNotPresent);
944 EXPECT_EQ(headers[2].generic->decode_target_indications[kMaxTemporalStreams],
945 DecodeTargetIndication::kNotPresent);
946 EXPECT_EQ(headers[3].generic->decode_target_indications[0],
947 DecodeTargetIndication::kNotPresent);
948 EXPECT_NE(headers[3].generic->decode_target_indications[kMaxTemporalStreams],
949 DecodeTargetIndication::kNotPresent);
950
951 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // S0, 1
952 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // S1, 3
953 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // S0, 5
954 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(3)); // S1, 7
955
956 EXPECT_THAT(headers[0].generic->chain_diffs, ElementsAre(0, 0));
957 EXPECT_THAT(headers[1].generic->chain_diffs, ElementsAre(2, 2));
958 EXPECT_THAT(headers[2].generic->chain_diffs, ElementsAre(4, 2));
959 EXPECT_THAT(headers[3].generic->chain_diffs, ElementsAre(2, 4));
960}
961
philipel8aba8fe2019-06-13 15:13:16 +0200962class RtpPayloadParamsH264ToGenericTest : public ::testing::Test {
963 public:
964 enum LayerSync { kNoSync, kSync };
965
966 RtpPayloadParamsH264ToGenericTest()
Danil Chapovalov636865e2020-06-03 14:11:26 +0200967 : state_(), params_(123, &state_, trials_config_) {}
philipel8aba8fe2019-06-13 15:13:16 +0200968
969 void ConvertAndCheck(int temporal_index,
970 int64_t shared_frame_id,
971 VideoFrameType frame_type,
972 LayerSync layer_sync,
973 const std::set<int64_t>& expected_deps,
974 uint16_t width = 0,
975 uint16_t height = 0) {
976 EncodedImage encoded_image;
977 encoded_image._frameType = frame_type;
978 encoded_image._encodedWidth = width;
979 encoded_image._encodedHeight = height;
980
981 CodecSpecificInfo codec_info;
982 codec_info.codecType = kVideoCodecH264;
983 codec_info.codecSpecific.H264.temporal_idx = temporal_index;
984 codec_info.codecSpecific.H264.base_layer_sync = layer_sync == kSync;
985
986 RTPVideoHeader header =
987 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
988
989 ASSERT_TRUE(header.generic);
philipel8aba8fe2019-06-13 15:13:16 +0200990 EXPECT_EQ(header.generic->spatial_index, 0);
991
992 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
993 EXPECT_EQ(header.generic->temporal_index, temporal_index);
994 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
995 header.generic->dependencies.end());
996 EXPECT_EQ(expected_deps, actual_deps);
997
998 EXPECT_EQ(header.width, width);
999 EXPECT_EQ(header.height, height);
1000 }
1001
1002 protected:
Erik Språngcbc0cba2020-04-18 14:36:59 +02001003 FieldTrialBasedConfig trials_config_;
philipel8aba8fe2019-06-13 15:13:16 +02001004 RtpPayloadState state_;
1005 RtpPayloadParams params_;
1006};
1007
1008TEST_F(RtpPayloadParamsH264ToGenericTest, Keyframe) {
1009 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1010 ConvertAndCheck(0, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1011 ConvertAndCheck(0, 2, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1012}
1013
1014TEST_F(RtpPayloadParamsH264ToGenericTest, TooHighTemporalIndex) {
1015 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1016
1017 EncodedImage encoded_image;
1018 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
1019 CodecSpecificInfo codec_info;
1020 codec_info.codecType = kVideoCodecH264;
1021 codec_info.codecSpecific.H264.temporal_idx =
1022 RtpGenericFrameDescriptor::kMaxTemporalLayers;
1023 codec_info.codecSpecific.H264.base_layer_sync = false;
1024
1025 RTPVideoHeader header =
1026 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
1027 EXPECT_FALSE(header.generic);
1028}
1029
1030TEST_F(RtpPayloadParamsH264ToGenericTest, LayerSync) {
1031 // 02120212 pattern
1032 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1033 ConvertAndCheck(2, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1034 ConvertAndCheck(1, 2, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1035 ConvertAndCheck(2, 3, VideoFrameType::kVideoFrameDelta, kNoSync, {0, 1, 2});
1036
1037 ConvertAndCheck(0, 4, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1038 ConvertAndCheck(2, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {2, 3, 4});
1039 ConvertAndCheck(1, 6, VideoFrameType::kVideoFrameDelta, kSync,
1040 {4}); // layer sync
1041 ConvertAndCheck(2, 7, VideoFrameType::kVideoFrameDelta, kNoSync, {4, 5, 6});
1042}
1043
1044TEST_F(RtpPayloadParamsH264ToGenericTest, FrameIdGaps) {
1045 // 0101 pattern
1046 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
1047 ConvertAndCheck(1, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1048
1049 ConvertAndCheck(0, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
1050 ConvertAndCheck(1, 10, VideoFrameType::kVideoFrameDelta, kNoSync, {1, 5});
1051
1052 ConvertAndCheck(0, 15, VideoFrameType::kVideoFrameDelta, kNoSync, {5});
1053 ConvertAndCheck(1, 20, VideoFrameType::kVideoFrameDelta, kNoSync, {10, 15});
1054}
1055
Emil Lundmark6c81a422022-05-18 17:13:34 +02001056} // namespace
Stefan Holmerf7044682018-07-17 10:16:41 +02001057} // namespace webrtc