blob: 9368f57db703e8f72ccbf8937fe8a582c8e6a3bc [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"
22#include "modules/video_coding/svc/scalability_structure_test_helpers.h"
23#include "modules/video_coding/svc/scalable_video_controller.h"
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020024#include "test/gmock.h"
25#include "test/gtest.h"
26
27namespace webrtc {
28namespace {
29
30using ::testing::AllOf;
Danil Chapovalovaa40b892020-06-03 18:13:20 +020031using ::testing::Contains;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020032using ::testing::Each;
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020033using ::testing::ElementsAreArray;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020034using ::testing::Field;
35using ::testing::Ge;
36using ::testing::IsEmpty;
37using ::testing::Le;
38using ::testing::Lt;
39using ::testing::Not;
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020040using ::testing::NotNull;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020041using ::testing::SizeIs;
42using ::testing::TestWithParam;
43using ::testing::Values;
44
45struct SvcTestParam {
46 friend std::ostream& operator<<(std::ostream& os, const SvcTestParam& param) {
47 return os << param.name;
48 }
49
50 std::string name;
Danil Chapovalovaa40b892020-06-03 18:13:20 +020051 int num_temporal_units;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020052};
53
Danil Chapovalov294729f2020-10-09 18:58:42 +020054class ScalabilityStructureTest : public TestWithParam<SvcTestParam> {};
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020055
56TEST_P(ScalabilityStructureTest,
Danil Chapovalov5d3bf6a2021-09-06 15:41:54 +020057 StaticConfigMatchesConfigReturnedByController) {
58 std::unique_ptr<ScalableVideoController> controller =
59 CreateScalabilityStructure(GetParam().name);
60 absl::optional<ScalableVideoController::StreamLayersConfig> static_config =
61 ScalabilityStructureConfig(GetParam().name);
62 ASSERT_THAT(controller, NotNull());
63 ASSERT_NE(static_config, absl::nullopt);
64 ScalableVideoController::StreamLayersConfig config =
65 controller->StreamConfig();
66 EXPECT_EQ(config.num_spatial_layers, static_config->num_spatial_layers);
67 EXPECT_EQ(config.num_temporal_layers, static_config->num_temporal_layers);
68 EXPECT_THAT(
69 rtc::MakeArrayView(config.scaling_factor_num, config.num_spatial_layers),
70 ElementsAreArray(static_config->scaling_factor_num,
71 static_config->num_spatial_layers));
72 EXPECT_THAT(
73 rtc::MakeArrayView(config.scaling_factor_den, config.num_spatial_layers),
74 ElementsAreArray(static_config->scaling_factor_den,
75 static_config->num_spatial_layers));
76}
77
78TEST_P(ScalabilityStructureTest,
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020079 NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) {
80 FrameDependencyStructure structure =
Danil Chapovalova13e7a12020-07-14 12:34:36 +020081 CreateScalabilityStructure(GetParam().name)->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020082 EXPECT_GT(structure.num_decode_targets, 0);
Danil Chapovalov09867d32020-06-18 17:03:57 +020083 EXPECT_LE(structure.num_decode_targets,
84 DependencyDescriptor::kMaxDecodeTargets);
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020085 EXPECT_GE(structure.num_chains, 0);
86 EXPECT_LE(structure.num_chains, structure.num_decode_targets);
87 if (structure.num_chains == 0) {
88 EXPECT_THAT(structure.decode_target_protected_by_chain, IsEmpty());
89 } else {
90 EXPECT_THAT(structure.decode_target_protected_by_chain,
91 AllOf(SizeIs(structure.num_decode_targets), Each(Ge(0)),
Danil Chapovalova5d9c1a2020-07-14 18:00:17 +020092 Each(Lt(structure.num_chains))));
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020093 }
Danil Chapovalov09867d32020-06-18 17:03:57 +020094 EXPECT_THAT(structure.templates,
95 SizeIs(Lt(size_t{DependencyDescriptor::kMaxTemplates})));
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020096}
97
98TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) {
99 FrameDependencyStructure structure =
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200100 CreateScalabilityStructure(GetParam().name)->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200101 ASSERT_THAT(structure.templates, Not(IsEmpty()));
102 const auto& first_templates = structure.templates.front();
103 EXPECT_EQ(first_templates.spatial_id, 0);
104 EXPECT_EQ(first_templates.temporal_id, 0);
105 for (size_t i = 1; i < structure.templates.size(); ++i) {
106 const auto& prev_template = structure.templates[i - 1];
107 const auto& next_template = structure.templates[i];
108 if (next_template.spatial_id == prev_template.spatial_id &&
109 next_template.temporal_id == prev_template.temporal_id) {
110 // Same layer, next_layer_idc == 0
111 } else if (next_template.spatial_id == prev_template.spatial_id &&
112 next_template.temporal_id == prev_template.temporal_id + 1) {
113 // Next temporal layer, next_layer_idc == 1
114 } else if (next_template.spatial_id == prev_template.spatial_id + 1 &&
115 next_template.temporal_id == 0) {
116 // Next spatial layer, next_layer_idc == 2
117 } else {
118 // everything else is invalid.
119 ADD_FAILURE() << "Invalid templates order. Template #" << i
120 << " with layer (" << next_template.spatial_id << ","
121 << next_template.temporal_id
122 << ") follows template with layer ("
123 << prev_template.spatial_id << ","
124 << prev_template.temporal_id << ").";
125 }
126 }
127}
128
129TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) {
130 FrameDependencyStructure structure =
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200131 CreateScalabilityStructure(GetParam().name)->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200132 EXPECT_THAT(
133 structure.templates,
134 Each(AllOf(Field(&FrameDependencyTemplate::decode_target_indications,
135 SizeIs(structure.num_decode_targets)),
136 Field(&FrameDependencyTemplate::chain_diffs,
137 SizeIs(structure.num_chains)))));
138}
139
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200140TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200141 std::unique_ptr<ScalableVideoController> svc_controller =
142 CreateScalabilityStructure(GetParam().name);
143 FrameDependencyStructure structure = svc_controller->DependencyStructure();
144 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200145 ScalabilityStructureWrapper(*svc_controller)
146 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200147 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
148 const auto& frame = frame_infos[frame_id];
149 EXPECT_GE(frame.spatial_id, 0) << " for frame " << frame_id;
150 EXPECT_GE(frame.temporal_id, 0) << " for frame " << frame_id;
151 EXPECT_THAT(frame.decode_target_indications,
152 SizeIs(structure.num_decode_targets))
153 << " for frame " << frame_id;
154 EXPECT_THAT(frame.part_of_chain, SizeIs(structure.num_chains))
155 << " for frame " << frame_id;
156 }
157}
158
159TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200160 std::unique_ptr<ScalableVideoController> svc_controller =
161 CreateScalabilityStructure(GetParam().name);
162 FrameDependencyStructure structure = svc_controller->DependencyStructure();
163 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200164 ScalabilityStructureWrapper(*svc_controller)
165 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200166 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
167 EXPECT_THAT(structure.templates, Contains(frame_infos[frame_id]))
168 << " for frame " << frame_id;
169 }
170}
171
172TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200173 std::unique_ptr<ScalableVideoController> svc_controller =
174 CreateScalabilityStructure(GetParam().name);
175 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200176 ScalabilityStructureWrapper(*svc_controller)
177 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200178 int64_t num_frames = frame_infos.size();
179
180 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
181 const auto& frame = frame_infos[frame_id];
182 for (int frame_diff : frame.frame_diffs) {
183 int64_t base_frame_id = frame_id - frame_diff;
184 const auto& base_frame = frame_infos[base_frame_id];
185 EXPECT_GE(frame.spatial_id, base_frame.spatial_id)
186 << "Frame " << frame_id << " depends on frame " << base_frame_id;
187 EXPECT_GE(frame.temporal_id, base_frame.temporal_id)
188 << "Frame " << frame_id << " depends on frame " << base_frame_id;
189 }
190 }
191}
192
193TEST_P(ScalabilityStructureTest, NoFrameDependsOnDiscardableOrNotPresent) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200194 std::unique_ptr<ScalableVideoController> svc_controller =
195 CreateScalabilityStructure(GetParam().name);
196 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200197 ScalabilityStructureWrapper(*svc_controller)
198 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200199 int64_t num_frames = frame_infos.size();
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200200 FrameDependencyStructure structure = svc_controller->DependencyStructure();
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200201
202 for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
203 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
204 const auto& frame = frame_infos[frame_id];
205 if (frame.decode_target_indications[dt] ==
206 DecodeTargetIndication::kNotPresent) {
207 continue;
208 }
209 for (int frame_diff : frame.frame_diffs) {
210 int64_t base_frame_id = frame_id - frame_diff;
211 const auto& base_frame = frame_infos[base_frame_id];
212 EXPECT_NE(base_frame.decode_target_indications[dt],
213 DecodeTargetIndication::kNotPresent)
214 << "Frame " << frame_id << " depends on frame " << base_frame_id
215 << " that is not part of decode target#" << dt;
216 EXPECT_NE(base_frame.decode_target_indications[dt],
217 DecodeTargetIndication::kDiscardable)
218 << "Frame " << frame_id << " depends on frame " << base_frame_id
219 << " that is discardable for decode target#" << dt;
220 }
221 }
222 }
223}
224
225TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200226 std::unique_ptr<ScalableVideoController> svc_controller =
227 CreateScalabilityStructure(GetParam().name);
228 FrameDependencyStructure structure = svc_controller->DependencyStructure();
229 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200230 ScalabilityStructureWrapper(*svc_controller)
231 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200232 int64_t num_frames = frame_infos.size();
233 std::vector<std::set<int64_t>> full_deps(num_frames);
234
235 // For each frame calculate set of all frames it depends on, both directly and
236 // indirectly.
237 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
238 std::set<int64_t> all_base_frames;
239 for (int frame_diff : frame_infos[frame_id].frame_diffs) {
240 int64_t base_frame_id = frame_id - frame_diff;
241 all_base_frames.insert(base_frame_id);
242 const auto& indirect = full_deps[base_frame_id];
243 all_base_frames.insert(indirect.begin(), indirect.end());
244 }
245 full_deps[frame_id] = std::move(all_base_frames);
246 }
247
248 // Now check the switch indication: frames after the switch indication mustn't
249 // depend on any addition frames before the switch indications.
250 for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
251 for (int64_t switch_frame_id = 0; switch_frame_id < num_frames;
252 ++switch_frame_id) {
253 if (frame_infos[switch_frame_id].decode_target_indications[dt] !=
254 DecodeTargetIndication::kSwitch) {
255 continue;
256 }
257 for (int64_t later_frame_id = switch_frame_id + 1;
258 later_frame_id < num_frames; ++later_frame_id) {
259 if (frame_infos[later_frame_id].decode_target_indications[dt] ==
260 DecodeTargetIndication::kNotPresent) {
261 continue;
262 }
263 for (int frame_diff : frame_infos[later_frame_id].frame_diffs) {
264 int64_t early_frame_id = later_frame_id - frame_diff;
265 if (early_frame_id < switch_frame_id) {
266 EXPECT_THAT(full_deps[switch_frame_id], Contains(early_frame_id))
267 << "For decode target #" << dt << " frame " << later_frame_id
268 << " depends on the frame " << early_frame_id
269 << " that switch indication frame " << switch_frame_id
270 << " doesn't directly on indirectly depend on.";
271 }
272 }
273 }
274 }
275 }
276}
277
Danil Chapovalov71002a22020-10-23 19:04:11 +0200278TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200279 std::unique_ptr<ScalableVideoController> svc_controller =
280 CreateScalabilityStructure(GetParam().name);
281 ScalableVideoController::StreamLayersConfig structure =
282 svc_controller->StreamConfig();
283
284 VideoBitrateAllocation all_bitrates;
285 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) {
286 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) {
287 all_bitrates.SetBitrate(sid, tid, 100'000);
288 }
289 }
290
291 svc_controller->OnRatesUpdated(all_bitrates);
Danil Chapovalov294729f2020-10-09 18:58:42 +0200292 ScalabilityStructureWrapper wrapper(*svc_controller);
293 std::vector<GenericFrameInfo> frames =
294 wrapper.GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200295
296 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) {
297 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) {
298 // When all layers were enabled, expect there was a frame for each layer.
299 EXPECT_THAT(frames,
300 Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid),
301 Field(&GenericFrameInfo::temporal_id, tid))))
302 << "For layer (" << sid << "," << tid << ")";
303 // Restore bitrates for all layers before disabling single layer.
304 VideoBitrateAllocation bitrates = all_bitrates;
305 bitrates.SetBitrate(sid, tid, 0);
306 svc_controller->OnRatesUpdated(bitrates);
307 // With layer (sid, tid) disabled, expect no frames are produced for it.
308 EXPECT_THAT(
Danil Chapovalov294729f2020-10-09 18:58:42 +0200309 wrapper.GenerateFrames(GetParam().num_temporal_units),
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200310 Not(Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid),
311 Field(&GenericFrameInfo::temporal_id, tid)))))
312 << "For layer (" << sid << "," << tid << ")";
313 }
314 }
315}
316
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200317INSTANTIATE_TEST_SUITE_P(
318 Svc,
319 ScalabilityStructureTest,
Danil Chapovalov45d22342021-02-11 14:58:29 +0100320 Values(SvcTestParam{"NONE", /*num_temporal_units=*/3},
321 SvcTestParam{"L1T2", /*num_temporal_units=*/4},
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200322 SvcTestParam{"L1T3", /*num_temporal_units=*/8},
323 SvcTestParam{"L2T1", /*num_temporal_units=*/3},
324 SvcTestParam{"L2T1_KEY", /*num_temporal_units=*/3},
325 SvcTestParam{"L3T1", /*num_temporal_units=*/3},
326 SvcTestParam{"L3T3", /*num_temporal_units=*/8},
327 SvcTestParam{"S2T1", /*num_temporal_units=*/3},
Danil Chapovalov735e33f2021-02-18 14:39:52 +0100328 SvcTestParam{"S3T3", /*num_temporal_units=*/8},
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200329 SvcTestParam{"L2T2", /*num_temporal_units=*/4},
330 SvcTestParam{"L2T2_KEY", /*num_temporal_units=*/4},
Danil Chapovalov4b18e242020-10-16 16:14:58 +0200331 SvcTestParam{"L2T2_KEY_SHIFT", /*num_temporal_units=*/4},
Emil Lundmarkc9b99302021-02-18 16:51:05 +0100332 SvcTestParam{"L2T3_KEY", /*num_temporal_units=*/8},
Danil Chapovalov4b18e242020-10-16 16:14:58 +0200333 SvcTestParam{"L3T3_KEY", /*num_temporal_units=*/8}),
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200334 [](const testing::TestParamInfo<SvcTestParam>& info) {
335 return info.param.name;
336 });
337
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200338} // namespace
339} // namespace webrtc