Coverage Report

Created: 2025-11-16 07:20

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
8.03k
child_type *av_iamf_ ## parent_name ## _add_ ## child_name(parent_type *parent_name)                       \
34
8.03k
{                                                                                                          \
35
8.03k
    child_type **child_name ## suffix, *child_name;                                                        \
36
8.03k
                                                                                                           \
37
8.03k
    if (parent_name->nb_## child_name ## suffix == UINT_MAX)                                               \
38
8.03k
        return NULL;                                                                                       \
39
8.03k
                                                                                                           \
40
8.03k
    child_name ## suffix = av_realloc_array(parent_name->child_name ## suffix,                             \
41
8.03k
                                            parent_name->nb_## child_name ## suffix + 1,                   \
42
8.03k
                                            sizeof(*parent_name->child_name ## suffix));                   \
43
8.03k
    if (!child_name ## suffix)                                                                             \
44
8.03k
        return NULL;                                                                                       \
45
8.03k
                                                                                                           \
46
8.03k
    parent_name->child_name ## suffix = child_name ## suffix;                                              \
47
8.03k
                                                                                                           \
48
8.03k
    child_name = parent_name->child_name ## suffix[parent_name->nb_## child_name ## suffix]                \
49
8.03k
               = av_mallocz(sizeof(*child_name));                                                          \
50
8.03k
    if (!child_name)                                                                                       \
51
8.03k
        return NULL;                                                                                       \
52
8.03k
                                                                                                           \
53
8.03k
    child_name->av_class = &child_name ## _class;                                                          \
54
8.03k
    av_opt_set_defaults(child_name);                                                                       \
55
8.03k
    parent_name->nb_## child_name ## suffix++;                                                             \
56
8.03k
                                                                                                           \
57
8.03k
    return child_name;                                                                                     \
58
8.03k
}
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
16.6k
{
162
163
16.6k
    struct MixGainStruct {
164
16.6k
        AVIAMFParamDefinition p;
165
16.6k
        AVIAMFMixGain m;
166
16.6k
    };
167
16.6k
    struct DemixStruct {
168
16.6k
        AVIAMFParamDefinition p;
169
16.6k
        AVIAMFDemixingInfo d;
170
16.6k
    };
171
16.6k
    struct ReconGainStruct {
172
16.6k
        AVIAMFParamDefinition p;
173
16.6k
        AVIAMFReconGain r;
174
16.6k
    };
175
16.6k
    size_t subblocks_offset, subblock_size;
176
16.6k
    size_t size;
177
16.6k
    AVIAMFParamDefinition *par;
178
179
16.6k
    switch (type) {
180
15.1k
    case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN:
181
15.1k
        subblocks_offset = offsetof(struct MixGainStruct, m);
182
15.1k
        subblock_size = sizeof(AVIAMFMixGain);
183
15.1k
        break;
184
937
    case AV_IAMF_PARAMETER_DEFINITION_DEMIXING:
185
937
        subblocks_offset = offsetof(struct DemixStruct, d);
186
937
        subblock_size = sizeof(AVIAMFDemixingInfo);
187
937
        break;
188
629
    case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN:
189
629
        subblocks_offset = offsetof(struct ReconGainStruct, r);
190
629
        subblock_size = sizeof(AVIAMFReconGain);
191
629
        break;
192
0
    default:
193
0
        return NULL;
194
16.6k
    }
195
196
16.6k
    size = subblocks_offset;
197
16.6k
    if (nb_subblocks > (SIZE_MAX - size) / subblock_size)
198
0
        return NULL;
199
16.6k
    size += subblock_size * nb_subblocks;
200
201
16.6k
    par = av_mallocz(size);
202
16.6k
    if (!par)
203
20
        return NULL;
204
205
16.6k
    par->av_class = &param_definition_class;
206
16.6k
    av_opt_set_defaults(par);
207
208
16.6k
    par->type = type;
209
16.6k
    par->nb_subblocks = nb_subblocks;
210
16.6k
    par->subblock_size = subblock_size;
211
16.6k
    par->subblocks_offset = subblocks_offset;
212
213
160M
    for (int i = 0; i < nb_subblocks; i++) {
214
160M
        void *subblock = av_iamf_param_definition_get_subblock(par, i);
215
216
160M
        switch (type) {
217
38.8M
        case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN:
218
38.8M
            ((AVIAMFMixGain *)subblock)->av_class = &mix_gain_class;
219
38.8M
            break;
220
37.1M
        case AV_IAMF_PARAMETER_DEFINITION_DEMIXING:
221
37.1M
            ((AVIAMFDemixingInfo *)subblock)->av_class = &demixing_info_class;
222
37.1M
            break;
223
84.0M
        case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN:
224
84.0M
            ((AVIAMFReconGain *)subblock)->av_class = &recon_gain_class;
225
84.0M
            break;
226
0
        default:
227
0
            av_assert0(0);
228
160M
        }
229
230
160M
        av_opt_set_defaults(subblock);
231
160M
    }
232
233
16.6k
    if (out_size)
234
16.6k
        *out_size = size;
235
236
16.6k
    return par;
237
16.6k
}
238
239
//
240
// Audio Element
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
    { NULL },
273
};
274
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,
280
};
281
282
#undef OFFSET
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 },
293
    { NULL },
