2222#include " absl/status/status.h"
2323#include " absl/status/statusor.h"
2424#include " absl/strings/str_cat.h"
25- #include " absl/strings/string_view.h"
2625#include " absl/types/span.h"
2726#include " iamf/common/read_bit_buffer.h"
2827#include " iamf/common/utils/macros.h"
2928#include " iamf/common/write_bit_buffer.h"
29+ #include " iamf/obu/element_gain_offset_config.h"
3030#include " iamf/obu/param_definitions/cart16_param_definition.h"
3131#include " iamf/obu/param_definitions/cart8_param_definition.h"
3232#include " iamf/obu/param_definitions/dual_cart16_param_definition.h"
@@ -105,6 +105,7 @@ absl::Status WriteRenderingConfigParamDefinitions(
105105absl::Status WriteRenderingConfigExtension (
106106 const std::vector<RenderingConfigParamDefinition>&
107107 rendering_config_param_definitions,
108+ const std::optional<ElementGainOffsetConfig>& element_gain_offset_config,
108109 const std::vector<uint8_t >& rendering_config_extension_bytes,
109110 WriteBitBuffer& wb) {
110111 // Allocate a temporary buffer to write the rendering config param
@@ -114,6 +115,9 @@ absl::Status WriteRenderingConfigExtension(
114115 // Write the rendering config param definitions to the temporary buffer.
115116 RETURN_IF_NOT_OK (WriteRenderingConfigParamDefinitions (
116117 rendering_config_param_definitions, temp_wb));
118+ if (element_gain_offset_config.has_value ()) {
119+ RETURN_IF_NOT_OK (element_gain_offset_config->Write (temp_wb));
120+ }
117121 RETURN_IF_NOT_OK (temp_wb.WriteUint8Span (
118122 absl::MakeConstSpan (rendering_config_extension_bytes)));
119123 ABSL_CHECK (temp_wb.IsByteAligned ());
@@ -125,15 +129,13 @@ absl::Status WriteRenderingConfigExtension(
125129 return wb.WriteUint8Span (absl::MakeConstSpan (temp_wb.bit_buffer ()));
126130}
127131
128- absl::Status ReadRenderingConfigParamDefinitions (
129- ReadBitBuffer& rb, std::vector<RenderingConfigParamDefinition>&
130- output_rendering_config_param_definitions) {
132+ absl::Status ReadRenderingConfigExtension (
133+ bool element_gain_offset_flag, ReadBitBuffer& rb,
134+ std::vector<RenderingConfigParamDefinition>&
135+ output_rendering_config_param_definitions,
136+ std::optional<ElementGainOffsetConfig>& output_element_gain_offset_config) {
131137 DecodedUleb128 num_params;
132138 RETURN_IF_NOT_OK (rb.ReadULeb128 (num_params));
133- if (num_params == 0 ) {
134- return absl::InvalidArgumentError (
135- " Expected at least one rendering config param definition, but got 0." );
136- }
137139 for (int i = 0 ; i < num_params; ++i) {
138140 auto rendering_config_param_definition =
139141 RenderingConfigParamDefinition::CreateFromBuffer (rb);
@@ -143,6 +145,17 @@ absl::Status ReadRenderingConfigParamDefinitions(
143145 output_rendering_config_param_definitions.push_back (
144146 std::move (*rendering_config_param_definition));
145147 }
148+
149+ if (element_gain_offset_flag) {
150+ auto read_element_gain_offset_config =
151+ ElementGainOffsetConfig::CreateFromBuffer (rb);
152+ if (!read_element_gain_offset_config.ok ()) {
153+ return read_element_gain_offset_config.status ();
154+ }
155+ output_element_gain_offset_config =
156+ *std::move (read_element_gain_offset_config);
157+ }
158+
146159 return absl::OkStatus ();
147160}
148161
@@ -233,8 +246,11 @@ absl::StatusOr<RenderingConfig> RenderingConfig::CreateFromBuffer(
233246 HeadphonesRenderingMode headphones_rendering_mode_enum =
234247 static_cast <HeadphonesRenderingMode>(headphones_rendering_mode);
235248
249+ bool element_gain_offset_flag;
250+ RETURN_IF_NOT_OK (rb.ReadBoolean (element_gain_offset_flag));
251+
236252 uint8_t reserved;
237- RETURN_IF_NOT_OK (rb.ReadUnsignedLiteral (6 , reserved));
253+ RETURN_IF_NOT_OK (rb.ReadUnsignedLiteral (5 , reserved));
238254 DecodedUleb128 rendering_config_extension_size;
239255 RETURN_IF_NOT_OK (rb.ReadULeb128 (rendering_config_extension_size));
240256 if (rendering_config_extension_size == 0 ) {
@@ -243,20 +259,21 @@ absl::StatusOr<RenderingConfig> RenderingConfig::CreateFromBuffer(
243259 .reserved = reserved};
244260 }
245261
246- // Some fields are absent in older profiles..
247- const auto position_before_reading_rendering_config_param_definitions =
248- rb. Tell ();
262+ const auto position_after_rendering_config_extension_size = rb. Tell ();
263+ // Read in the well-defined fields. These are related to parameters, and
264+ // (optionally), the element gain offset config.
249265 std::vector<RenderingConfigParamDefinition>
250266 rendering_config_param_definitions;
251- auto status = ReadRenderingConfigParamDefinitions (
252- rb, rendering_config_param_definitions);
267+ std::optional<ElementGainOffsetConfig> element_gain_offset_config;
268+ auto status = ReadRenderingConfigExtension (element_gain_offset_flag, rb,
269+ rendering_config_param_definitions,
270+ element_gain_offset_config);
271+
253272 int64_t extension_bytes_to_read = rendering_config_extension_size;
254273 if (status.ok ()) {
255274 extension_bytes_to_read =
256275 rendering_config_extension_size -
257- ((rb.Tell () -
258- position_before_reading_rendering_config_param_definitions) /
259- 8 );
276+ ((rb.Tell () - position_after_rendering_config_extension_size) / 8 );
260277 if (extension_bytes_to_read < 0 ) {
261278 return absl::InvalidArgumentError (absl::StrCat (
262279 " Expected `rendering_config_extension_size` to be greater than or "
@@ -265,11 +282,12 @@ absl::StatusOr<RenderingConfig> RenderingConfig::CreateFromBuffer(
265282 extension_bytes_to_read));
266283 }
267284 } else {
268- // Failed to read param definitions, so seek back to the position before
269- // reading the param definitions so we can read these bytes as extension
270- // bytes instead.
271- RETURN_IF_NOT_OK (
272- rb.Seek (position_before_reading_rendering_config_param_definitions));
285+ rendering_config_param_definitions.clear ();
286+ element_gain_offset_config = std::nullopt ;
287+ // Failed to read extension, so seek back to the position before reading the
288+ // extension size so we can read these bytes as generic extension bytes
289+ // instead.
290+ RETURN_IF_NOT_OK (rb.Seek (position_after_rendering_config_extension_size));
273291 }
274292 std::vector<uint8_t > rendering_config_extension_bytes (
275293 extension_bytes_to_read);
@@ -280,25 +298,30 @@ absl::StatusOr<RenderingConfig> RenderingConfig::CreateFromBuffer(
280298 .reserved = reserved,
281299 .rendering_config_param_definitions =
282300 std::move (rendering_config_param_definitions),
301+ .element_gain_offset_config = element_gain_offset_config,
283302 .rendering_config_extension_bytes =
284303 std::move (rendering_config_extension_bytes)};
285304}
286305
287306absl::Status RenderingConfig::ValidateAndWrite (WriteBitBuffer& wb) const {
288307 RETURN_IF_NOT_OK (wb.WriteUnsignedLiteral (
289308 static_cast <uint8_t >(headphones_rendering_mode), 2 ));
290- RETURN_IF_NOT_OK (wb.WriteUnsignedLiteral (static_cast <uint8_t >(reserved), 6 ));
309+ const bool element_gain_offset_flag = element_gain_offset_config.has_value ();
310+ RETURN_IF_NOT_OK (wb.WriteBoolean (element_gain_offset_flag));
311+ RETURN_IF_NOT_OK (wb.WriteUnsignedLiteral (static_cast <uint8_t >(reserved), 5 ));
291312
292313 if (rendering_config_param_definitions.empty () &&
314+ !element_gain_offset_config.has_value () &&
293315 rendering_config_extension_bytes.empty ()) {
294316 // TODO(b/468358730): Check if we can remove this branch, without breaking
295317 // compatibility.
296- // Older profiles had no rendering config param definitions . For maximum
318+ // Older profiles had nothing in the rendering config extension . For maximum
297319 // backwards compatibility, if both extensions are empty. Write an empty
298320 // `rendering_config_extension_size`.
299321 return wb.WriteUleb128 (0 );
300322 } else {
301323 return WriteRenderingConfigExtension (rendering_config_param_definitions,
324+ element_gain_offset_config,
302325 rendering_config_extension_bytes, wb);
303326 }
304327}
0 commit comments