blob: d6766f0d507777bcf87ad6434a9c04b4d0c28b64 [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 Chapovalov09867d32020-06-18 17:03:57 +020019#include "api/transport/rtp/dependency_descriptor.h"
Danil Chapovalovda7fe392020-10-15 15:57:17 +020020#include "modules/video_coding/svc/create_scalability_structure.h"
21#include "modules/video_coding/svc/scalability_structure_test_helpers.h"
22#include "modules/video_coding/svc/scalable_video_controller.h"
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020023#include "test/gmock.h"
24#include "test/gtest.h"
25
26namespace webrtc {
27namespace {
28
29using ::testing::AllOf;
Danil Chapovalovaa40b892020-06-03 18:13:20 +020030using ::testing::Contains;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020031using ::testing::Each;
32using ::testing::Field;
33using ::testing::Ge;
34using ::testing::IsEmpty;
35using ::testing::Le;
36using ::testing::Lt;
37using ::testing::Not;
38using ::testing::SizeIs;
39using ::testing::TestWithParam;
40using ::testing::Values;
41
42struct SvcTestParam {
43 friend std::ostream& operator<<(std::ostream& os, const SvcTestParam& param) {
44 return os << param.name;
45 }
46
47 std::string name;
Danil Chapovalovaa40b892020-06-03 18:13:20 +020048 int num_temporal_units;
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020049};
50
Danil Chapovalov294729f2020-10-09 18:58:42 +020051class ScalabilityStructureTest : public TestWithParam<SvcTestParam> {};
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020052
53TEST_P(ScalabilityStructureTest,
54 NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) {
55 FrameDependencyStructure structure =
Danil Chapovalova13e7a12020-07-14 12:34:36 +020056 CreateScalabilityStructure(GetParam().name)->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020057 EXPECT_GT(structure.num_decode_targets, 0);
Danil Chapovalov09867d32020-06-18 17:03:57 +020058 EXPECT_LE(structure.num_decode_targets,
59 DependencyDescriptor::kMaxDecodeTargets);
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020060 EXPECT_GE(structure.num_chains, 0);
61 EXPECT_LE(structure.num_chains, structure.num_decode_targets);
62 if (structure.num_chains == 0) {
63 EXPECT_THAT(structure.decode_target_protected_by_chain, IsEmpty());
64 } else {
65 EXPECT_THAT(structure.decode_target_protected_by_chain,
66 AllOf(SizeIs(structure.num_decode_targets), Each(Ge(0)),
Danil Chapovalova5d9c1a2020-07-14 18:00:17 +020067 Each(Lt(structure.num_chains))));
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020068 }
Danil Chapovalov09867d32020-06-18 17:03:57 +020069 EXPECT_THAT(structure.templates,
70 SizeIs(Lt(size_t{DependencyDescriptor::kMaxTemplates})));
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020071}
72
73TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) {
74 FrameDependencyStructure structure =
Danil Chapovalova13e7a12020-07-14 12:34:36 +020075 CreateScalabilityStructure(GetParam().name)->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +020076 ASSERT_THAT(structure.templates, Not(IsEmpty()));
77 const auto& first_templates = structure.templates.front();
78 EXPECT_EQ(first_templates.spatial_id, 0);
79 EXPECT_EQ(first_templates.temporal_id, 0);
80 for (size_t i = 1; i < structure.templates.size(); ++i) {
81 const auto& prev_template = structure.templates[i - 1];
82 const auto& next_template = structure.templates[i];
83 if (next_template.spatial_id == prev_template.spatial_id &&
84 next_template.temporal_id == prev_template.temporal_id) {
85 // Same layer, next_layer_idc == 0
86 } else if (next_template.spatial_id == prev_template.spatial_id &&
87 next_template.temporal_id == prev_template.temporal_id + 1) {
88 // Next temporal layer, next_layer_idc == 1
89 } else if (next_template.spatial_id == prev_template.spatial_id + 1 &&
90 next_template.temporal_id == 0) {
91 // Next spatial layer, next_layer_idc == 2
92 } else {
93 // everything else is invalid.
94 ADD_FAILURE() << "Invalid templates order. Template #" << i
95 << " with layer (" << next_template.spatial_id << ","
96 << next_template.temporal_id
97 << ") follows template with layer ("
98 << prev_template.spatial_id << ","
99 << prev_template.temporal_id << ").";
100 }
101 }
102}
103
104TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) {
105 FrameDependencyStructure structure =
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200106 CreateScalabilityStructure(GetParam().name)->DependencyStructure();
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200107 EXPECT_THAT(
108 structure.templates,
109 Each(AllOf(Field(&FrameDependencyTemplate::decode_target_indications,
110 SizeIs(structure.num_decode_targets)),
111 Field(&FrameDependencyTemplate::chain_diffs,
112 SizeIs(structure.num_chains)))));
113}
114
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200115TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200116 std::unique_ptr<ScalableVideoController> svc_controller =
117 CreateScalabilityStructure(GetParam().name);
118 FrameDependencyStructure structure = svc_controller->DependencyStructure();
119 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200120 ScalabilityStructureWrapper(*svc_controller)
121 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200122 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
123 const auto& frame = frame_infos[frame_id];
124 EXPECT_GE(frame.spatial_id, 0) << " for frame " << frame_id;
125 EXPECT_GE(frame.temporal_id, 0) << " for frame " << frame_id;
126 EXPECT_THAT(frame.decode_target_indications,
127 SizeIs(structure.num_decode_targets))
128 << " for frame " << frame_id;
129 EXPECT_THAT(frame.part_of_chain, SizeIs(structure.num_chains))
130 << " for frame " << frame_id;
131 }
132}
133
134TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200135 std::unique_ptr<ScalableVideoController> svc_controller =
136 CreateScalabilityStructure(GetParam().name);
137 FrameDependencyStructure structure = svc_controller->DependencyStructure();
138 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200139 ScalabilityStructureWrapper(*svc_controller)
140 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200141 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) {
142 EXPECT_THAT(structure.templates, Contains(frame_infos[frame_id]))
143 << " for frame " << frame_id;
144 }
145}
146
147TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200148 std::unique_ptr<ScalableVideoController> svc_controller =
149 CreateScalabilityStructure(GetParam().name);
150 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200151 ScalabilityStructureWrapper(*svc_controller)
152 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200153 int64_t num_frames = frame_infos.size();
154
155 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
156 const auto& frame = frame_infos[frame_id];
157 for (int frame_diff : frame.frame_diffs) {
158 int64_t base_frame_id = frame_id - frame_diff;
159 const auto& base_frame = frame_infos[base_frame_id];
160 EXPECT_GE(frame.spatial_id, base_frame.spatial_id)
161 << "Frame " << frame_id << " depends on frame " << base_frame_id;
162 EXPECT_GE(frame.temporal_id, base_frame.temporal_id)
163 << "Frame " << frame_id << " depends on frame " << base_frame_id;
164 }
165 }
166}
167
168TEST_P(ScalabilityStructureTest, NoFrameDependsOnDiscardableOrNotPresent) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200169 std::unique_ptr<ScalableVideoController> svc_controller =
170 CreateScalabilityStructure(GetParam().name);
171 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200172 ScalabilityStructureWrapper(*svc_controller)
173 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200174 int64_t num_frames = frame_infos.size();
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200175 FrameDependencyStructure structure = svc_controller->DependencyStructure();
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200176
177 for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
178 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
179 const auto& frame = frame_infos[frame_id];
180 if (frame.decode_target_indications[dt] ==
181 DecodeTargetIndication::kNotPresent) {
182 continue;
183 }
184 for (int frame_diff : frame.frame_diffs) {
185 int64_t base_frame_id = frame_id - frame_diff;
186 const auto& base_frame = frame_infos[base_frame_id];
187 EXPECT_NE(base_frame.decode_target_indications[dt],
188 DecodeTargetIndication::kNotPresent)
189 << "Frame " << frame_id << " depends on frame " << base_frame_id
190 << " that is not part of decode target#" << dt;
191 EXPECT_NE(base_frame.decode_target_indications[dt],
192 DecodeTargetIndication::kDiscardable)
193 << "Frame " << frame_id << " depends on frame " << base_frame_id
194 << " that is discardable for decode target#" << dt;
195 }
196 }
197 }
198}
199
200TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200201 std::unique_ptr<ScalableVideoController> svc_controller =
202 CreateScalabilityStructure(GetParam().name);
203 FrameDependencyStructure structure = svc_controller->DependencyStructure();
204 std::vector<GenericFrameInfo> frame_infos =
Danil Chapovalov294729f2020-10-09 18:58:42 +0200205 ScalabilityStructureWrapper(*svc_controller)
206 .GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovaa40b892020-06-03 18:13:20 +0200207 int64_t num_frames = frame_infos.size();
208 std::vector<std::set<int64_t>> full_deps(num_frames);
209
210 // For each frame calculate set of all frames it depends on, both directly and
211 // indirectly.
212 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) {
213 std::set<int64_t> all_base_frames;
214 for (int frame_diff : frame_infos[frame_id].frame_diffs) {
215 int64_t base_frame_id = frame_id - frame_diff;
216 all_base_frames.insert(base_frame_id);
217 const auto& indirect = full_deps[base_frame_id];
218 all_base_frames.insert(indirect.begin(), indirect.end());
219 }
220 full_deps[frame_id] = std::move(all_base_frames);
221 }
222
223 // Now check the switch indication: frames after the switch indication mustn't
224 // depend on any addition frames before the switch indications.
225 for (int dt = 0; dt < structure.num_decode_targets; ++dt) {
226 for (int64_t switch_frame_id = 0; switch_frame_id < num_frames;
227 ++switch_frame_id) {
228 if (frame_infos[switch_frame_id].decode_target_indications[dt] !=
229 DecodeTargetIndication::kSwitch) {
230 continue;
231 }
232 for (int64_t later_frame_id = switch_frame_id + 1;
233 later_frame_id < num_frames; ++later_frame_id) {
234 if (frame_infos[later_frame_id].decode_target_indications[dt] ==
235 DecodeTargetIndication::kNotPresent) {
236 continue;
237 }
238 for (int frame_diff : frame_infos[later_frame_id].frame_diffs) {
239 int64_t early_frame_id = later_frame_id - frame_diff;
240 if (early_frame_id < switch_frame_id) {
241 EXPECT_THAT(full_deps[switch_frame_id], Contains(early_frame_id))
242 << "For decode target #" << dt << " frame " << later_frame_id
243 << " depends on the frame " << early_frame_id
244 << " that switch indication frame " << switch_frame_id
245 << " doesn't directly on indirectly depend on.";
246 }
247 }
248 }
249 }
250 }
251}
252
Danil Chapovalov71002a22020-10-23 19:04:11 +0200253TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) {
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200254 std::unique_ptr<ScalableVideoController> svc_controller =
255 CreateScalabilityStructure(GetParam().name);
256 ScalableVideoController::StreamLayersConfig structure =
257 svc_controller->StreamConfig();
258
259 VideoBitrateAllocation all_bitrates;
260 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) {
261 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) {
262 all_bitrates.SetBitrate(sid, tid, 100'000);
263 }
264 }
265
266 svc_controller->OnRatesUpdated(all_bitrates);
Danil Chapovalov294729f2020-10-09 18:58:42 +0200267 ScalabilityStructureWrapper wrapper(*svc_controller);
268 std::vector<GenericFrameInfo> frames =
269 wrapper.GenerateFrames(GetParam().num_temporal_units);
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200270
271 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) {
272 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) {
273 // When all layers were enabled, expect there was a frame for each layer.
274 EXPECT_THAT(frames,
275 Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid),
276 Field(&GenericFrameInfo::temporal_id, tid))))
277 << "For layer (" << sid << "," << tid << ")";
278 // Restore bitrates for all layers before disabling single layer.
279 VideoBitrateAllocation bitrates = all_bitrates;
280 bitrates.SetBitrate(sid, tid, 0);
281 svc_controller->OnRatesUpdated(bitrates);
282 // With layer (sid, tid) disabled, expect no frames are produced for it.
283 EXPECT_THAT(
Danil Chapovalov294729f2020-10-09 18:58:42 +0200284 wrapper.GenerateFrames(GetParam().num_temporal_units),
Danil Chapovalovb6103ff2020-09-28 12:32:41 +0200285 Not(Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid),
286 Field(&GenericFrameInfo::temporal_id, tid)))))
287 << "For layer (" << sid << "," << tid << ")";
288 }
289 }
290}
291
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200292INSTANTIATE_TEST_SUITE_P(
293 Svc,
294 ScalabilityStructureTest,
Danil Chapovalova13e7a12020-07-14 12:34:36 +0200295 Values(SvcTestParam{"L1T2", /*num_temporal_units=*/4},
296 SvcTestParam{"L1T3", /*num_temporal_units=*/8},
297 SvcTestParam{"L2T1", /*num_temporal_units=*/3},
298 SvcTestParam{"L2T1_KEY", /*num_temporal_units=*/3},
299 SvcTestParam{"L3T1", /*num_temporal_units=*/3},
300 SvcTestParam{"L3T3", /*num_temporal_units=*/8},
301 SvcTestParam{"S2T1", /*num_temporal_units=*/3},
302 SvcTestParam{"L2T2", /*num_temporal_units=*/4},
303 SvcTestParam{"L2T2_KEY", /*num_temporal_units=*/4},
Danil Chapovalov4b18e242020-10-16 16:14:58 +0200304 SvcTestParam{"L2T2_KEY_SHIFT", /*num_temporal_units=*/4},
305 SvcTestParam{"L3T3_KEY", /*num_temporal_units=*/8}),
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200306 [](const testing::TestParamInfo<SvcTestParam>& info) {
307 return info.param.name;
308 });
309
Danil Chapovalov40f1fe92020-06-03 12:01:41 +0200310} // namespace
311} // namespace webrtc