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 ¶m_definition_class; | |
157 | } | ||
158 | |||
159 | 184 | 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 114 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
|
184 | switch (type) { |
180 | 114 | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: | |
181 | 114 | subblocks_offset = offsetof(struct MixGainStruct, m); | |
182 | 114 | subblock_size = sizeof(AVIAMFMixGain); | |
183 | 114 | break; | |
184 | 25 | case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: | |
185 | 25 | subblocks_offset = offsetof(struct DemixStruct, d); | |
186 | 25 | subblock_size = sizeof(AVIAMFDemixingInfo); | |
187 | 25 | break; | |
188 | 45 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: | |
189 | 45 | subblocks_offset = offsetof(struct ReconGainStruct, r); | |
190 | 45 | subblock_size = sizeof(AVIAMFReconGain); | |
191 | 45 | break; | |
192 | ✗ | default: | |
193 | ✗ | return NULL; | |
194 | } | ||
195 | |||
196 | 184 | size = subblocks_offset; | |
197 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 184 times.
|
184 | if (nb_subblocks > (SIZE_MAX - size) / subblock_size) |
198 | ✗ | return NULL; | |
199 | 184 | size += subblock_size * nb_subblocks; | |
200 | |||
201 | 184 | par = av_mallocz(size); | |
202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 184 times.
|
184 | if (!par) |
203 | ✗ | return NULL; | |
204 | |||
205 | 184 | par->av_class = ¶m_definition_class; | |
206 | 184 | av_opt_set_defaults(par); | |
207 | |||
208 | 184 | par->type = type; | |
209 | 184 | par->nb_subblocks = nb_subblocks; | |
210 | 184 | par->subblock_size = subblock_size; | |
211 | 184 | par->subblocks_offset = subblocks_offset; | |
212 | |||
213 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 184 times.
|
286 | for (int i = 0; i < nb_subblocks; i++) { |
214 | 102 | void *subblock = av_iamf_param_definition_get_subblock(par, i); | |
215 | |||
216 |
3/4✓ Branch 0 taken 32 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
|
102 | switch (type) { |
217 | 32 | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: | |
218 | 32 | ((AVIAMFMixGain *)subblock)->av_class = &mix_gain_class; | |
219 | 32 | break; | |
220 | 25 | case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: | |
221 | 25 | ((AVIAMFDemixingInfo *)subblock)->av_class = &demixing_info_class; | |
222 | 25 | break; | |
223 | 45 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: | |
224 | 45 | ((AVIAMFReconGain *)subblock)->av_class = &recon_gain_class; | |
225 | 45 | break; | |
226 | ✗ | default: | |
227 | ✗ | av_assert0(0); | |
228 | } | ||
229 | |||
230 | 102 | av_opt_set_defaults(subblock); | |
231 | } | ||
232 | |||
233 |
2/2✓ Branch 0 taken 140 times.
✓ Branch 1 taken 44 times.
|
184 | if (out_size) |
234 | 140 | *out_size = size; | |
235 | |||
236 | 184 | return par; | |
237 | } | ||
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 | { | ||
298 | ✗ | uintptr_t i = (uintptr_t)*opaque; | |
299 | ✗ | const AVClass *ret = NULL; | |
300 | |||
301 | ✗ | if (i) | |
302 | ✗ | ret = &layer_class; | |
303 | |||
304 | ✗ | if (ret) | |
305 | ✗ | *opaque = (void*)(i + 1); | |
306 | ✗ | return ret; | |
307 | } | ||
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 | { | ||
319 | ✗ | return &audio_element_class; | |
320 | } | ||
321 | |||
322 | 60 | AVIAMFAudioElement *av_iamf_audio_element_alloc(void) | |
323 | { | ||
324 | 60 | AVIAMFAudioElement *audio_element = av_mallocz(sizeof(*audio_element)); | |
325 | |||
326 |
1/2✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
|
60 | if (audio_element) { |
327 | 60 | audio_element->av_class = &audio_element_class; | |
328 | 60 | av_opt_set_defaults(audio_element); | |
329 | } | ||
330 | |||
331 | 60 | return audio_element; | |
332 | } | ||
333 | |||
334 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 86 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 86 times.
|
86 | IAMF_ADD_FUNC_TEMPLATE(AVIAMFAudioElement, audio_element, AVIAMFLayer, layer, s) |
335 | |||
336 | 95 | void av_iamf_audio_element_free(AVIAMFAudioElement **paudio_element) | |
337 | { | ||
338 | 95 | AVIAMFAudioElement *audio_element = *paudio_element; | |
339 | |||
340 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 60 times.
|
95 | if (!audio_element) |
341 | 35 | return; | |
342 | |||
343 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 60 times.
|
146 | for (int i = 0; i < audio_element->nb_layers; i++) { |
344 | 86 | AVIAMFLayer *layer = audio_element->layers[i]; | |
345 | 86 | av_opt_free(layer); | |
346 | 86 | av_free(layer->demixing_matrix); | |
347 | 86 | av_free(layer); | |
348 | } | ||
349 | 60 | av_free(audio_element->layers); | |
350 | |||
351 | 60 | av_free(audio_element->demixing_info); | |
352 | 60 | av_free(audio_element->recon_gain_info); | |
353 | 60 | av_freep(paudio_element); | |
354 | } | ||
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 | 65 | static void *submix_element_child_next(void *obj, void *prev) | |
375 | { | ||
376 | 65 | AVIAMFSubmixElement *submix_element = obj; | |
377 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 26 times.
|
65 | if (!prev) |
378 | 39 | return submix_element->element_mix_config; | |
379 | |||
380 | 26 | return NULL; | |
381 | } | ||
382 | |||
383 | ✗ | static const AVClass *submix_element_child_iterate(void **opaque) | |
384 | { | ||
385 | ✗ | uintptr_t i = (uintptr_t)*opaque; | |
386 | ✗ | const AVClass *ret = NULL; | |
387 | |||
388 | ✗ | if (i) | |
389 | ✗ | ret = ¶m_definition_class; | |
390 | |||
391 | ✗ | if (ret) | |
392 | ✗ | *opaque = (void*)(i + 1); | |
393 | ✗ | return ret; | |
394 | } | ||
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 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 41 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 41 times.
|
41 | 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 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 92 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 92 times.
|
92 | 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 | 38 | static void *submix_presentation_child_next(void *obj, void *prev) | |
443 | { | ||
444 | 38 | AVIAMFSubmix *sub_mix = obj; | |
445 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 8 times.
|
38 | if (!prev) |
446 | 30 | return sub_mix->output_mix_config; | |
447 | |||
448 | 8 | return NULL; | |
449 | } | ||
450 | |||
451 | ✗ | static const AVClass *submix_presentation_child_iterate(void **opaque) | |
452 | { | ||
453 | ✗ | uintptr_t i = (uintptr_t)*opaque; | |
454 | ✗ | const AVClass *ret = NULL; | |
455 | |||
456 | ✗ | switch(i) { | |
457 | ✗ | case 0: | |
458 | ✗ | ret = &element_class; | |
459 | ✗ | break; | |
460 | ✗ | case 1: | |
461 | ✗ | ret = &layout_class; | |
462 | ✗ | break; | |
463 | ✗ | case 2: | |
464 | ✗ | ret = ¶m_definition_class; | |
465 | ✗ | break; | |
466 | ✗ | default: | |
467 | ✗ | break; | |
468 | } | ||
469 | |||
470 | ✗ | if (ret) | |
471 | ✗ | *opaque = (void*)(i + 1); | |
472 | ✗ | return ret; | |
473 | } | ||
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 | { | ||
496 | ✗ | uintptr_t i = (uintptr_t)*opaque; | |
497 | ✗ | const AVClass *ret = NULL; | |
498 | |||
499 | ✗ | if (i) | |
500 | ✗ | ret = &submix_class; | |
501 | |||
502 | ✗ | if (ret) | |
503 | ✗ | *opaque = (void*)(i + 1); | |
504 | ✗ | return ret; | |
505 | } | ||
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 | { | ||
517 | ✗ | return &mix_presentation_class; | |
518 | } | ||
519 | |||
520 | 60 | AVIAMFMixPresentation *av_iamf_mix_presentation_alloc(void) | |
521 | { | ||
522 | 60 | AVIAMFMixPresentation *mix_presentation = av_mallocz(sizeof(*mix_presentation)); | |
523 | |||
524 |
1/2✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
|
60 | if (mix_presentation) { |
525 | 60 | mix_presentation->av_class = &mix_presentation_class; | |
526 | 60 | av_opt_set_defaults(mix_presentation); | |
527 | } | ||
528 | |||
529 | 60 | return mix_presentation; | |
530 | } | ||
531 | |||
532 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 41 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 41 times.
|
41 | IAMF_ADD_FUNC_TEMPLATE(AVIAMFMixPresentation, mix_presentation, AVIAMFSubmix, submix, es) |
533 | |||
534 | 95 | void av_iamf_mix_presentation_free(AVIAMFMixPresentation **pmix_presentation) | |
535 | { | ||
536 | 95 | AVIAMFMixPresentation *mix_presentation = *pmix_presentation; | |
537 | |||
538 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 60 times.
|
95 | if (!mix_presentation) |
539 | 35 | return; | |
540 | |||
541 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 60 times.
|
101 | for (int i = 0; i < mix_presentation->nb_submixes; i++) { |
542 | 41 | AVIAMFSubmix *sub_mix = mix_presentation->submixes[i]; | |
543 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 41 times.
|
82 | for (int j = 0; j < sub_mix->nb_elements; j++) { |
544 | 41 | AVIAMFSubmixElement *submix_element = sub_mix->elements[j]; | |
545 | 41 | av_opt_free(submix_element); | |
546 | 41 | av_free(submix_element->element_mix_config); | |
547 | 41 | av_free(submix_element); | |
548 | } | ||
549 | 41 | av_free(sub_mix->elements); | |
550 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 41 times.
|
133 | for (int j = 0; j < sub_mix->nb_layouts; j++) { |
551 | 92 | AVIAMFSubmixLayout *submix_layout = sub_mix->layouts[j]; | |
552 | 92 | av_opt_free(submix_layout); | |
553 | 92 | av_free(submix_layout); | |
554 | } | ||
555 | 41 | av_free(sub_mix->layouts); | |
556 | 41 | av_free(sub_mix->output_mix_config); | |
557 | 41 | av_free(sub_mix); | |
558 | } | ||
559 | 60 | av_opt_free(mix_presentation); | |
560 | 60 | av_free(mix_presentation->submixes); | |
561 | |||
562 | 60 | av_freep(pmix_presentation); | |
563 | } | ||
564 |