Coverage Report

Created: 2026-03-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavutil/iamf.c
Line
Count
Source
1
/*
2
 * Immersive Audio Model and Formats helper functions and defines
3
 *
4
 * This file is part of FFmpeg.
5
 *
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.
10
 *
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.
15
 *
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
19
 */
20
21
#include <limits.h>
22
#include <stddef.h>
23
#include <stdint.h>
24
25
#include "avassert.h"
26
#include "error.h"
27
#include "iamf.h"
28
#include "log.h"
29
#include "mem.h"
30
#include "opt.h"
31
32
#define IAMF_ADD_FUNC_TEMPLATE(parent_type, parent_name, child_type, child_name, suffix)                   \
33
0
child_type *av_iamf_ ## parent_name ## _add_ ## child_name(parent_type *parent_name)                       \
34
0
{                                                                                                          \
35
0
    child_type **child_name ## suffix, *child_name;                                                        \
36
0
                                                                                                           \
37
0
    if (parent_name->nb_## child_name ## suffix == UINT_MAX)                                               \
38
0
        return NULL;                                                                                       \
39
0
                                                                                                           \
40
0
    child_name ## suffix = av_realloc_array(parent_name->child_name ## suffix,                             \
41
0
                                            parent_name->nb_## child_name ## suffix + 1,                   \
42
0
                                            sizeof(*parent_name->child_name ## suffix));                   \
43
0
    if (!child_name ## suffix)                                                                             \
44
0
        return NULL;                                                                                       \
45
0
                                                                                                           \
46
0
    parent_name->child_name ## suffix = child_name ## suffix;                                              \
47
0
                                                                                                           \
48
0
    child_name = parent_name->child_name ## suffix[parent_name->nb_## child_name ## suffix]                \
49
0
               = av_mallocz(sizeof(*child_name));                                                          \
50
0
    if (!child_name)                                                                                       \
51
0
        return NULL;                                                                                       \
52
0
                                                                                                           \
53
0
    child_name->av_class = &child_name ## _class;                                                          \
54
0
    av_opt_set_defaults(child_name);                                                                       \
55
0
    parent_name->nb_## child_name ## suffix++;                                                             \
56
0
                                                                                                           \
57
0
    return child_name;                                                                                     \
58
0
}
59
60
#define FLAGS AV_OPT_FLAG_ENCODING_PARAM
61
62
//
63
// Param Definition
64
//
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 },
73
    { NULL },
74
};
75
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,
81
};
82
83
#undef OFFSET
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 },
88
    { NULL },
89
};
90
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,
96
};
97
98
#undef OFFSET
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 },
102
    { NULL },
103
};
104
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,
110
};
111
112
#undef OFFSET
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 },
119
    { NULL },
120
};
121
122
static const AVClass *param_definition_child_iterate(void **opaque)
123
0
{
124
0
    uintptr_t i = (uintptr_t)*opaque;
125
0
    const AVClass *ret = NULL;
126
127
0
    switch(i) {
128
0
    case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN:
129
0
        ret = &mix_gain_class;
130
0
        break;
131
0
    case AV_IAMF_PARAMETER_DEFINITION_DEMIXING:
132
0
        ret = &demixing_info_class;
133
0
        break;
134
0
    case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN:
135
0
        ret = &recon_gain_class;
136
0
        break;
137
0
    default:
138
0
        break;
139
0
    }
140
141
0
    if (ret)
142
0
        *opaque = (void*)(i + 1);
143
0
    return ret;
144
0
}
145
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,
152
};
153
154
const AVClass *av_iamf_param_definition_get_class(void)
155
0
{
156
0
    return &param_definition_class;
157
0
}
158
159
AVIAMFParamDefinition *av_iamf_param_definition_alloc(enum AVIAMFParamDefinitionType type,
160
                                                      unsigned int nb_subblocks, size_t *out_size)
