• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <algorithm>
14 #include <cstdint>
15 #include <filesystem>
16 #include <istream>
17 
18 #include "absl/log/log.h"
19 #include "absl/status/status.h"
20 #include "absl/status/statusor.h"
21 #include "absl/strings/string_view.h"
22 #include "iamf/cli/adm_to_user_metadata/adm/adm_elements.h"
23 #include "iamf/cli/adm_to_user_metadata/adm/bw64_reader.h"
24 #include "iamf/cli/adm_to_user_metadata/adm/wav_file_splicer.h"
25 #include "iamf/cli/adm_to_user_metadata/iamf/user_metadata_generator.h"
26 #include "iamf/common/utils/macros.h"
27 #include "iamf/obu/ia_sequence_header.h"
28 
29 namespace iamf_tools {
30 namespace adm_to_user_metadata {
31 
32 namespace {
33 
34 // ADM audioPackFormatID corresponding to 3rd order ambisonics, in which "0004"
35 // denotes type definition Ambisonics and "0003" denotes order 3.
36 constexpr char kAudioPackFormatIdFor3OA[] = "AP_00040003";
37 // A dummy audioPackFormatID created to represent typeDefinition as
38 // DirectSpeakers (0001) and layout as LFE (1FFF).
39 constexpr char kAudioPackFormatIdForLfe[] = "AP_00011FFF";
40 
ModifyAdmToPanObjectsTo3OAAndSeparateLfe(const ProfileVersion profile_version,const int lfe_count,ADM & adm_metadata)41 void ModifyAdmToPanObjectsTo3OAAndSeparateLfe(
42     const ProfileVersion profile_version, const int lfe_count,
43     ADM& adm_metadata) {
44   using enum ProfileVersion;
45   if (profile_version == kIamfBaseProfile) {
46     // For IA Base Profile, max channels allowed per mix is 18, hence pan all
47     // audio objects(both channel beds and objects) to 3OA (16 channels).
48     adm_metadata.audio_objects.erase(adm_metadata.audio_objects.begin() + 1,
49                                      adm_metadata.audio_objects.end());
50     adm_metadata.audio_objects[0].audio_pack_format_id_refs[0] =
51         kAudioPackFormatIdFor3OA;
52   } else if (profile_version == kIamfBaseEnhancedProfile) {
53     // For IA Base Enhanced Profile, max channels allowed per mix is 28, hence
54     // pan all non-LFE channels(both channel beds and objects) in the to 3OA (16
55     // channels) and keep the LFE(s) as separate audio element(s).
56     adm_metadata.audio_objects.erase(
57         adm_metadata.audio_objects.begin() + 1 + lfe_count,
58         adm_metadata.audio_objects.end());
59     adm_metadata.audio_objects[0].audio_pack_format_id_refs[0] =
60         kAudioPackFormatIdFor3OA;
61     for (int lfe_index = 1; lfe_index <= lfe_count; ++lfe_index) {
62       adm_metadata.audio_objects[lfe_index].audio_pack_format_id_refs[0] =
63           kAudioPackFormatIdForLfe;
64     }
65   }
66 }
67 
68 }  // namespace
69 
70 absl::StatusOr<iamf_tools_cli_proto::UserMetadata>
GenerateUserMetadataAndSpliceWavFiles(absl::string_view file_prefix,int32_t frame_duration_ms,int32_t input_importance_threshold,const std::filesystem::path & output_path,std::istream & adm_file,const iamf_tools::ProfileVersion profile_version)71 GenerateUserMetadataAndSpliceWavFiles(
72     absl::string_view file_prefix, int32_t frame_duration_ms,
73     int32_t input_importance_threshold,
74     const std::filesystem::path& output_path, std::istream& adm_file,
75     const iamf_tools::ProfileVersion profile_version) {
76   // Parse the input ADM BWF file.
77   const auto& reader =
78       iamf_tools::adm_to_user_metadata::Bw64Reader::BuildFromStream(
79           std::clamp(input_importance_threshold, 0, 10), adm_file);
80   if (!reader.ok()) {
81     return reader.status();
82   }
83 
84   int lfe_count = 0;
85   // Write output ".wav" file(s).
86   RETURN_IF_NOT_OK(iamf_tools::adm_to_user_metadata::SpliceWavFilesFromAdm(
87       output_path, file_prefix, profile_version, *reader, adm_file, lfe_count));
88 
89   ADM adm_metadata = reader->adm_;
90 
91   if (reader->adm_.file_type == kAdmFileTypeDolby) {
92     ModifyAdmToPanObjectsTo3OAAndSeparateLfe(profile_version, lfe_count,
93                                              adm_metadata);
94   }
95 
96   // Generate the user metadata.
97   const auto& user_metadata_generator =
98       iamf_tools::adm_to_user_metadata::UserMetadataGenerator(
99           adm_metadata, reader->format_info_, frame_duration_ms);
100 
101   using enum iamf_tools_cli_proto::ProfileVersion;
102   using enum iamf_tools::ProfileVersion;
103   iamf_tools_cli_proto::ProfileVersion version_for_proto;
104   if (profile_version == kIamfBaseProfile) {
105     version_for_proto = PROFILE_VERSION_BASE;
106   } else if (profile_version == kIamfBaseEnhancedProfile) {
107     version_for_proto = PROFILE_VERSION_BASE_ENHANCED;
108   } else {
109     return absl::InvalidArgumentError("Invalid profile version for proto.");
110   }
111 
112   return user_metadata_generator.GenerateUserMetadata(version_for_proto,
113                                                       file_prefix);
114 }
115 
116 }  // namespace adm_to_user_metadata
117 }  // namespace iamf_tools
118