Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Immersive Audio Model and Formats parsing | ||
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/avassert.h" | ||
23 | #include "libavutil/iamf.h" | ||
24 | #include "libavutil/intreadwrite.h" | ||
25 | #include "libavutil/log.h" | ||
26 | #include "libavutil/mem.h" | ||
27 | #include "libavcodec/get_bits.h" | ||
28 | #include "libavcodec/flac.h" | ||
29 | #include "libavcodec/leb.h" | ||
30 | #include "libavcodec/mpeg4audio.h" | ||
31 | #include "libavcodec/put_bits.h" | ||
32 | #include "avio_internal.h" | ||
33 | #include "iamf_parse.h" | ||
34 | #include "isom.h" | ||
35 | |||
36 | 5 | static int opus_decoder_config(IAMFCodecConfig *codec_config, | |
37 | AVIOContext *pb, int len) | ||
38 | { | ||
39 | 5 | int left = len - avio_tell(pb); | |
40 | |||
41 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (left < 11) |
42 | ✗ | return AVERROR_INVALIDDATA; | |
43 | |||
44 | 5 | codec_config->extradata = av_malloc(left + 8); | |
45 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (!codec_config->extradata) |
46 | ✗ | return AVERROR(ENOMEM); | |
47 | |||
48 | 5 | AV_WB32(codec_config->extradata, MKBETAG('O','p','u','s')); | |
49 | 5 | AV_WB32(codec_config->extradata + 4, MKBETAG('H','e','a','d')); | |
50 | 5 | codec_config->extradata_size = avio_read(pb, codec_config->extradata + 8, left); | |
51 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (codec_config->extradata_size < left) |
52 | ✗ | return AVERROR_INVALIDDATA; | |
53 | |||
54 | 5 | codec_config->extradata_size += 8; | |
55 | 5 | codec_config->sample_rate = 48000; | |
56 | |||
57 | 5 | return 0; | |
58 | } | ||
59 | |||
60 | ✗ | static int aac_decoder_config(IAMFCodecConfig *codec_config, | |
61 | AVIOContext *pb, int len, void *logctx) | ||
62 | { | ||
63 | ✗ | MPEG4AudioConfig cfg = { 0 }; | |
64 | int object_type_id, codec_id, stream_type; | ||
65 | int ret, tag, left; | ||
66 | |||
67 | ✗ | tag = avio_r8(pb); | |
68 | ✗ | if (tag != MP4DecConfigDescrTag) | |
69 | ✗ | return AVERROR_INVALIDDATA; | |
70 | |||
71 | ✗ | object_type_id = avio_r8(pb); | |
72 | ✗ | if (object_type_id != 0x40) | |
73 | ✗ | return AVERROR_INVALIDDATA; | |
74 | |||
75 | ✗ | stream_type = avio_r8(pb); | |
76 | ✗ | if (((stream_type >> 2) != 5) || ((stream_type >> 1) & 1)) | |
77 | ✗ | return AVERROR_INVALIDDATA; | |
78 | |||
79 | ✗ | avio_skip(pb, 3); // buffer size db | |
80 | ✗ | avio_skip(pb, 4); // rc_max_rate | |
81 | ✗ | avio_skip(pb, 4); // avg bitrate | |
82 | |||
83 | ✗ | codec_id = ff_codec_get_id(ff_mp4_obj_type, object_type_id); | |
84 | ✗ | if (codec_id && codec_id != codec_config->codec_id) | |
85 | ✗ | return AVERROR_INVALIDDATA; | |
86 | |||
87 | ✗ | tag = avio_r8(pb); | |
88 | ✗ | if (tag != MP4DecSpecificDescrTag) | |
89 | ✗ | return AVERROR_INVALIDDATA; | |
90 | |||
91 | ✗ | left = len - avio_tell(pb); | |
92 | ✗ | if (left <= 0) | |
93 | ✗ | return AVERROR_INVALIDDATA; | |
94 | |||
95 | ✗ | codec_config->extradata = av_malloc(left); | |
96 | ✗ | if (!codec_config->extradata) | |
97 | ✗ | return AVERROR(ENOMEM); | |
98 | |||
99 | ✗ | codec_config->extradata_size = avio_read(pb, codec_config->extradata, left); | |
100 | ✗ | if (codec_config->extradata_size < left) | |
101 | ✗ | return AVERROR_INVALIDDATA; | |
102 | |||
103 | ✗ | ret = avpriv_mpeg4audio_get_config2(&cfg, codec_config->extradata, | |
104 | codec_config->extradata_size, 1, logctx); | ||
105 | ✗ | if (ret < 0) | |
106 | ✗ | return ret; | |
107 | |||
108 | ✗ | codec_config->sample_rate = cfg.sample_rate; | |
109 | |||
110 | ✗ | return 0; | |
111 | } | ||
112 | |||
113 | 16 | static int flac_decoder_config(IAMFCodecConfig *codec_config, | |
114 | AVIOContext *pb, int len) | ||
115 | { | ||
116 | int left; | ||
117 | |||
118 | 16 | avio_skip(pb, 4); // METADATA_BLOCK_HEADER | |
119 | |||
120 | 16 | left = len - avio_tell(pb); | |
121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (left < FLAC_STREAMINFO_SIZE) |
122 | ✗ | return AVERROR_INVALIDDATA; | |
123 | |||
124 | 16 | codec_config->extradata = av_malloc(left); | |
125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (!codec_config->extradata) |
126 | ✗ | return AVERROR(ENOMEM); | |
127 | |||
128 | 16 | codec_config->extradata_size = avio_read(pb, codec_config->extradata, left); | |
129 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (codec_config->extradata_size < left) |
130 | ✗ | return AVERROR_INVALIDDATA; | |
131 | |||
132 | 16 | codec_config->sample_rate = AV_RB24(codec_config->extradata + 10) >> 4; | |
133 | |||
134 | 16 | return 0; | |
135 | } | ||
136 | |||
137 | ✗ | static int ipcm_decoder_config(IAMFCodecConfig *codec_config, | |
138 | AVIOContext *pb, int len) | ||
139 | { | ||
140 | static const enum AVCodecID sample_fmt[2][3] = { | ||
141 | { AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S24BE, AV_CODEC_ID_PCM_S32BE }, | ||
142 | { AV_CODEC_ID_PCM_S16LE, AV_CODEC_ID_PCM_S24LE, AV_CODEC_ID_PCM_S32LE }, | ||
143 | }; | ||
144 | ✗ | int sample_format = avio_r8(pb); // 0 = BE, 1 = LE | |
145 | ✗ | int sample_size = (avio_r8(pb) / 8 - 2); // 16, 24, 32 | |
146 | ✗ | if (sample_format > 1 || sample_size > 2) | |
147 | ✗ | return AVERROR_INVALIDDATA; | |
148 | |||
149 | ✗ | codec_config->codec_id = sample_fmt[sample_format][sample_size]; | |
150 | ✗ | codec_config->sample_rate = avio_rb32(pb); | |
151 | |||
152 | ✗ | if (len - avio_tell(pb)) | |
153 | ✗ | return AVERROR_INVALIDDATA; | |
154 | |||
155 | ✗ | return 0; | |
156 | } | ||
157 | |||
158 | 21 | static int codec_config_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) | |
159 | { | ||
160 | 21 | IAMFCodecConfig **tmp, *codec_config = NULL; | |
161 | FFIOContext b; | ||
162 | AVIOContext *pbc; | ||
163 | uint8_t *buf; | ||
164 | enum AVCodecID avcodec_id; | ||
165 | unsigned codec_config_id, nb_samples, codec_id; | ||
166 | int16_t seek_preroll; | ||
167 | int ret; | ||
168 | |||
169 | 21 | buf = av_malloc(len); | |
170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!buf) |
171 | ✗ | return AVERROR(ENOMEM); | |
172 | |||
173 | 21 | ret = avio_read(pb, buf, len); | |
174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret != len) { |
175 | ✗ | if (ret >= 0) | |
176 | ✗ | ret = AVERROR_INVALIDDATA; | |
177 | ✗ | goto fail; | |
178 | } | ||
179 | |||
180 | 21 | ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); | |
181 | 21 | pbc = &b.pub; | |
182 | |||
183 | 21 | codec_config_id = ffio_read_leb(pbc); | |
184 | 21 | codec_id = avio_rb32(pbc); | |
185 | 21 | nb_samples = ffio_read_leb(pbc); | |
186 | 21 | seek_preroll = avio_rb16(pbc); | |
187 | |||
188 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
21 | switch(codec_id) { |
189 | 5 | case MKBETAG('O','p','u','s'): | |
190 | 5 | avcodec_id = AV_CODEC_ID_OPUS; | |
191 | 5 | break; | |
192 | ✗ | case MKBETAG('m','p','4','a'): | |
193 | ✗ | avcodec_id = AV_CODEC_ID_AAC; | |
194 | ✗ | break; | |
195 | 16 | case MKBETAG('f','L','a','C'): | |
196 | 16 | avcodec_id = AV_CODEC_ID_FLAC; | |
197 | 16 | break; | |
198 | ✗ | default: | |
199 | ✗ | avcodec_id = AV_CODEC_ID_NONE; | |
200 | ✗ | break; | |
201 | } | ||
202 | |||
203 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | for (int i = 0; i < c->nb_codec_configs; i++) |
204 | ✗ | if (c->codec_configs[i]->codec_config_id == codec_config_id) { | |
205 | ✗ | ret = AVERROR_INVALIDDATA; | |
206 | ✗ | goto fail; | |
207 | } | ||
208 | |||
209 | 21 | tmp = av_realloc_array(c->codec_configs, c->nb_codec_configs + 1, sizeof(*c->codec_configs)); | |
210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!tmp) { |
211 | ✗ | ret = AVERROR(ENOMEM); | |
212 | ✗ | goto fail; | |
213 | } | ||
214 | 21 | c->codec_configs = tmp; | |
215 | |||
216 | 21 | codec_config = av_mallocz(sizeof(*codec_config)); | |
217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!codec_config) { |
218 | ✗ | ret = AVERROR(ENOMEM); | |
219 | ✗ | goto fail; | |
220 | } | ||
221 | |||
222 | 21 | codec_config->codec_config_id = codec_config_id; | |
223 | 21 | codec_config->codec_id = avcodec_id; | |
224 | 21 | codec_config->nb_samples = nb_samples; | |
225 | 21 | codec_config->seek_preroll = seek_preroll; | |
226 | |||
227 |
2/5✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
21 | switch(codec_id) { |
228 | 5 | case MKBETAG('O','p','u','s'): | |
229 | 5 | ret = opus_decoder_config(codec_config, pbc, len); | |
230 | 5 | break; | |
231 | ✗ | case MKBETAG('m','p','4','a'): | |
232 | ✗ | ret = aac_decoder_config(codec_config, pbc, len, s); | |
233 | ✗ | break; | |
234 | 16 | case MKBETAG('f','L','a','C'): | |
235 | 16 | ret = flac_decoder_config(codec_config, pbc, len); | |
236 | 16 | break; | |
237 | ✗ | case MKBETAG('i','p','c','m'): | |
238 | ✗ | ret = ipcm_decoder_config(codec_config, pbc, len); | |
239 | ✗ | break; | |
240 | ✗ | default: | |
241 | ✗ | break; | |
242 | } | ||
243 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret < 0) |
244 | ✗ | goto fail; | |
245 | |||
246 | 21 | c->codec_configs[c->nb_codec_configs++] = codec_config; | |
247 | |||
248 | 21 | len -= avio_tell(pbc); | |
249 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (len) |
250 | ✗ | av_log(s, AV_LOG_WARNING, "Underread in codec_config_obu. %d bytes left at the end\n", len); | |
251 | |||
252 | 21 | ret = 0; | |
253 | 21 | fail: | |
254 | 21 | av_free(buf); | |
255 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret < 0) { |
256 | ✗ | if (codec_config) | |
257 | ✗ | av_free(codec_config->extradata); | |
258 | ✗ | av_free(codec_config); | |
259 | } | ||
260 | 21 | return ret; | |
261 | } | ||
262 | |||
263 | 92 | static int update_extradata(AVCodecParameters *codecpar) | |
264 | { | ||
265 | GetBitContext gb; | ||
266 | PutBitContext pb; | ||
267 | int ret; | ||
268 | |||
269 |
2/4✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
|
92 | switch(codecpar->codec_id) { |
270 | 20 | case AV_CODEC_ID_OPUS: | |
271 | 20 | AV_WB8(codecpar->extradata + 9, codecpar->ch_layout.nb_channels); | |
272 | 20 | break; | |
273 | ✗ | case AV_CODEC_ID_AAC: { | |
274 | uint8_t buf[5]; | ||
275 | |||
276 | ✗ | init_put_bits(&pb, buf, sizeof(buf)); | |
277 | ✗ | ret = init_get_bits8(&gb, codecpar->extradata, codecpar->extradata_size); | |
278 | ✗ | if (ret < 0) | |
279 | ✗ | return ret; | |
280 | |||
281 | ✗ | ret = get_bits(&gb, 5); | |
282 | ✗ | put_bits(&pb, 5, ret); | |
283 | ✗ | if (ret == AOT_ESCAPE) // violates section 3.11.2, but better check for it | |
284 | ✗ | put_bits(&pb, 6, get_bits(&gb, 6)); | |
285 | ✗ | ret = get_bits(&gb, 4); | |
286 | ✗ | put_bits(&pb, 4, ret); | |
287 | ✗ | if (ret == 0x0f) | |
288 | ✗ | put_bits(&pb, 24, get_bits(&gb, 24)); | |
289 | |||
290 | ✗ | skip_bits(&gb, 4); | |
291 | ✗ | put_bits(&pb, 4, codecpar->ch_layout.nb_channels); // set channel config | |
292 | ✗ | ret = put_bits_left(&pb); | |
293 | ✗ | put_bits(&pb, ret, get_bits(&gb, ret)); | |
294 | ✗ | flush_put_bits(&pb); | |
295 | |||
296 | ✗ | memcpy(codecpar->extradata, buf, sizeof(buf)); | |
297 | ✗ | break; | |
298 | } | ||
299 | 72 | case AV_CODEC_ID_FLAC: { | |
300 | uint8_t buf[13]; | ||
301 | |||
302 | 72 | init_put_bits(&pb, buf, sizeof(buf)); | |
303 | 72 | ret = init_get_bits8(&gb, codecpar->extradata, codecpar->extradata_size); | |
304 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
|
72 | if (ret < 0) |
305 | ✗ | return ret; | |
306 | |||
307 | 72 | put_bits32(&pb, get_bits_long(&gb, 32)); // min/max blocksize | |
308 | 72 | put_bits64(&pb, 48, get_bits64(&gb, 48)); // min/max framesize | |
309 | 72 | put_bits(&pb, 20, get_bits(&gb, 20)); // samplerate | |
310 | 72 | skip_bits(&gb, 3); | |
311 | 72 | put_bits(&pb, 3, codecpar->ch_layout.nb_channels - 1); | |
312 | 72 | ret = put_bits_left(&pb); | |
313 | 72 | put_bits(&pb, ret, get_bits(&gb, ret)); | |
314 | 72 | flush_put_bits(&pb); | |
315 | |||
316 | 72 | memcpy(codecpar->extradata, buf, sizeof(buf)); | |
317 | 72 | break; | |
318 | } | ||
319 | } | ||
320 | |||
321 | 92 | return 0; | |
322 | } | ||
323 | |||
324 | 17 | static int scalable_channel_layout_config(void *s, AVIOContext *pb, | |
325 | IAMFAudioElement *audio_element, | ||
326 | const IAMFCodecConfig *codec_config) | ||
327 | { | ||
328 | 17 | int nb_layers, k = 0; | |
329 | |||
330 | 17 | nb_layers = avio_r8(pb) >> 5; // get_bits(&gb, 3); | |
331 | // skip_bits(&gb, 5); //reserved | ||
332 | |||
333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (nb_layers > 6) |
334 | ✗ | return AVERROR_INVALIDDATA; | |
335 | |||
336 | 17 | audio_element->layers = av_calloc(nb_layers, sizeof(*audio_element->layers)); | |
337 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!audio_element->layers) |
338 | ✗ | return AVERROR(ENOMEM); | |
339 | |||
340 | 17 | audio_element->nb_layers = nb_layers; | |
341 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 17 times.
|
63 | for (int i = 0; i < nb_layers; i++) { |
342 | AVIAMFLayer *layer; | ||
343 | int loudspeaker_layout, output_gain_is_present_flag; | ||
344 | int substream_count, coupled_substream_count; | ||
345 | 46 | int ret, byte = avio_r8(pb); | |
346 | |||
347 | 46 | layer = av_iamf_audio_element_add_layer(audio_element->element); | |
348 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (!layer) |
349 | ✗ | return AVERROR(ENOMEM); | |
350 | |||
351 | 46 | loudspeaker_layout = byte >> 4; // get_bits(&gb, 4); | |
352 | 46 | output_gain_is_present_flag = (byte >> 3) & 1; //get_bits1(&gb); | |
353 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 41 times.
|
46 | if ((byte >> 2) & 1) |
354 | 5 | layer->flags |= AV_IAMF_LAYER_FLAG_RECON_GAIN; | |
355 | 46 | substream_count = avio_r8(pb); | |
356 | 46 | coupled_substream_count = avio_r8(pb); | |
357 | |||
358 | 46 | audio_element->layers[i].substream_count = substream_count; | |
359 | 46 | audio_element->layers[i].coupled_substream_count = coupled_substream_count; | |
360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | if (output_gain_is_present_flag) { |
361 | ✗ | layer->output_gain_flags = avio_r8(pb) >> 2; // get_bits(&gb, 6); | |
362 | ✗ | layer->output_gain = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); | |
363 | } | ||
364 | |||
365 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | if (loudspeaker_layout < 10) |
366 | 46 | av_channel_layout_copy(&layer->ch_layout, &ff_iamf_scalable_ch_layouts[loudspeaker_layout]); | |
367 | else | ||
368 | ✗ | layer->ch_layout = (AVChannelLayout){ .order = AV_CHANNEL_ORDER_UNSPEC, | |
369 | ✗ | .nb_channels = substream_count + | |
370 | coupled_substream_count }; | ||
371 | |||
372 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 46 times.
|
122 | for (int j = 0; j < substream_count; j++) { |
373 | 76 | IAMFSubStream *substream = &audio_element->substreams[k++]; | |
374 | |||
375 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 26 times.
|
76 | substream->codecpar->ch_layout = coupled_substream_count-- > 0 ? (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO : |
376 | (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | ||
377 | |||
378 | 76 | ret = update_extradata(substream->codecpar); | |
379 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
|
76 | if (ret < 0) |
380 | ✗ | return ret; | |
381 | } | ||
382 | |||
383 | } | ||
384 | |||
385 | 17 | return 0; | |
386 | } | ||
387 | |||
388 | 4 | static int ambisonics_config(void *s, AVIOContext *pb, | |
389 | IAMFAudioElement *audio_element, | ||
390 | const IAMFCodecConfig *codec_config) | ||
391 | { | ||
392 | AVIAMFLayer *layer; | ||
393 | unsigned ambisonics_mode; | ||
394 | int output_channel_count, substream_count, order; | ||
395 | int ret; | ||
396 | |||
397 | 4 | ambisonics_mode = ffio_read_leb(pb); | |
398 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (ambisonics_mode > 1) |
399 | ✗ | return 0; | |
400 | |||
401 | 4 | output_channel_count = avio_r8(pb); // C | |
402 | 4 | substream_count = avio_r8(pb); // N | |
403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (audio_element->nb_substreams != substream_count) |
404 | ✗ | return AVERROR_INVALIDDATA; | |
405 | |||
406 | 4 | order = floor(sqrt(output_channel_count - 1)); | |
407 | /* incomplete order - some harmonics are missing */ | ||
408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if ((order + 1) * (order + 1) != output_channel_count) |
409 | ✗ | return AVERROR_INVALIDDATA; | |
410 | |||
411 | 4 | audio_element->layers = av_mallocz(sizeof(*audio_element->layers)); | |
412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!audio_element->layers) |
413 | ✗ | return AVERROR(ENOMEM); | |
414 | |||
415 | 4 | audio_element->nb_layers = 1; | |
416 | 4 | audio_element->layers->substream_count = substream_count; | |
417 | |||
418 | 4 | layer = av_iamf_audio_element_add_layer(audio_element->element); | |
419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!layer) |
420 | ✗ | return AVERROR(ENOMEM); | |
421 | |||
422 | 4 | layer->ambisonics_mode = ambisonics_mode; | |
423 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (ambisonics_mode == 0) { |
424 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
|
20 | for (int i = 0; i < substream_count; i++) { |
425 | 16 | IAMFSubStream *substream = &audio_element->substreams[i]; | |
426 | |||
427 | 16 | substream->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | |
428 | |||
429 | 16 | ret = update_extradata(substream->codecpar); | |
430 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (ret < 0) |
431 | ✗ | return ret; | |
432 | } | ||
433 | |||
434 | 4 | layer->ch_layout.order = AV_CHANNEL_ORDER_CUSTOM; | |
435 | 4 | layer->ch_layout.nb_channels = output_channel_count; | |
436 | 4 | layer->ch_layout.u.map = av_calloc(output_channel_count, sizeof(*layer->ch_layout.u.map)); | |
437 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!layer->ch_layout.u.map) |
438 | ✗ | return AVERROR(ENOMEM); | |
439 | |||
440 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
|
20 | for (int i = 0; i < output_channel_count; i++) |
441 | 16 | layer->ch_layout.u.map[i].id = avio_r8(pb) + AV_CHAN_AMBISONIC_BASE; | |
442 | } else { | ||
443 | ✗ | int coupled_substream_count = avio_r8(pb); // M | |
444 | ✗ | int nb_demixing_matrix = substream_count + coupled_substream_count; | |
445 | ✗ | int demixing_matrix_size = nb_demixing_matrix * output_channel_count; | |
446 | |||
447 | ✗ | audio_element->layers->coupled_substream_count = coupled_substream_count; | |
448 | |||
449 | ✗ | layer->ch_layout = (AVChannelLayout){ .order = AV_CHANNEL_ORDER_AMBISONIC, .nb_channels = output_channel_count }; | |
450 | ✗ | layer->demixing_matrix = av_malloc_array(demixing_matrix_size, sizeof(*layer->demixing_matrix)); | |
451 | ✗ | if (!layer->demixing_matrix) | |
452 | ✗ | return AVERROR(ENOMEM); | |
453 | |||
454 | ✗ | for (int i = 0; i < demixing_matrix_size; i++) | |
455 | ✗ | layer->demixing_matrix[i] = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); | |
456 | |||
457 | ✗ | for (int i = 0; i < substream_count; i++) { | |
458 | ✗ | IAMFSubStream *substream = &audio_element->substreams[i]; | |
459 | |||
460 | ✗ | substream->codecpar->ch_layout = coupled_substream_count-- > 0 ? (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO : | |
461 | (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | ||
462 | |||
463 | |||
464 | ✗ | ret = update_extradata(substream->codecpar); | |
465 | ✗ | if (ret < 0) | |
466 | ✗ | return ret; | |
467 | } | ||
468 | } | ||
469 | |||
470 | 4 | return 0; | |
471 | } | ||
472 | |||
473 | 68 | static int param_parse(void *s, IAMFContext *c, AVIOContext *pb, | |
474 | unsigned int type, | ||
475 | const IAMFAudioElement *audio_element, | ||
476 | AVIAMFParamDefinition **out_param_definition) | ||
477 | { | ||
478 | 68 | IAMFParamDefinition *param_definition = NULL; | |
479 | AVIAMFParamDefinition *param; | ||
480 | unsigned int parameter_id, parameter_rate, mode; | ||
481 | 68 | unsigned int duration = 0, constant_subblock_duration = 0, nb_subblocks = 0; | |
482 | size_t param_size; | ||
483 | |||
484 | 68 | parameter_id = ffio_read_leb(pb); | |
485 | |||
486 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 39 times.
|
109 | for (int i = 0; i < c->nb_param_definitions; i++) |
487 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 41 times.
|
70 | if (c->param_definitions[i]->param->parameter_id == parameter_id) { |
488 | 29 | param_definition = c->param_definitions[i]; | |
489 | 29 | break; | |
490 | } | ||
491 | |||
492 | 68 | parameter_rate = ffio_read_leb(pb); | |
493 | 68 | mode = avio_r8(pb) >> 7; | |
494 | |||
495 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 50 times.
|
68 | if (mode == 0) { |
496 | 18 | duration = ffio_read_leb(pb); | |
497 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!duration) |
498 | ✗ | return AVERROR_INVALIDDATA; | |
499 | 18 | constant_subblock_duration = ffio_read_leb(pb); | |
500 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (constant_subblock_duration == 0) |
501 | ✗ | nb_subblocks = ffio_read_leb(pb); | |
502 | else | ||
503 | 18 | nb_subblocks = duration / constant_subblock_duration; | |
504 | } | ||
505 | |||
506 | 68 | param = av_iamf_param_definition_alloc(type, nb_subblocks, ¶m_size); | |
507 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
|
68 | if (!param) |
508 | ✗ | return AVERROR(ENOMEM); | |
509 | |||
510 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 68 times.
|
86 | for (int i = 0; i < nb_subblocks; i++) { |
511 | 18 | void *subblock = av_iamf_param_definition_get_subblock(param, i); | |
512 | 18 | unsigned int subblock_duration = constant_subblock_duration; | |
513 | |||
514 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (constant_subblock_duration == 0) |
515 | ✗ | subblock_duration = ffio_read_leb(pb); | |
516 | |||
517 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
18 | switch (type) { |
518 | ✗ | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { | |
519 | ✗ | AVIAMFMixGain *mix = subblock; | |
520 | ✗ | mix->subblock_duration = subblock_duration; | |
521 | ✗ | break; | |
522 | } | ||
523 | 13 | case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: { | |
524 | 13 | AVIAMFDemixingInfo *demix = subblock; | |
525 | 13 | demix->subblock_duration = subblock_duration; | |
526 | // DefaultDemixingInfoParameterData | ||
527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | av_assert0(audio_element); |
528 | 13 | demix->dmixp_mode = avio_r8(pb) >> 5; | |
529 | 13 | audio_element->element->default_w = avio_r8(pb) >> 4; | |
530 | 13 | break; | |
531 | } | ||
532 | 5 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: { | |
533 | 5 | AVIAMFReconGain *recon = subblock; | |
534 | 5 | recon->subblock_duration = subblock_duration; | |
535 | 5 | break; | |
536 | } | ||
537 | ✗ | default: | |
538 | ✗ | av_free(param); | |
539 | ✗ | return AVERROR_INVALIDDATA; | |
540 | } | ||
541 | } | ||
542 | |||
543 | 68 | param->parameter_id = parameter_id; | |
544 | 68 | param->parameter_rate = parameter_rate; | |
545 | 68 | param->duration = duration; | |
546 | 68 | param->constant_subblock_duration = constant_subblock_duration; | |
547 | 68 | param->nb_subblocks = nb_subblocks; | |
548 | |||
549 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 39 times.
|
68 | if (param_definition) { |
550 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29 times.
|
29 | if (param_definition->param_size != param_size || memcmp(param_definition->param, param, param_size)) { |
551 | ✗ | av_log(s, AV_LOG_ERROR, "Incosistent parameters for parameter_id %u\n", parameter_id); | |
552 | ✗ | av_free(param); | |
553 | ✗ | return AVERROR_INVALIDDATA; | |
554 | } | ||
555 | } else { | ||
556 | 39 | IAMFParamDefinition **tmp = av_realloc_array(c->param_definitions, c->nb_param_definitions + 1, | |
557 | sizeof(*c->param_definitions)); | ||
558 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | if (!tmp) { |
559 | ✗ | av_free(param); | |
560 | ✗ | return AVERROR(ENOMEM); | |
561 | } | ||
562 | 39 | c->param_definitions = tmp; | |
563 | |||
564 | 39 | param_definition = av_mallocz(sizeof(*param_definition)); | |
565 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | if (!param_definition) { |
566 | ✗ | av_free(param); | |
567 | ✗ | return AVERROR(ENOMEM); | |
568 | } | ||
569 | 39 | param_definition->param = param; | |
570 | 39 | param_definition->mode = !mode; | |
571 | 39 | param_definition->param_size = param_size; | |
572 | 39 | param_definition->audio_element = audio_element; | |
573 | |||
574 | 39 | c->param_definitions[c->nb_param_definitions++] = param_definition; | |
575 | } | ||
576 | |||
577 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
|
68 | av_assert0(out_param_definition); |
578 | 68 | *out_param_definition = param; | |
579 | |||
580 | 68 | return 0; | |
581 | } | ||
582 | |||
583 | 21 | static int audio_element_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) | |
584 | { | ||
585 | const IAMFCodecConfig *codec_config; | ||
586 | AVIAMFAudioElement *element; | ||
587 | 21 | IAMFAudioElement **tmp, *audio_element = NULL; | |
588 | FFIOContext b; | ||
589 | AVIOContext *pbc; | ||
590 | uint8_t *buf; | ||
591 | unsigned audio_element_id, codec_config_id, num_parameters; | ||
592 | int audio_element_type, ret; | ||
593 | |||
594 | 21 | buf = av_malloc(len); | |
595 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!buf) |
596 | ✗ | return AVERROR(ENOMEM); | |
597 | |||
598 | 21 | ret = avio_read(pb, buf, len); | |
599 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret != len) { |
600 | ✗ | if (ret >= 0) | |
601 | ✗ | ret = AVERROR_INVALIDDATA; | |
602 | ✗ | goto fail; | |
603 | } | ||
604 | |||
605 | 21 | ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); | |
606 | 21 | pbc = &b.pub; | |
607 | |||
608 | 21 | audio_element_id = ffio_read_leb(pbc); | |
609 | |||
610 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | for (int i = 0; i < c->nb_audio_elements; i++) |
611 | ✗ | if (c->audio_elements[i]->audio_element_id == audio_element_id) { | |
612 | ✗ | av_log(s, AV_LOG_ERROR, "Duplicate audio_element_id %d\n", audio_element_id); | |
613 | ✗ | ret = AVERROR_INVALIDDATA; | |
614 | ✗ | goto fail; | |
615 | } | ||
616 | |||
617 | 21 | audio_element_type = avio_r8(pbc) >> 5; | |
618 | 21 | codec_config_id = ffio_read_leb(pbc); | |
619 | |||
620 | 21 | codec_config = ff_iamf_get_codec_config(c, codec_config_id); | |
621 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!codec_config) { |
622 | ✗ | av_log(s, AV_LOG_ERROR, "Non existant codec config id %d referenced in an audio element\n", codec_config_id); | |
623 | ✗ | ret = AVERROR_INVALIDDATA; | |
624 | ✗ | goto fail; | |
625 | } | ||
626 | |||
627 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (codec_config->codec_id == AV_CODEC_ID_NONE) { |
628 | ✗ | av_log(s, AV_LOG_DEBUG, "Unknown codec id referenced in an audio element. Ignoring\n"); | |
629 | ✗ | ret = 0; | |
630 | ✗ | goto fail; | |
631 | } | ||
632 | |||
633 | 21 | tmp = av_realloc_array(c->audio_elements, c->nb_audio_elements + 1, sizeof(*c->audio_elements)); | |
634 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!tmp) { |
635 | ✗ | ret = AVERROR(ENOMEM); | |
636 | ✗ | goto fail; | |
637 | } | ||
638 | 21 | c->audio_elements = tmp; | |
639 | |||
640 | 21 | audio_element = av_mallocz(sizeof(*audio_element)); | |
641 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!audio_element) { |
642 | ✗ | ret = AVERROR(ENOMEM); | |
643 | ✗ | goto fail; | |
644 | } | ||
645 | |||
646 | 21 | audio_element->nb_substreams = ffio_read_leb(pbc); | |
647 | 21 | audio_element->codec_config_id = codec_config_id; | |
648 | 21 | audio_element->audio_element_id = audio_element_id; | |
649 | 21 | audio_element->substreams = av_calloc(audio_element->nb_substreams, sizeof(*audio_element->substreams)); | |
650 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!audio_element->substreams) { |
651 | ✗ | ret = AVERROR(ENOMEM); | |
652 | ✗ | goto fail; | |
653 | } | ||
654 | |||
655 | 21 | element = audio_element->element = av_iamf_audio_element_alloc(); | |
656 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!element) { |
657 | ✗ | ret = AVERROR(ENOMEM); | |
658 | ✗ | goto fail; | |
659 | } | ||
660 | 21 | audio_element->celement = element; | |
661 | |||
662 | 21 | element->audio_element_type = audio_element_type; | |
663 | |||
664 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 21 times.
|
113 | for (int i = 0; i < audio_element->nb_substreams; i++) { |
665 | 92 | IAMFSubStream *substream = &audio_element->substreams[i]; | |
666 | |||
667 | 92 | substream->codecpar = avcodec_parameters_alloc(); | |
668 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
|
92 | if (!substream->codecpar) { |
669 | ✗ | ret = AVERROR(ENOMEM); | |
670 | ✗ | goto fail; | |
671 | } | ||
672 | |||
673 | 92 | substream->audio_substream_id = ffio_read_leb(pbc); | |
674 | |||
675 | 92 | substream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; | |
676 | 92 | substream->codecpar->codec_id = codec_config->codec_id; | |
677 | 92 | substream->codecpar->frame_size = codec_config->nb_samples; | |
678 | 92 | substream->codecpar->sample_rate = codec_config->sample_rate; | |
679 | 92 | substream->codecpar->seek_preroll = codec_config->seek_preroll; | |
680 | |||
681 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
92 | switch(substream->codecpar->codec_id) { |
682 | 92 | case AV_CODEC_ID_AAC: | |
683 | case AV_CODEC_ID_FLAC: | ||
684 | case AV_CODEC_ID_OPUS: | ||
685 | 92 | substream->codecpar->extradata = av_malloc(codec_config->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); | |
686 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
|
92 | if (!substream->codecpar->extradata) { |
687 | ✗ | ret = AVERROR(ENOMEM); | |
688 | ✗ | goto fail; | |
689 | } | ||
690 | 92 | memcpy(substream->codecpar->extradata, codec_config->extradata, codec_config->extradata_size); | |
691 | 92 | memset(substream->codecpar->extradata + codec_config->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); | |
692 | 92 | substream->codecpar->extradata_size = codec_config->extradata_size; | |
693 | 92 | break; | |
694 | } | ||
695 | } | ||
696 | |||
697 | 21 | num_parameters = ffio_read_leb(pbc); | |
698 |
3/4✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
21 | if (num_parameters && audio_element_type != 0) { |
699 | ✗ | av_log(s, AV_LOG_ERROR, "Audio Element parameter count %u is invalid" | |
700 | " for Scene representations\n", num_parameters); | ||
701 | ✗ | ret = AVERROR_INVALIDDATA; | |
702 | ✗ | goto fail; | |
703 | } | ||
704 | |||
705 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 21 times.
|
39 | for (int i = 0; i < num_parameters; i++) { |
706 | unsigned type; | ||
707 | |||
708 | 18 | type = ffio_read_leb(pbc); | |
709 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (type == AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN) |
710 | ✗ | ret = AVERROR_INVALIDDATA; | |
711 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
|
18 | else if (type == AV_IAMF_PARAMETER_DEFINITION_DEMIXING) |
712 | 13 | ret = param_parse(s, c, pbc, type, audio_element, &element->demixing_info); | |
713 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | else if (type == AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN) |
714 | 5 | ret = param_parse(s, c, pbc, type, audio_element, &element->recon_gain_info); | |
715 | else { | ||
716 | ✗ | unsigned param_definition_size = ffio_read_leb(pbc); | |
717 | ✗ | avio_skip(pbc, param_definition_size); | |
718 | } | ||
719 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (ret < 0) |
720 | ✗ | goto fail; | |
721 | } | ||
722 | |||
723 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
|
21 | if (audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL) { |
724 | 17 | ret = scalable_channel_layout_config(s, pbc, audio_element, codec_config); | |
725 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (ret < 0) |
726 | ✗ | goto fail; | |
727 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | } else if (audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE) { |
728 | 4 | ret = ambisonics_config(s, pbc, audio_element, codec_config); | |
729 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (ret < 0) |
730 | ✗ | goto fail; | |
731 | } else { | ||
732 | ✗ | unsigned audio_element_config_size = ffio_read_leb(pbc); | |
733 | ✗ | avio_skip(pbc, audio_element_config_size); | |
734 | } | ||
735 | |||
736 | 21 | c->audio_elements[c->nb_audio_elements++] = audio_element; | |
737 | |||
738 | 21 | len -= avio_tell(pbc); | |
739 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (len) |
740 | ✗ | av_log(s, AV_LOG_WARNING, "Underread in audio_element_obu. %d bytes left at the end\n", len); | |
741 | |||
742 | 21 | ret = 0; | |
743 | 21 | fail: | |
744 | 21 | av_free(buf); | |
745 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret < 0) |
746 | ✗ | ff_iamf_free_audio_element(&audio_element); | |
747 | 21 | return ret; | |
748 | } | ||
749 | |||
750 | 67 | static int label_string(AVIOContext *pb, char **label) | |
751 | { | ||
752 | uint8_t buf[128]; | ||
753 | |||
754 | 67 | avio_get_str(pb, sizeof(buf), buf, sizeof(buf)); | |
755 | |||
756 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | if (pb->error) |
757 | ✗ | return pb->error; | |
758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | if (pb->eof_reached) |
759 | ✗ | return AVERROR_INVALIDDATA; | |
760 | 67 | *label = av_strdup(buf); | |
761 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | if (!*label) |
762 | ✗ | return AVERROR(ENOMEM); | |
763 | |||
764 | 67 | return 0; | |
765 | } | ||
766 | |||
767 | 21 | static int mix_presentation_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) | |
768 | { | ||
769 | AVIAMFMixPresentation *mix; | ||
770 | 21 | IAMFMixPresentation **tmp, *mix_presentation = NULL; | |
771 | FFIOContext b; | ||
772 | AVIOContext *pbc; | ||
773 | uint8_t *buf; | ||
774 | unsigned nb_submixes, mix_presentation_id; | ||
775 | int ret; | ||
776 | |||
777 | 21 | buf = av_malloc(len); | |
778 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!buf) |
779 | ✗ | return AVERROR(ENOMEM); | |
780 | |||
781 | 21 | ret = avio_read(pb, buf, len); | |
782 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret != len) { |
783 | ✗ | if (ret >= 0) | |
784 | ✗ | ret = AVERROR_INVALIDDATA; | |
785 | ✗ | goto fail; | |
786 | } | ||
787 | |||
788 | 21 | ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); | |
789 | 21 | pbc = &b.pub; | |
790 | |||
791 | 21 | mix_presentation_id = ffio_read_leb(pbc); | |
792 | |||
793 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | for (int i = 0; i < c->nb_mix_presentations; i++) |
794 | ✗ | if (c->mix_presentations[i]->mix_presentation_id == mix_presentation_id) { | |
795 | ✗ | av_log(s, AV_LOG_ERROR, "Duplicate mix_presentation_id %d\n", mix_presentation_id); | |
796 | ✗ | ret = AVERROR_INVALIDDATA; | |
797 | ✗ | goto fail; | |
798 | } | ||
799 | |||
800 | 21 | tmp = av_realloc_array(c->mix_presentations, c->nb_mix_presentations + 1, sizeof(*c->mix_presentations)); | |
801 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!tmp) { |
802 | ✗ | ret = AVERROR(ENOMEM); | |
803 | ✗ | goto fail; | |
804 | } | ||
805 | 21 | c->mix_presentations = tmp; | |
806 | |||
807 | 21 | mix_presentation = av_mallocz(sizeof(*mix_presentation)); | |
808 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!mix_presentation) { |
809 | ✗ | ret = AVERROR(ENOMEM); | |
810 | ✗ | goto fail; | |
811 | } | ||
812 | |||
813 | 21 | mix_presentation->mix_presentation_id = mix_presentation_id; | |
814 | 21 | mix = mix_presentation->mix = av_iamf_mix_presentation_alloc(); | |
815 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!mix) { |
816 | ✗ | ret = AVERROR(ENOMEM); | |
817 | ✗ | goto fail; | |
818 | } | ||
819 | 21 | mix_presentation->cmix = mix; | |
820 | |||
821 | 21 | mix_presentation->count_label = ffio_read_leb(pbc); | |
822 | 21 | mix_presentation->language_label = av_calloc(mix_presentation->count_label, | |
823 | sizeof(*mix_presentation->language_label)); | ||
824 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (!mix_presentation->language_label) { |
825 | ✗ | mix_presentation->count_label = 0; | |
826 | ✗ | ret = AVERROR(ENOMEM); | |
827 | ✗ | goto fail; | |
828 | } | ||
829 | |||
830 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
|
42 | for (int i = 0; i < mix_presentation->count_label; i++) { |
831 | 21 | ret = label_string(pbc, &mix_presentation->language_label[i]); | |
832 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret < 0) |
833 | ✗ | goto fail; | |
834 | } | ||
835 | |||
836 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
|
42 | for (int i = 0; i < mix_presentation->count_label; i++) { |
837 | 21 | char *annotation = NULL; | |
838 | 21 | ret = label_string(pbc, &annotation); | |
839 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret < 0) |
840 | ✗ | goto fail; | |
841 | 21 | ret = av_dict_set(&mix->annotations, mix_presentation->language_label[i], annotation, | |
842 | AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE); | ||
843 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret < 0) |
844 | ✗ | goto fail; | |
845 | } | ||
846 | |||
847 | 21 | nb_submixes = ffio_read_leb(pbc); | |
848 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 21 times.
|
46 | for (int i = 0; i < nb_submixes; i++) { |
849 | AVIAMFSubmix *sub_mix; | ||
850 | unsigned nb_elements, nb_layouts; | ||
851 | |||
852 | 25 | sub_mix = av_iamf_mix_presentation_add_submix(mix); | |
853 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (!sub_mix) { |
854 | ✗ | ret = AVERROR(ENOMEM); | |
855 | ✗ | goto fail; | |
856 | } | ||
857 | |||
858 | 25 | nb_elements = ffio_read_leb(pbc); | |
859 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
|
50 | for (int j = 0; j < nb_elements; j++) { |
860 | AVIAMFSubmixElement *submix_element; | ||
861 | 25 | IAMFAudioElement *audio_element = NULL; | |
862 | unsigned int rendering_config_extension_size; | ||
863 | |||
864 | 25 | submix_element = av_iamf_submix_add_element(sub_mix); | |
865 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (!submix_element) { |
866 | ✗ | ret = AVERROR(ENOMEM); | |
867 | ✗ | goto fail; | |
868 | } | ||
869 | |||
870 | 25 | submix_element->audio_element_id = ffio_read_leb(pbc); | |
871 | |||
872 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | for (int k = 0; k < c->nb_audio_elements; k++) |
873 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | if (c->audio_elements[k]->audio_element_id == submix_element->audio_element_id) { |
874 | 25 | audio_element = c->audio_elements[k]; | |
875 | 25 | break; | |
876 | } | ||
877 | |||
878 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (!audio_element) { |
879 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid Audio Element with id %u referenced by Mix Parameters %u\n", | |
880 | submix_element->audio_element_id, mix_presentation_id); | ||
881 | ✗ | ret = AVERROR_INVALIDDATA; | |
882 | ✗ | goto fail; | |
883 | } | ||
884 | |||
885 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
|
50 | for (int k = 0; k < mix_presentation->count_label; k++) { |
886 | 25 | char *annotation = NULL; | |
887 | 25 | ret = label_string(pbc, &annotation); | |
888 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (ret < 0) |
889 | ✗ | goto fail; | |
890 | 25 | ret = av_dict_set(&submix_element->annotations, mix_presentation->language_label[k], annotation, | |
891 | AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE); | ||
892 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (ret < 0) |
893 | ✗ | goto fail; | |
894 | } | ||
895 | |||
896 | 25 | submix_element->headphones_rendering_mode = avio_r8(pbc) >> 6; | |
897 | |||
898 | 25 | rendering_config_extension_size = ffio_read_leb(pbc); | |
899 | 25 | avio_skip(pbc, rendering_config_extension_size); | |
900 | |||
901 | 25 | ret = param_parse(s, c, pbc, AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN, | |
902 | NULL, | ||
903 | &submix_element->element_mix_config); | ||
904 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (ret < 0) |
905 | ✗ | goto fail; | |
906 | 25 | submix_element->default_mix_gain = av_make_q(sign_extend(avio_rb16(pbc), 16), 1 << 8); | |
907 | } | ||
908 | |||
909 | 25 | ret = param_parse(s, c, pbc, AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN, NULL, &sub_mix->output_mix_config); | |
910 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if (ret < 0) |
911 | ✗ | goto fail; | |
912 | 25 | sub_mix->default_mix_gain = av_make_q(sign_extend(avio_rb16(pbc), 16), 1 << 8); | |
913 | |||
914 | 25 | nb_layouts = ffio_read_leb(pbc); | |
915 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 25 times.
|
79 | for (int j = 0; j < nb_layouts; j++) { |
916 | AVIAMFSubmixLayout *submix_layout; | ||
917 | int info_type; | ||
918 | 54 | int byte = avio_r8(pbc); | |
919 | |||
920 | 54 | submix_layout = av_iamf_submix_add_layout(sub_mix); | |
921 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
|
54 | if (!submix_layout) { |
922 | ✗ | ret = AVERROR(ENOMEM); | |
923 | ✗ | goto fail; | |
924 | } | ||
925 | |||
926 | 54 | submix_layout->layout_type = byte >> 6; | |
927 |
1/2✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
|
54 | if (submix_layout->layout_type < AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS || |
928 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
|
54 | submix_layout->layout_type > AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL) { |
929 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid Layout type %u in a submix from Mix Presentation %u\n", | |
930 | ✗ | submix_layout->layout_type, mix_presentation_id); | |
931 | ✗ | ret = AVERROR_INVALIDDATA; | |
932 | ✗ | goto fail; | |
933 | } | ||
934 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 4 times.
|
54 | if (submix_layout->layout_type == 2) { |
935 | int sound_system; | ||
936 | 50 | sound_system = (byte >> 2) & 0xF; | |
937 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (sound_system >= FF_ARRAY_ELEMS(ff_iamf_sound_system_map)) { |
938 | ✗ | ret = AVERROR_INVALIDDATA; | |
939 | ✗ | goto fail; | |
940 | } | ||
941 | 50 | av_channel_layout_copy(&submix_layout->sound_system, &ff_iamf_sound_system_map[sound_system].layout); | |
942 | } | ||
943 | |||
944 | 54 | info_type = avio_r8(pbc); | |
945 | 54 | submix_layout->integrated_loudness = av_make_q(sign_extend(avio_rb16(pbc), 16), 1 << 8); | |
946 | 54 | submix_layout->digital_peak = av_make_q(sign_extend(avio_rb16(pbc), 16), 1 << 8); | |
947 | |||
948 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
|
54 | if (info_type & 1) |
949 | ✗ | submix_layout->true_peak = av_make_q(sign_extend(avio_rb16(pbc), 16), 1 << 8); | |
950 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
|
54 | if (info_type & 2) { |
951 | ✗ | unsigned int num_anchored_loudness = avio_r8(pbc); | |
952 | |||
953 | ✗ | for (int k = 0; k < num_anchored_loudness; k++) { | |
954 | ✗ | unsigned int anchor_element = avio_r8(pbc); | |
955 | ✗ | AVRational anchored_loudness = av_make_q(sign_extend(avio_rb16(pbc), 16), 1 << 8); | |
956 | ✗ | if (anchor_element == IAMF_ANCHOR_ELEMENT_DIALOGUE) | |
957 | ✗ | submix_layout->dialogue_anchored_loudness = anchored_loudness; | |
958 | ✗ | else if (anchor_element <= IAMF_ANCHOR_ELEMENT_ALBUM) | |
959 | ✗ | submix_layout->album_anchored_loudness = anchored_loudness; | |
960 | else | ||
961 | ✗ | av_log(s, AV_LOG_DEBUG, "Unknown anchor_element. Ignoring\n"); | |
962 | } | ||
963 | } | ||
964 | |||
965 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
|
54 | if (info_type & 0xFC) { |
966 | ✗ | unsigned int info_type_size = ffio_read_leb(pbc); | |
967 | ✗ | avio_skip(pbc, info_type_size); | |
968 | } | ||
969 | } | ||
970 | } | ||
971 | |||
972 | 21 | c->mix_presentations[c->nb_mix_presentations++] = mix_presentation; | |
973 | |||
974 | 21 | len -= avio_tell(pbc); | |
975 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (len) |
976 | ✗ | av_log(s, AV_LOG_WARNING, "Underread in mix_presentation_obu. %d bytes left at the end\n", len); | |
977 | |||
978 | 21 | ret = 0; | |
979 | 21 | fail: | |
980 | 21 | av_free(buf); | |
981 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (ret < 0) |
982 | ✗ | ff_iamf_free_mix_presentation(&mix_presentation); | |
983 | 21 | return ret; | |
984 | } | ||
985 | |||
986 | 7828 | int ff_iamf_parse_obu_header(const uint8_t *buf, int buf_size, | |
987 | unsigned *obu_size, int *start_pos, enum IAMF_OBU_Type *type, | ||
988 | unsigned *skip_samples, unsigned *discard_padding) | ||
989 | { | ||
990 | GetBitContext gb; | ||
991 | int ret, extension_flag, trimming, start; | ||
992 | 7828 | unsigned skip = 0, discard = 0; | |
993 | unsigned size; | ||
994 | |||
995 | 7828 | ret = init_get_bits8(&gb, buf, FFMIN(buf_size, MAX_IAMF_OBU_HEADER_SIZE)); | |
996 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7828 times.
|
7828 | if (ret < 0) |
997 | ✗ | return ret; | |
998 | |||
999 | 7828 | *type = get_bits(&gb, 5); | |
1000 | 7828 | /*redundant =*/ get_bits1(&gb); | |
1001 | 7828 | trimming = get_bits1(&gb); | |
1002 | 7828 | extension_flag = get_bits1(&gb); | |
1003 | |||
1004 | 7828 | *obu_size = get_leb(&gb); | |
1005 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 7819 times.
|
7828 | if (*obu_size > INT_MAX) |
1006 | 9 | return AVERROR_INVALIDDATA; | |
1007 | |||
1008 | 7819 | start = get_bits_count(&gb) / 8; | |
1009 | |||
1010 |
2/2✓ Branch 0 taken 2313 times.
✓ Branch 1 taken 5506 times.
|
7819 | if (trimming) { |
1011 | 2313 | discard = get_leb(&gb); // num_samples_to_trim_at_end | |
1012 | 2313 | skip = get_leb(&gb); // num_samples_to_trim_at_start | |
1013 | } | ||
1014 | |||
1015 |
2/2✓ Branch 0 taken 553 times.
✓ Branch 1 taken 7266 times.
|
7819 | if (skip_samples) |
1016 | 553 | *skip_samples = skip; | |
1017 |
2/2✓ Branch 0 taken 553 times.
✓ Branch 1 taken 7266 times.
|
7819 | if (discard_padding) |
1018 | 553 | *discard_padding = discard; | |
1019 | |||
1020 |
2/2✓ Branch 0 taken 724 times.
✓ Branch 1 taken 7095 times.
|
7819 | if (extension_flag) { |
1021 | unsigned int extension_bytes; | ||
1022 | 724 | extension_bytes = get_leb(&gb); | |
1023 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 706 times.
|
724 | if (extension_bytes > INT_MAX / 8) |
1024 | 18 | return AVERROR_INVALIDDATA; | |
1025 | 706 | skip_bits_long(&gb, extension_bytes * 8); | |
1026 | } | ||
1027 | |||
1028 |
2/2✓ Branch 1 taken 526 times.
✓ Branch 2 taken 7275 times.
|
7801 | if (get_bits_left(&gb) < 0) |
1029 | 526 | return AVERROR_INVALIDDATA; | |
1030 | |||
1031 | 7275 | size = *obu_size + start; | |
1032 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7275 times.
|
7275 | if (size > INT_MAX) |
1033 | ✗ | return AVERROR_INVALIDDATA; | |
1034 | |||
1035 | 7275 | *obu_size -= get_bits_count(&gb) / 8 - start; | |
1036 | 7275 | *start_pos = size - *obu_size; | |
1037 | |||
1038 | 7275 | return size; | |
1039 | } | ||
1040 | |||
1041 | 21 | int ff_iamfdec_read_descriptors(IAMFContext *c, AVIOContext *pb, | |
1042 | int max_size, void *log_ctx) | ||
1043 | { | ||
1044 | uint8_t header[MAX_IAMF_OBU_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; | ||
1045 | int ret; | ||
1046 | |||
1047 | 76 | while (1) { | |
1048 | unsigned obu_size; | ||
1049 | enum IAMF_OBU_Type type; | ||
1050 | int start_pos, len, size; | ||
1051 | |||
1052 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 97 times.
|
97 | if ((ret = ffio_ensure_seekback(pb, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size))) < 0) |
1053 | ✗ | return ret; | |
1054 | 97 | size = avio_read(pb, header, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); | |
1055 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
|
97 | if (size < 0) |
1056 | ✗ | return size; | |
1057 | |||
1058 | 97 | len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type, NULL, NULL); | |
1059 |
2/4✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 97 times.
|
97 | if (len < 0 || obu_size > max_size) { |
1060 | ✗ | av_log(log_ctx, AV_LOG_ERROR, "Failed to read obu header\n"); | |
1061 | ✗ | avio_seek(pb, -size, SEEK_CUR); | |
1062 | ✗ | return len; | |
1063 | } | ||
1064 | |||
1065 |
4/4✓ Branch 0 taken 34 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 21 times.
|
97 | if (type >= IAMF_OBU_IA_PARAMETER_BLOCK && type < IAMF_OBU_IA_SEQUENCE_HEADER) { |
1066 | 13 | avio_seek(pb, -size, SEEK_CUR); | |
1067 | 13 | break; | |
1068 | } | ||
1069 | |||
1070 | 84 | avio_seek(pb, -(size - start_pos), SEEK_CUR); | |
1071 |
4/5✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
|
84 | switch (type) { |
1072 | 21 | case IAMF_OBU_IA_CODEC_CONFIG: | |
1073 | 21 | ret = codec_config_obu(log_ctx, c, pb, obu_size); | |
1074 | 21 | break; | |
1075 | 21 | case IAMF_OBU_IA_AUDIO_ELEMENT: | |
1076 | 21 | ret = audio_element_obu(log_ctx, c, pb, obu_size); | |
1077 | 21 | break; | |
1078 | 21 | case IAMF_OBU_IA_MIX_PRESENTATION: | |
1079 | 21 | ret = mix_presentation_obu(log_ctx, c, pb, obu_size); | |
1080 | 21 | break; | |
1081 | ✗ | case IAMF_OBU_IA_TEMPORAL_DELIMITER: | |
1082 | ✗ | break; | |
1083 | 21 | default: { | |
1084 | 21 | int64_t offset = avio_skip(pb, obu_size); | |
1085 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | if (offset < 0) |
1086 | ✗ | ret = offset; | |
1087 | 21 | break; | |
1088 | } | ||
1089 | } | ||
1090 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
|
84 | if (ret < 0) { |
1091 | ✗ | av_log(log_ctx, AV_LOG_ERROR, "Failed to read obu type %d\n", type); | |
1092 | ✗ | return ret; | |
1093 | } | ||
1094 | 84 | max_size -= obu_size + start_pos; | |
1095 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
|
84 | if (max_size < 0) |
1096 | ✗ | return AVERROR_INVALIDDATA; | |
1097 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 76 times.
|
84 | if (!max_size) |
1098 | 8 | break; | |
1099 | } | ||
1100 | |||
1101 | 21 | return 0; | |
1102 | } | ||
1103 |