294
};
295
296
static const AVClass *audio_element_child_iterate(void **opaque)
297
0
{
298
0
    uintptr_t i = (uintptr_t)*opaque;
299
0
    const AVClass *ret = NULL;
300
301
0
    if (i)
302
0
        ret = &layer_class;
303
304
0
    if (ret)
305
0
        *opaque = (void*)(i + 1);
306
0
    return ret;
307
0
}
308
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,
315
};
316
317
const AVClass *av_iamf_audio_element_get_class(void)
318
0
{
319
0
    return &audio_element_class;
320
0
}
321
322
AVIAMFAudioElement *av_iamf_audio_element_alloc(void)
323
3.61k
{
324
3.61k
    AVIAMFAudioElement *audio_element = av_mallocz(sizeof(*audio_element));
325
326
3.61k
    if (audio_element) {
327
3.61k
        audio_element->av_class = &audio_element_class;
328
3.61k
        av_opt_set_defaults(audio_element);
329
3.61k
    }
330
331
3.61k
    return audio_element;
332
3.61k
}
333
334
2.88k
IAMF_ADD_FUNC_TEMPLATE(AVIAMFAudioElement, audio_element, AVIAMFLayer, layer, s)
335
336
void av_iamf_audio_element_free(AVIAMFAudioElement **paudio_element)
337
5.24k
{
338
5.24k
    AVIAMFAudioElement *audio_element = *paudio_element;
339
340
5.24k
    if (!audio_element)
341
1.63k
        return;
342
343
6.49k
    for (int i = 0; i < audio_element->nb_layers; i++) {
344
2.88k
        AVIAMFLayer *layer = audio_element->layers[i];
345
2.88k
        av_opt_free(layer);
346
2.88k
        av_free(layer->demixing_matrix);
347
2.88k
        av_free(layer);
348
2.88k
    }
349
3.61k
    av_free(audio_element->layers);
350
351
3.61k
    av_free(audio_element->demixing_info);
352
3.61k
    av_free(audio_element->recon_gain_info);
353
3.61k
    av_freep(paudio_element);
354
3.61k
}
355
356
//
357
// Mix Presentation
358
//
359
#undef OFFSET
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 },
371
    { NULL },
372
};
373
374
static void *submix_element_child_next(void *obj, void *prev)
375
0
{
376
0
    AVIAMFSubmixElement *submix_element = obj;
377
0
    if (!prev)
378
0
        return submix_element->element_mix_config;
379
380
0
    return NULL;
381
0
}
382
383
static const AVClass *submix_element_child_iterate(void **opaque)
384
0
{
385
0
    uintptr_t i = (uintptr_t)*opaque;
386
0
    const AVClass *ret = NULL;
387
388
0
    if (i)
389
0
        ret = &param_definition_class;
390
391
0
    if (ret)
392
0
        *opaque = (void*)(i + 1);
393
0
    return ret;
394
0
}
395
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,
403
};
404
405
247
IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix, submix, AVIAMFSubmixElement, element, s)
406
407
#undef OFFSET
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 },
423
    { NULL },
