• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       &parameter_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       &parameter_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