Skip to content

Commit df22b95

Browse files
committed
Implement AudioFrameGenerator::Create instead of Initialize.
- Able to reduce held data, - Existing callsites use `std::unique_ptr`, for reference stability (b/390150766), or delayed initialization. - Make interface based on `std::unique_ptr`, switch over some `std::optional` holders. - Use `ABSL_CHECK` in some places since the inner pointer is `absl_nonnull`. PiperOrigin-RevId: 828507760
1 parent 9cb0c27 commit df22b95

File tree

6 files changed

+149
-117
lines changed

6 files changed

+149
-117
lines changed

iamf/cli/iamf_encoder.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,11 +361,14 @@ absl::StatusOr<std::unique_ptr<IamfEncoder>> IamfEncoder::Create(
361361
return demixing_module.status();
362362
}
363363

364-
auto audio_frame_generator = std::make_unique<AudioFrameGenerator>(
364+
auto audio_frame_generator = AudioFrameGenerator::Create(
365365
user_metadata.audio_frame_metadata(),
366366
user_metadata.codec_config_metadata(), *audio_elements, *demixing_module,
367367
**parameters_manager, *global_timing_module);
368-
RETURN_IF_NOT_OK(audio_frame_generator->Initialize());
368+
if (!audio_frame_generator.ok()) {
369+
return audio_frame_generator.status();
370+
}
371+
ABSL_CHECK_NE(*audio_frame_generator, nullptr);
369372

370373
// Initialize the audio frame decoder. It is needed to determine the recon
371374
// gain parameters and measure the loudness of the mixes.
@@ -407,7 +410,7 @@ absl::StatusOr<std::unique_ptr<IamfEncoder>> IamfEncoder::Create(
407410
std::move(timestamp_to_arbitrary_obus),
408411
std::move(param_definition_variants),
409412
std::move(parameter_block_generator), std::move(*parameters_manager),
410-
*demixing_module, std::move(audio_frame_generator),
413+
*demixing_module, *std::move(audio_frame_generator),
411414
std::move(audio_frame_decoder), std::move(global_timing_module),
412415
std::move(*mix_presentation_finalizer), std::move(obu_sequencers),
413416
std::move(streaming_obu_sequencer)));

