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