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