diff --git a/iamf/cli/BUILD b/iamf/cli/BUILD index 601b1b6..617238d 100644 --- a/iamf/cli/BUILD +++ b/iamf/cli/BUILD @@ -90,13 +90,10 @@ cc_library( "//iamf/cli/proto:obu_header_cc_proto", "//iamf/cli/proto:param_definitions_cc_proto", "//iamf/cli/proto:parameter_data_cc_proto", - "//iamf/cli/proto:temporal_delimiter_cc_proto", - "//iamf/cli/proto:user_metadata_cc_proto", "//iamf/common:macros", "//iamf/common:obu_util", "//iamf/obu:audio_element", "//iamf/obu:codec_config", - "//iamf/obu:ia_sequence_header", "//iamf/obu:mix_presentation", "//iamf/obu:obu_header", "//iamf/obu:param_definitions", @@ -147,7 +144,6 @@ cc_library( deps = [ ":audio_element_with_data", ":audio_frame_with_data", - ":cli_util", ":demixing_module", ":iamf_components", ":iamf_encoder", @@ -157,6 +153,7 @@ cc_library( ":rendering_mix_presentation_finalizer", ":wav_sample_provider", ":wav_writer", + "//iamf/cli/proto:temporal_delimiter_cc_proto", "//iamf/cli/proto:test_vector_metadata_cc_proto", "//iamf/cli/proto:user_metadata_cc_proto", "//iamf/cli/proto_to_obu:arbitrary_obu_generator", diff --git a/iamf/cli/cli_util.cc b/iamf/cli/cli_util.cc index 4e203e7..1bd5641 100644 --- a/iamf/cli/cli_util.cc +++ b/iamf/cli/cli_util.cc @@ -32,14 +32,11 @@ #include "iamf/cli/proto/obu_header.pb.h" #include "iamf/cli/proto/param_definitions.pb.h" #include "iamf/cli/proto/parameter_data.pb.h" -#include "iamf/cli/proto/temporal_delimiter.pb.h" -#include "iamf/cli/proto/user_metadata.pb.h" #include "iamf/common/macros.h" #include "iamf/common/obu_util.h" #include "iamf/obu/audio_element.h" #include "iamf/obu/codec_config.h" #include "iamf/obu/demixing_info_parameter_data.h" -#include "iamf/obu/ia_sequence_header.h" #include "iamf/obu/mix_presentation.h" #include "iamf/obu/obu_header.h" #include "iamf/obu/param_definitions.h" @@ -197,41 +194,6 @@ absl::Status CopyDMixPMode(DemixingInfoParameterData::DMixPMode obu_dmixp_mode, "Proto version of internal `DMixPMode`", dmixp_mode); } -// Returns `true` if the profile fully supports temporal delimiter OBUs. -// Although profile that do not support them can safely ignore them. -bool ProfileSupportsTemporalDelimiterObus(ProfileVersion profile) { - switch (profile) { - case ProfileVersion::kIamfSimpleProfile: - case ProfileVersion::kIamfBaseProfile: - return true; - default: - return false; - } -} - -absl::Status GetIncludeTemporalDelimiterObus( - const iamf_tools_cli_proto::UserMetadata& user_metadata, - const IASequenceHeaderObu& ia_sequence_header_obu, - bool& include_temporal_delimiter) { - const bool input_include_temporal_delimiter = - user_metadata.temporal_delimiter_metadata().enable_temporal_delimiters(); - - // Allow Temporal Delimiter OBUs as long as at least one of the profiles - // supports them. If one of the profiles (e.g. simple profile) does not - // "support" them they can be safely ignored. - if (input_include_temporal_delimiter && - (!ProfileSupportsTemporalDelimiterObus( - ia_sequence_header_obu.GetPrimaryProfile()) && - !ProfileSupportsTemporalDelimiterObus( - ia_sequence_header_obu.GetAdditionalProfile()))) { - return absl::InvalidArgumentError( - "Temporal Delimiter OBUs need either `primary_profile` or " - "`additional_profile` to support them."); - } - include_temporal_delimiter = input_include_temporal_delimiter; - return absl::OkStatus(); -} - absl::Status CollectAndValidateParamDefinitions( const absl::flat_hash_map& audio_elements, diff --git a/iamf/cli/cli_util.h b/iamf/cli/cli_util.h index 93950e2..1e74340 100644 --- a/iamf/cli/cli_util.h +++ b/iamf/cli/cli_util.h @@ -28,10 +28,8 @@ #include "iamf/cli/proto/obu_header.pb.h" #include "iamf/cli/proto/param_definitions.pb.h" #include "iamf/cli/proto/parameter_data.pb.h" -#include "iamf/cli/proto/user_metadata.pb.h" #include "iamf/obu/codec_config.h" #include "iamf/obu/demixing_info_parameter_data.h" -#include "iamf/obu/ia_sequence_header.h" #include "iamf/obu/mix_presentation.h" #include "iamf/obu/obu_header.h" #include "iamf/obu/param_definitions.h" @@ -77,20 +75,6 @@ absl::Status CopyDemixingInfoParameterData( absl::Status CopyDMixPMode(DemixingInfoParameterData::DMixPMode obu_dmixp_mode, iamf_tools_cli_proto::DMixPMode& dmixp_mode); -/*!\brief Checks whether temporal delimiters OBUs should be inserted. - * - * \param user_metadata User controlled metadata. - * \param ia_sequence_header_obu IA Sequence Header OBU in the IA sequence. - * \param include_temporal_delimiter_obus True when temporal delimiters should - * be included in the IA sequence. - * \return `absl::OkStatus()` on success. `absl::InvalidArgumentError()` if - * including temporal delimiters would be invalid. - */ -absl::Status GetIncludeTemporalDelimiterObus( - const iamf_tools_cli_proto::UserMetadata& user_metadata, - const IASequenceHeaderObu& ia_sequence_header_obu, - bool& include_temporal_delimiter_obus); - /*!\brief Collects and validates the parameter definitions against the spec. * * When `param_definition_mode = 0`, `duration`, `num_subblocks`, diff --git a/iamf/cli/encoder_main_lib.cc b/iamf/cli/encoder_main_lib.cc index 59b74b9..8bef009 100644 --- a/iamf/cli/encoder_main_lib.cc +++ b/iamf/cli/encoder_main_lib.cc @@ -26,13 +26,13 @@ #include "absl/strings/str_cat.h" #include "iamf/cli/audio_element_with_data.h" #include "iamf/cli/audio_frame_with_data.h" -#include "iamf/cli/cli_util.h" #include "iamf/cli/demixing_module.h" #include "iamf/cli/iamf_components.h" #include "iamf/cli/iamf_encoder.h" #include "iamf/cli/obu_sequencer.h" #include "iamf/cli/parameter_block_partitioner.h" #include "iamf/cli/parameter_block_with_data.h" +#include "iamf/cli/proto/temporal_delimiter.pb.h" #include "iamf/cli/proto/test_vector_metadata.pb.h" #include "iamf/cli/proto/user_metadata.pb.h" #include "iamf/cli/proto_to_obu/arbitrary_obu_generator.h" @@ -309,9 +309,8 @@ absl::Status WriteObus( const std::list& audio_frames, const std::list& parameter_blocks, const std::list& arbitrary_obus) { - bool include_temporal_delimiters; - RETURN_IF_NOT_OK(GetIncludeTemporalDelimiterObus( - user_metadata, ia_sequence_header_obu, include_temporal_delimiters)); + const bool include_temporal_delimiters = + user_metadata.temporal_delimiter_metadata().enable_temporal_delimiters(); // TODO(b/349271859): Move the OBU sequencer inside `IamfEncoder`. auto obu_sequencers = CreateObuSequencers( diff --git a/iamf/cli/testdata/test_000006.textproto b/iamf/cli/testdata/test_000006.textproto index 61c4b9f..eabf6d9 100644 --- a/iamf/cli/testdata/test_000006.textproto +++ b/iamf/cli/testdata/test_000006.textproto @@ -13,8 +13,8 @@ test_vector_metadata { human_readable_description: - "A stereo base profile IAMF stream with temporal " - "delimiters." + "A stereo Base profile IAMF stream with temporal " + " delimiters." file_name_prefix: "test_000006" is_valid: true is_valid_to_decode: true @@ -30,7 +30,7 @@ test_vector_metadata { "4.2/temporal_delimiter_obu", "5.1/IA Sequence", "5.1.2/IA Data OBUs", - "6.2.4/temporal_delimiter_obu" + "4.2/Temporal Delimiter OBU" ] base_test: "test_000005" } diff --git a/iamf/cli/testdata/test_000712.textproto b/iamf/cli/testdata/test_000712.textproto new file mode 100644 index 0000000..601c47f --- /dev/null +++ b/iamf/cli/testdata/test_000712.textproto @@ -0,0 +1,158 @@ +# Copyright (c) 2024, Alliance for Open Media. All rights reserved +# +# This source code is subject to the terms of the BSD 3-Clause Clear License +# and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear +# License was not distributed with this source code in the LICENSE file, you +# can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the +# Alliance for Open Media Patent License 1.0 was not distributed with this +# source code in the PATENTS file, you can obtain it at +# www.aomedia.org/license/patent. + +# proto-file: iamf/cli/proto/user_metadata.proto +# proto-message: UserMetadata + +test_vector_metadata { + human_readable_description: + "A Base-Enhanced IAMF stream with Temporal Delimiter" + " OBUs " + file_name_prefix: "test_000712" + is_valid: true + is_valid_to_decode: true + validate_user_loudness: true + mp4_fixed_timestamp: "2024-10-28 00:00:00" + test_repository_tags: [ + "github/aomediacodec/libiamf/main" + ] + primary_tested_spec_sections: ["3.10/Temporal Delimiter OBU"] + base_test: "test_000005" +} + +ia_sequence_header_metadata { + primary_profile: PROFILE_VERSION_BASE_ENHANCED + additional_profile: PROFILE_VERSION_BASE_ENHANCED +} + +codec_config_metadata { + codec_config_id: 200 + codec_config { + codec_id: CODEC_ID_LPCM + num_samples_per_frame: 64 + audio_roll_distance: 0 + decoder_config_lpcm { + sample_format_flags: LPCM_LITTLE_ENDIAN + sample_size: 16 + sample_rate: 16000 + } + } +} + +audio_element_metadata { + audio_element_id: 300 + audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED + reserved: 0 + codec_config_id: 200 + num_substreams: 1 + audio_substream_ids: [0] + num_parameters: 0 + scalable_channel_layout_config { + num_layers: 1 + reserved: 0 + channel_audio_layer_configs: [ + { + loudspeaker_layout: LOUDSPEAKER_LAYOUT_EXPANDED + expanded_loudspeaker_layout: EXPANDED_LOUDSPEAKER_LAYOUT_STEREO_S + output_gain_is_present_flag: 0 + recon_gain_is_present_flag: 0 + reserved_a: 0 + substream_count: 1 + coupled_substream_count: 1 + } + ] + } +} + +mix_presentation_metadata { + mix_presentation_id: 42 + count_label: 1 + annotations_language: ["en-us"] + localized_presentation_annotations: ["test_mix_pres"] + num_sub_mixes: 1 + sub_mixes { + num_audio_elements: 1 + audio_elements { + audio_element_id: 300 + localized_element_annotations: ["test_sub_mix_0_audio_element_0"] + rendering_config { + headphones_rendering_mode: HEADPHONES_RENDERING_MODE_STEREO + } + element_mix_gain { + param_definition { + parameter_id: 100 + parameter_rate: 16000 + param_definition_mode: 1 + reserved: 0 + } + default_mix_gain: 0 + } + } + output_mix_gain { + param_definition { + parameter_id: 100 + parameter_rate: 16000 + param_definition_mode: 1 + reserved: 0 + } + default_mix_gain: 0 + } + num_layouts: 1 + layouts { + loudness_layout { + layout_type: LAYOUT_TYPE_LOUDSPEAKERS_SS_CONVENTION + ss_layout { + sound_system: SOUND_SYSTEM_A_0_2_0 + reserved: 0 + } + } + loudness { + info_type_bit_masks: [] + integrated_loudness: -13733 + digital_peak: -12879 + } + } + } +} + +audio_frame_metadata { + wav_filename: "sawtooth_100_stereo.wav" + samples_to_trim_at_end: 0 + samples_to_trim_at_start: 0 + audio_element_id: 300 + channel_metadatas: [ + { channel_id: 0 channel_label: CHANNEL_LABEL_LS_5 }, + { channel_id: 1 channel_label: CHANNEL_LABEL_RS_5 } + ] +} + +parameter_block_metadata { + parameter_id: 100 + start_timestamp: 0 + duration: 8000 + num_subblocks: 1 + constant_subblock_duration: 8000 + subblocks: [ + { + mix_gain_parameter_data { + animation_type: ANIMATE_STEP + param_data { + step { + start_point_value: 0 + } + } + } + } + ] +} + +temporal_delimiter_metadata { + enable_temporal_delimiters: true +} diff --git a/iamf/cli/tests/BUILD b/iamf/cli/tests/BUILD index bf4724e..599da0a 100644 --- a/iamf/cli/tests/BUILD +++ b/iamf/cli/tests/BUILD @@ -91,13 +91,10 @@ cc_test( "//iamf/cli:cli_util", "//iamf/cli/proto:obu_header_cc_proto", "//iamf/cli/proto:parameter_data_cc_proto", - "//iamf/cli/proto:temporal_delimiter_cc_proto", - "//iamf/cli/proto:user_metadata_cc_proto", "//iamf/cli/proto_to_obu:audio_element_generator", "//iamf/obu:audio_element", "//iamf/obu:audio_frame", "//iamf/obu:codec_config", - "//iamf/obu:ia_sequence_header", "//iamf/obu:mix_presentation", "//iamf/obu:obu_header", "//iamf/obu:param_definitions", diff --git a/iamf/cli/tests/cli_util_test.cc b/iamf/cli/tests/cli_util_test.cc index 835633c..efa6127 100644 --- a/iamf/cli/tests/cli_util_test.cc +++ b/iamf/cli/tests/cli_util_test.cc @@ -30,15 +30,12 @@ #include "iamf/cli/audio_frame_with_data.h" #include "iamf/cli/proto/obu_header.pb.h" #include "iamf/cli/proto/parameter_data.pb.h" -#include "iamf/cli/proto/temporal_delimiter.pb.h" -#include "iamf/cli/proto/user_metadata.pb.h" #include "iamf/cli/proto_to_obu/audio_element_generator.h" #include "iamf/cli/tests/cli_test_utils.h" #include "iamf/obu/audio_element.h" #include "iamf/obu/audio_frame.h" #include "iamf/obu/codec_config.h" #include "iamf/obu/demixing_info_parameter_data.h" -#include "iamf/obu/ia_sequence_header.h" #include "iamf/obu/mix_presentation.h" #include "iamf/obu/obu_header.h" #include "iamf/obu/param_definitions.h" @@ -59,69 +56,6 @@ constexpr DecodedUleb128 kParameterRate = 48000; constexpr DecodedUleb128 kFirstSubstreamId = 31; constexpr DecodedUleb128 kSecondSubstreamId = 32; -struct IncludeTemporalDelimitersTestCase { - ProfileVersion primary_profile; - ProfileVersion additional_profile; - bool enable_temporal_delimiters; - absl::StatusCode status_code; -}; - -using IncludeTemporalDelimiters = - ::testing::TestWithParam; - -TEST_P(IncludeTemporalDelimiters, CliUtils) { - const IncludeTemporalDelimitersTestCase& test_case = GetParam(); - - // Initialize the arguments for `get_include_temporal_delimiter_obus`. - IASequenceHeaderObu ia_sequence_header_obu( - ObuHeader(), IASequenceHeaderObu::kIaCode, test_case.primary_profile, - test_case.additional_profile); - - iamf_tools_cli_proto::UserMetadata user_metadata; - user_metadata.mutable_temporal_delimiter_metadata() - ->set_enable_temporal_delimiters(test_case.enable_temporal_delimiters); - - // Call and validate results match expected. - bool result; - EXPECT_EQ(GetIncludeTemporalDelimiterObus(user_metadata, - ia_sequence_header_obu, result) - .code(), - test_case.status_code); - if (test_case.status_code == absl::StatusCode::kOk) { - EXPECT_EQ(result, test_case.enable_temporal_delimiters); - } -} - -INSTANTIATE_TEST_SUITE_P(DisabledSimpleProfile, IncludeTemporalDelimiters, - testing::ValuesIn( - {{ProfileVersion::kIamfSimpleProfile, - ProfileVersion::kIamfSimpleProfile, false, - absl::StatusCode::kOk}})); - -INSTANTIATE_TEST_SUITE_P(EnabledSimpleProfile, IncludeTemporalDelimiters, - testing::ValuesIn( - {{ProfileVersion::kIamfSimpleProfile, - ProfileVersion::kIamfSimpleProfile, true, - absl::StatusCode::kOk}})); - -INSTANTIATE_TEST_SUITE_P(DisabledBaseProfile, IncludeTemporalDelimiters, - testing::ValuesIn( - {{ProfileVersion::kIamfBaseProfile, - ProfileVersion::kIamfBaseProfile, false, - absl::StatusCode::kOk}})); - -INSTANTIATE_TEST_SUITE_P(EnabledBaseProfile, IncludeTemporalDelimiters, - testing::ValuesIn( - {{ProfileVersion::kIamfBaseProfile, - ProfileVersion::kIamfBaseProfile, true, - absl::StatusCode::kOk}})); - -INSTANTIATE_TEST_SUITE_P(EnabledBaseAndSimpleProfile, IncludeTemporalDelimiters, - testing::ValuesIn( - {{ProfileVersion::kIamfSimpleProfile, - ProfileVersion::kIamfBaseProfile, true, - absl::StatusCode::kOk}})); - TEST(WritePcmFrameToBuffer, ResizesOutputBuffer) { const size_t kExpectedSize = 12; // 3 bytes per sample * 4 samples. std::vector> frame_to_write = {{0x7f000000, 0x7e000000}, diff --git a/iamf/cli/tests/encoder_main_lib_test.cc b/iamf/cli/tests/encoder_main_lib_test.cc index 63ab965..9a357d4 100644 --- a/iamf/cli/tests/encoder_main_lib_test.cc +++ b/iamf/cli/tests/encoder_main_lib_test.cc @@ -869,6 +869,9 @@ INSTANTIATE_TEST_SUITE_P(InvalidWithMoreThanTwentyEightAudioElements, INSTANTIATE_TEST_SUITE_P(InvalidWithMoreThanTwentyEightChannels, TestVector, testing::Values("test_000711.textproto")); +INSTANTIATE_TEST_SUITE_P(BaseEnhancedProfileWithTemporalUnitObus, TestVector, + testing::Values("test_000712.textproto")); + // TODO(b/308385831): Add more tests. } // namespace diff --git a/iamf/cli/tests/obu_sequencer_test.cc b/iamf/cli/tests/obu_sequencer_test.cc index 7b2acee..46c1a5e 100644 --- a/iamf/cli/tests/obu_sequencer_test.cc +++ b/iamf/cli/tests/obu_sequencer_test.cc @@ -343,20 +343,19 @@ TEST(WriteTemporalUnit, WritesArbitraryObuBeforeParameterBlocksAtTime) { InitializeOneParameterBlockAndOneAudioFrame(per_id_metadata, parameter_blocks, audio_frames, codec_config_obus, audio_elements); - std::list arbitrary_obus; - arbitrary_obus.emplace_back( - ArbitraryObu(kObuIaReserved25, ObuHeader(), {}, - ArbitraryObu::kInsertionHookBeforeParameterBlocksAtTick)); + const std::list kArbitraryObuBeforeParameterBlocks( + {ArbitraryObu(kObuIaReserved25, ObuHeader(), {}, + ArbitraryObu::kInsertionHookBeforeParameterBlocksAtTick)}); TemporalUnit temporal_unit = { .audio_frames = {&audio_frames.front()}, .parameter_blocks = {¶meter_blocks.front()}, - .arbitrary_obus = {&arbitrary_obus.front()}, + .arbitrary_obus = {&kArbitraryObuBeforeParameterBlocks.front()}, }; const TemporalDelimiterObu temporal_delimiter_obu(ObuHeader{}); const std::list expected_arbitrary_obu_between_temporal_delimiter_and_parameter_block = { - &temporal_delimiter_obu, &arbitrary_obus.front(), + &temporal_delimiter_obu, &kArbitraryObuBeforeParameterBlocks.front(), parameter_blocks.front().obu.get(), &audio_frames.front().obu}; ValidateWriteTemporalUnitSequence( @@ -374,20 +373,19 @@ TEST(WriteTemporalUnit, WritesArbitraryObuAfterParameterBlocksAtTime) { InitializeOneParameterBlockAndOneAudioFrame(per_id_metadata, parameter_blocks, audio_frames, codec_config_obus, audio_elements); - std::list arbitrary_obus; - arbitrary_obus.emplace_back( - ArbitraryObu(kObuIaReserved25, ObuHeader(), {}, - ArbitraryObu::kInsertionHookAfterParameterBlocksAtTick)); - TemporalUnit temporal_unit = { + const std::list kArbitraryObuAfterParameterBlocks( + {ArbitraryObu(kObuIaReserved25, ObuHeader(), {}, + ArbitraryObu::kInsertionHookAfterParameterBlocksAtTick)}); + const TemporalUnit temporal_unit = { .audio_frames = {&audio_frames.front()}, .parameter_blocks = {¶meter_blocks.front()}, - .arbitrary_obus = {&arbitrary_obus.front()}, + .arbitrary_obus = {&kArbitraryObuAfterParameterBlocks.front()}, }; const std::list expected_arbitrary_obu_between_parameter_block_and_audio_frame = { parameter_blocks.front().obu.get(), - &arbitrary_obus.front(), + &kArbitraryObuAfterParameterBlocks.front(), &audio_frames.front().obu, }; @@ -406,20 +404,19 @@ TEST(WriteTemporalUnit, WritesArbitraryObuAfterAudioFramesAtTime) { InitializeOneParameterBlockAndOneAudioFrame(per_id_metadata, parameter_blocks, audio_frames, codec_config_obus, audio_elements); - std::list arbitrary_obus; - arbitrary_obus.emplace_back( - ArbitraryObu(kObuIaReserved25, ObuHeader(), {}, - ArbitraryObu::kInsertionHookAfterAudioFramesAtTick)); - TemporalUnit temporal_unit = { + const std::list kArbitraryObuAfterAudioFrames( + {ArbitraryObu(kObuIaReserved25, ObuHeader(), {}, + ArbitraryObu::kInsertionHookAfterAudioFramesAtTick)}); + const TemporalUnit temporal_unit = { .audio_frames = {&audio_frames.front()}, .parameter_blocks = {¶meter_blocks.front()}, - .arbitrary_obus = {&arbitrary_obus.front()}, + .arbitrary_obus = {&kArbitraryObuAfterAudioFrames.front()}, }; const std::list expected_arbitrary_obu_after_audio_frame = { parameter_blocks.front().obu.get(), &audio_frames.front().obu, - &arbitrary_obus.front(), + &kArbitraryObuAfterAudioFrames.front(), }; ValidateWriteTemporalUnitSequence(kDoNotIncludeTemporalDelimiters, @@ -441,7 +438,7 @@ TEST(WriteTemporalUnit, AddsNumberOfUntrimmedSamplesToNumSamples) { audio_frames.front().obu.header_.num_samples_to_trim_at_start = 1; constexpr uint32_t kNumUntrimmedSamples = kNumSamplesPerFrame - 1 - 2; - TemporalUnit temporal_unit = { + const TemporalUnit temporal_unit = { .audio_frames = {&audio_frames.front()}, .parameter_blocks = {¶meter_blocks.front()}, }; @@ -474,7 +471,7 @@ TEST(WriteTemporalUnit, FailsWhenAudioFrameHasNoAudioElement) { // Corrupt the audio frame by disassociating the audio element. audio_frames.front().audio_element_with_data = nullptr; - TemporalUnit temporal_unit = { + const TemporalUnit temporal_unit = { .audio_frames = {&audio_frames.front()}, .parameter_blocks = {¶meter_blocks.front()}, }; @@ -514,6 +511,56 @@ TEST(WriteTemporalUnit, FailsWhenAudioElementHasNoCodecConfig) { .ok()); } +TEST(WriteTemporalUnit, WritesTemporalDelimiterObuWhenEnabled) { + std::list parameter_blocks; + std::list audio_frames; + absl::flat_hash_map codec_config_obus; + absl::flat_hash_map audio_elements; + PerIdParameterMetadata per_id_metadata = + CreatePerIdMetadataForDemixing(kFirstDemixingParameterId); + InitializeOneParameterBlockAndOneAudioFrame(per_id_metadata, parameter_blocks, + audio_frames, codec_config_obus, + audio_elements); + const TemporalUnit temporal_unit = { + .audio_frames = {&audio_frames.front()}, + .parameter_blocks = {¶meter_blocks.front()}, + }; + const TemporalDelimiterObu kTemporalDelimiterObu(ObuHeader{}); + + const std::list expected_sequence = { + &kTemporalDelimiterObu, + parameter_blocks.front().obu.get(), + &audio_frames.front().obu, + }; + + ValidateWriteTemporalUnitSequence(kIncludeTemporalDelimiters, temporal_unit, + expected_sequence); +} + +TEST(WriteTemporalUnit, OmitsTemporalDelimiterObuWhenDisabled) { + std::list parameter_blocks; + std::list audio_frames; + absl::flat_hash_map codec_config_obus; + absl::flat_hash_map audio_elements; + PerIdParameterMetadata per_id_metadata = + CreatePerIdMetadataForDemixing(kFirstDemixingParameterId); + InitializeOneParameterBlockAndOneAudioFrame(per_id_metadata, parameter_blocks, + audio_frames, codec_config_obus, + audio_elements); + const TemporalUnit temporal_unit = { + .audio_frames = {&audio_frames.front()}, + .parameter_blocks = {¶meter_blocks.front()}, + }; + + const std::list expected_sequence = { + parameter_blocks.front().obu.get(), + &audio_frames.front().obu, + }; + + ValidateWriteTemporalUnitSequence(kDoNotIncludeTemporalDelimiters, + temporal_unit, expected_sequence); +} + class ObuSequencerTest : public ::testing::Test { public: void InitializeDescriptorObus() { @@ -832,6 +879,60 @@ TEST(ObuSequencerIamf, PickAndPlaceWritesFileWithOnlyIaSequenceHeader) { EXPECT_TRUE(std::filesystem::exists(kOutputIamfFilename)); } +struct ProfileVersionsAndEnableTemporalDelimiters { + ProfileVersion primary_profile; + ProfileVersion additional_profile; + bool enable_temporal_delimiters; +}; + +using TestProfileVersionAndEnableTemporalDelimiters = + ::testing::TestWithParam; + +TEST_P(TestProfileVersionAndEnableTemporalDelimiters, PickAndPlace) { + const IASequenceHeaderObu ia_sequence_header_obu( + ObuHeader(), IASequenceHeaderObu::kIaCode, GetParam().primary_profile, + GetParam().additional_profile); + ObuSequencerIamf sequencer(std::string(kOmitOutputIamfFile), + GetParam().enable_temporal_delimiters, + *LebGenerator::Create()); + + EXPECT_THAT(sequencer.PickAndPlace( + ia_sequence_header_obu, /*codec_config_obus=*/{}, + /*audio_elements=*/{}, /*mix_presentation_obus=*/{}, + /*audio_frames=*/{}, /*parameter_blocks=*/{}, + /*arbitrary_obus=*/{}), + IsOk()); +} + +INSTANTIATE_TEST_SUITE_P( + SimpleProfileWithTemporalDelimiters, + TestProfileVersionAndEnableTemporalDelimiters, + testing::Values( + {ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfSimpleProfile, + kIncludeTemporalDelimiters})); + +INSTANTIATE_TEST_SUITE_P( + SimpleProfileWithoutTemporalDelimiters, + TestProfileVersionAndEnableTemporalDelimiters, + testing::Values( + {ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfSimpleProfile, + kDoNotIncludeTemporalDelimiters})); + +INSTANTIATE_TEST_SUITE_P( + BaseProfileWithoutTemporalDelimiters, + TestProfileVersionAndEnableTemporalDelimiters, + testing::Values( + {ProfileVersion::kIamfBaseProfile, ProfileVersion::kIamfBaseProfile, + kDoNotIncludeTemporalDelimiters})); + +INSTANTIATE_TEST_SUITE_P( + BaseEnhancedProfileWithoutTemporalDelimiters, + TestProfileVersionAndEnableTemporalDelimiters, + testing::Values( + {ProfileVersion::kIamfBaseEnhancedProfile, + ProfileVersion::kIamfBaseEnhancedProfile, + kDoNotIncludeTemporalDelimiters})); + TEST(ObuSequencerIamf, PickAndPlaceSucceedsWithEmptyOutputFile) { const IASequenceHeaderObu ia_sequence_header_obu( ObuHeader(), IASequenceHeaderObu::kIaCode,