FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggparsevorbis.c
Date: 2026-11-01 11:15:23
Exec Total Coverage
Lines: 305 365 83.6%
Functions: 12 12 100.0%
Branches: 200 272 73.5%

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 352 static int ogm_chapter(AVFormatContext *as, const uint8_t *key, const uint8_t *val)
44 {
45 352 int i, cnum, h, m, s, ms, keylen = strlen(key);
46 352 AVChapter *chapter = NULL;
47
48
5/6
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 237 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
352 if (keylen < 9 || av_strncasecmp(key, "CHAPTER", 7) || sscanf(key+7, "%03d", &cnum) != 1)
49 328 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 99 int ff_vorbis_stream_comment(AVFormatContext *as, AVStream *st,
75 const uint8_t *buf, int size)
76 {
77 99 int updates = ff_vorbis_comment(as, &st->metadata, buf, size, 1);
78
79
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 13 times.
99 if (updates > 0) {
80 86 st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
81 }
82
83 99 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 359 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 359 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 356 times.
359 if (!v)
100 3 return 0;
101
102 356 tl = v - t;
103 356 vl = size - tl - 1;
104 356 v++;
105
106
2/4
✓ Branch 0 taken 356 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 356 times.
356 if (!tl || !vl)
107 ✗ return 0;
108
109 356 t[tl] = 0;
110
111 356 backup = v[vl];
112 356 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 352 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
360 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 328 times.
352 } else if (!ogm_chapter(as, t, v)) {
137 328 (*updates)++;
138
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 328 times.
328 if (av_dict_get(*m, t, NULL, 0))
139 ✗ av_dict_set(m, t, ";", AV_DICT_APPEND);
140 328 av_dict_set(m, t, v, AV_DICT_APPEND);
141 }
142 24 end:
143 356 t[tl] = '=';
144 356 v[vl] = backup;
145
146 356 return 0;
147 }
148
149 140 int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
150 const uint8_t *buf, int size,
151 int parse_picture)
152 {
153 140 const uint8_t *p = buf;
154 140 const uint8_t *end = buf + size;
155 140 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 140 times.
140 if (size < 8)
161 ✗ return AVERROR_INVALIDDATA;
162
163 140 s = bytestream_get_le32(&p);
164
165
2/4
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 140 times.
140 if (end - p - 4 < s || s < 0)
166 ✗ return AVERROR_INVALIDDATA;
167
168 140 p += s;
169
170 140 n = bytestream_get_le32(&p);
171
172
4/4
✓ Branch 0 taken 370 times.
✓ Branch 1 taken 129 times.
✓ Branch 2 taken 359 times.
✓ Branch 3 taken 11 times.
499 while (end - p >= 4 && n > 0) {
173 359 s = bytestream_get_le32(&p);
174
175
2/4
✓ Branch 0 taken 359 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 359 times.
✗ Branch 3 not taken.
359 if (end - p < s || s < 0)
176 break;
177
178 359 ret = vorbis_parse_single_comment(as, m, p, s, &updates, parse_picture);
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 359 times.
359 if (ret < 0)
180 ✗ return ret;
181 359 p += s;
182 359 n--;
183 }
184
185
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 129 times.
140 if (p != end)
186 11 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 140 times.
140 if (n > 0)
189 ✗ av_log(as, AV_LOG_INFO,
190 "truncated comment header, %i comments not found\n", n);
191
192 140 ff_metadata_conv(m, NULL, ff_vorbiscomment_metadata_conv);
193
194 140 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 enum VorbisPacketType {
213 VORBIS_PACKET_DATA,
214 VORBIS_PACKET_ID,
215 VORBIS_PACKET_COMMENT,
216 VORBIS_PACKET_SETUP,
217 VORBIS_PACKET_RESERVED,
218 };
219
220 struct oggvorbis_private {
221 unsigned int len[3];
222 unsigned char *packet[3];
223 enum VorbisPacketType last_packet; ///< type of the last packet seen by vorbis_packet()
224 AVVorbisParseContext *vp;
225 int64_t bos_page_pos;
226 int ts_offset;
227 int64_t last_page_granule;
228 int eos_page_duration;
229 };
230
231 45 static int fixup_vorbis_headers(AVFormatContext *as,
232 struct oggvorbis_private *priv,
233 uint8_t **buf)
234 {
235 int i, offset, len, err;
236 int buf_len;
237 unsigned char *ptr;
238 uint64_t total_len;
239
240 45 total_len = (uint64_t)priv->len[0] + priv->len[1] + priv->len[2];
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 if (total_len + total_len / 255 + 64 > INT_MAX)
242 ✗ return AVERROR_INVALIDDATA;
243
244 45 len = total_len;
245 45 buf_len = len + len / 255 + 64;
246
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 if (*buf)
248 ✗ return AVERROR_INVALIDDATA;
249
250 45 ptr = *buf = av_realloc(NULL, buf_len);
251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 if (!ptr)
252 ✗ return AVERROR(ENOMEM);
253 45 memset(*buf, '\0', buf_len);
254
255 45 ptr[0] = 2;
256 45 offset = 1;
257 45 offset += av_xiphlacing(&ptr[offset], priv->len[0]);
258 45 offset += av_xiphlacing(&ptr[offset], priv->len[1]);
259
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 45 times.
180 for (i = 0; i < 3; i++) {
260 135 memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
261 135 offset += priv->len[i];
262 135 av_freep(&priv->packet[i]);
263 }
264
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
45 if ((err = av_reallocp(buf, offset + AV_INPUT_BUFFER_PADDING_SIZE)) < 0)
265 ✗ return err;
266 45 return offset;
267 }
268
269 39 static void vorbis_cleanup(AVFormatContext *s, int idx)
270 {
271 39 struct ogg *ogg = s->priv_data;
272 39 struct ogg_stream *os = ogg->streams + idx;
273 39 struct oggvorbis_private *priv = os->private;
274 int i;
275
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (os->private) {
276 39 av_vorbis_parse_free(&priv->vp);
277
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 39 times.
156 for (i = 0; i < 3; i++)
278 117 av_freep(&priv->packet[i]);
279 }
280 39 }
281
282 71 int ff_vorbis_update_metadata(AVFormatContext *s, AVStream *st,
283 const uint8_t *buf, int size)
284 {
285 71 struct ogg *ogg = s->priv_data;
286 71 struct ogg_stream *os = ogg->streams + st->index;
287 int ret;
288
289 /* New metadata packet; release old data. */
290 71 av_dict_free(&st->metadata);
291 71 ret = ff_vorbis_stream_comment(s, st, buf, size);
292
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 if (ret < 0)
293 ✗ return ret;
294
295 /* Update the metadata if possible. */
296 71 av_freep(&os->new_metadata);
297
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 10 times.
71 if (st->metadata) {
298 61 os->new_metadata = av_packet_pack_dictionary(st->metadata, &os->new_metadata_size);
299 /* Send an empty dictionary to indicate that metadata has been cleared. */
300 } else {
301 10 os->new_metadata = av_mallocz(1);
302 10 os->new_metadata_size = 0;
303 }
304
305 71 return ret;
306 }
307
308 46 static int vorbis_parse_header(AVFormatContext *s, AVStream *st,
309 const uint8_t *p, unsigned int psize)
310 {
311 unsigned blocksize, bs0, bs1;
312 int srate;
313 int channels;
314
315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (psize != 30)
316 ✗ return AVERROR_INVALIDDATA;
317
318 46 p += 7; /* skip "\001vorbis" tag */
319
320
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
46 if (bytestream_get_le32(&p) != 0) /* vorbis_version */
321 ✗ return AVERROR_INVALIDDATA;
322
323 46 channels = bytestream_get_byte(&p);
324
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 39 times.
46 if (st->codecpar->ch_layout.nb_channels &&
325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 channels != st->codecpar->ch_layout.nb_channels) {
326 ✗ av_log(s, AV_LOG_ERROR, "Channel change is not supported\n");
327 ✗ return AVERROR_PATCHWELCOME;
328 }
329 46 st->codecpar->ch_layout.nb_channels = channels;
330 46 srate = bytestream_get_le32(&p);
331 46 p += 4; // skip maximum bitrate
332 46 st->codecpar->bit_rate = bytestream_get_le32(&p); // nominal bitrate
333 46 p += 4; // skip minimum bitrate
334
335 46 blocksize = bytestream_get_byte(&p);
336 46 bs0 = blocksize & 15;
337 46 bs1 = blocksize >> 4;
338
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (bs0 > bs1)
340 ✗ return AVERROR_INVALIDDATA;
341
2/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
46 if (bs0 < 6 || bs1 > 13)
342 ✗ return AVERROR_INVALIDDATA;
343
344
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
46 if (bytestream_get_byte(&p) != 1) /* framing_flag */
345 ✗ return AVERROR_INVALIDDATA;
346
347 46 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
348 46 st->codecpar->codec_id = AV_CODEC_ID_VORBIS;
349
350
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (srate > 0) {
351
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 39 times.
46 if (st->codecpar->sample_rate &&
352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 srate != st->codecpar->sample_rate) {
353 ✗ av_log(s, AV_LOG_ERROR, "Sample rate change is not supported\n");
354 ✗ return AVERROR_PATCHWELCOME;
355 }
356
357 46 st->codecpar->sample_rate = srate;
358 46 avpriv_set_pts_info(st, 64, 1, srate);
359 }
360
361 46 return 1;
362 }
363
364 45 static int vorbis_update_metadata(AVFormatContext *s, int idx)
365 {
366 45 struct ogg *ogg = s->priv_data;
367 45 struct ogg_stream *os = ogg->streams + idx;
368 45 AVStream *st = s->streams[idx];
369
370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 if (os->psize <= 8)
371 ✗ return 0;
372
373 45 return ff_vorbis_update_metadata(s, st, os->buf + os->pstart + 7,
374 45 os->psize - 8);
375 }
376
377 157 static int vorbis_header(AVFormatContext *s, int idx)
378 {
379 157 struct ogg *ogg = s->priv_data;
380 157 AVStream *st = s->streams[idx];
381 157 struct ogg_stream *os = ogg->streams + idx;
382 struct oggvorbis_private *priv;
383 157 int pkt_type = os->buf[os->pstart];
384
385
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 118 times.
157 if (!os->private)
386 39 os->private = av_mallocz(sizeof(struct oggvorbis_private));
387
388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
157 if (!os->private)
389 ✗ return AVERROR(ENOMEM);
390
391 157 priv = os->private;
392 157 priv->bos_page_pos = -1;
393
394
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 117 times.
157 if (!(pkt_type & 1))
395
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 return priv->vp ? 0 : AVERROR_INVALIDDATA;
396
397
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (pkt_type > 5) {
398 ✗ av_log(s, AV_LOG_VERBOSE, "Ignoring packet with unknown type %d\n", pkt_type);
399 ✗ return 1;
400 }
401
402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (os->psize < 1)
403 ✗ return AVERROR_INVALIDDATA;
404
405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (priv->packet[pkt_type >> 1])
406 ✗ return AVERROR_INVALIDDATA;
407
6/8
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 78 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 39 times.
117 if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1])
408 ✗ return priv->vp ? 0 : AVERROR_INVALIDDATA;
409
410 117 priv->len[pkt_type >> 1] = os->psize;
411 117 priv->packet[pkt_type >> 1] = av_memdup(os->buf + os->pstart, os->psize);
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (!priv->packet[pkt_type >> 1])
413 ✗ return AVERROR(ENOMEM);
414
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 78 times.
117 if (pkt_type == 1)
415 39 return vorbis_parse_header(s, st, os->buf + os->pstart, os->psize);
416
417
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 39 times.
78 if (pkt_type == 3) {
418
2/4
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
39 if (vorbis_update_metadata(s, idx) >= 0 && priv->len[1] > 10) {
419 unsigned new_len;
420
421 39 int ret = ff_replaygain_export(st, st->metadata);
422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0)
423 ✗ return ret;
424
425 // drop all metadata we parsed and which is not required by libvorbis
426 39 new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1;
427
3/4
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 8 times.
39 if (new_len >= 16 && new_len < os->psize) {
428 31 AV_WL32(priv->packet[1] + new_len - 5, 0);
429 31 priv->packet[1][new_len - 1] = 1;
430 31 priv->len[1] = new_len;
431 }
432 }
433 } else {
434 int ret;
435
436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (priv->vp)
437 ✗ return AVERROR_INVALIDDATA;
438
439 39 ret = fixup_vorbis_headers(s, priv, &st->codecpar->extradata);
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (ret < 0) {
441 ✗ st->codecpar->extradata_size = 0;
442 ✗ return ret;
443 }
444 39 st->codecpar->extradata_size = ret;
445
446 39 priv->vp = av_vorbis_parse_init(st->codecpar->extradata, st->codecpar->extradata_size);
447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (!priv->vp) {
448 ✗ av_freep(&st->codecpar->extradata);
449 ✗ st->codecpar->extradata_size = 0;
450 ✗ return AVERROR_UNKNOWN;
451 }
452 }
453
454 78 return 1;
455 }
456
457 /**
458 * Check that a packet follows the identification, comment, setup order of a
459 * chained stream's headers, and record it as the last packet.
460 *
461 * An identification header starts a new set. A misplaced packet discards the
462 * buffered headers, so an incomplete or misordered set is never packed.
463 * Reserved packet types are ignored, per Vorbis I §1.3.2.
464 *
465 * @return 0 if the packet is in order, AVERROR_INVALIDDATA otherwise
466 */
467 12254 static int vorbis_check_packet_order(AVFormatContext *s,
468 struct oggvorbis_private *priv,
469 enum VorbisPacketType type)
470 {
471 12254 enum VorbisPacketType last = priv->last_packet;
472 12254 const char *error = NULL;
473
474
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12231 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
12254 switch (type) {
475 ✗ case VORBIS_PACKET_RESERVED:
476 ✗ return 0;
477 12231 case VORBIS_PACKET_DATA:
478
3/4
✓ Branch 0 taken 12230 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12230 times.
12231 if (last == VORBIS_PACKET_ID || last == VORBIS_PACKET_COMMENT)
479 1 error = "data packet before the setup header";
480 12231 break;
481 7 case VORBIS_PACKET_ID:
482
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (last == VORBIS_PACKET_ID || last == VORBIS_PACKET_COMMENT)
483 ✗ error = "identification header before the setup header";
484 7 break;
485 8 case VORBIS_PACKET_COMMENT:
486
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (last != VORBIS_PACKET_ID)
487 2 error = "comment header without identification header";
488 8 break;
489 8 case VORBIS_PACKET_SETUP:
490
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (last != VORBIS_PACKET_COMMENT)
491 2 error = "setup header without comment header";
492 8 break;
493 }
494
495
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12249 times.
12254 if (error)
496 5 av_log(s, AV_LOG_WARNING,
497 "Invalid chained stream headers: %s, discarding them\n", error);
498
499
4/4
✓ Branch 0 taken 12249 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 12242 times.
12254 if (error || type == VORBIS_PACKET_ID)
500
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 12 times.
48 for (int i = 0; i < 3; i++)
501 36 av_freep(&priv->packet[i]);
502
503
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12249 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
12254 priv->last_packet = error && type != VORBIS_PACKET_ID ? VORBIS_PACKET_DATA : type;
504
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12249 times.
12254 return error ? AVERROR_INVALIDDATA : 0;
505 }
506
507 12254 static int vorbis_packet(AVFormatContext *s, int idx)
508 {
509 12254 struct ogg *ogg = s->priv_data;
510 12254 struct ogg_stream *os = ogg->streams + idx;
511 12254 struct oggvorbis_private *priv = os->private;
512 12254 int duration, flags = 0;
513 12254 int bos, skip_packet = 0;
514 int ret;
515
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12254 times.
12254 if (os->psize == 0)
517 ✗ return AVERROR_INVALIDDATA;
518
519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12254 times.
12254 if (!priv->vp)
520 ✗ return AVERROR_INVALIDDATA;
521
522 /* Track the page holding the first data packet by its file position,
523 * which stays stable when probing rescans the start of the stream. */
524
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 12208 times.
12254 if (priv->bos_page_pos < 0)
525 46 priv->bos_page_pos = os->page_pos;
526
527
4/4
✓ Branch 0 taken 646 times.
✓ Branch 1 taken 11608 times.
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 564 times.
12254 bos = os->page_start && os->page_pos == priv->bos_page_pos;
528
529
6/6
✓ Branch 0 taken 12172 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 564 times.
✓ Branch 3 taken 11608 times.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 545 times.
12254 if (bos || (os->page_start && os->lastpts == AV_NOPTS_VALUE))
530 101 av_vorbis_parse_reset(priv->vp);
531
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 12172 times.
12254 if (bos)
532 82 priv->last_page_granule = 0;
533
534 12254 duration = av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, &flags);
535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12254 times.
12254 if (duration < 0) {
536 ✗ os->pflags |= AV_PKT_FLAG_CORRUPT;
537 ✗ return 0;
538 }
539 12254 os->pduration = duration;
540
541 /* Save ts_offset from the very first chained stream to account for the
542 * first priming packet. This only shifts timestamps; the Vorbis decoder
543 * discards the leading priming samples itself, so we do not set
544 * codecpar->initial_padding. */
545
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 12215 times.
12254 if (!priv->ts_offset)
546 39 priv->ts_offset = os->pduration;
547
548 /* Initial position shift to account for encoder delay, or page scan
549 * to recover the page start timestamp after a seek. */
550
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 12172 times.
12254 if (bos) {
551
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 if (os->lastpts != AV_NOPTS_VALUE) {
552
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 43 times.
82 if (s->streams[idx]->start_time == AV_NOPTS_VALUE) {
553 39 s->streams[idx]->start_time = os->lastpts;
554
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 2 times.
39 if (s->streams[idx]->duration != AV_NOPTS_VALUE)
555 37 s->streams[idx]->duration -= s->streams[idx]->start_time;
556 }
557 82 os->lastpts -= priv->ts_offset;
558 }
559
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 37 times.
82 if (os->lastdts != AV_NOPTS_VALUE)
560 45 os->lastdts -= priv->ts_offset;
561
4/4
✓ Branch 0 taken 564 times.
✓ Branch 1 taken 11608 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 545 times.
12172 } else if (os->page_start && os->lastpts == AV_NOPTS_VALUE &&
562
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
19 !(os->flags & OGG_FLAG_EOS) && (int64_t)os->granule >= 0) {
563 15 int seg, page_duration = os->pduration;
564 15 uint8_t *last_pkt = os->buf + os->pstart + os->psize;
565 15 uint8_t *next_pkt = last_pkt;
566
567
2/2
✓ Branch 0 taken 494 times.
✓ Branch 1 taken 15 times.
509 for (seg = os->segp; seg < os->nsegs; seg++) {
568 494 next_pkt += os->segments[seg];
569
3/4
✓ Branch 0 taken 380 times.
✓ Branch 1 taken 114 times.
✓ Branch 2 taken 380 times.
✗ Branch 3 not taken.
494 if (os->segments[seg] < 255 && next_pkt != last_pkt) {
570 380 int pkt_flags = 0;
571 380 int d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &pkt_flags);
572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
380 if (d < 0) {
573 ✗ page_duration = os->granule;
574 ✗ break;
575 }
576 380 page_duration += d;
577 380 last_pkt = next_pkt;
578 }
579 }
580 15 av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, &flags);
581 15 os->lastpts =
582 15 os->lastdts = os->granule - page_duration;
583 }
584
585 /* Broken files may have granule=0 on pages that contain audio data.
586 * In that case timestamps are unreliable, so discard them.
587 * See https://trac.ffmpeg.org/ticket/3710 */
588
4/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 12227 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 23 times.
12254 if (!os->granule && os->pduration)
589 4 os->lastpts = os->lastdts = AV_NOPTS_VALUE;
590
591
2/2
✓ Branch 0 taken 525 times.
✓ Branch 1 taken 11729 times.
12254 if (os->flags & OGG_FLAG_EOS) {
592 /* Reset at the start of the EOS page to avoid carrying over stale
593 * duration from a previously processed EOS page, as can happen on
594 * short or chained ogg streams and when probing rescans the page.
595 * os->segp has already been advanced past the current packet by
596 * ogg_packet(), so rely on os->page_start to detect the page start. */
597
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 501 times.
525 if (os->page_start)
598 24 priv->eos_page_duration = 0;
599
600
2/2
✓ Branch 0 taken 507 times.
✓ Branch 1 taken 18 times.
525 if (os->segp != os->nsegs) {
601 507 priv->eos_page_duration += os->pduration;
602 } else {
603 18 int64_t skip = priv->eos_page_duration + os->pduration -
604 18 (os->granule - priv->last_page_granule);
605
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
18 if (skip > 0)
606 14 os->end_trimming = skip;
607 }
608 } else
609 11729 priv->last_page_granule = os->granule;
610
611 /* Handle in-stream header packets from chained streams. The packet is
612 * skipped; the headers are buffered and attached as extradata to the
613 * first data packet that follows. */
614
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 12247 times.
12254 if (flags & VORBIS_FLAG_HEADER) {
615 7 vorbis_check_packet_order(s, priv, VORBIS_PACKET_ID);
616
617 7 ret = vorbis_parse_header(s, s->streams[idx], os->buf + os->pstart, os->psize);
618
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ret < 0)
619 ✗ return ret;
620
621 7 ret = av_reallocp(&priv->packet[0], os->psize);
622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ret < 0)
623 ✗ return ret;
624
625 7 memcpy(priv->packet[0], os->buf + os->pstart, os->psize);
626 7 priv->len[0] = os->psize;
627
628 7 skip_packet = 1;
629 }
630
631
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12246 times.
12254 if (flags & VORBIS_FLAG_COMMENT) {
632
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
8 if (vorbis_check_packet_order(s, priv, VORBIS_PACKET_COMMENT) < 0)
633 2 return 1;
634
635 6 ret = vorbis_update_metadata(s, idx);
636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (ret < 0)
637 ✗ return ret;
638
639 6 ret = av_reallocp(&priv->packet[1], os->psize);
640
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (ret < 0)
641 ✗ return ret;
642
643 6 memcpy(priv->packet[1], os->buf + os->pstart, os->psize);
644 6 priv->len[1] = os->psize;
645
646 6 flags = 0;
647 6 skip_packet = 1;
648 }
649
650
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12244 times.
12252 if (flags & VORBIS_FLAG_SETUP) {
651
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
8 if (vorbis_check_packet_order(s, priv, VORBIS_PACKET_SETUP) < 0)
652 2 return 1;
653
654 6 ret = av_reallocp(&priv->packet[2], os->psize);
655
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (ret < 0)
656 ✗ return ret;
657
658 6 memcpy(priv->packet[2], os->buf + os->pstart, os->psize);
659 6 priv->len[2] = os->psize;
660
661 6 skip_packet = 1;
662 }
663
664
2/2
✓ Branch 0 taken 12231 times.
✓ Branch 1 taken 19 times.
12250 if (!skip_packet)
665 12231 vorbis_check_packet_order(s, priv, os->buf[os->pstart] & 1 ?
666 12231 VORBIS_PACKET_RESERVED : VORBIS_PACKET_DATA);
667
668 /* All three headers for the new chained stream have been collected;
669 * pack them into new extradata to be attached to the next data packet. */
670
6/6
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 12231 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
12250 if (priv->packet[0] && priv->packet[1] && priv->packet[2]) {
671 6 av_freep(&os->new_extradata);
672 6 ret = fixup_vorbis_headers(s, priv, &os->new_extradata);
673
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (ret < 0) {
674 ✗ os->new_extradata_size = 0;
675 ✗ return ret;
676 }
677 6 os->new_extradata_size = ret;
678
679 6 av_vorbis_parse_free(&priv->vp);
680 6 priv->vp = av_vorbis_parse_init(os->new_extradata, os->new_extradata_size);
681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!priv->vp) {
682 ✗ av_log(s, AV_LOG_ERROR, "Failed to re-initialize Vorbis parser\n");
683 ✗ return AVERROR_INVALIDDATA;
684 }
685
686 /* Reset bos_page_pos so the next packet will initialize it for the
687 * new chained stream. */
688 6 priv->bos_page_pos = -1;
689 }
690
691 12250 return skip_packet;
692 }
693
694 const struct ogg_codec ff_vorbis_codec = {
695 .magic = "\001vorbis",
696 .magicsize = 7,
697 .header = vorbis_header,
698 .packet = vorbis_packet,
699 .cleanup = vorbis_cleanup,
700 .nb_header = 3,
701 };
702