scalability_structure_unittest.cc (16760B)
1 /* 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 <cstddef> 12 #include <cstdint> 13 #include <memory> 14 #include <optional> 15 #include <ostream> 16 #include <set> 17 #include <string> 18 #include <utility> 19 #include <vector> 20 21 #include "api/array_view.h" 22 #include "api/transport/rtp/dependency_descriptor.h" 23 #include "api/video/video_bitrate_allocation.h" 24 #include "api/video_codecs/scalability_mode.h" 25 #include "common_video/generic_frame_descriptor/generic_frame_info.h" 26 #include "modules/video_coding/svc/create_scalability_structure.h" 27 #include "modules/video_coding/svc/scalability_mode_util.h" 28 #include "modules/video_coding/svc/scalability_structure_test_helpers.h" 29 #include "modules/video_coding/svc/scalable_video_controller.h" 30 #include "rtc_base/checks.h" 31 #include "rtc_base/strings/string_builder.h" 32 #include "test/gmock.h" 33 #include "test/gtest.h" 34 35 namespace webrtc { 36 namespace { 37 38 using ::testing::AllOf; 39 using ::testing::Contains; 40 using ::testing::Each; 41 using ::testing::ElementsAreArray; 42 using ::testing::Field; 43 using ::testing::Ge; 44 using ::testing::IsEmpty; 45 using ::testing::Le; 46 using ::testing::Lt; 47 using ::testing::Not; 48 using ::testing::NotNull; 49 using ::testing::SizeIs; 50 using ::testing::TestWithParam; 51 using ::testing::Values; 52 53 std::string FrameDependencyTemplateToString(const FrameDependencyTemplate& t) { 54 StringBuilder sb; 55 sb << "S" << t.spatial_id << "T" << t.temporal_id; 56 sb << ": dtis = "; 57 for (const auto dtis : t.decode_target_indications) { 58 switch (dtis) { 59 case DecodeTargetIndication::kNotPresent: 60 sb << "-"; 61 break; 62 case DecodeTargetIndication::kDiscardable: 63 sb << "D"; 64 break; 65 case DecodeTargetIndication::kSwitch: 66 sb << "S"; 67 break; 68 case DecodeTargetIndication::kRequired: 69 sb << "R"; 70 break; 71 default: 72 sb << "?"; 73 break; 74 } 75 } 76 sb << ", frame diffs = { "; 77 for (int d : t.frame_diffs) { 78 sb << d << ", "; 79 } 80 sb << "}, chain diffs = { "; 81 for (int d : t.chain_diffs) { 82 sb << d << ", "; 83 } 84 sb << "}"; 85 return sb.Release(); 86 } 87 88 struct SvcTestParam { 89 friend std::ostream& operator<<(std::ostream& os, const SvcTestParam& param) { 90 return os << param.name; 91 } 92 93 ScalabilityMode GetScalabilityMode() const { 94 std::optional<ScalabilityMode> scalability_mode = 95 ScalabilityModeFromString(name); 96 RTC_CHECK(scalability_mode.has_value()); 97 return *scalability_mode; 98 } 99 100 std::string name; 101 int num_temporal_units; 102 }; 103 104 class ScalabilityStructureTest : public TestWithParam<SvcTestParam> {}; 105 106 TEST_P(ScalabilityStructureTest, 107 StaticConfigMatchesConfigReturnedByController) { 108 std::unique_ptr<ScalableVideoController> controller = 109 CreateScalabilityStructure(GetParam().GetScalabilityMode()); 110 std::optional<ScalableVideoController::StreamLayersConfig> static_config = 111 ScalabilityStructureConfig(GetParam().GetScalabilityMode()); 112 ASSERT_THAT(controller, NotNull()); 113 ASSERT_NE(static_config, std::nullopt); 114 ScalableVideoController::StreamLayersConfig config = 115 controller->StreamConfig(); 116 EXPECT_EQ(config.num_spatial_layers, static_config->num_spatial_layers); 117 EXPECT_EQ(config.num_temporal_layers, static_config->num_temporal_layers); 118 EXPECT_THAT( 119 MakeArrayView(config.scaling_factor_num, config.num_spatial_layers), 120 ElementsAreArray(static_config->scaling_factor_num, 121 static_config->num_spatial_layers)); 122 EXPECT_THAT( 123 MakeArrayView(config.scaling_factor_den, config.num_spatial_layers), 124 ElementsAreArray(static_config->scaling_factor_den, 125 static_config->num_spatial_layers)); 126 } 127 128 TEST_P(ScalabilityStructureTest, 129 NumberOfDecodeTargetsAndChainsAreInRangeAndConsistent) { 130 FrameDependencyStructure structure = 131 CreateScalabilityStructure(GetParam().GetScalabilityMode()) 132 ->DependencyStructure(); 133 EXPECT_GT(structure.num_decode_targets, 0); 134 EXPECT_LE(structure.num_decode_targets, 135 DependencyDescriptor::kMaxDecodeTargets); 136 EXPECT_GE(structure.num_chains, 0); 137 EXPECT_LE(structure.num_chains, structure.num_decode_targets); 138 if (structure.num_chains == 0) { 139 EXPECT_THAT(structure.decode_target_protected_by_chain, IsEmpty()); 140 } else { 141 EXPECT_THAT(structure.decode_target_protected_by_chain, 142 AllOf(SizeIs(structure.num_decode_targets), Each(Ge(0)), 143 Each(Lt(structure.num_chains)))); 144 } 145 EXPECT_THAT(structure.templates, 146 SizeIs(Lt(size_t{DependencyDescriptor::kMaxTemplates}))); 147 } 148 149 TEST_P(ScalabilityStructureTest, TemplatesAreSortedByLayerId) { 150 FrameDependencyStructure structure = 151 CreateScalabilityStructure(GetParam().GetScalabilityMode()) 152 ->DependencyStructure(); 153 ASSERT_THAT(structure.templates, Not(IsEmpty())); 154 const auto& first_templates = structure.templates.front(); 155 EXPECT_EQ(first_templates.spatial_id, 0); 156 EXPECT_EQ(first_templates.temporal_id, 0); 157 for (size_t i = 1; i < structure.templates.size(); ++i) { 158 const auto& prev_template = structure.templates[i - 1]; 159 const auto& next_template = structure.templates[i]; 160 if (next_template.spatial_id == prev_template.spatial_id && 161 next_template.temporal_id == prev_template.temporal_id) { 162 // Same layer, next_layer_idc == 0 163 } else if (next_template.spatial_id == prev_template.spatial_id && 164 next_template.temporal_id == prev_template.temporal_id + 1) { 165 // Next temporal layer, next_layer_idc == 1 166 } else if (next_template.spatial_id == prev_template.spatial_id + 1 && 167 next_template.temporal_id == 0) { 168 // Next spatial layer, next_layer_idc == 2 169 } else { 170 // everything else is invalid. 171 ADD_FAILURE() << "Invalid templates order. Template #" << i 172 << " with layer (" << next_template.spatial_id << "," 173 << next_template.temporal_id 174 << ") follows template with layer (" 175 << prev_template.spatial_id << "," 176 << prev_template.temporal_id << ")."; 177 } 178 } 179 } 180 181 TEST_P(ScalabilityStructureTest, TemplatesMatchNumberOfDecodeTargetsAndChains) { 182 FrameDependencyStructure structure = 183 CreateScalabilityStructure(GetParam().GetScalabilityMode()) 184 ->DependencyStructure(); 185 EXPECT_THAT( 186 structure.templates, 187 Each(AllOf(Field(&FrameDependencyTemplate::decode_target_indications, 188 SizeIs(structure.num_decode_targets)), 189 Field(&FrameDependencyTemplate::chain_diffs, 190 SizeIs(structure.num_chains))))); 191 } 192 193 TEST_P(ScalabilityStructureTest, FrameInfoMatchesFrameDependencyStructure) { 194 std::unique_ptr<ScalableVideoController> svc_controller = 195 CreateScalabilityStructure(GetParam().GetScalabilityMode()); 196 FrameDependencyStructure structure = svc_controller->DependencyStructure(); 197 std::vector<GenericFrameInfo> frame_infos = 198 ScalabilityStructureWrapper(*svc_controller) 199 .GenerateFrames(GetParam().num_temporal_units); 200 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) { 201 const auto& frame = frame_infos[frame_id]; 202 EXPECT_GE(frame.spatial_id, 0) << " for frame " << frame_id; 203 EXPECT_GE(frame.temporal_id, 0) << " for frame " << frame_id; 204 EXPECT_THAT(frame.decode_target_indications, 205 SizeIs(structure.num_decode_targets)) 206 << " for frame " << frame_id; 207 EXPECT_THAT(frame.part_of_chain, SizeIs(structure.num_chains)) 208 << " for frame " << frame_id; 209 } 210 } 211 212 TEST_P(ScalabilityStructureTest, ThereIsAPerfectTemplateForEachFrame) { 213 std::unique_ptr<ScalableVideoController> svc_controller = 214 CreateScalabilityStructure(GetParam().GetScalabilityMode()); 215 FrameDependencyStructure structure = svc_controller->DependencyStructure(); 216 std::vector<GenericFrameInfo> frame_infos = 217 ScalabilityStructureWrapper(*svc_controller) 218 .GenerateFrames(GetParam().num_temporal_units); 219 for (size_t frame_id = 0; frame_id < frame_infos.size(); ++frame_id) { 220 EXPECT_THAT(structure.templates, Contains(frame_infos[frame_id])) 221 << " for frame " << frame_id << ", Expected " 222 << FrameDependencyTemplateToString(frame_infos[frame_id]); 223 } 224 } 225 226 TEST_P(ScalabilityStructureTest, FrameDependsOnSameOrLowerLayer) { 227 std::unique_ptr<ScalableVideoController> svc_controller = 228 CreateScalabilityStructure(GetParam().GetScalabilityMode()); 229 std::vector<GenericFrameInfo> frame_infos = 230 ScalabilityStructureWrapper(*svc_controller) 231 .GenerateFrames(GetParam().num_temporal_units); 232 int64_t num_frames = frame_infos.size(); 233 234 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) { 235 const auto& frame = frame_infos[frame_id]; 236 for (int frame_diff : frame.frame_diffs) { 237 int64_t base_frame_id = frame_id - frame_diff; 238 const auto& base_frame = frame_infos[base_frame_id]; 239 EXPECT_GE(frame.spatial_id, base_frame.spatial_id) 240 << "Frame " << frame_id << " depends on frame " << base_frame_id; 241 EXPECT_GE(frame.temporal_id, base_frame.temporal_id) 242 << "Frame " << frame_id << " depends on frame " << base_frame_id; 243 } 244 } 245 } 246 247 TEST_P(ScalabilityStructureTest, NoFrameDependsOnDiscardableOrNotPresent) { 248 std::unique_ptr<ScalableVideoController> svc_controller = 249 CreateScalabilityStructure(GetParam().GetScalabilityMode()); 250 std::vector<GenericFrameInfo> frame_infos = 251 ScalabilityStructureWrapper(*svc_controller) 252 .GenerateFrames(GetParam().num_temporal_units); 253 int64_t num_frames = frame_infos.size(); 254 FrameDependencyStructure structure = svc_controller->DependencyStructure(); 255 256 for (int dt = 0; dt < structure.num_decode_targets; ++dt) { 257 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) { 258 const auto& frame = frame_infos[frame_id]; 259 if (frame.decode_target_indications[dt] == 260 DecodeTargetIndication::kNotPresent) { 261 continue; 262 } 263 for (int frame_diff : frame.frame_diffs) { 264 int64_t base_frame_id = frame_id - frame_diff; 265 const auto& base_frame = frame_infos[base_frame_id]; 266 EXPECT_NE(base_frame.decode_target_indications[dt], 267 DecodeTargetIndication::kNotPresent) 268 << "Frame " << frame_id << " depends on frame " << base_frame_id 269 << " that is not part of decode target#" << dt; 270 EXPECT_NE(base_frame.decode_target_indications[dt], 271 DecodeTargetIndication::kDiscardable) 272 << "Frame " << frame_id << " depends on frame " << base_frame_id 273 << " that is discardable for decode target#" << dt; 274 } 275 } 276 } 277 } 278 279 TEST_P(ScalabilityStructureTest, NoFrameDependsThroughSwitchIndication) { 280 std::unique_ptr<ScalableVideoController> svc_controller = 281 CreateScalabilityStructure(GetParam().GetScalabilityMode()); 282 FrameDependencyStructure structure = svc_controller->DependencyStructure(); 283 std::vector<GenericFrameInfo> frame_infos = 284 ScalabilityStructureWrapper(*svc_controller) 285 .GenerateFrames(GetParam().num_temporal_units); 286 int64_t num_frames = frame_infos.size(); 287 std::vector<std::set<int64_t>> full_deps(num_frames); 288 289 // For each frame calculate set of all frames it depends on, both directly and 290 // indirectly. 291 for (int64_t frame_id = 0; frame_id < num_frames; ++frame_id) { 292 std::set<int64_t> all_base_frames; 293 for (int frame_diff : frame_infos[frame_id].frame_diffs) { 294 int64_t base_frame_id = frame_id - frame_diff; 295 all_base_frames.insert(base_frame_id); 296 const auto& indirect = full_deps[base_frame_id]; 297 all_base_frames.insert(indirect.begin(), indirect.end()); 298 } 299 full_deps[frame_id] = std::move(all_base_frames); 300 } 301 302 // Now check the switch indication: frames after the switch indication mustn't 303 // depend on any addition frames before the switch indications. 304 for (int dt = 0; dt < structure.num_decode_targets; ++dt) { 305 for (int64_t switch_frame_id = 0; switch_frame_id < num_frames; 306 ++switch_frame_id) { 307 if (frame_infos[switch_frame_id].decode_target_indications[dt] != 308 DecodeTargetIndication::kSwitch) { 309 continue; 310 } 311 for (int64_t later_frame_id = switch_frame_id + 1; 312 later_frame_id < num_frames; ++later_frame_id) { 313 if (frame_infos[later_frame_id].decode_target_indications[dt] == 314 DecodeTargetIndication::kNotPresent) { 315 continue; 316 } 317 for (int frame_diff : frame_infos[later_frame_id].frame_diffs) { 318 int64_t early_frame_id = later_frame_id - frame_diff; 319 if (early_frame_id < switch_frame_id) { 320 EXPECT_THAT(full_deps[switch_frame_id], Contains(early_frame_id)) 321 << "For decode target #" << dt << " frame " << later_frame_id 322 << " depends on the frame " << early_frame_id 323 << " that switch indication frame " << switch_frame_id 324 << " doesn't directly on indirectly depend on."; 325 } 326 } 327 } 328 } 329 } 330 } 331 332 TEST_P(ScalabilityStructureTest, ProduceNoFrameForDisabledLayers) { 333 std::unique_ptr<ScalableVideoController> svc_controller = 334 CreateScalabilityStructure(GetParam().GetScalabilityMode()); 335 ScalableVideoController::StreamLayersConfig structure = 336 svc_controller->StreamConfig(); 337 338 VideoBitrateAllocation all_bitrates; 339 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) { 340 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) { 341 all_bitrates.SetBitrate(sid, tid, 100'000); 342 } 343 } 344 345 svc_controller->OnRatesUpdated(all_bitrates); 346 ScalabilityStructureWrapper wrapper(*svc_controller); 347 std::vector<GenericFrameInfo> frames = 348 wrapper.GenerateFrames(GetParam().num_temporal_units); 349 350 for (int sid = 0; sid < structure.num_spatial_layers; ++sid) { 351 for (int tid = 0; tid < structure.num_temporal_layers; ++tid) { 352 // When all layers were enabled, expect there was a frame for each layer. 353 EXPECT_THAT(frames, 354 Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid), 355 Field(&GenericFrameInfo::temporal_id, tid)))) 356 << "For layer (" << sid << "," << tid << ")"; 357 // Restore bitrates for all layers before disabling single layer. 358 VideoBitrateAllocation bitrates = all_bitrates; 359 bitrates.SetBitrate(sid, tid, 0); 360 svc_controller->OnRatesUpdated(bitrates); 361 // With layer (sid, tid) disabled, expect no frames are produced for it. 362 EXPECT_THAT( 363 wrapper.GenerateFrames(GetParam().num_temporal_units), 364 Not(Contains(AllOf(Field(&GenericFrameInfo::spatial_id, sid), 365 Field(&GenericFrameInfo::temporal_id, tid))))) 366 << "For layer (" << sid << "," << tid << ")"; 367 } 368 } 369 } 370 371 INSTANTIATE_TEST_SUITE_P( 372 Svc, 373 ScalabilityStructureTest, 374 Values(SvcTestParam{"L1T1", /*num_temporal_units=*/3}, 375 SvcTestParam{"L1T2", /*num_temporal_units=*/4}, 376 SvcTestParam{"L1T3", /*num_temporal_units=*/8}, 377 SvcTestParam{"L2T1", /*num_temporal_units=*/3}, 378 SvcTestParam{"L2T1_KEY", /*num_temporal_units=*/3}, 379 SvcTestParam{"L3T1", /*num_temporal_units=*/3}, 380 SvcTestParam{"L3T1_KEY", /*num_temporal_units=*/3}, 381 SvcTestParam{"L3T3", /*num_temporal_units=*/8}, 382 SvcTestParam{"S2T1", /*num_temporal_units=*/3}, 383 SvcTestParam{"S2T2", /*num_temporal_units=*/4}, 384 SvcTestParam{"S2T3", /*num_temporal_units=*/8}, 385 SvcTestParam{"S3T1", /*num_temporal_units=*/3}, 386 SvcTestParam{"S3T2", /*num_temporal_units=*/4}, 387 SvcTestParam{"S3T3", /*num_temporal_units=*/8}, 388 SvcTestParam{"L2T2", /*num_temporal_units=*/4}, 389 SvcTestParam{"L2T2_KEY", /*num_temporal_units=*/4}, 390 SvcTestParam{"L2T2_KEY_SHIFT", /*num_temporal_units=*/4}, 391 SvcTestParam{"L2T3", /*num_temporal_units=*/8}, 392 SvcTestParam{"L2T3_KEY", /*num_temporal_units=*/8}, 393 SvcTestParam{"L3T2", /*num_temporal_units=*/4}, 394 SvcTestParam{"L3T2_KEY", /*num_temporal_units=*/4}, 395 SvcTestParam{"L3T3_KEY", /*num_temporal_units=*/8}), 396 [](const testing::TestParamInfo<SvcTestParam>& info) { 397 return info.param.name; 398 }); 399 400 } // namespace 401 } // namespace webrtc