FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/iamf_writer.c
Date: 2026-10-15 22:25:26
Exec Total Coverage
Lines: 597 849 70.3%
Functions: 19 19 100.0%
Branches: 306 481 63.6%

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