blob: b155c4c2048125519c6870540fc9be11c218cb36 [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
Danil Chapovalovaf366442021-04-22 15:20:28 +020034using ::testing::Each;
Danil Chapovalovdc7fe402019-12-13 12:23:58 +010035using ::testing::ElementsAre;
philipel5b231de2021-09-01 15:21:16 +020036using ::testing::Eq;
Danil Chapovalovdc7fe402019-12-13 12:23:58 +010037using ::testing::IsEmpty;
Danil Chapovalov4b860c12020-05-19 14:48:19 +020038using ::testing::SizeIs;
Danil Chapovalovdc7fe402019-12-13 12:23:58 +010039
Qingsi Wang1c1b99e2020-01-07 19:16:33 +000040namespace webrtc {
41namespace {
Stefan Holmerf7044682018-07-17 10:16:41 +020042const uint32_t kSsrc1 = 12345;
43const uint32_t kSsrc2 = 23456;
44const int16_t kPictureId = 123;
45const int16_t kTl0PicIdx = 20;
46const uint8_t kTemporalIdx = 1;
47const int16_t kInitialPictureId1 = 222;
48const int16_t kInitialTl0PicIdx1 = 99;
philipelbf2b6202018-08-27 14:33:18 +020049const int64_t kDontCare = 0;
Stefan Holmerf7044682018-07-17 10:16:41 +020050} // namespace
51
52TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp8) {
53 RtpPayloadState state2;
54 state2.picture_id = kPictureId;
55 state2.tl0_pic_idx = kTl0PicIdx;
56 std::map<uint32_t, RtpPayloadState> states = {{kSsrc2, state2}};
57
Erik Språngcbc0cba2020-04-18 14:36:59 +020058 RtpPayloadParams params(kSsrc2, &state2, FieldTrialBasedConfig());
Stefan Holmerf7044682018-07-17 10:16:41 +020059 EncodedImage encoded_image;
60 encoded_image.rotation_ = kVideoRotation_90;
61 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
Niels Möllerd3b8c632018-08-27 15:33:42 +020062 encoded_image.SetSpatialIndex(1);
Stefan Holmerf7044682018-07-17 10:16:41 +020063
64 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 10:16:41 +020065 codec_info.codecType = kVideoCodecVP8;
philipelbf2b6202018-08-27 14:33:18 +020066 codec_info.codecSpecific.VP8.temporalIdx = 0;
Stefan Holmerf7044682018-07-17 10:16:41 +020067 codec_info.codecSpecific.VP8.keyIdx = kNoKeyIdx;
philipelbf2b6202018-08-27 14:33:18 +020068 codec_info.codecSpecific.VP8.layerSync = false;
Stefan Holmerf7044682018-07-17 10:16:41 +020069 codec_info.codecSpecific.VP8.nonReference = true;
70
philipelbf2b6202018-08-27 14:33:18 +020071 RTPVideoHeader header =
72 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
73
74 codec_info.codecType = kVideoCodecVP8;
philipelbf2b6202018-08-27 14:33:18 +020075 codec_info.codecSpecific.VP8.temporalIdx = 1;
76 codec_info.codecSpecific.VP8.layerSync = true;
77
78 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 1);
Stefan Holmerf7044682018-07-17 10:16:41 +020079
80 EXPECT_EQ(kVideoRotation_90, header.rotation);
81 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
82 EXPECT_EQ(1, header.simulcastIdx);
83 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +000084 const auto& vp8_header =
85 absl::get<RTPVideoHeaderVP8>(header.video_type_header);
86 EXPECT_EQ(kPictureId + 2, vp8_header.pictureId);
87 EXPECT_EQ(kTemporalIdx, vp8_header.temporalIdx);
88 EXPECT_EQ(kTl0PicIdx + 1, vp8_header.tl0PicIdx);
89 EXPECT_EQ(kNoKeyIdx, vp8_header.keyIdx);
90 EXPECT_TRUE(vp8_header.layerSync);
91 EXPECT_TRUE(vp8_header.nonReference);
Stefan Holmerf7044682018-07-17 10:16:41 +020092}
93
94TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp9) {
95 RtpPayloadState state;
96 state.picture_id = kPictureId;
97 state.tl0_pic_idx = kTl0PicIdx;
Erik Språngcbc0cba2020-04-18 14:36:59 +020098 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
Stefan Holmerf7044682018-07-17 10:16:41 +020099
100 EncodedImage encoded_image;
101 encoded_image.rotation_ = kVideoRotation_90;
102 encoded_image.content_type_ = VideoContentType::SCREENSHARE;
Niels Möllerd3b8c632018-08-27 15:33:42 +0200103 encoded_image.SetSpatialIndex(0);
Stefan Holmerf7044682018-07-17 10:16:41 +0200104 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 10:16:41 +0200105 codec_info.codecType = kVideoCodecVP9;
106 codec_info.codecSpecific.VP9.num_spatial_layers = 3;
107 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
Stefan Holmerf7044682018-07-17 10:16:41 +0200108 codec_info.codecSpecific.VP9.temporal_idx = 2;
Danil Chapovalov06bbeb32020-11-11 12:42:56 +0100109 codec_info.end_of_picture = false;
Stefan Holmerf7044682018-07-17 10:16:41 +0200110
philipelbf2b6202018-08-27 14:33:18 +0200111 RTPVideoHeader header =
112 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200113
114 EXPECT_EQ(kVideoRotation_90, header.rotation);
115 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
116 EXPECT_EQ(kVideoCodecVP9, header.codec);
Johannes Krond0b69a82018-12-03 14:18:53 +0100117 EXPECT_FALSE(header.color_space);
philipel29d88462018-08-08 14:26:00 +0200118 const auto& vp9_header =
119 absl::get<RTPVideoHeaderVP9>(header.video_type_header);
120 EXPECT_EQ(kPictureId + 1, vp9_header.picture_id);
121 EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx);
122 EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx);
Niels Möllerd3b8c632018-08-27 15:33:42 +0200123 EXPECT_EQ(vp9_header.spatial_idx, encoded_image.SpatialIndex());
philipel29d88462018-08-08 14:26:00 +0200124 EXPECT_EQ(vp9_header.num_spatial_layers,
Stefan Holmerf7044682018-07-17 10:16:41 +0200125 codec_info.codecSpecific.VP9.num_spatial_layers);
Danil Chapovalov06bbeb32020-11-11 12:42:56 +0100126 EXPECT_EQ(vp9_header.end_of_picture, codec_info.end_of_picture);
Stefan Holmerf7044682018-07-17 10:16:41 +0200127
128 // Next spatial layer.
129 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
Danil Chapovalov06bbeb32020-11-11 12:42:56 +0100130 codec_info.end_of_picture = true;
Stefan Holmerf7044682018-07-17 10:16:41 +0200131
Niels Möllerd3b8c632018-08-27 15:33:42 +0200132 encoded_image.SetSpatialIndex(1);
Johannes Krond0b69a82018-12-03 14:18:53 +0100133 ColorSpace color_space(
134 ColorSpace::PrimaryID::kSMPTE170M, ColorSpace::TransferID::kSMPTE170M,
135 ColorSpace::MatrixID::kSMPTE170M, ColorSpace::RangeID::kFull);
Danil Chapovalovb7698942019-02-05 11:32:19 +0100136 encoded_image.SetColorSpace(color_space);
philipelbf2b6202018-08-27 14:33:18 +0200137 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200138
139 EXPECT_EQ(kVideoRotation_90, header.rotation);
140 EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type);
141 EXPECT_EQ(kVideoCodecVP9, header.codec);
Johannes Krond0b69a82018-12-03 14:18:53 +0100142 EXPECT_EQ(absl::make_optional(color_space), header.color_space);
philipel29d88462018-08-08 14:26:00 +0200143 EXPECT_EQ(kPictureId + 1, vp9_header.picture_id);
144 EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx);
145 EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx);
Niels Möllerd3b8c632018-08-27 15:33:42 +0200146 EXPECT_EQ(vp9_header.spatial_idx, encoded_image.SpatialIndex());
philipel29d88462018-08-08 14:26:00 +0200147 EXPECT_EQ(vp9_header.num_spatial_layers,
Stefan Holmerf7044682018-07-17 10:16:41 +0200148 codec_info.codecSpecific.VP9.num_spatial_layers);
Danil Chapovalov06bbeb32020-11-11 12:42:56 +0100149 EXPECT_EQ(vp9_header.end_of_picture, codec_info.end_of_picture);
Stefan Holmerf7044682018-07-17 10:16:41 +0200150}
151
Stefan Holmerf7044682018-07-17 10:16:41 +0200152TEST(RtpPayloadParamsTest, PictureIdIsSetForVp8) {
153 RtpPayloadState state;
154 state.picture_id = kInitialPictureId1;
155 state.tl0_pic_idx = kInitialTl0PicIdx1;
156
157 EncodedImage encoded_image;
158 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 10:16:41 +0200159 codec_info.codecType = kVideoCodecVP8;
Stefan Holmerf7044682018-07-17 10:16:41 +0200160
Erik Språngcbc0cba2020-04-18 14:36:59 +0200161 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 14:33:18 +0200162 RTPVideoHeader header =
163 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200164 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +0000165 EXPECT_EQ(kInitialPictureId1 + 1,
166 absl::get<RTPVideoHeaderVP8>(header.video_type_header).pictureId);
Stefan Holmerf7044682018-07-17 10:16:41 +0200167
168 // State should hold latest used picture id and tl0_pic_idx.
169 state = params.state();
170 EXPECT_EQ(kInitialPictureId1 + 1, state.picture_id);
171 EXPECT_EQ(kInitialTl0PicIdx1 + 1, state.tl0_pic_idx);
172}
173
174TEST(RtpPayloadParamsTest, PictureIdWraps) {
175 RtpPayloadState state;
176 state.picture_id = kMaxTwoBytePictureId;
177 state.tl0_pic_idx = kInitialTl0PicIdx1;
178
179 EncodedImage encoded_image;
180 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 10:16:41 +0200181 codec_info.codecType = kVideoCodecVP8;
182 codec_info.codecSpecific.VP8.temporalIdx = kNoTemporalIdx;
183
Erik Språngcbc0cba2020-04-18 14:36:59 +0200184 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 14:33:18 +0200185 RTPVideoHeader header =
186 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200187 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +0000188 EXPECT_EQ(0,
189 absl::get<RTPVideoHeaderVP8>(header.video_type_header).pictureId);
Stefan Holmerf7044682018-07-17 10:16:41 +0200190
191 // State should hold latest used picture id and tl0_pic_idx.
192 EXPECT_EQ(0, params.state().picture_id); // Wrapped.
193 EXPECT_EQ(kInitialTl0PicIdx1, params.state().tl0_pic_idx);
194}
195
196TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp8) {
197 RtpPayloadState state;
198 state.picture_id = kInitialPictureId1;
199 state.tl0_pic_idx = kInitialTl0PicIdx1;
200
201 EncodedImage encoded_image;
202 // Modules are sending for this test.
203 // OnEncodedImage, temporalIdx: 1.
204 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 10:16:41 +0200205 codec_info.codecType = kVideoCodecVP8;
206 codec_info.codecSpecific.VP8.temporalIdx = 1;
207
Erik Språngcbc0cba2020-04-18 14:36:59 +0200208 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 14:33:18 +0200209 RTPVideoHeader header =
210 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200211
212 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +0000213 const auto& vp8_header =
214 absl::get<RTPVideoHeaderVP8>(header.video_type_header);
215 EXPECT_EQ(kInitialPictureId1 + 1, vp8_header.pictureId);
216 EXPECT_EQ(kInitialTl0PicIdx1, vp8_header.tl0PicIdx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200217
218 // OnEncodedImage, temporalIdx: 0.
219 codec_info.codecSpecific.VP8.temporalIdx = 0;
220
philipelbf2b6202018-08-27 14:33:18 +0200221 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200222 EXPECT_EQ(kVideoCodecVP8, header.codec);
Philip Eliassond52a1a62018-09-07 13:03:55 +0000223 EXPECT_EQ(kInitialPictureId1 + 2, vp8_header.pictureId);
224 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp8_header.tl0PicIdx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200225
226 // State should hold latest used picture id and tl0_pic_idx.
227 EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id);
228 EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx);
229}
230
231TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp9) {
232 RtpPayloadState state;
233 state.picture_id = kInitialPictureId1;
234 state.tl0_pic_idx = kInitialTl0PicIdx1;
235
236 EncodedImage encoded_image;
237 // Modules are sending for this test.
238 // OnEncodedImage, temporalIdx: 1.
239 CodecSpecificInfo codec_info;
Stefan Holmerf7044682018-07-17 10:16:41 +0200240 codec_info.codecType = kVideoCodecVP9;
241 codec_info.codecSpecific.VP9.temporal_idx = 1;
242 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
243
Erik Språngcbc0cba2020-04-18 14:36:59 +0200244 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipelbf2b6202018-08-27 14:33:18 +0200245 RTPVideoHeader header =
246 params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200247
248 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200249 const auto& vp9_header =
250 absl::get<RTPVideoHeaderVP9>(header.video_type_header);
251 EXPECT_EQ(kInitialPictureId1 + 1, vp9_header.picture_id);
252 EXPECT_EQ(kInitialTl0PicIdx1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200253
254 // OnEncodedImage, temporalIdx: 0.
255 codec_info.codecSpecific.VP9.temporal_idx = 0;
256
philipelbf2b6202018-08-27 14:33:18 +0200257 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200258
259 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200260 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
261 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200262
263 // OnEncodedImage, first_frame_in_picture = false
264 codec_info.codecSpecific.VP9.first_frame_in_picture = false;
265
philipelbf2b6202018-08-27 14:33:18 +0200266 header = params.GetRtpVideoHeader(encoded_image, &codec_info, kDontCare);
Stefan Holmerf7044682018-07-17 10:16:41 +0200267
268 EXPECT_EQ(kVideoCodecVP9, header.codec);
philipel29d88462018-08-08 14:26:00 +0200269 EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id);
270 EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx);
Stefan Holmerf7044682018-07-17 10:16:41 +0200271
272 // State should hold latest used picture id and tl0_pic_idx.
273 EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id);
274 EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx);
275}
philipelbf2b6202018-08-27 14:33:18 +0200276
277TEST(RtpPayloadParamsTest, PictureIdForOldGenericFormat) {
Jonas Orelandc7f691a2022-03-09 15:12:07 +0100278 test::ScopedKeyValueConfig field_trials("WebRTC-GenericPictureId/Enabled/");
philipelbf2b6202018-08-27 14:33:18 +0200279 RtpPayloadState state{};
280
281 EncodedImage encoded_image;
philipeld1d03592019-03-01 13:53:55 +0100282 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 14:33:18 +0200283 codec_info.codecType = kVideoCodecGeneric;
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100284 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
philipelbf2b6202018-08-27 14:33:18 +0200285
Jonas Orelandc7f691a2022-03-09 15:12:07 +0100286 RtpPayloadParams params(kSsrc1, &state, field_trials);
philipelbf2b6202018-08-27 14:33:18 +0200287 RTPVideoHeader header =
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100288 params.GetRtpVideoHeader(encoded_image, &codec_info, 10);
philipelbf2b6202018-08-27 14:33:18 +0200289
290 EXPECT_EQ(kVideoCodecGeneric, header.codec);
Danil Chapovalovb6bf0b22020-01-28 18:36:57 +0100291 const auto* generic =
292 absl::get_if<RTPVideoHeaderLegacyGeneric>(&header.video_type_header);
293 ASSERT_TRUE(generic);
294 EXPECT_EQ(0, generic->picture_id);
philipelbf2b6202018-08-27 14:33:18 +0200295
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100296 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
297 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 20);
Danil Chapovalovb6bf0b22020-01-28 18:36:57 +0100298 generic =
299 absl::get_if<RTPVideoHeaderLegacyGeneric>(&header.video_type_header);
300 ASSERT_TRUE(generic);
301 EXPECT_EQ(1, generic->picture_id);
philipelbf2b6202018-08-27 14:33:18 +0200302}
303
philipel8aba8fe2019-06-13 15:13:16 +0200304TEST(RtpPayloadParamsTest, GenericDescriptorForGenericCodec) {
philipel5b231de2021-09-01 15:21:16 +0200305 RtpPayloadState state;
philipel8aba8fe2019-06-13 15:13:16 +0200306
307 EncodedImage encoded_image;
308 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
309 CodecSpecificInfo codec_info;
310 codec_info.codecType = kVideoCodecGeneric;
311
Erik Språngcbc0cba2020-04-18 14:36:59 +0200312 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
philipel8aba8fe2019-06-13 15:13:16 +0200313 RTPVideoHeader header =
314 params.GetRtpVideoHeader(encoded_image, &codec_info, 0);
315
philipel5b231de2021-09-01 15:21:16 +0200316 EXPECT_THAT(header.codec, Eq(kVideoCodecGeneric));
317
philipel8aba8fe2019-06-13 15:13:16 +0200318 ASSERT_TRUE(header.generic);
philipel5b231de2021-09-01 15:21:16 +0200319 EXPECT_THAT(header.generic->frame_id, Eq(0));
320 EXPECT_THAT(header.generic->spatial_index, Eq(0));
321 EXPECT_THAT(header.generic->temporal_index, Eq(0));
322 EXPECT_THAT(header.generic->decode_target_indications,
323 ElementsAre(DecodeTargetIndication::kSwitch));
philipel8aba8fe2019-06-13 15:13:16 +0200324 EXPECT_THAT(header.generic->dependencies, IsEmpty());
philipel5b231de2021-09-01 15:21:16 +0200325 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(0));
philipel8aba8fe2019-06-13 15:13:16 +0200326
327 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
philipel5b231de2021-09-01 15:21:16 +0200328 header = params.GetRtpVideoHeader(encoded_image, &codec_info, 3);
philipel8aba8fe2019-06-13 15:13:16 +0200329 ASSERT_TRUE(header.generic);
philipel5b231de2021-09-01 15:21:16 +0200330 EXPECT_THAT(header.generic->frame_id, Eq(3));
331 EXPECT_THAT(header.generic->spatial_index, Eq(0));
332 EXPECT_THAT(header.generic->temporal_index, Eq(0));
philipel8aba8fe2019-06-13 15:13:16 +0200333 EXPECT_THAT(header.generic->dependencies, ElementsAre(0));
philipel5b231de2021-09-01 15:21:16 +0200334 EXPECT_THAT(header.generic->decode_target_indications,
335 ElementsAre(DecodeTargetIndication::kSwitch));
336 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(3));
philipel8aba8fe2019-06-13 15:13:16 +0200337}
338
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100339TEST(RtpPayloadParamsTest, SetsGenericFromGenericFrameInfo) {
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100340 RtpPayloadState state;
341 EncodedImage encoded_image;
342 CodecSpecificInfo codec_info;
343
Erik Språngcbc0cba2020-04-18 14:36:59 +0200344 RtpPayloadParams params(kSsrc1, &state, FieldTrialBasedConfig());
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100345
346 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
347 codec_info.generic_frame_info =
348 GenericFrameInfo::Builder().S(1).T(0).Dtis("S").Build();
349 codec_info.generic_frame_info->encoder_buffers = {
350 {/*id=*/0, /*referenced=*/false, /*updated=*/true}};
Danil Chapovalov4b860c12020-05-19 14:48:19 +0200351 codec_info.generic_frame_info->part_of_chain = {true, false};
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100352 RTPVideoHeader key_header =
353 params.GetRtpVideoHeader(encoded_image, &codec_info, /*frame_id=*/1);
354
355 ASSERT_TRUE(key_header.generic);
356 EXPECT_EQ(key_header.generic->spatial_index, 1);
357 EXPECT_EQ(key_header.generic->temporal_index, 0);
358 EXPECT_EQ(key_header.generic->frame_id, 1);
359 EXPECT_THAT(key_header.generic->dependencies, IsEmpty());
360 EXPECT_THAT(key_header.generic->decode_target_indications,
361 ElementsAre(DecodeTargetIndication::kSwitch));
Danil Chapovalov4b860c12020-05-19 14:48:19 +0200362 EXPECT_THAT(key_header.generic->chain_diffs, SizeIs(2));
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100363
364 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
365 codec_info.generic_frame_info =
366 GenericFrameInfo::Builder().S(2).T(3).Dtis("D").Build();
367 codec_info.generic_frame_info->encoder_buffers = {
368 {/*id=*/0, /*referenced=*/true, /*updated=*/false}};
Danil Chapovalov4b860c12020-05-19 14:48:19 +0200369 codec_info.generic_frame_info->part_of_chain = {false, false};
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100370 RTPVideoHeader delta_header =
371 params.GetRtpVideoHeader(encoded_image, &codec_info, /*frame_id=*/3);
372
373 ASSERT_TRUE(delta_header.generic);
374 EXPECT_EQ(delta_header.generic->spatial_index, 2);
375 EXPECT_EQ(delta_header.generic->temporal_index, 3);
376 EXPECT_EQ(delta_header.generic->frame_id, 3);
377 EXPECT_THAT(delta_header.generic->dependencies, ElementsAre(1));
378 EXPECT_THAT(delta_header.generic->decode_target_indications,
379 ElementsAre(DecodeTargetIndication::kDiscardable));
Danil Chapovalov4b860c12020-05-19 14:48:19 +0200380 EXPECT_THAT(delta_header.generic->chain_diffs, SizeIs(2));
Danil Chapovalov02d71fb2020-02-10 16:22:57 +0100381}
382
philipelbf2b6202018-08-27 14:33:18 +0200383class RtpPayloadParamsVp8ToGenericTest : public ::testing::Test {
384 public:
385 enum LayerSync { kNoSync, kSync };
386
philipel569397f2018-09-26 12:25:31 +0200387 RtpPayloadParamsVp8ToGenericTest()
Danil Chapovalov636865e2020-06-03 14:11:26 +0200388 : state_(), params_(123, &state_, trials_config_) {}
philipelbf2b6202018-08-27 14:33:18 +0200389
390 void ConvertAndCheck(int temporal_index,
391 int64_t shared_frame_id,
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000392 VideoFrameType frame_type,
philipelbf2b6202018-08-27 14:33:18 +0200393 LayerSync layer_sync,
philipelfab91292018-10-17 14:36:08 +0200394 const std::set<int64_t>& expected_deps,
395 uint16_t width = 0,
396 uint16_t height = 0) {
philipelbf2b6202018-08-27 14:33:18 +0200397 EncodedImage encoded_image;
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000398 encoded_image._frameType = frame_type;
philipelfab91292018-10-17 14:36:08 +0200399 encoded_image._encodedWidth = width;
400 encoded_image._encodedHeight = height;
philipelbf2b6202018-08-27 14:33:18 +0200401
philipeld1d03592019-03-01 13:53:55 +0100402 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 14:33:18 +0200403 codec_info.codecType = kVideoCodecVP8;
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000404 codec_info.codecSpecific.VP8.temporalIdx = temporal_index;
405 codec_info.codecSpecific.VP8.layerSync = layer_sync == kSync;
philipelbf2b6202018-08-27 14:33:18 +0200406
407 RTPVideoHeader header =
408 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
409
410 ASSERT_TRUE(header.generic);
philipelbf2b6202018-08-27 14:33:18 +0200411 EXPECT_EQ(header.generic->spatial_index, 0);
412
413 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
414 EXPECT_EQ(header.generic->temporal_index, temporal_index);
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000415 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
416 header.generic->dependencies.end());
417 EXPECT_EQ(expected_deps, actual_deps);
philipelfab91292018-10-17 14:36:08 +0200418
419 EXPECT_EQ(header.width, width);
420 EXPECT_EQ(header.height, height);
philipelbf2b6202018-08-27 14:33:18 +0200421 }
422
423 protected:
Erik Språngcbc0cba2020-04-18 14:36:59 +0200424 FieldTrialBasedConfig trials_config_;
philipelbf2b6202018-08-27 14:33:18 +0200425 RtpPayloadState state_;
426 RtpPayloadParams params_;
427};
428
429TEST_F(RtpPayloadParamsVp8ToGenericTest, Keyframe) {
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000430 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
431 ConvertAndCheck(0, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
432 ConvertAndCheck(0, 2, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
philipelbf2b6202018-08-27 14:33:18 +0200433}
434
435TEST_F(RtpPayloadParamsVp8ToGenericTest, TooHighTemporalIndex) {
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000436 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
philipelbf2b6202018-08-27 14:33:18 +0200437
438 EncodedImage encoded_image;
Niels Möller8f7ce222019-03-21 15:43:58 +0100439 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
philipeld1d03592019-03-01 13:53:55 +0100440 CodecSpecificInfo codec_info;
philipelbf2b6202018-08-27 14:33:18 +0200441 codec_info.codecType = kVideoCodecVP8;
442 codec_info.codecSpecific.VP8.temporalIdx =
443 RtpGenericFrameDescriptor::kMaxTemporalLayers;
444 codec_info.codecSpecific.VP8.layerSync = false;
445
446 RTPVideoHeader header =
447 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
448 EXPECT_FALSE(header.generic);
449}
450
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000451TEST_F(RtpPayloadParamsVp8ToGenericTest, LayerSync) {
452 // 02120212 pattern
453 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
454 ConvertAndCheck(2, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
455 ConvertAndCheck(1, 2, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
456 ConvertAndCheck(2, 3, VideoFrameType::kVideoFrameDelta, kNoSync, {0, 1, 2});
philipelbf2b6202018-08-27 14:33:18 +0200457
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000458 ConvertAndCheck(0, 4, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
459 ConvertAndCheck(2, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {2, 3, 4});
460 ConvertAndCheck(1, 6, VideoFrameType::kVideoFrameDelta, kSync,
461 {4}); // layer sync
462 ConvertAndCheck(2, 7, VideoFrameType::kVideoFrameDelta, kNoSync, {4, 5, 6});
philipelbf2b6202018-08-27 14:33:18 +0200463}
464
465TEST_F(RtpPayloadParamsVp8ToGenericTest, FrameIdGaps) {
466 // 0101 pattern
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000467 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
468 ConvertAndCheck(1, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
philipelbf2b6202018-08-27 14:33:18 +0200469
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000470 ConvertAndCheck(0, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
471 ConvertAndCheck(1, 10, VideoFrameType::kVideoFrameDelta, kNoSync, {1, 5});
philipelbf2b6202018-08-27 14:33:18 +0200472
Qingsi Wang1c1b99e2020-01-07 19:16:33 +0000473 ConvertAndCheck(0, 15, VideoFrameType::kVideoFrameDelta, kNoSync, {5});
474 ConvertAndCheck(1, 20, VideoFrameType::kVideoFrameDelta, kNoSync, {10, 15});
philipelbf2b6202018-08-27 14:33:18 +0200475}
476
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200477TEST(RtpPayloadParamsVp9ToGenericTest, NoScalability) {
478 RtpPayloadState state;
479 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 15:20:28 +0200480
481 EncodedImage encoded_image;
482 CodecSpecificInfo codec_info;
483 codec_info.codecType = kVideoCodecVP9;
484 codec_info.codecSpecific.VP9.num_spatial_layers = 1;
485 codec_info.codecSpecific.VP9.temporal_idx = kNoTemporalIdx;
486 codec_info.codecSpecific.VP9.first_frame_in_picture = true;
487 codec_info.end_of_picture = true;
488
489 // Key frame.
490 encoded_image._frameType = VideoFrameType::kVideoFrameKey;
491 codec_info.codecSpecific.VP9.inter_pic_predicted = false;
492 codec_info.codecSpecific.VP9.num_ref_pics = 0;
493 RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info,
494 /*shared_frame_id=*/1);
495
496 ASSERT_TRUE(header.generic);
497 EXPECT_EQ(header.generic->spatial_index, 0);
498 EXPECT_EQ(header.generic->temporal_index, 0);
499 EXPECT_EQ(header.generic->frame_id, 1);
500 ASSERT_THAT(header.generic->decode_target_indications, Not(IsEmpty()));
501 EXPECT_EQ(header.generic->decode_target_indications[0],
502 DecodeTargetIndication::kSwitch);
503 EXPECT_THAT(header.generic->dependencies, IsEmpty());
504 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(0));
505
506 // Delta frame.
507 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
508 codec_info.codecSpecific.VP9.inter_pic_predicted = true;
509 codec_info.codecSpecific.VP9.num_ref_pics = 1;
510 codec_info.codecSpecific.VP9.p_diff[0] = 1;
511 header = params.GetRtpVideoHeader(encoded_image, &codec_info,
512 /*shared_frame_id=*/3);
513
514 ASSERT_TRUE(header.generic);
515 EXPECT_EQ(header.generic->spatial_index, 0);
516 EXPECT_EQ(header.generic->temporal_index, 0);
517 EXPECT_EQ(header.generic->frame_id, 3);
518 ASSERT_THAT(header.generic->decode_target_indications, Not(IsEmpty()));
519 EXPECT_EQ(header.generic->decode_target_indications[0],
520 DecodeTargetIndication::kSwitch);
521 EXPECT_THAT(header.generic->dependencies, ElementsAre(1));
522 // previous frame in the chain was frame#1,
523 EXPECT_THAT(header.generic->chain_diffs, ElementsAre(3 - 1));
524}
525
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200526TEST(RtpPayloadParamsVp9ToGenericTest, TemporalScalabilityWith2Layers) {
Danil Chapovalovaf366442021-04-22 15:20:28 +0200527 // Test with 2 temporal layers structure that is not used by webrtc:
528 // 1---3 5
529 // / / / ...
530 // 0---2---4---
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200531 RtpPayloadState state;
532 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 15:20:28 +0200533
534 EncodedImage image;
535 CodecSpecificInfo info;
536 info.codecType = kVideoCodecVP9;
537 info.codecSpecific.VP9.num_spatial_layers = 1;
538 info.codecSpecific.VP9.first_frame_in_picture = true;
539 info.end_of_picture = true;
540
541 RTPVideoHeader headers[6];
542 // Key frame.
543 image._frameType = VideoFrameType::kVideoFrameKey;
544 info.codecSpecific.VP9.inter_pic_predicted = false;
545 info.codecSpecific.VP9.num_ref_pics = 0;
546 info.codecSpecific.VP9.temporal_up_switch = true;
547 info.codecSpecific.VP9.temporal_idx = 0;
548 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
549
550 // Delta frames.
551 info.codecSpecific.VP9.inter_pic_predicted = true;
552 image._frameType = VideoFrameType::kVideoFrameDelta;
553
554 info.codecSpecific.VP9.temporal_up_switch = true;
555 info.codecSpecific.VP9.temporal_idx = 1;
556 info.codecSpecific.VP9.num_ref_pics = 1;
557 info.codecSpecific.VP9.p_diff[0] = 1;
558 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
559
560 info.codecSpecific.VP9.temporal_up_switch = false;
561 info.codecSpecific.VP9.temporal_idx = 0;
562 info.codecSpecific.VP9.num_ref_pics = 1;
563 info.codecSpecific.VP9.p_diff[0] = 2;
564 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
565
566 info.codecSpecific.VP9.temporal_up_switch = false;
567 info.codecSpecific.VP9.temporal_idx = 1;
568 info.codecSpecific.VP9.num_ref_pics = 2;
569 info.codecSpecific.VP9.p_diff[0] = 1;
570 info.codecSpecific.VP9.p_diff[1] = 2;
571 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
572
573 info.codecSpecific.VP9.temporal_up_switch = true;
574 info.codecSpecific.VP9.temporal_idx = 0;
575 info.codecSpecific.VP9.num_ref_pics = 1;
576 info.codecSpecific.VP9.p_diff[0] = 2;
577 headers[4] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/9);
578
579 info.codecSpecific.VP9.temporal_up_switch = true;
580 info.codecSpecific.VP9.temporal_idx = 1;
581 info.codecSpecific.VP9.num_ref_pics = 1;
582 info.codecSpecific.VP9.p_diff[0] = 1;
583 headers[5] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/11);
584
585 ASSERT_TRUE(headers[0].generic);
586 int num_decode_targets = headers[0].generic->decode_target_indications.size();
587 ASSERT_GE(num_decode_targets, 2);
588
589 for (int frame_idx = 0; frame_idx < 6; ++frame_idx) {
590 const RTPVideoHeader& header = headers[frame_idx];
591 ASSERT_TRUE(header.generic);
592 EXPECT_EQ(header.generic->spatial_index, 0);
593 EXPECT_EQ(header.generic->temporal_index, frame_idx % 2);
594 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
595 ASSERT_THAT(header.generic->decode_target_indications,
596 SizeIs(num_decode_targets));
597 // Expect only T0 frames are needed for the 1st decode target.
598 if (header.generic->temporal_index == 0) {
599 EXPECT_NE(header.generic->decode_target_indications[0],
600 DecodeTargetIndication::kNotPresent);
601 } else {
602 EXPECT_EQ(header.generic->decode_target_indications[0],
603 DecodeTargetIndication::kNotPresent);
604 }
605 // Expect all frames are needed for the 2nd decode target.
606 EXPECT_NE(header.generic->decode_target_indications[1],
607 DecodeTargetIndication::kNotPresent);
608 }
609
610 // Expect switch at every beginning of the pattern.
611 EXPECT_THAT(headers[0].generic->decode_target_indications,
612 Each(DecodeTargetIndication::kSwitch));
613 EXPECT_THAT(headers[4].generic->decode_target_indications,
614 Each(DecodeTargetIndication::kSwitch));
615
616 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // T0, 1
617 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // T1, 3
618 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // T0, 5
619 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(5, 3)); // T1, 7
620 EXPECT_THAT(headers[4].generic->dependencies, ElementsAre(5)); // T0, 9
621 EXPECT_THAT(headers[5].generic->dependencies, ElementsAre(9)); // T1, 11
622
623 EXPECT_THAT(headers[0].generic->chain_diffs, ElementsAre(0));
624 EXPECT_THAT(headers[1].generic->chain_diffs, ElementsAre(2));
625 EXPECT_THAT(headers[2].generic->chain_diffs, ElementsAre(4));
626 EXPECT_THAT(headers[3].generic->chain_diffs, ElementsAre(2));
627 EXPECT_THAT(headers[4].generic->chain_diffs, ElementsAre(4));
628 EXPECT_THAT(headers[5].generic->chain_diffs, ElementsAre(2));
629}
630
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200631TEST(RtpPayloadParamsVp9ToGenericTest, TemporalScalabilityWith3Layers) {
Danil Chapovalovaf366442021-04-22 15:20:28 +0200632 // Test with 3 temporal layers structure that is not used by webrtc, but used
633 // by chromium: https://imgur.com/pURAGvp
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200634 RtpPayloadState state;
635 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 15:20:28 +0200636
637 EncodedImage image;
638 CodecSpecificInfo info;
639 info.codecType = kVideoCodecVP9;
640 info.codecSpecific.VP9.num_spatial_layers = 1;
641 info.codecSpecific.VP9.first_frame_in_picture = true;
642 info.end_of_picture = true;
643
644 RTPVideoHeader headers[9];
645 // Key frame.
646 image._frameType = VideoFrameType::kVideoFrameKey;
647 info.codecSpecific.VP9.inter_pic_predicted = false;
648 info.codecSpecific.VP9.num_ref_pics = 0;
649 info.codecSpecific.VP9.temporal_up_switch = true;
650 info.codecSpecific.VP9.temporal_idx = 0;
651 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
652
653 // Delta frames.
654 info.codecSpecific.VP9.inter_pic_predicted = true;
655 image._frameType = VideoFrameType::kVideoFrameDelta;
656
657 info.codecSpecific.VP9.temporal_up_switch = true;
658 info.codecSpecific.VP9.temporal_idx = 2;
659 info.codecSpecific.VP9.num_ref_pics = 1;
660 info.codecSpecific.VP9.p_diff[0] = 1;
661 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
662
663 info.codecSpecific.VP9.temporal_up_switch = true;
664 info.codecSpecific.VP9.temporal_idx = 1;
665 info.codecSpecific.VP9.num_ref_pics = 1;
666 info.codecSpecific.VP9.p_diff[0] = 2;
667 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
668
669 info.codecSpecific.VP9.temporal_up_switch = true;
670 info.codecSpecific.VP9.temporal_idx = 2;
671 info.codecSpecific.VP9.num_ref_pics = 1;
672 info.codecSpecific.VP9.p_diff[0] = 1;
673 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
674
675 info.codecSpecific.VP9.temporal_up_switch = false;
676 info.codecSpecific.VP9.temporal_idx = 0;
677 info.codecSpecific.VP9.num_ref_pics = 1;
678 info.codecSpecific.VP9.p_diff[0] = 4;
679 headers[4] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/9);
680
681 info.codecSpecific.VP9.temporal_up_switch = true;
682 info.codecSpecific.VP9.temporal_idx = 2;
683 info.codecSpecific.VP9.num_ref_pics = 2;
684 info.codecSpecific.VP9.p_diff[0] = 1;
685 info.codecSpecific.VP9.p_diff[1] = 3;
686 headers[5] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/11);
687
688 info.codecSpecific.VP9.temporal_up_switch = false;
689 info.codecSpecific.VP9.temporal_idx = 1;
690 info.codecSpecific.VP9.num_ref_pics = 2;
691 info.codecSpecific.VP9.p_diff[0] = 2;
692 info.codecSpecific.VP9.p_diff[1] = 4;
693 headers[6] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/13);
694
695 info.codecSpecific.VP9.temporal_up_switch = true;
696 info.codecSpecific.VP9.temporal_idx = 2;
697 info.codecSpecific.VP9.num_ref_pics = 1;
698 info.codecSpecific.VP9.p_diff[0] = 1;
699 headers[7] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/15);
700
701 info.codecSpecific.VP9.temporal_up_switch = true;
702 info.codecSpecific.VP9.temporal_idx = 0;
703 info.codecSpecific.VP9.num_ref_pics = 1;
704 info.codecSpecific.VP9.p_diff[0] = 4;
705 headers[8] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/17);
706
707 ASSERT_TRUE(headers[0].generic);
708 int num_decode_targets = headers[0].generic->decode_target_indications.size();
709 ASSERT_GE(num_decode_targets, 3);
710
711 for (int frame_idx = 0; frame_idx < 9; ++frame_idx) {
712 const RTPVideoHeader& header = headers[frame_idx];
713 ASSERT_TRUE(header.generic);
714 EXPECT_EQ(header.generic->spatial_index, 0);
715 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
716 ASSERT_THAT(header.generic->decode_target_indications,
717 SizeIs(num_decode_targets));
718 // Expect only T0 frames are needed for the 1st decode target.
719 if (header.generic->temporal_index == 0) {
720 EXPECT_NE(header.generic->decode_target_indications[0],
721 DecodeTargetIndication::kNotPresent);
722 } else {
723 EXPECT_EQ(header.generic->decode_target_indications[0],
724 DecodeTargetIndication::kNotPresent);
725 }
726 // Expect only T0 and T1 frames are needed for the 2nd decode target.
727 if (header.generic->temporal_index <= 1) {
728 EXPECT_NE(header.generic->decode_target_indications[1],
729 DecodeTargetIndication::kNotPresent);
730 } else {
731 EXPECT_EQ(header.generic->decode_target_indications[1],
732 DecodeTargetIndication::kNotPresent);
733 }
734 // Expect all frames are needed for the 3rd decode target.
735 EXPECT_NE(header.generic->decode_target_indications[2],
736 DecodeTargetIndication::kNotPresent);
737 }
738
739 EXPECT_EQ(headers[0].generic->temporal_index, 0);
740 EXPECT_EQ(headers[1].generic->temporal_index, 2);
741 EXPECT_EQ(headers[2].generic->temporal_index, 1);
742 EXPECT_EQ(headers[3].generic->temporal_index, 2);
743 EXPECT_EQ(headers[4].generic->temporal_index, 0);
744 EXPECT_EQ(headers[5].generic->temporal_index, 2);
745 EXPECT_EQ(headers[6].generic->temporal_index, 1);
746 EXPECT_EQ(headers[7].generic->temporal_index, 2);
747 EXPECT_EQ(headers[8].generic->temporal_index, 0);
748
749 // Expect switch at every beginning of the pattern.
750 EXPECT_THAT(headers[0].generic->decode_target_indications,
751 Each(DecodeTargetIndication::kSwitch));
752 EXPECT_THAT(headers[8].generic->decode_target_indications,
753 Each(DecodeTargetIndication::kSwitch));
754
755 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // T0, 1
756 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // T2, 3
757 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // T1, 5
758 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(5)); // T2, 7
759 EXPECT_THAT(headers[4].generic->dependencies, ElementsAre(1)); // T0, 9
760 EXPECT_THAT(headers[5].generic->dependencies, ElementsAre(9, 5)); // T2, 11
761 EXPECT_THAT(headers[6].generic->dependencies, ElementsAre(9, 5)); // T1, 13
762 EXPECT_THAT(headers[7].generic->dependencies, ElementsAre(13)); // T2, 15
763 EXPECT_THAT(headers[8].generic->dependencies, ElementsAre(9)); // T0, 17
764
765 EXPECT_THAT(headers[0].generic->chain_diffs, ElementsAre(0));
766 EXPECT_THAT(headers[1].generic->chain_diffs, ElementsAre(2));
767 EXPECT_THAT(headers[2].generic->chain_diffs, ElementsAre(4));
768 EXPECT_THAT(headers[3].generic->chain_diffs, ElementsAre(6));
769 EXPECT_THAT(headers[4].generic->chain_diffs, ElementsAre(8));
770 EXPECT_THAT(headers[5].generic->chain_diffs, ElementsAre(2));
771 EXPECT_THAT(headers[6].generic->chain_diffs, ElementsAre(4));
772 EXPECT_THAT(headers[7].generic->chain_diffs, ElementsAre(6));
773 EXPECT_THAT(headers[8].generic->chain_diffs, ElementsAre(8));
774}
775
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200776TEST(RtpPayloadParamsVp9ToGenericTest, SpatialScalabilityKSvc) {
Danil Chapovalovaf366442021-04-22 15:20:28 +0200777 // 1---3--
778 // | ...
779 // 0---2--
Emil Lundmarkb01e6452021-09-14 11:46:44 +0200780 RtpPayloadState state;
781 RtpPayloadParams params(/*ssrc=*/123, &state, FieldTrialBasedConfig());
Danil Chapovalovaf366442021-04-22 15:20:28 +0200782
783 EncodedImage image;
784 CodecSpecificInfo info;
785 info.codecType = kVideoCodecVP9;
786 info.codecSpecific.VP9.num_spatial_layers = 2;
787 info.codecSpecific.VP9.first_frame_in_picture = true;
788
789 RTPVideoHeader headers[4];
790 // Key frame.
791 image._frameType = VideoFrameType::kVideoFrameKey;
792 image.SetSpatialIndex(0);
793 info.codecSpecific.VP9.inter_pic_predicted = false;
794 info.codecSpecific.VP9.inter_layer_predicted = false;
795 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = false;
796 info.codecSpecific.VP9.num_ref_pics = 0;
797 info.codecSpecific.VP9.first_frame_in_picture = true;
798 info.end_of_picture = false;
799 headers[0] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/1);
800
801 image.SetSpatialIndex(1);
802 info.codecSpecific.VP9.inter_layer_predicted = true;
803 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
804 info.codecSpecific.VP9.first_frame_in_picture = false;
805 info.end_of_picture = true;
806 headers[1] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/3);
807
808 // Delta frames.
809 info.codecSpecific.VP9.inter_pic_predicted = true;
810 image._frameType = VideoFrameType::kVideoFrameDelta;
811 info.codecSpecific.VP9.num_ref_pics = 1;
812 info.codecSpecific.VP9.p_diff[0] = 1;
813
814 image.SetSpatialIndex(0);
815 info.codecSpecific.VP9.inter_layer_predicted = false;
816 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
817 info.codecSpecific.VP9.first_frame_in_picture = true;
818 info.end_of_picture = false;
819 headers[2] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/5);
820
821 image.SetSpatialIndex(1);
822 info.codecSpecific.VP9.inter_layer_predicted = false;
823 info.codecSpecific.VP9.non_ref_for_inter_layer_pred = true;
824 info.codecSpecific.VP9.first_frame_in_picture = false;
825 info.end_of_picture = true;
826 headers[3] = params.GetRtpVideoHeader(image, &info, /*shared_frame_id=*/7);
827
828 ASSERT_TRUE(headers[0].generic);
829 int num_decode_targets = headers[0].generic->decode_target_indications.size();
830 // Rely on implementation detail there are always kMaxTemporalStreams temporal
831 // layers assumed, in particular assume Decode Target#0 matches layer S0T0,
832 // and Decode Target#kMaxTemporalStreams matches layer S1T0.
833 ASSERT_EQ(num_decode_targets, kMaxTemporalStreams * 2);
834
835 for (int frame_idx = 0; frame_idx < 4; ++frame_idx) {
836 const RTPVideoHeader& header = headers[frame_idx];
837 ASSERT_TRUE(header.generic);
838 EXPECT_EQ(header.generic->spatial_index, frame_idx % 2);
839 EXPECT_EQ(header.generic->temporal_index, 0);
840 EXPECT_EQ(header.generic->frame_id, 1 + 2 * frame_idx);
841 ASSERT_THAT(header.generic->decode_target_indications,
842 SizeIs(num_decode_targets));
843 }
844
845 // Expect S0 key frame is switch for both Decode Targets.
846 EXPECT_EQ(headers[0].generic->decode_target_indications[0],
847 DecodeTargetIndication::kSwitch);
848 EXPECT_EQ(headers[0].generic->decode_target_indications[kMaxTemporalStreams],
849 DecodeTargetIndication::kSwitch);
850 // S1 key frame is only needed for the 2nd Decode Targets.
851 EXPECT_EQ(headers[1].generic->decode_target_indications[0],
852 DecodeTargetIndication::kNotPresent);
853 EXPECT_NE(headers[1].generic->decode_target_indications[kMaxTemporalStreams],
854 DecodeTargetIndication::kNotPresent);
855 // Delta frames are only needed for their own Decode Targets.
856 EXPECT_NE(headers[2].generic->decode_target_indications[0],
857 DecodeTargetIndication::kNotPresent);
858 EXPECT_EQ(headers[2].generic->decode_target_indications[kMaxTemporalStreams],
859 DecodeTargetIndication::kNotPresent);
860 EXPECT_EQ(headers[3].generic->decode_target_indications[0],
861 DecodeTargetIndication::kNotPresent);
862 EXPECT_NE(headers[3].generic->decode_target_indications[kMaxTemporalStreams],
863 DecodeTargetIndication::kNotPresent);
864
865 EXPECT_THAT(headers[0].generic->dependencies, IsEmpty()); // S0, 1
866 EXPECT_THAT(headers[1].generic->dependencies, ElementsAre(1)); // S1, 3
867 EXPECT_THAT(headers[2].generic->dependencies, ElementsAre(1)); // S0, 5
868 EXPECT_THAT(headers[3].generic->dependencies, ElementsAre(3)); // S1, 7
869
870 EXPECT_THAT(headers[0].generic->chain_diffs, ElementsAre(0, 0));
871 EXPECT_THAT(headers[1].generic->chain_diffs, ElementsAre(2, 2));
872 EXPECT_THAT(headers[2].generic->chain_diffs, ElementsAre(4, 2));
873 EXPECT_THAT(headers[3].generic->chain_diffs, ElementsAre(2, 4));
874}
875
philipel8aba8fe2019-06-13 15:13:16 +0200876class RtpPayloadParamsH264ToGenericTest : public ::testing::Test {
877 public:
878 enum LayerSync { kNoSync, kSync };
879
880 RtpPayloadParamsH264ToGenericTest()
Danil Chapovalov636865e2020-06-03 14:11:26 +0200881 : state_(), params_(123, &state_, trials_config_) {}
philipel8aba8fe2019-06-13 15:13:16 +0200882
883 void ConvertAndCheck(int temporal_index,
884 int64_t shared_frame_id,
885 VideoFrameType frame_type,
886 LayerSync layer_sync,
887 const std::set<int64_t>& expected_deps,
888 uint16_t width = 0,
889 uint16_t height = 0) {
890 EncodedImage encoded_image;
891 encoded_image._frameType = frame_type;
892 encoded_image._encodedWidth = width;
893 encoded_image._encodedHeight = height;
894
895 CodecSpecificInfo codec_info;
896 codec_info.codecType = kVideoCodecH264;
897 codec_info.codecSpecific.H264.temporal_idx = temporal_index;
898 codec_info.codecSpecific.H264.base_layer_sync = layer_sync == kSync;
899
900 RTPVideoHeader header =
901 params_.GetRtpVideoHeader(encoded_image, &codec_info, shared_frame_id);
902
903 ASSERT_TRUE(header.generic);
philipel8aba8fe2019-06-13 15:13:16 +0200904 EXPECT_EQ(header.generic->spatial_index, 0);
905
906 EXPECT_EQ(header.generic->frame_id, shared_frame_id);
907 EXPECT_EQ(header.generic->temporal_index, temporal_index);
908 std::set<int64_t> actual_deps(header.generic->dependencies.begin(),
909 header.generic->dependencies.end());
910 EXPECT_EQ(expected_deps, actual_deps);
911
912 EXPECT_EQ(header.width, width);
913 EXPECT_EQ(header.height, height);
914 }
915
916 protected:
Erik Språngcbc0cba2020-04-18 14:36:59 +0200917 FieldTrialBasedConfig trials_config_;
philipel8aba8fe2019-06-13 15:13:16 +0200918 RtpPayloadState state_;
919 RtpPayloadParams params_;
920};
921
922TEST_F(RtpPayloadParamsH264ToGenericTest, Keyframe) {
923 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
924 ConvertAndCheck(0, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
925 ConvertAndCheck(0, 2, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
926}
927
928TEST_F(RtpPayloadParamsH264ToGenericTest, TooHighTemporalIndex) {
929 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
930
931 EncodedImage encoded_image;
932 encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
933 CodecSpecificInfo codec_info;
934 codec_info.codecType = kVideoCodecH264;
935 codec_info.codecSpecific.H264.temporal_idx =
936 RtpGenericFrameDescriptor::kMaxTemporalLayers;
937 codec_info.codecSpecific.H264.base_layer_sync = false;
938
939 RTPVideoHeader header =
940 params_.GetRtpVideoHeader(encoded_image, &codec_info, 1);
941 EXPECT_FALSE(header.generic);
942}
943
944TEST_F(RtpPayloadParamsH264ToGenericTest, LayerSync) {
945 // 02120212 pattern
946 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
947 ConvertAndCheck(2, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
948 ConvertAndCheck(1, 2, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
949 ConvertAndCheck(2, 3, VideoFrameType::kVideoFrameDelta, kNoSync, {0, 1, 2});
950
951 ConvertAndCheck(0, 4, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
952 ConvertAndCheck(2, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {2, 3, 4});
953 ConvertAndCheck(1, 6, VideoFrameType::kVideoFrameDelta, kSync,
954 {4}); // layer sync
955 ConvertAndCheck(2, 7, VideoFrameType::kVideoFrameDelta, kNoSync, {4, 5, 6});
956}
957
958TEST_F(RtpPayloadParamsH264ToGenericTest, FrameIdGaps) {
959 // 0101 pattern
960 ConvertAndCheck(0, 0, VideoFrameType::kVideoFrameKey, kNoSync, {}, 480, 360);
961 ConvertAndCheck(1, 1, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
962
963 ConvertAndCheck(0, 5, VideoFrameType::kVideoFrameDelta, kNoSync, {0});
964 ConvertAndCheck(1, 10, VideoFrameType::kVideoFrameDelta, kNoSync, {1, 5});
965
966 ConvertAndCheck(0, 15, VideoFrameType::kVideoFrameDelta, kNoSync, {5});
967 ConvertAndCheck(1, 20, VideoFrameType::kVideoFrameDelta, kNoSync, {10, 15});
968}
969
Stefan Holmerf7044682018-07-17 10:16:41 +0200970} // namespace webrtc