FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/iamf_writer.c
Date: 2025-01-20 09:27:23
Exec Total Coverage
Lines: 540 764 70.7%
Functions: 18 18 100.0%
Branches: 262 409 64.1%

Line Branch Exec Source
1 /*
2 * Immersive Audio Model and Formats muxing helpers and structs
3 * Copyright (c) 2023 James Almer <jamrial@gmail.com>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "libavutil/bprint.h"
23 #include "libavutil/channel_layout.h"
24 #include "libavutil/intreadwrite.h"
25 #include "libavutil/iamf.h"
26 #include "libavutil/mem.h"
27 #include "libavcodec/get_bits.h"
28 #include "libavcodec/put_bits.h"
29 #include "avformat.h"
30 #include "avio_internal.h"
31 #include "iamf.h"
32 #include "iamf_writer.h"
33
34
35 65 static int update_extradata(IAMFCodecConfig *codec_config)
36 {
37 GetBitContext gb;
38 PutBitContext pb;
39 int ret;
40
41
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
65 switch(codec_config->codec_id) {
42 1 case AV_CODEC_ID_OPUS:
43
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (codec_config->extradata_size != 19)
44 return AVERROR_INVALIDDATA;
45 1 codec_config->extradata_size -= 8;
46 1 AV_WB8(codec_config->extradata + 0, AV_RL8(codec_config->extradata + 8)); // version
47 1 AV_WB8(codec_config->extradata + 1, 2); // set channels to stereo
48 1 AV_WB16A(codec_config->extradata + 2, AV_RL16A(codec_config->extradata + 10)); // Byte swap pre-skip
49 1 AV_WB32A(codec_config->extradata + 4, AV_RL32A(codec_config->extradata + 12)); // Byte swap sample rate
50 1 AV_WB16A(codec_config->extradata + 8, 0); // set Output Gain to 0
51 1 AV_WB8(codec_config->extradata + 10, AV_RL8(codec_config->extradata + 18)); // Mapping family
52 1 break;
53 64 case AV_CODEC_ID_FLAC: {
54 uint8_t buf[13];
55
56 64 init_put_bits(&pb, buf, sizeof(buf));
57 64 ret = init_get_bits8(&gb, codec_config->extradata, codec_config->extradata_size);
58
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if (ret < 0)
59 return ret;
60
61 64 put_bits32(&pb, get_bits_long(&gb, 32)); // min/max blocksize
62 64 put_bits64(&pb, 48, get_bits64(&gb, 48)); // min/max framesize
63 64 put_bits(&pb, 20, get_bits(&gb, 20)); // samplerate
64 64 skip_bits(&gb, 3);
65 64 put_bits(&pb, 3, 1); // set channels to stereo
66 64 ret = put_bits_left(&pb);
67 64 put_bits(&pb, ret, get_bits(&gb, ret));
68 64 flush_put_bits(&pb);
69
70 64 memcpy(codec_config->extradata, buf, sizeof(buf));
71 64 break;
72 }
73 default:
74 break;
75 }
76
77 65 return 0;
78 }
79
80 12 static int populate_audio_roll_distance(IAMFCodecConfig *codec_config)
81 {
82
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
12 switch (codec_config->codec_id) {
83 1 case AV_CODEC_ID_OPUS:
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!codec_config->nb_samples)
85 return AVERROR(EINVAL);
86 // ceil(3840 / nb_samples)
87 1 codec_config->audio_roll_distance = -(1 + ((3840 - 1) / codec_config->nb_samples));
88 1 break;
89 case AV_CODEC_ID_AAC:
90 codec_config->audio_roll_distance = -1;
91 break;
92 11 case AV_CODEC_ID_FLAC:
93 case AV_CODEC_ID_PCM_S16BE:
94 case AV_CODEC_ID_PCM_S24BE:
95 case AV_CODEC_ID_PCM_S32BE:
96 case AV_CODEC_ID_PCM_S16LE:
97 case AV_CODEC_ID_PCM_S24LE:
98 case AV_CODEC_ID_PCM_S32LE:
99 11 codec_config->audio_roll_distance = 0;
100 11 break;
101 default:
102 return AVERROR(EINVAL);
103 }
104
105 12 return 0;
106 }
107
108 12 static int fill_codec_config(IAMFContext *iamf, const AVStreamGroup *stg,
109 IAMFCodecConfig *codec_config)
110 {
111 12 const AVStream *st = stg->streams[0];
112 IAMFCodecConfig **tmp;
113 12 int j, ret = 0;
114
115 12 codec_config->codec_id = st->codecpar->codec_id;
116 12 codec_config->codec_tag = st->codecpar->codec_tag;
117
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 switch (codec_config->codec_id) {
118 1 case AV_CODEC_ID_OPUS:
119 1 codec_config->sample_rate = 48000;
120 1 codec_config->nb_samples = av_rescale(st->codecpar->frame_size, 48000, st->codecpar->sample_rate);
121 1 break;
122 11 default:
123 11 codec_config->sample_rate = st->codecpar->sample_rate;
124 11 codec_config->nb_samples = st->codecpar->frame_size;
125 11 break;
126 }
127 12 populate_audio_roll_distance(codec_config);
128
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (st->codecpar->extradata_size) {
129 12 codec_config->extradata = av_memdup(st->codecpar->extradata, st->codecpar->extradata_size);
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!codec_config->extradata)
131 return AVERROR(ENOMEM);
132 12 codec_config->extradata_size = st->codecpar->extradata_size;
133 12 ret = update_extradata(codec_config);
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (ret < 0)
135 goto fail;
136 }
137
138
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 for (j = 0; j < iamf->nb_codec_configs; j++) {
139
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!memcmp(iamf->codec_configs[j], codec_config, offsetof(IAMFCodecConfig, extradata)) &&
140
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!codec_config->extradata_size || !memcmp(iamf->codec_configs[j]->extradata,
141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 codec_config->extradata, codec_config->extradata_size)))
142 break;
143 }
144
145
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (j < iamf->nb_codec_configs) {
146 1 av_free(iamf->codec_configs[j]->extradata);
147 1 av_free(iamf->codec_configs[j]);
148 1 iamf->codec_configs[j] = codec_config;
149 1 return j;
150 }
151
152 11 tmp = av_realloc_array(iamf->codec_configs, iamf->nb_codec_configs + 1, sizeof(*iamf->codec_configs));
153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!tmp) {
154 ret = AVERROR(ENOMEM);
155 goto fail;
156 }
157
158 11 iamf->codec_configs = tmp;
159 11 iamf->codec_configs[iamf->nb_codec_configs] = codec_config;
160 11 codec_config->codec_config_id = iamf->nb_codec_configs;
161
162 11 return iamf->nb_codec_configs++;
163
164 fail:
165 av_freep(&codec_config->extradata);
166 return ret;
167 }
168
169 31 static int add_param_definition(IAMFContext *iamf, AVIAMFParamDefinition *param,
170 const IAMFAudioElement *audio_element, void *log_ctx)
171 {
172 IAMFParamDefinition **tmp, *param_definition;
173 31 IAMFCodecConfig *codec_config = NULL;
174
175 31 tmp = av_realloc_array(iamf->param_definitions, iamf->nb_param_definitions + 1,
176 sizeof(*iamf->param_definitions));
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if (!tmp)
178 return AVERROR(ENOMEM);
179
180 31 iamf->param_definitions = tmp;
181
182
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 11 times.
31 if (audio_element)
183 20 codec_config = iamf->codec_configs[audio_element->codec_config_id];
184
185
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 13 times.
31 if (!param->parameter_rate) {
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!codec_config) {
187 av_log(log_ctx, AV_LOG_ERROR, "parameter_rate needed but not set for parameter_id %u\n",
188 param->parameter_id);
189 return AVERROR(EINVAL);
190 }
191 18 param->parameter_rate = codec_config->sample_rate;
192 }
193
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 11 times.
31 if (codec_config) {
194
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 if (!param->duration)
195 18 param->duration = av_rescale(codec_config->nb_samples, param->parameter_rate, codec_config->sample_rate);
196
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 if (!param->constant_subblock_duration)
197 18 param->constant_subblock_duration = av_rescale(codec_config->nb_samples, param->parameter_rate, codec_config->sample_rate);
198 }
199
200 31 param_definition = av_mallocz(sizeof(*param_definition));
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if (!param_definition)
202 return AVERROR(ENOMEM);
203
204 31 param_definition->mode = !!param->duration;
205 31 param_definition->param = param;
206 31 param_definition->audio_element = audio_element;
207 31 iamf->param_definitions[iamf->nb_param_definitions++] = param_definition;
208
209 31 return 0;
210 }
211
212 12 int ff_iamf_add_audio_element(IAMFContext *iamf, const AVStreamGroup *stg, void *log_ctx)
213 {
214 const AVIAMFAudioElement *iamf_audio_element;
215 IAMFAudioElement **tmp, *audio_element;
216 IAMFCodecConfig *codec_config;
217 int ret;
218
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
220 return AVERROR(EINVAL);
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!stg->nb_streams) {
222 av_log(log_ctx, AV_LOG_ERROR, "Audio Element id %"PRId64" has no streams\n", stg->id);
223 return AVERROR(EINVAL);
224 }
225
226 12 iamf_audio_element = stg->params.iamf_audio_element;
227
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
12 if (iamf_audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE) {
228 2 const AVIAMFLayer *layer = iamf_audio_element->layers[0];
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (iamf_audio_element->nb_layers != 1) {
230 av_log(log_ctx, AV_LOG_ERROR, "Invalid amount of layers for SCENE_BASED audio element. Must be 1\n");
231 return AVERROR(EINVAL);
232 }
233
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (layer->ch_layout.order != AV_CHANNEL_ORDER_CUSTOM &&
234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 layer->ch_layout.order != AV_CHANNEL_ORDER_AMBISONIC) {
235 av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout for SCENE_BASED audio element\n");
236 return AVERROR(EINVAL);
237 }
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (layer->ambisonics_mode >= AV_IAMF_AMBISONICS_MODE_PROJECTION) {
239 av_log(log_ctx, AV_LOG_ERROR, "Unsuported ambisonics mode %d\n", layer->ambisonics_mode);
240 return AVERROR_PATCHWELCOME;
241 }
242
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 for (int i = 0; i < stg->nb_streams; i++) {
243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (stg->streams[i]->codecpar->ch_layout.nb_channels > 1) {
244 av_log(log_ctx, AV_LOG_ERROR, "Invalid amount of channels in a stream for MONO mode ambisonics\n");
245 return AVERROR(EINVAL);
246 }
247 }
248 } else
249
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
36 for (int j, i = 0; i < iamf_audio_element->nb_layers; i++) {
250 26 const AVIAMFLayer *layer = iamf_audio_element->layers[i];
251
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 1 times.
128 for (j = 0; j < FF_ARRAY_ELEMS(ff_iamf_scalable_ch_layouts); j++)
252
2/2
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 102 times.
127 if (!av_channel_layout_compare(&layer->ch_layout, &ff_iamf_scalable_ch_layouts[j]))
253 25 break;
254
255
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 25 times.
26 if (j >= FF_ARRAY_ELEMS(ff_iamf_scalable_ch_layouts)) {
256
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 for (j = 0; j < FF_ARRAY_ELEMS(ff_iamf_expanded_scalable_ch_layouts); j++)
257
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 8 times.
9 if (!av_channel_layout_compare(&layer->ch_layout, &ff_iamf_expanded_scalable_ch_layouts[j]))
258 1 break;
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (j >= FF_ARRAY_ELEMS(ff_iamf_expanded_scalable_ch_layouts)) {
260 AVBPrint bp;
261 av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
262 av_channel_layout_describe_bprint(&layer->ch_layout, &bp);
263 av_log(log_ctx, AV_LOG_ERROR, "Unsupported channel layout in Audio Element id %"PRId64
264 ", Layer %d: %s\n",
265 stg->id, i, bp.str);
266 av_bprint_finalize(&bp, NULL);
267 return AVERROR(EINVAL);
268 }
269 }
270 }
271
272
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
13 for (int i = 0; i < iamf->nb_audio_elements; i++) {
273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stg->id == iamf->audio_elements[i]->audio_element_id) {
274 av_log(log_ctx, AV_LOG_ERROR, "Duplicated Audio Element id %"PRId64"\n", stg->id);
275 return AVERROR(EINVAL);
276 }
277 }
278
279 12 codec_config = av_mallocz(sizeof(*codec_config));
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!codec_config)
281 return AVERROR(ENOMEM);
282
283 12 ret = fill_codec_config(iamf, stg, codec_config);
284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (ret < 0) {
285 av_free(codec_config);
286 return ret;
287 }
288
289 12 audio_element = av_mallocz(sizeof(*audio_element));
290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!audio_element)
291 return AVERROR(ENOMEM);
292
293 12 audio_element->celement = stg->params.iamf_audio_element;
294 12 audio_element->audio_element_id = stg->id;
295 12 audio_element->codec_config_id = ret;
296
297 12 audio_element->substreams = av_calloc(stg->nb_streams, sizeof(*audio_element->substreams));
298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!audio_element->substreams) {
299 ret = AVERROR(ENOMEM);
300 goto fail;
301 }
302 12 audio_element->nb_substreams = stg->nb_streams;
303
304 12 audio_element->layers = av_calloc(iamf_audio_element->nb_layers, sizeof(*audio_element->layers));
305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!audio_element->layers) {
306 ret = AVERROR(ENOMEM);
307 goto fail;
308 }
309
310
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 12 times.
40 for (int i = 0, j = 0; i < iamf_audio_element->nb_layers; i++) {
311 28 int nb_channels = iamf_audio_element->layers[i]->ch_layout.nb_channels;
312
313 28 IAMFLayer *layer = &audio_element->layers[i];
314
315
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 12 times.
28 if (i)
316 16 nb_channels -= iamf_audio_element->layers[i - 1]->ch_layout.nb_channels;
317
3/4
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
85 for (; nb_channels > 0 && j < stg->nb_streams; j++) {
318 57 const AVStream *st = stg->streams[j];
319 57 IAMFSubStream *substream = &audio_element->substreams[j];
320
321 57 substream->audio_substream_id = st->id;
322 57 layer->substream_count++;
323 57 layer->coupled_substream_count += st->codecpar->ch_layout.nb_channels == 2;
324 57 nb_channels -= st->codecpar->ch_layout.nb_channels;
325 }
326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (nb_channels) {
327 av_log(log_ctx, AV_LOG_ERROR, "Invalid channel count across substreams in layer %u from stream group %u\n",
328 i, stg->index);
329 ret = AVERROR(EINVAL);
330 goto fail;
331 }
332 }
333
334
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 12 times.
69 for (int i = 0; i < audio_element->nb_substreams; i++) {
335
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 57 times.
204 for (int j = i + 1; j < audio_element->nb_substreams; j++)
336 147 if (audio_element->substreams[i].audio_substream_id ==
337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 audio_element->substreams[j].audio_substream_id) {
338 av_log(log_ctx, AV_LOG_ERROR, "Duplicate id %u in streams %u and %u from stream group %u\n",
339 audio_element->substreams[i].audio_substream_id, i, j, stg->index);
340 ret = AVERROR(EINVAL);
341 goto fail;
342 }
343 }
344
345
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (iamf_audio_element->demixing_info) {
346 12 AVIAMFParamDefinition *param = iamf_audio_element->demixing_info;
347 12 const IAMFParamDefinition *param_definition = ff_iamf_get_param_definition(iamf, param->parameter_id);
348
349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (param->nb_subblocks != 1) {
350 av_log(log_ctx, AV_LOG_ERROR, "nb_subblocks in demixing_info for stream group %u is not 1\n", stg->index);
351 ret = AVERROR(EINVAL);
352 goto fail;
353 }
354
355
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 if (!param_definition) {
356 11 ret = add_param_definition(iamf, param, audio_element, log_ctx);
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ret < 0)
358 goto fail;
359 }
360 }
361
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (iamf_audio_element->recon_gain_info) {
362 12 AVIAMFParamDefinition *param = iamf_audio_element->recon_gain_info;
363 12 const IAMFParamDefinition *param_definition = ff_iamf_get_param_definition(iamf, param->parameter_id);
364
365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (param->nb_subblocks != 1) {
366 av_log(log_ctx, AV_LOG_ERROR, "nb_subblocks in recon_gain_info for stream group %u is not 1\n", stg->index);
367 ret = AVERROR(EINVAL);
368 goto fail;
369 }
370
371
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 if (!param_definition) {
372 9 ret = add_param_definition(iamf, param, audio_element, log_ctx);
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
374 goto fail;
375 }
376 }
377
378 12 tmp = av_realloc_array(iamf->audio_elements, iamf->nb_audio_elements + 1, sizeof(*iamf->audio_elements));
379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!tmp) {
380 ret = AVERROR(ENOMEM);
381 goto fail;
382 }
383
384 12 iamf->audio_elements = tmp;
385 12 iamf->audio_elements[iamf->nb_audio_elements++] = audio_element;
386
387 12 return 0;
388 fail:
389 ff_iamf_free_audio_element(&audio_element);
390 return ret;
391 }
392
393 11 int ff_iamf_add_mix_presentation(IAMFContext *iamf, const AVStreamGroup *stg, void *log_ctx)
394 {
395 IAMFMixPresentation **tmp, *mix_presentation;
396 int ret;
397
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
399 return AVERROR(EINVAL);
400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!stg->nb_streams) {
401 av_log(log_ctx, AV_LOG_ERROR, "Mix Presentation id %"PRId64" has no streams\n", stg->id);
402 return AVERROR(EINVAL);
403 }
404
405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 for (int i = 0; i < iamf->nb_mix_presentations; i++) {
406 if (stg->id == iamf->mix_presentations[i]->mix_presentation_id) {
407 av_log(log_ctx, AV_LOG_ERROR, "Duplicate Mix Presentation id %"PRId64"\n", stg->id);
408 return AVERROR(EINVAL);
409 }
410 }
411
412 11 mix_presentation = av_mallocz(sizeof(*mix_presentation));
413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!mix_presentation)
414 return AVERROR(ENOMEM);
415
416 11 mix_presentation->cmix = stg->params.iamf_mix_presentation;
417 11 mix_presentation->mix_presentation_id = stg->id;
418
419
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 11 times.
24 for (int i = 0; i < mix_presentation->cmix->nb_submixes; i++) {
420 13 const AVIAMFSubmix *submix = mix_presentation->cmix->submixes[i];
421 13 AVIAMFParamDefinition *param = submix->output_mix_config;
422 IAMFParamDefinition *param_definition;
423
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!param) {
425 av_log(log_ctx, AV_LOG_ERROR, "output_mix_config is not present in submix %u from "
426 "Mix Presentation ID %"PRId64"\n", i, stg->id);
427 ret = AVERROR(EINVAL);
428 goto fail;
429 }
430
431 13 param_definition = ff_iamf_get_param_definition(iamf, param->parameter_id);
432
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
13 if (!param_definition) {
433 11 ret = add_param_definition(iamf, param, NULL, log_ctx);
434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ret < 0)
435 goto fail;
436 }
437
438
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 13 times.
27 for (int j = 0; j < submix->nb_elements; j++) {
439 14 const AVIAMFSubmixElement *element = submix->elements[j];
440 14 param = element->element_mix_config;
441
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (!param) {
443 av_log(log_ctx, AV_LOG_ERROR, "element_mix_config is not present for element %u in submix %u from "
444 "Mix Presentation ID %"PRId64"\n", j, i, stg->id);
445 ret = AVERROR(EINVAL);
446 goto fail;
447 }
448 14 param_definition = ff_iamf_get_param_definition(iamf, param->parameter_id);
449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (!param_definition) {
450 ret = add_param_definition(iamf, param, NULL, log_ctx);
451 if (ret < 0)
452 goto fail;
453 }
454 }
455 }
456
457 11 tmp = av_realloc_array(iamf->mix_presentations, iamf->nb_mix_presentations + 1, sizeof(*iamf->mix_presentations));
458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!tmp) {
459 ret = AVERROR(ENOMEM);
460 goto fail;
461 }
462
463 11 iamf->mix_presentations = tmp;
464 11 iamf->mix_presentations[iamf->nb_mix_presentations++] = mix_presentation;
465
466 11 return 0;
467 fail:
468 ff_iamf_free_mix_presentation(&mix_presentation);
469 return ret;
470 }
471
472 16 static int iamf_write_codec_config(const IAMFContext *iamf,
473 const IAMFCodecConfig *codec_config,
474 AVIOContext *pb)
475 {
476 uint8_t header[MAX_IAMF_OBU_HEADER_SIZE];
477 AVIOContext *dyn_bc;
478 16 uint8_t *dyn_buf = NULL;
479 PutBitContext pbc;
480 int dyn_size;
481
482 16 int ret = avio_open_dyn_buf(&dyn_bc);
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (ret < 0)
484 return ret;
485
486 16 ffio_write_leb(dyn_bc, codec_config->codec_config_id);
487 16 avio_wl32(dyn_bc, codec_config->codec_tag);
488
489 16 ffio_write_leb(dyn_bc, codec_config->nb_samples);
490 16 avio_wb16(dyn_bc, codec_config->audio_roll_distance);
491
492
2/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
16 switch(codec_config->codec_id) {
493 1 case AV_CODEC_ID_OPUS:
494 1 avio_write(dyn_bc, codec_config->extradata, codec_config->extradata_size);
495 1 break;
496 case AV_CODEC_ID_AAC:
497 return AVERROR_PATCHWELCOME;
498 15 case AV_CODEC_ID_FLAC:
499 15 avio_w8(dyn_bc, 0x80);
500 15 avio_wb24(dyn_bc, codec_config->extradata_size);
501 15 avio_write(dyn_bc, codec_config->extradata, codec_config->extradata_size);
502 15 break;
503 case AV_CODEC_ID_PCM_S16LE:
504 avio_w8(dyn_bc, 1);
505 avio_w8(dyn_bc, 16);
506 avio_wb32(dyn_bc, codec_config->sample_rate);
507 break;
508 case AV_CODEC_ID_PCM_S24LE:
509 avio_w8(dyn_bc, 1);
510 avio_w8(dyn_bc, 24);
511 avio_wb32(dyn_bc, codec_config->sample_rate);
512 break;
513 case AV_CODEC_ID_PCM_S32LE:
514 avio_w8(dyn_bc, 1);
515 avio_w8(dyn_bc, 32);
516 avio_wb32(dyn_bc, codec_config->sample_rate);
517 break;
518 case AV_CODEC_ID_PCM_S16BE:
519 avio_w8(dyn_bc, 0);
520 avio_w8(dyn_bc, 16);
521 avio_wb32(dyn_bc, codec_config->sample_rate);
522 break;
523 case AV_CODEC_ID_PCM_S24BE:
524 avio_w8(dyn_bc, 0);
525 avio_w8(dyn_bc, 24);
526 avio_wb32(dyn_bc, codec_config->sample_rate);
527 break;
528 case AV_CODEC_ID_PCM_S32BE:
529 avio_w8(dyn_bc, 0);
530 avio_w8(dyn_bc, 32);
531 avio_wb32(dyn_bc, codec_config->sample_rate);
532 break;
533 default:
534 break;
535 }
536
537 16 init_put_bits(&pbc, header, sizeof(header));
538 16 put_bits(&pbc, 5, IAMF_OBU_IA_CODEC_CONFIG);
539 16 put_bits(&pbc, 3, 0);
540 16 flush_put_bits(&pbc);
541
542 16 dyn_size = avio_get_dyn_buf(dyn_bc, &dyn_buf);
543 16 avio_write(pb, header, put_bytes_count(&pbc, 1));
544 16 ffio_write_leb(pb, dyn_size);
545 16 avio_write(pb, dyn_buf, dyn_size);
546 16 ffio_free_dyn_buf(&dyn_bc);
547
548 16 return 0;
549 }
550
551 152 static inline int rescale_rational(AVRational q, int b)
552 {
553 152 return av_clip_int16(av_rescale(q.num, b, q.den));
554 }
555
556 15 static int scalable_channel_layout_config(const IAMFAudioElement *audio_element,
557 AVIOContext *dyn_bc)
558 {
559 15 const AVIAMFAudioElement *element = audio_element->celement;
560 uint8_t header[MAX_IAMF_OBU_HEADER_SIZE];
561 PutBitContext pb;
562
563 15 init_put_bits(&pb, header, sizeof(header));
564 15 put_bits(&pb, 3, element->nb_layers);
565 15 put_bits(&pb, 5, 0);
566 15 flush_put_bits(&pb);
567 15 avio_write(dyn_bc, header, put_bytes_count(&pb, 1));
568
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 15 times.
52 for (int i = 0; i < element->nb_layers; i++) {
569 37 const AVIAMFLayer *layer = element->layers[i];
570 37 int layout, expanded_layout = -1;
571
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 2 times.
183 for (layout = 0; layout < FF_ARRAY_ELEMS(ff_iamf_scalable_ch_layouts); layout++) {
572
2/2
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 146 times.
181 if (!av_channel_layout_compare(&layer->ch_layout, &ff_iamf_scalable_ch_layouts[layout]))
573 35 break;
574 }
575
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 35 times.
37 if (layout >= FF_ARRAY_ELEMS(ff_iamf_scalable_ch_layouts))
576
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 for (expanded_layout = 0; expanded_layout < FF_ARRAY_ELEMS(ff_iamf_scalable_ch_layouts); expanded_layout++) {
577
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 16 times.
18 if (!av_channel_layout_compare(&layer->ch_layout, &ff_iamf_expanded_scalable_ch_layouts[expanded_layout]))
578 2 break;
579 }
580
3/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35 times.
37 av_assert0(expanded_layout > 0 || layout < FF_ARRAY_ELEMS(ff_iamf_scalable_ch_layouts));
581 37 init_put_bits(&pb, header, sizeof(header));
582
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 2 times.
37 put_bits(&pb, 4, expanded_layout >= 0 ? 15 : layout);
583 37 put_bits(&pb, 1, !!layer->output_gain_flags);
584 37 put_bits(&pb, 1, !!(layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN));
585 37 put_bits(&pb, 2, 0); // reserved
586 37 put_bits(&pb, 8, audio_element->layers[i].substream_count);
587 37 put_bits(&pb, 8, audio_element->layers[i].coupled_substream_count);
588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (layer->output_gain_flags) {
589 put_bits(&pb, 6, layer->output_gain_flags);
590 put_bits(&pb, 2, 0);
591 put_bits(&pb, 16, rescale_rational(layer->output_gain, 1 << 8));
592 }
593
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 35 times.
37 if (expanded_layout >= 0)
594 2 put_bits(&pb, 8, expanded_layout);
595 37 flush_put_bits(&pb);
596 37 avio_write(dyn_bc, header, put_bytes_count(&pb, 1));
597 }
598
599 15 return 0;
600 }
601
602 3 static int ambisonics_config(const IAMFAudioElement *audio_element,
603 AVIOContext *dyn_bc)
604 {
605 3 const AVIAMFAudioElement *element = audio_element->celement;
606 3 const AVIAMFLayer *layer = element->layers[0];
607
608 3 ffio_write_leb(dyn_bc, 0); // ambisonics_mode
609 3 ffio_write_leb(dyn_bc, layer->ch_layout.nb_channels); // output_channel_count
610 3 ffio_write_leb(dyn_bc, audio_element->nb_substreams); // substream_count
611
612
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (layer->ch_layout.order == AV_CHANNEL_ORDER_AMBISONIC)
613
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
15 for (int i = 0; i < layer->ch_layout.nb_channels; i++)
614 12 avio_w8(dyn_bc, i);
615 else
616 for (int i = 0; i < layer->ch_layout.nb_channels; i++)
617 avio_w8(dyn_bc, layer->ch_layout.u.map[i].id);
618
619 3 return 0;
620 }
621
622 49 static int param_definition(const IAMFContext *iamf,
623 const IAMFParamDefinition *param_def,
624 AVIOContext *dyn_bc, void *log_ctx)
625 {
626 49 const AVIAMFParamDefinition *param = param_def->param;
627
628 49 ffio_write_leb(dyn_bc, param->parameter_id);
629 49 ffio_write_leb(dyn_bc, param->parameter_rate);
630
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 40 times.
49 avio_w8(dyn_bc, param->duration ? 0 : 1 << 7);
631
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 40 times.
49 if (param->duration) {
632 9 ffio_write_leb(dyn_bc, param->duration);
633 9 ffio_write_leb(dyn_bc, param->constant_subblock_duration);
634
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (param->constant_subblock_duration == 0) {
635 ffio_write_leb(dyn_bc, param->nb_subblocks);
636 for (int i = 0; i < param->nb_subblocks; i++) {
637 const void *subblock = av_iamf_param_definition_get_subblock(param, i);
638
639 switch (param->type) {
640 case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: {
641 const AVIAMFMixGain *mix = subblock;
642 ffio_write_leb(dyn_bc, mix->subblock_duration);
643 break;
644 }
645 case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: {
646 const AVIAMFDemixingInfo *demix = subblock;
647 ffio_write_leb(dyn_bc, demix->subblock_duration);
648 break;
649 }
650 case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: {
651 const AVIAMFReconGain *recon = subblock;
652 ffio_write_leb(dyn_bc, recon->subblock_duration);
653 break;
654 }
655 }
656 }
657 }
658 }
659
660 49 return 0;
661 }
662
663 18 static int iamf_write_audio_element(const IAMFContext *iamf,
664 const IAMFAudioElement *audio_element,
665 AVIOContext *pb, void *log_ctx)
666 {
667 18 const AVIAMFAudioElement *element = audio_element->celement;
668 18 const IAMFCodecConfig *codec_config = iamf->codec_configs[audio_element->codec_config_id];
669 uint8_t header[MAX_IAMF_OBU_HEADER_SIZE];
670 AVIOContext *dyn_bc;
671 18 uint8_t *dyn_buf = NULL;
672 PutBitContext pbc;
673 18 int param_definition_types = AV_IAMF_PARAMETER_DEFINITION_DEMIXING, dyn_size;
674
675 18 int ret = avio_open_dyn_buf(&dyn_bc);
676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (ret < 0)
677 return ret;
678
679 18 ffio_write_leb(dyn_bc, audio_element->audio_element_id);
680
681 18 init_put_bits(&pbc, header, sizeof(header));
682 18 put_bits(&pbc, 3, element->audio_element_type);
683 18 put_bits(&pbc, 5, 0);
684 18 flush_put_bits(&pbc);
685 18 avio_write(dyn_bc, header, put_bytes_count(&pbc, 1));
686
687 18 ffio_write_leb(dyn_bc, audio_element->codec_config_id);
688 18 ffio_write_leb(dyn_bc, audio_element->nb_substreams);
689
690
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 18 times.
103 for (int i = 0; i < audio_element->nb_substreams; i++)
691 85 ffio_write_leb(dyn_bc, audio_element->substreams[i].audio_substream_id);
692
693
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 8 times.
18 if (element->nb_layers == 1)
694 10 param_definition_types &= ~AV_IAMF_PARAMETER_DEFINITION_DEMIXING;
695
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (element->nb_layers > 1)
696 8 param_definition_types |= AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN;
697
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 if (codec_config->codec_tag == MKTAG('f','L','a','C') ||
698
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 codec_config->codec_tag == MKTAG('i','p','c','m'))
699 17 param_definition_types &= ~AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN;
700
701 18 ffio_write_leb(dyn_bc, av_popcount(param_definition_types)); // num_parameters
702
703
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (param_definition_types & 1) {
704 8 const AVIAMFParamDefinition *param = element->demixing_info;
705 const IAMFParamDefinition *param_def;
706 const AVIAMFDemixingInfo *demix;
707
708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!param) {
709 av_log(log_ctx, AV_LOG_ERROR, "demixing_info needed but not set in Stream Group #%u\n",
710 audio_element->audio_element_id);
711 return AVERROR(EINVAL);
712 }
713
714 8 demix = av_iamf_param_definition_get_subblock(param, 0);
715 8 ffio_write_leb(dyn_bc, AV_IAMF_PARAMETER_DEFINITION_DEMIXING); // type
716
717 8 param_def = ff_iamf_get_param_definition(iamf, param->parameter_id);
718 8 ret = param_definition(iamf, param_def, dyn_bc, log_ctx);
719
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (ret < 0)
720 return ret;
721
722 8 avio_w8(dyn_bc, demix->dmixp_mode << 5); // dmixp_mode
723 8 avio_w8(dyn_bc, element->default_w << 4); // default_w
724 }
725
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 if (param_definition_types & 2) {
726 1 const AVIAMFParamDefinition *param = element->recon_gain_info;
727 const IAMFParamDefinition *param_def;
728
729
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!param) {
730 av_log(log_ctx, AV_LOG_ERROR, "recon_gain_info needed but not set in Stream Group #%u\n",
731 audio_element->audio_element_id);
732 return AVERROR(EINVAL);
733 }
734 1 ffio_write_leb(dyn_bc, AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN); // type
735
736 1 param_def = ff_iamf_get_param_definition(iamf, param->parameter_id);
737 1 ret = param_definition(iamf, param_def, dyn_bc, log_ctx);
738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
739 return ret;
740 }
741
742
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if (element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL) {
743 15 ret = scalable_channel_layout_config(audio_element, dyn_bc);
744
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (ret < 0)
745 return ret;
746 } else {
747 3 ret = ambisonics_config(audio_element, dyn_bc);
748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ret < 0)
749 return ret;
750 }
751
752 18 init_put_bits(&pbc, header, sizeof(header));
753 18 put_bits(&pbc, 5, IAMF_OBU_IA_AUDIO_ELEMENT);
754 18 put_bits(&pbc, 3, 0);
755 18 flush_put_bits(&pbc);
756
757 18 dyn_size = avio_get_dyn_buf(dyn_bc, &dyn_buf);
758 18 avio_write(pb, header, put_bytes_count(&pbc, 1));
759 18 ffio_write_leb(pb, dyn_size);
760 18 avio_write(pb, dyn_buf, dyn_size);
761 18 ffio_free_dyn_buf(&dyn_bc);
762
763 18 return 0;
764 }
765
766 16 static int iamf_write_mixing_presentation(const IAMFContext *iamf,
767 const IAMFMixPresentation *mix_presentation,
768 AVIOContext *pb, void *log_ctx)
769 {
770 uint8_t header[MAX_IAMF_OBU_HEADER_SIZE];
771 16 const AVIAMFMixPresentation *mix = mix_presentation->cmix;
772 16 const AVDictionaryEntry *tag = NULL;
773 PutBitContext pbc;
774 AVIOContext *dyn_bc;
775 16 uint8_t *dyn_buf = NULL;
776 int dyn_size;
777
778 16 int ret = avio_open_dyn_buf(&dyn_bc);
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (ret < 0)
780 return ret;
781
782 16 ffio_write_leb(dyn_bc, mix_presentation->mix_presentation_id); // mix_presentation_id
783 16 ffio_write_leb(dyn_bc, av_dict_count(mix->annotations)); // count_label
784
785
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
32 while ((tag = av_dict_iterate(mix->annotations, tag)))
786 16 avio_put_str(dyn_bc, tag->key);
787
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
32 while ((tag = av_dict_iterate(mix->annotations, tag)))
788 16 avio_put_str(dyn_bc, tag->value);
789
790 16 ffio_write_leb(dyn_bc, mix->nb_submixes);
791
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 16 times.
35 for (int i = 0; i < mix->nb_submixes; i++) {
792 19 const AVIAMFSubmix *sub_mix = mix->submixes[i];
793 const IAMFParamDefinition *param_def;
794
795 19 ffio_write_leb(dyn_bc, sub_mix->nb_elements);
796
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 19 times.
40 for (int j = 0; j < sub_mix->nb_elements; j++) {
797 21 const IAMFAudioElement *audio_element = NULL;
798 21 const AVIAMFSubmixElement *submix_element = sub_mix->elements[j];
799
800
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 for (int k = 0; k < iamf->nb_audio_elements; k++)
801
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
23 if (iamf->audio_elements[k]->audio_element_id == submix_element->audio_element_id) {
802 21 audio_element = iamf->audio_elements[k];
803 21 break;
804 }
805
806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 av_assert0(audio_element);
807 21 ffio_write_leb(dyn_bc, submix_element->audio_element_id);
808
809
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
21 if (av_dict_count(submix_element->annotations) != av_dict_count(mix->annotations)) {
810 av_log(log_ctx, AV_LOG_ERROR, "Inconsistent amount of labels in submix %d from Mix Presentation id #%u\n",
811 j, audio_element->audio_element_id);
812 return AVERROR(EINVAL);
813 }
814
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 21 times.
42 while ((tag = av_dict_iterate(submix_element->annotations, tag)))
815 21 avio_put_str(dyn_bc, tag->value);
816
817 21 init_put_bits(&pbc, header, sizeof(header));
818 21 put_bits(&pbc, 2, submix_element->headphones_rendering_mode);
819 21 put_bits(&pbc, 6, 0); // reserved
820 21 flush_put_bits(&pbc);
821 21 avio_write(dyn_bc, header, put_bytes_count(&pbc, 1));
822 21 ffio_write_leb(dyn_bc, 0); // rendering_config_extension_size
823
824 21 param_def = ff_iamf_get_param_definition(iamf, submix_element->element_mix_config->parameter_id);
825 21 ret = param_definition(iamf, param_def, dyn_bc, log_ctx);
826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (ret < 0)
827 return ret;
828
829 21 avio_wb16(dyn_bc, rescale_rational(submix_element->default_mix_gain, 1 << 8));
830 }
831
832 19 param_def = ff_iamf_get_param_definition(iamf, sub_mix->output_mix_config->parameter_id);
833 19 ret = param_definition(iamf, param_def, dyn_bc, log_ctx);
834
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (ret < 0)
835 return ret;
836 19 avio_wb16(dyn_bc, rescale_rational(sub_mix->default_mix_gain, 1 << 8));
837
838 19 ffio_write_leb(dyn_bc, sub_mix->nb_layouts); // nb_layouts
839
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 19 times.
62 for (int i = 0; i < sub_mix->nb_layouts; i++) {
840 43 const AVIAMFSubmixLayout *submix_layout = sub_mix->layouts[i];
841 int layout, info_type;
842
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
43 int dialogue = submix_layout->dialogue_anchored_loudness.num &&
843 submix_layout->dialogue_anchored_loudness.den;
844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
43 int album = submix_layout->album_anchored_loudness.num &&
845 submix_layout->album_anchored_loudness.den;
846
847
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 3 times.
43 if (submix_layout->layout_type == AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS) {
848
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 for (layout = 0; layout < FF_ARRAY_ELEMS(ff_iamf_sound_system_map); layout++) {
849
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 165 times.
205 if (!av_channel_layout_compare(&submix_layout->sound_system, &ff_iamf_sound_system_map[layout].layout))
850 40 break;
851 }
852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (layout == FF_ARRAY_ELEMS(ff_iamf_sound_system_map)) {
853 av_log(log_ctx, AV_LOG_ERROR, "Invalid Sound System value in a submix\n");
854 return AVERROR(EINVAL);
855 }
856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (submix_layout->layout_type != AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL) {
857 av_log(log_ctx, AV_LOG_ERROR, "Unsupported Layout Type value in a submix\n");
858 return AVERROR(EINVAL);
859 }
860 43 init_put_bits(&pbc, header, sizeof(header));
861 43 put_bits(&pbc, 2, submix_layout->layout_type); // layout_type
862
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 3 times.
43 if (submix_layout->layout_type == AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS) {
863 40 put_bits(&pbc, 4, ff_iamf_sound_system_map[layout].id); // sound_system
864 40 put_bits(&pbc, 2, 0); // reserved
865 } else
866 3 put_bits(&pbc, 6, 0); // reserved
867 43 flush_put_bits(&pbc);
868 43 avio_write(dyn_bc, header, put_bytes_count(&pbc, 1));
869
870
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
43 info_type = (submix_layout->true_peak.num && submix_layout->true_peak.den);
871
2/4
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43 times.
43 info_type |= (dialogue || album) << 1;
872 43 avio_w8(dyn_bc, info_type);
873 43 avio_wb16(dyn_bc, rescale_rational(submix_layout->integrated_loudness, 1 << 8));
874 43 avio_wb16(dyn_bc, rescale_rational(submix_layout->digital_peak, 1 << 8));
875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
43 if (info_type & 1)
876 avio_wb16(dyn_bc, rescale_rational(submix_layout->true_peak, 1 << 8));
877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
43 if (info_type & 2) {
878 avio_w8(dyn_bc, dialogue + album); // num_anchored_loudness
879 if (dialogue) {
880 avio_w8(dyn_bc, IAMF_ANCHOR_ELEMENT_DIALOGUE);
881 avio_wb16(dyn_bc, rescale_rational(submix_layout->dialogue_anchored_loudness, 1 << 8));
882 }
883 if (album) {
884 avio_w8(dyn_bc, IAMF_ANCHOR_ELEMENT_ALBUM);
885 avio_wb16(dyn_bc, rescale_rational(submix_layout->album_anchored_loudness, 1 << 8));
886 }
887 }
888 }
889 }
890
891 16 init_put_bits(&pbc, header, sizeof(header));
892 16 put_bits(&pbc, 5, IAMF_OBU_IA_MIX_PRESENTATION);
893 16 put_bits(&pbc, 3, 0);
894 16 flush_put_bits(&pbc);
895
896 16 dyn_size = avio_get_dyn_buf(dyn_bc, &dyn_buf);
897 16 avio_write(pb, header, put_bytes_count(&pbc, 1));
898 16 ffio_write_leb(pb, dyn_size);
899 16 avio_write(pb, dyn_buf, dyn_size);
900 16 ffio_free_dyn_buf(&dyn_bc);
901
902 16 return 0;
903 }
904
905 16 int ff_iamf_write_descriptors(const IAMFContext *iamf, AVIOContext *pb, void *log_ctx)
906 {
907 int ret;
908
909 // Sequence Header
910 16 avio_w8(pb, IAMF_OBU_IA_SEQUENCE_HEADER << 3);
911
912 16 ffio_write_leb(pb, 6);
913 16 avio_wb32(pb, MKBETAG('i','a','m','f'));
914 16 avio_w8(pb, iamf->nb_audio_elements > 1); // primary_profile
915 16 avio_w8(pb, iamf->nb_audio_elements > 1); // additional_profile
916
917
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 for (int i = 0; i < iamf->nb_codec_configs; i++) {
918 16 ret = iamf_write_codec_config(iamf, iamf->codec_configs[i], pb);
919
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (ret < 0)
920 return ret;
921 }
922
923
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 16 times.
34 for (int i = 0; i < iamf->nb_audio_elements; i++) {
924 18 ret = iamf_write_audio_element(iamf, iamf->audio_elements[i], pb, log_ctx);
925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (ret < 0)
926 return ret;
927 }
928
929
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 for (int i = 0; i < iamf->nb_mix_presentations; i++) {
930 16 ret = iamf_write_mixing_presentation(iamf, iamf->mix_presentations[i], pb, log_ctx);
931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (ret < 0)
932 return ret;
933 }
934
935 16 return 0;
936 }
937
938 52 static int write_parameter_block(const IAMFContext *iamf, AVIOContext *pb,
939 const AVIAMFParamDefinition *param, void *log_ctx)
940 {
941 uint8_t header[MAX_IAMF_OBU_HEADER_SIZE];
942 52 const IAMFParamDefinition *param_definition = ff_iamf_get_param_definition(iamf, param->parameter_id);
943 PutBitContext pbc;
944 AVIOContext *dyn_bc;
945 52 uint8_t *dyn_buf = NULL;
946 int dyn_size, ret;
947
948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (param->type > AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN) {
949 av_log(log_ctx, AV_LOG_DEBUG, "Ignoring side data with unknown type %u\n",
950 param->type);
951 return 0;
952 }
953
954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (!param_definition) {
955 av_log(log_ctx, AV_LOG_ERROR, "Non-existent Parameter Definition with ID %u referenced by a packet\n",
956 param->parameter_id);
957 return AVERROR(EINVAL);
958 }
959
960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (param->type != param_definition->param->type) {
961 av_log(log_ctx, AV_LOG_ERROR, "Inconsistent values for Parameter Definition "
962 "with ID %u in a packet\n",
963 param->parameter_id);
964 return AVERROR(EINVAL);
965 }
966
967 52 ret = avio_open_dyn_buf(&dyn_bc);
968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (ret < 0)
969 return ret;
970
971 // Sequence Header
972 52 init_put_bits(&pbc, header, sizeof(header));
973 52 put_bits(&pbc, 5, IAMF_OBU_IA_PARAMETER_BLOCK);
974 52 put_bits(&pbc, 3, 0);
975 52 flush_put_bits(&pbc);
976 52 avio_write(pb, header, put_bytes_count(&pbc, 1));
977
978 52 ffio_write_leb(dyn_bc, param->parameter_id);
979
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 if (!param_definition->mode) {
980 26 ffio_write_leb(dyn_bc, param->duration);
981 26 ffio_write_leb(dyn_bc, param->constant_subblock_duration);
982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (param->constant_subblock_duration == 0)
983 ffio_write_leb(dyn_bc, param->nb_subblocks);
984 }
985
986
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 52 times.
104 for (int i = 0; i < param->nb_subblocks; i++) {
987 52 const void *subblock = av_iamf_param_definition_get_subblock(param, i);
988
989
2/4
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
52 switch (param->type) {
990 26 case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: {
991 26 const AVIAMFMixGain *mix = subblock;
992
2/4
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
26 if (!param_definition->mode && param->constant_subblock_duration == 0)
993 ffio_write_leb(dyn_bc, mix->subblock_duration);
994
995 26 ffio_write_leb(dyn_bc, mix->animation_type);
996
997 26 avio_wb16(dyn_bc, rescale_rational(mix->start_point_value, 1 << 8));
998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (mix->animation_type >= AV_IAMF_ANIMATION_TYPE_LINEAR)
999 avio_wb16(dyn_bc, rescale_rational(mix->end_point_value, 1 << 8));
1000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (mix->animation_type == AV_IAMF_ANIMATION_TYPE_BEZIER) {
1001 avio_wb16(dyn_bc, rescale_rational(mix->control_point_value, 1 << 8));
1002 avio_w8(dyn_bc, av_clip_uint8(av_rescale(mix->control_point_relative_time.num, 1 << 8,
1003 mix->control_point_relative_time.den)));
1004 }
1005 26 break;
1006 }
1007 case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: {
1008 const AVIAMFDemixingInfo *demix = subblock;
1009 if (!param_definition->mode && param->constant_subblock_duration == 0)
1010 ffio_write_leb(dyn_bc, demix->subblock_duration);
1011
1012 avio_w8(dyn_bc, demix->dmixp_mode << 5);
1013 break;
1014 }
1015 26 case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: {
1016 26 const AVIAMFReconGain *recon = subblock;
1017 26 const AVIAMFAudioElement *audio_element = param_definition->audio_element->celement;
1018
1019
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26 if (!param_definition->mode && param->constant_subblock_duration == 0)
1020 ffio_write_leb(dyn_bc, recon->subblock_duration);
1021
1022
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (!audio_element) {
1023 av_log(log_ctx, AV_LOG_ERROR, "Invalid Parameter Definition with ID %u referenced by a packet\n", param->parameter_id);
1024 return AVERROR(EINVAL);
1025 }
1026
1027
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 26 times.
78 for (int j = 0; j < audio_element->nb_layers; j++) {
1028 52 const AVIAMFLayer *layer = audio_element->layers[j];
1029
1030
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 if (layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN) {
1031 26 unsigned int recon_gain_flags = 0;
1032 26 int k = 0;
1033
1034
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 26 times.
208 for (; k < 7; k++)
1035 182 recon_gain_flags |= (1 << k) * !!recon->recon_gain[j][k];
1036
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 26 times.
156 for (; k < 12; k++)
1037 130 recon_gain_flags |= (2 << k) * !!recon->recon_gain[j][k];
1038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (recon_gain_flags >> 8)
1039 recon_gain_flags |= (1 << k);
1040
1041 26 ffio_write_leb(dyn_bc, recon_gain_flags);
1042
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 26 times.
338 for (k = 0; k < 12; k++) {
1043
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 208 times.
312 if (recon->recon_gain[j][k])
1044 104 avio_w8(dyn_bc, recon->recon_gain[j][k]);
1045 }
1046 }
1047 }
1048 26 break;
1049 }
1050 default:
1051 av_assert0(0);
1052 }
1053 }
1054
1055 52 dyn_size = avio_get_dyn_buf(dyn_bc, &dyn_buf);
1056 52 ffio_write_leb(pb, dyn_size);
1057 52 avio_write(pb, dyn_buf, dyn_size);
1058 52 ffio_free_dyn_buf(&dyn_bc);
1059
1060 52 return 0;
1061 }
1062
1063 136 int ff_iamf_write_parameter_blocks(const IAMFContext *iamf, AVIOContext *pb,
1064 const AVPacket *pkt, void *log_ctx)
1065 {
1066 AVIAMFParamDefinition *mix =
1067 136 (AVIAMFParamDefinition *)av_packet_get_side_data(pkt,
1068 AV_PKT_DATA_IAMF_MIX_GAIN_PARAM,
1069 NULL);
1070 AVIAMFParamDefinition *demix =
1071 136 (AVIAMFParamDefinition *)av_packet_get_side_data(pkt,
1072 AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM,
1073 NULL);
1074 AVIAMFParamDefinition *recon =
1075 136 (AVIAMFParamDefinition *)av_packet_get_side_data(pkt,
1076 AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM,
1077 NULL);
1078
1079
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 110 times.
136 if (mix) {
1080 26 int ret = write_parameter_block(iamf, pb, mix, log_ctx);
1081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (ret < 0)
1082 return ret;
1083 }
1084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
136 if (demix) {
1085 int ret = write_parameter_block(iamf, pb, demix, log_ctx);
1086 if (ret < 0)
1087 return ret;
1088 }
1089
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 110 times.
136 if (recon) {
1090 26 int ret = write_parameter_block(iamf, pb, recon, log_ctx);
1091
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (ret < 0)
1092 return ret;
1093 }
1094
1095 136 return 0;
1096 }
1097
1098 53 static IAMFAudioElement *get_audio_element(const IAMFContext *c,
1099 unsigned int audio_substream_id)
1100 {
1101
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 for (int i = 0; i < c->nb_audio_elements; i++) {
1102 54 IAMFAudioElement *audio_element = c->audio_elements[i];
1103
2/2
✓ Branch 0 taken 203 times.
✓ Branch 1 taken 1 times.
204 for (int j = 0; j < audio_element->nb_substreams; j++) {
1104 203 IAMFSubStream *substream = &audio_element->substreams[j];
1105
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 150 times.
203 if (substream->audio_substream_id == audio_substream_id)
1106 53 return audio_element;
1107 }
1108 }
1109
1110 return NULL;
1111 }
1112
1113 687 int ff_iamf_write_audio_frame(const IAMFContext *iamf, AVIOContext *pb,
1114 unsigned audio_substream_id, const AVPacket *pkt)
1115 {
1116 uint8_t header[MAX_IAMF_OBU_HEADER_SIZE];
1117 PutBitContext pbc;
1118 AVIOContext *dyn_bc;
1119 const uint8_t *side_data;
1120 687 uint8_t *dyn_buf = NULL;
1121 687 unsigned int skip_samples = 0, discard_padding = 0;
1122 size_t side_data_size;
1123 687 int dyn_size, type = audio_substream_id <= 17 ?
1124
1/2
✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
687 audio_substream_id + IAMF_OBU_IA_AUDIO_FRAME_ID0 : IAMF_OBU_IA_AUDIO_FRAME;
1125 int ret;
1126
1127
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 634 times.
687 if (!pkt->size) {
1128 const IAMFAudioElement *audio_element;
1129 IAMFCodecConfig *codec_config;
1130 size_t new_extradata_size;
1131 53 const uint8_t *new_extradata = av_packet_get_side_data(pkt,
1132 AV_PKT_DATA_NEW_EXTRADATA,
1133 &new_extradata_size);
1134
1135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (!new_extradata)
1136 return AVERROR_INVALIDDATA;
1137 53 audio_element = get_audio_element(iamf, audio_substream_id);
1138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (!audio_element)
1139 return AVERROR(EINVAL);
1140 53 codec_config = ff_iamf_get_codec_config(iamf, audio_element->codec_config_id);
1141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (!codec_config)
1142 return AVERROR(EINVAL);
1143
1144 53 av_free(codec_config->extradata);
1145 53 codec_config->extradata = av_memdup(new_extradata, new_extradata_size);
1146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (!codec_config->extradata) {
1147 codec_config->extradata_size = 0;
1148 return AVERROR(ENOMEM);
1149 }
1150 53 codec_config->extradata_size = new_extradata_size;
1151
1152 53 return update_extradata(codec_config);
1153 }
1154
1155 634 side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES,
1156 &side_data_size);
1157
1158
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 626 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
634 if (side_data && side_data_size >= 10) {
1159 8 skip_samples = AV_RL32(side_data);
1160 8 discard_padding = AV_RL32(side_data + 4);
1161 }
1162
1163 634 ret = avio_open_dyn_buf(&dyn_bc);
1164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 634 times.
634 if (ret < 0)
1165 return ret;
1166
1167 634 init_put_bits(&pbc, header, sizeof(header));
1168 634 put_bits(&pbc, 5, type);
1169 634 put_bits(&pbc, 1, 0); // obu_redundant_copy
1170
4/4
✓ Branch 0 taken 630 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 626 times.
634 put_bits(&pbc, 1, skip_samples || discard_padding);
1171 634 put_bits(&pbc, 1, 0); // obu_extension_flag
1172 634 flush_put_bits(&pbc);
1173 634 avio_write(pb, header, put_bytes_count(&pbc, 1));
1174
1175
4/4
✓ Branch 0 taken 630 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 626 times.
634 if (skip_samples || discard_padding) {
1176 8 ffio_write_leb(dyn_bc, discard_padding);
1177 8 ffio_write_leb(dyn_bc, skip_samples);
1178 }
1179
1180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 634 times.
634 if (audio_substream_id > 17)
1181 ffio_write_leb(dyn_bc, audio_substream_id);
1182
1183 634 dyn_size = avio_get_dyn_buf(dyn_bc, &dyn_buf);
1184 634 ffio_write_leb(pb, dyn_size + pkt->size);
1185 634 avio_write(pb, dyn_buf, dyn_size);
1186 634 ffio_free_dyn_buf(&dyn_bc);
1187 634 avio_write(pb, pkt->data, pkt->size);
1188
1189 634 return 0;
1190 }
1191