1 /*
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
11 #include "call/rtp_payload_params.h"
12
13 #include <string.h>
14
15 #include <map>
16 #include <set>
17
18 #include "absl/container/inlined_vector.h"
19 #include "absl/types/optional.h"
20 #include "absl/types/variant.h"
21 #include "api/transport/field_trial_based_config.h"
22 #include "api/video/video_content_type.h"
23 #include "api/video/video_rotation.h"
24 #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"
28 #include "modules/video_coding/include/video_codec_interface.h"
29 #include "test/field_trial.h"
30 #include "test/gmock.h"
31 #include "test/gtest.h"
32
33 using ::testing::ElementsAre;
34 using ::testing::IsEmpty;
35 using ::testing::SizeIs;
36
37 namespace webrtc {
38 namespace {
39 const uint32_t kSsrc1 = 12345;
40 const uint32_t kSsrc2 = 23456;
41 const int16_t kPictureId = 123;
42 const int16_t kTl0PicIdx = 20;
43 const uint8_t kTemporalIdx = 1;
44 const int16_t kInitialPictureId1 = 222;
45 const int16_t kInitialTl0PicIdx1 = 99;
46 const int64_t kDontCare = 0;
47 } // namespace
48
TEST(RtpPayloadParamsTest,InfoMappedToRtpVideoHeader_Vp8)49 TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp8) {
50 RtpPayloadState state2;
51 state2.picture_id = kPictureId;
52 state2.tl0_pic_idx = kTl0PicIdx;
53 std::map<uint32_t, RtpPayloadState> states = {{kSsrc2, state2}};
54
55 RtpPayloadParams params(kSsrc2, &state2, FieldTrialBasedConfig());
56 EncodedImage encoded_image;
57 encoded_image.rotation_ = kVideoRotation_90;
58 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
59 encoded_image.SetSpatialIndex(1);
60
61 CodecSpecificInfo codec_info;
62 codec_info.codecType = kVideoCodecVP8;
63 codec_info.codecSpecific.VP8.temporalIdx = 0;
64 codec_info.codecSpecific.VP8.keyIdx = kNoKeyIdx;
65 codec_info.codecSpecific.VP8.layerSync = false;
66 codec_info.codecSpecific.VP8.nonReference = true;
67
68 RTPVideoHeader header =
69 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
70
71 codec_info.codecType = kVideoCodecVP8;
72 codec_info.codecSpecific.VP8.temporalIdx = 1;
73 codec_info.codecSpecific.VP8.layerSync = true;
74
75 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 1);
76
77 EXPECT_EQ(kVideoRotation_90, header.rotation);
78 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
79 EXPECT_EQ(1, header.simulcastIdx);
80 EXPECT_EQ(kVideoCodecVP8, header.codec);
81 const auto& vp8_header =
82 absl::get<RTPVideoHeaderVP8>(header.video_type_header);
83 EXPECT_EQ(kPictureId + 2, vp8_header.pictureId);
84 EXPECT_EQ(kTemporalIdx, vp8_header.temporalIdx);
85 EXPECT_EQ(kTl0PicIdx + 1, vp8_header.tl0PicIdx);
86 EXPECT_EQ(kNoKeyIdx, vp8_header.keyIdx);
87 EXPECT_TRUE(vp8_header.layerSync);
88 EXPECT_TRUE(vp8_header.nonReference);
89 }
90
TEST(RtpPayloadParamsTest,InfoMappedToRtpVideoHeader_Vp9)91 TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp9) {
92 RtpPayloadState state;
93 state.picture_id = kPictureId;
94 state.tl0_pic_idx = kTl0PicIdx;
95 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
96
97 EncodedImage encoded_image;
98 encoded_image.rotation_ = kVideoRotation_90;
99 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
100 encoded_image.SetSpatialIndex(0);
101 CodecSpecificInfo codec_info;
102 codec_info.codecType = kVideoCodecVP9;
103 codec_info.codecSpecific.VP9.num_spatial_layers = 3;
104 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
105 codec_info.codecSpecific.VP9.temporal_idx = 2;
106 codec_info.codecSpecific.VP9.end_of_picture = false;
107
108 RTPVideoHeader header =
109 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
110
111 EXPECT_EQ(kVideoRotation_90, header.rotation);
112 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
113 EXPECT_EQ(kVideoCodecVP9, header.codec);
114 EXPECT_FALSE(header.color_space);
115 const auto& vp9_header =
116 absl::get<RTPVideoHeaderVP9>(header.video_type_header);
117 EXPECT_EQ(kPictureId + 1, vp9_header.picture_id);
118 EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx);
119 EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx);
120 EXPECT_EQ(vp9_header.spatial_idx, encoded_image.SpatialIndex());
121 EXPECT_EQ(vp9_header.num_spatial_layers,
122 codec_info.codecSpecific.VP9.num_spatial_layers);
123 EXPECT_EQ(vp9_header.end_of_picture,
124 codec_info.codecSpecific.VP9.end_of_picture);
125
126 // Next spatial layer.
127 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
128 codec_info.codecSpecific.VP9.end_of_picture = true;
129
130 encoded_image.SetSpatialIndex(1);
131 ColorSpace color_space(
132 ColorSpace::PrimaryID::kSMPTE170M, ColorSpace::TransferID::kSMPTE170M,
133 ColorSpace::MatrixID::kSMPTE170M, ColorSpace::RangeID::kFull);
134 encoded_image.SetColorSpace(color_space);
135 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
136
137 EXPECT_EQ(kVideoRotation_90, header.rotation);
138 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
139 EXPECT_EQ(kVideoCodecVP9, header.codec);
140 EXPECT_EQ(absl::make_optional(color_space), header.color_space);
141 EXPECT_EQ(kPictureId + 1, vp9_header.picture_id);
142 EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx);
143 EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx);
144 EXPECT_EQ(vp9_header.spatial_idx, encoded_image.SpatialIndex());
145 EXPECT_EQ(vp9_header.num_spatial_layers,
146 codec_info.codecSpecific.VP9.num_spatial_layers);
147 EXPECT_EQ(vp9_header.end_of_picture,
148 codec_info.codecSpecific.VP9.end_of_picture);
149 }
150
TEST(RtpPayloadParamsTest,PictureIdIsSetForVp8)151 TEST(RtpPayloadParamsTest, PictureIdIsSetForVp8) {
152 RtpPayloadState state;
153 state.picture_id = kInitialPictureId1;
154 state.tl0_pic_idx = kInitialTl0PicIdx1;
155
156 EncodedImage encoded_image;
157 CodecSpecificInfo codec_info;
158 codec_info.codecType = kVideoCodecVP8;
159
160 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
161 RTPVideoHeader header =
162 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
163 EXPECT_EQ(kVideoCodecVP8, header.codec);
164 EXPECT_EQ(kInitialPictureId1 + 1,
165 absl::get<RTPVideoHeaderVP8>(header.video_type_header).pictureId);
166
167 // State should hold latest used picture id and tl0_pic_idx.
168 state = params.state();
169 EXPECT_EQ(kInitialPictureId1 + 1, state.picture_id);
170 EXPECT_EQ(kInitialTl0PicIdx1 + 1, state.tl0_pic_idx);
171 }
172
TEST(RtpPayloadParamsTest,PictureIdWraps)173 TEST(RtpPayloadParamsTest, PictureIdWraps) {
174 RtpPayloadState state;
175 state.picture_id = kMaxTwoBytePictureId;
176 state.tl0_pic_idx = kInitialTl0PicIdx1;
177
178 EncodedImage encoded_image;
179 CodecSpecificInfo codec_info;
180 codec_info.codecType = kVideoCodecVP8;
181 codec_info.codecSpecific.VP8.temporalIdx = kNoTemporalIdx;
182
183 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
184 RTPVideoHeader header =
185 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
186 EXPECT_EQ(kVideoCodecVP8, header.codec);
187 EXPECT_EQ(0,
188 absl::get<RTPVideoHeaderVP8>(header.video_type_header).pictureId);
189
190 // State should hold latest used picture id and tl0_pic_idx.
191 EXPECT_EQ(0, params.state().picture_id); // Wrapped.
192 EXPECT_EQ(kInitialTl0PicIdx1, params.state().tl0_pic_idx);
193 }
194
TEST(RtpPayloadParamsTest,Tl0PicIdxUpdatedForVp8)195 TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp8) {
196 RtpPayloadState state;
197 state.picture_id = kInitialPictureId1;
198 state.tl0_pic_idx = kInitialTl0PicIdx1;
199
200 EncodedImage encoded_image;
201 // Modules are sending for this test.
202 // OnEncodedImage, temporalIdx: 1.
203 CodecSpecificInfo codec_info;
204 codec_info.codecType = kVideoCodecVP8;
205 codec_info.codecSpecific.VP8.temporalIdx = 1;
206
207 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
208 RTPVideoHeader header =
209 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
210
211 EXPECT_EQ(kVideoCodecVP8, header.codec);
212 const auto& vp8_header =
213 absl::get<RTPVideoHeaderVP8>(header.video_type_header);
214 EXPECT_EQ(kInitialPictureId1 + 1, vp8_header.pictureId);
215 EXPECT_EQ(kInitialTl0PicIdx1, vp8_header.tl0PicIdx);
216
217 // OnEncodedImage, temporalIdx: 0.
218 codec_info.codecSpecific.VP8.temporalIdx = 0;
219
220 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
221 EXPECT_EQ(kVideoCodecVP8, header.codec);
222 EXPECT_EQ(kInitialPictureId1 + 2, vp8_header.pictureId);
223 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp8_header.tl0PicIdx);
224
225 // State should hold latest used picture id and tl0_pic_idx.
226 EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id);
227 EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx);
228 }
229
TEST(RtpPayloadParamsTest,Tl0PicIdxUpdatedForVp9)230 TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp9) {
231 RtpPayloadState state;
232 state.picture_id = kInitialPictureId1;
233 state.tl0_pic_idx = kInitialTl0PicIdx1;
234
235 EncodedImage encoded_image;
236 // Modules are sending for this test.
237 // OnEncodedImage, temporalIdx: 1.
238 CodecSpecificInfo codec_info;
239 codec_info.codecType = kVideoCodecVP9;
240 codec_info.codecSpecific.VP9.temporal_idx = 1;
241 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
242
243 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
244 RTPVideoHeader header =
245 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
246
247 EXPECT_EQ(kVideoCodecVP9, header.codec);
248 const auto& vp9_header =
249 absl::get<RTPVideoHeaderVP9>(header.video_type_header);
250 EXPECT_EQ(kInitialPictureId1 + 1, vp9_header.picture_id);
251 EXPECT_EQ(kInitialTl0PicIdx1, vp9_header.tl0_pic_idx);
252
253 // OnEncodedImage, temporalIdx: 0.
254 codec_info.codecSpecific.VP9.temporal_idx = 0;
255
256 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
257
258 EXPECT_EQ(kVideoCodecVP9, header.codec);
259 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
260 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
261
262 // OnEncodedImage, first_frame_in_picture = false
263 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
264
265 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
266
267 EXPECT_EQ(kVideoCodecVP9, header.codec);
268 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
269 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
270
271 // State should hold latest used picture id and tl0_pic_idx.
272 EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id);
273 EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx);
274 }
275
TEST(RtpPayloadParamsTest,PictureIdForOldGenericFormat)276 TEST(RtpPayloadParamsTest, PictureIdForOldGenericFormat) {
277 test::ScopedFieldTrials generic_picture_id(
278 "WebRTC-GenericPictureId/Enabled/");
279 RtpPayloadState state{};
280
281 EncodedImage encoded_image;
282 CodecSpecificInfo codec_info;
283 codec_info.codecType = kVideoCodecGeneric;
284 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
285
286 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
287 RTPVideoHeader header =
288 params.GetRtpVideoHeader(encoded_image, &codec_info, 10);
289
290 EXPECT_EQ(kVideoCodecGeneric, header.codec);
291 const auto* generic =
292 absl::get_if<RTPVideoHeaderLegacyGeneric>(&header.video_type_header);
293 ASSERT_TRUE(generic);
294 EXPECT_EQ(0, generic->picture_id);
295
296 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
297 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 20);
298 generic =
299 absl::get_if<RTPVideoHeaderLegacyGeneric>(&header.video_type_header);
300 ASSERT_TRUE(generic);
301 EXPECT_EQ(1, generic->picture_id);
302 }
303
TEST(RtpPayloadParamsTest,GenericDescriptorForGenericCodec)304 TEST(RtpPayloadParamsTest, GenericDescriptorForGenericCodec) {
305 RtpPayloadState state{};
306
307 EncodedImage encoded_image;
308 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
309 CodecSpecificInfo codec_info;
310 codec_info.codecType = kVideoCodecGeneric;
311
312 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
313 RTPVideoHeader header =
314 params.GetRtpVideoHeader(encoded_image, &codec_info, 0);
315
316 EXPECT_EQ(kVideoCodecGeneric, header.codec);
317 ASSERT_TRUE(header.generic);
318 EXPECT_EQ(0, header.generic->frame_id);
319 EXPECT_THAT(header.generic->dependencies, IsEmpty());
320
321 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
322 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 1);
323 ASSERT_TRUE(header.generic);
324 EXPECT_EQ(1, header.generic->frame_id);
325 EXPECT_THAT(header.generic->dependencies, ElementsAre(0));
326 }
327
TEST(RtpPayloadParamsTest,SetsGenericFromGenericFrameInfo)328 TEST(RtpPayloadParamsTest, SetsGenericFromGenericFrameInfo) {
329 RtpPayloadState state;
330 EncodedImage encoded_image;
331 CodecSpecificInfo codec_info;
332
333 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
334
335 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
336 codec_info.generic_frame_info =
337 GenericFrameInfo::Builder().S(1).T(0).Dtis("S").Build();
338 codec_info.generic_frame_info->encoder_buffers = {
339 {/*id=*/0, /*referenced=*/false, /*updated=*/true}};
340 codec_info.generic_frame_info->part_of_chain = {true, false};
341 RTPVideoHeader key_header =
342 params.GetRtpVideoHeader(encoded_image, &codec_info, /*frame_id=*/1);
343
344 ASSERT_TRUE(key_header.generic);
345 EXPECT_EQ(key_header.generic->spatial_index, 1);
346 EXPECT_EQ(key_header.generic->temporal_index, 0);
347 EXPECT_EQ(key_header.generic->frame_id, 1);
348 EXPECT_THAT(key_header.generic->dependencies, IsEmpty());
349 EXPECT_THAT(key_header.generic->decode_target_indications,
350 ElementsAre(DecodeTargetIndication::kSwitch));
351 EXPECT_THAT(key_header.generic->chain_diffs, SizeIs(2));
352
353 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
354 codec_info.generic_frame_info =
355 GenericFrameInfo::Builder().S(2).T(3).Dtis("D").Build();
356 codec_info.generic_frame_info->encoder_buffers = {
357 {/*id=*/0, /*referenced=*/true, /*updated=*/false}};
358 codec_info.generic_frame_info->part_of_chain = {false, false};
359 RTPVideoHeader delta_header =
360 params.GetRtpVideoHeader(encoded_image, &codec_info, /*frame_id=*/3);
361
362 ASSERT_TRUE(delta_header.generic);
363 EXPECT_EQ(delta_header.generic->spatial_index, 2);
364 EXPECT_EQ(delta_header.generic->temporal_index, 3);
365 EXPECT_EQ(delta_header.generic->frame_id, 3);
366 EXPECT_THAT(delta_header.generic->dependencies, ElementsAre(1));
367 EXPECT_THAT(delta_header.generic->decode_target_indications,
368 ElementsAre(DecodeTargetIndication::kDiscardable));
369 EXPECT_THAT(delta_header.generic->chain_diffs, SizeIs(2));
370 }
371
372 class RtpPayloadParamsVp8ToGenericTest : public ::testing::Test {
373 public:
374 enum LayerSync { kNoSync, kSync };
375
RtpPayloadParamsVp8ToGenericTest()376 RtpPayloadParamsVp8ToGenericTest()
377 : state_(), params_(123, &state_, trials_config_) {}
378
ConvertAndCheck(int temporal_index,int64_t shared_frame_id,VideoFrameType frame_type,LayerSync layer_sync,const std::set<int64_t> & expected_deps,uint16_t width=0,uint16_t height=0)379 void ConvertAndCheck(int temporal_index,
380 int64_t shared_frame_id,
381 VideoFrameType frame_type,
382 LayerSync layer_sync,
383 const std::set<int64_t>& expected_deps,
384 uint16_t width = 0,
385 uint16_t height = 0) {
386 EncodedImage encoded_image;
387 encoded_image._frameType = frame_type;
388 encoded_image._encodedWidth = width;
389 encoded_image._encodedHeight = height;
390
391 CodecSpecificInfo codec_info;
392 codec_info.codecType = kVideoCodecVP8;
393 codec_info.codecSpecific.VP8.temporalIdx = temporal_index;
394 codec_info.codecSpecific.VP8.layerSync = layer_sync == kSync;
395
396 RTPVideoHeader header =
397 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
398
399 ASSERT_TRUE(header.generic);
400 EXPECT_EQ(header.generic->spatial_index, 0);
401
402 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
403 EXPECT_EQ(header.generic->temporal_index, temporal_index);
404 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
405 header.generic->dependencies.end());
406 EXPECT_EQ(expected_deps, actual_deps);
407
408 EXPECT_EQ(header.width, width);
409 EXPECT_EQ(header.height, height);
410 }
411
412 protected:
413 FieldTrialBasedConfig trials_config_;
414 RtpPayloadState state_;
415 RtpPayloadParams params_;
416 };
417
TEST_F(RtpPayloadParamsVp8ToGenericTest,Keyframe)418 TEST_F(RtpPayloadParamsVp8ToGenericTest, Keyframe) {
419 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
420 ConvertAndCheck(0, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
421 ConvertAndCheck(0, 2, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
422 }
423
TEST_F(RtpPayloadParamsVp8ToGenericTest,TooHighTemporalIndex)424 TEST_F(RtpPayloadParamsVp8ToGenericTest, TooHighTemporalIndex) {
425 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
426
427 EncodedImage encoded_image;
428 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
429 CodecSpecificInfo codec_info;
430 codec_info.codecType = kVideoCodecVP8;
431 codec_info.codecSpecific.VP8.temporalIdx =
432 RtpGenericFrameDescriptor::kMaxTemporalLayers;
433 codec_info.codecSpecific.VP8.layerSync = false;
434
435 RTPVideoHeader header =
436 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
437 EXPECT_FALSE(header.generic);
438 }
439
TEST_F(RtpPayloadParamsVp8ToGenericTest,LayerSync)440 TEST_F(RtpPayloadParamsVp8ToGenericTest, LayerSync) {
441 // 02120212 pattern
442 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
443 ConvertAndCheck(2, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
444 ConvertAndCheck(1, 2, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
445 ConvertAndCheck(2, 3, VideoFrameType::kVideoFrameDelta, kNoSync, {0, 1, 2});
446
447 ConvertAndCheck(0, 4, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
448 ConvertAndCheck(2, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {2, 3, 4});
449 ConvertAndCheck(1, 6, VideoFrameType::kVideoFrameDelta, kSync,
450 {4}); // layer sync
451 ConvertAndCheck(2, 7, VideoFrameType::kVideoFrameDelta, kNoSync, {4, 5, 6});
452 }
453
TEST_F(RtpPayloadParamsVp8ToGenericTest,FrameIdGaps)454 TEST_F(RtpPayloadParamsVp8ToGenericTest, FrameIdGaps) {
455 // 0101 pattern
456 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
457 ConvertAndCheck(1, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
458
459 ConvertAndCheck(0, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
460 ConvertAndCheck(1, 10, VideoFrameType::kVideoFrameDelta, kNoSync, {1, 5});
461
462 ConvertAndCheck(0, 15, VideoFrameType::kVideoFrameDelta, kNoSync, {5});
463 ConvertAndCheck(1, 20, VideoFrameType::kVideoFrameDelta, kNoSync, {10, 15});
464 }
465
466 class RtpPayloadParamsH264ToGenericTest : public ::testing::Test {
467 public:
468 enum LayerSync { kNoSync, kSync };
469
RtpPayloadParamsH264ToGenericTest()470 RtpPayloadParamsH264ToGenericTest()
471 : state_(), params_(123, &state_, trials_config_) {}
472
ConvertAndCheck(int temporal_index,int64_t shared_frame_id,VideoFrameType frame_type,LayerSync layer_sync,const std::set<int64_t> & expected_deps,uint16_t width=0,uint16_t height=0)473 void ConvertAndCheck(int temporal_index,
474 int64_t shared_frame_id,
475 VideoFrameType frame_type,
476 LayerSync layer_sync,
477 const std::set<int64_t>& expected_deps,
478 uint16_t width = 0,
479 uint16_t height = 0) {
480 EncodedImage encoded_image;
481 encoded_image._frameType = frame_type;
482 encoded_image._encodedWidth = width;
483 encoded_image._encodedHeight = height;
484
485 CodecSpecificInfo codec_info;
486 codec_info.codecType = kVideoCodecH264;
487 codec_info.codecSpecific.H264.temporal_idx = temporal_index;
488 codec_info.codecSpecific.H264.base_layer_sync = layer_sync == kSync;
489
490 RTPVideoHeader header =
491 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
492
493 ASSERT_TRUE(header.generic);
494 EXPECT_EQ(header.generic->spatial_index, 0);
495
496 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
497 EXPECT_EQ(header.generic->temporal_index, temporal_index);
498 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
499 header.generic->dependencies.end());
500 EXPECT_EQ(expected_deps, actual_deps);
501
502 EXPECT_EQ(header.width, width);
503 EXPECT_EQ(header.height, height);
504 }
505
506 protected:
507 FieldTrialBasedConfig trials_config_;
508 RtpPayloadState state_;
509 RtpPayloadParams params_;
510 };
511
TEST_F(RtpPayloadParamsH264ToGenericTest,Keyframe)512 TEST_F(RtpPayloadParamsH264ToGenericTest, Keyframe) {
513 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
514 ConvertAndCheck(0, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
515 ConvertAndCheck(0, 2, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
516 }
517
TEST_F(RtpPayloadParamsH264ToGenericTest,TooHighTemporalIndex)518 TEST_F(RtpPayloadParamsH264ToGenericTest, TooHighTemporalIndex) {
519 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
520
521 EncodedImage encoded_image;
522 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
523 CodecSpecificInfo codec_info;
524 codec_info.codecType = kVideoCodecH264;
525 codec_info.codecSpecific.H264.temporal_idx =
526 RtpGenericFrameDescriptor::kMaxTemporalLayers;
527 codec_info.codecSpecific.H264.base_layer_sync = false;
528
529 RTPVideoHeader header =
530 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
531 EXPECT_FALSE(header.generic);
532 }
533
TEST_F(RtpPayloadParamsH264ToGenericTest,LayerSync)534 TEST_F(RtpPayloadParamsH264ToGenericTest, LayerSync) {
535 // 02120212 pattern
536 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
537 ConvertAndCheck(2, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
538 ConvertAndCheck(1, 2, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
539 ConvertAndCheck(2, 3, VideoFrameType::kVideoFrameDelta, kNoSync, {0, 1, 2});
540
541 ConvertAndCheck(0, 4, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
542 ConvertAndCheck(2, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {2, 3, 4});
543 ConvertAndCheck(1, 6, VideoFrameType::kVideoFrameDelta, kSync,
544 {4}); // layer sync
545 ConvertAndCheck(2, 7, VideoFrameType::kVideoFrameDelta, kNoSync, {4, 5, 6});
546 }
547
TEST_F(RtpPayloadParamsH264ToGenericTest,FrameIdGaps)548 TEST_F(RtpPayloadParamsH264ToGenericTest, FrameIdGaps) {
549 // 0101 pattern
550 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
551 ConvertAndCheck(1, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
552
553 ConvertAndCheck(0, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
554 ConvertAndCheck(1, 10, VideoFrameType::kVideoFrameDelta, kNoSync, {1, 5});
555
556 ConvertAndCheck(0, 15, VideoFrameType::kVideoFrameDelta, kNoSync, {5});
557 ConvertAndCheck(1, 20, VideoFrameType::kVideoFrameDelta, kNoSync, {10, 15});
558 }
559
560 } // namespace webrtc
561