FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/iamf.c
Date: 2026-04-24 19:58:39
Exec Total Coverage
Lines: 101 173 58.4%
Functions: 11 19 57.9%
Branches: 42 84 50.0%

Line Branch Exec 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 child_type *av_iamf_ ## parent_name ## _add_ ## child_name(parent_type *parent_name) \
34 { \
35 child_type **child_name ## suffix, *child_name; \
36 \
37 if (parent_name->nb_## child_name ## suffix == UINT_MAX) \
38 return NULL; \
39 \
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) \
44 return NULL; \
45 \
46 parent_name->child_name ## suffix = child_name ## suffix; \
47 \
48 child_name = parent_name->child_name ## suffix[parent_name->nb_## child_name ## suffix] \
49 = av_mallocz(sizeof(*child_name)); \
50 if (!child_name) \
51 return NULL; \
52 \
53 child_name->av_class = &child_name ## _class; \
54 av_opt_set_defaults(child_name); \
55 parent_name->nb_## child_name ## suffix++; \
56 \
57 return child_name; \
58 }
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 {
124 uintptr_t i = (uintptr_t)*opaque;
125 const AVClass *ret = NULL;
126
127 switch(i) {
128 case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN:
129 ret = &mix_gain_class;
130 break;
131 case AV_IAMF_PARAMETER_DEFINITION_DEMIXING:
132 ret = &demixing_info_class;
133 break;
134 case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN:
135 ret = &recon_gain_class;
136 break;
137 default:
138 break;
139 }
140
141 if (ret)
142 *opaque = (void*)(i + 1);
143 return ret;
144 }
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 {
156 return &param_definition_class;
157 }
158
159 255 AVIAMFParamDefinition *av_iamf_param_definition_alloc(enum AVIAMFParamDefinitionType type,
160 unsigned int nb_subblocks, size_t *out_size)
161 {
162
163 struct MixGainStruct {
164 AVIAMFParamDefinition p;
165 AVIAMFMixGain m;
166 };
167 struct DemixStruct {
168 AVIAMFParamDefinition p;
169 AVIAMFDemixingInfo d;
170 };
171 struct ReconGainStruct {
172 AVIAMFParamDefinition p;
173 AVIAMFReconGain r;
174 };
175 size_t subblocks_offset, subblock_size;
176 size_t size;
177 AVIAMFParamDefinition *par;
178
179
3/4
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
255 switch (type) {
180 172 case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN:
181 172 subblocks_offset = offsetof(struct MixGainStruct, m);
182 172 subblock_size = sizeof(AVIAMFMixGain);
183 172 break;
184 31 case AV_IAMF_PARAMETER_DEFINITION_DEMIXING:
185 31 subblocks_offset = offsetof(struct DemixStruct, d);
186 31 subblock_size = sizeof(AVIAMFDemixingInfo);
187 31 break;
188 52 case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN:
189 52 subblocks_offset = offsetof(struct ReconGainStruct, r);
190 52 subblock_size = sizeof(AVIAMFReconGain);
191 52 break;
192 default:
193 return NULL;
194 }
195
196 255 size = subblocks_offset;
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
255 if (nb_subblocks > (SIZE_MAX - size) / subblock_size)
198 return NULL;
199 255 size += subblock_size * nb_subblocks;
200
201 255 par = av_mallocz(size);
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
255 if (!par)
203 return NULL;
204
205 255 par->av_class = &param_definition_class;
206 255 av_opt_set_defaults(par);
207
208 255 par->type = type;
209 255 par->nb_subblocks = nb_subblocks;
210 255 par->subblock_size = subblock_size;
211 255 par->subblocks_offset = subblocks_offset;
212
213
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 255 times.
397 for (int i = 0; i < nb_subblocks; i++) {
214 142 void *subblock = av_iamf_param_definition_get_subblock(par, i);
215
216
3/4
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
142 switch (type) {
217 59 case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN:
218 59 ((AVIAMFMixGain *)subblock)->av_class = &mix_gain_class;
219 59 break;
220 31 case AV_IAMF_PARAMETER_DEFINITION_DEMIXING:
221 31 ((AVIAMFDemixingInfo *)subblock)->av_class = &demixing_info_class;
222 31 break;
223 52 case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN:
224 52 ((AVIAMFReconGain *)subblock)->av_class = &recon_gain_class;
225 52 break;
226 default:
227 av_assert0(0);
228 }
229 }
230
231
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 59 times.
255 if (out_size)
232 196 *out_size = size;
233
234 255 return par;
235 }
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 {
300 uintptr_t i = (uintptr_t)*opaque;
301 const AVClass *ret = NULL;
302
303 if (i)
304 ret = &layer_class;
305
306 if (ret)
307 *opaque = (void*)(i + 1);
308 return ret;
309 }
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 {
321 return &audio_element_class;
322 }
323
324 90 AVIAMFAudioElement *av_iamf_audio_element_alloc(void)
325 {
326 90 AVIAMFAudioElement *audio_element = av_mallocz(sizeof(*audio_element));
327
328
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 if (audio_element) {
329 90 audio_element->av_class = &audio_element_class;
330 90 av_opt_set_defaults(audio_element);
331 }
332
333 90 return audio_element;
334 }
335
336
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 109 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 109 times.
109 IAMF_ADD_FUNC_TEMPLATE(AVIAMFAudioElement, audio_element, AVIAMFLayer, layer, s)
337
338 142 void av_iamf_audio_element_free(AVIAMFAudioElement **paudio_element)
339 {
340 142 AVIAMFAudioElement *audio_element = *paudio_element;
341
342
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 90 times.
142 if (!audio_element)
343 52 return;
344
345
2/2
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 90 times.
199 for (int i = 0; i < audio_element->nb_layers; i++) {
346 109 AVIAMFLayer *layer = audio_element->layers[i];
347 109 av_opt_free(layer);
348 109 av_free(layer->demixing_matrix);
349 109 av_free(layer);
350 }
351 90 av_free(audio_element->layers);
352
353 90 av_free(audio_element->demixing_info);
354 90 av_free(audio_element->recon_gain_info);
355 90 av_freep(paudio_element);
356 }
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 86 static void *submix_element_child_next(void *obj, void *prev)
377 {
378 86 AVIAMFSubmixElement *submix_element = obj;
379
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 34 times.
86 if (!prev)
380 52 return submix_element->element_mix_config;
381
382 34 return NULL;
383 }
384
385 static const AVClass *submix_element_child_iterate(void **opaque)
386 {
387 uintptr_t i = (uintptr_t)*opaque;
388 const AVClass *ret = NULL;
389
390 if (i)
391 ret = &param_definition_class;
392
393 if (ret)
394 *opaque = (void*)(i + 1);
395 return ret;
396 }
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
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 58 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 58 times.
58 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
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 115 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 115 times.
115 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 48 static void *submix_presentation_child_next(void *obj, void *prev)
445 {
446 48 AVIAMFSubmix *sub_mix = obj;
447
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 10 times.
48 if (!prev)
448 38 return sub_mix->output_mix_config;
449
450 10 return NULL;
451 }
452
453 static const AVClass *submix_presentation_child_iterate(void **opaque)
454 {
455 uintptr_t i = (uintptr_t)*opaque;
456 const AVClass *ret = NULL;
457
458 switch(i) {
459 case 0:
460 ret = &element_class;
461 break;
462 case 1:
463 ret = &layout_class;
464 break;
465 case 2:
466 ret = &param_definition_class;
467 break;
468 default:
469 break;
470 }
471
472 if (ret)
473 *opaque = (void*)(i + 1);
474 return ret;
475 }
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 {
498 uintptr_t i = (uintptr_t)*opaque;
499 const AVClass *ret = NULL;
500
501 if (i)
502 ret = &submix_class;
503
504 if (ret)
505 *opaque = (void*)(i + 1);
506 return ret;
507 }
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 {
519 return &mix_presentation_class;
520 }
521
522 85 AVIAMFMixPresentation *av_iamf_mix_presentation_alloc(void)
523 {
524 85 AVIAMFMixPresentation *mix_presentation = av_mallocz(sizeof(*mix_presentation));
525
526
1/2
✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
85 if (mix_presentation) {
527 85 mix_presentation->av_class = &mix_presentation_class;
528 85 av_opt_set_defaults(mix_presentation);
529 }
530
531 85 return mix_presentation;
532 }
533
534
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 55 times.
55 IAMF_ADD_FUNC_TEMPLATE(AVIAMFMixPresentation, mix_presentation, AVIAMFSubmix, submix, es)
535
536 134 void av_iamf_mix_presentation_free(AVIAMFMixPresentation **pmix_presentation)
537 {
538 134 AVIAMFMixPresentation *mix_presentation = *pmix_presentation;
539
540
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 85 times.
134 if (!mix_presentation)
541 49 return;
542
543
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 85 times.
140 for (int i = 0; i < mix_presentation->nb_submixes; i++) {
544 55 AVIAMFSubmix *sub_mix = mix_presentation->submixes[i];
545
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 55 times.
113 for (int j = 0; j < sub_mix->nb_elements; j++) {
546 58 AVIAMFSubmixElement *submix_element = sub_mix->elements[j];
547 58 av_opt_free(submix_element);
548 58 av_free(submix_element->element_mix_config);
549 58 av_free(submix_element);
550 }
551 55 av_free(sub_mix->elements);
552
2/2
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 55 times.
170 for (int j = 0; j < sub_mix->nb_layouts; j++) {
553 115 AVIAMFSubmixLayout *submix_layout = sub_mix->layouts[j];
554 115 av_opt_free(submix_layout);
555 115 av_free(submix_layout);
556 }
557 55 av_free(sub_mix->layouts);
558 55 av_free(sub_mix->output_mix_config);
559 55 av_free(sub_mix);
560 }
561 85 av_opt_free(mix_presentation);
562 85 av_free(mix_presentation->submixes);
563
564 85 av_freep(pmix_presentation);
565 }
566