blob: 4d0b017fa01f2ab02b9476607abfd49c6d0acbfd [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
11#include <memory>
philipelbf2b6202018-08-27 14:33:18 +020012#include <set>
Stefan Holmerf7044682018-07-17 10:16:41 +020013
Stefan Holmer9416ef82018-07-19 10:34:38 +020014#include "call/rtp_payload_params.h"
Stefan Holmerf7044682018-07-17 10:16:41 +020015#include "modules/video_coding/include/video_codec_interface.h"
philipelbf2b6202018-08-27 14:33:18 +020016#include "test/field_trial.h"
Stefan Holmerf7044682018-07-17 10:16:41 +020017#include "test/gtest.h"
18
19namespace webrtc {
20namespace {
21const uint32_t kSsrc1 = 12345;
22const uint32_t kSsrc2 = 23456;
23const int16_t kPictureId = 123;
24const int16_t kTl0PicIdx = 20;
25const uint8_t kTemporalIdx = 1;
26const int16_t kInitialPictureId1 = 222;
27const int16_t kInitialTl0PicIdx1 = 99;
philipelbf2b6202018-08-27 14:33:18 +020028const int64_t kDontCare = 0;
Stefan Holmerf7044682018-07-17 10:16:41 +020029} // namespace
30
31TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp8) {
32 RtpPayloadState state2;
33 state2.picture_id = kPictureId;
34 state2.tl0_pic_idx = kTl0PicIdx;
35 std::map<uint32_t, RtpPayloadState> states = {{kSsrc2, state2}};
36
37 RtpPayloadParams params(kSsrc2, &state2);
38 EncodedImage encoded_image;
39 encoded_image.rotation_ = kVideoRotation_90;
40 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
41
42 CodecSpecificInfo codec_info;
43 memset(&codec_info, 0, sizeof(CodecSpecificInfo));
44 codec_info.codecType = kVideoCodecVP8;
Niels Moller5a998d72018-08-29 14:35:58 +000045 codec_info.codecSpecific.VP8.simulcastIdx = 1;
philipelbf2b6202018-08-27 14:33:18 +020046 codec_info.codecSpecific.VP8.temporalIdx = 0;
Stefan Holmerf7044682018-07-17 10:16:41 +020047 codec_info.codecSpecific.VP8.keyIdx = kNoKeyIdx;
philipelbf2b6202018-08-27 14:33:18 +020048 codec_info.codecSpecific.VP8.layerSync = false;
Stefan Holmerf7044682018-07-17 10:16:41 +020049 codec_info.codecSpecific.VP8.nonReference = true;
50
philipelbf2b6202018-08-27 14:33:18 +020051 RTPVideoHeader header =
52 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
53
54 codec_info.codecType = kVideoCodecVP8;
Niels Moller5a998d72018-08-29 14:35:58 +000055 codec_info.codecSpecific.VP8.simulcastIdx = 1;
philipelbf2b6202018-08-27 14:33:18 +020056 codec_info.codecSpecific.VP8.temporalIdx = 1;
57 codec_info.codecSpecific.VP8.layerSync = true;
58
59 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 1);
Stefan Holmerf7044682018-07-17 10:16:41 +020060
61 EXPECT_EQ(kVideoRotation_90, header.rotation);
62 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
63 EXPECT_EQ(1, header.simulcastIdx);
64 EXPECT_EQ(kVideoCodecVP8, header.codec);
philipelbf2b6202018-08-27 14:33:18 +020065 EXPECT_EQ(kPictureId + 2, header.vp8().pictureId);
Stefan Holmerf7044682018-07-17 10:16:41 +020066 EXPECT_EQ(kTemporalIdx, header.vp8().temporalIdx);
philipelbf2b6202018-08-27 14:33:18 +020067 EXPECT_EQ(kTl0PicIdx + 1, header.vp8().tl0PicIdx);
Stefan Holmerf7044682018-07-17 10:16:41 +020068 EXPECT_EQ(kNoKeyIdx, header.vp8().keyIdx);
69 EXPECT_TRUE(header.vp8().layerSync);
70 EXPECT_TRUE(header.vp8().nonReference);
71}
72
73TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp9) {
74 RtpPayloadState state;
75 state.picture_id = kPictureId;
76 state.tl0_pic_idx = kTl0PicIdx;
77 RtpPayloadParams params(kSsrc1, &state);
78
79 EncodedImage encoded_image;
80 encoded_image.rotation_ = kVideoRotation_90;
81 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
Niels Moller5a998d72018-08-29 14:35:58 +000082
Stefan Holmerf7044682018-07-17 10:16:41 +020083 CodecSpecificInfo codec_info;
84 memset(&codec_info, 0, sizeof(CodecSpecificInfo));
85 codec_info.codecType = kVideoCodecVP9;
86 codec_info.codecSpecific.VP9.num_spatial_layers = 3;
87 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
Niels Moller5a998d72018-08-29 14:35:58 +000088 codec_info.codecSpecific.VP9.spatial_idx = 0;
Stefan Holmerf7044682018-07-17 10:16:41 +020089 codec_info.codecSpecific.VP9.temporal_idx = 2;
90 codec_info.codecSpecific.VP9.end_of_picture = false;
91
philipelbf2b6202018-08-27 14:33:18 +020092 RTPVideoHeader header =
93 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +020094
95 EXPECT_EQ(kVideoRotation_90, header.rotation);
96 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
97 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +020098 const auto& vp9_header =
99 absl::get<RTPVideoHeaderVP9>(header.video_type_header);
100 EXPECT_EQ(kPictureId + 1, vp9_header.picture_id);
101 EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx);
102 EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx);
Niels Moller5a998d72018-08-29 14:35:58 +0000103 EXPECT_EQ(vp9_header.spatial_idx, codec_info.codecSpecific.VP9.spatial_idx);
philipel29d88462018-08-08 14:26:00 +0200104 EXPECT_EQ(vp9_header.num_spatial_layers,
Stefan Holmerf7044682018-07-17 10:16:41 +0200105 codec_info.codecSpecific.VP9.num_spatial_layers);
philipel29d88462018-08-08 14:26:00 +0200106 EXPECT_EQ(vp9_header.end_of_picture,
Stefan Holmerf7044682018-07-17 10:16:41 +0200107 codec_info.codecSpecific.VP9.end_of_picture);
108
109 // Next spatial layer.
110 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
Niels Moller5a998d72018-08-29 14:35:58 +0000111 codec_info.codecSpecific.VP9.spatial_idx += 1;
Stefan Holmerf7044682018-07-17 10:16:41 +0200112 codec_info.codecSpecific.VP9.end_of_picture = true;
113
philipelbf2b6202018-08-27 14:33:18 +0200114 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200115
116 EXPECT_EQ(kVideoRotation_90, header.rotation);
117 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
118 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200119 EXPECT_EQ(kPictureId + 1, vp9_header.picture_id);
120 EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx);
121 EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx);
Niels Moller5a998d72018-08-29 14:35:58 +0000122 EXPECT_EQ(vp9_header.spatial_idx, codec_info.codecSpecific.VP9.spatial_idx);
philipel29d88462018-08-08 14:26:00 +0200123 EXPECT_EQ(vp9_header.num_spatial_layers,
Stefan Holmerf7044682018-07-17 10:16:41 +0200124 codec_info.codecSpecific.VP9.num_spatial_layers);
philipel29d88462018-08-08 14:26:00 +0200125 EXPECT_EQ(vp9_header.end_of_picture,
Stefan Holmerf7044682018-07-17 10:16:41 +0200126 codec_info.codecSpecific.VP9.end_of_picture);
127}
128
129TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_H264) {
130 RtpPayloadParams params(kSsrc1, {});
131
132 EncodedImage encoded_image;
133 CodecSpecificInfo codec_info;
134 memset(&codec_info, 0, sizeof(CodecSpecificInfo));
135 codec_info.codecType = kVideoCodecH264;
136 codec_info.codecSpecific.H264.packetization_mode =
137 H264PacketizationMode::SingleNalUnit;
138
philipelbf2b6202018-08-27 14:33:18 +0200139 RTPVideoHeader header =
140 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200141
142 EXPECT_EQ(0, header.simulcastIdx);
143 EXPECT_EQ(kVideoCodecH264, header.codec);
144 const auto& h264 = absl::get<RTPVideoHeaderH264>(header.video_type_header);
145 EXPECT_EQ(H264PacketizationMode::SingleNalUnit, h264.packetization_mode);
146}
147
148TEST(RtpPayloadParamsTest, PictureIdIsSetForVp8) {
149 RtpPayloadState state;
150 state.picture_id = kInitialPictureId1;
151 state.tl0_pic_idx = kInitialTl0PicIdx1;
152
153 EncodedImage encoded_image;
154 CodecSpecificInfo codec_info;
155 memset(&codec_info, 0, sizeof(CodecSpecificInfo));
156 codec_info.codecType = kVideoCodecVP8;
Niels Moller5a998d72018-08-29 14:35:58 +0000157 codec_info.codecSpecific.VP8.simulcastIdx = 0;
Stefan Holmerf7044682018-07-17 10:16:41 +0200158
159 RtpPayloadParams params(kSsrc1, &state);
philipelbf2b6202018-08-27 14:33:18 +0200160 RTPVideoHeader header =
161 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200162 EXPECT_EQ(kVideoCodecVP8, header.codec);
163 EXPECT_EQ(kInitialPictureId1 + 1, header.vp8().pictureId);
164
165 // State should hold latest used picture id and tl0_pic_idx.
166 state = params.state();
167 EXPECT_EQ(kInitialPictureId1 + 1, state.picture_id);
168 EXPECT_EQ(kInitialTl0PicIdx1 + 1, state.tl0_pic_idx);
169}
170
171TEST(RtpPayloadParamsTest, PictureIdWraps) {
172 RtpPayloadState state;
173 state.picture_id = kMaxTwoBytePictureId;
174 state.tl0_pic_idx = kInitialTl0PicIdx1;
175
176 EncodedImage encoded_image;
177 CodecSpecificInfo codec_info;
178 memset(&codec_info, 0, sizeof(CodecSpecificInfo));
179 codec_info.codecType = kVideoCodecVP8;
180 codec_info.codecSpecific.VP8.temporalIdx = kNoTemporalIdx;
181
182 RtpPayloadParams params(kSsrc1, &state);
philipelbf2b6202018-08-27 14:33:18 +0200183 RTPVideoHeader header =
184 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200185 EXPECT_EQ(kVideoCodecVP8, header.codec);
186 EXPECT_EQ(0, header.vp8().pictureId);
187
188 // State should hold latest used picture id and tl0_pic_idx.
189 EXPECT_EQ(0, params.state().picture_id); // Wrapped.
190 EXPECT_EQ(kInitialTl0PicIdx1, params.state().tl0_pic_idx);
191}
192
193TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp8) {
194 RtpPayloadState state;
195 state.picture_id = kInitialPictureId1;
196 state.tl0_pic_idx = kInitialTl0PicIdx1;
197
198 EncodedImage encoded_image;
199 // Modules are sending for this test.
200 // OnEncodedImage, temporalIdx: 1.
201 CodecSpecificInfo codec_info;
202 memset(&codec_info, 0, sizeof(CodecSpecificInfo));
203 codec_info.codecType = kVideoCodecVP8;
204 codec_info.codecSpecific.VP8.temporalIdx = 1;
205
206 RtpPayloadParams params(kSsrc1, &state);
philipelbf2b6202018-08-27 14:33:18 +0200207 RTPVideoHeader header =
208 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200209
210 EXPECT_EQ(kVideoCodecVP8, header.codec);
211 EXPECT_EQ(kInitialPictureId1 + 1, header.vp8().pictureId);
212 EXPECT_EQ(kInitialTl0PicIdx1, header.vp8().tl0PicIdx);
213
214 // OnEncodedImage, temporalIdx: 0.
215 codec_info.codecSpecific.VP8.temporalIdx = 0;
216
philipelbf2b6202018-08-27 14:33:18 +0200217 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200218 EXPECT_EQ(kVideoCodecVP8, header.codec);
219 EXPECT_EQ(kInitialPictureId1 + 2, header.vp8().pictureId);
220 EXPECT_EQ(kInitialTl0PicIdx1 + 1, header.vp8().tl0PicIdx);
221
222 // State should hold latest used picture id and tl0_pic_idx.
223 EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id);
224 EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx);
225}
226
227TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp9) {
228 RtpPayloadState state;
229 state.picture_id = kInitialPictureId1;
230 state.tl0_pic_idx = kInitialTl0PicIdx1;
231
232 EncodedImage encoded_image;
233 // Modules are sending for this test.
234 // OnEncodedImage, temporalIdx: 1.
235 CodecSpecificInfo codec_info;
236 memset(&codec_info, 0, sizeof(CodecSpecificInfo));
237 codec_info.codecType = kVideoCodecVP9;
238 codec_info.codecSpecific.VP9.temporal_idx = 1;
239 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
240
241 RtpPayloadParams params(kSsrc1, &state);
philipelbf2b6202018-08-27 14:33:18 +0200242 RTPVideoHeader header =
243 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200244
245 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200246 const auto& vp9_header =
247 absl::get<RTPVideoHeaderVP9>(header.video_type_header);
248 EXPECT_EQ(kInitialPictureId1 + 1, vp9_header.picture_id);
249 EXPECT_EQ(kInitialTl0PicIdx1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200250
251 // OnEncodedImage, temporalIdx: 0.
252 codec_info.codecSpecific.VP9.temporal_idx = 0;
253
philipelbf2b6202018-08-27 14:33:18 +0200254 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200255
256 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200257 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
258 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200259
260 // OnEncodedImage, first_frame_in_picture = false
261 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
262
philipelbf2b6202018-08-27 14:33:18 +0200263 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200264
265 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200266 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
267 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200268
269 // State should hold latest used picture id and tl0_pic_idx.
270 EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id);
271 EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx);
272}
philipelbf2b6202018-08-27 14:33:18 +0200273
274TEST(RtpPayloadParamsTest, PictureIdForOldGenericFormat) {
275 test::ScopedFieldTrials generic_picture_id(
276 "WebRTC-GenericPictureId/Enabled/");
277 RtpPayloadState state{};
278
279 EncodedImage encoded_image;
280 CodecSpecificInfo codec_info{};
281 codec_info.codecType = kVideoCodecGeneric;
282
283 RtpPayloadParams params(kSsrc1, &state);
284 RTPVideoHeader header =
285 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
286
287 EXPECT_EQ(kVideoCodecGeneric, header.codec);
288 ASSERT_TRUE(header.generic);
289 EXPECT_EQ(0, header.generic->frame_id);
290
291 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
292 ASSERT_TRUE(header.generic);
293 EXPECT_EQ(1, header.generic->frame_id);
294}
295
296class RtpPayloadParamsVp8ToGenericTest : public ::testing::Test {
297 public:
298 enum LayerSync { kNoSync, kSync };
299
300 RtpPayloadParamsVp8ToGenericTest() : state_(), params_(123, &state_) {}
301
302 void ConvertAndCheck(int temporal_index,
303 int64_t shared_frame_id,
304 FrameType frame_type,
305 LayerSync layer_sync,
306 const std::set<int64_t>& expected_deps) {
307 EncodedImage encoded_image;
308 encoded_image._frameType = frame_type;
309
310 CodecSpecificInfo codec_info{};
311 codec_info.codecType = kVideoCodecVP8;
312 codec_info.codecSpecific.VP8.temporalIdx = temporal_index;
313 codec_info.codecSpecific.VP8.layerSync = layer_sync == kSync;
314
315 RTPVideoHeader header =
316 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
317
318 ASSERT_TRUE(header.generic);
319 EXPECT_TRUE(header.generic->higher_spatial_layers.empty());
320 EXPECT_EQ(header.generic->spatial_index, 0);
321
322 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
323 EXPECT_EQ(header.generic->temporal_index, temporal_index);
324 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
325 header.generic->dependencies.end());
326 EXPECT_EQ(expected_deps, actual_deps);
327 }
328
329 protected:
330 RtpPayloadState state_;
331 RtpPayloadParams params_;
332};
333
334TEST_F(RtpPayloadParamsVp8ToGenericTest, Keyframe) {
335 ConvertAndCheck(0, 0, kVideoFrameKey, kNoSync, {});
336 ConvertAndCheck(0, 1, kVideoFrameDelta, kNoSync, {0});
337 ConvertAndCheck(0, 2, kVideoFrameKey, kNoSync, {});
338}
339
340TEST_F(RtpPayloadParamsVp8ToGenericTest, TooHighTemporalIndex) {
341 ConvertAndCheck(0, 0, kVideoFrameKey, kNoSync, {});
342
343 EncodedImage encoded_image;
344 encoded_image._frameType = kVideoFrameDelta;
345 CodecSpecificInfo codec_info{};
346 codec_info.codecType = kVideoCodecVP8;
347 codec_info.codecSpecific.VP8.temporalIdx =
348 RtpGenericFrameDescriptor::kMaxTemporalLayers;
349 codec_info.codecSpecific.VP8.layerSync = false;
350
351 RTPVideoHeader header =
352 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
353 EXPECT_FALSE(header.generic);
354}
355
356TEST_F(RtpPayloadParamsVp8ToGenericTest, LayerSync) {
357 // 02120212 pattern
358 ConvertAndCheck(0, 0, kVideoFrameKey, kNoSync, {});
359 ConvertAndCheck(2, 1, kVideoFrameDelta, kNoSync, {0});
360 ConvertAndCheck(1, 2, kVideoFrameDelta, kNoSync, {0});
361 ConvertAndCheck(2, 3, kVideoFrameDelta, kNoSync, {0, 1, 2});
362
363 ConvertAndCheck(0, 4, kVideoFrameDelta, kNoSync, {0});
364 ConvertAndCheck(2, 5, kVideoFrameDelta, kNoSync, {2, 3, 4});
365 ConvertAndCheck(1, 6, kVideoFrameDelta, kSync, {4}); // layer sync
366 ConvertAndCheck(2, 7, kVideoFrameDelta, kNoSync, {4, 5, 6});
367}
368
369TEST_F(RtpPayloadParamsVp8ToGenericTest, FrameIdGaps) {
370 // 0101 pattern
371 ConvertAndCheck(0, 0, kVideoFrameKey, kNoSync, {});
372 ConvertAndCheck(1, 1, kVideoFrameDelta, kNoSync, {0});
373
374 ConvertAndCheck(0, 5, kVideoFrameDelta, kNoSync, {0});
375 ConvertAndCheck(1, 10, kVideoFrameDelta, kNoSync, {1, 5});
376
377 ConvertAndCheck(0, 15, kVideoFrameDelta, kNoSync, {5});
378 ConvertAndCheck(1, 20, kVideoFrameDelta, kNoSync, {10, 15});
379}
380
Stefan Holmerf7044682018-07-17 10:16:41 +0200381} // namespace webrtc