blob: ffc085da0420c0a53b69a1c2bcfd6517d5cac04d [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"
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020025#include "test/gmock.h"
26#include "test/gtest.h"
27
28namespace webrtc {
29namespace {
30
31using ::testing::AllOf;
Danil Chapovalovaa40b892020-06-03 18:13:20 +020032using ::testing::Contains;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020033using ::testing::Each;
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020034using ::testing::ElementsAreArray;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020035using ::testing::Field;
36using ::testing::Ge;
37using ::testing::IsEmpty;
38using ::testing::Le;
39using ::testing::Lt;
40using ::testing::Not;
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020041using ::testing::NotNull;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020042using ::testing::SizeIs;
43using ::testing::TestWithParam;
44using ::testing::Values;
45
46struct SvcTestParam {
47 friend std::ostream& operator<<(std::ostream& os, const SvcTestParam& param) {
48 return os << param.name;
49 }
50
Niels Möller79d566b2022-04-29 11:03:13 +020051 ScalabilityMode GetScalabilityMode() const {
52 absl::optional<ScalabilityMode> scalability_mode =
53 ScalabilityModeFromString(name);
54 RTC_CHECK(scalability_mode.has_value());
55 return *scalability_mode;
56 }
57
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020058 std::string name;
Danil Chapovalovaa40b892020-06-03 18:13:20 +020059 int num_temporal_units;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020060};
61
Danil Chapovalov294729f2020-10-09 18:58:42 +020062class ScalabilityStructureTest : public TestWithParam<SvcTestParam> {};
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020063
64TEST_P(ScalabilityStructureTest,
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020065 StaticConfigMatchesConfigReturnedByController) {
66 std::unique_ptr<ScalableVideoController> controller =
Niels Möller79d566b2022-04-29 11:03:13 +020067 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020068 absl::optional<ScalableVideoController::StreamLayersConfig> static_config =
Niels Möller79d566b2022-04-29 11:03:13 +020069 ScalabilityStructureConfig(GetParam().GetScalabilityMode());
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020070 ASSERT_THAT(controller, NotNull());
71 ASSERT_NE(static_config, absl::nullopt);
72 ScalableVideoController::StreamLayersConfig config =
73 controller->StreamConfig();
74 EXPECT_EQ(config.num_spatial_layers, static_config->num_spatial_layers);
75 EXPECT_EQ(config.num_temporal_layers, static_config->num_temporal_layers);
76 EXPECT_THAT(
77 rtc::MakeArrayView(config.scaling_factor_num, config.num_spatial_layers),
78 ElementsAreArray(static_config->scaling_factor_num,
79 static_config->num_spatial_layers));
80 EXPECT_THAT(
81 rtc::MakeArrayView(config.scaling_factor_den, config.num_spatial_layers),
82 ElementsAreArray(static_config->scaling_factor_den,
83 static_config->num_spatial_layers));
84}
85
86TEST_P(ScalabilityStructureTest,
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020087 NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) {
88 FrameDependencyStructure structure =
Niels Möller79d566b2022-04-29 11:03:13 +020089 CreateScalabilityStructure(GetParam().GetScalabilityMode())
90 ->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020091 EXPECT_GT(structure.num_decode_targets, 0);
Danil Chapovalov09867d32020-06-18 17:03:57 +020092 EXPECT_LE(structure.num_decode_targets,
93 DependencyDescriptor::kMaxDecodeTargets);
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020094 EXPECT_GE(structure.num_chains, 0);
95 EXPECT_LE(structure.num_chains, structure.num_decode_targets);
96 if (structure.num_chains == 0) {
97 EXPECT_THAT(structure.decode_target_protected_by_chain, IsEmpty());
98 } else {
99 EXPECT_THAT(structure.decode_target_protected_by_chain,
100 AllOf(SizeIs(structure.num_decode_targets), Each(Ge(0)),
Danil Chapovalova5d9c1a2020-07-14 18:00:17 +0200101 Each(Lt(structure.num_chains))));
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200102 }
Danil Chapovalov09867d32020-06-18 17:03:57 +0200103 EXPECT_THAT(structure.templates,
104 SizeIs(Lt(size_t{DependencyDescriptor::kMaxTemplates})));
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200105}
106
107TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) {
108 FrameDependencyStructure structure =
Niels Möller79d566b2022-04-29 11:03:13 +0200109 CreateScalabilityStructure(GetParam().GetScalabilityMode())
110 ->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200111 ASSERT_THAT(structure.templates, Not(IsEmpty()));
112 const auto& first_templates = structure.templates.front();
113 EXPECT_EQ(first_templates.spatial_id, 0);
114 EXPECT_EQ(first_templates.temporal_id, 0);
115 for (size_t i = 1; i < structure.templates.size(); ++i) {
116 const auto& prev_template = structure.templates[i - 1];
117 const auto& next_template = structure.templates[i];
118 if (next_template.spatial_id == prev_template.spatial_id &&
119 next_template.temporal_id == prev_template.temporal_id) {
120 // Same layer, next_layer_idc == 0
121 } else if (next_template.spatial_id == prev_template.spatial_id &&
122 next_template.temporal_id == prev_template.temporal_id + 1) {
123 // Next temporal layer, next_layer_idc == 1
124 } else if (next_template.spatial_id == prev_template.spatial_id + 1 &&
125 next_template.temporal_id == 0) {
126 // Next spatial layer, next_layer_idc == 2
127 } else {
128 // everything else is invalid.
129 ADD_FAILURE() << "Invalid templates order. Template #" << i
130 << " with layer (" << next_template.spatial_id << ","
131 << next_template.temporal_id
132 << ") follows template with layer ("
133 << prev_template.spatial_id << ","
134 << prev_template.temporal_id << ").";
135 }
136 }
137}
138
139TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) {
140 FrameDependencyStructure structure =
Niels Möller79d566b2022-04-29 11:03:13 +0200141 CreateScalabilityStructure(GetParam().GetScalabilityMode())
142 ->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200143 EXPECT_THAT(
144 structure.templates,
145 Each(AllOf(Field(&FrameDependencyTemplate::decode_target_indications,
146 SizeIs(structure.num_decode_targets)),
147 Field(&FrameDependencyTemplate::chain_diffs,
148 SizeIs(structure.num_chains)))));
149}
150
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200151TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200152 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200153 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200154 FrameDependencyStructure structure = svc_controller->DependencyStructure();
155 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200156 ScalabilityStructureWrapper(*svc_controller)
157 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200158 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
159 const auto& frame = frame_infos[frame_id];
160 EXPECT_GE(frame.spatial_id, 0) << " for frame " << frame_id;
161 EXPECT_GE(frame.temporal_id, 0) << " for frame " << frame_id;
162 EXPECT_THAT(frame.decode_target_indications,
163 SizeIs(structure.num_decode_targets))
164 << " for frame " << frame_id;
165 EXPECT_THAT(frame.part_of_chain, SizeIs(structure.num_chains))
166 << " for frame " << frame_id;
167 }
168}
169
170TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200171 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200172 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200173 FrameDependencyStructure structure = svc_controller->DependencyStructure();
174 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200175 ScalabilityStructureWrapper(*svc_controller)
176 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200177 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
178 EXPECT_THAT(structure.templates, Contains(frame_infos[frame_id]))
179 << " for frame " << frame_id;
180 }
181}
182
183TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200184 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200185 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200186 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200187 ScalabilityStructureWrapper(*svc_controller)
188 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200189 int64_t num_frames = frame_infos.size();
190
191 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
192 const auto& frame = frame_infos[frame_id];
193 for (int frame_diff : frame.frame_diffs) {
194 int64_t base_frame_id = frame_id - frame_diff;
195 const auto& base_frame = frame_infos[base_frame_id];
196 EXPECT_GE(frame.spatial_id, base_frame.spatial_id)
197 << "Frame " << frame_id << " depends on frame " << base_frame_id;
198 EXPECT_GE(frame.temporal_id, base_frame.temporal_id)
199 << "Frame " << frame_id << " depends on frame " << base_frame_id;
200 }
201 }
202}
203
204TEST_P(ScalabilityStructureTest, NoFrameDependsOnDiscardableOrNotPresent) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200205 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200206 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200207 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200208 ScalabilityStructureWrapper(*svc_controller)
209 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200210 int64_t num_frames = frame_infos.size();
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200211 FrameDependencyStructure structure = svc_controller->DependencyStructure();
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200212
213 for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
214 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
215 const auto& frame = frame_infos[frame_id];
216 if (frame.decode_target_indications[dt] ==
217 DecodeTargetIndication::kNotPresent) {
218 continue;
219 }
220 for (int frame_diff : frame.frame_diffs) {
221 int64_t base_frame_id = frame_id - frame_diff;
222 const auto& base_frame = frame_infos[base_frame_id];
223 EXPECT_NE(base_frame.decode_target_indications[dt],
224 DecodeTargetIndication::kNotPresent)
225 << "Frame " << frame_id << " depends on frame " << base_frame_id
226 << " that is not part of decode target#" << dt;
227 EXPECT_NE(base_frame.decode_target_indications[dt],
228 DecodeTargetIndication::kDiscardable)
229 << "Frame " << frame_id << " depends on frame " << base_frame_id
230 << " that is discardable for decode target#" << dt;
231 }
232 }
233 }
234}
235
236TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200237 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200238 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200239 FrameDependencyStructure structure = svc_controller->DependencyStructure();
240 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200241 ScalabilityStructureWrapper(*svc_controller)
242 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200243 int64_t num_frames = frame_infos.size();
244 std::vector<std::set<int64_t>> full_deps(num_frames);
245
246 // For each frame calculate set of all frames it depends on, both directly and
247 // indirectly.
248 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
249 std::set<int64_t> all_base_frames;
250 for (int frame_diff : frame_infos[frame_id].frame_diffs) {
251 int64_t base_frame_id = frame_id - frame_diff;
252 all_base_frames.insert(base_frame_id);
253 const auto& indirect = full_deps[base_frame_id];
254 all_base_frames.insert(indirect.begin(), indirect.end());
255 }
256 full_deps[frame_id] = std::move(all_base_frames);
257 }
258
259 // Now check the switch indication: frames after the switch indication mustn't
260 // depend on any addition frames before the switch indications.
261 for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
262 for (int64_t switch_frame_id = 0; switch_frame_id < num_frames;
263 ++switch_frame_id) {
264 if (frame_infos[switch_frame_id].decode_target_indications[dt] !=
265 DecodeTargetIndication::kSwitch) {
266 continue;
267 }
268 for (int64_t later_frame_id = switch_frame_id + 1;
269 later_frame_id < num_frames; ++later_frame_id) {
270 if (frame_infos[later_frame_id].decode_target_indications[dt] ==
271 DecodeTargetIndication::kNotPresent) {
272 continue;
273 }
274 for (int frame_diff : frame_infos[later_frame_id].frame_diffs) {
275 int64_t early_frame_id = later_frame_id - frame_diff;
276 if (early_frame_id < switch_frame_id) {
277 EXPECT_THAT(full_deps[switch_frame_id], Contains(early_frame_id))
278 << "For decode target #" << dt << " frame " << later_frame_id
279 << " depends on the frame " << early_frame_id
280 << " that switch indication frame " << switch_frame_id
281 << " doesn't directly on indirectly depend on.";
282 }
283 }
284 }
285 }
286 }
287}
288
Danil Chapovalov71002a22020-10-23 19:04:11 +0200289TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200290 std::unique_ptr<ScalableVideoController> svc_controller =
Niels Möller79d566b2022-04-29 11:03:13 +0200291 CreateScalabilityStructure(GetParam().GetScalabilityMode());
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200292 ScalableVideoController::StreamLayersConfig structure =
293 svc_controller->StreamConfig();
294
295 VideoBitrateAllocation all_bitrates;
296 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) {
297 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) {
298 all_bitrates.SetBitrate(sid, tid, 100'000);
299 }
300 }
301
302 svc_controller->OnRatesUpdated(all_bitrates);
Danil Chapovalov294729f2020-10-09 18:58:42 +0200303 ScalabilityStructureWrapper wrapper(*svc_controller);
304 std::vector<GenericFrameInfo> frames =
305 wrapper.GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200306
307 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) {
308 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) {
309 // When all layers were enabled, expect there was a frame for each layer.
310 EXPECT_THAT(frames,
311 Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid),
312 Field(&GenericFrameInfo::temporal_id, tid))))
313 << "For layer (" << sid << "," << tid << ")";
314 // Restore bitrates for all layers before disabling single layer.
315 VideoBitrateAllocation bitrates = all_bitrates;
316 bitrates.SetBitrate(sid, tid, 0);
317 svc_controller->OnRatesUpdated(bitrates);
318 // With layer (sid, tid) disabled, expect no frames are produced for it.
319 EXPECT_THAT(
Danil Chapovalov294729f2020-10-09 18:58:42 +0200320 wrapper.GenerateFrames(GetParam().num_temporal_units),
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200321 Not(Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid),
322 Field(&GenericFrameInfo::temporal_id, tid)))))
323 << "For layer (" << sid << "," << tid << ")";
324 }
325 }
326}
327
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200328INSTANTIATE_TEST_SUITE_P(
329 Svc,
330 ScalabilityStructureTest,
Niels Möllercc171952022-04-06 13:37:40 +0200331 Values(SvcTestParam{"L1T1", /*num_temporal_units=*/3},
Danil Chapovalov45d22342021-02-11 14:58:29 +0100332 SvcTestParam{"L1T2", /*num_temporal_units=*/4},
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200333 SvcTestParam{"L1T3", /*num_temporal_units=*/8},
334 SvcTestParam{"L2T1", /*num_temporal_units=*/3},
335 SvcTestParam{"L2T1_KEY", /*num_temporal_units=*/3},
336 SvcTestParam{"L3T1", /*num_temporal_units=*/3},
337 SvcTestParam{"L3T3", /*num_temporal_units=*/8},
338 SvcTestParam{"S2T1", /*num_temporal_units=*/3},
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100339 SvcTestParam{"S3T3", /*num_temporal_units=*/8},
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200340 SvcTestParam{"L2T2", /*num_temporal_units=*/4},
341 SvcTestParam{"L2T2_KEY", /*num_temporal_units=*/4},
Danil Chapovalov4b18e242020-10-16 16:14:58 +0200342 SvcTestParam{"L2T2_KEY_SHIFT", /*num_temporal_units=*/4},
Emil Lundmarkc9b99302021-02-18 16:51:05 +0100343 SvcTestParam{"L2T3_KEY", /*num_temporal_units=*/8},
Danil Chapovalov4b18e242020-10-16 16:14:58 +0200344 SvcTestParam{"L3T3_KEY", /*num_temporal_units=*/8}),
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200345 [](const testing::TestParamInfo<SvcTestParam>& info) {
346 return info.param.name;
347 });
348
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200349} // namespace
350} // namespace webrtc