1 /*
2 * Copyright (c) 2024, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 3-Clause Clear License
5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6 * License was not distributed with this source code in the LICENSE file, you
7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8 * Alliance for Open Media Patent License 1.0 was not distributed with this
9 * source code in the PATENTS file, you can obtain it at
10 * www.aomedia.org/license/patent.
11 */
12
13 #include "iamf/cli/adm_to_user_metadata/iamf/user_metadata_generator.h"
14
15 #include <cstdint>
16 #include <filesystem>
17 #include <fstream>
18 #include <ios>
19 #include <string>
20 #include <vector>
21
22 #include "absl/log/log.h"
23 #include "absl/status/status.h"
24 #include "absl/status/statusor.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/string_view.h"
27 #include "iamf/cli/adm_to_user_metadata/adm/adm_elements.h"
28 #include "iamf/cli/adm_to_user_metadata/iamf/ia_sequence_header_obu_metadata_handler.h"
29 #include "iamf/cli/adm_to_user_metadata/iamf/iamf.h"
30 #include "iamf/cli/adm_to_user_metadata/iamf/mix_presentation_handler.h"
31 #include "iamf/cli/adm_to_user_metadata/iamf/test_vector_metadata_handler.h"
32 #include "iamf/cli/proto/user_metadata.pb.h"
33 #include "iamf/cli/user_metadata_builder/audio_frame_metadata_builder.h"
34 #include "iamf/cli/user_metadata_builder/codec_config_obu_metadata_builder.h"
35 #include "iamf/obu/types.h"
36
37 namespace iamf_tools {
38 namespace adm_to_user_metadata {
39
40 namespace {
41 constexpr DecodedUleb128 kCodecConfigId = 0;
42 }
43
WriteUserMetadataToFile(bool write_binary_proto,const std::filesystem::path & file_path,const iamf_tools_cli_proto::UserMetadata & user_metadata)44 absl::Status UserMetadataGenerator::WriteUserMetadataToFile(
45 bool write_binary_proto, const std::filesystem::path& file_path,
46 const iamf_tools_cli_proto::UserMetadata& user_metadata) {
47 const auto file_name =
48 file_path /
49 absl::StrCat(user_metadata.test_vector_metadata().file_name_prefix(),
50 write_binary_proto ? ".binpb" : ".textproto");
51
52 std::ofstream output_file(file_name, std::ios::binary | std::ios::out);
53 if (!output_file.is_open()) {
54 return absl::FailedPreconditionError(
55 absl::StrCat("Failed to open file_name= ", file_name.string()));
56 }
57
58 if (write_binary_proto) {
59 output_file << user_metadata.SerializeAsString();
60 } else {
61 output_file << user_metadata.DebugString();
62 }
63
64 output_file.close();
65 LOG(INFO) << file_name.string() << " generated successfully.";
66
67 return absl::OkStatus();
68 }
69
70 absl::StatusOr<iamf_tools_cli_proto::UserMetadata>
GenerateUserMetadata(iamf_tools_cli_proto::ProfileVersion profile_version,absl::string_view file_prefix) const71 UserMetadataGenerator::GenerateUserMetadata(
72 iamf_tools_cli_proto::ProfileVersion profile_version,
73 absl::string_view file_prefix) const {
74 std::vector<std::string> audio_pack_format_ids;
75 audio_pack_format_ids.reserve(adm_.audio_objects.size());
76 for (auto audio_object : adm_.audio_objects) {
77 audio_pack_format_ids.push_back(audio_object.audio_pack_format_id_refs[0]);
78 }
79
80 auto iamf =
81 IAMF::Create(adm_, max_frame_duration_, format_info_.samples_per_sec);
82 if (!iamf.ok()) {
83 return iamf.status();
84 }
85 iamf_tools_cli_proto::UserMetadata user_metadata;
86
87 // Generate test vector metadata.
88 TestVectorMetadataHandler(file_prefix,
89 *user_metadata.mutable_test_vector_metadata());
90
91 // Generate ia sequence header metadata.
92 PopulateIaSequenceHeaderObuMetadata(
93 profile_version, *user_metadata.add_ia_sequence_header_metadata());
94
95 // Generate codec config obu metadata.
96 user_metadata.mutable_codec_config_metadata()->Add(
97 CodecConfigObuMetadataBuilder::GetLpcmCodecConfigObuMetadata(
98 kCodecConfigId, iamf->num_samples_per_frame_,
99 format_info_.bits_per_sample, format_info_.samples_per_sec));
100
101 // Mapping of audio element
102 constexpr int32_t kFirstAudioElementId = 0;
103 if (adm_.audio_programmes.empty()) {
104 if (const auto status =
105 iamf->audio_element_metadata_builder_.PopulateAudioElementMetadata(
106 kFirstAudioElementId, kCodecConfigId, iamf->input_layouts_[0],
107 *user_metadata.add_audio_element_metadata());
108 !status.ok()) {
109 return status;
110 };
111 } else {
112 for (const auto& [unused_audio_object_id, audio_element_id] :
113 iamf->audio_object_to_audio_element_) {
114 if (const auto status =
115 iamf->audio_element_metadata_builder_
116 .PopulateAudioElementMetadata(
117 audio_element_id, kCodecConfigId,
118 iamf->input_layouts_[audio_element_id],
119 *user_metadata.add_audio_element_metadata());
120 !status.ok()) {
121 return status;
122 }
123 }
124 }
125
126 // Generate mix presentation obu metadata.
127
128 if (adm_.audio_programmes.empty()) {
129 constexpr int32_t kFirstMixPresentationId = 0;
130 // Generate a mix presentation with the first audio object and default
131 // loudness metadata.
132 const std::vector<AudioObject>& audio_objects = {adm_.audio_objects[0]};
133
134 if (const auto& status =
135 iamf->mix_presentation_handler_.PopulateMixPresentation(
136 kFirstMixPresentationId, audio_objects, LoudnessMetadata(),
137 *user_metadata.add_mix_presentation_metadata());
138 !status.ok()) {
139 return status;
140 }
141 } else {
142 for (const auto& [mix_presentation_id, audio_objects_and_metadata] :
143 iamf->mix_presentation_id_to_audio_objects_and_metadata_) {
144 if (const auto& status =
145 iamf->mix_presentation_handler_.PopulateMixPresentation(
146 mix_presentation_id, audio_objects_and_metadata.audio_objects,
147 adm_.audio_programmes[audio_objects_and_metadata
148 .original_audio_programme_index]
149 .loudness_metadata,
150 *user_metadata.add_mix_presentation_metadata());
151 !status.ok()) {
152 return status;
153 }
154 }
155 }
156
157 // Generate audio frame metadata.
158 if (adm_.audio_programmes.empty()) {
159 // The output files have suffixes starting from 1.
160 static const absl::string_view kFirstFileSuffix = "1";
161
162 if (const auto& status =
163 AudioFrameMetadataBuilder::PopulateAudioFrameMetadata(
164 absl::StrCat(file_prefix, "_converted", kFirstFileSuffix,
165 ".wav"),
166 kFirstAudioElementId, iamf->input_layouts_[0],
167 *user_metadata.add_audio_frame_metadata());
168 !status.ok()) {
169 return status;
170 }
171 } else {
172 int32_t audio_pack_index = 0;
173 for (const auto& [unused_audio_object_id, audio_element_id] :
174 iamf->audio_object_to_audio_element_) {
175 // The output files have suffixes starting from 1.
176 const std::string wav_file_name =
177 absl::StrCat(file_prefix, "_converted", audio_pack_index + 1, ".wav");
178 if (const auto& status =
179 AudioFrameMetadataBuilder::PopulateAudioFrameMetadata(
180 wav_file_name, audio_element_id,
181 iamf->input_layouts_[audio_pack_index++],
182 *user_metadata.add_audio_frame_metadata());
183 !status.ok()) {
184 return status;
185 }
186 }
187 }
188
189 return user_metadata;
190 }
191
192 } // namespace adm_to_user_metadata
193 } // namespace iamf_tools
194