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/param_definitions.h"
13
14 #include <cstdint>
15 #include <memory>
16 #include <vector>
17
18 #include "absl/log/log.h"
19 #include "absl/status/status.h"
20 #include "absl/strings/str_cat.h"
21 #include "absl/types/span.h"
22 #include "iamf/common/read_bit_buffer.h"
23 #include "iamf/common/utils/macros.h"
24 #include "iamf/common/utils/numeric_utils.h"
25 #include "iamf/common/utils/validation_utils.h"
26 #include "iamf/common/write_bit_buffer.h"
27 #include "iamf/obu/extension_parameter_data.h"
28 #include "iamf/obu/mix_gain_parameter_data.h"
29 #include "iamf/obu/parameter_data.h"
30 #include "iamf/obu/recon_gain_info_parameter_data.h"
31 #include "iamf/obu/types.h"
32
33 namespace iamf_tools {
34
35 namespace {
36
ValidateSpecificParamDefinition(const ParamDefinition & param_definition)37 absl::Status ValidateSpecificParamDefinition(
38 const ParamDefinition& param_definition) {
39 using enum ParamDefinition::ParameterDefinitionType;
40 const auto& type = param_definition.GetType();
41 if (!type.has_value()) {
42 return absl::OkStatus();
43 }
44 switch (*type) {
45 case kParameterDefinitionDemixing:
46 case kParameterDefinitionReconGain:
47 RETURN_IF_NOT_OK(ValidateEqual(
48 param_definition.param_definition_mode_, uint8_t{0},
49 absl::StrCat("`param_definition_mode` for parameter_id= ",
50 param_definition.parameter_id_)));
51 RETURN_IF_NOT_OK(
52 ValidateNotEqual(param_definition.duration_, DecodedUleb128{0},
53 absl::StrCat("duration for parameter_id= ",
54 param_definition.parameter_id_)));
55 RETURN_IF_NOT_OK(ValidateEqual(
56 param_definition.constant_subblock_duration_,
57 param_definition.duration_,
58 absl::StrCat("`constant_subblock_duration` for parameter_id= ",
59 param_definition.parameter_id_)));
60 return absl::OkStatus();
61
62 // Mix gain does not have any specific validation. For backwards
63 // compatibility we must assume extension param definitions are valid as
64 // well.
65 case kParameterDefinitionMixGain:
66 default:
67 return absl::OkStatus();
68 }
69 }
70
71 } // namespace
72
GetNumSubblocks() const73 DecodedUleb128 ParamDefinition::GetNumSubblocks() const {
74 return num_subblocks_;
75 }
76
InitializeSubblockDurations(const uint32_t num_subblocks)77 void ParamDefinition::InitializeSubblockDurations(
78 const uint32_t num_subblocks) {
79 // Check if the `subblock_durations` is included.
80 if (!IncludeSubblockDurationArray()) {
81 subblock_durations_.clear();
82 } else {
83 num_subblocks_ = num_subblocks;
84 subblock_durations_.resize(num_subblocks);
85 }
86 }
87
GetSubblockDuration(int subblock_index) const88 DecodedUleb128 ParamDefinition::GetSubblockDuration(int subblock_index) const {
89 return subblock_durations_[subblock_index];
90 }
91
SetSubblockDuration(int subblock_index,DecodedUleb128 duration)92 absl::Status ParamDefinition::SetSubblockDuration(int subblock_index,
93 DecodedUleb128 duration) {
94 if (subblock_index > subblock_durations_.size()) {
95 return absl::InvalidArgumentError(absl::StrCat(
96 "Subblock index greater than `subblock_durations_.size()`= ",
97 subblock_durations_.size()));
98 }
99
100 subblock_durations_[subblock_index] = duration;
101 return absl::OkStatus();
102 }
103
ValidateAndWrite(WriteBitBuffer & wb) const104 absl::Status ParamDefinition::ValidateAndWrite(WriteBitBuffer& wb) const {
105 RETURN_IF_NOT_OK(Validate());
106
107 // Write the fields that are always present in `param_definition`.
108 RETURN_IF_NOT_OK(wb.WriteUleb128(parameter_id_));
109 RETURN_IF_NOT_OK(wb.WriteUleb128(parameter_rate_));
110 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(param_definition_mode_, 1));
111 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(reserved_, 7));
112 if (param_definition_mode_ != 0) {
113 return absl::OkStatus();
114 }
115
116 // Write the fields dependent on `param_definition_mode == 0`.
117 RETURN_IF_NOT_OK(wb.WriteUleb128(duration_));
118 RETURN_IF_NOT_OK(wb.WriteUleb128(constant_subblock_duration_));
119 if (constant_subblock_duration_ != 0) {
120 return absl::OkStatus();
121 }
122
123 // Loop to write the `subblock_durations` array if it should be included.
124 RETURN_IF_NOT_OK(wb.WriteUleb128(num_subblocks_));
125 for (const auto& subblock_duration : subblock_durations_) {
126 RETURN_IF_NOT_OK(wb.WriteUleb128(subblock_duration));
127 }
128 return absl::OkStatus();
129 }
130
ReadAndValidate(ReadBitBuffer & rb)131 absl::Status ParamDefinition::ReadAndValidate(ReadBitBuffer& rb) {
132 // Read the fields that are always present in `param_definition`.
133 RETURN_IF_NOT_OK(rb.ReadULeb128(parameter_id_));
134 RETURN_IF_NOT_OK(rb.ReadULeb128(parameter_rate_));
135 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(1, param_definition_mode_));
136 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(7, reserved_));
137 if (param_definition_mode_ != 0) {
138 return absl::OkStatus();
139 }
140
141 // Read the fields dependent on `param_definition_mode == 0`.
142 RETURN_IF_NOT_OK(rb.ReadULeb128(duration_));
143 RETURN_IF_NOT_OK(rb.ReadULeb128(constant_subblock_duration_));
144 if (constant_subblock_duration_ != 0) {
145 return absl::OkStatus();
146 }
147
148 // Loop to read the `subblock_durations` array if it should be included.
149 RETURN_IF_NOT_OK(rb.ReadULeb128(num_subblocks_));
150 for (int i = 0; i < num_subblocks_; i++) {
151 DecodedUleb128 subblock_duration;
152 RETURN_IF_NOT_OK(rb.ReadULeb128(subblock_duration));
153 subblock_durations_.push_back(subblock_duration);
154 }
155
156 RETURN_IF_NOT_OK(Validate());
157 return absl::OkStatus();
158 }
159
Print() const160 void ParamDefinition::Print() const {
161 LOG(INFO) << " parameter_type= "
162 << (type_.has_value() ? absl::StrCat(*type_) : "NONE");
163 LOG(INFO) << " parameter_id= " << parameter_id_;
164 LOG(INFO) << " parameter_rate= " << parameter_rate_;
165 LOG(INFO) << " param_definition_mode= "
166 << absl::StrCat(param_definition_mode_);
167 LOG(INFO) << " reserved= " << absl::StrCat(reserved_);
168 if (param_definition_mode_ == 0) {
169 LOG(INFO) << " duration= " << duration_;
170 LOG(INFO) << " constant_subblock_duration= "
171 << constant_subblock_duration_;
172 LOG(INFO) << " num_subblocks= " << GetNumSubblocks();
173
174 // Subblock durations.
175 if (constant_subblock_duration_ == 0) {
176 for (int k = 0; k < GetNumSubblocks(); k++) {
177 LOG(INFO) << " subblock_durations[" << k
178 << "]= " << GetSubblockDuration(k);
179 }
180 }
181 }
182 }
183
IncludeSubblockDurationArray() const184 bool ParamDefinition::IncludeSubblockDurationArray() const {
185 return param_definition_mode_ == 0 && constant_subblock_duration_ == 0;
186 }
187
Validate() const188 absl::Status ParamDefinition::Validate() const {
189 // For logging purposes.
190 const uint32_t parameter_id = parameter_id_;
191
192 absl::Status status = absl::OkStatus();
193 if (parameter_rate_ == 0) {
194 status = absl::InvalidArgumentError(absl::StrCat(
195 "Parameter rate should not be zero. Parameter ID= ", parameter_id));
196 }
197
198 // Fields below are conditional on `param_definition_mode == 1`. Otherwise
199 // these are defined directly in the Parameter Block OBU.
200 if (param_definition_mode_ == 0) {
201 if (duration_ == 0) {
202 status = absl::InvalidArgumentError(absl::StrCat(
203 "Duration should not be zero. Parameter ID = ", parameter_id));
204 }
205
206 // Check if the `subblock_durations` is included.
207 if (IncludeSubblockDurationArray()) {
208 RETURN_IF_NOT_OK(ValidateContainerSizeEqual(
209 "subblock_durations", subblock_durations_, num_subblocks_));
210
211 // Loop to add cumulative durations.
212 uint32_t total_subblock_durations = 0;
213 for (int i = 0; i < num_subblocks_; i++) {
214 if (subblock_durations_[i] == 0) {
215 status = absl::InvalidArgumentError(
216 absl::StrCat("Illegal zero duration for subblock[", i, "]. ",
217 "Parameter ID = ", parameter_id));
218 }
219
220 RETURN_IF_NOT_OK(AddUint32CheckOverflow(total_subblock_durations,
221 subblock_durations_[i],
222 total_subblock_durations));
223 }
224
225 // Check total duration matches expected duration.
226 if (total_subblock_durations != duration_) {
227 status = absl::InvalidArgumentError(absl::StrCat(
228 "Inconsistent total duration and the cumulative durations of ",
229 "subblocks. Parameter ID = ", parameter_id));
230 }
231 }
232 }
233
234 RETURN_IF_NOT_OK(ValidateSpecificParamDefinition(*this));
235
236 return status;
237 }
238
ValidateAndWrite(WriteBitBuffer & wb) const239 absl::Status MixGainParamDefinition::ValidateAndWrite(
240 WriteBitBuffer& wb) const {
241 // The common part.
242 RETURN_IF_NOT_OK(ParamDefinition::ValidateAndWrite(wb));
243
244 // The sub-class specific part.
245 RETURN_IF_NOT_OK(wb.WriteSigned16(default_mix_gain_));
246 return absl::OkStatus();
247 }
248
ReadAndValidate(ReadBitBuffer & rb)249 absl::Status MixGainParamDefinition::ReadAndValidate(ReadBitBuffer& rb) {
250 // The common part.
251 RETURN_IF_NOT_OK(ParamDefinition::ReadAndValidate(rb));
252
253 // The sub-class specific part.
254 RETURN_IF_NOT_OK(rb.ReadSigned16(default_mix_gain_));
255 return absl::OkStatus();
256 }
257
CreateParameterData() const258 std::unique_ptr<ParameterData> MixGainParamDefinition::CreateParameterData()
259 const {
260 return std::make_unique<MixGainParameterData>();
261 }
262
Print() const263 void MixGainParamDefinition::Print() const {
264 LOG(INFO) << "MixGainParamDefinition:";
265 ParamDefinition::Print();
266 LOG(INFO) << " default_mix_gain= " << default_mix_gain_;
267 }
268
ValidateAndWrite(WriteBitBuffer & wb) const269 absl::Status ReconGainParamDefinition::ValidateAndWrite(
270 WriteBitBuffer& wb) const {
271 // The common part.
272 RETURN_IF_NOT_OK(ParamDefinition::ValidateAndWrite(wb));
273
274 // No sub-class specific part for Recon Gain Parameter Definition.
275
276 return absl::OkStatus();
277 }
278
ReadAndValidate(ReadBitBuffer & rb)279 absl::Status ReconGainParamDefinition::ReadAndValidate(ReadBitBuffer& rb) {
280 // The common part.
281 RETURN_IF_NOT_OK(ParamDefinition::ReadAndValidate(rb));
282
283 // No sub-class specific part for Recon Gain Parameter Definition.
284
285 return absl::OkStatus();
286 }
287
CreateParameterData() const288 std::unique_ptr<ParameterData> ReconGainParamDefinition::CreateParameterData()
289 const {
290 auto recon_gain_parameter_data =
291 std::make_unique<ReconGainInfoParameterData>();
292 recon_gain_parameter_data->recon_gain_is_present_flags.resize(
293 aux_data_.size());
294 for (int i = 0; i < aux_data_.size(); i++) {
295 recon_gain_parameter_data->recon_gain_is_present_flags[i] =
296 aux_data_[i].recon_gain_is_present_flag;
297 }
298 recon_gain_parameter_data->recon_gain_elements.resize(aux_data_.size());
299 return recon_gain_parameter_data;
300 }
301
Print() const302 void ReconGainParamDefinition::Print() const {
303 LOG(INFO) << "ReconGainParamDefinition:";
304 ParamDefinition::Print();
305 LOG(INFO) << " audio_element_id= " << audio_element_id_;
306
307 for (int i = 0; i < aux_data_.size(); i++) {
308 LOG(INFO) << " // recon_gain_is_present_flags[" << i
309 << "]= " << absl::StrCat(aux_data_[i].recon_gain_is_present_flag);
310 const auto& channel_numbers = aux_data_[i].channel_numbers_for_layer;
311 LOG(INFO) << " // channel_numbers_for_layer[" << i
312 << "]= " << channel_numbers.surround << "." << channel_numbers.lfe
313 << "." << channel_numbers.height;
314 }
315 }
316
ValidateAndWrite(WriteBitBuffer & wb) const317 absl::Status ExtendedParamDefinition::ValidateAndWrite(
318 WriteBitBuffer& wb) const {
319 // This class does not write the base class's data, i.e. it doesn't call
320 // `ParamDefinition::ValidateAndWrite(wb)`.
321 RETURN_IF_NOT_OK(wb.WriteUleb128(param_definition_size_));
322 RETURN_IF_NOT_OK(ValidateContainerSizeEqual("param_definition_bytes_",
323 param_definition_bytes_,
324 param_definition_size_));
325 RETURN_IF_NOT_OK(
326 wb.WriteUint8Span(absl::MakeConstSpan(param_definition_bytes_)));
327
328 return absl::OkStatus();
329 }
330
ReadAndValidate(ReadBitBuffer & rb)331 absl::Status ExtendedParamDefinition::ReadAndValidate(ReadBitBuffer& rb) {
332 // This class does not read the base class's data, i.e. it doesn't call
333 // `ParamDefinition::ReadAndWrite(wb)`.
334 RETURN_IF_NOT_OK(rb.ReadULeb128(param_definition_size_));
335 param_definition_bytes_.resize(param_definition_size_);
336 RETURN_IF_NOT_OK(rb.ReadUint8Span(absl::MakeSpan(param_definition_bytes_)));
337
338 return absl::OkStatus();
339 }
340
CreateParameterData() const341 std::unique_ptr<ParameterData> ExtendedParamDefinition::CreateParameterData()
342 const {
343 return std::make_unique<ExtensionParameterData>();
344 }
345
Print() const346 void ExtendedParamDefinition::Print() const {
347 LOG(INFO) << "ExtendedParamDefinition:";
348 // This class does not read the base class's data, i.e. it doesn't call
349 // `ParamDefinition::Print()`.
350 LOG(INFO) << " param_definition_size= " << param_definition_size_;
351 LOG(INFO) << " // Skipped printing param_definition_bytes";
352 }
353
354 } // namespace iamf_tools
355