iamf/cli/proto_conversion/proto_to_obu/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ cc_library(
8282
"//iamf/obu:parameter_data",
8383
"//iamf/obu:types",
8484
"@abseil-cpp//absl/base:core_headers",
85+
"@abseil-cpp//absl/base:nullability",
8586
"@abseil-cpp//absl/container:flat_hash_map",
8687
"@abseil-cpp//absl/container:flat_hash_set",
8788
"@abseil-cpp//absl/log:absl_check",

iamf/cli/proto_conversion/proto_to_obu/audio_frame_generator.cc

Lines changed: 65 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <utility>
2525
#include <vector>
2626

27+
#include "absl/base/nullability.h"
2728
#include "absl/container/flat_hash_map.h"
2829
#include "absl/container/flat_hash_set.h"
2930
#include "absl/log/absl_check.h"
@@ -625,58 +626,35 @@ absl::Status ValidateAndApplyUserTrimming(
625626

626627
} // namespace
627628

628-
AudioFrameGenerator::AudioFrameGenerator(
629+
absl::StatusOr<std::unique_ptr<AudioFrameGenerator> absl_nonnull>
630+
AudioFrameGenerator::Create(
629631
const ::google::protobuf::RepeatedPtrField<
630-
iamf_tools_cli_proto::AudioFrameObuMetadata>& audio_frame_metadata,
632+
iamf_tools_cli_proto::AudioFrameObuMetadata>& audio_frame_metadatas,
631633
const ::google::protobuf::RepeatedPtrField<
632-
iamf_tools_cli_proto::CodecConfigObuMetadata>& codec_config_metadata,
634+
iamf_tools_cli_proto::CodecConfigObuMetadata>& codec_config_metadatas,
633635
const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>&
634636
audio_elements,
635637
const DemixingModule& demixing_module,
636638
ParametersManager& parameters_manager,
637-
GlobalTimingModule& global_timing_module)
638-
: audio_elements_(audio_elements),
639-
demixing_module_(demixing_module),
640-
parameters_manager_(parameters_manager),
641-
global_timing_module_(global_timing_module),
642-
// Set to a state NOT taking samples at first; may be changed to
643-
// `kTakingSamples` once `Initialize()` is called.
644-
state_(kFlushingRemaining) {
645-
for (const auto& audio_frame_obu_metadata : audio_frame_metadata) {
646-
audio_frame_metadata_[audio_frame_obu_metadata.audio_element_id()] =
647-
audio_frame_obu_metadata;
648-
}
649-
650-
for (const auto& codec_config_obu_metadata : codec_config_metadata) {
651-
codec_config_metadata_[codec_config_obu_metadata.codec_config_id()] =
639+
GlobalTimingModule& global_timing_module) {
640+
if (audio_frame_metadatas.empty()) {
641+
// Ok, nothing will be generated. This state helps clients handle trivial IA
642+
// Sequences.
643+
return absl::WrapUnique(
644+
new AudioFrameGenerator({}, {}, demixing_module, parameters_manager,
645+
global_timing_module, {}, {}, {}));
646+
}
647+
648+
// Mapping from Codec Config ID to additional codec config metadata used
649+
// to configure encoders.
650+
absl::flat_hash_map<DecodedUleb128, iamf_tools_cli_proto::CodecConfig>
651+
codec_config_metadata;
652+
for (const auto& codec_config_obu_metadata : codec_config_metadatas) {
653+
codec_config_metadata[codec_config_obu_metadata.codec_config_id()] =
652654
codec_config_obu_metadata.codec_config();
653655
}
654-
}
655-
656-
absl::StatusOr<uint32_t> AudioFrameGenerator::GetNumberOfSamplesToDelayAtStart(
657-
const iamf_tools_cli_proto::CodecConfig& codec_config_metadata,
658-
const CodecConfigObu& codec_config) {
659-
// This function is useful when querying what the codec delay should be. We
660-
// don't want it to fail if the user-provided codec delay is wrong.
661-
constexpr bool kDontValidateCodecDelay = false;
662-
663-
std::unique_ptr<EncoderBase> encoder;
664-
RETURN_IF_NOT_OK(InitializeEncoder(codec_config_metadata, codec_config,
665-
/*num_channels=*/1, encoder,
666-
kDontValidateCodecDelay));
667-
if (encoder == nullptr) {
668-
return absl::InvalidArgumentError("Failed to initialize encoder");
669-
}
670-
return encoder->GetNumberOfSamplesToDelayAtStart();
671-
}
672656

673-
absl::Status AudioFrameGenerator::Initialize() {
674-
absl::MutexLock lock(&mutex_);
675-
if (audio_frame_metadata_.empty()) {
676-
return absl::OkStatus();
677-
}
678-
const auto& first_audio_frame_metadata =
679-
audio_frame_metadata_.begin()->second;
657+
const auto& first_audio_frame_metadata = *audio_frame_metadatas.begin();
680658
const int64_t common_samples_to_trim_at_start = static_cast<int64_t>(
681659
first_audio_frame_metadata.samples_to_trim_at_start());
682660
const int64_t common_samples_to_trim_at_end =
@@ -687,15 +665,23 @@ absl::Status AudioFrameGenerator::Initialize() {
687665
first_audio_frame_metadata
688666
.samples_to_trim_at_start_includes_codec_delay();
689667

690-
for (const auto& [audio_element_id, audio_frame_metadata] :
691-
audio_frame_metadata_) {
668+
absl::flat_hash_map<DecodedUleb128, absl::flat_hash_set<ChannelLabel::Label>>
669+
audio_element_id_to_labels;
670+
absl::flat_hash_map<uint32_t, std::unique_ptr<EncoderBase>>
671+
substream_id_to_encoder;
672+
absl::flat_hash_map<uint32_t, SubstreamData> substream_id_to_substream_data;
673+
absl::flat_hash_map<uint32_t, TrimmingState> substream_id_to_trimming_state;
674+
for (const auto& audio_frame_metadata : audio_frame_metadatas) {
675+
const DecodedUleb128 audio_element_id =
676+
audio_frame_metadata.audio_element_id();
677+
692678
// Precompute the `ChannelLabel::Label` for each channel label string.
693679
RETURN_IF_NOT_OK(ChannelLabelUtils::SelectConvertAndFillLabels(
694-
audio_frame_metadata, audio_element_id_to_labels_[audio_element_id]));
680+
audio_frame_metadata, audio_element_id_to_labels[audio_element_id]));
695681

696682
// Find the Codec Config OBU for this mono or coupled stereo substream.
697-
const auto audio_elements_iter = audio_elements_.find(audio_element_id);
698-
if (audio_elements_iter == audio_elements_.end()) {
683+
const auto audio_elements_iter = audio_elements.find(audio_element_id);
684+
if (audio_elements_iter == audio_elements.end()) {
699685
return absl::InvalidArgumentError(absl::StrCat(
700686
"Audio Element with ID= ", audio_element_id, " not found"));
701687
}
@@ -710,25 +696,25 @@ absl::Status AudioFrameGenerator::Initialize() {
710696
"The spec disallows trimming multiple frames from the end.");
711697
}
712698
RETURN_IF_NOT_OK(GetEncodingDataAndInitializeEncoders(
713-
codec_config_metadata_, audio_element_with_data,
714-
substream_id_to_encoder_));
699+
codec_config_metadata, audio_element_with_data,
700+
substream_id_to_encoder));
715701

716702
// Intermediate data for all substreams belonging to an Audio Element.
717703
RETURN_IF_NOT_OK(InitializeSubstreamData(
718-
audio_element_with_data.substream_id_to_labels,
719-
substream_id_to_encoder_, num_samples_per_frame,
704+
audio_element_with_data.substream_id_to_labels, substream_id_to_encoder,
705+
num_samples_per_frame,
720706
audio_frame_metadata.samples_to_trim_at_start_includes_codec_delay(),
721707
audio_frame_metadata.samples_to_trim_at_start(),
722-
substream_id_to_substream_data_));
708+
substream_id_to_substream_data));
723709

724710
// Validate that a `DemixingParamDefinition` is available if down-mixing
725711
// is needed.
726712
absl::StatusOr<const std::list<Demixer>*> down_mixers =
727-
demixing_module_.GetDownMixers(audio_element_id);
713+
demixing_module.GetDownMixers(audio_element_id);
728714
if (!down_mixers.ok()) {
729715
return down_mixers.status();
730716
}
731-
if (!parameters_manager_.DemixingParamDefinitionAvailable(
717+
if (!parameters_manager.DemixingParamDefinitionAvailable(
732718
audio_element_id) &&
733719
!(*down_mixers)->empty()) {
734720
return absl::InvalidArgumentError(
@@ -749,9 +735,9 @@ absl::Status AudioFrameGenerator::Initialize() {
749735
const int64_t additional_samples_to_trim_at_start =
750736
common_samples_to_trim_at_start_includes_codec_delay
751737
? 0
752-
: substream_id_to_encoder_[substream_id]
738+
: substream_id_to_encoder[substream_id]
753739
->GetNumberOfSamplesToDelayAtStart();
754-
substream_id_to_trimming_state_[substream_id] = {
740+
substream_id_to_trimming_state[substream_id] = {
755741
.increment_samples_to_trim_at_end_by_padding =
756742
!audio_frame_metadata.samples_to_trim_at_end_includes_padding(),
757743
.user_samples_left_to_trim_at_end = common_samples_to_trim_at_end,
@@ -762,13 +748,29 @@ absl::Status AudioFrameGenerator::Initialize() {
762748
}
763749
}
764750

765-
// If `substream_id_to_substream_data_` is not empty, meaning this generator
766-
// is expecting audio substreams and is ready to take audio samples.
767-
if (!substream_id_to_substream_data_.empty()) {
768-
state_ = kTakingSamples;
769-
}
751+
return absl::WrapUnique(new AudioFrameGenerator(
752+
audio_element_id_to_labels, audio_elements, demixing_module,
753+
parameters_manager, global_timing_module,
754+
std::move(substream_id_to_encoder),
755+
std::move(substream_id_to_substream_data),
756+
std::move(substream_id_to_trimming_state)));
757+
}
770758

771-
return absl::OkStatus();
759+
absl::StatusOr<uint32_t> AudioFrameGenerator::GetNumberOfSamplesToDelayAtStart(
760+
const iamf_tools_cli_proto::CodecConfig& codec_config_metadata,
761+
const CodecConfigObu& codec_config) {
762+
// This function is useful when querying what the codec delay should be. We
763+
// don't want it to fail if the user-provided codec delay is wrong.
764+
constexpr bool kDontValidateCodecDelay = false;
765+
766+
std::unique_ptr<EncoderBase> encoder;
767+
RETURN_IF_NOT_OK(InitializeEncoder(codec_config_metadata, codec_config,
768+
/*num_channels=*/1, encoder,
769+
kDontValidateCodecDelay));
770+
if (encoder == nullptr) {
771+
return absl::InvalidArgumentError("Failed to initialize encoder");
772+
}
773+
return encoder->GetNumberOfSamplesToDelayAtStart();
772774
}
773775

774776
bool AudioFrameGenerator::TakingSamples() const {

iamf/cli/proto_conversion/proto_to_obu/audio_frame_generator.h

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
#include <cstdint>
1717
#include <list>
1818
#include <memory>
19+
#include <utility>
1920

21+
#include "absl/base/nullability.h"
2022
#include "absl/base/thread_annotations.h"
2123
#include "absl/container/flat_hash_map.h"
2224
#include "absl/container/flat_hash_set.h"
@@ -55,8 +57,7 @@ namespace iamf_tools {
5557
*
5658
* The use pattern of this class is:
5759
*
58-
* - Initialize (`Initialize()`).
59-
* - (This puts the generator in the `kTakingSamples` state.)
60+
* - Call `Create()`.
6061
*
6162
* Thread 1:
6263
* - Repeat until no new sample to add (by checking `TakingSamples()`):
@@ -84,7 +85,7 @@ class AudioFrameGenerator {
8485
int64_t user_samples_left_to_trim_at_start;
8586
};
8687

87-
/*!\brief Constructor.
88+
/*!\brief Factory function to create an `AudioFrameGenerator`.
8889
*
8990
* \param audio_frame_metadata Input audio frame metadata.
9091
* \param codec_config_metadata Input codec config metadata.
@@ -93,7 +94,8 @@ class AudioFrameGenerator {
9394
* \param parameters_manager Manager of parameters.
9495
* \param global_timing_module Global Timing Module.
9596
*/
96-
AudioFrameGenerator(
97+
static absl::StatusOr<std::unique_ptr<AudioFrameGenerator> absl_nonnull>
98+
Create(
9799
const ::google::protobuf::RepeatedPtrField<
98100
iamf_tools_cli_proto::AudioFrameObuMetadata>& audio_frame_metadata,
99101
const ::google::protobuf::RepeatedPtrField<
@@ -118,12 +120,6 @@ class AudioFrameGenerator {
118120
const iamf_tools_cli_proto::CodecConfig& codec_config_metadata,
119121
const CodecConfigObu& codec_config);
120122

121-
/*!\brief Initializes encoders and relevant data structures.
122-
*
123-
* \return `absl::OkStatus()` on success. A specific status on failure.
124-
*/
125-
absl::Status Initialize();
126-
127123
/*!\brief Returns whether the generator is still taking audio samples.
128124
*
129125
* \return True if the generator is still taking audio samples.
@@ -183,24 +179,57 @@ class AudioFrameGenerator {
183179
kFlushingRemaining,
184180
};
185181

186-
// Mapping from Audio Element ID to audio frame metadata.
187-
absl::flat_hash_map<DecodedUleb128,
188-
iamf_tools_cli_proto::AudioFrameObuMetadata>
189-
audio_frame_metadata_;
182+
/*!\brief Private constructor.
183+
*
184+
* \param audio_element_id_to_labels Mapping from Audio Element ID to labels.
185+
* \param audio_elements Mapping from Audio Element ID to audio element data.
186+
* \param demixing_module Demixng module.
187+
* \param parameters_manager Manager of parameters.
188+
* \param global_timing_module Global Timing Module.
189+
* \param substream_id_to_encoder Mapping from audio substream IDs to
190+
* encoders.
191+
* \param substream_id_to_substream_data Mapping from substream IDs to
192+
* substream data.
193+
* \param substream_id_to_trimming_state Mapping from substream IDs to
194+
* trimming states.
195+
*/
196+
AudioFrameGenerator(
197+
absl::flat_hash_map<DecodedUleb128,
198+
absl::flat_hash_set<ChannelLabel::Label>>
199+
audio_element_id_to_labels,
200+
const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>&
201+
audio_elements,
202+
const DemixingModule& demixing_module,
203+
ParametersManager& parameters_manager,
204+
GlobalTimingModule& global_timing_module,
205+
absl::flat_hash_map<uint32_t, std::unique_ptr<EncoderBase>>
206+
substream_id_to_encoder,
207+
absl::flat_hash_map<uint32_t, SubstreamData>
208+
substream_id_to_substream_data,
209+
absl::flat_hash_map<uint32_t, TrimmingState>
210+
substream_id_to_trimming_state)
211+
: audio_element_id_to_labels_(std::move(audio_element_id_to_labels)),
212+
audio_elements_(audio_elements),
213+
substream_id_to_encoder_(std::move(substream_id_to_encoder)),
214+
substream_id_to_substream_data_(
215+
std::move(substream_id_to_substream_data)),
216+
substream_id_to_trimming_state_(
217+
std::move(substream_id_to_trimming_state)),
218+
demixing_module_(demixing_module),
219+
parameters_manager_(parameters_manager),
220+
global_timing_module_(global_timing_module),
221+
state_(substream_id_to_encoder_.empty() ? kFlushingRemaining
222+
: kTakingSamples) {}
190223

191224
// Mapping from Audio Element ID to labels.
192-
absl::flat_hash_map<DecodedUleb128, absl::flat_hash_set<ChannelLabel::Label>>
225+
const absl::flat_hash_map<DecodedUleb128,
226+
absl::flat_hash_set<ChannelLabel::Label>>
193227
audio_element_id_to_labels_;
194228

195229
// Mapping from Audio Element ID to audio element data.
196230
const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>&
197231
audio_elements_;
198232

199-
// Mapping from Codec Config ID to additional codec config metadata used
200-
// to configure encoders.
201-
absl::flat_hash_map<DecodedUleb128, iamf_tools_cli_proto::CodecConfig>
202-
codec_config_metadata_;
203-
204233
// Mapping from audio substream IDs to encoders.
205234
absl::flat_hash_map<uint32_t, std::unique_ptr<EncoderBase>>
206235
substream_id_to_encoder_ ABSL_GUARDED_BY(mutex_);

iamf/cli/proto_conversion/proto_to_obu/tests/audio_frame_generator_benchmark.cc

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
#include <cstdint>
1414
#include <memory>
15-
#include <optional>
1615
#include <utility>
1716
#include <vector>
1817

@@ -80,7 +79,7 @@ void InitializeAudioFrameGenerator(
8079
absl::flat_hash_map<DecodedUleb128, AudioElementWithData>& audio_elements,
8180
std::unique_ptr<GlobalTimingModule>& global_timing_module,
8281
std::unique_ptr<ParametersManager>& parameters_manager,
83-
std::optional<AudioFrameGenerator>& audio_frame_generator) {
82+
std::unique_ptr<AudioFrameGenerator>& audio_frame_generator) {
8483
// Initialize pre-requisite OBUs and the global timing module. This is all
8584
// derived from the `user_metadata`.
8685
CodecConfigGenerator codec_config_generator(
@@ -104,14 +103,12 @@ void InitializeAudioFrameGenerator(
104103
parameters_manager = *std::move(temp_parameters_manager);
105104

106105
// Create an audio frame generator.
107-
audio_frame_generator.emplace(user_metadata.audio_frame_metadata(),
108-
user_metadata.codec_config_metadata(),
109-
audio_elements, *demixing_module,
110-
*parameters_manager, *global_timing_module);
111-
ABSL_CHECK(audio_frame_generator.has_value());
112-
113-
// Initialize.
114-
ABSL_CHECK_OK(audio_frame_generator->Initialize());
106+
auto temp_audio_frame_generator = AudioFrameGenerator::Create(
107+
user_metadata.audio_frame_metadata(),
108+
user_metadata.codec_config_metadata(), audio_elements, *demixing_module,
109+
*parameters_manager, *global_timing_module);
110+
ABSL_CHECK_OK(temp_audio_frame_generator);
111+
audio_frame_generator = std::move(*temp_audio_frame_generator);
115112
}
116113

117114
static void BM_AddSamples(benchmark::State& state) {
@@ -133,7 +130,7 @@ static void BM_AddSamples(benchmark::State& state) {
133130
absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements = {};
134131
std::unique_ptr<GlobalTimingModule> global_timing_module;
135132
std::unique_ptr<ParametersManager> parameters_manager;
136-
std::optional<AudioFrameGenerator> audio_frame_generator;
133+
std::unique_ptr<AudioFrameGenerator> audio_frame_generator;
137134
InitializeAudioFrameGenerator(
138135
user_metadata, param_definitions, codec_config_obus, audio_elements,
139136
global_timing_module, parameters_manager, audio_frame_generator);

0 commit comments

Comments
 (0)