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