Shaka Packager SDK
iamf_audio_util.cc
1 // Copyright 2024 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/media/codecs/iamf_audio_util.h>
8 
9 #include <iomanip>
10 
11 #include <packager/media/base/bit_reader.h>
12 #include <packager/media/base/fourccs.h>
13 #include <packager/media/base/rcheck.h>
14 #include <packager/media/base/stream_info.h>
15 
16 namespace shaka {
17 namespace media {
18 
19 namespace {
20 
21 const uint8_t kMaxIamfProfile = 2;
22 
23 // 3.2. OBU type
24 // Only the IA Sequence Header and Codec Configs are used in this
25 // implementation.
26 enum ObuType {
27  OBU_IA_Codec_Config = 0,
28  OBU_IA_Sequence_Header = 31,
29 };
30 
31 // 8.1.1. leb128(). Unsigned integer represented by a variable number of
32 // little-endian bytes.
33 bool ReadLeb128(BitReader& reader, size_t* size, size_t* leb128_bytes) {
34  size_t value = 0;
35  size_t bytes_read = 0;
36  for (int i = 0; i < 8; i++) {
37  size_t leb128_byte = 0;
38  RCHECK(reader.ReadBits(8, &leb128_byte));
39  value |= (leb128_byte & 0x7f) << (i * 7);
40  bytes_read += 1;
41  if (!(leb128_byte & 0x80))
42  break;
43  }
44  // It is a requirement of bitstream conformance that the value returned from
45  // the leb128 parsing process is less than or equal to (1<<32) - 1.
46  RCHECK(value <= ((1ull << 32) - 1));
47  if (size != nullptr) {
48  *size = value;
49  }
50  if (leb128_bytes != nullptr) {
51  *leb128_bytes = bytes_read;
52  }
53  return true;
54 }
55 
56 bool ParseObuHeader(BitReader& reader, int& obu_type, size_t& obu_size) {
57  size_t leb128_bytes;
58  bool obu_trimming_status_flag;
59  bool obu_extension_flag;
60 
61  RCHECK(reader.ReadBits(5, &obu_type));
62  RCHECK(reader.SkipBits(1)); // Skip obu_redundant_copy
63  RCHECK(reader.ReadBits(1, &obu_trimming_status_flag));
64  RCHECK(reader.ReadBits(1, &obu_extension_flag));
65 
66  RCHECK(ReadLeb128(reader, &obu_size, &leb128_bytes));
67 
68  if (obu_trimming_status_flag) {
69  // Skip num_samples_to_trim_at_end
70  RCHECK(ReadLeb128(reader, nullptr, &leb128_bytes));
71  obu_size -= leb128_bytes;
72  // Skip num_samples_to_trim_at_start
73  RCHECK(ReadLeb128(reader, nullptr, &leb128_bytes));
74  obu_size -= leb128_bytes;
75  }
76 
77  if (obu_extension_flag) {
78  size_t extension_header_size;
79  RCHECK(ReadLeb128(reader, &extension_header_size, &leb128_bytes));
80  obu_size -= leb128_bytes;
81  RCHECK(reader.SkipBits(extension_header_size * 8));
82  obu_size -= extension_header_size * 8;
83  }
84 
85  return true;
86 }
87 
88 bool ParseSequenceHeaderObu(BitReader& reader,
89  uint8_t& primary_profile,
90  uint8_t& additional_profile) {
91  uint32_t ia_code;
92 
93  RCHECK(reader.ReadBits(32, &ia_code));
94  if (ia_code != FOURCC_iamf) {
95  LOG(WARNING) << "Unknown ia_code= " << std::setfill('0') << std::setw(8)
96  << std::hex << ia_code;
97  return false;
98  }
99 
100  RCHECK(reader.ReadBits(8, &primary_profile));
101  if (primary_profile > kMaxIamfProfile) {
102  LOG(WARNING) << "Unknown primary_profile= " << primary_profile;
103  return false;
104  }
105 
106  RCHECK(reader.ReadBits(8, &additional_profile));
107  if (additional_profile > kMaxIamfProfile) {
108  LOG(WARNING) << "Unknown additional_profile= " << additional_profile;
109  return false;
110  }
111 
112  return true;
113 }
114 
115 bool ParseCodecConfigObu(BitReader& reader, size_t obu_size, Codec& codec) {
116  uint32_t codec_id;
117  size_t leb128_bytes;
118 
119  // Skip codec_config_id
120  RCHECK(ReadLeb128(reader, nullptr, &leb128_bytes));
121  obu_size -= leb128_bytes;
122 
123  RCHECK(reader.ReadBits(32, &codec_id));
124  obu_size -= 4;
125 
126  // Skip the remainder of the OBU.
127  RCHECK(reader.SkipBits(obu_size * 8));
128 
129  switch (codec_id) {
130  case FOURCC_Opus:
131  codec = kCodecOpus;
132  break;
133  case FOURCC_mp4a:
134  codec = kCodecAAC;
135  break;
136  case FOURCC_fLaC:
137  codec = kCodecFlac;
138  break;
139  case FOURCC_ipcm:
140  codec = kCodecPcm;
141  break;
142  default:
143  LOG(WARNING) << "Unknown codec_id= " << std::setfill('0') << std::setw(8)
144  << std::hex << codec_id;
145  return false;
146  }
147 
148  return true;
149 }
150 } // namespace
151 
152 bool GetIamfCodecStringInfo(const std::vector<uint8_t>& iacb,
153  uint8_t& codec_string_info) {
154  uint8_t primary_profile = 0;
155  uint8_t additional_profile = 0;
156  // codec used to encode IAMF audio substreams
157  Codec iamf_codec = Codec::kUnknownCodec;
158 
159  int obu_type;
160  size_t obu_size;
161 
162  BitReader reader(iacb.data(), iacb.size());
163 
164  // configurationVersion
165  RCHECK(reader.SkipBits(8));
166 
167  // configOBUs_size
168  RCHECK(ReadLeb128(reader, &obu_size, nullptr));
169 
170  while (reader.bits_available() > 0) {
171  RCHECK(ParseObuHeader(reader, obu_type, obu_size));
172 
173  switch (obu_type) {
174  case OBU_IA_Sequence_Header:
175  RCHECK(ParseSequenceHeaderObu(reader, primary_profile,
176  additional_profile));
177  break;
178  case OBU_IA_Codec_Config:
179  RCHECK(ParseCodecConfigObu(reader, obu_size, iamf_codec));
180  break;
181  default:
182  // Skip other irrelevant OBUs.
183  RCHECK(reader.SkipBits(obu_size * 8));
184  break;
185  }
186  }
187 
188  // In IAMF v1.1 (https://aomediacodec.github.io/iamf),
189  // the valid values of primary_profile and additional_profile are {0, 1, 2}.
190  // The valid codec_ids are {Opus, mp4a, fLaC, ipcm}.
191  //
192  // This can be represented in uint8_t as:
193  // primary_profile (2bits) + additional_profile (2bits) + iamf_codec (4bits),
194  // where iamf_codec is represented using the Codec enum.
195  //
196  // Since iamf_codec is limited to 16 values, subtract the value of kCodecAudio
197  // to ensure it fits. If future audio codecs are added to the Codec enum,
198  // it may break the assumption that IAMF supported codecs are present within
199  // the first 16 audio codec entries.
200  // Further, if these values change in future version of IAMF, this format may
201  // need to be changed, and AudioStreamInfo::GetCodecString needs to be updated
202  // accordingly.
203  codec_string_info =
204  ((primary_profile << 6) | ((additional_profile << 4) & 0x3F) |
205  ((iamf_codec - kCodecAudio) & 0xF));
206 
207  return true;
208 }
209 
210 } // namespace media
211 } // namespace shaka
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66