FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/iamf_writer.c
Date: 2026-08-31 11:24:46
Exec Total Coverage
Lines: 588 839 70.1%
Functions: 19 19 100.0%
Branches: 298 473 63.0%

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