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