blob: 86d7cc0fcfffa3118cad6ec8b3ca98344b6a32ad [file] [log] [blame]
Danil Chapovalov40f1fe92020-06-03 12:01:41 +02001/*
2 * Copyright (c) 2020 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 <stddef.h>
12#include <stdint.h>
13
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020014#include <memory>
15#include <ostream>
16#include <string>
17
18#include "absl/types/optional.h"
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020019#include "api/array_view.h"
Danil Chapovalov09867d32020-06-18 17:03:57 +020020#include "api/transport/rtp/dependency_descriptor.h"
Danil Chapovalovda7fe392020-10-15 15:57:17 +020021#include "modules/video_coding/svc/create_scalability_structure.h"
Niels Möller79d566b2022-04-29 11:03:13 +020022#include "modules/video_coding/svc/scalability_mode_util.h"
Danil Chapovalovda7fe392020-10-15 15:57:17 +020023#include "modules/video_coding/svc/scalability_structure_test_helpers.h"
24#include "modules/video_coding/svc/scalable_video_controller.h"
Niels Möller3c24c092022-06-30 15:42:51 +020025#include "rtc_base/strings/string_builder.h"
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020026#include "test/gmock.h"
27#include "test/gtest.h"
28
29namespace webrtc {
30namespace {
31
32using ::testing::AllOf;
Danil Chapovalovaa40b892020-06-03 18:13:20 +020033using ::testing::Contains;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020034using ::testing::Each;
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020035using ::testing::ElementsAreArray;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020036using ::testing::Field;
37using ::testing::Ge;
38using ::testing::IsEmpty;
39using ::testing::Le;
40using ::testing::Lt;
41using ::testing::Not;
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020042using ::testing::NotNull;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020043using ::testing::SizeIs;
44using ::testing::TestWithParam;
45using ::testing::Values;
46
Niels Möller3c24c092022-06-30 15:42:51 +020047std::string FrameDependencyTemplateToString(const FrameDependencyTemplate& t) {
48 rtc::StringBuilder sb;
49 sb << "S" << t.spatial_id << "T" << t.temporal_id;
50 sb << ": dtis = ";
51 for (const auto dtis : t.decode_target_indications) {
52 switch (dtis) {
53 case DecodeTargetIndication::kNotPresent:
54 sb << "-";
55 break;
56 case DecodeTargetIndication::kDiscardable:
57 sb << "D";
58 break;
59 case DecodeTargetIndication::kSwitch:
60 sb << "S";
61 break;
62 case DecodeTargetIndication::kRequired:
63 sb << "R";
64 break;
65 default:
66 sb << "?";
67 break;
68 }
69 }
70 sb << ", frame diffs = { ";
71 for (int d : t.frame_diffs) {
72 sb << d << ", ";
73 }
74 sb << "}, chain diffs = { ";
75 for (int d : t.chain_diffs) {
76 sb << d << ", ";
77 }
78 sb << "}";
79 return sb.Release();
80}
81
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020082struct SvcTestParam {
83 friend std::ostream& operator<<(std::ostream& os, const SvcTestParam& param) {
84 return os << param.name;
85 }
86
Niels Möller79d566b2022-04-29 11:03:13 +020087 ScalabilityMode GetScalabilityMode() const {
88 absl::optional<ScalabilityMode> scalability_mode =
89 ScalabilityModeFromString(name);
90 RTC_CHECK(scalability_mode.has_value());
91 return *scalability_mode;
92 }
93
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020094 std::string name;
Danil Chapovalovaa40b892020-06-03 18:13:20 +020095 int num_temporal_units;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020096};
97
Danil Chapovalov294729f2020-10-09 18:58:42 +020098class ScalabilityStructureTest : public TestWithParam<SvcTestParam> {};
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020099
100TEST_P(ScalabilityStructureTest,
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +0200101 StaticConfigMatchesConfigReturnedByController) {
102 std::unique_ptr<ScalableVideoController> controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200103 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +0200104 absl::optional<ScalableVideoController::StreamLayersConfig> static_config =
Niels Möller79d566b2022-04-29 11:03:13 +0200105 ScalabilityStructureConfig(GetParam().GetScalabilityMode());
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +0200106 ASSERT_THAT(controller, NotNull());
107 ASSERT_NE(static_config, absl::nullopt);
108 ScalableVideoController::StreamLayersConfig config =
109 controller->StreamConfig();
110 EXPECT_EQ(config.num_spatial_layers, static_config->num_spatial_layers);
111 EXPECT_EQ(config.num_temporal_layers, static_config->num_temporal_layers);
112 EXPECT_THAT(
113 rtc::MakeArrayView(config.scaling_factor_num, config.num_spatial_layers),
114 ElementsAreArray(static_config->scaling_factor_num,
115 static_config->num_spatial_layers));
116 EXPECT_THAT(
117 rtc::MakeArrayView(config.scaling_factor_den, config.num_spatial_layers),
118 ElementsAreArray(static_config->scaling_factor_den,
119 static_config->num_spatial_layers));
120}
121
122TEST_P(ScalabilityStructureTest,
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200123 NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) {
124 FrameDependencyStructure structure =
Niels Möller79d566b2022-04-29 11:03:13 +0200125 CreateScalabilityStructure(GetParam().GetScalabilityMode())
126 ->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200127 EXPECT_GT(structure.num_decode_targets, 0);
Danil Chapovalov09867d32020-06-18 17:03:57 +0200128 EXPECT_LE(structure.num_decode_targets,
129 DependencyDescriptor::kMaxDecodeTargets);
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200130 EXPECT_GE(structure.num_chains, 0);
131 EXPECT_LE(structure.num_chains, structure.num_decode_targets);
132 if (structure.num_chains == 0) {
133 EXPECT_THAT(structure.decode_target_protected_by_chain, IsEmpty());
134 } else {
135 EXPECT_THAT(structure.decode_target_protected_by_chain,
136 AllOf(SizeIs(structure.num_decode_targets), Each(Ge(0)),
Danil Chapovalova5d9c1a2020-07-14 18:00:17 +0200137 Each(Lt(structure.num_chains))));
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200138 }
Danil Chapovalov09867d32020-06-18 17:03:57 +0200139 EXPECT_THAT(structure.templates,
140 SizeIs(Lt(size_t{DependencyDescriptor::kMaxTemplates})));
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200141}
142
143TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) {
144 FrameDependencyStructure structure =
Niels Möller79d566b2022-04-29 11:03:13 +0200145 CreateScalabilityStructure(GetParam().GetScalabilityMode())
146 ->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200147 ASSERT_THAT(structure.templates, Not(IsEmpty()));
148 const auto& first_templates = structure.templates.front();
149 EXPECT_EQ(first_templates.spatial_id, 0);
150 EXPECT_EQ(first_templates.temporal_id, 0);
151 for (size_t i = 1; i < structure.templates.size(); ++i) {
152 const auto& prev_template = structure.templates[i - 1];
153 const auto& next_template = structure.templates[i];
154 if (next_template.spatial_id == prev_template.spatial_id &&
155 next_template.temporal_id == prev_template.temporal_id) {
156 // Same layer, next_layer_idc == 0
157 } else if (next_template.spatial_id == prev_template.spatial_id &&
158 next_template.temporal_id == prev_template.temporal_id + 1) {
159 // Next temporal layer, next_layer_idc == 1
160 } else if (next_template.spatial_id == prev_template.spatial_id + 1 &&
161 next_template.temporal_id == 0) {
162 // Next spatial layer, next_layer_idc == 2
163 } else {
164 // everything else is invalid.
165 ADD_FAILURE() << "Invalid templates order. Template #" << i
166 << " with layer (" << next_template.spatial_id << ","
167 << next_template.temporal_id
168 << ") follows template with layer ("
169 << prev_template.spatial_id << ","
170 << prev_template.temporal_id << ").";
171 }
172 }
173}
174
175TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) {
176 FrameDependencyStructure structure =
Niels Möller79d566b2022-04-29 11:03:13 +0200177 CreateScalabilityStructure(GetParam().GetScalabilityMode())
178 ->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200179 EXPECT_THAT(
180 structure.templates,
181 Each(AllOf(Field(&FrameDependencyTemplate::decode_target_indications,
182 SizeIs(structure.num_decode_targets)),
183 Field(&FrameDependencyTemplate::chain_diffs,
184 SizeIs(structure.num_chains)))));
185}
186
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200187TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200188 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200189 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200190 FrameDependencyStructure structure = svc_controller->DependencyStructure();
191 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200192 ScalabilityStructureWrapper(*svc_controller)
193 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200194 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
195 const auto& frame = frame_infos[frame_id];
196 EXPECT_GE(frame.spatial_id, 0) << " for frame " << frame_id;
197 EXPECT_GE(frame.temporal_id, 0) << " for frame " << frame_id;
198 EXPECT_THAT(frame.decode_target_indications,
199 SizeIs(structure.num_decode_targets))
200 << " for frame " << frame_id;
201 EXPECT_THAT(frame.part_of_chain, SizeIs(structure.num_chains))
202 << " for frame " << frame_id;
203 }
204}
205
206TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200207 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200208 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200209 FrameDependencyStructure structure = svc_controller->DependencyStructure();
210 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200211 ScalabilityStructureWrapper(*svc_controller)
212 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200213 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
214 EXPECT_THAT(structure.templates, Contains(frame_infos[frame_id]))
Niels Möller3c24c092022-06-30 15:42:51 +0200215 << " for frame " << frame_id << ", Expected "
216 << FrameDependencyTemplateToString(frame_infos[frame_id]);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200217 }
218}
219
220TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200221 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200222 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200223 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200224 ScalabilityStructureWrapper(*svc_controller)
225 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200226 int64_t num_frames = frame_infos.size();
227
228 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
229 const auto& frame = frame_infos[frame_id];
230 for (int frame_diff : frame.frame_diffs) {
231 int64_t base_frame_id = frame_id - frame_diff;
232 const auto& base_frame = frame_infos[base_frame_id];
233 EXPECT_GE(frame.spatial_id, base_frame.spatial_id)
234 << "Frame " << frame_id << " depends on frame " << base_frame_id;
235 EXPECT_GE(frame.temporal_id, base_frame.temporal_id)
236 << "Frame " << frame_id << " depends on frame " << base_frame_id;
237 }
238 }
239}
240
241TEST_P(ScalabilityStructureTest, NoFrameDependsOnDiscardableOrNotPresent) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200242 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200243 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200244 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200245 ScalabilityStructureWrapper(*svc_controller)
246 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200247 int64_t num_frames = frame_infos.size();
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200248 FrameDependencyStructure structure = svc_controller->DependencyStructure();
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200249
250 for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
251 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
252 const auto& frame = frame_infos[frame_id];
253 if (frame.decode_target_indications[dt] ==
254 DecodeTargetIndication::kNotPresent) {
255 continue;
256 }
257 for (int frame_diff : frame.frame_diffs) {
258 int64_t base_frame_id = frame_id - frame_diff;
259 const auto& base_frame = frame_infos[base_frame_id];
260 EXPECT_NE(base_frame.decode_target_indications[dt],
261 DecodeTargetIndication::kNotPresent)
262 << "Frame " << frame_id << " depends on frame " << base_frame_id
263 << " that is not part of decode target#" << dt;
264 EXPECT_NE(base_frame.decode_target_indications[dt],
265 DecodeTargetIndication::kDiscardable)
266 << "Frame " << frame_id << " depends on frame " << base_frame_id
267 << " that is discardable for decode target#" << dt;
268 }
269 }
270 }
271}
272
273TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200274 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200275 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200276 FrameDependencyStructure structure = svc_controller->DependencyStructure();
277 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200278 ScalabilityStructureWrapper(*svc_controller)
279 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200280 int64_t num_frames = frame_infos.size();
281 std::vector<std::set<int64_t>> full_deps(num_frames);
282
283 // For each frame calculate set of all frames it depends on, both directly and
284 // indirectly.
285 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
286 std::set<int64_t> all_base_frames;
287 for (int frame_diff : frame_infos[frame_id].frame_diffs) {
288 int64_t base_frame_id = frame_id - frame_diff;
289 all_base_frames.insert(base_frame_id);
290 const auto& indirect = full_deps[base_frame_id];
291 all_base_frames.insert(indirect.begin(), indirect.end());
292 }
293 full_deps[frame_id] = std::move(all_base_frames);
294 }
295
296 // Now check the switch indication: frames after the switch indication mustn't
297 // depend on any addition frames before the switch indications.
298 for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
299 for (int64_t switch_frame_id = 0; switch_frame_id < num_frames;
300 ++switch_frame_id) {
301 if (frame_infos[switch_frame_id].decode_target_indications[dt] !=
302 DecodeTargetIndication::kSwitch) {
303 continue;
304 }
305 for (int64_t later_frame_id = switch_frame_id + 1;
306 later_frame_id < num_frames; ++later_frame_id) {
307 if (frame_infos[later_frame_id].decode_target_indications[dt] ==
308 DecodeTargetIndication::kNotPresent) {
309 continue;
310 }
311 for (int frame_diff : frame_infos[later_frame_id].frame_diffs) {
312 int64_t early_frame_id = later_frame_id - frame_diff;
313 if (early_frame_id < switch_frame_id) {
314 EXPECT_THAT(full_deps[switch_frame_id], Contains(early_frame_id))
315 << "For decode target #" << dt << " frame " << later_frame_id
316 << " depends on the frame " << early_frame_id
317 << " that switch indication frame " << switch_frame_id
318 << " doesn't directly on indirectly depend on.";
319 }
320 }
321 }
322 }
323 }
324}
325
Danil Chapovalov71002a22020-10-23 19:04:11 +0200326TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200327 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200328 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200329 ScalableVideoController::StreamLayersConfig structure =
330 svc_controller->StreamConfig();
331
332 VideoBitrateAllocation all_bitrates;
333 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) {
334 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) {
335 all_bitrates.SetBitrate(sid, tid, 100'000);
336 }
337 }
338
339 svc_controller->OnRatesUpdated(all_bitrates);
Danil Chapovalov294729f2020-10-09 18:58:42 +0200340 ScalabilityStructureWrapper wrapper(*svc_controller);
341 std::vector<GenericFrameInfo> frames =
342 wrapper.GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200343
344 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) {
345 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) {
346 // When all layers were enabled, expect there was a frame for each layer.
347 EXPECT_THAT(frames,
348 Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid),
349 Field(&GenericFrameInfo::temporal_id, tid))))
350 << "For layer (" << sid << "," << tid << ")";
351 // Restore bitrates for all layers before disabling single layer.
352 VideoBitrateAllocation bitrates = all_bitrates;
353 bitrates.SetBitrate(sid, tid, 0);
354 svc_controller->OnRatesUpdated(bitrates);
355 // With layer (sid, tid) disabled, expect no frames are produced for it.
356 EXPECT_THAT(
Danil Chapovalov294729f2020-10-09 18:58:42 +0200357 wrapper.GenerateFrames(GetParam().num_temporal_units),
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200358 Not(Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid),
359 Field(&GenericFrameInfo::temporal_id, tid)))))
360 << "For layer (" << sid << "," << tid << ")";
361 }
362 }
363}
364
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200365INSTANTIATE_TEST_SUITE_P(
366 Svc,
367 ScalabilityStructureTest,
Niels Möllercc171952022-04-06 13:37:40 +0200368 Values(SvcTestParam{"L1T1", /*num_temporal_units=*/3},
Danil Chapovalov45d22342021-02-11 14:58:29 +0100369 SvcTestParam{"L1T2", /*num_temporal_units=*/4},
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200370 SvcTestParam{"L1T3", /*num_temporal_units=*/8},
371 SvcTestParam{"L2T1", /*num_temporal_units=*/3},
372 SvcTestParam{"L2T1_KEY", /*num_temporal_units=*/3},
373 SvcTestParam{"L3T1", /*num_temporal_units=*/3},
374 SvcTestParam{"L3T3", /*num_temporal_units=*/8},
375 SvcTestParam{"S2T1", /*num_temporal_units=*/3},
Niels Möller3c24c092022-06-30 15:42:51 +0200376 SvcTestParam{"S2T3", /*num_temporal_units=*/8},
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100377 SvcTestParam{"S3T3", /*num_temporal_units=*/8},
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200378 SvcTestParam{"L2T2", /*num_temporal_units=*/4},
379 SvcTestParam{"L2T2_KEY", /*num_temporal_units=*/4},
Danil Chapovalov4b18e242020-10-16 16:14:58 +0200380 SvcTestParam{"L2T2_KEY_SHIFT", /*num_temporal_units=*/4},
Niels Möller3c24c092022-06-30 15:42:51 +0200381 SvcTestParam{"L2T3", /*num_temporal_units=*/8},
Emil Lundmarkc9b99302021-02-18 16:51:05 +0100382 SvcTestParam{"L2T3_KEY", /*num_temporal_units=*/8},
Danil Chapovalov4b18e242020-10-16 16:14:58 +0200383 SvcTestParam{"L3T3_KEY", /*num_temporal_units=*/8}),
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200384 [](const testing::TestParamInfo<SvcTestParam>& info) {
385 return info.param.name;
386 });
387
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200388} // namespace
389} // namespace webrtc