FFmpeg coverage


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