• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 3-Clause Clear License
5  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6  * License was not distributed with this source code in the LICENSE file, you
7  * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8  * Alliance for Open Media Patent License 1.0 was not distributed with this
9  * source code in the PATENTS file, you can obtain it at
10  * www.aomedia.org/license/patent.
11  */
12 #include "iamf/cli/parameter_block_partitioner.h"
13 
14 #include <cstddef>
15 #include <cstdint>
16 #include <vector>
17 
18 #include "absl/status/status.h"
19 #include "absl/status/status_matchers.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include "iamf/cli/proto/parameter_block.pb.h"
23 #include "iamf/cli/proto/parameter_data.pb.h"
24 #include "src/google/protobuf/text_format.h"
25 
26 namespace iamf_tools {
27 namespace {
28 
29 using ::absl_testing::IsOk;
30 
31 using iamf_tools_cli_proto::MixGainParameterData;
32 using iamf_tools_cli_proto::ParameterBlockObuMetadata;
33 
CreateStepMixGainParameterData(const int32_t start_point_value)34 MixGainParameterData CreateStepMixGainParameterData(
35     const int32_t start_point_value) {
36   MixGainParameterData mix_gain_parameter_data;
37   mix_gain_parameter_data.set_animation_type(
38       iamf_tools_cli_proto::ANIMATE_STEP);
39   mix_gain_parameter_data.mutable_param_data()
40       ->mutable_step()
41       ->set_start_point_value(start_point_value);
42   return mix_gain_parameter_data;
43 }
44 
CreateLinearMixGainParameterData(const int32_t start_point_value,const int32_t end_point_value)45 MixGainParameterData CreateLinearMixGainParameterData(
46     const int32_t start_point_value, const int32_t end_point_value) {
47   MixGainParameterData mix_gain_parameter_data;
48   mix_gain_parameter_data.set_animation_type(
49       iamf_tools_cli_proto::ANIMATE_LINEAR);
50   auto* linear = mix_gain_parameter_data.mutable_param_data()->mutable_linear();
51   linear->set_start_point_value(start_point_value);
52   linear->set_end_point_value(end_point_value);
53   return mix_gain_parameter_data;
54 }
55 
CreateBezierMixGainParameterData(const int32_t start_point_value,const int32_t end_point_value,const int32_t control_point_value,const uint32_t control_point_relative_time)56 MixGainParameterData CreateBezierMixGainParameterData(
57     const int32_t start_point_value, const int32_t end_point_value,
58     const int32_t control_point_value,
59     const uint32_t control_point_relative_time) {
60   MixGainParameterData mix_gain_parameter_data;
61   mix_gain_parameter_data.set_animation_type(
62       iamf_tools_cli_proto::ANIMATE_BEZIER);
63   auto* bezier = mix_gain_parameter_data.mutable_param_data()->mutable_bezier();
64   bezier->set_start_point_value(start_point_value);
65   bezier->set_end_point_value(end_point_value);
66   bezier->set_control_point_value(control_point_value);
67   bezier->set_control_point_relative_time(control_point_relative_time);
68   return mix_gain_parameter_data;
69 }
70 
71 /*!\brief Creates a minimal parameter block OBU metadata.
72  *
73  * \param subblock_durations Input subblock durations.
74  * \param mix_gain_parameter_data Input mix gain parameter datas or an empty
75  *        vector to assume all gains as step with a value of 0.
76  * \param full_parameter_block Output parameter block OBU metadata.
77  * \return `absl::OkStatus()` on success. A specific status on failure.
78  */
CreateMinimalParameterBlockObuMetadata(const std::vector<uint32_t> & subblock_durations,const std::vector<MixGainParameterData> & mix_gain_parameter_data,ParameterBlockObuMetadata & full_parameter_block)79 absl::Status CreateMinimalParameterBlockObuMetadata(
80     const std::vector<uint32_t>& subblock_durations,
81     const std::vector<MixGainParameterData>& mix_gain_parameter_data,
82     ParameterBlockObuMetadata& full_parameter_block) {
83   if (subblock_durations.empty()) {
84     return absl::InvalidArgumentError("Subblock durations cannot be empty.");
85   }
86   std::vector<MixGainParameterData> mix_gains;
87   if (mix_gain_parameter_data.empty()) {
88     // Fill with steps with a value of 0 if the input argument is not present.
89     mix_gains.resize(subblock_durations.size(),
90                      CreateStepMixGainParameterData(0));
91   } else {
92     mix_gains = mix_gain_parameter_data;
93   }
94 
95   // Calculate the duration from the input subblocks.
96   uint32_t duration = 0;
97   uint32_t constant_subblock_duration =
98       ParameterBlockPartitioner::FindConstantSubblockDuration(
99           subblock_durations);
100 
101   // Add the duration of the remaining blocks.
102   for (auto& subblock_duration : subblock_durations) {
103     duration += subblock_duration;
104   }
105   full_parameter_block.set_duration(duration);
106   full_parameter_block.set_num_subblocks(subblock_durations.size());
107   full_parameter_block.set_constant_subblock_duration(
108       constant_subblock_duration);
109   for (int i = 0; i < subblock_durations.size(); i++) {
110     // Configure the subblocks with the input durations and mix gains.
111     auto* subblock = full_parameter_block.add_subblocks();
112     subblock->set_subblock_duration(subblock_durations[i]);
113     *subblock->mutable_mix_gain_parameter_data() = mix_gains[i];
114   }
115   full_parameter_block.set_start_timestamp(0);
116 
117   return absl::OkStatus();
118 }
119 
120 // TODO(b/277731089): Test `PartitionParameterBlock()` and
121 //                    `PartitionFrameAligned()` more thoroughly.
122 
123 struct PartitionParameterBlocksTestCase {
124   std::vector<uint32_t> input_subblock_durations;
125   std::vector<MixGainParameterData> input_mix_gains;
126   int32_t partition_start;
127   int32_t partition_end;
128   std::vector<uint32_t> expected_partition_durations;
129   std::vector<MixGainParameterData> expected_output_mix_gains;
130   uint32_t constant_subblock_duration;
131   bool status_ok;
132 };
133 
134 using PartitionParameterBlocks =
135     ::testing::TestWithParam<PartitionParameterBlocksTestCase>;
136 
TEST_P(PartitionParameterBlocks,PartitionParameterBlock)137 TEST_P(PartitionParameterBlocks, PartitionParameterBlock) {
138   const PartitionParameterBlocksTestCase& test_case = GetParam();
139 
140   // Create the parameter block to partition.
141   ParameterBlockObuMetadata full_parameter_block;
142   EXPECT_THAT(CreateMinimalParameterBlockObuMetadata(
143                   test_case.input_subblock_durations, test_case.input_mix_gains,
144                   full_parameter_block),
145               IsOk());
146 
147   // Partition the parameter block.
148   ParameterBlockObuMetadata partitioned_parameter_block;
149 
150   EXPECT_EQ(ParameterBlockPartitioner::PartitionParameterBlock(
151                 full_parameter_block, test_case.partition_start,
152                 test_case.partition_end, partitioned_parameter_block)
153                 .ok(),
154             test_case.status_ok);
155 
156   if (test_case.status_ok) {
157     // Validate the parameter block has as many subblocks in the partition as
158     // expected.
159     EXPECT_EQ(partitioned_parameter_block.num_subblocks(),
160               test_case.expected_partition_durations.size());
161 
162     EXPECT_EQ(partitioned_parameter_block.constant_subblock_duration(),
163               test_case.constant_subblock_duration);
164     if (test_case.constant_subblock_duration == 0) {
165       // If the subblocks are included validate the all match the expected
166       // subblock.
167       for (int i = 0; i < test_case.expected_partition_durations.size(); ++i) {
168         EXPECT_EQ(partitioned_parameter_block.subblocks(i).subblock_duration(),
169                   test_case.expected_partition_durations[i]);
170       }
171     }
172 
173     // Compare the expected mix gains if present.
174     for (int i = 0; i < test_case.expected_output_mix_gains.size(); ++i) {
175       const auto& actual_mix_gain =
176           partitioned_parameter_block.subblocks(i).mix_gain_parameter_data();
177       const auto& expected_mix_gain = test_case.expected_output_mix_gains[i];
178       const auto& actual_param_data = actual_mix_gain.param_data();
179       const auto& expected_param_data = expected_mix_gain.param_data();
180       EXPECT_EQ(actual_mix_gain.animation_type(),
181                 expected_mix_gain.animation_type());
182       switch (actual_mix_gain.animation_type()) {
183         using enum iamf_tools_cli_proto::AnimationType;
184         case ANIMATE_STEP:
185           EXPECT_EQ(actual_param_data.step().start_point_value(),
186                     expected_param_data.step().start_point_value());
187           break;
188         case ANIMATE_LINEAR:
189           EXPECT_EQ(actual_param_data.linear().start_point_value(),
190                     expected_param_data.linear().start_point_value());
191           EXPECT_EQ(actual_param_data.linear().end_point_value(),
192                     expected_param_data.linear().end_point_value());
193           break;
194         case ANIMATE_BEZIER:
195           EXPECT_EQ(actual_param_data.bezier().start_point_value(),
196                     expected_param_data.bezier().start_point_value());
197           EXPECT_EQ(actual_param_data.bezier().end_point_value(),
198                     expected_param_data.bezier().end_point_value());
199           EXPECT_EQ(actual_param_data.bezier().control_point_value(),
200                     expected_param_data.bezier().control_point_value());
201           EXPECT_EQ(actual_param_data.bezier().control_point_relative_time(),
202                     expected_param_data.bezier().control_point_relative_time());
203           break;
204         default:
205           FAIL() << "Invalid animation type";
206       }
207     }
208   }
209 }
210 
211 INSTANTIATE_TEST_SUITE_P(OneSubblock, PartitionParameterBlocks,
212                          testing::ValuesIn<PartitionParameterBlocksTestCase>({
213                              {{8000}, {}, 0, 1, {1}, {}, 1, true},
214                              {{8000}, {}, 0, 128, {128}, {}, 128, true},
215                              {{8000}, {}, 0, 8000, {8000}, {}, 8000, true},
216                          }));
217 
218 INSTANTIATE_TEST_SUITE_P(
219     TwoSubblocksConstantSubblockDurationNonzero, PartitionParameterBlocks,
220     testing::ValuesIn<PartitionParameterBlocksTestCase>({
221         {{4000, 4000}, {}, 0, 3999, {3999}, {}, 3999, true},
222         {{4000, 4000}, {}, 3950, 4050, {50, 50}, {}, 50, true},
223         {{4000, 4000}, {}, 3950, 4025, {50, 25}, {}, 50, true},
224     }));
225 
226 INSTANTIATE_TEST_SUITE_P(
227     TwoSubblocksConstantSubblockDuration0, PartitionParameterBlocks,
228     testing::ValuesIn<PartitionParameterBlocksTestCase>({
229         {{4000, 4000}, {}, 3975, 4050, {25, 50}, {}, 0, true},
230     }));
231 
232 INSTANTIATE_TEST_SUITE_P(
233     ManySubblocks, PartitionParameterBlocks,
234     testing::ValuesIn<PartitionParameterBlocksTestCase>({
235         {{1, 2, 3, 10, 10, 10}, {}, 0, 35, {1, 2, 3, 10, 10, 9}, {}, 0, true},
236         {{1, 2, 3, 10, 10, 10}, {}, 2, 35, {1, 3, 10, 10, 9}, {}, 0, true},
237     }));
238 
239 INSTANTIATE_TEST_SUITE_P(ErrorZeroDuration, PartitionParameterBlocks,
240                          testing::ValuesIn<PartitionParameterBlocksTestCase>({
241                              {{4000, 4000}, {}, 0, 0, {}, {}, 0, false},
242                          }));
243 
244 INSTANTIATE_TEST_SUITE_P(ErrorNegativeDuration, PartitionParameterBlocks,
245                          testing::ValuesIn<PartitionParameterBlocksTestCase>({
246                              {{4000, 4000}, {}, 10000, 0, {}, {}, 0, false},
247                          }));
248 
249 INSTANTIATE_TEST_SUITE_P(ErrorNotFullyCovered, PartitionParameterBlocks,
250                          testing::ValuesIn<PartitionParameterBlocksTestCase>({
251                              {{4000, 4000}, {}, 4000, 8001, {}, {}, 0, false},
252                          }));
253 
254 INSTANTIATE_TEST_SUITE_P(Step, PartitionParameterBlocks,
255                          testing::ValuesIn<PartitionParameterBlocksTestCase>({
256                              {{4000, 4000},
257                               {CreateStepMixGainParameterData(10),
258                                CreateStepMixGainParameterData(20)},
259                               0,
260                               3999,
261                               {3999},
262                               {CreateStepMixGainParameterData(10)},
263                               3999,
264                               true},
265                              {{4000, 4000},
266                               {CreateStepMixGainParameterData(10),
267                                CreateStepMixGainParameterData(20)},
268                               2000,
269                               6000,
270                               {2000, 2000},
271                               {CreateStepMixGainParameterData(10),
272                                CreateStepMixGainParameterData(20)},
273                               2000,
274                               true},
275                          }));
276 
277 INSTANTIATE_TEST_SUITE_P(Linear, PartitionParameterBlocks,
278                          testing::ValuesIn<PartitionParameterBlocksTestCase>({
279                              {{4000, 4000},
280                               {CreateLinearMixGainParameterData(0, 100),
281                                CreateLinearMixGainParameterData(100, 1000)},
282                               1000,
283                               3000,
284                               {2000},
285                               {CreateLinearMixGainParameterData(25, 75)},
286                               2000,
287                               true},
288                          }));
289 
290 INSTANTIATE_TEST_SUITE_P(LinearTwoSubblocks, PartitionParameterBlocks,
291                          testing::ValuesIn<PartitionParameterBlocksTestCase>({
292                              {{4000, 4000},
293                               {CreateLinearMixGainParameterData(0, 100),
294                                CreateLinearMixGainParameterData(100, 1000)},
295                               1000,
296                               6000,
297                               {3000, 2000},
298                               {CreateLinearMixGainParameterData(25, 100),
299                                CreateLinearMixGainParameterData(100, 550)},
300                               3000,
301                               true},
302                          }));
303 
304 INSTANTIATE_TEST_SUITE_P(
305     BezierAligned, PartitionParameterBlocks,
306     testing::ValuesIn<PartitionParameterBlocksTestCase>({
307         {{4000},
308          {CreateBezierMixGainParameterData(0, 100, 64, 100)},
309          0,
310          4000,
311          {4000},
312          {CreateBezierMixGainParameterData(0, 100, 64, 100)},
313          4000,
314          true},
315     }));
316 
TEST(PartitionParameterBlock,InvalidForUnknownOrMissingParameterData)317 TEST(PartitionParameterBlock, InvalidForUnknownOrMissingParameterData) {
318   ParameterBlockObuMetadata full_parameter_block;
319   google::protobuf::TextFormat::ParseFromString(
320       R"pb(
321         parameter_id: 100
322         start_timestamp: 0
323         duration: 4000
324         num_subblocks: 1
325         constant_subblock_duration: 4000
326         subblocks {
327           # Parameter data is missing.
328         }
329       )pb",
330       &full_parameter_block);
331 
332   ParameterBlockObuMetadata unused_parameter_block;
333   EXPECT_FALSE(ParameterBlockPartitioner::PartitionParameterBlock(
334                    full_parameter_block, /*partitioned_start_time=*/0,
335                    /*partitioned_end_time=*/4000, unused_parameter_block)
336                    .ok());
337 }
338 
ExpectHasOneSubblockWithDMixPMode(const ParameterBlockObuMetadata & parameter_block_metadata,const iamf_tools_cli_proto::DMixPMode & expected_dmixp_mode)339 void ExpectHasOneSubblockWithDMixPMode(
340     const ParameterBlockObuMetadata& parameter_block_metadata,
341     const iamf_tools_cli_proto::DMixPMode& expected_dmixp_mode) {
342   EXPECT_EQ(parameter_block_metadata.subblocks().size(), 1);
343   ASSERT_TRUE(
344       parameter_block_metadata.subblocks(0).has_demixing_info_parameter_data());
345   EXPECT_EQ(parameter_block_metadata.subblocks(0)
346                 .demixing_info_parameter_data()
347                 .dmixp_mode(),
348             expected_dmixp_mode);
349 }
350 
TEST(PartitionParameterBlock,IsEquivalentWhenSubblockBoundaryIsNotCrossedForDemixing)351 TEST(PartitionParameterBlock,
352      IsEquivalentWhenSubblockBoundaryIsNotCrossedForDemixing) {
353   ParameterBlockObuMetadata full_parameter_block;
354   google::protobuf::TextFormat::ParseFromString(
355       R"pb(
356         parameter_id: 100
357         start_timestamp: 0
358         duration: 12000
359         num_subblocks: 3
360         constant_subblock_duration: 4000
361         # t = [0, 4000).
362         subblocks { demixing_info_parameter_data { dmixp_mode: DMIXP_MODE_1 } }
363         # t = [4000, 8000).
364         subblocks { demixing_info_parameter_data { dmixp_mode: DMIXP_MODE_3 } }
365         # t = [8000, 12000).
366         subblocks { demixing_info_parameter_data { dmixp_mode: DMIXP_MODE_2 } }
367       )pb",
368       &full_parameter_block);
369 
370   // OK if it spans the whole (semi-open) range.
371   ParameterBlockObuMetadata partition_from_first_subblock;
372   EXPECT_THAT(ParameterBlockPartitioner::PartitionParameterBlock(
373                   full_parameter_block, /*partitioned_start_time=*/0,
374                   /*partitioned_end_time=*/4000, partition_from_first_subblock),
375               IsOk());
376   ExpectHasOneSubblockWithDMixPMode(partition_from_first_subblock,
377                                     iamf_tools_cli_proto::DMIXP_MODE_1);
378   // OK if the new duration is shorter than the original subblock duration.
379   ParameterBlockObuMetadata partition_from_third_subblock;
380   EXPECT_THAT(ParameterBlockPartitioner::PartitionParameterBlock(
381                   full_parameter_block, /*partitioned_start_time=*/9000,
382                   /*partitioned_end_time=*/9001, partition_from_third_subblock),
383               IsOk());
384   ExpectHasOneSubblockWithDMixPMode(partition_from_third_subblock,
385                                     iamf_tools_cli_proto::DMIXP_MODE_2);
386 }
387 
TEST(PartitionParameterBlock,InvalidWhenSubblockBoundaryIsCrossedForDemixing)388 TEST(PartitionParameterBlock, InvalidWhenSubblockBoundaryIsCrossedForDemixing) {
389   ParameterBlockObuMetadata full_parameter_block;
390   google::protobuf::TextFormat::ParseFromString(
391       R"pb(
392         parameter_id: 100
393         start_timestamp: 0
394         duration: 12000
395         num_subblocks: 3
396         constant_subblock_duration: 4000
397         # t = [0, 4000).
398         subblocks { demixing_info_parameter_data { dmixp_mode: DMIXP_MODE_1 } }
399         # t = [4000, 8000).
400         subblocks { demixing_info_parameter_data { dmixp_mode: DMIXP_MODE_3 } }
401         # t = [8000, 12000).
402         subblocks { demixing_info_parameter_data { dmixp_mode: DMIXP_MODE_2 } }
403       )pb",
404       &full_parameter_block);
405 
406   ParameterBlockObuMetadata unused_partitioned_parameter_block;
407   EXPECT_FALSE(ParameterBlockPartitioner::PartitionParameterBlock(
408                    full_parameter_block, /*partitioned_start_time=*/3950,
409                    /*partitioned_end_time=*/4500,
410                    unused_partitioned_parameter_block)
411                    .ok());
412   EXPECT_FALSE(ParameterBlockPartitioner::PartitionParameterBlock(
413                    full_parameter_block, /*partitioned_start_time=*/3999,
414                    /*partitioned_end_time=*/4001,
415                    unused_partitioned_parameter_block)
416                    .ok());
417 }
418 
TEST(PartitionParameterBlock,IsEquivalentWhenSubblockBoundaryIsNotCrossedForReconGain)419 TEST(PartitionParameterBlock,
420      IsEquivalentWhenSubblockBoundaryIsNotCrossedForReconGain) {
421   const int32_t kStartDuration = 0;
422   const int32_t kEndDuration = 4000;
423   const int32_t kExpectedDuration = kEndDuration - kStartDuration;
424   ParameterBlockObuMetadata full_parameter_block;
425   google::protobuf::TextFormat::ParseFromString(
426       R"pb(
427         parameter_id: 100
428         start_timestamp: 0
429         duration: 8000
430         num_subblocks: 1
431         constant_subblock_duration: 8000
432         subblocks {
433           recon_gain_info_parameter_data {
434             recon_gains_for_layer {}
435             recon_gains_for_layer { recon_gain { key: 2 value: 200 } }
436           }
437         }
438       )pb",
439       &full_parameter_block);
440   const size_t kNumLayers = 2;
441   const size_t kNumReconGainsForSecondLayer = 1;
442   const size_t kSecondLayerReconGainValueForKey2 = 200;
443 
444   ParameterBlockObuMetadata partitioned_parameter_block;
445   EXPECT_THAT(ParameterBlockPartitioner::PartitionParameterBlock(
446                   full_parameter_block, kStartDuration, kEndDuration,
447                   partitioned_parameter_block),
448               IsOk());
449 
450   EXPECT_EQ(partitioned_parameter_block.duration(), kExpectedDuration);
451   EXPECT_EQ(partitioned_parameter_block.subblocks().size(), 1);
452   ASSERT_TRUE(partitioned_parameter_block.subblocks(0)
453                   .has_recon_gain_info_parameter_data());
454   const auto& recon_gain_info_parameter_data =
455       partitioned_parameter_block.subblocks(0).recon_gain_info_parameter_data();
456   EXPECT_EQ(recon_gain_info_parameter_data.recon_gains_for_layer().size(),
457             kNumLayers);
458   EXPECT_TRUE(recon_gain_info_parameter_data.recon_gains_for_layer(0)
459                   .recon_gain()
460                   .empty());
461   const auto& second_layer_recon_gains =
462       recon_gain_info_parameter_data.recon_gains_for_layer(1);
463   EXPECT_EQ(second_layer_recon_gains.recon_gain().size(),
464             kNumReconGainsForSecondLayer);
465   EXPECT_EQ(second_layer_recon_gains.recon_gain().at(2),
466             kSecondLayerReconGainValueForKey2);
467 }
468 
TEST(PartitionParameterBlock,InvalidWhenSubblockBoundaryIsCrossedForReconGain)469 TEST(PartitionParameterBlock,
470      InvalidWhenSubblockBoundaryIsCrossedForReconGain) {
471   ParameterBlockObuMetadata full_parameter_block;
472   google::protobuf::TextFormat::ParseFromString(
473       R"pb(
474         parameter_id: 100
475         start_timestamp: 0
476         duration: 8000
477         num_subblocks: 2
478         constant_subblock_duration: 4000
479         # t = [0, 4000).
480         subblocks {
481           recon_gain_info_parameter_data {
482             recon_gains_for_layer {}
483             recon_gains_for_layer { recon_gain { key: 2 value: 200 } }
484           }
485         }
486         # t = [4000, 8000).
487         subblocks {
488           recon_gain_info_parameter_data {
489             recon_gains_for_layer {}
490             recon_gains_for_layer { recon_gain { key: 2 value: 100 } }
491           }
492         }
493       )pb",
494       &full_parameter_block);
495 
496   ParameterBlockObuMetadata partitioned_parameter_block;
497   EXPECT_FALSE(ParameterBlockPartitioner::PartitionParameterBlock(
498                    full_parameter_block, /*partitioned_start_time=*/3999,
499                    /*partitioned_end_time=*/4001, partitioned_parameter_block)
500                    .ok());
501 }
502 
503 struct FindConstantSubblockDurationTestCase {
504   std::vector<uint32_t> input_subblock_durations;
505   uint32_t expected_constant_subblock_duration;
506 };
507 
508 using FindConstantSubblockDurationTest =
509     ::testing::TestWithParam<FindConstantSubblockDurationTestCase>;
510 
TEST_P(FindConstantSubblockDurationTest,PartitionParameterBlock)511 TEST_P(FindConstantSubblockDurationTest, PartitionParameterBlock) {
512   const FindConstantSubblockDurationTestCase& test_case = GetParam();
513 
514   EXPECT_EQ(test_case.expected_constant_subblock_duration,
515             ParameterBlockPartitioner::FindConstantSubblockDuration(
516                 test_case.input_subblock_durations));
517 }
518 
519 INSTANTIATE_TEST_SUITE_P(
520     OneSubblock, FindConstantSubblockDurationTest,
521     testing::ValuesIn<FindConstantSubblockDurationTestCase>({
522         {{1}, 1},
523         {{4000}, 4000},
524         {{UINT32_MAX}, UINT32_MAX},
525     }));
526 
527 INSTANTIATE_TEST_SUITE_P(
528     TwoSubblocksFirstLonger, FindConstantSubblockDurationTest,
529     testing::ValuesIn<FindConstantSubblockDurationTestCase>({
530         {{2, 1}, 2},
531     }));
532 
533 INSTANTIATE_TEST_SUITE_P(
534     TwoSubblocksFirstShorter, FindConstantSubblockDurationTest,
535     testing::ValuesIn<FindConstantSubblockDurationTestCase>({
536         {{1, 2}, 0},
537     }));
538 
539 INSTANTIATE_TEST_SUITE_P(
540     ManySubblocksEqual, FindConstantSubblockDurationTest,
541     testing::ValuesIn<FindConstantSubblockDurationTestCase>({
542         {{99, 99, 99, 99}, 99},
543         {{4, 4, 4, 4}, 4},
544     }));
545 
546 INSTANTIATE_TEST_SUITE_P(
547     ManySubblocksLastShorter, FindConstantSubblockDurationTest,
548     testing::ValuesIn<FindConstantSubblockDurationTestCase>({
549         {{99, 99, 99, 97}, 99},
550         {{4, 4, 4, 3}, 4},
551     }));
552 
553 INSTANTIATE_TEST_SUITE_P(
554     ManySubblocksUnequal, FindConstantSubblockDurationTest,
555     testing::ValuesIn<FindConstantSubblockDurationTestCase>({
556         {{4, 4, 4, 5}, 0},
557         {{99, 100, 101, 102}, 0},
558     }));
559 
560 }  // namespace
561 }  // namespace iamf_tools
562