• 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
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 #include "iamf/cli/obu_sequencer_iamf.h"
13 
14 #include <cstdint>
15 #include <filesystem>
16 #include <list>
17 #include <memory>
18 #include <optional>
19 #include <string>
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/strings/string_view.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/temporal_unit_view.h"
32 #include "iamf/cli/tests/cli_test_utils.h"
33 #include "iamf/common/leb_generator.h"
34 #include "iamf/common/read_bit_buffer.h"
35 #include "iamf/obu/arbitrary_obu.h"
36 #include "iamf/obu/audio_frame.h"
37 #include "iamf/obu/codec_config.h"
38 #include "iamf/obu/demixing_info_parameter_data.h"
39 #include "iamf/obu/demixing_param_definition.h"
40 #include "iamf/obu/ia_sequence_header.h"
41 #include "iamf/obu/mix_presentation.h"
42 #include "iamf/obu/obu_header.h"
43 #include "iamf/obu/parameter_block.h"
44 #include "iamf/obu/types.h"
45 
46 namespace iamf_tools {
47 namespace {
48 
49 using ::absl_testing::IsOk;
50 
51 constexpr DecodedUleb128 kCodecConfigId = 1;
52 constexpr uint32_t kSampleRate = 48000;
53 constexpr DecodedUleb128 kFirstAudioElementId = 1;
54 constexpr DecodedUleb128 kFirstSubstreamId = 1;
55 constexpr DecodedUleb128 kFirstMixPresentationId = 100;
56 constexpr DecodedUleb128 kFirstDemixingParameterId = 998;
57 constexpr DecodedUleb128 kCommonMixGainParameterId = 999;
58 constexpr uint32_t kCommonMixGainParameterRate = kSampleRate;
59 
60 constexpr absl::string_view kOmitOutputIamfFile = "";
61 constexpr bool kIncludeTemporalDelimiters = true;
62 constexpr bool kDoNotIncludeTemporalDelimiters = false;
63 
64 constexpr std::nullopt_t kOriginalSamplesAreIrrelevant = std::nullopt;
65 
66 constexpr int64_t kReadBitBufferCapacity = 1024;
67 
68 // TODO(b/302470464): Add test coverage for `ObuSequencerIamf::PickAndPlace()`
69 //                    configured with minimal and fixed-size leb generators.
70 
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)71 void AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
72     uint32_t audio_element_id, uint32_t substream_id,
73     InternalTimestamp start_timestamp, InternalTimestamp end_timestamp,
74     const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
75     std::list<AudioFrameWithData>& audio_frames) {
76   ASSERT_TRUE(audio_elements.contains(audio_element_id));
77 
78   audio_frames.emplace_back(AudioFrameWithData{
79       .obu = AudioFrameObu(ObuHeader(), substream_id, {}),
80       .start_timestamp = start_timestamp,
81       .end_timestamp = end_timestamp,
82       .pcm_samples = kOriginalSamplesAreIrrelevant,
83       .down_mixing_params = {.in_bitstream = false},
84       .audio_element_with_data = &audio_elements.at(audio_element_id)});
85 }
86 
CreateDemixingParamDefinition(const DecodedUleb128 parameter_id)87 DemixingParamDefinition CreateDemixingParamDefinition(
88     const DecodedUleb128 parameter_id) {
89   DemixingParamDefinition demixing_param_definition;
90   demixing_param_definition.parameter_id_ = parameter_id;
91   demixing_param_definition.parameter_rate_ = 48000;
92   demixing_param_definition.param_definition_mode_ = 0;
93   demixing_param_definition.duration_ = 8;
94   demixing_param_definition.constant_subblock_duration_ = 8;
95   demixing_param_definition.reserved_ = 10;
96 
97   return demixing_param_definition;
98 }
99 
InitializeOneParameterBlockAndOneAudioFrame(DemixingParamDefinition & param_definition,std::list<ParameterBlockWithData> & parameter_blocks,std::list<AudioFrameWithData> & audio_frames,absl::flat_hash_map<uint32_t,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements)100 void InitializeOneParameterBlockAndOneAudioFrame(
101     DemixingParamDefinition& param_definition,
102     std::list<ParameterBlockWithData>& parameter_blocks,
103     std::list<AudioFrameWithData>& audio_frames,
104     absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus,
105     absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements) {
106   constexpr InternalTimestamp kStartTimestamp = 0;
107   constexpr InternalTimestamp kEndTimestamp = 16;
108   AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
109                                         codec_config_obus);
110   AddAmbisonicsMonoAudioElementWithSubstreamIds(
111       kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
112       codec_config_obus, audio_elements);
113   AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
114       kFirstAudioElementId, kFirstSubstreamId, kStartTimestamp, kEndTimestamp,
115       audio_elements, audio_frames);
116   auto data = std::make_unique<DemixingInfoParameterData>();
117   data->dmixp_mode = DemixingInfoParameterData::kDMixPMode1;
118   data->reserved = 0;
119   auto parameter_block = std::make_unique<ParameterBlockObu>(
120       ObuHeader(), param_definition.parameter_id_, param_definition);
121   ASSERT_THAT(parameter_block->InitializeSubblocks(), IsOk());
122   parameter_block->subblocks_[0].param_data = std::move(data);
123   parameter_blocks.emplace_back(ParameterBlockWithData{
124       .obu = std::move(parameter_block),
125       .start_timestamp = 0,
126       .end_timestamp = 16,
127   });
128 }
129 
130 class ObuSequencerIamfTest : public ::testing::Test {
131  public:
InitializeDescriptorObus()132   void InitializeDescriptorObus() {
133     ia_sequence_header_obu_.emplace(ObuHeader(), IASequenceHeaderObu::kIaCode,
134                                     ProfileVersion::kIamfSimpleProfile,
135                                     ProfileVersion::kIamfSimpleProfile);
136     AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
137                                           codec_config_obus_);
138     AddAmbisonicsMonoAudioElementWithSubstreamIds(
139         kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
140         codec_config_obus_, audio_elements_);
141     AddMixPresentationObuWithAudioElementIds(
142         kFirstMixPresentationId, {kFirstAudioElementId},
143         kCommonMixGainParameterId, kCommonMixGainParameterRate,
144         mix_presentation_obus_);
145 
146     ASSERT_TRUE(ia_sequence_header_obu_.has_value());
147     ASSERT_TRUE(codec_config_obus_.contains(kCodecConfigId));
148     ASSERT_TRUE(audio_elements_.contains(kFirstAudioElementId));
149     ASSERT_FALSE(mix_presentation_obus_.empty());
150   }
151 
InitObusForOneFrameIaSequence()152   void InitObusForOneFrameIaSequence() {
153     ia_sequence_header_obu_.emplace(ObuHeader(), IASequenceHeaderObu::kIaCode,
154                                     ProfileVersion::kIamfSimpleProfile,
155                                     ProfileVersion::kIamfSimpleProfile);
156     param_definition_ =
157         CreateDemixingParamDefinition(kFirstDemixingParameterId);
158     InitializeOneParameterBlockAndOneAudioFrame(
159         param_definition_, parameter_blocks_, audio_frames_, codec_config_obus_,
160         audio_elements_);
161     AddMixPresentationObuWithAudioElementIds(
162         kFirstMixPresentationId, {audio_elements_.begin()->first},
163         kCommonMixGainParameterId, kCommonMixGainParameterRate,
164         mix_presentation_obus_);
165   }
166 
167  protected:
168   std::optional<IASequenceHeaderObu> ia_sequence_header_obu_;
169   absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus_;
170   absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements_;
171   std::list<MixPresentationObu> mix_presentation_obus_;
172 
173   DemixingParamDefinition param_definition_;
174   std::list<ParameterBlockWithData> parameter_blocks_;
175   std::list<AudioFrameWithData> audio_frames_;
176 
177   std::list<ArbitraryObu> arbitrary_obus_;
178 };
179 
TEST(ObuSequencerIamf,PickAndPlaceWritesFileWithOnlyIaSequenceHeader)180 TEST(ObuSequencerIamf, PickAndPlaceWritesFileWithOnlyIaSequenceHeader) {
181   const std::string kOutputIamfFilename = GetAndCleanupOutputFileName(".iamf");
182   {
183     const IASequenceHeaderObu ia_sequence_header_obu(
184         ObuHeader(), IASequenceHeaderObu::kIaCode,
185         ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
186     ObuSequencerIamf sequencer(kOutputIamfFilename,
187                                kDoNotIncludeTemporalDelimiters,
188                                *LebGenerator::Create());
189 
190     EXPECT_THAT(sequencer.PickAndPlace(
191                     ia_sequence_header_obu, /*codec_config_obus=*/{},
192                     /*audio_elements=*/{}, /*mix_presentation_obus=*/{},
193                     /*audio_frames=*/{}, /*parameter_blocks=*/{},
194                     /*arbitrary_obus=*/{}),
195                 IsOk());
196 
197     // `ObuSequencerIamf` goes out of scope and closes the file.
198   }
199 
200   EXPECT_TRUE(std::filesystem::exists(kOutputIamfFilename));
201 }
202 
203 struct ProfileVersionsAndEnableTemporalDelimiters {
204   ProfileVersion primary_profile;
205   ProfileVersion additional_profile;
206   bool enable_temporal_delimiters;
207 };
208 
209 using TestProfileVersionAndEnableTemporalDelimiters =
210     ::testing::TestWithParam<ProfileVersionsAndEnableTemporalDelimiters>;
211 
TEST_P(TestProfileVersionAndEnableTemporalDelimiters,PickAndPlace)212 TEST_P(TestProfileVersionAndEnableTemporalDelimiters, PickAndPlace) {
213   const IASequenceHeaderObu ia_sequence_header_obu(
214       ObuHeader(), IASequenceHeaderObu::kIaCode, GetParam().primary_profile,
215       GetParam().additional_profile);
216   ObuSequencerIamf sequencer(std::string(kOmitOutputIamfFile),
217                              GetParam().enable_temporal_delimiters,
218                              *LebGenerator::Create());
219 
220   EXPECT_THAT(sequencer.PickAndPlace(
221                   ia_sequence_header_obu, /*codec_config_obus=*/{},
222                   /*audio_elements=*/{}, /*mix_presentation_obus=*/{},
223                   /*audio_frames=*/{}, /*parameter_blocks=*/{},
224                   /*arbitrary_obus=*/{}),
225               IsOk());
226 }
227 
228 INSTANTIATE_TEST_SUITE_P(
229     SimpleProfileWithTemporalDelimiters,
230     TestProfileVersionAndEnableTemporalDelimiters,
231     testing::Values<ProfileVersionsAndEnableTemporalDelimiters>(
232         {ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfSimpleProfile,
233          kIncludeTemporalDelimiters}));
234 
235 INSTANTIATE_TEST_SUITE_P(
236     SimpleProfileWithoutTemporalDelimiters,
237     TestProfileVersionAndEnableTemporalDelimiters,
238     testing::Values<ProfileVersionsAndEnableTemporalDelimiters>(
239         {ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfSimpleProfile,
240          kDoNotIncludeTemporalDelimiters}));
241 
242 INSTANTIATE_TEST_SUITE_P(
243     BaseProfileWithoutTemporalDelimiters,
244     TestProfileVersionAndEnableTemporalDelimiters,
245     testing::Values<ProfileVersionsAndEnableTemporalDelimiters>(
246         {ProfileVersion::kIamfBaseProfile, ProfileVersion::kIamfBaseProfile,
247          kDoNotIncludeTemporalDelimiters}));
248 
249 INSTANTIATE_TEST_SUITE_P(
250     BaseEnhancedProfileWithoutTemporalDelimiters,
251     TestProfileVersionAndEnableTemporalDelimiters,
252     testing::Values<ProfileVersionsAndEnableTemporalDelimiters>(
253         {ProfileVersion::kIamfBaseEnhancedProfile,
254          ProfileVersion::kIamfBaseEnhancedProfile,
255          kDoNotIncludeTemporalDelimiters}));
256 
TEST(ObuSequencerIamf,PickAndPlaceSucceedsWithEmptyOutputFile)257 TEST(ObuSequencerIamf, PickAndPlaceSucceedsWithEmptyOutputFile) {
258   const IASequenceHeaderObu ia_sequence_header_obu(
259       ObuHeader(), IASequenceHeaderObu::kIaCode,
260       ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
261 
262   ObuSequencerIamf sequencer(std::string(kOmitOutputIamfFile),
263                              kDoNotIncludeTemporalDelimiters,
264                              *LebGenerator::Create());
265 
266   EXPECT_THAT(sequencer.PickAndPlace(
267                   ia_sequence_header_obu, /*codec_config_obus=*/{},
268                   /*audio_elements=*/{}, /*mix_presentation_obus=*/{},
269                   /*audio_frames=*/{}, /*parameter_blocks=*/{},
270                   /*arbitrary_obus=*/{}),
271               IsOk());
272 }
273 
TEST_F(ObuSequencerIamfTest,PickAndPlaceCreatesFileWithOneFrameIaSequence)274 TEST_F(ObuSequencerIamfTest, PickAndPlaceCreatesFileWithOneFrameIaSequence) {
275   const std::string kOutputIamfFilename = GetAndCleanupOutputFileName(".iamf");
276   InitObusForOneFrameIaSequence();
277   ObuSequencerIamf sequencer(kOutputIamfFilename,
278                              kDoNotIncludeTemporalDelimiters,
279                              *LebGenerator::Create());
280 
281   ASSERT_THAT(
282       sequencer.PickAndPlace(*ia_sequence_header_obu_, codec_config_obus_,
283                              audio_elements_, mix_presentation_obus_,
284                              audio_frames_, parameter_blocks_, arbitrary_obus_),
285       IsOk());
286 
287   EXPECT_TRUE(std::filesystem::exists(kOutputIamfFilename));
288 }
289 
TEST_F(ObuSequencerIamfTest,PickAndPlaceFileCanBeReadBacks)290 TEST_F(ObuSequencerIamfTest, PickAndPlaceFileCanBeReadBacks) {
291   const std::string kOutputIamfFilename = GetAndCleanupOutputFileName(".iamf");
292   InitializeDescriptorObus();
293   AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
294       kFirstAudioElementId, kFirstSubstreamId, 0, 16, audio_elements_,
295       audio_frames_);
296 
297   ObuSequencerIamf sequencer(kOutputIamfFilename,
298                              kDoNotIncludeTemporalDelimiters,
299                              *LebGenerator::Create());
300 
301   ASSERT_THAT(
302       sequencer.PickAndPlace(*ia_sequence_header_obu_, codec_config_obus_,
303                              audio_elements_, mix_presentation_obus_,
304                              audio_frames_, parameter_blocks_, arbitrary_obus_),
305       IsOk());
306 
307   // Read back the file, we expect all sequenced OBUs to be present.
308   auto read_bit_buffer = FileBasedReadBitBuffer::CreateFromFilePath(
309       kReadBitBufferCapacity, kOutputIamfFilename);
310   ASSERT_NE(read_bit_buffer, nullptr);
311   IASequenceHeaderObu ia_sequence_header;
312   absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
313   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
314   std::list<MixPresentationObu> mix_presentations;
315   std::list<AudioFrameWithData> audio_frames;
316   std::list<ParameterBlockWithData> parameter_blocks;
317   EXPECT_THAT(CollectObusFromIaSequence(*read_bit_buffer, ia_sequence_header,
318                                         codec_config_obus, audio_elements,
319                                         mix_presentations, audio_frames,
320                                         parameter_blocks),
321               IsOk());
322   EXPECT_EQ(ia_sequence_header, ia_sequence_header_obu_);
323   EXPECT_EQ(codec_config_obus.size(), 1);
324   EXPECT_EQ(codec_config_obus.size(), 1);
325   EXPECT_EQ(audio_elements.size(), 1);
326   EXPECT_EQ(mix_presentations.size(), 1);
327   EXPECT_EQ(audio_frames.size(), 1);
328   EXPECT_TRUE(parameter_blocks.empty());
329 }
330 
TEST_F(ObuSequencerIamfTest,PickAndPlaceLeavesNoFileWhenDescriptorsAreInvalid)331 TEST_F(ObuSequencerIamfTest,
332        PickAndPlaceLeavesNoFileWhenDescriptorsAreInvalid) {
333   constexpr uint32_t kInvalidIaCode = IASequenceHeaderObu::kIaCode + 1;
334   const std::string kOutputIamfFilename = GetAndCleanupOutputFileName(".iamf");
335   InitObusForOneFrameIaSequence();
336   // Overwrite the IA Sequence Header with an invalid one.
337   ia_sequence_header_obu_ = IASequenceHeaderObu(
338       ObuHeader(), kInvalidIaCode, ProfileVersion::kIamfSimpleProfile,
339       ProfileVersion::kIamfSimpleProfile);
340   ObuSequencerIamf sequencer(kOutputIamfFilename,
341                              kDoNotIncludeTemporalDelimiters,
342                              *LebGenerator::Create());
343 
344   ASSERT_FALSE(sequencer
345                    .PickAndPlace(*ia_sequence_header_obu_, codec_config_obus_,
346                                  audio_elements_, mix_presentation_obus_,
347                                  audio_frames_, parameter_blocks_,
348                                  arbitrary_obus_)
349                    .ok());
350 
351   EXPECT_FALSE(std::filesystem::exists(kOutputIamfFilename));
352 }
353 
TEST_F(ObuSequencerIamfTest,PickAndPlaceLeavesNoFileWhenTemporalUnitsAreInvalid)354 TEST_F(ObuSequencerIamfTest,
355        PickAndPlaceLeavesNoFileWhenTemporalUnitsAreInvalid) {
356   constexpr bool kInvalidateTemporalUnit = true;
357   const std::string kOutputIamfFilename = GetAndCleanupOutputFileName(".iamf");
358   InitObusForOneFrameIaSequence();
359   arbitrary_obus_.emplace_back(
360       ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
361                    ArbitraryObu::kInsertionHookAfterAudioFramesAtTick, 0,
362                    kInvalidateTemporalUnit));
363   ObuSequencerIamf sequencer(kOutputIamfFilename,
364                              kDoNotIncludeTemporalDelimiters,
365                              *LebGenerator::Create());
366 
367   ASSERT_FALSE(sequencer
368                    .PickAndPlace(*ia_sequence_header_obu_, codec_config_obus_,
369                                  audio_elements_, mix_presentation_obus_,
370                                  audio_frames_, parameter_blocks_,
371                                  arbitrary_obus_)
372                    .ok());
373 
374   EXPECT_FALSE(std::filesystem::exists(kOutputIamfFilename));
375 }
376 
TEST_F(ObuSequencerIamfTest,PickAndPlaceOnInvalidTemporalUnitFailsWhenOutputFileIsOmitted)377 TEST_F(ObuSequencerIamfTest,
378        PickAndPlaceOnInvalidTemporalUnitFailsWhenOutputFileIsOmitted) {
379   constexpr bool kInvalidateTemporalUnit = true;
380   InitObusForOneFrameIaSequence();
381   arbitrary_obus_.emplace_back(
382       ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
383                    ArbitraryObu::kInsertionHookAfterAudioFramesAtTick, 0,
384                    kInvalidateTemporalUnit));
385   ObuSequencerIamf sequencer(std::string(kOmitOutputIamfFile),
386                              kDoNotIncludeTemporalDelimiters,
387                              *LebGenerator::Create());
388 
389   ASSERT_FALSE(sequencer
390                    .PickAndPlace(*ia_sequence_header_obu_, codec_config_obus_,
391                                  audio_elements_, mix_presentation_obus_,
392                                  audio_frames_, parameter_blocks_,
393                                  arbitrary_obus_)
394                    .ok());
395 }
396 
TEST_F(ObuSequencerIamfTest,FileContainsUpdatedDescriptorObusAfterUpdateDescriptorObusAndClose)397 TEST_F(ObuSequencerIamfTest,
398        FileContainsUpdatedDescriptorObusAfterUpdateDescriptorObusAndClose) {
399   const ProfileVersion kOriginalProfile = ProfileVersion::kIamfBaseProfile;
400   const ProfileVersion kUpdatedProfile =
401       ProfileVersion::kIamfBaseEnhancedProfile;
402   InitObusForOneFrameIaSequence();
403   parameter_blocks_.clear();
404   ia_sequence_header_obu_ =
405       IASequenceHeaderObu(ObuHeader(), IASequenceHeaderObu::kIaCode,
406                           kOriginalProfile, kOriginalProfile);
407   const std::string kOutputIamfFilename = GetAndCleanupOutputFileName(".iamf");
408   ObuSequencerIamf sequencer(kOutputIamfFilename,
409                              kDoNotIncludeTemporalDelimiters,
410                              *LebGenerator::Create());
411   EXPECT_THAT(sequencer.PushDescriptorObus(
412                   *ia_sequence_header_obu_, codec_config_obus_, audio_elements_,
413                   mix_presentation_obus_, arbitrary_obus_),
414               IsOk());
415   const auto temporal_unit = TemporalUnitView::Create(
416       parameter_blocks_, audio_frames_, arbitrary_obus_);
417   ASSERT_THAT(temporal_unit, IsOk());
418   EXPECT_THAT(sequencer.PushTemporalUnit(*temporal_unit), IsOk());
419   // As a toy example, we will update the IA Sequence Header.
420   ia_sequence_header_obu_ =
421       IASequenceHeaderObu(ObuHeader(), IASequenceHeaderObu::kIaCode,
422                           kUpdatedProfile, kUpdatedProfile);
423 
424   // Finalize the descriptor OBUs with a new IA Sequence Header.
425   EXPECT_THAT(sequencer.UpdateDescriptorObusAndClose(
426                   *ia_sequence_header_obu_, codec_config_obus_, audio_elements_,
427                   mix_presentation_obus_, arbitrary_obus_),
428               IsOk());
429 
430   auto read_bit_buffer = FileBasedReadBitBuffer::CreateFromFilePath(
431       kReadBitBufferCapacity, kOutputIamfFilename);
432   ASSERT_NE(read_bit_buffer, nullptr);
433   IASequenceHeaderObu read_ia_sequence_header;
434   absl::flat_hash_map<DecodedUleb128, CodecConfigObu> read_codec_config_obus;
435   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> read_audio_elements;
436   std::list<MixPresentationObu> read_mix_presentation_obus;
437   std::list<AudioFrameWithData> read_audio_frames;
438   std::list<ParameterBlockWithData> read_parameter_blocks;
439   EXPECT_THAT(
440       CollectObusFromIaSequence(*read_bit_buffer, read_ia_sequence_header,
441                                 read_codec_config_obus, read_audio_elements,
442                                 read_mix_presentation_obus, read_audio_frames,
443                                 read_parameter_blocks),
444       IsOk());
445   // Finally we expect to see evidence of the modified IA Sequence Header.
446   EXPECT_EQ(read_ia_sequence_header.GetPrimaryProfile(), kUpdatedProfile);
447 }
448 
449 }  // namespace
450 }  // namespace iamf_tools
451