161
0
{
162
163
0
    struct MixGainStruct {
164
0
        AVIAMFParamDefinition p;
165
0
        AVIAMFMixGain m;
166
0
    };
167
0
    struct DemixStruct {
168
0
        AVIAMFParamDefinition p;
169
0
        AVIAMFDemixingInfo d;
170
0
    };
171
0
    struct ReconGainStruct {
172
0
        AVIAMFParamDefinition p;
173
0
        AVIAMFReconGain r;
174
0
    };
175
0
    size_t subblocks_offset, subblock_size;
176
0
    size_t size;
177
0
    AVIAMFParamDefinition *par;
178
179
0
    switch (type) {
180
0
    case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN:
181
0
        subblocks_offset = offsetof(struct MixGainStruct, m);
182
0
        subblock_size = sizeof(AVIAMFMixGain);
183
0
        break;
184
0
    case AV_IAMF_PARAMETER_DEFINITION_DEMIXING:
185
0
        subblocks_offset = offsetof(struct DemixStruct, d);
186
0
        subblock_size = sizeof(AVIAMFDemixingInfo);
187
0
        break;
188
0
    case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN:
189
0
        subblocks_offset = offsetof(struct ReconGainStruct, r);
190
0
        subblock_size = sizeof(AVIAMFReconGain);
191
0
        break;
192
0
    default:
193
0
        return NULL;
194
0
    }
195
196
0
    size = subblocks_offset;
197
0
    if (nb_subblocks > (SIZE_MAX - size) / subblock_size)
198
0
        return NULL;
199
0
    size += subblock_size * nb_subblocks;
200
201
0
    par = av_mallocz(size);
202
0
    if (!par)
203
0
        return NULL;
204
205
0
    par->av_class = &param_definition_class;
206
0
    av_opt_set_defaults(par);
207
208
0
    par->type = type;
209
0
    par->nb_subblocks = nb_subblocks;
210
0
    par->subblock_size = subblock_size;
211
0
    par->subblocks_offset = subblocks_offset;
212
213
0
    for (int i = 0; i < nb_subblocks; i++) {
214
0
        void *subblock = av_iamf_param_definition_get_subblock(par, i);
215
216
0
        switch (type) {
217
0
        case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN:
218
0
            ((AVIAMFMixGain *)subblock)->av_class = &mix_gain_class;
219
0
            break;
220
0
        case AV_IAMF_PARAMETER_DEFINITION_DEMIXING:
221
0
            ((AVIAMFDemixingInfo *)subblock)->av_class = &demixing_info_class;
222
0
            break;
223
0
        case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN:
224
0
            ((AVIAMFReconGain *)subblock)->av_class = &recon_gain_class;
225
0
            break;
226
0
        default:
227
0
            av_assert0(0);
228
0
        }
229
0
    }
230
231
0
    if (out_size)
232
0
        *out_size = size;
233
234
0
    return par;
235
0
}
236
237
//
238
// Audio Element
239
//
240
static const AVOptionArrayDef demixing_matrix_def = { .size_max = (255 + 255) * 255, .sep = '|' };
241
242
#undef OFFSET
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" },
272
    { "demixing_matrix", "set demixing_matrix", OFFSET(demixing_matrix), AV_OPT_TYPE_RATIONAL | AV_OPT_TYPE_FLAG_ARRAY,
273
            { .arr = &demixing_matrix_def }, -1.0, 1.0, FLAGS },
274
    { NULL },
