Coverage Report

Created: 2026-01-25 07:18

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
230
0
        av_opt_set_defaults(subblock);
231
0
    }
232
233
0
    if (out_size)
234
0
        *out_size = size;
235
236
0
    return par;
237
0
}
238
239
//
240
// Audio Element
241
//
242
static const AVOptionArrayDef demixing_matrix_def = { .size_max = (255 + 255) * 255, .sep = '|' };
243
244
#undef OFFSET
245
#define OFFSET(x) offsetof(AVIAMFLayer, x)
246
static const AVOption layer_options[] = {
247
    { "ch_layout", "set ch_layout", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str = NULL }, 0, 0, FLAGS },
248
    { "flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS,
249
        {.i64 = 0 }, 0, AV_IAMF_LAYER_FLAG_RECON_GAIN, FLAGS, .unit = "flags" },
250
            {"recon_gain",  "Recon gain is present", 0, AV_OPT_TYPE_CONST,
251
                {.i64 = AV_IAMF_LAYER_FLAG_RECON_GAIN }, INT_MIN, INT_MAX, FLAGS, .unit = "flags"},
252
    { "output_gain_flags", "set output_gain_flags", OFFSET(output_gain_flags), AV_OPT_TYPE_FLAGS,
253
        {.i64 = 0 }, 0, (1 << 6) - 1, FLAGS, .unit = "output_gain_flags" },
