• 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 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 #include "iamf/cli/proto_conversion/proto_to_obu/codec_config_generator.h"
13 
14 #include <algorithm>
15 #include <cstdint>
16 #include <utility>
17 #include <vector>
18 
19 #include "absl/base/no_destructor.h"
20 #include "absl/container/flat_hash_map.h"
21 #include "absl/log/log.h"
22 #include "absl/status/status.h"
23 #include "absl/strings/str_cat.h"
24 #include "iamf/cli/proto/codec_config.pb.h"
25 #include "iamf/cli/proto_conversion/lookup_tables.h"
26 #include "iamf/cli/proto_conversion/proto_to_obu/audio_frame_generator.h"
27 #include "iamf/cli/proto_conversion/proto_utils.h"
28 #include "iamf/common/utils/macros.h"
29 #include "iamf/common/utils/map_utils.h"
30 #include "iamf/common/utils/numeric_utils.h"
31 #include "iamf/obu/codec_config.h"
32 #include "iamf/obu/decoder_config/aac_decoder_config.h"
33 #include "iamf/obu/decoder_config/flac_decoder_config.h"
34 #include "iamf/obu/decoder_config/lpcm_decoder_config.h"
35 #include "iamf/obu/decoder_config/opus_decoder_config.h"
36 #include "src/google/protobuf/repeated_ptr_field.h"
37 
38 namespace iamf_tools {
39 
40 namespace {
41 
42 // Copies the `CodecId` based on the input data.
CopyCodecId(const iamf_tools_cli_proto::CodecConfig & input_codec_config,CodecConfig::CodecId & output_codec_id)43 absl::Status CopyCodecId(
44     const iamf_tools_cli_proto::CodecConfig& input_codec_config,
45     CodecConfig::CodecId& output_codec_id) {
46   if (input_codec_config.has_deprecated_codec_id()) {
47     return absl::InvalidArgumentError(
48         "Please upgrade the `deprecated_codec_id` field to the new `codec_id` "
49         "field.\n"
50         "Suggested upgrades:\n"
51         "- `deprecated_codec_id: 0x6d703461` -> `codec_id: CODEC_ID_AAC_LC`\n"
52         "- `deprecated_codec_id: 0x664c6143` -> `codec_id: CODEC_ID_FLAC`\n"
53         "- `deprecated_codec_id: 0x6970636d` -> `codec_id: CODEC_ID_LPCM`\n"
54         "- `deprecated_codec_id: 0x4f707573` -> `codec_id: CODEC_ID_OPUS`\n");
55   }
56   if (!input_codec_config.has_codec_id()) {
57     return absl::InvalidArgumentError("Missing `codec_id` field.");
58   }
59 
60   static const auto kProtoToInternalCodecId =
61       BuildStaticMapFromPairs(LookupTables::kProtoAndInternalCodecIds);
62 
63   return CopyFromMap(*kProtoToInternalCodecId, input_codec_config.codec_id(),
64                      "Internal version of proto `CodecId`= ", output_codec_id);
65 }
66 
CopyFlacBlockType(iamf_tools_cli_proto::FlacBlockType input_flac_block_type,FlacMetaBlockHeader::FlacBlockType & output_flac_block_type)67 absl::Status CopyFlacBlockType(
68     iamf_tools_cli_proto::FlacBlockType input_flac_block_type,
69     FlacMetaBlockHeader::FlacBlockType& output_flac_block_type) {
70   static const auto kProtoToInternalFlacBlockType =
71       BuildStaticMapFromPairs(LookupTables::kProtoAndInternalFlacBlockTypes);
72 
73   return CopyFromMap(*kProtoToInternalFlacBlockType, input_flac_block_type,
74                      "Internal version of proto `FlacBlockType`",
75                      output_flac_block_type);
76 }
77 
CopySampleFrequencyIndex(iamf_tools_cli_proto::SampleFrequencyIndex input_sample_frequency_index,AudioSpecificConfig::SampleFrequencyIndex & output_sample_frequency_index)78 absl::Status CopySampleFrequencyIndex(
79     iamf_tools_cli_proto::SampleFrequencyIndex input_sample_frequency_index,
80     AudioSpecificConfig::SampleFrequencyIndex& output_sample_frequency_index) {
81   static const auto kProtoToInternalSampleFrequencyIndex =
82       BuildStaticMapFromPairs(
83           LookupTables::kProtoAndInternalSampleFrequencyIndices);
84 
85   return CopyFromMap(*kProtoToInternalSampleFrequencyIndex,
86                      input_sample_frequency_index,
87                      "Internal version of proto `SampleFrequencyIndex`",
88                      output_sample_frequency_index);
89 }
90 
GenerateLpcmDecoderConfig(const iamf_tools_cli_proto::CodecConfig & user_codec_config,LpcmDecoderConfig & obu_decoder_config)91 absl::Status GenerateLpcmDecoderConfig(
92     const iamf_tools_cli_proto::CodecConfig& user_codec_config,
93     LpcmDecoderConfig& obu_decoder_config) {
94   if (!user_codec_config.has_decoder_config_lpcm()) {
95     return absl::InvalidArgumentError("Missing LPCM decoder config.");
96   }
97   const auto& lpcm_metadata = user_codec_config.decoder_config_lpcm();
98   switch (lpcm_metadata.sample_format_flags()) {
99     using enum iamf_tools_cli_proto::LpcmFormatFlags;
100     using enum LpcmDecoderConfig::LpcmFormatFlagsBitmask;
101     case LPCM_BIG_ENDIAN:
102       obu_decoder_config.sample_format_flags_bitmask_ = kLpcmBigEndian;
103       break;
104     case LPCM_LITTLE_ENDIAN:
105       obu_decoder_config.sample_format_flags_bitmask_ = kLpcmLittleEndian;
106       break;
107     default:
108       return absl::InvalidArgumentError(
109           absl::StrCat("Unknown sample_format_flags= ",
110                        lpcm_metadata.sample_format_flags()));
111   }
112 
113   obu_decoder_config.sample_rate_ = lpcm_metadata.sample_rate();
114   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
115       "LpcmDecoderConfig.sample_size", lpcm_metadata.sample_size(),
116       obu_decoder_config.sample_size_));
117 
118   return absl::OkStatus();
119 }
120 
GenerateOpusDecoderConfig(const iamf_tools_cli_proto::CodecConfig & user_codec_config,OpusDecoderConfig & obu_decoder_config)121 absl::Status GenerateOpusDecoderConfig(
122     const iamf_tools_cli_proto::CodecConfig& user_codec_config,
123     OpusDecoderConfig& obu_decoder_config) {
124   if (!user_codec_config.has_decoder_config_opus()) {
125     return absl::InvalidArgumentError("Missing Opus decoder config.");
126   }
127   const auto& opus_metadata = user_codec_config.decoder_config_opus();
128 
129   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
130       "OpusDecoderConfig.version", opus_metadata.version(),
131       obu_decoder_config.version_));
132   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
133       "OpusDecoderConfig.output_channel_count",
134       opus_metadata.output_channel_count(),
135       obu_decoder_config.output_channel_count_));
136   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint16_t>(
137       "OpusDecoderConfig.pre_skip", opus_metadata.pre_skip(),
138       obu_decoder_config.pre_skip_));
139   obu_decoder_config.input_sample_rate_ = opus_metadata.input_sample_rate();
140   RETURN_IF_NOT_OK(StaticCastIfInRange<int32_t, int16_t>(
141       "OpusDecoderConfig.output_gain", opus_metadata.output_gain(),
142       obu_decoder_config.output_gain_));
143   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
144       "OpusDecoderConfig.mapping_family", opus_metadata.mapping_family(),
145       obu_decoder_config.mapping_family_));
146   return absl::OkStatus();
147 }
148 
CopyStreamInfo(const iamf_tools_cli_proto::FlacMetaBlockStreamInfo & user_stream_info,FlacMetaBlockStreamInfo & obu_stream_info)149 absl::Status CopyStreamInfo(
150     const iamf_tools_cli_proto::FlacMetaBlockStreamInfo& user_stream_info,
151     FlacMetaBlockStreamInfo& obu_stream_info) {
152   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint16_t>(
153       "FlacMetaBlockStreamInfo.minimum_block_size",
154       user_stream_info.minimum_block_size(),
155       obu_stream_info.minimum_block_size));
156   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint16_t>(
157       "FlacMetaBlockStreamInfo.maximum_block_size",
158       user_stream_info.maximum_block_size(),
159       obu_stream_info.maximum_block_size));
160   obu_stream_info.minimum_frame_size = user_stream_info.minimum_frame_size();
161   obu_stream_info.maximum_frame_size = user_stream_info.maximum_frame_size();
162   obu_stream_info.sample_rate = user_stream_info.sample_rate();
163 
164   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
165       "FlacMetaBlockStreamInfo.number_of_channels",
166       user_stream_info.number_of_channels(),
167       obu_stream_info.number_of_channels));
168   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
169       "FlacMetaBlockStreamInfo.bits_per_sample",
170       user_stream_info.bits_per_sample(), obu_stream_info.bits_per_sample));
171   obu_stream_info.total_samples_in_stream =
172       user_stream_info.total_samples_in_stream();
173   if (user_stream_info.md5_signature().size() !=
174       obu_stream_info.md5_signature.size()) {
175     return absl::InvalidArgumentError(
176         absl::StrCat("Expected a 16 byte MD5 signature. Actual size: ",
177                      user_stream_info.md5_signature().size()));
178   }
179   std::transform(user_stream_info.md5_signature().begin(),
180                  user_stream_info.md5_signature().end(),
181                  obu_stream_info.md5_signature.begin(),
182                  [](const char x) { return static_cast<uint8_t>(x); });
183   return absl::OkStatus();
184 }
185 
GenerateFlacDecoderConfig(const iamf_tools_cli_proto::CodecConfig & user_codec_config,FlacDecoderConfig & obu_decoder_config)186 absl::Status GenerateFlacDecoderConfig(
187     const iamf_tools_cli_proto::CodecConfig& user_codec_config,
188     FlacDecoderConfig& obu_decoder_config) {
189   if (!user_codec_config.has_decoder_config_flac()) {
190     return absl::InvalidArgumentError("Missing FLAC decoder config.");
191   }
192 
193   const auto& flac_metadata = user_codec_config.decoder_config_flac();
194 
195   obu_decoder_config.metadata_blocks_.reserve(
196       flac_metadata.metadata_blocks().size());
197   for (const auto& metadata_block : flac_metadata.metadata_blocks()) {
198     FlacMetadataBlock obu_metadata_block;
199 
200     // Generate the header.
201     obu_metadata_block.header.last_metadata_block_flag =
202         metadata_block.header().last_metadata_block_flag();
203 
204     RETURN_IF_NOT_OK(CopyFlacBlockType(metadata_block.header().block_type(),
205                                        obu_metadata_block.header.block_type));
206 
207     obu_metadata_block.header.metadata_data_block_length =
208         metadata_block.header().metadata_data_block_length();
209 
210     // Generate the block specific fields.
211     if (obu_metadata_block.header.block_type ==
212         FlacMetaBlockHeader::kFlacStreamInfo) {
213       // Stream info has semantic meaning for IAMF. Copy in all fields.
214       if (!metadata_block.has_stream_info()) {
215         return absl::InvalidArgumentError("Missing FLAC stream info.");
216       }
217 
218       FlacMetaBlockStreamInfo obu_stream_info;
219       RETURN_IF_NOT_OK(
220           CopyStreamInfo(metadata_block.stream_info(), obu_stream_info));
221       obu_metadata_block.payload = obu_stream_info;
222     } else {
223       // For most blocks just copy in the payload.
224       if (!metadata_block.has_generic_block()) {
225         return absl::InvalidArgumentError("Missing generic block.");
226       }
227 
228       obu_metadata_block.payload = std::vector<uint8_t>(
229           obu_metadata_block.header.metadata_data_block_length);
230 
231       std::transform(
232           metadata_block.generic_block().begin(),
233           metadata_block.generic_block().end(),
234           std::get<std::vector<uint8_t>>(obu_metadata_block.payload).begin(),
235           [](const char x) { return static_cast<uint8_t>(x); });
236     }
237 
238     obu_decoder_config.metadata_blocks_.push_back(obu_metadata_block);
239   }
240 
241   return absl::OkStatus();
242 }
243 
GenerateAacDecoderConfig(const iamf_tools_cli_proto::CodecConfig & user_codec_config,AacDecoderConfig & obu_decoder_config)244 absl::Status GenerateAacDecoderConfig(
245     const iamf_tools_cli_proto::CodecConfig& user_codec_config,
246     AacDecoderConfig& obu_decoder_config) {
247   if (!user_codec_config.has_decoder_config_aac()) {
248     return absl::InvalidArgumentError("Missing AAC decoder config.");
249   }
250   const auto& aac_metadata = user_codec_config.decoder_config_aac();
251 
252   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
253       "AacDecoderConfig.decoder_config_descriptor_tag",
254       aac_metadata.decoder_config_descriptor_tag(),
255       obu_decoder_config.decoder_config_descriptor_tag_));
256   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
257       "AacDecoderConfig.object_type_indication",
258       aac_metadata.object_type_indication(),
259       obu_decoder_config.object_type_indication_));
260   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
261       "AacDecoderConfig.stream_type", aac_metadata.stream_type(),
262       obu_decoder_config.stream_type_));
263   obu_decoder_config.upstream_ = aac_metadata.upstream();
264   obu_decoder_config.reserved_ = aac_metadata.reserved();
265   obu_decoder_config.buffer_size_db_ = aac_metadata.buffer_size_db();
266   obu_decoder_config.max_bitrate_ = aac_metadata.max_bitrate();
267   obu_decoder_config.average_bit_rate_ = aac_metadata.average_bit_rate();
268 
269   if (!aac_metadata.has_decoder_specific_info()) {
270     return absl::InvalidArgumentError("Missing AAC decoder specific info.");
271   }
272   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
273       "AacDecoderConfig.decoder_specific_info_descriptor_tag",
274       aac_metadata.decoder_specific_info()
275           .decoder_specific_info_descriptor_tag(),
276       obu_decoder_config.decoder_specific_info_.decoder_specific_info_tag));
277   auto& audio_specific_config =
278       obu_decoder_config.decoder_specific_info_.audio_specific_config;
279   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
280       "AacDecoderConfig.audio_object_type",
281       aac_metadata.decoder_specific_info().audio_object_type(),
282       audio_specific_config.audio_object_type_));
283   RETURN_IF_NOT_OK(CopySampleFrequencyIndex(
284       aac_metadata.decoder_specific_info().sample_frequency_index(),
285       audio_specific_config.sample_frequency_index_));
286   if (audio_specific_config.sample_frequency_index_ ==
287       AudioSpecificConfig::SampleFrequencyIndex::kEscapeValue) {
288     // The `sampling_frequency` is directly included in the stream.
289     audio_specific_config.sampling_frequency_ =
290         aac_metadata.decoder_specific_info().sampling_frequency();
291   }
292 
293   RETURN_IF_NOT_OK(StaticCastIfInRange<uint32_t, uint8_t>(
294       "AacDecoderConfig.channel_configuration",
295       aac_metadata.decoder_specific_info().channel_configuration(),
296       audio_specific_config.channel_configuration_));
297 
298   audio_specific_config.ga_specific_config_.frame_length_flag =
299       aac_metadata.ga_specific_config().frame_length_flag();
300   audio_specific_config.ga_specific_config_.depends_on_core_coder =
301       aac_metadata.ga_specific_config().depends_on_core_coder();
302   audio_specific_config.ga_specific_config_.extension_flag =
303       aac_metadata.ga_specific_config().extension_flag();
304 
305   return absl::OkStatus();
306 }
307 
LogCodecConfigObus(const absl::flat_hash_map<uint32_t,CodecConfigObu> & codec_config_obus)308 void LogCodecConfigObus(
309     const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus) {
310   for (const auto& [codec_config_id, codec_config_obu] : codec_config_obus) {
311     codec_config_obu.PrintObu();
312   }
313 }
314 
OverrideCodecDelay(const iamf_tools_cli_proto::CodecConfig & codec_config_metadata,CodecConfigObu & codec_config_obu)315 absl::Status OverrideCodecDelay(
316     const iamf_tools_cli_proto::CodecConfig& codec_config_metadata,
317     CodecConfigObu& codec_config_obu) {
318   const auto required_codec_delay =
319       AudioFrameGenerator::GetNumberOfSamplesToDelayAtStart(
320           codec_config_metadata, codec_config_obu);
321   if (!required_codec_delay.ok()) {
322     return required_codec_delay.status();
323   }
324 
325   return codec_config_obu.SetCodecDelay(*required_codec_delay);
326 }
327 
328 }  // namespace
329 
Generate(absl::flat_hash_map<uint32_t,CodecConfigObu> & codec_config_obus)330 absl::Status CodecConfigGenerator::Generate(
331     absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus) {
332   // Codec Config-related parameters.
333   for (auto const& codec_config_metadata : codec_config_metadata_) {
334     // Common section for all codecs.
335     // Most fields nested within the inner `codec_config`.
336     const auto& input_codec_config = codec_config_metadata.codec_config();
337 
338     CodecConfig::CodecId obu_codec_id;
339     RETURN_IF_NOT_OK(CopyCodecId(input_codec_config, obu_codec_id));
340 
341     CodecConfig obu_codec_config{
342         .codec_id = obu_codec_id,
343         .num_samples_per_frame = input_codec_config.num_samples_per_frame()};
344 
345     RETURN_IF_NOT_OK(StaticCastIfInRange<int32_t, int16_t>(
346         "CodecConfigObu.audio_roll_distance",
347         input_codec_config.audio_roll_distance(),
348         obu_codec_config.audio_roll_distance));
349 
350     // Process the codec-specific `decoder_config` field.
351     if (obu_codec_id == CodecConfig::kCodecIdLpcm) {
352       LpcmDecoderConfig lpcm_decoder_config;
353       RETURN_IF_NOT_OK(
354           GenerateLpcmDecoderConfig(input_codec_config, lpcm_decoder_config));
355       obu_codec_config.decoder_config = lpcm_decoder_config;
356     } else if (obu_codec_id == CodecConfig::kCodecIdOpus) {
357       OpusDecoderConfig opus_decoder_config;
358       RETURN_IF_NOT_OK(
359           GenerateOpusDecoderConfig(input_codec_config, opus_decoder_config));
360       obu_codec_config.decoder_config = opus_decoder_config;
361     } else if (obu_codec_id == CodecConfig::kCodecIdFlac) {
362       FlacDecoderConfig flac_decoder_config;
363       RETURN_IF_NOT_OK(
364           GenerateFlacDecoderConfig(input_codec_config, flac_decoder_config));
365       obu_codec_config.decoder_config = flac_decoder_config;
366     } else if (obu_codec_id == CodecConfig::kCodecIdAacLc) {
367       AacDecoderConfig aac_decoder_config;
368       RETURN_IF_NOT_OK(
369           GenerateAacDecoderConfig(input_codec_config, aac_decoder_config));
370       obu_codec_config.decoder_config = aac_decoder_config;
371     } else {
372       // This should not be possible because `CopyCodecId` would have already
373       // detected the error.
374       return absl::InvalidArgumentError(
375           absl::StrCat("Unsupported codec with codec_id= ", obu_codec_id));
376     }
377 
378     CodecConfigObu obu(
379         GetHeaderFromMetadata(codec_config_metadata.obu_header()),
380         codec_config_metadata.codec_config_id(), obu_codec_config);
381     RETURN_IF_NOT_OK(obu.Initialize(
382         input_codec_config.automatically_override_audio_roll_distance()));
383     if (input_codec_config.automatically_override_codec_delay()) {
384       RETURN_IF_NOT_OK(OverrideCodecDelay(input_codec_config, obu));
385     }
386 
387     codec_config_obus.emplace(codec_config_metadata.codec_config_id(),
388                               std::move(obu));
389   }
390 
391   LogCodecConfigObus(codec_config_obus);
392   return absl::OkStatus();
393 }
394 
395 }  // namespace iamf_tools
396