2 * Immersive Audio Model and Formats helper functions and defines
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 #define IAMF_ADD_FUNC_TEMPLATE(parent_type, parent_name, child_type, child_name, suffix) \
33 child_type *av_iamf_ ## parent_name ## _add_ ## child_name(parent_type *parent_name) \
35 child_type **child_name ## suffix, *child_name; \
37 if (parent_name->nb_## child_name ## suffix == UINT_MAX) \
40 child_name ## suffix = av_realloc_array(parent_name->child_name ## suffix, \
41 parent_name->nb_## child_name ## suffix + 1, \
42 sizeof(*parent_name->child_name ## suffix)); \
43 if (!child_name ## suffix) \
46 parent_name->child_name ## suffix = child_name ## suffix; \
48 child_name = parent_name->child_name ## suffix[parent_name->nb_## child_name ## suffix] \
49 = av_mallocz(sizeof(*child_name)); \
53 child_name->av_class = &child_name ## _class; \
54 av_opt_set_defaults(child_name); \
55 parent_name->nb_## child_name ## suffix++; \
60 #define FLAGS AV_OPT_FLAG_ENCODING_PARAM
65 #define OFFSET(x) offsetof(AVIAMFMixGain, x)
66 static const AVOption mix_gain_options
[] = {
67 { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration
), AV_OPT_TYPE_UINT
, {.i64
= 1 }, 1, UINT_MAX
, FLAGS
},
68 { "animation_type", "set animation_type", OFFSET(animation_type
), AV_OPT_TYPE_UINT
, {.i64
= 0 }, 0, 2, FLAGS
},
69 { "start_point_value", "set start_point_value", OFFSET(start_point_value
), AV_OPT_TYPE_RATIONAL
, {.dbl
= 0 }, -128.0, 128.0, FLAGS
},
70 { "end_point_value", "set end_point_value", OFFSET(end_point_value
), AV_OPT_TYPE_RATIONAL
, {.dbl
= 0 }, -128.0, 128.0, FLAGS
},
71 { "control_point_value", "set control_point_value", OFFSET(control_point_value
), AV_OPT_TYPE_RATIONAL
, {.dbl
= 0 }, -128.0, 128.0, FLAGS
},
72 { "control_point_relative_time", "set control_point_relative_time", OFFSET(control_point_relative_time
), AV_OPT_TYPE_RATIONAL
, {.dbl
= 0 }, 0.0, 1.0, FLAGS
},
76 static const AVClass mix_gain_class
= {
77 .class_name
= "AVIAMFMixGain",
78 .item_name
= av_default_item_name
,
79 .version
= LIBAVUTIL_VERSION_INT
,
80 .option
= mix_gain_options
,
84 #define OFFSET(x) offsetof(AVIAMFDemixingInfo, x)
85 static const AVOption demixing_info_options
[] = {
86 { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration
), AV_OPT_TYPE_UINT
, {.i64
= 1 }, 1, UINT_MAX
, FLAGS
},
87 { "dmixp_mode", "set dmixp_mode", OFFSET(dmixp_mode
), AV_OPT_TYPE_UINT
, {.i64
= 0 }, 0, 6, FLAGS
},
91 static const AVClass demixing_info_class
= {
92 .class_name
= "AVIAMFDemixingInfo",
93 .item_name
= av_default_item_name
,
94 .version
= LIBAVUTIL_VERSION_INT
,
95 .option
= demixing_info_options
,
99 #define OFFSET(x) offsetof(AVIAMFReconGain, x)
100 static const AVOption recon_gain_options
[] = {
101 { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration
), AV_OPT_TYPE_UINT
, {.i64
= 1 }, 1, UINT_MAX
, FLAGS
},
105 static const AVClass recon_gain_class
= {
106 .class_name
= "AVIAMFReconGain",
107 .item_name
= av_default_item_name
,
108 .version
= LIBAVUTIL_VERSION_INT
,
109 .option
= recon_gain_options
,
113 #define OFFSET(x) offsetof(AVIAMFParamDefinition, x)
114 static const AVOption param_definition_options
[] = {
115 { "parameter_id", "set parameter_id", OFFSET(parameter_id
), AV_OPT_TYPE_UINT
, {.i64
= 0 }, 0, UINT_MAX
, FLAGS
},
116 { "parameter_rate", "set parameter_rate", OFFSET(parameter_rate
), AV_OPT_TYPE_UINT
, {.i64
= 0 }, 0, UINT_MAX
, FLAGS
},
117 { "duration", "set duration", OFFSET(duration
), AV_OPT_TYPE_UINT
, {.i64
= 0 }, 0, UINT_MAX
, FLAGS
},
118 { "constant_subblock_duration", "set constant_subblock_duration", OFFSET(constant_subblock_duration
), AV_OPT_TYPE_UINT
, {.i64
= 0 }, 0, UINT_MAX
, FLAGS
},
122 static const AVClass
*param_definition_child_iterate(void **opaque
)
124 uintptr_t i
= (uintptr_t)*opaque
;
125 const AVClass
*ret
= NULL
;
128 case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN
:
129 ret
= &mix_gain_class
;
131 case AV_IAMF_PARAMETER_DEFINITION_DEMIXING
:
132 ret
= &demixing_info_class
;
134 case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN
:
135 ret
= &recon_gain_class
;
142 *opaque
= (void*)(i
+ 1);
146 static const AVClass param_definition_class
= {
147 .class_name
= "AVIAMFParamDefinition",
148 .item_name
= av_default_item_name
,
149 .version
= LIBAVUTIL_VERSION_INT
,
150 .option
= param_definition_options
,
151 .child_class_iterate
= param_definition_child_iterate
,
154 const AVClass
*av_iamf_param_definition_get_class(void)
156 return ¶m_definition_class
;
159 AVIAMFParamDefinition
*av_iamf_param_definition_alloc(enum AVIAMFParamDefinitionType type
,
160 unsigned int nb_subblocks
, size_t *out_size
)
163 struct MixGainStruct
{
164 AVIAMFParamDefinition p
;
168 AVIAMFParamDefinition p
;
169 AVIAMFDemixingInfo d
;
171 struct ReconGainStruct
{
172 AVIAMFParamDefinition p
;
175 size_t subblocks_offset
, subblock_size
;
177 AVIAMFParamDefinition
*par
;
180 case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN
:
181 subblocks_offset
= offsetof(struct MixGainStruct
, m
);
182 subblock_size
= sizeof(AVIAMFMixGain
);
184 case AV_IAMF_PARAMETER_DEFINITION_DEMIXING
:
185 subblocks_offset
= offsetof(struct DemixStruct
, d
);
186 subblock_size
= sizeof(AVIAMFDemixingInfo
);
188 case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN
:
189 subblocks_offset
= offsetof(struct ReconGainStruct
, r
);
190 subblock_size
= sizeof(AVIAMFReconGain
);
196 size
= subblocks_offset
;
197 if (nb_subblocks
> (SIZE_MAX
- size
) / subblock_size
)
199 size
+= subblock_size
* nb_subblocks
;
201 par
= av_mallocz(size
);
205 par
->av_class
= ¶m_definition_class
;
206 av_opt_set_defaults(par
);
209 par
->nb_subblocks
= nb_subblocks
;
210 par
->subblock_size
= subblock_size
;
211 par
->subblocks_offset
= subblocks_offset
;
213 for (int i
= 0; i
< nb_subblocks
; i
++) {
214 void *subblock
= av_iamf_param_definition_get_subblock(par
, i
);
217 case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN
:
218 ((AVIAMFMixGain
*)subblock
)->av_class
= &mix_gain_class
;
220 case AV_IAMF_PARAMETER_DEFINITION_DEMIXING
:
221 ((AVIAMFDemixingInfo
*)subblock
)->av_class
= &demixing_info_class
;
223 case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN
:
224 ((AVIAMFReconGain
*)subblock
)->av_class
= &recon_gain_class
;
230 av_opt_set_defaults(subblock
);
243 #define OFFSET(x) offsetof(AVIAMFLayer, x)
244 static const AVOption layer_options
[] = {
245 { "ch_layout", "set ch_layout", OFFSET(ch_layout
), AV_OPT_TYPE_CHLAYOUT
, {.str
= NULL
}, 0, 0, FLAGS
},
246 { "flags", "set flags", OFFSET(flags
), AV_OPT_TYPE_FLAGS
,
247 {.i64
= 0 }, 0, AV_IAMF_LAYER_FLAG_RECON_GAIN
, FLAGS
, .unit
= "flags" },
248 {"recon_gain", "Recon gain is present", 0, AV_OPT_TYPE_CONST
,
249 {.i64
= AV_IAMF_LAYER_FLAG_RECON_GAIN
}, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "flags"},
250 { "output_gain_flags", "set output_gain_flags", OFFSET(output_gain_flags
), AV_OPT_TYPE_FLAGS
,
251 {.i64
= 0 }, 0, (1 << 6) - 1, FLAGS
, .unit
= "output_gain_flags" },
252 {"FL", "Left channel", 0, AV_OPT_TYPE_CONST
,
253 {.i64
= 1 << 5 }, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "output_gain_flags"},
254 {"FR", "Right channel", 0, AV_OPT_TYPE_CONST
,
255 {.i64
= 1 << 4 }, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "output_gain_flags"},
256 {"BL", "Left surround channel", 0, AV_OPT_TYPE_CONST
,
257 {.i64
= 1 << 3 }, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "output_gain_flags"},
258 {"BR", "Right surround channel", 0, AV_OPT_TYPE_CONST
,
259 {.i64
= 1 << 2 }, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "output_gain_flags"},
260 {"TFL", "Left top front channel", 0, AV_OPT_TYPE_CONST
,
261 {.i64
= 1 << 1 }, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "output_gain_flags"},
262 {"TFR", "Right top front channel", 0, AV_OPT_TYPE_CONST
,
263 {.i64
= 1 << 0 }, INT_MIN
, INT_MAX
, FLAGS
, .unit
= "output_gain_flags"},
264 { "output_gain", "set output_gain", OFFSET(output_gain
), AV_OPT_TYPE_RATIONAL
, { .dbl
= 0 }, -128.0, 128.0, FLAGS
},
265 { "ambisonics_mode", "set ambisonics_mode", OFFSET(ambisonics_mode
), AV_OPT_TYPE_INT
,
266 { .i64
= AV_IAMF_AMBISONICS_MODE_MONO
},
267 AV_IAMF_AMBISONICS_MODE_MONO
, AV_IAMF_AMBISONICS_MODE_PROJECTION
, FLAGS
, .unit
= "ambisonics_mode" },
268 { "mono", NULL
, 0, AV_OPT_TYPE_CONST
,
269 { .i64
= AV_IAMF_AMBISONICS_MODE_MONO
}, .unit
= "ambisonics_mode" },
270 { "projection", NULL
, 0, AV_OPT_TYPE_CONST
,
271 { .i64
= AV_IAMF_AMBISONICS_MODE_PROJECTION
}, .unit
= "ambisonics_mode" },
275 static const AVClass layer_class
= {
276 .class_name
= "AVIAMFLayer",
277 .item_name
= av_default_item_name
,
278 .version
= LIBAVUTIL_VERSION_INT
,
279 .option
= layer_options
,
283 #define OFFSET(x) offsetof(AVIAMFAudioElement, x)
284 static const AVOption audio_element_options
[] = {
285 { "audio_element_type", "set audio_element_type", OFFSET(audio_element_type
), AV_OPT_TYPE_INT
,
286 {.i64
= AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL
},
287 AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL
, AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE
, FLAGS
, .unit
= "audio_element_type" },
288 { "channel", NULL
, 0, AV_OPT_TYPE_CONST
,
289 { .i64
= AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL
}, .unit
= "audio_element_type" },
290 { "scene", NULL
, 0, AV_OPT_TYPE_CONST
,
291 { .i64
= AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE
}, .unit
= "audio_element_type" },
292 { "default_w", "set default_w", OFFSET(default_w
), AV_OPT_TYPE_UINT
, {.i64
= 0 }, 0, 10, FLAGS
},
296 static const AVClass
*audio_element_child_iterate(void **opaque
)
298 uintptr_t i
= (uintptr_t)*opaque
;
299 const AVClass
*ret
= NULL
;
305 *opaque
= (void*)(i
+ 1);
309 static const AVClass audio_element_class
= {
310 .class_name
= "AVIAMFAudioElement",
311 .item_name
= av_default_item_name
,
312 .version
= LIBAVUTIL_VERSION_INT
,
313 .option
= audio_element_options
,
314 .child_class_iterate
= audio_element_child_iterate
,
317 const AVClass
*av_iamf_audio_element_get_class(void)
319 return &audio_element_class
;
322 AVIAMFAudioElement
*av_iamf_audio_element_alloc(void)
324 AVIAMFAudioElement
*audio_element
= av_mallocz(sizeof(*audio_element
));
327 audio_element
->av_class
= &audio_element_class
;
328 av_opt_set_defaults(audio_element
);
331 return audio_element
;
334 IAMF_ADD_FUNC_TEMPLATE(AVIAMFAudioElement
, audio_element
, AVIAMFLayer
, layer
, s
)
336 void av_iamf_audio_element_free(AVIAMFAudioElement
**paudio_element
)
338 AVIAMFAudioElement
*audio_element
= *paudio_element
;
343 for (int i
= 0; i
< audio_element
->nb_layers
; i
++) {
344 AVIAMFLayer
*layer
= audio_element
->layers
[i
];
346 av_free(layer
->demixing_matrix
);
349 av_free(audio_element
->layers
);
351 av_free(audio_element
->demixing_info
);
352 av_free(audio_element
->recon_gain_info
);
353 av_freep(paudio_element
);
360 #define OFFSET(x) offsetof(AVIAMFSubmixElement, x)
361 static const AVOption submix_element_options
[] = {
362 { "headphones_rendering_mode", "Headphones rendering mode", OFFSET(headphones_rendering_mode
), AV_OPT_TYPE_INT
,
363 { .i64
= AV_IAMF_HEADPHONES_MODE_STEREO
},
364 AV_IAMF_HEADPHONES_MODE_STEREO
, AV_IAMF_HEADPHONES_MODE_BINAURAL
, FLAGS
, .unit
= "headphones_rendering_mode" },
365 { "stereo", NULL
, 0, AV_OPT_TYPE_CONST
,
366 { .i64
= AV_IAMF_HEADPHONES_MODE_STEREO
}, .unit
= "headphones_rendering_mode" },
367 { "binaural", NULL
, 0, AV_OPT_TYPE_CONST
,
368 { .i64
= AV_IAMF_HEADPHONES_MODE_BINAURAL
}, .unit
= "headphones_rendering_mode" },
369 { "default_mix_gain", "Default mix gain", OFFSET(default_mix_gain
), AV_OPT_TYPE_RATIONAL
, { .dbl
= 0 }, -128.0, 128.0, FLAGS
},
370 { "annotations", "Annotations", OFFSET(annotations
), AV_OPT_TYPE_DICT
, { .str
= NULL
}, 0, 0, FLAGS
},
374 static void *submix_element_child_next(void *obj
, void *prev
)
376 AVIAMFSubmixElement
*submix_element
= obj
;
378 return submix_element
->element_mix_config
;
383 static const AVClass
*submix_element_child_iterate(void **opaque
)
385 uintptr_t i
= (uintptr_t)*opaque
;
386 const AVClass
*ret
= NULL
;
389 ret
= ¶m_definition_class
;
392 *opaque
= (void*)(i
+ 1);
396 static const AVClass element_class
= {
397 .class_name
= "AVIAMFSubmixElement",
398 .item_name
= av_default_item_name
,
399 .version
= LIBAVUTIL_VERSION_INT
,
400 .option
= submix_element_options
,
401 .child_next
= submix_element_child_next
,
402 .child_class_iterate
= submix_element_child_iterate
,
405 IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix
, submix
, AVIAMFSubmixElement
, element
, s
)
408 #define OFFSET(x) offsetof(AVIAMFSubmixLayout, x)
409 static const AVOption submix_layout_options
[] = {
410 { "layout_type", "Layout type", OFFSET(layout_type
), AV_OPT_TYPE_INT
,
411 { .i64
= AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS
},
412 AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS
, AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL
, FLAGS
, .unit
= "layout_type" },
413 { "loudspeakers", NULL
, 0, AV_OPT_TYPE_CONST
,
414 { .i64
= AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS
}, .unit
= "layout_type" },
415 { "binaural", NULL
, 0, AV_OPT_TYPE_CONST
,
416 { .i64
= AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL
}, .unit
= "layout_type" },
417 { "sound_system", "Sound System", OFFSET(sound_system
), AV_OPT_TYPE_CHLAYOUT
, { .str
= NULL
}, 0, 0, FLAGS
},
418 { "integrated_loudness", "Integrated loudness", OFFSET(integrated_loudness
), AV_OPT_TYPE_RATIONAL
, { .dbl
= 0 }, -128.0, 128.0, FLAGS
},
419 { "digital_peak", "Digital peak", OFFSET(digital_peak
), AV_OPT_TYPE_RATIONAL
, { .dbl
= 0 }, -128.0, 128.0, FLAGS
},
420 { "true_peak", "True peak", OFFSET(true_peak
), AV_OPT_TYPE_RATIONAL
, { .dbl
= 0 }, -128.0, 128.0, FLAGS
},
421 { "dialog_anchored_loudness", "Anchored loudness (Dialog)", OFFSET(dialogue_anchored_loudness
), AV_OPT_TYPE_RATIONAL
, { .dbl
= 0 }, -128.0, 128.0, FLAGS
},
422 { "album_anchored_loudness", "Anchored loudness (Album)", OFFSET(album_anchored_loudness
), AV_OPT_TYPE_RATIONAL
, { .dbl
= 0 }, -128.0, 128.0, FLAGS
},
426 static const AVClass layout_class
= {
427 .class_name
= "AVIAMFSubmixLayout",
428 .item_name
= av_default_item_name
,
429 .version
= LIBAVUTIL_VERSION_INT
,
430 .option
= submix_layout_options
,
433 IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix
, submix
, AVIAMFSubmixLayout
, layout
, s
)
436 #define OFFSET(x) offsetof(AVIAMFSubmix, x)
437 static const AVOption submix_presentation_options
[] = {
438 { "default_mix_gain", "Default mix gain", OFFSET(default_mix_gain
), AV_OPT_TYPE_RATIONAL
, { .dbl
= 0 }, -128.0, 128.0, FLAGS
},
442 static void *submix_presentation_child_next(void *obj
, void *prev
)
444 AVIAMFSubmix
*sub_mix
= obj
;
446 return sub_mix
->output_mix_config
;
451 static const AVClass
*submix_presentation_child_iterate(void **opaque
)
453 uintptr_t i
= (uintptr_t)*opaque
;
454 const AVClass
*ret
= NULL
;
458 ret
= &element_class
;
464 ret
= ¶m_definition_class
;
471 *opaque
= (void*)(i
+ 1);
475 static const AVClass submix_class
= {
476 .class_name
= "AVIAMFSubmix",
477 .item_name
= av_default_item_name
,
478 .version
= LIBAVUTIL_VERSION_INT
,
479 .option
= submix_presentation_options
,
480 .child_next
= submix_presentation_child_next
,
481 .child_class_iterate
= submix_presentation_child_iterate
,
485 #define OFFSET(x) offsetof(AVIAMFMixPresentation, x)
486 static const AVOption mix_presentation_options
[] = {
487 { "annotations", "set annotations", OFFSET(annotations
), AV_OPT_TYPE_DICT
, {.str
= NULL
}, 0, 0, FLAGS
},
494 static const AVClass
*mix_presentation_child_iterate(void **opaque
)
496 uintptr_t i
= (uintptr_t)*opaque
;
497 const AVClass
*ret
= NULL
;
503 *opaque
= (void*)(i
+ 1);
507 static const AVClass mix_presentation_class
= {
508 .class_name
= "AVIAMFMixPresentation",
509 .item_name
= av_default_item_name
,
510 .version
= LIBAVUTIL_VERSION_INT
,
511 .option
= mix_presentation_options
,
512 .child_class_iterate
= mix_presentation_child_iterate
,
515 const AVClass
*av_iamf_mix_presentation_get_class(void)
517 return &mix_presentation_class
;
520 AVIAMFMixPresentation
*av_iamf_mix_presentation_alloc(void)
522 AVIAMFMixPresentation
*mix_presentation
= av_mallocz(sizeof(*mix_presentation
));
524 if (mix_presentation
) {
525 mix_presentation
->av_class
= &mix_presentation_class
;
526 av_opt_set_defaults(mix_presentation
);
529 return mix_presentation
;
532 IAMF_ADD_FUNC_TEMPLATE(AVIAMFMixPresentation
, mix_presentation
, AVIAMFSubmix
, submix
, es
)
534 void av_iamf_mix_presentation_free(AVIAMFMixPresentation
**pmix_presentation
)
536 AVIAMFMixPresentation
*mix_presentation
= *pmix_presentation
;
538 if (!mix_presentation
)
541 for (int i
= 0; i
< mix_presentation
->nb_submixes
; i
++) {
542 AVIAMFSubmix
*sub_mix
= mix_presentation
->submixes
[i
];
543 for (int j
= 0; j
< sub_mix
->nb_elements
; j
++) {
544 AVIAMFSubmixElement
*submix_element
= sub_mix
->elements
[j
];
545 av_opt_free(submix_element
);
546 av_free(submix_element
->element_mix_config
);
547 av_free(submix_element
);
549 av_free(sub_mix
->elements
);
550 for (int j
= 0; j
< sub_mix
->nb_layouts
; j
++) {
551 AVIAMFSubmixLayout
*submix_layout
= sub_mix
->layouts
[j
];
552 av_opt_free(submix_layout
);
553 av_free(submix_layout
);
555 av_free(sub_mix
->layouts
);
556 av_free(sub_mix
->output_mix_config
);
559 av_opt_free(mix_presentation
);
560 av_free(mix_presentation
->submixes
);
562 av_freep(pmix_presentation
);