1 /*
2 * Copyright (c) 2025, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 3-Clause Clear
5 * License and the Alliance for Open Media Patent License 1.0. If the BSD
6 * 3-Clause Clear License was not distributed with this source code in the
7 * LICENSE file, you can obtain it at
8 * www.aomedia.org/license/software-license/bsd-3-c-c. If the Alliance for
9 * Open Media Patent License 1.0 was not distributed with this source code
10 * in the PATENTS file, you can obtain it at www.aomedia.org/license/patent.
11 */
12
13 #include "iamf/cli/temporal_unit_view.h"
14
15 #include <array>
16 #include <cstdint>
17 #include <list>
18 #include <memory>
19 #include <optional>
20 #include <utility>
21 #include <vector>
22
23 #include "absl/container/flat_hash_map.h"
24 #include "absl/status/status_matchers.h"
25 #include "absl/types/span.h"
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28 #include "iamf/cli/audio_element_with_data.h"
29 #include "iamf/cli/audio_frame_with_data.h"
30 #include "iamf/cli/parameter_block_with_data.h"
31 #include "iamf/cli/tests/cli_test_utils.h"
32 #include "iamf/obu/arbitrary_obu.h"
33 #include "iamf/obu/audio_frame.h"
34 #include "iamf/obu/codec_config.h"
35 #include "iamf/obu/mix_gain_parameter_data.h"
36 #include "iamf/obu/obu_header.h"
37 #include "iamf/obu/param_definitions.h"
38 #include "iamf/obu/parameter_block.h"
39 #include "iamf/obu/types.h"
40
41 namespace iamf_tools {
42 namespace {
43
44 using ::absl_testing::IsOk;
45 using ::testing::Not;
46
47 constexpr DecodedUleb128 kCodecConfigId = 1;
48 constexpr uint32_t kNumSamplesPerFrame = 8;
49 constexpr uint32_t kSampleRate = 48000;
50 constexpr DecodedUleb128 kFirstAudioElementId = 1;
51 constexpr DecodedUleb128 kSecondAudioElementId = 2;
52 constexpr DecodedUleb128 kFirstSubstreamId = 1;
53 constexpr DecodedUleb128 kSecondSubstreamId = 2;
54 constexpr InternalTimestamp kFirstTimestamp = 0;
55 constexpr InternalTimestamp kSecondTimestamp = 8;
56 constexpr InternalTimestamp kFirstAudioFrameStartTimestamp = 0;
57 constexpr InternalTimestamp kFirstAudioFrameEndTimestamp = 8;
58 constexpr DecodedUleb128 kFirstParameterId = 998;
59 constexpr std::nullopt_t kOriginalSamplesAreIrrelevant = std::nullopt;
60
61 constexpr absl::Span<ParameterBlockWithData> kNoParameterBlocks = {};
62 constexpr absl::Span<AudioFrameWithData> kNoAudioFrames = {};
63 constexpr absl::Span<ArbitraryObu> kNoArbitraryObus = {};
64
65 constexpr absl::Span<const ParameterBlockWithData*> kNoParameterBlockPtrs = {};
66 constexpr absl::Span<const ArbitraryObu*> kNoArbitraryObuPtrs = {};
67
InitializePrerequisiteObusForOneSubstream(absl::flat_hash_map<DecodedUleb128,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements)68 void InitializePrerequisiteObusForOneSubstream(
69 absl::flat_hash_map<DecodedUleb128, CodecConfigObu>& codec_config_obus,
70 absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements) {
71 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
72 codec_config_obus);
73 AddAmbisonicsMonoAudioElementWithSubstreamIds(
74 kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
75 codec_config_obus, audio_elements);
76 }
77
AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(uint32_t audio_element_id,uint32_t substream_id,InternalTimestamp start_timestamp,InternalTimestamp end_timestamp,const absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements,std::list<AudioFrameWithData> & audio_frames)78 void AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
79 uint32_t audio_element_id, uint32_t substream_id,
80 InternalTimestamp start_timestamp, InternalTimestamp end_timestamp,
81 const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
82 std::list<AudioFrameWithData>& audio_frames) {
83 ASSERT_TRUE(audio_elements.contains(audio_element_id));
84
85 audio_frames.emplace_back(AudioFrameWithData{
86 .obu = AudioFrameObu(ObuHeader(), substream_id, {}),
87 .start_timestamp = start_timestamp,
88 .end_timestamp = end_timestamp,
89 .pcm_samples = kOriginalSamplesAreIrrelevant,
90 .down_mixing_params = {.in_bitstream = false},
91 .audio_element_with_data = &audio_elements.at(audio_element_id)});
92 }
93
CreateDemixingParamDefinition(const DecodedUleb128 parameter_id)94 MixGainParamDefinition CreateDemixingParamDefinition(
95 const DecodedUleb128 parameter_id) {
96 MixGainParamDefinition mix_gain_param_definition;
97 mix_gain_param_definition.parameter_id_ = parameter_id;
98 mix_gain_param_definition.parameter_rate_ = 48000;
99 mix_gain_param_definition.param_definition_mode_ = 0;
100 mix_gain_param_definition.duration_ = 8;
101 mix_gain_param_definition.constant_subblock_duration_ = 8;
102
103 return mix_gain_param_definition;
104 }
105
AddMixGainParameterBlock(const MixGainParamDefinition & param_definition,InternalTimestamp start_timestamp,InternalTimestamp end_timestamp,std::list<ParameterBlockWithData> & parameter_blocks)106 void AddMixGainParameterBlock(
107 const MixGainParamDefinition& param_definition,
108 InternalTimestamp start_timestamp, InternalTimestamp end_timestamp,
109 std::list<ParameterBlockWithData>& parameter_blocks) {
110 auto data = std::make_unique<MixGainParameterData>();
111 data->animation_type = MixGainParameterData::kAnimateStep;
112 data->param_data = AnimationStepInt16{.start_point_value = 1};
113 auto parameter_block = std::make_unique<ParameterBlockObu>(
114 ObuHeader(), param_definition.parameter_id_, param_definition);
115 ASSERT_THAT(parameter_block->InitializeSubblocks(), IsOk());
116 parameter_block->subblocks_[0].param_data = std::move(data);
117 parameter_blocks.emplace_back(ParameterBlockWithData{
118 .obu = std::move(parameter_block),
119 .start_timestamp = start_timestamp,
120 .end_timestamp = end_timestamp,
121 });
122 }
123
InitializeOneFrameIaSequence(absl::flat_hash_map<uint32_t,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements,std::list<AudioFrameWithData> & audio_frames)124 void InitializeOneFrameIaSequence(
125 absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus,
126 absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
127 std::list<AudioFrameWithData>& audio_frames) {
128 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
129 codec_config_obus);
130 AddAmbisonicsMonoAudioElementWithSubstreamIds(
131 kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
132 codec_config_obus, audio_elements);
133 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
134 kFirstAudioElementId, kFirstSubstreamId, kFirstTimestamp,
135 kSecondTimestamp, audio_elements, audio_frames);
136 }
137
InitializePrerequsiteObusForTwoSubstreams(absl::flat_hash_map<DecodedUleb128,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements)138 void InitializePrerequsiteObusForTwoSubstreams(
139 absl::flat_hash_map<DecodedUleb128, CodecConfigObu>& codec_config_obus,
140 absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements) {
141 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
142 codec_config_obus);
143 AddAmbisonicsMonoAudioElementWithSubstreamIds(
144 kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
145 codec_config_obus, audio_elements);
146 AddAmbisonicsMonoAudioElementWithSubstreamIds(
147 kSecondAudioElementId, kCodecConfigId, {kSecondSubstreamId},
148 codec_config_obus, audio_elements);
149 }
150
TEST(Create,PopulatesMemberVariablesWithOneAudioFrame)151 TEST(Create, PopulatesMemberVariablesWithOneAudioFrame) {
152 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
153 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
154 std::list<AudioFrameWithData> audio_frames;
155 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
156
157 const auto temporal_unit = TemporalUnitView::Create(
158 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
159 ASSERT_THAT(temporal_unit, IsOk());
160
161 EXPECT_EQ(temporal_unit->audio_frames_.size(), 1);
162 EXPECT_TRUE(temporal_unit->parameter_blocks_.empty());
163 EXPECT_TRUE(temporal_unit->arbitrary_obus_.empty());
164 EXPECT_EQ(temporal_unit->num_untrimmed_samples_, kNumSamplesPerFrame);
165 }
166
TEST(Create,PopulatesMemberVariablesWithOneParameterBlock)167 TEST(Create, PopulatesMemberVariablesWithOneParameterBlock) {
168 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
169 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
170 std::list<AudioFrameWithData> audio_frames;
171 std::list<ParameterBlockWithData> parameter_blocks;
172 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
173 const auto mix_gain_param_definition =
174 CreateDemixingParamDefinition(kFirstParameterId);
175 AddMixGainParameterBlock(mix_gain_param_definition, kFirstTimestamp,
176 kSecondTimestamp, parameter_blocks);
177
178 const auto temporal_unit = TemporalUnitView::Create(
179 parameter_blocks, audio_frames, kNoArbitraryObus);
180 ASSERT_THAT(temporal_unit, IsOk());
181
182 EXPECT_EQ(temporal_unit->parameter_blocks_.size(), 1);
183 }
184
TEST(Create,OrderingByAscendingParameterId)185 TEST(Create, OrderingByAscendingParameterId) {
186 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
187 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
188 std::list<AudioFrameWithData> audio_frames;
189 std::list<ParameterBlockWithData> parameter_blocks;
190 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
191 constexpr DecodedUleb128 kHighParameterId = 999;
192 constexpr DecodedUleb128 kLowParameterId = 998;
193 const auto high_id_param_definition =
194 CreateDemixingParamDefinition(kHighParameterId);
195 AddMixGainParameterBlock(high_id_param_definition, kFirstTimestamp,
196 kSecondTimestamp, parameter_blocks);
197 const ParameterBlockWithData* high_id_parameter_block =
198 ¶meter_blocks.back();
199 const auto low_id_param_definition =
200 CreateDemixingParamDefinition(kLowParameterId);
201 AddMixGainParameterBlock(low_id_param_definition, kFirstTimestamp,
202 kSecondTimestamp, parameter_blocks);
203 const ParameterBlockWithData* low_id_parameter_block =
204 ¶meter_blocks.back();
205 const std::vector<const ParameterBlockWithData*> kExpectedOrder = {
206 low_id_parameter_block, high_id_parameter_block};
207
208 const auto temporal_unit = TemporalUnitView::Create(
209 parameter_blocks, audio_frames, kNoArbitraryObus);
210 ASSERT_THAT(temporal_unit, IsOk());
211
212 EXPECT_EQ(temporal_unit->parameter_blocks_, kExpectedOrder);
213 }
214
TEST(CompareAudioElementIdAudioSubstreamId,OrdersByAudioElementIdThenSubstreamId)215 TEST(CompareAudioElementIdAudioSubstreamId,
216 OrdersByAudioElementIdThenSubstreamId) {
217 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
218 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
219 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
220 codec_config_obus);
221 constexpr uint32_t kFirstAudioElementId = 1;
222 constexpr uint32_t kSecondAudioElementId = 10;
223 constexpr uint32_t kFirstSubstreamId = 500;
224 constexpr uint32_t kSecondSubstreamId = 250;
225 constexpr uint32_t kThirdSubstreamId = 750;
226 constexpr uint32_t kFourthSubstreamId = 999;
227 AddAmbisonicsMonoAudioElementWithSubstreamIds(
228 kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
229 codec_config_obus, audio_elements);
230 AddAmbisonicsMonoAudioElementWithSubstreamIds(
231 kSecondAudioElementId, kCodecConfigId,
232 {kSecondSubstreamId, kThirdSubstreamId, kFourthSubstreamId},
233 codec_config_obus, audio_elements);
234
235 // Add the audio frames in a non-canonical order.
236 std::list<AudioFrameWithData> audio_frames;
237 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
238 kSecondAudioElementId, kThirdSubstreamId, kFirstAudioFrameStartTimestamp,
239 kFirstAudioFrameEndTimestamp, audio_elements, audio_frames);
240 const AudioFrameWithData* third_audio_frame_after_sort = &audio_frames.back();
241 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
242 kSecondAudioElementId, kFourthSubstreamId, kFirstAudioFrameStartTimestamp,
243 kFirstAudioFrameEndTimestamp, audio_elements, audio_frames);
244 const AudioFrameWithData* fourth_audio_frame_after_sort =
245 &audio_frames.back();
246 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
247 kFirstAudioElementId, kFirstSubstreamId, kFirstAudioFrameStartTimestamp,
248 kFirstAudioFrameEndTimestamp, audio_elements, audio_frames);
249 const AudioFrameWithData* first_audio_frame_after_sort = &audio_frames.back();
250 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
251 kSecondAudioElementId, kSecondSubstreamId, kFirstAudioFrameStartTimestamp,
252 kFirstAudioFrameEndTimestamp, audio_elements, audio_frames);
253 const AudioFrameWithData* second_audio_frame_after_sort =
254 &audio_frames.back();
255
256 // The view will be based a "canonical" (but not necessarily IAMF-required)
257 // order.
258 const std::vector<const AudioFrameWithData*> kExpectedOrder = {
259 first_audio_frame_after_sort, second_audio_frame_after_sort,
260 third_audio_frame_after_sort, fourth_audio_frame_after_sort};
261
262 const auto temporal_unit = TemporalUnitView::Create(
263 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
264 ASSERT_THAT(temporal_unit, IsOk());
265
266 EXPECT_EQ(temporal_unit->audio_frames_, kExpectedOrder);
267 }
268
TEST(Create,MaintainsArbitraryObusInInputOrder)269 TEST(Create, MaintainsArbitraryObusInInputOrder) {
270 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
271 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
272 std::list<AudioFrameWithData> audio_frames;
273 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
274 std::list<ArbitraryObu> arbitrary_obus;
275 const auto& first_abitrary_obu = arbitrary_obus.emplace_back(ArbitraryObu(
276 kObuIaReserved25, ObuHeader(), {},
277 ArbitraryObu::kInsertionHookAfterParameterBlocksAtTick, kFirstTimestamp));
278 const auto& second_abitrary_obu = arbitrary_obus.emplace_back(ArbitraryObu(
279 kObuIaReserved25, ObuHeader(), {},
280 ArbitraryObu::kInsertionHookAfterParameterBlocksAtTick, kFirstTimestamp));
281 const std::vector<const ArbitraryObu*> arbitrary_obus_ptrs = {
282 &first_abitrary_obu, &second_abitrary_obu};
283
284 const auto temporal_unit = TemporalUnitView::Create(
285 kNoParameterBlocks, audio_frames, arbitrary_obus);
286 ASSERT_THAT(temporal_unit, IsOk());
287
288 EXPECT_EQ(temporal_unit->arbitrary_obus_, arbitrary_obus_ptrs);
289 }
290
TEST(Create,SetsStartTimestamp)291 TEST(Create, SetsStartTimestamp) {
292 constexpr InternalTimestamp kExpectedStartTimestamp = 123456789;
293 constexpr InternalTimestamp kEndTimestamp = kExpectedStartTimestamp + 8;
294 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
295 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
296 std::list<AudioFrameWithData> audio_frames;
297 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
298 audio_frames.front().start_timestamp = kExpectedStartTimestamp;
299 audio_frames.front().end_timestamp = kEndTimestamp;
300
301 const auto temporal_unit = TemporalUnitView::Create(
302 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
303 ASSERT_THAT(temporal_unit, IsOk());
304
305 EXPECT_EQ(temporal_unit->start_timestamp_, kExpectedStartTimestamp);
306 }
307
TEST(Create,SetsEndTimestamp)308 TEST(Create, SetsEndTimestamp) {
309 constexpr InternalTimestamp kStartTimestamp = 123456789;
310 constexpr InternalTimestamp kExpectedEndTimestamp = kStartTimestamp + 8;
311 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
312 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
313 std::list<AudioFrameWithData> audio_frames;
314 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
315 audio_frames.front().start_timestamp = kStartTimestamp;
316 audio_frames.front().end_timestamp = kExpectedEndTimestamp;
317
318 const auto temporal_unit = TemporalUnitView::Create(
319 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
320 ASSERT_THAT(temporal_unit, IsOk());
321
322 EXPECT_EQ(temporal_unit->end_timestamp_, kExpectedEndTimestamp);
323 }
324
TEST(Create,SetsNumSamplesToTrimAtStart)325 TEST(Create, SetsNumSamplesToTrimAtStart) {
326 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
327 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
328 std::list<AudioFrameWithData> audio_frames;
329 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
330 const uint32_t kExpectedNumSamplesToTrimAtStart = 4;
331 audio_frames.front().obu.header_ = ObuHeader{
332 .num_samples_to_trim_at_start = kExpectedNumSamplesToTrimAtStart};
333
334 const auto temporal_unit = TemporalUnitView::Create(
335 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
336 ASSERT_THAT(temporal_unit, IsOk());
337
338 EXPECT_EQ(temporal_unit->num_samples_to_trim_at_start_,
339 kExpectedNumSamplesToTrimAtStart);
340 }
341
TEST(Create,SetsNumUntrimmedSamplesToZeroForFullyTrimmedAudioFrame)342 TEST(Create, SetsNumUntrimmedSamplesToZeroForFullyTrimmedAudioFrame) {
343 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
344 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
345 std::list<AudioFrameWithData> audio_frames;
346 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
347 // Ok. Fully trimmed frames are allowed. They are common in codecs like
348 // AAC-LC.
349 audio_frames.front().obu.header_ =
350 ObuHeader{.num_samples_to_trim_at_end = kNumSamplesPerFrame,
351 .num_samples_to_trim_at_start = 0};
352
353 const auto temporal_unit = TemporalUnitView::Create(
354 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
355 ASSERT_THAT(temporal_unit, IsOk());
356
357 EXPECT_EQ(temporal_unit->num_untrimmed_samples_, 0);
358 }
359
TEST(Create,SetsNumUntrimmedSamples)360 TEST(Create, SetsNumUntrimmedSamples) {
361 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
362 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
363 std::list<AudioFrameWithData> audio_frames;
364 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
365 audio_frames.front().obu.header_ = ObuHeader{
366 .num_samples_to_trim_at_end = 2, .num_samples_to_trim_at_start = 4};
367 // There are 8 samples in the frame, but a total of 5 (2+4) are trimmed. We
368 // expect the number of untrimmed samples to be 2.
369 const uint32_t kExpectedNumUntrimmedSamples = 2;
370
371 const auto temporal_unit = TemporalUnitView::Create(
372 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
373 ASSERT_THAT(temporal_unit, IsOk());
374
375 EXPECT_EQ(temporal_unit->num_untrimmed_samples_,
376 kExpectedNumUntrimmedSamples);
377 }
378
TEST(Create,FailsWithNoAudioFrames)379 TEST(Create, FailsWithNoAudioFrames) {
380 EXPECT_THAT(TemporalUnitView::Create(kNoParameterBlocks, kNoAudioFrames,
381 kNoArbitraryObus),
382 Not(IsOk()));
383 }
384
TEST(CreateFromPointers,FailsIfAudioFramesContainNullPtrs)385 TEST(CreateFromPointers, FailsIfAudioFramesContainNullPtrs) {
386 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
387 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
388 InitializePrerequisiteObusForOneSubstream(codec_config_obus, audio_elements);
389 constexpr std::array<const AudioFrameWithData*, 1> kNullAudioFramePtr = {
390 nullptr};
391
392 EXPECT_THAT(TemporalUnitView::CreateFromPointers(
393 kNoParameterBlockPtrs,
394 absl::MakeConstSpan(kNullAudioFramePtr), kNoArbitraryObuPtrs),
395 Not(IsOk()));
396 }
397
TEST(CreateFromPointers,FailsIfParameterBlocksContainNullPtrs)398 TEST(CreateFromPointers, FailsIfParameterBlocksContainNullPtrs) {
399 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
400 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
401 std::list<AudioFrameWithData> audio_frames;
402 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
403 const std::vector<const AudioFrameWithData*> audio_frames_ptrs = {
404 &audio_frames.back()};
405 const std::array<const ParameterBlockWithData*, 1> kNullParameterBlockPtr = {
406 nullptr};
407
408 EXPECT_THAT(
409 TemporalUnitView::CreateFromPointers(
410 kNullParameterBlockPtr, audio_frames_ptrs, kNoArbitraryObuPtrs),
411 Not(IsOk()));
412 }
413
TEST(CreateFromPointers,FailsIfArbitraryObusContainNullPtrs)414 TEST(CreateFromPointers, FailsIfArbitraryObusContainNullPtrs) {
415 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
416 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
417 std::list<AudioFrameWithData> audio_frames;
418 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
419 const std::vector<const AudioFrameWithData*> audio_frames_ptrs = {
420 &audio_frames.back()};
421 const std::array<const ArbitraryObu*, 1> kNullArbitraryObuPtr = {nullptr};
422
423 EXPECT_THAT(
424 TemporalUnitView::CreateFromPointers(
425 kNoParameterBlockPtrs, audio_frames_ptrs, kNullArbitraryObuPtr),
426 Not(IsOk()));
427 }
428
TEST(Create,ReturnsErrorIfAudioElementWithDataIsNullptr)429 TEST(Create, ReturnsErrorIfAudioElementWithDataIsNullptr) {
430 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
431 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
432 std::list<AudioFrameWithData> audio_frames;
433 InitializePrerequisiteObusForOneSubstream(codec_config_obus, audio_elements);
434 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
435 kFirstAudioElementId, kFirstSubstreamId, kFirstTimestamp,
436 kSecondTimestamp, audio_elements, audio_frames);
437 // Corrupt the audio frame by disassociating the audio element.
438 audio_frames.back().audio_element_with_data = nullptr;
439
440 EXPECT_THAT(TemporalUnitView::Create(kNoParameterBlocks, audio_frames,
441 kNoArbitraryObus),
442 Not(IsOk()));
443 }
444
TEST(Create,ReturnsErrorIfCodecConfigIsNullptr)445 TEST(Create, ReturnsErrorIfCodecConfigIsNullptr) {
446 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
447 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
448 std::list<AudioFrameWithData> audio_frames;
449 InitializePrerequisiteObusForOneSubstream(codec_config_obus, audio_elements);
450 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
451 kFirstAudioElementId, kFirstSubstreamId, kFirstTimestamp,
452 kSecondTimestamp, audio_elements, audio_frames);
453 // Corrupt the audio element by disassociating the codec config.
454 audio_elements.at(kFirstAudioElementId).codec_config = nullptr;
455
456 EXPECT_THAT(TemporalUnitView::Create(kNoParameterBlocks, audio_frames,
457 kNoArbitraryObus),
458 Not(IsOk()));
459 }
460
TEST(Create,ReturnsErrorIfTrimmingIsImplausible)461 TEST(Create, ReturnsErrorIfTrimmingIsImplausible) {
462 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
463 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
464 std::list<AudioFrameWithData> audio_frames;
465 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
466 // Corrupt the audio frame. Trim cannot be greater than the total number of
467 // samples in the frame.
468 audio_frames.front().obu.header_ =
469 ObuHeader{.num_samples_to_trim_at_end = kNumSamplesPerFrame,
470 .num_samples_to_trim_at_start = 1};
471
472 EXPECT_THAT(TemporalUnitView::Create(kNoParameterBlocks, audio_frames,
473 kNoArbitraryObus),
474 Not(IsOk()));
475 }
476
TEST(Create,ReturnsErrorIfSubstreamIdsAreRepeated)477 TEST(Create, ReturnsErrorIfSubstreamIdsAreRepeated) {
478 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
479 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
480 std::list<AudioFrameWithData> audio_frames;
481 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
482 constexpr DecodedUleb128 kRepeatedSubstreamId = kFirstSubstreamId;
483 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
484 kFirstAudioElementId, kRepeatedSubstreamId, kFirstTimestamp,
485 kSecondTimestamp, audio_elements, audio_frames);
486
487 EXPECT_THAT(TemporalUnitView::Create(kNoParameterBlocks, audio_frames,
488 kNoArbitraryObus),
489 Not(IsOk()));
490 }
491
TEST(Create,ReturnsErrorIfTrimmingIsInconsistent)492 TEST(Create, ReturnsErrorIfTrimmingIsInconsistent) {
493 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
494 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
495 std::list<AudioFrameWithData> audio_frames;
496 InitializePrerequsiteObusForTwoSubstreams(codec_config_obus, audio_elements);
497 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
498 kFirstAudioElementId, kFirstSubstreamId, kFirstTimestamp,
499 kSecondTimestamp, audio_elements, audio_frames);
500 audio_frames.back().obu.header_ = ObuHeader{
501 .num_samples_to_trim_at_end = 1, .num_samples_to_trim_at_start = 1};
502 // Add a new frame. It has trimming information inconsistent with the first
503 // frame.
504 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
505 kFirstAudioElementId, kSecondSubstreamId, kFirstTimestamp,
506 kSecondTimestamp, audio_elements, audio_frames);
507 audio_frames.back().obu.header_ = ObuHeader{
508 .num_samples_to_trim_at_end = 2, .num_samples_to_trim_at_start = 1};
509
510 EXPECT_THAT(TemporalUnitView::Create(kNoParameterBlocks, audio_frames,
511 kNoArbitraryObus),
512 Not(IsOk()));
513 }
514
TEST(Create,ReturnsErrorIfAudioFrameTimestampsAreInconsistent)515 TEST(Create, ReturnsErrorIfAudioFrameTimestampsAreInconsistent) {
516 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
517 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
518 std::list<AudioFrameWithData> audio_frames;
519 InitializePrerequsiteObusForTwoSubstreams(codec_config_obus, audio_elements);
520 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
521 kFirstAudioElementId, kFirstSubstreamId, kFirstTimestamp,
522 kSecondTimestamp, audio_elements, audio_frames);
523 constexpr InternalTimestamp kInconsistentTimestamp = kSecondTimestamp + 1;
524 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
525 kFirstAudioElementId, kSecondSubstreamId, kFirstTimestamp,
526 kInconsistentTimestamp, audio_elements, audio_frames);
527
528 EXPECT_THAT(TemporalUnitView::Create(kNoParameterBlocks, audio_frames,
529 kNoArbitraryObus),
530 Not(IsOk()));
531 }
532
TEST(Create,ReturnsErrorIfParameterBlockTimestampsAreInconsistent)533 TEST(Create, ReturnsErrorIfParameterBlockTimestampsAreInconsistent) {
534 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
535 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
536 std::list<AudioFrameWithData> audio_frames;
537 std::list<ParameterBlockWithData> parameter_blocks;
538 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
539 const auto mix_gain_param_definition =
540 CreateDemixingParamDefinition(kFirstParameterId);
541 constexpr InternalTimestamp kInconsistentTimestamp = kSecondTimestamp + 1;
542 AddMixGainParameterBlock(mix_gain_param_definition, kFirstTimestamp,
543 kInconsistentTimestamp, parameter_blocks);
544
545 EXPECT_THAT(TemporalUnitView::Create(parameter_blocks, audio_frames,
546 kNoArbitraryObus),
547 Not(IsOk()));
548 }
549
TEST(Create,ReturnsErrorIfParameterBlockIdsAreRepeated)550 TEST(Create, ReturnsErrorIfParameterBlockIdsAreRepeated) {
551 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
552 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
553 std::list<AudioFrameWithData> audio_frames;
554 std::list<ParameterBlockWithData> parameter_blocks;
555 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
556 const auto mix_gain_param_definition =
557 CreateDemixingParamDefinition(kFirstParameterId);
558 AddMixGainParameterBlock(mix_gain_param_definition, kFirstTimestamp,
559 kSecondTimestamp, parameter_blocks);
560 AddMixGainParameterBlock(mix_gain_param_definition, kFirstTimestamp,
561 kSecondTimestamp, parameter_blocks);
562
563 EXPECT_THAT(TemporalUnitView::Create(parameter_blocks, audio_frames,
564 kNoArbitraryObus),
565 Not(IsOk()));
566 }
567
TEST(Create,ReturnsErrorIfArbitraryObuTimestampsAreInconsistent)568 TEST(Create, ReturnsErrorIfArbitraryObuTimestampsAreInconsistent) {
569 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
570 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
571 std::list<AudioFrameWithData> audio_frames;
572 std::list<ArbitraryObu> arbitrary_obus;
573 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
574 InternalTimestamp kInconsistentTimestamp = kFirstTimestamp + 1;
575 arbitrary_obus.emplace_back(
576 ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
577 ArbitraryObu::kInsertionHookAfterParameterBlocksAtTick,
578 kInconsistentTimestamp));
579
580 EXPECT_THAT(TemporalUnitView::Create(kNoParameterBlocks, audio_frames,
581 arbitrary_obus),
582 Not(IsOk()));
583 }
584
585 } // namespace
586 } // namespace iamf_tools
587