FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/iamf_writer.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 511 735 69.5%
Functions: 18 18 100.0%
Branches: 229 383 59.8%

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