424
};
425
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,
431
};
432
433
2.85k
IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix, submix, AVIAMFSubmixLayout, layout, s)
434
435
#undef OFFSET
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 },
439
    { NULL },
440
};
441
442
static void *submix_presentation_child_next(void *obj, void *prev)
443
0
{
444
0
    AVIAMFSubmix *sub_mix = obj;
445
0
    if (!prev)
446
0
        return sub_mix->output_mix_config;
447
448
0
    return NULL;
449
0
}
450
451
static const AVClass *submix_presentation_child_iterate(void **opaque)
452
0
{
453
0
    uintptr_t i = (uintptr_t)*opaque;
454
0
    const AVClass *ret = NULL;
455
456
0
    switch(i) {
457
0
    case 0:
458
0
        ret = &element_class;
459
0
        break;
460
0
    case 1:
461
0
        ret = &layout_class;
462
0
        break;
463
0
    case 2:
464
0
        ret = &param_definition_class;
465
0
        break;
466
0
    default:
467
0
        break;
468
0
    }
469
470
0
    if (ret)
471
0
        *opaque = (void*)(i + 1);
472
0
    return ret;
473
0
}
474
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,
482
};
483
484
#undef OFFSET
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 },
488
    { NULL },
489
};
490
491
#undef OFFSET
492
#undef FLAGS
493
494
static const AVClass *mix_presentation_child_iterate(void **opaque)
495
0
{
496
0
    uintptr_t i = (uintptr_t)*opaque;
497
0
    const AVClass *ret = NULL;
498
499
0
    if (i)
500
0
        ret = &submix_class;
501
502
0
    if (ret)
503
0
        *opaque = (void*)(i + 1);
504
0
    return ret;
505
0
}
506
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,
513
};
514
515
const AVClass *av_iamf_mix_presentation_get_class(void)
516
0
{
517
0
    return &mix_presentation_class;
518
0
}
519
520
AVIAMFMixPresentation *av_iamf_mix_presentation_alloc(void)
521
1.80k
{
522
1.80k
    AVIAMFMixPresentation *mix_presentation = av_mallocz(sizeof(*mix_presentation));
523
524
1.80k
    if (mix_presentation) {
525
1.80k
        mix_presentation->av_class = &mix_presentation_class;
526
1.80k
        av_opt_set_defaults(mix_presentation);
527
1.80k
    }
528
529
1.80k
    return mix_presentation;
530
1.80k
}
531
532
2.03k
IAMF_ADD_FUNC_TEMPLATE(AVIAMFMixPresentation, mix_presentation, AVIAMFSubmix, submix, es)
533
534
void av_iamf_mix_presentation_free(AVIAMFMixPresentation **pmix_presentation)
535
2.19k
{
536
2.19k
    AVIAMFMixPresentation *mix_presentation = *pmix_presentation;
537
538
2.19k
    if (!mix_presentation)
539
391
        return;
540
541
3.84k
    for (int i = 0; i < mix_presentation->nb_submixes; i++) {
542
2.03k
        AVIAMFSubmix *sub_mix = mix_presentation->submixes[i];
543
2.28k
        for (int j = 0; j < sub_mix->nb_elements; j++) {
544
247
            AVIAMFSubmixElement *submix_element = sub_mix->elements[j];
545
247
            av_opt_free(submix_element);
546
247
            av_free(submix_element->element_mix_config);
547
247
            av_free(submix_element);
548
247
        }
549
2.03k
        av_free(sub_mix->elements);
550
4.89k
        for (int j = 0; j < sub_mix->nb_layouts; j++) {
551
2.85k
            AVIAMFSubmixLayout *submix_layout = sub_mix->layouts[j];
552
2.85k
            av_opt_free(submix_layout);
553
2.85k
            av_free(submix_layout);
554
2.85k
        }
555
2.03k
        av_free(sub_mix->layouts);
556
2.03k
        av_free(sub_mix->output_mix_config);
557
2.03k
        av_free(sub_mix);
558
2.03k
    }
559
1.80k
    av_opt_free(mix_presentation);
560
1.80k
    av_free(mix_presentation->submixes);
561
562
1.80k
    av_freep(pmix_presentation);
563
1.80k
}