FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/iamf_writer.c
Date: 2026-05-03 03:13:14
Exec Total Coverage
Lines: 586 834 70.3%
Functions: 19 19 100.0%
Branches: 293 469 62.5%

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