FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggparsevorbis.c
Date: 2026-09-12 04:54:02
Exec Total Coverage
Lines: 266 320 83.1%
Functions: 11 11 100.0%
Branches: 145 208 69.7%

Line Branch Exec Source
1 /*
2 * Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <stdlib.h>
26
27 #include "libavutil/avstring.h"
28 #include "libavutil/base64.h"
29 #include "libavutil/dict.h"
30 #include "libavutil/mem.h"
31
32 #include "libavcodec/bytestream.h"
33 #include "libavcodec/vorbis_parser.h"
34
35 #include "avformat.h"
36 #include "demux.h"
37 #include "flac_picture.h"
38 #include "internal.h"
39 #include "oggdec.h"
40 #include "vorbiscomment.h"
41 #include "replaygain.h"
42
43 303 static int ogm_chapter(AVFormatContext *as, const uint8_t *key, const uint8_t *val)
44 {
45 303 int i, cnum, h, m, s, ms, keylen = strlen(key);
46 303 AVChapter *chapter = NULL;
47
48
5/6
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 204 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
303 if (keylen < 9 || av_strncasecmp(key, "CHAPTER", 7) || sscanf(key+7, "%03d", &cnum) != 1)
49 279 return 0;
50
51
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (keylen <= 10) {
52
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4)
53 return 0;
54
55 12 avpriv_new_chapter(as, cnum, (AVRational) { 1, 1000 },
56 12 ms + 1000 * (s + 60 * (m + 60 * h)),
57 AV_NOPTS_VALUE, NULL);
58
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 } else if (!av_strcasecmp(key + keylen - 4, "NAME")) {
59
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 for (i = 0; i < as->nb_chapters; i++)
60
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
30 if (as->chapters[i]->id == cnum) {
61 12 chapter = as->chapters[i];
62 12 break;
63 }
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!chapter)
65 return 0;
66
67 12 av_dict_set(&chapter->metadata, "title", val, 0);
68 } else
69 return 0;
70
71 24 return 1;
72 }
73
74 83 int ff_vorbis_stream_comment(AVFormatContext *as, AVStream *st,
75 const uint8_t *buf, int size)
76 {
77 83 int updates = ff_vorbis_comment(as, &st->metadata, buf, size, 1);
78
79
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 13 times.
83 if (updates > 0) {
80 70 st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
81 }
82
83 83 return updates;
84 }
85
86 /**
87 * This function temporarily modifies the (const qualified) input buffer
88 * and reverts its changes before return. The input buffer needs to have
89 * at least one byte of padding.
90 */
91 310 static int vorbis_parse_single_comment(AVFormatContext *as, AVDictionary **m,
92 const uint8_t *buf, uint32_t size,
93 int *updates, int parse_picture)
94 {
95 310 char *t = (char*)buf, *v = memchr(t, '=', size);
96 int tl, vl;
97 char backup;
98
99
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 307 times.
310 if (!v)
100 3 return 0;
101
102 307 tl = v - t;
103 307 vl = size - tl - 1;
104 307 v++;
105
106
2/4
✓ Branch 0 taken 307 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 307 times.
307 if (!tl || !vl)
107 return 0;
108
109 307 t[tl] = 0;
110
111 307 backup = v[vl];
112 307 v[vl] = 0;
113
114 /* The format in which the pictures are stored is the FLAC format.
115 * Xiph says: "The binary FLAC picture structure is base64 encoded
116 * and placed within a VorbisComment with the tag name
117 * 'METADATA_BLOCK_PICTURE'. This is the preferred and
118 * recommended way of embedding cover art within VorbisComments."
119 */
120
3/4
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 303 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
311 if (!av_strcasecmp(t, "METADATA_BLOCK_PICTURE") && parse_picture) {
121 4 int ret, len = AV_BASE64_DECODE_SIZE(vl);
122 4 uint8_t *pict = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE);
123
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pict) {
125 av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n");
126 goto end;
127 }
128 4 ret = av_base64_decode(pict, v, len);
129
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (ret > 0)
130 4 ret = ff_flac_parse_picture(as, &pict, ret, 0);
131 4 av_freep(&pict);
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0) {
133 av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n");
134 goto end;
135 }
136
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 279 times.
303 } else if (!ogm_chapter(as, t, v)) {
137 279 (*updates)++;
138
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 279 times.
279 if (av_dict_get(*m, t, NULL, 0))
139 av_dict_set(m, t, ";", AV_DICT_APPEND);
140 279 av_dict_set(m, t, v, AV_DICT_APPEND);
141 }
142 24 end:
143 307 t[tl] = '=';
144 307 v[vl] = backup;
145
146 307 return 0;
147 }
148
149 124 int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
150 const uint8_t *buf, int size,
151 int parse_picture)
152 {
153 124 const uint8_t *p = buf;
154 124 const uint8_t *end = buf + size;
155 124 int updates = 0;
156 unsigned n;
157 int s, ret;
158
159 /* must have vendor_length and user_comment_list_length */
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 if (size < 8)
161 return AVERROR_INVALIDDATA;
162
163 124 s = bytestream_get_le32(&p);
164
165
2/4
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 124 times.
124 if (end - p - 4 < s || s < 0)
166 return AVERROR_INVALIDDATA;
167
168 124 p += s;
169
170 124 n = bytestream_get_le32(&p);
171
172
4/4
✓ Branch 0 taken 317 times.
✓ Branch 1 taken 117 times.
✓ Branch 2 taken 310 times.
✓ Branch 3 taken 7 times.
434 while (end - p >= 4 && n > 0) {
173 310 s = bytestream_get_le32(&p);
174
175
2/4
✓ Branch 0 taken 310 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 310 times.
✗ Branch 3 not taken.
310 if (end - p < s || s < 0)
176 break;
177
178 310 ret = vorbis_parse_single_comment(as, m, p, s, &updates, parse_picture);
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 310 times.
310 if (ret < 0)
180 return ret;
181 310 p += s;
182 310 n--;
183 }
184
185
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 117 times.
124 if (p != end)
186 7 av_log(as, AV_LOG_INFO,
187 "%td bytes of comment header remain\n", end - p);
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 if (n > 0)
189 av_log(as, AV_LOG_INFO,
190 "truncated comment header, %i comments not found\n", n);
191
192 124 ff_metadata_conv(m, NULL, ff_vorbiscomment_metadata_conv);
193
194 124 return updates;
195 }
196
197 /*
198 * Parse the vorbis header
199 *
200 * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec
201 * [vorbis_version] = read 32 bits as unsigned integer | Not used
202 * [audio_channels] = read 8 bit integer as unsigned | Used
203 * [audio_sample_rate] = read 32 bits as unsigned integer | Used
204 * [bitrate_maximum] = read 32 bits as signed integer | Not used yet
205 * [bitrate_nominal] = read 32 bits as signed integer | Not used yet
206 * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate
207 * [blocksize_0] = read 4 bits as unsigned integer | Not Used
208 * [blocksize_1] = read 4 bits as unsigned integer | Not Used
209 * [framing_flag] = read one bit | Not Used
210 */
211
212 struct oggvorbis_private {
213 unsigned int len[3];
214 unsigned char *packet[3];
215 AVVorbisParseContext *vp;
216 uint8_t *header;
217 int header_size;
218 uint8_t *comment;
219 int comment_size;
220 uint8_t *setup;
221 int setup_size;
222 int64_t bos_page_pos;
223 int ts_offset;
224 int64_t last_page_granule;
225 int eos_page_duration;
226 };
227
228 34 static int fixup_vorbis_headers(AVFormatContext *as,
229 struct oggvorbis_private *priv,
230 uint8_t **buf)
231 {
232 int i, offset, len, err;
233 int buf_len;
234 unsigned char *ptr;
235 uint64_t total_len;
236
237 34 total_len = (uint64_t)priv->len[0] + priv->len[1] + priv->len[2];
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (total_len + total_len / 255 + 64 > INT_MAX)
239 return AVERROR_INVALIDDATA;
240
241 34 len = total_len;
242 34 buf_len = len + len / 255 + 64;
243
244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (*buf)
245 return AVERROR_INVALIDDATA;
246
247 34 ptr = *buf = av_realloc(NULL, buf_len);
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (!ptr)
249 return AVERROR(ENOMEM);
250 34 memset(*buf, '\0', buf_len);
251
252 34 ptr[0] = 2;
253 34 offset = 1;
254 34 offset += av_xiphlacing(&ptr[offset], priv->len[0]);
255 34 offset += av_xiphlacing(&ptr[offset], priv->len[1]);
256
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 34 times.
136 for (i = 0; i < 3; i++) {
257 102 memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
258 102 offset += priv->len[i];
259 102 av_freep(&priv->packet[i]);
260 }
261
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
34 if ((err = av_reallocp(buf, offset + AV_INPUT_BUFFER_PADDING_SIZE)) < 0)
262 return err;
263 34 return offset;
264 }
265
266 34 static void vorbis_cleanup(AVFormatContext *s, int idx)
267 {
268 34 struct ogg *ogg = s->priv_data;
269 34 struct ogg_stream *os = ogg->streams + idx;
270 34 struct oggvorbis_private *priv = os->private;
271 int i;
272
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 if (os->private) {
273 34 av_vorbis_parse_free(&priv->vp);
274
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 34 times.
136 for (i = 0; i < 3; i++)
275 102 av_freep(&priv->packet[i]);
276
277 34 av_freep(&priv->header);
278 34 av_freep(&priv->comment);
279 34 av_freep(&priv->setup);
280 }
281 34 }
282
283 62 int ff_vorbis_update_metadata(AVFormatContext *s, AVStream *st,
284 const uint8_t *buf, int size)
285 {
286 62 struct ogg *ogg = s->priv_data;
287 62 struct ogg_stream *os = ogg->streams + st->index;
288 int ret;
289
290 /* New metadata packet; release old data. */
291 62 av_dict_free(&st->metadata);
292 62 ret = ff_vorbis_stream_comment(s, st, buf, size);
293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 if (ret < 0)
294 return ret;
295
296 /* Update the metadata if possible. */
297 62 av_freep(&os->new_metadata);
298
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 10 times.
62 if (st->metadata) {
299 52 os->new_metadata = av_packet_pack_dictionary(st->metadata, &os->new_metadata_size);
300 /* Send an empty dictionary to indicate that metadata has been cleared. */
301 } else {
302 10 os->new_metadata = av_mallocz(1);
303 10 os->new_metadata_size = 0;
304 }
305
306 62 return ret;
307 }
308
309 38 static int vorbis_parse_header(AVFormatContext *s, AVStream *st,
310 const uint8_t *p, unsigned int psize)
311 {
312 unsigned blocksize, bs0, bs1;
313 int srate;
314 int channels;
315
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (psize != 30)
317 return AVERROR_INVALIDDATA;
318
319 38 p += 7; /* skip "\001vorbis" tag */
320
321
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
38 if (bytestream_get_le32(&p) != 0) /* vorbis_version */
322 return AVERROR_INVALIDDATA;
323
324 38 channels = bytestream_get_byte(&p);
325
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 34 times.
38 if (st->codecpar->ch_layout.nb_channels &&
326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 channels != st->codecpar->ch_layout.nb_channels) {
327 av_log(s, AV_LOG_ERROR, "Channel change is not supported\n");
328 return AVERROR_PATCHWELCOME;
329 }
330 38 st->codecpar->ch_layout.nb_channels = channels;
331 38 srate = bytestream_get_le32(&p);
332 38 p += 4; // skip maximum bitrate
333 38 st->codecpar->bit_rate = bytestream_get_le32(&p); // nominal bitrate
334 38 p += 4; // skip minimum bitrate
335
336 38 blocksize = bytestream_get_byte(&p);
337 38 bs0 = blocksize & 15;
338 38 bs1 = blocksize >> 4;
339
340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (bs0 > bs1)
341 return AVERROR_INVALIDDATA;
342
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
38 if (bs0 < 6 || bs1 > 13)
343 return AVERROR_INVALIDDATA;
344
345
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
38 if (bytestream_get_byte(&p) != 1) /* framing_flag */
346 return AVERROR_INVALIDDATA;
347
348 38 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
349 38 st->codecpar->codec_id = AV_CODEC_ID_VORBIS;
350
351
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (srate > 0) {
352
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 34 times.
38 if (st->codecpar->sample_rate &&
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 srate != st->codecpar->sample_rate) {
354 av_log(s, AV_LOG_ERROR, "Sample rate change is not supported\n");
355 return AVERROR_PATCHWELCOME;
356 }
357
358 38 st->codecpar->sample_rate = srate;
359 38 avpriv_set_pts_info(st, 64, 1, srate);
360 }
361
362 38 return 1;
363 }
364
365 38 static int vorbis_update_metadata(AVFormatContext *s, int idx)
366 {
367 38 struct ogg *ogg = s->priv_data;
368 38 struct ogg_stream *os = ogg->streams + idx;
369 38 AVStream *st = s->streams[idx];
370
371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (os->psize <= 8)
372 return 0;
373
374 38 return ff_vorbis_update_metadata(s, st, os->buf + os->pstart + 7,
375 38 os->psize - 8);
376 }
377
378 137 static int vorbis_header(AVFormatContext *s, int idx)
379 {
380 137 struct ogg *ogg = s->priv_data;
381 137 AVStream *st = s->streams[idx];
382 137 struct ogg_stream *os = ogg->streams + idx;
383 struct oggvorbis_private *priv;
384 137 int pkt_type = os->buf[os->pstart];
385
386
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 103 times.
137 if (!os->private)
387 34 os->private = av_mallocz(sizeof(struct oggvorbis_private));
388
389
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
137 if (!os->private)
390 return AVERROR(ENOMEM);
391
392 137 priv = os->private;
393 137 priv->bos_page_pos = -1;
394
395
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 102 times.
137 if (!(pkt_type & 1))
396
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 return priv->vp ? 0 : AVERROR_INVALIDDATA;
397
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (pkt_type > 5) {
399 av_log(s, AV_LOG_VERBOSE, "Ignoring packet with unknown type %d\n", pkt_type);
400 return 1;
401 }
402
403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (os->psize < 1)
404 return AVERROR_INVALIDDATA;
405
406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (priv->packet[pkt_type >> 1])
407 return AVERROR_INVALIDDATA;
408
6/8
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 68 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 34 times.
102 if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1])
409 return priv->vp ? 0 : AVERROR_INVALIDDATA;
410
411 102 priv->len[pkt_type >> 1] = os->psize;
412 102 priv->packet[pkt_type >> 1] = av_memdup(os->buf + os->pstart, os->psize);
413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (!priv->packet[pkt_type >> 1])
414 return AVERROR(ENOMEM);
415
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 68 times.
102 if (pkt_type == 1)
416 34 return vorbis_parse_header(s, st, os->buf + os->pstart, os->psize);
417
418
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 34 times.
68 if (pkt_type == 3) {
419
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 34 times.
✗ Branch 4 not taken.
34 if (vorbis_update_metadata(s, idx) >= 0 && priv->len[1] > 10) {
420 unsigned new_len;
421
422 34 int ret = ff_replaygain_export(st, st->metadata);
423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (ret < 0)
424 return ret;
425
426 // drop all metadata we parsed and which is not required by libvorbis
427 34 new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1;
428
3/4
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 8 times.
34 if (new_len >= 16 && new_len < os->psize) {
429 26 AV_WL32(priv->packet[1] + new_len - 5, 0);
430 26 priv->packet[1][new_len - 1] = 1;
431 26 priv->len[1] = new_len;
432 }
433 }
434 } else {
435 int ret;
436
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (priv->vp)
438 return AVERROR_INVALIDDATA;
439
440 34 ret = fixup_vorbis_headers(s, priv, &st->codecpar->extradata);
441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (ret < 0) {
442 st->codecpar->extradata_size = 0;
443 return ret;
444 }
445 34 st->codecpar->extradata_size = ret;
446
447 34 priv->vp = av_vorbis_parse_init(st->codecpar->extradata, st->codecpar->extradata_size);
448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (!priv->vp) {
449 av_freep(&st->codecpar->extradata);
450 st->codecpar->extradata_size = 0;
451 return AVERROR_UNKNOWN;
452 }
453 }
454
455 68 return 1;
456 }
457
458 11723 static int vorbis_packet(AVFormatContext *s, int idx)
459 {
460 11723 struct ogg *ogg = s->priv_data;
461 11723 struct ogg_stream *os = ogg->streams + idx;
462 11723 struct oggvorbis_private *priv = os->private;
463 11723 int duration, flags = 0;
464 11723 int bos, skip_packet = 0;
465 int ret, new_extradata_size;
466 PutByteContext pb;
467
468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11723 times.
11723 if (os->psize == 0)
469 return AVERROR_INVALIDDATA;
470
471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11723 times.
11723 if (!priv->vp)
472 return AVERROR_INVALIDDATA;
473
474 /* Track the page holding the first data packet by its file position,
475 * which stays stable when probing rescans the start of the stream. */
476
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 11684 times.
11723 if (priv->bos_page_pos < 0)
477 39 priv->bos_page_pos = os->page_pos;
478
479
4/4
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 11121 times.
✓ Branch 2 taken 72 times.
✓ Branch 3 taken 530 times.
11723 bos = os->page_start && os->page_pos == priv->bos_page_pos;
480
481
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 11651 times.
11723 if (bos) {
482 72 av_vorbis_parse_reset(priv->vp);
483 72 priv->last_page_granule = 0;
484 }
485
486 11723 duration = av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, &flags);
487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11723 times.
11723 if (duration < 0) {
488 os->pflags |= AV_PKT_FLAG_CORRUPT;
489 return 0;
490 }
491 11723 os->pduration = duration;
492
493 /* Save ts_offset from the very first chained stream to account for the
494 * first priming packet. This only shifts timestamps; the Vorbis decoder
495 * discards the leading priming samples itself, so we do not set
496 * codecpar->initial_padding. */
497
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 11689 times.
11723 if (!priv->ts_offset)
498 34 priv->ts_offset = os->pduration;
499
500 /* Initial position shift to account for encoder delay. */
501
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 11651 times.
11723 if (bos) {
502
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 if (os->lastpts != AV_NOPTS_VALUE)
503 72 os->lastpts -= priv->ts_offset;
504
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 34 times.
72 if (os->lastdts != AV_NOPTS_VALUE)
505 38 os->lastdts -= priv->ts_offset;
506 }
507
508 /* Broken files may have granule=0 on pages that contain audio data.
509 * In that case timestamps are unreliable, so discard them.
510 * See https://trac.ffmpeg.org/ticket/3710 */
511
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 11707 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 12 times.
11723 if (!os->granule && os->pduration)
512 4 os->lastpts = os->lastdts = AV_NOPTS_VALUE;
513
514
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 11452 times.
11723 if (os->flags & OGG_FLAG_EOS) {
515 /* Reset at the start of the EOS page to avoid carrying over stale
516 * duration from a previously processed EOS page, as can happen on
517 * short or chained ogg streams and when probing rescans the page.
518 * os->segp has already been advanced past the current packet by
519 * ogg_packet(), so rely on os->page_start to detect the page start. */
520
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 250 times.
271 if (os->page_start)
521 21 priv->eos_page_duration = 0;
522
523
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 14 times.
271 if (os->segp != os->nsegs) {
524 257 priv->eos_page_duration += os->pduration;
525 } else {
526 14 int64_t skip = priv->eos_page_duration + os->pduration -
527 14 (os->granule - priv->last_page_granule);
528
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3 times.
14 if (skip > 0)
529 11 os->end_trimming = skip;
530 }
531 } else
532 11452 priv->last_page_granule = os->granule;
533
534 /* Handle in-stream header packets from chained streams. The packet is
535 * skipped; the headers are buffered and attached as extradata to the
536 * first data packet that follows. */
537
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11719 times.
11723 if (flags & VORBIS_FLAG_HEADER) {
538 4 ret = vorbis_parse_header(s, s->streams[idx], os->buf + os->pstart, os->psize);
539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
540 return ret;
541
542 4 ret = av_reallocp(&priv->header, os->psize);
543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
544 return ret;
545
546 4 memcpy(priv->header, os->buf + os->pstart, os->psize);
547 4 priv->header_size = os->psize;
548
549 4 skip_packet = 1;
550 }
551
552
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11719 times.
11723 if (flags & VORBIS_FLAG_COMMENT) {
553 4 ret = vorbis_update_metadata(s, idx);
554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
555 return ret;
556
557 4 ret = av_reallocp(&priv->comment, os->psize);
558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
559 return ret;
560
561 4 memcpy(priv->comment, os->buf + os->pstart, os->psize);
562 4 priv->comment_size = os->psize;
563
564 4 flags = 0;
565 4 skip_packet = 1;
566 }
567
568
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11719 times.
11723 if (flags & VORBIS_FLAG_SETUP) {
569 4 ret = av_reallocp(&priv->setup, os->psize);
570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
571 return ret;
572
573 4 memcpy(priv->setup, os->buf + os->pstart, os->psize);
574 4 priv->setup_size = os->psize;
575
576 4 skip_packet = 1;
577 }
578
579
580 /* All three headers for the new chained stream have been collected;
581 * pack them into new extradata to be attached to the next data packet. */
582
6/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11711 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
11723 if (priv->header && priv->comment && priv->setup) {
583 4 new_extradata_size = priv->header_size + priv->comment_size + priv->setup_size + 6;
584
585 4 ret = av_reallocp(&os->new_extradata, new_extradata_size);
586
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
587 return ret;
588
589 4 os->new_extradata_size = new_extradata_size;
590 4 bytestream2_init_writer(&pb, os->new_extradata, new_extradata_size);
591 4 bytestream2_put_be16(&pb, priv->header_size);
592 4 bytestream2_put_buffer(&pb, priv->header, priv->header_size);
593 4 bytestream2_put_be16(&pb, priv->comment_size);
594 4 bytestream2_put_buffer(&pb, priv->comment, priv->comment_size);
595 4 bytestream2_put_be16(&pb, priv->setup_size);
596 4 bytestream2_put_buffer(&pb, priv->setup, priv->setup_size);
597
598 4 av_freep(&priv->header);
599 4 priv->header_size = 0;
600 4 av_freep(&priv->comment);
601 4 priv->comment_size = 0;
602 4 av_freep(&priv->setup);
603 4 priv->setup_size = 0;
604
605 4 av_vorbis_parse_free(&priv->vp);
606 4 priv->vp = av_vorbis_parse_init(os->new_extradata, os->new_extradata_size);
607
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!priv->vp) {
608 av_log(s, AV_LOG_ERROR, "Failed to re-initialize Vorbis parser\n");
609 return AVERROR_INVALIDDATA;
610 }
611
612 /* Reset bos_page_pos so the next packet will initialize it for the
613 * new chained stream. */
614 4 priv->bos_page_pos = -1;
615 }
616
617 11723 return skip_packet;
618 }
619
620 const struct ogg_codec ff_vorbis_codec = {
621 .magic = "\001vorbis",
622 .magicsize = 7,
623 .header = vorbis_header,
624 .packet = vorbis_packet,
625 .cleanup = vorbis_cleanup,
626 .nb_header = 3,
627 };
628