| 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 | 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 = ¶m_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 = ¶m_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 = ¶m_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 |