275
};
276
277
static const AVClass layer_class = {
278
    .class_name     = "AVIAMFLayer",
279
    .item_name      = av_default_item_name,
280
    .version        = LIBAVUTIL_VERSION_INT,
281
    .option         = layer_options,
282
};
283
284
#undef OFFSET
285
#define OFFSET(x) offsetof(AVIAMFAudioElement, x)
286
static const AVOption audio_element_options[] = {
287
    { "audio_element_type", "set audio_element_type", OFFSET(audio_element_type), AV_OPT_TYPE_INT,
288
            {.i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL },
289
            AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL, AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE, FLAGS, .unit = "audio_element_type" },
290
        { "channel", NULL, 0, AV_OPT_TYPE_CONST,
291
                   { .i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL }, .unit = "audio_element_type" },
292
        { "scene",   NULL, 0, AV_OPT_TYPE_CONST,
293
                   { .i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE },   .unit = "audio_element_type" },
294
    { "default_w", "set default_w", OFFSET(default_w), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, 10, FLAGS },
295
    { NULL },
296
};
297
298
static const AVClass *audio_element_child_iterate(void **opaque)
299
0
{
300
0
    uintptr_t i = (uintptr_t)*opaque;
301
0
    const AVClass *ret = NULL;
302
303
0
    if (i)
304
0
        ret = &layer_class;
305
306
0
    if (ret)
307
0
        *opaque = (void*)(i + 1);
308
0
    return ret;
309
0
}
310
311
static const AVClass audio_element_class = {
312
    .class_name          = "AVIAMFAudioElement",
313
    .item_name           = av_default_item_name,
314
    .version             = LIBAVUTIL_VERSION_INT,
315
    .option              = audio_element_options,
316
    .child_class_iterate = audio_element_child_iterate,
317
};
318
319
const AVClass *av_iamf_audio_element_get_class(void)
320
0
{
321
0
    return &audio_element_class;
322
0
}
323
324
AVIAMFAudioElement *av_iamf_audio_element_alloc(void)
325
0
{
326
0
    AVIAMFAudioElement *audio_element = av_mallocz(sizeof(*audio_element));
327
328
0
    if (audio_element) {
329
0
        audio_element->av_class = &audio_element_class;
330
0
        av_opt_set_defaults(audio_element);
331
0
    }
332
333
0
    return audio_element;
334
0
}
335
336
0
IAMF_ADD_FUNC_TEMPLATE(AVIAMFAudioElement, audio_element, AVIAMFLayer, layer, s)
337
338
void av_iamf_audio_element_free(AVIAMFAudioElement **paudio_element)
339
0
{
340
0
    AVIAMFAudioElement *audio_element = *paudio_element;
341
342
0
    if (!audio_element)
343
0
        return;
344
345
0
    for (int i = 0; i < audio_element->nb_layers; i++) {
346
0
        AVIAMFLayer *layer = audio_element->layers[i];
347
0
        av_opt_free(layer);
348
0
        av_free(layer->demixing_matrix);
349
0
        av_free(layer);
350
0
    }
351
0
    av_free(audio_element->layers);
352
353
0
    av_free(audio_element->demixing_info);
354
0
    av_free(audio_element->recon_gain_info);
355
0
    av_freep(paudio_element);
356
0
}
357
358
//
359
// Mix Presentation
360
//
361
#undef OFFSET
362
#define OFFSET(x) offsetof(AVIAMFSubmixElement, x)
363
static const AVOption submix_element_options[] = {
364
    { "headphones_rendering_mode", "Headphones rendering mode", OFFSET(headphones_rendering_mode), AV_OPT_TYPE_INT,
365
            { .i64 = AV_IAMF_HEADPHONES_MODE_STEREO },
366
            AV_IAMF_HEADPHONES_MODE_STEREO, AV_IAMF_HEADPHONES_MODE_BINAURAL, FLAGS, .unit = "headphones_rendering_mode" },
367
        { "stereo",   NULL, 0, AV_OPT_TYPE_CONST,
368
                   { .i64 = AV_IAMF_HEADPHONES_MODE_STEREO },   .unit = "headphones_rendering_mode" },
369
        { "binaural", NULL, 0, AV_OPT_TYPE_CONST,
370
                   { .i64 = AV_IAMF_HEADPHONES_MODE_BINAURAL }, .unit = "headphones_rendering_mode" },
371
    { "default_mix_gain", "Default mix gain", OFFSET(default_mix_gain), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
372
    { "annotations", "Annotations", OFFSET(annotations), AV_OPT_TYPE_DICT, { .str = NULL }, 0, 0, FLAGS },
373
    { NULL },
374
};
375
376
static void *submix_element_child_next(void *obj, void *prev)
377
0
{
378
0
    AVIAMFSubmixElement *submix_element = obj;
379
0
    if (!prev)
380
0
        return submix_element->element_mix_config;
381
382
0
    return NULL;
383
0
}
384
385
static const AVClass *submix_element_child_iterate(void **opaque)
386
0
{
387
0
    uintptr_t i = (uintptr_t)*opaque;
388
0
    const AVClass *ret = NULL;
389
390
0
    if (i)
391
0
        ret = &param_definition_class;
392
393
0
    if (ret)
394
0
        *opaque = (void*)(i + 1);
395
0
    return ret;
396
0
}
397
398
static const AVClass element_class = {
399
    .class_name          = "AVIAMFSubmixElement",
400
    .item_name           = av_default_item_name,
401
    .version             = LIBAVUTIL_VERSION_INT,
402
    .option              = submix_element_options,
403
    .child_next          = submix_element_child_next,
404
    .child_class_iterate = submix_element_child_iterate,
405
};
406
407
0
IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix, submix, AVIAMFSubmixElement, element, s)
408
409
#undef OFFSET
410
#define OFFSET(x) offsetof(AVIAMFSubmixLayout, x)
411
static const AVOption submix_layout_options[] = {
412
    { "layout_type", "Layout type", OFFSET(layout_type), AV_OPT_TYPE_INT,
413
            { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS },
414
            AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS, AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL, FLAGS, .unit = "layout_type" },
415
        { "loudspeakers", NULL, 0, AV_OPT_TYPE_CONST,
416
                   { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS }, .unit = "layout_type" },
417
        { "binaural",     NULL, 0, AV_OPT_TYPE_CONST,
418
                   { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL },     .unit = "layout_type" },
419
    { "sound_system", "Sound System", OFFSET(sound_system), AV_OPT_TYPE_CHLAYOUT, { .str = NULL }, 0, 0, FLAGS },
420
    { "integrated_loudness", "Integrated loudness", OFFSET(integrated_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
421
    { "digital_peak", "Digital peak", OFFSET(digital_peak), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
422
    { "true_peak", "True peak", OFFSET(true_peak), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
423
    { "dialog_anchored_loudness", "Anchored loudness (Dialog)", OFFSET(dialogue_anchored_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
424
    { "album_anchored_loudness", "Anchored loudness (Album)", OFFSET(album_anchored_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
425
    { NULL },
426
};
427
428
static const AVClass layout_class = {
429
    .class_name     = "AVIAMFSubmixLayout",
430
    .item_name      = av_default_item_name,
431
    .version        = LIBAVUTIL_VERSION_INT,
432
    .option         = submix_layout_options,
433
};
434
435
0
IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix, submix, AVIAMFSubmixLayout, layout, s)
436
437
#undef OFFSET
438
#define OFFSET(x) offsetof(AVIAMFSubmix, x)
439
static const AVOption submix_presentation_options[] = {
440
    { "default_mix_gain", "Default mix gain", OFFSET(default_mix_gain), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
441
    { NULL },
442
};
443
444
static void *submix_presentation_child_next(void *obj, void *prev)
445
0
{
446
0
    AVIAMFSubmix *sub_mix = obj;
447
0
    if (!prev)
448
0
        return sub_mix->output_mix_config;
449
450
0
    return NULL;
451
0
}
452
453
static const AVClass *submix_presentation_child_iterate(void **opaque)
454
0
{
455
0
    uintptr_t i = (uintptr_t)*opaque;
456
0
    const AVClass *ret = NULL;
457
458
0
    switch(i) {
459
0
    case 0:
460
0
        ret = &element_class;
461
0
        break;
462
0
    case 1:
463
0
        ret = &layout_class;
464
0
        break;
465
0
    case 2:
466
0
        ret = &param_definition_class;
467
0
        break;
468
0
    default:
469
0
        break;
470
0
    }
471
472
0
    if (ret)
473
0
        *opaque = (void*)(i + 1);
474
0
    return ret;
475
0
}
476
477
static const AVClass submix_class = {
478
    .class_name          = "AVIAMFSubmix",
479
    .item_name           = av_default_item_name,
480
    .version             = LIBAVUTIL_VERSION_INT,
481
    .option              = submix_presentation_options,
482
    .child_next          = submix_presentation_child_next,
483
    .child_class_iterate = submix_presentation_child_iterate,
484
};
485
486
#undef OFFSET
487
#define OFFSET(x) offsetof(AVIAMFMixPresentation, x)
488
static const AVOption mix_presentation_options[] = {
489
    { "annotations", "set annotations", OFFSET(annotations), AV_OPT_TYPE_DICT, {.str = NULL }, 0, 0, FLAGS },
490
    { NULL },
491
};
492
493
#undef OFFSET
494
#undef FLAGS
495
496
static const AVClass *mix_presentation_child_iterate(void **opaque)
497
0
{
498
0
    uintptr_t i = (uintptr_t)*opaque;
499
0
    const AVClass *ret = NULL;
500
501
0
    if (i)
502
0
        ret = &submix_class;
503
504
0
    if (ret)
505
0
        *opaque = (void*)(i + 1);
506
0
    return ret;
507
0
}
508
509
static const AVClass mix_presentation_class = {
510
    .class_name          = "AVIAMFMixPresentation",
511
    .item_name           = av_default_item_name,
512
    .version             = LIBAVUTIL_VERSION_INT,
513
    .option              = mix_presentation_options,
514
    .child_class_iterate = mix_presentation_child_iterate,
515
};
516
517
const AVClass *av_iamf_mix_presentation_get_class(void)
518
0
{
519
0
    return &mix_presentation_class;
520
0
}
521
522
AVIAMFMixPresentation *av_iamf_mix_presentation_alloc(void)
523
0
{
524
0
    AVIAMFMixPresentation *mix_presentation = av_mallocz(sizeof(*mix_presentation));
525
526
0
    if (mix_presentation) {
527
0
        mix_presentation->av_class = &mix_presentation_class;
528
0
        av_opt_set_defaults(mix_presentation);
529
0
    }
530
531
0
    return mix_presentation;
532
0
}
533
534
0
IAMF_ADD_FUNC_TEMPLATE(AVIAMFMixPresentation, mix_presentation, AVIAMFSubmix, submix, es)
535
536
void av_iamf_mix_presentation_free(AVIAMFMixPresentation **pmix_presentation)
537
0
{
538
0
    AVIAMFMixPresentation *mix_presentation = *pmix_presentation;
539
540
0
    if (!mix_presentation)
541
0
        return;
542
543
0
    for (int i = 0; i < mix_presentation->nb_submixes; i++) {
544
0
        AVIAMFSubmix *sub_mix = mix_presentation->submixes[i];
545
0
        for (int j = 0; j < sub_mix->nb_elements; j++) {
546
0
            AVIAMFSubmixElement *submix_element = sub_mix->elements[j];
547
0
            av_opt_free(submix_element);
548
0
            av_free(submix_element->element_mix_config);
549
0
            av_free(submix_element);
550
0
        }
551
0
        av_free(sub_mix->elements);
552
0
        for (int j = 0; j < sub_mix->nb_layouts; j++) {
553
0
            AVIAMFSubmixLayout *submix_layout = sub_mix->layouts[j];
554
0
            av_opt_free(submix_layout);
555
0
            av_free(submix_layout);
556
0
        }
557
0
        av_free(sub_mix->layouts);
558
0
        av_free(sub_mix->output_mix_config);
559
0
        av_free(sub_mix);
560
0
    }
561
0
    av_opt_free(mix_presentation);
562
0
    av_free(mix_presentation->submixes);
563
564
0
    av_freep(pmix_presentation);
565
0
}