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/obu/codec_config.h"
13
14 #include <cstdint>
15 #include <utility>
16 #include <variant>
17
18 #include "absl/log/log.h"
19 #include "absl/status/status.h"
20 #include "absl/status/statusor.h"
21 #include "absl/strings/str_cat.h"
22 #include "iamf/common/read_bit_buffer.h"
23 #include "iamf/common/utils/macros.h"
24 #include "iamf/common/write_bit_buffer.h"
25 #include "iamf/obu/decoder_config/aac_decoder_config.h"
26 #include "iamf/obu/decoder_config/flac_decoder_config.h"
27 #include "iamf/obu/decoder_config/lpcm_decoder_config.h"
28 #include "iamf/obu/decoder_config/opus_decoder_config.h"
29 #include "iamf/obu/obu_base.h"
30 #include "iamf/obu/obu_header.h"
31 #include "iamf/obu/types.h"
32
33 namespace iamf_tools {
34
35 namespace {
36
ValidateNumSamplesPerFrame(uint32_t num_samples_per_frame)37 absl::Status ValidateNumSamplesPerFrame(uint32_t num_samples_per_frame) {
38 if (num_samples_per_frame == 0) {
39 return absl::InvalidArgumentError(
40 "Number of samples per frame must be non-zero.");
41 }
42 return absl::OkStatus();
43 }
44
OverrideAudioRollDistance(CodecConfig::CodecId codec_id,uint32_t num_samples_per_frame,int16_t & output_audio_roll_distance)45 absl::Status OverrideAudioRollDistance(CodecConfig::CodecId codec_id,
46 uint32_t num_samples_per_frame,
47 int16_t& output_audio_roll_distance) {
48 switch (codec_id) {
49 using enum CodecConfig::CodecId;
50 case CodecConfig::kCodecIdOpus: {
51 auto audio_roll_distance =
52 OpusDecoderConfig::GetRequiredAudioRollDistance(
53 num_samples_per_frame);
54 if (!audio_roll_distance.ok()) {
55 return audio_roll_distance.status();
56 }
57 output_audio_roll_distance = *audio_roll_distance;
58 return absl::OkStatus();
59 }
60 case kCodecIdLpcm:
61 output_audio_roll_distance =
62 LpcmDecoderConfig::GetRequiredAudioRollDistance();
63 return absl::OkStatus();
64 case kCodecIdFlac:
65 output_audio_roll_distance =
66 FlacDecoderConfig::GetRequiredAudioRollDistance();
67 return absl::OkStatus();
68 case kCodecIdAacLc:
69 output_audio_roll_distance =
70 AacDecoderConfig::GetRequiredAudioRollDistance();
71 return absl::OkStatus();
72 default:
73 return absl::InvalidArgumentError(
74 absl::StrCat("Unknown codec_id: ", codec_id));
75 }
76 }
77
SetSampleRatesAndBitDepths(uint32_t codec_id,const DecoderConfig & decoder_config,uint32_t & output_sample_rate,uint32_t & input_sample_rate,uint8_t & bit_depth_to_measure_loudness)78 absl::Status SetSampleRatesAndBitDepths(
79 uint32_t codec_id, const DecoderConfig& decoder_config,
80 uint32_t& output_sample_rate, uint32_t& input_sample_rate,
81 uint8_t& bit_depth_to_measure_loudness) {
82 switch (codec_id) {
83 using enum CodecConfig::CodecId;
84 case kCodecIdOpus: {
85 const auto& opus_decoder_config =
86 std::get<OpusDecoderConfig>(decoder_config);
87 output_sample_rate = opus_decoder_config.GetOutputSampleRate();
88 input_sample_rate = opus_decoder_config.GetInputSampleRate();
89 bit_depth_to_measure_loudness =
90 OpusDecoderConfig::GetBitDepthToMeasureLoudness();
91 return absl::OkStatus();
92 }
93 case kCodecIdLpcm: {
94 const auto& lpcm_decoder_config =
95 std::get<LpcmDecoderConfig>(decoder_config);
96 RETURN_IF_NOT_OK(
97 lpcm_decoder_config.GetOutputSampleRate(output_sample_rate));
98 input_sample_rate = output_sample_rate;
99 RETURN_IF_NOT_OK(lpcm_decoder_config.GetBitDepthToMeasureLoudness(
100 bit_depth_to_measure_loudness));
101 return absl::OkStatus();
102 }
103 case kCodecIdAacLc:
104 RETURN_IF_NOT_OK(std::get<AacDecoderConfig>(decoder_config)
105 .GetOutputSampleRate(output_sample_rate));
106 input_sample_rate = output_sample_rate;
107 bit_depth_to_measure_loudness =
108 AacDecoderConfig::GetBitDepthToMeasureLoudness();
109 return absl::OkStatus();
110 case kCodecIdFlac: {
111 const auto& flac_decoder_config =
112 std::get<FlacDecoderConfig>(decoder_config);
113 RETURN_IF_NOT_OK(
114 flac_decoder_config.GetOutputSampleRate(output_sample_rate));
115 input_sample_rate = output_sample_rate;
116 RETURN_IF_NOT_OK(flac_decoder_config.GetBitDepthToMeasureLoudness(
117 bit_depth_to_measure_loudness));
118
119 return absl::OkStatus();
120 }
121 default:
122 return absl::InvalidArgumentError(
123 absl::StrCat("Unknown codec_id: ", codec_id));
124 }
125 }
126
127 } // namespace
128
CodecConfigObu(const ObuHeader & header,const DecodedUleb128 codec_config_id,const CodecConfig & codec_config)129 CodecConfigObu::CodecConfigObu(const ObuHeader& header,
130 const DecodedUleb128 codec_config_id,
131 const CodecConfig& codec_config)
132 : ObuBase(header, kObuIaCodecConfig),
133 codec_config_id_(codec_config_id),
134 codec_config_(std::move(codec_config)) {}
135
CreateFromBuffer(const ObuHeader & header,int64_t payload_size,ReadBitBuffer & rb)136 absl::StatusOr<CodecConfigObu> CodecConfigObu::CreateFromBuffer(
137 const ObuHeader& header, int64_t payload_size, ReadBitBuffer& rb) {
138 CodecConfigObu codec_config_obu(header);
139 RETURN_IF_NOT_OK(codec_config_obu.ReadAndValidatePayload(payload_size, rb));
140 RETURN_IF_NOT_OK(codec_config_obu.Initialize());
141 return codec_config_obu;
142 }
143
ValidateAndWriteDecoderConfig(WriteBitBuffer & wb) const144 absl::Status CodecConfigObu::ValidateAndWriteDecoderConfig(
145 WriteBitBuffer& wb) const {
146 if (!init_status_.ok()) {
147 return init_status_;
148 }
149
150 // Write the `decoder_config` struct portion. This is codec specific.
151 const int16_t audio_roll_distance = codec_config_.audio_roll_distance;
152 const uint32_t num_samples_per_frame = codec_config_.num_samples_per_frame;
153 switch (codec_config_.codec_id) {
154 using enum CodecConfig::CodecId;
155 case kCodecIdOpus:
156 return std::get<OpusDecoderConfig>(codec_config_.decoder_config)
157 .ValidateAndWrite(num_samples_per_frame, audio_roll_distance, wb);
158 case kCodecIdLpcm:
159 return std::get<LpcmDecoderConfig>(codec_config_.decoder_config)
160 .ValidateAndWrite(audio_roll_distance, wb);
161 case kCodecIdAacLc:
162 return std::get<AacDecoderConfig>(codec_config_.decoder_config)
163 .ValidateAndWrite(audio_roll_distance, wb);
164 case kCodecIdFlac:
165 return std::get<FlacDecoderConfig>(codec_config_.decoder_config)
166 .ValidateAndWrite(num_samples_per_frame, audio_roll_distance, wb);
167 default:
168 return absl::InvalidArgumentError(
169 absl::StrCat("Unknown codec_id: ", codec_config_.codec_id));
170 }
171 }
172
ValidateAndWritePayload(WriteBitBuffer & wb) const173 absl::Status CodecConfigObu::ValidateAndWritePayload(WriteBitBuffer& wb) const {
174 if (!init_status_.ok()) {
175 return init_status_;
176 }
177
178 RETURN_IF_NOT_OK(wb.WriteUleb128(codec_config_id_));
179
180 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(codec_config_.codec_id, 32));
181 RETURN_IF_NOT_OK(
182 ValidateNumSamplesPerFrame(codec_config_.num_samples_per_frame));
183 RETURN_IF_NOT_OK(wb.WriteUleb128(codec_config_.num_samples_per_frame));
184 RETURN_IF_NOT_OK(wb.WriteSigned16(codec_config_.audio_roll_distance));
185
186 // Write the `decoder_config_`. This is codec specific.
187 RETURN_IF_NOT_OK(ValidateAndWriteDecoderConfig(wb));
188
189 return absl::OkStatus();
190 }
191
ReadAndValidateDecoderConfig(ReadBitBuffer & rb)192 absl::Status CodecConfigObu::ReadAndValidateDecoderConfig(ReadBitBuffer& rb) {
193 const int16_t audio_roll_distance = codec_config_.audio_roll_distance;
194 const uint32_t num_samples_per_frame = codec_config_.num_samples_per_frame;
195 // Read the `decoder_config` struct portion. This is codec specific.
196 switch (codec_config_.codec_id) {
197 using enum CodecConfig::CodecId;
198 case kCodecIdOpus: {
199 OpusDecoderConfig opus_decoder_config;
200 RETURN_IF_NOT_OK(opus_decoder_config.ReadAndValidate(
201 num_samples_per_frame, audio_roll_distance, rb));
202 codec_config_.decoder_config = opus_decoder_config;
203 return absl::OkStatus();
204 }
205 case kCodecIdLpcm: {
206 LpcmDecoderConfig lpcm_decoder_config;
207 RETURN_IF_NOT_OK(
208 lpcm_decoder_config.ReadAndValidate(audio_roll_distance, rb));
209 codec_config_.decoder_config = lpcm_decoder_config;
210 return absl::OkStatus();
211 }
212 case kCodecIdAacLc: {
213 AacDecoderConfig aac_decoder_config;
214 RETURN_IF_NOT_OK(
215 aac_decoder_config.ReadAndValidate(audio_roll_distance, rb));
216 codec_config_.decoder_config = aac_decoder_config;
217 return absl::OkStatus();
218 }
219 case kCodecIdFlac: {
220 FlacDecoderConfig flac_decoder_config;
221 RETURN_IF_NOT_OK(flac_decoder_config.ReadAndValidate(
222 num_samples_per_frame, audio_roll_distance, rb));
223 codec_config_.decoder_config = flac_decoder_config;
224 return absl::OkStatus();
225 }
226 default:
227 return absl::InvalidArgumentError(
228 absl::StrCat("Unknown codec_id: ", codec_config_.codec_id));
229 }
230 return absl::OkStatus();
231 }
232
ReadAndValidatePayloadDerived(int64_t,ReadBitBuffer & rb)233 absl::Status CodecConfigObu::ReadAndValidatePayloadDerived(
234 int64_t /*payload_size*/, ReadBitBuffer& rb) {
235 RETURN_IF_NOT_OK(rb.ReadULeb128(codec_config_id_));
236 uint64_t codec_id;
237 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(32, codec_id));
238 codec_config_.codec_id = static_cast<CodecConfig::CodecId>(codec_id);
239 RETURN_IF_NOT_OK(rb.ReadULeb128(codec_config_.num_samples_per_frame));
240 RETURN_IF_NOT_OK(
241 ValidateNumSamplesPerFrame(codec_config_.num_samples_per_frame));
242 RETURN_IF_NOT_OK(rb.ReadSigned16(codec_config_.audio_roll_distance));
243
244 // Read the `decoder_config_`. This is codec specific.
245 RETURN_IF_NOT_OK(ReadAndValidateDecoderConfig(rb));
246 return absl::OkStatus();
247 }
248
PrintObu() const249 void CodecConfigObu::PrintObu() const {
250 if (!init_status_.ok()) {
251 LOG(ERROR) << "This OBU failed to initialize with error= " << init_status_;
252 }
253 LOG(INFO) << "Codec Config OBU:";
254 LOG(INFO) << " codec_config_id= " << codec_config_id_;
255 LOG(INFO) << " codec_config:";
256 LOG(INFO) << " codec_id= " << codec_config_.codec_id;
257 LOG(INFO) << " num_samples_per_frame= " << GetNumSamplesPerFrame();
258 LOG(INFO) << " audio_roll_distance= " << codec_config_.audio_roll_distance;
259
260 // Print the `decoder_config_`. This is codec specific.
261 switch (codec_config_.codec_id) {
262 using enum CodecConfig::CodecId;
263 case kCodecIdLpcm:
264 std::get<LpcmDecoderConfig>(codec_config_.decoder_config).Print();
265 break;
266 case kCodecIdOpus:
267 std::get<OpusDecoderConfig>(codec_config_.decoder_config).Print();
268 break;
269 case kCodecIdFlac:
270 std::get<FlacDecoderConfig>(codec_config_.decoder_config).Print();
271 break;
272 case kCodecIdAacLc:
273 std::get<AacDecoderConfig>(codec_config_.decoder_config).Print();
274 break;
275 default:
276 LOG(ERROR) << "Unknown codec_id: " << codec_config_.codec_id;
277 break;
278 }
279
280 LOG(INFO) << " // input_sample_rate_= " << input_sample_rate_;
281 LOG(INFO) << " // output_sample_rate_= " << output_sample_rate_;
282 LOG(INFO) << " // bit_depth_to_measure_loudness_= "
283 << absl::StrCat(bit_depth_to_measure_loudness_);
284 }
285
Initialize(bool automatically_override_roll_distance)286 absl::Status CodecConfigObu::Initialize(
287 bool automatically_override_roll_distance) {
288 init_status_ = SetSampleRatesAndBitDepths(
289 codec_config_.codec_id, codec_config_.decoder_config, output_sample_rate_,
290 input_sample_rate_, bit_depth_to_measure_loudness_);
291
292 if (automatically_override_roll_distance) {
293 init_status_.Update(OverrideAudioRollDistance(
294 codec_config_.codec_id, codec_config_.num_samples_per_frame,
295 codec_config_.audio_roll_distance));
296 }
297
298 if (!init_status_.ok()) {
299 PrintObu();
300 }
301 return init_status_;
302 }
303
SetCodecDelay(uint16_t codec_delay)304 absl::Status CodecConfigObu::SetCodecDelay(uint16_t codec_delay) {
305 switch (codec_config_.codec_id) {
306 using enum CodecConfig::CodecId;
307 case kCodecIdLpcm:
308 case kCodecIdFlac:
309 case kCodecIdAacLc:
310 // Ok the `decoder_config` does not have a field for codec delay.
311 return absl::OkStatus();
312 case kCodecIdOpus: {
313 OpusDecoderConfig* opus_decoder_config =
314 std::get_if<OpusDecoderConfig>(&codec_config_.decoder_config);
315 if (opus_decoder_config == nullptr) {
316 return absl::InvalidArgumentError(
317 "OpusDecoderConfig is not set in CodecConfig.");
318 }
319 opus_decoder_config->pre_skip_ = codec_delay;
320 return absl::OkStatus();
321 }
322 }
323 LOG(FATAL) << "Unknown codec_id: " << codec_config_.codec_id;
324 }
325
IsLossless() const326 bool CodecConfigObu::IsLossless() const {
327 using enum CodecConfig::CodecId;
328 return codec_config_.codec_id == kCodecIdFlac ||
329 codec_config_.codec_id == kCodecIdLpcm;
330 }
331
332 } // namespace iamf_tools
333