• 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/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