254
            {"FL",  "Left channel",            0, AV_OPT_TYPE_CONST,
255
                {.i64 = 1 << 5 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"},
256
            {"FR",  "Right channel",           0, AV_OPT_TYPE_CONST,
257
                {.i64 = 1 << 4 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"},
258
            {"BL",  "Left surround channel",   0, AV_OPT_TYPE_CONST,
259
                {.i64 = 1 << 3 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"},
260
            {"BR",  "Right surround channel",  0, AV_OPT_TYPE_CONST,
261
                {.i64 = 1 << 2 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"},
262
            {"TFL", "Left top front channel",  0, AV_OPT_TYPE_CONST,
263
                {.i64 = 1 << 1 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"},
264
            {"TFR", "Right top front channel", 0, AV_OPT_TYPE_CONST,
265
                {.i64 = 1 << 0 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"},
266
    { "output_gain", "set output_gain", OFFSET(output_gain), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
267
    { "ambisonics_mode", "set ambisonics_mode", OFFSET(ambisonics_mode), AV_OPT_TYPE_INT,
268
            { .i64 = AV_IAMF_AMBISONICS_MODE_MONO },
269
            AV_IAMF_AMBISONICS_MODE_MONO, AV_IAMF_AMBISONICS_MODE_PROJECTION, FLAGS, .unit = "ambisonics_mode" },
270
        { "mono",       NULL, 0, AV_OPT_TYPE_CONST,
271
                   { .i64 = AV_IAMF_AMBISONICS_MODE_MONO },       .unit = "ambisonics_mode" },
272
        { "projection", NULL, 0, AV_OPT_TYPE_CONST,
273
                   { .i64 = AV_IAMF_AMBISONICS_MODE_PROJECTION }, .unit = "ambisonics_mode" },
274
    { "demixing_matrix", "set demixing_matrix", OFFSET(demixing_matrix), AV_OPT_TYPE_RATIONAL | AV_OPT_TYPE_FLAG_ARRAY,
275
            { .arr = &demixing_matrix_def }, -1.0, 1.0, FLAGS },
276
    { NULL },
277
};
278
279
static const AVClass layer_class = {
280
    .class_name     = "AVIAMFLayer",
281
    .item_name      = av_default_item_name,
282
    .version        = LIBAVUTIL_VERSION_INT,
283
    .option         = layer_options,
284
};
285
286
#undef OFFSET
287
#define OFFSET(x) offsetof(AVIAMFAudioElement, x)
288
static const AVOption audio_element_options[] = {
289
    { "audio_element_type", "set audio_element_type", OFFSET(audio_element_type), AV_OPT_TYPE_INT,
290
            {.i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL },
291
            AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL, AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE, FLAGS, .unit = "audio_element_type" },
292
        { "channel", NULL, 0, AV_OPT_TYPE_CONST,
293
                   { .i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL }, .unit = "audio_element_type" },
294
        { "scene",   NULL, 0, AV_OPT_TYPE_CONST,
295
                   { .i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE },   .unit = "audio_element_type" },
296
    { "default_w", "set default_w", OFFSET(default_w), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, 10, FLAGS },
297
    { NULL },
298
};
299
300
static const AVClass *audio_element_child_iterate(void **opaque)
301
0
{
302
0
    uintptr_t i = (uintptr_t)*opaque;
303
0
    const AVClass *ret = NULL;
304
305
0
    if (i)
306
0
        ret = &layer_class;
307
308
0
    if (ret)
309
0
        *opaque = (void*)(i + 1);
310
0
    return ret;
311
0
}
312
313
static const AVClass audio_element_class = {
314
    .class_name          = "AVIAMFAudioElement",
315
    .item_name           = av_default_item_name,
316
    .version             = LIBAVUTIL_VERSION_INT,
317
    .option              = audio_element_options,
318
    .child_class_iterate = audio_element_child_iterate,
319
};
320
321
const AVClass *av_iamf_audio_element_get_class(void)
322
0
{
323
0
    return &audio_element_class;
324
0
}
325
326
AVIAMFAudioElement *av_iamf_audio_element_alloc(void)
327
0
{
328
0
    AVIAMFAudioElement *audio_element = av_mallocz(sizeof(*audio_element));
329
330
0
    if (audio_element) {
331
0
        audio_element->av_class = &audio_element_class;
332
0
        av_opt_set_defaults(audio_element);
333
0
    }
334
335
0
    return audio_element;
336
0
}
337
338
0
IAMF_ADD_FUNC_TEMPLATE(AVIAMFAudioElement, audio_element, AVIAMFLayer, layer, s)
339
340
void av_iamf_audio_element_free(AVIAMFAudioElement **paudio_element)
341
0
{
342
0
    AVIAMFAudioElement *audio_element = *paudio_element;
343
344
0
    if (!audio_element)
345
0
        return;
346
347
0
    for (int i = 0; i < audio_element->nb_layers; i++) {
348
0
        AVIAMFLayer *layer = audio_element->layers[i];
349
0
        av_opt_free(layer);
350
0
        av_free(layer->demixing_matrix);
351
0
        av_free(layer);
352
0
    }
353
0
    av_free(audio_element->layers);
354
355
0
    av_free(audio_element->demixing_info);
356
0
    av_free(audio_element->recon_gain_info);
357
0
    av_freep(paudio_element);
358
0
}
359
360
//
361
// Mix Presentation
362
//
363
#undef OFFSET
364
#define OFFSET(x) offsetof(AVIAMFSubmixElement, x)
365
static const AVOption submix_element_options[] = {
366
    { "headphones_rendering_mode", "Headphones rendering mode", OFFSET(headphones_rendering_mode), AV_OPT_TYPE_INT,
367
            { .i64 = AV_IAMF_HEADPHONES_MODE_STEREO },
368
            AV_IAMF_HEADPHONES_MODE_STEREO, AV_IAMF_HEADPHONES_MODE_BINAURAL, FLAGS, .unit = "headphones_rendering_mode" },
369
        { "stereo",   NULL, 0, AV_OPT_TYPE_CONST,
370
                   { .i64 = AV_IAMF_HEADPHONES_MODE_STEREO },   .unit = "headphones_rendering_mode" },
371
        { "binaural", NULL, 0, AV_OPT_TYPE_CONST,
372
                   { .i64 = AV_IAMF_HEADPHONES_MODE_BINAURAL }, .unit = "headphones_rendering_mode" },
373
    { "default_mix_gain", "Default mix gain", OFFSET(default_mix_gain), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
374
    { "annotations", "Annotations", OFFSET(annotations), AV_OPT_TYPE_DICT, { .str = NULL }, 0, 0, FLAGS },
375
    { NULL },
376
};
377
378
static void *submix_element_child_next(void *obj, void *prev)
379
0
{
380
0
    AVIAMFSubmixElement *submix_element = obj;
381
0
    if (!prev)
382
0
        return submix_element->element_mix_config;
383
384
0
    return NULL;
385
0
}
386
387
static const AVClass *submix_element_child_iterate(void **opaque)
388
0
{
389
0
    uintptr_t i = (uintptr_t)*opaque;
390
0
    const AVClass *ret = NULL;
391
392
0
    if (i)
393
0
        ret = &param_definition_class;
394
395
0
    if (ret)
396
0
        *opaque = (void*)(i + 1);
397
0
    return ret;
398
0
}
399
400
static const AVClass element_class = {
401
    .class_name          = "AVIAMFSubmixElement",
402
    .item_name           = av_default_item_name,
403
    .version             = LIBAVUTIL_VERSION_INT,
404
    .option              = submix_element_options,
405
    .child_next          = submix_element_child_next,
406
    .child_class_iterate = submix_element_child_iterate,
407
};
408
409
0
IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix, submix, AVIAMFSubmixElement, element, s)
410
411
#undef OFFSET
412
#define OFFSET(x) offsetof(AVIAMFSubmixLayout, x)
413
static const AVOption submix_layout_options[] = {
414
    { "layout_type", "Layout type", OFFSET(layout_type), AV_OPT_TYPE_INT,
415
            { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS },
416
            AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS, AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL, FLAGS, .unit = "layout_type" },
417
        { "loudspeakers", NULL, 0, AV_OPT_TYPE_CONST,
418
                   { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS }, .unit = "layout_type" },
419
        { "binaural",     NULL, 0, AV_OPT_TYPE_CONST,
420
                   { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL },     .unit = "layout_type" },
421
    { "sound_system", "Sound System", OFFSET(sound_system), AV_OPT_TYPE_CHLAYOUT, { .str = NULL }, 0, 0, FLAGS },
422
    { "integrated_loudness", "Integrated loudness", OFFSET(integrated_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
423
    { "digital_peak", "Digital peak", OFFSET(digital_peak), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
424
    { "true_peak", "True peak", OFFSET(true_peak), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
425
    { "dialog_anchored_loudness", "Anchored loudness (Dialog)", OFFSET(dialogue_anchored_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
426
    { "album_anchored_loudness", "Anchored loudness (Album)", OFFSET(album_anchored_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
427
    { NULL },
428
};
429
430
static const AVClass layout_class = {
431
    .class_name     = "AVIAMFSubmixLayout",
432
    .item_name      = av_default_item_name,
433
    .version        = LIBAVUTIL_VERSION_INT,
434
    .option         = submix_layout_options,
435
};
436
437
0
IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix, submix, AVIAMFSubmixLayout, layout, s)
438
439
#undef OFFSET
440
#define OFFSET(x) offsetof(AVIAMFSubmix, x)
441
static const AVOption submix_presentation_options[] = {
442
    { "default_mix_gain", "Default mix gain", OFFSET(default_mix_gain), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS },
443
    { NULL },
444
};
445
446
static void *submix_presentation_child_next(void *obj, void *prev)
447
0
{
448
0
    AVIAMFSubmix *sub_mix = obj;
449
0
    if (!prev)
450
0
        return sub_mix->output_mix_config;
451
452
0
    return NULL;
453
0
}
454
455
static const AVClass *submix_presentation_child_iterate(void **opaque)
456
0
{
457
0
    uintptr_t i = (uintptr_t)*opaque;
458
0
    const AVClass *ret = NULL;
459
460
0
    switch(i) {
461
0
    case 0:
462
0
        ret = &element_class;
463
0
        break;
464
0
    case 1:
465
0
        ret = &layout_class;
466
0
        break;
467
0
    case 2:
468
0
        ret = &param_definition_class;
469
0
        break;
470
0
    default:
471
0
        break;
472
0
    }
473
474
0
    if (ret)
475
0
        *opaque = (void*)(i + 1);
476
0
    return ret;
477
0
}
478
479
static const AVClass submix_class = {
480
    .class_name          = "AVIAMFSubmix",
481
    .item_name           = av_default_item_name,
482
    .version             = LIBAVUTIL_VERSION_INT,
483
    .option              = submix_presentation_options,
484
    .child_next          = submix_presentation_child_next,
485
    .child_class_iterate = submix_presentation_child_iterate,
486
};
487
488
#undef OFFSET
489
#define OFFSET(x) offsetof(AVIAMFMixPresentation, x)
490
static const AVOption mix_presentation_options[] = {
491
    { "annotations", "set annotations", OFFSET(annotations), AV_OPT_TYPE_DICT, {.str = NULL }, 0, 0, FLAGS },
492
    { NULL },
493
};
494
495
#undef OFFSET
496
#undef FLAGS
497
498
static const AVClass *mix_presentation_child_iterate(void **opaque)
499
0
{
500
0
    uintptr_t i = (uintptr_t)*opaque;
501
0
    const AVClass *ret = NULL;
502
503
0
    if (i)
504
0
        ret = &submix_class;
505
506
0
    if (ret)
507
0
        *opaque = (void*)(i + 1);
508
0
    return ret;
509
0
}
510
511
static const AVClass mix_presentation_class = {
512
    .class_name          = "AVIAMFMixPresentation",
513
    .item_name           = av_default_item_name,
514
    .version             = LIBAVUTIL_VERSION_INT,
515
    .option              = mix_presentation_options,
516
    .child_class_iterate = mix_presentation_child_iterate,
517
};
518
519
const AVClass *av_iamf_mix_presentation_get_class(void)
520
0
{
521
0
    return &mix_presentation_class;
522
0
}
523
524
AVIAMFMixPresentation *av_iamf_mix_presentation_alloc(void)
525
0
{
526
0
    AVIAMFMixPresentation *mix_presentation = av_mallocz(sizeof(*mix_presentation));
527
528
0
    if (mix_presentation) {
529
0
        mix_presentation->av_class = &mix_presentation_class;
530
0
        av_opt_set_defaults(mix_presentation);
531
0
    }
532
533
0
    return mix_presentation;
534
0
}
535
536
0
IAMF_ADD_FUNC_TEMPLATE(AVIAMFMixPresentation, mix_presentation, AVIAMFSubmix, submix, es)
537
538
void av_iamf_mix_presentation_free(AVIAMFMixPresentation **pmix_presentation)
539
0
{
540
0
    AVIAMFMixPresentation *mix_presentation = *pmix_presentation;
541
542
0
    if (!mix_presentation)
543
0
        return;
544
545
0
    for (int i = 0; i < mix_presentation->nb_submixes; i++) {
546
0
        AVIAMFSubmix *sub_mix = mix_presentation->submixes[i];
547
0
        for (int j = 0; j < sub_mix->nb_elements; j++) {
548
0
            AVIAMFSubmixElement *submix_element = sub_mix->elements[j];
549
0
            av_opt_free(submix_element);
550
0
            av_free(submix_element->element_mix_config);
551
0
            av_free(submix_element);
552
0
        }
553
0
        av_free(sub_mix->elements);
554
0
        for (int j = 0; j < sub_mix->nb_layouts; j++) {
555
0
            AVIAMFSubmixLayout *submix_layout = sub_mix->layouts[j];
556
0
            av_opt_free(submix_layout);
557
0
            av_free(submix_layout);
558
0
        }
559
0
        av_free(sub_mix->layouts);
560
0
        av_free(sub_mix->output_mix_config);
561
0
        av_free(sub_mix);
562
0
    }
563
0
    av_opt_free(mix_presentation);
564
0
    av_free(mix_presentation->submixes);
565
566
0
    av_freep(pmix_presentation);
567
0
}