FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggdec.c
Date: 2026-09-28 23:39:34
Exec Total Coverage
Lines: 477 568 84.0%
Functions: 20 20 100.0%
Branches: 242 335 72.2%

Line Branch Exec Source
1 /*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
5 */
6
7 /*
8 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
9
10 Permission is hereby granted, free of charge, to any person
11 obtaining a copy of this software and associated documentation
12 files (the "Software"), to deal in the Software without
13 restriction, including without limitation the rights to use, copy,
14 modify, merge, publish, distribute, sublicense, and/or sell copies
15 of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
29 */
30
31 #include <stdio.h>
32 #include "libavutil/avassert.h"
33 #include "libavutil/intreadwrite.h"
34 #include "libavutil/mem.h"
35 #include "avio_internal.h"
36 #include "demux.h"
37 #include "oggdec.h"
38 #include "avformat.h"
39 #include "internal.h"
40
41 #define MAX_PAGE_SIZE 65307
42 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
43
44 static const struct ogg_codec * const ogg_codecs[] = {
45 &ff_skeleton_codec,
46 &ff_dirac_codec,
47 &ff_speex_codec,
48 &ff_vorbis_codec,
49 &ff_theora_codec,
50 &ff_flac_codec,
51 &ff_opus_codec,
52 &ff_vp8_codec,
53 &ff_old_dirac_codec,
54 &ff_old_flac_codec,
55 &ff_ogm_video_codec,
56 &ff_ogm_audio_codec,
57 &ff_ogm_text_codec,
58 &ff_ogm_old_codec,
59 NULL
60 };
61
62 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
63 static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
64 static int ogg_restore(AVFormatContext *s);
65
66 76 static void free_stream(AVFormatContext *s, int i)
67 {
68 76 struct ogg *ogg = s->priv_data;
69 76 struct ogg_stream *stream = &ogg->streams[i];
70
71 76 av_freep(&stream->buf);
72
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 if (stream->codec &&
73
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 42 times.
76 stream->codec->cleanup) {
74 34 stream->codec->cleanup(s, i);
75 }
76
77 76 av_freep(&stream->private);
78 76 av_freep(&stream->new_metadata);
79 76 av_freep(&stream->new_extradata);
80 76 }
81
82 //FIXME We could avoid some structure duplication
83 112 static int ogg_save(AVFormatContext *s)
84 {
85 112 struct ogg *ogg = s->priv_data;
86 struct ogg_state *ost =
87 112 av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
88 int i;
89 112 int ret = 0;
90
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (!ost)
92 ✗ return AVERROR(ENOMEM);
93
94 112 ost->pos = avio_tell(s->pb);
95 112 ost->curidx = ogg->curidx;
96 112 ost->next = ogg->state;
97 112 ost->nstreams = ogg->nstreams;
98 112 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
99
100
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 112 times.
228 for (i = 0; i < ogg->nstreams; i++) {
101 116 struct ogg_stream *os = ogg->streams + i;
102 116 os->buf = av_mallocz(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
103
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 if (os->buf)
104 116 memcpy(os->buf, ost->streams[i].buf, os->bufpos);
105 else
106 ✗ ret = AVERROR(ENOMEM);
107 116 os->new_metadata = NULL;
108 116 os->new_metadata_size = 0;
109 116 os->new_extradata = NULL;
110 116 os->new_extradata_size = 0;
111 }
112
113 112 ogg->state = ost;
114
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (ret < 0)
116 ✗ ogg_restore(s);
117
118 112 return ret;
119 }
120
121 112 static int ogg_restore(AVFormatContext *s)
122 {
123 112 struct ogg *ogg = s->priv_data;
124 112 AVIOContext *bc = s->pb;
125 112 struct ogg_state *ost = ogg->state;
126 int i, err;
127
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (!ost)
129 ✗ return 0;
130
131 112 ogg->state = ost->next;
132
133
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 112 times.
228 for (i = 0; i < ogg->nstreams; i++) {
134 116 struct ogg_stream *stream = &ogg->streams[i];
135 116 av_freep(&stream->buf);
136 116 av_freep(&stream->new_metadata);
137 116 av_freep(&stream->new_extradata);
138
139
3/4
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 98 times.
116 if (i >= ost->nstreams || !ost->streams[i].private) {
140 18 free_stream(s, i);
141 }
142 }
143
144 112 avio_seek(bc, ost->pos, SEEK_SET);
145 112 ogg->page_pos = -1;
146 112 ogg->curidx = ost->curidx;
147 112 ogg->nstreams = ost->nstreams;
148
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
112 if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
149 sizeof(*ogg->streams))) < 0) {
150 ✗ ogg->nstreams = 0;
151 ✗ return err;
152 } else
153 112 memcpy(ogg->streams, ost->streams,
154 112 ost->nstreams * sizeof(*ogg->streams));
155
156 112 av_free(ost);
157
158 112 return 0;
159 }
160
161 362 static int ogg_reset(AVFormatContext *s)
162 {
163 362 struct ogg *ogg = s->priv_data;
164 int i;
165 362 int64_t start_pos = avio_tell(s->pb);
166
167
2/2
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 362 times.
726 for (i = 0; i < ogg->nstreams; i++) {
168 364 struct ogg_stream *os = ogg->streams + i;
169 364 os->bufpos = 0;
170 364 os->pstart = 0;
171 364 os->psize = 0;
172 364 os->granule = -1;
173 364 os->lastpts = AV_NOPTS_VALUE;
174 364 os->lastdts = AV_NOPTS_VALUE;
175 364 os->sync_pos = -1;
176 364 os->page_pos = 0;
177 364 os->nsegs = 0;
178 364 os->segp = 0;
179 364 os->incomplete = 0;
180 364 os->got_data = 0;
181
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 254 times.
364 if (start_pos <= ffformatcontext(s)->data_offset) {
182 110 os->lastpts = 0;
183 }
184 364 os->start_trimming = 0;
185 364 os->end_trimming = 0;
186 364 av_freep(&os->new_metadata);
187 364 os->new_metadata_size = 0;
188 364 av_freep(&os->new_extradata);
189 364 os->new_extradata_size = 0;
190 }
191
192 362 ogg->page_pos = -1;
193 362 ogg->curidx = -1;
194
195 362 return 0;
196 }
197
198 82 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
199 {
200 int i;
201
202
1/2
✓ Branch 0 taken 423 times.
✗ Branch 1 not taken.
423 for (i = 0; ogg_codecs[i]; i++)
203
1/2
✓ Branch 0 taken 423 times.
✗ Branch 1 not taken.
423 if (size >= ogg_codecs[i]->magicsize &&
204
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 341 times.
423 !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
205 82 return ogg_codecs[i];
206
207 ✗ return NULL;
208 }
209
210 /**
211 * Replace the current stream with a new one. This is a typical webradio
212 * situation where a new audio stream spawn (identified with a new serial) and
213 * must replace the previous one (track switch).
214 */
215 24 static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic, int page_size,
216 int probing)
217 {
218 24 struct ogg *ogg = s->priv_data;
219 struct ogg_stream *os;
220 const struct ogg_codec *codec;
221 24 int i = 0;
222
223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (ogg->nstreams != 1) {
224 ✗ avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
225 ✗ return AVERROR_PATCHWELCOME;
226 }
227
228 /* Check for codecs */
229 24 codec = ogg_find_codec(magic, page_size);
230
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24 if (!codec && !probing) {
231 ✗ av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
232 ✗ return AVERROR_INVALIDDATA;
233 }
234
235 24 os = &ogg->streams[0];
236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (os->codec != codec)
237 ✗ return AVERROR(EINVAL);
238
239 24 os->serial = serial;
240 24 os->codec = codec;
241 24 os->serial = serial;
242 24 os->lastpts = 0;
243 24 os->lastdts = 0;
244 24 os->flags = 0;
245 24 os->start_trimming = 0;
246 24 os->end_trimming = 0;
247 24 os->replace = 1;
248
249 24 return i;
250 }
251
252 58 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
253 {
254 58 struct ogg *ogg = s->priv_data;
255 58 int idx = ogg->nstreams;
256 AVStream *st;
257 struct ogg_stream *os;
258
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (ogg->state) {
260 ✗ av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
261 "in between Ogg context save/restore operations.\n");
262 ✗ return AVERROR_BUG;
263 }
264
265 /* Allocate and init a new Ogg Stream */
266
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
58 if (!(os = av_realloc_array(ogg->streams, ogg->nstreams + 1,
267 sizeof(*ogg->streams))))
268 ✗ return AVERROR(ENOMEM);
269 58 ogg->streams = os;
270 58 os = ogg->streams + idx;
271 58 memset(os, 0, sizeof(*os));
272 58 os->serial = serial;
273 58 os->bufsize = DECODER_BUFFER_SIZE;
274 58 os->buf = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
275 58 os->header = -1;
276 58 os->start_granule = OGG_NOGRANULE_VALUE;
277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (!os->buf)
278 ✗ return AVERROR(ENOMEM);
279
280 /* Create the associated AVStream */
281 58 st = avformat_new_stream(s, NULL);
282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (!st) {
283 ✗ av_freep(&os->buf);
284 ✗ return AVERROR(ENOMEM);
285 }
286 58 st->id = idx;
287 58 avpriv_set_pts_info(st, 64, 1, 1000000);
288
289 58 ogg->nstreams++;
290 58 return idx;
291 }
292
293 82 static int data_packets_seen(const struct ogg *ogg)
294 {
295 int i;
296
297
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 58 times.
84 for (i = 0; i < ogg->nstreams; i++)
298
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
26 if (ogg->streams[i].got_data)
299 24 return 1;
300 58 return 0;
301 }
302
303 1860 static int buf_realloc(struct ogg_stream *os, int size)
304 {
305 /* Even if invalid guarantee there's enough memory to read the page */
306
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 1822 times.
1860 if (os->bufsize - os->bufpos < size) {
307 uint8_t *nb;
308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (os->bufsize > (UINT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) / 2)
309 ✗ return AVERROR(ENOMEM);
310 38 nb = av_realloc(os->buf, 2*os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (!nb)
312 ✗ return AVERROR(ENOMEM);
313 38 os->buf = nb;
314 38 os->bufsize *= 2;
315 }
316
317 1860 return 0;
318 }
319
320 2002 static int ogg_read_page(AVFormatContext *s, int *sid, int probing)
321 {
322 2002 AVIOContext *bc = s->pb;
323 2002 struct ogg *ogg = s->priv_data;
324 struct ogg_stream *os;
325 2002 int ret, i = 0;
326 int flags, nsegs;
327 uint64_t gp;
328 uint32_t serial;
329 uint32_t crc, crc_tmp;
330 2002 int size = 0, idx;
331 int64_t version, page_pos;
332 int64_t start_pos;
333 uint8_t sync[4];
334 uint8_t segments[255];
335 uint8_t *readout_buf;
336 2002 int sp = 0;
337
338 2002 ret = avio_read(bc, sync, 4);
339
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1938 times.
2002 if (ret < 4)
340
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 return ret < 0 ? ret : AVERROR_EOF;
341
342 do {
343 int c;
344
345
2/2
✓ Branch 0 taken 4650 times.
✓ Branch 1 taken 701661 times.
706311 if (sync[sp & 3] == 'O' &&
346
2/2
✓ Branch 0 taken 1877 times.
✓ Branch 1 taken 2773 times.
4650 sync[(sp + 1) & 3] == 'g' &&
347
3/4
✓ Branch 0 taken 1860 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1860 times.
✗ Branch 3 not taken.
1877 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
348 1860 break;
349
350
4/6
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 704320 times.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 131 times.
704451 if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
351 ✗ memset(sync, 0, 4);
352 ✗ avio_seek(bc, ogg->page_pos+4, SEEK_SET);
353 ✗ ogg->page_pos = -1;
354 }
355
356 704451 c = avio_r8(bc);
357
358
2/2
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 704373 times.
704451 if (avio_feof(bc))
359 78 return AVERROR_EOF;
360
361 704373 sync[sp++ & 3] = c;
362
1/2
✓ Branch 0 taken 704373 times.
✗ Branch 1 not taken.
704373 } while (i++ < MAX_PAGE_SIZE);
363
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1860 times.
1860 if (i >= MAX_PAGE_SIZE) {
365 ✗ av_log(s, AV_LOG_INFO, "cannot find sync word\n");
366 ✗ return AVERROR_INVALIDDATA;
367 }
368
369 /* 0x4fa9b05f = av_crc(AV_CRC_32_IEEE, 0x0, "OggS", 4) */
370 1860 ffio_init_checksum(bc, ff_crc04C11DB7_update, 0x4fa9b05f);
371
372 /* To rewind if checksum is bad/check magic on switches - this is the max packet size */
373 1860 ret = ffio_ensure_seekback(bc, MAX_PAGE_SIZE);
374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1860 times.
1860 if (ret < 0)
375 ✗ return ret;
376 1860 start_pos = avio_tell(bc);
377
378 1860 version = avio_r8(bc);
379 1860 flags = avio_r8(bc);
380 1860 gp = avio_rl64(bc);
381 1860 serial = avio_rl32(bc);
382 1860 avio_rl32(bc); /* seq */
383
384 1860 crc_tmp = ffio_get_checksum(bc);
385 1860 crc = avio_rb32(bc);
386 1860 crc_tmp = ff_crc04C11DB7_update(crc_tmp, (uint8_t[4]){0}, 4);
387 1860 ffio_init_checksum(bc, ff_crc04C11DB7_update, crc_tmp);
388
389 1860 nsegs = avio_r8(bc);
390 1860 page_pos = avio_tell(bc) - 27;
391
392 1860 ret = avio_read(bc, segments, nsegs);
393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1860 times.
1860 if (ret < nsegs)
394 ✗ return ret < 0 ? ret : AVERROR_EOF;
395
396
2/2
✓ Branch 0 taken 48034 times.
✓ Branch 1 taken 1860 times.
49894 for (i = 0; i < nsegs; i++)
397 48034 size += segments[i];
398
399 1860 idx = ogg_find_stream(ogg, serial);
400
2/2
✓ Branch 0 taken 1778 times.
✓ Branch 1 taken 82 times.
1860 if (idx >= 0) {
401 1778 os = ogg->streams + idx;
402
403 1778 ret = buf_realloc(os, size);
404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1778 times.
1778 if (ret < 0)
405 ✗ return ret;
406
407 1778 readout_buf = os->buf + os->bufpos;
408 } else {
409 82 readout_buf = av_malloc(size);
410 }
411
412 1860 ret = avio_read(bc, readout_buf, size);
413
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 1816 times.
1860 if (ret < size) {
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (idx < 0)
415 ✗ av_free(readout_buf);
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 return ret < 0 ? ret : AVERROR_EOF;
417 }
418
419
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1816 times.
1816 if (crc ^ ffio_get_checksum(bc)) {
420 ✗ av_log(s, AV_LOG_ERROR, "CRC mismatch!\n");
421 ✗ if (idx < 0)
422 ✗ av_free(readout_buf);
423 ✗ avio_seek(bc, start_pos, SEEK_SET);
424 ✗ *sid = -1;
425 ✗ return 0;
426 }
427
428 /* Since we're almost sure its a valid packet, checking the version after
429 * the checksum lets the demuxer be more tolerant */
430
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1816 times.
1816 if (version) {
431 ✗ av_log(s, AV_LOG_ERROR, "Invalid Ogg vers!\n");
432 ✗ if (idx < 0)
433 ✗ av_free(readout_buf);
434 ✗ avio_seek(bc, start_pos, SEEK_SET);
435 ✗ *sid = -1;
436 ✗ return 0;
437 }
438
439 /* CRC is correct so we can be 99% sure there's an actual change here */
440
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 1734 times.
1816 if (idx < 0) {
441
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 58 times.
82 if (data_packets_seen(ogg))
442 24 idx = ogg_replace_stream(s, serial, readout_buf, size, probing);
443 else
444 58 idx = ogg_new_stream(s, serial);
445
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (idx < 0) {
447 ✗ av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
448 ✗ av_free(readout_buf);
449 ✗ return idx;
450 }
451
452 82 os = ogg->streams + idx;
453
454 82 ret = buf_realloc(os, size);
455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (ret < 0) {
456 ✗ av_free(readout_buf);
457 ✗ return ret;
458 }
459
460 82 memcpy(os->buf + os->bufpos, readout_buf, size);
461 82 av_free(readout_buf);
462 }
463
464 1816 ogg->page_pos = page_pos;
465 1816 os->page_pos = page_pos;
466 1816 os->nsegs = nsegs;
467 1816 os->segp = 0;
468 1816 os->got_data = !(flags & OGG_FLAG_BOS);
469 1816 os->bufpos += size;
470 1816 os->granule = gp;
471 1816 os->flags = flags;
472 1816 memcpy(os->segments, segments, nsegs);
473 1816 memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
474
475
3/4
✓ Branch 0 taken 1174 times.
✓ Branch 1 taken 642 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1174 times.
1816 if (flags & OGG_FLAG_CONT || os->incomplete) {
476
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 472 times.
642 if (!os->psize) {
477 // If this is the very first segment we started
478 // playback in the middle of a continuation packet.
479 // Discard it since we missed the start of it.
480
1/2
✓ Branch 0 taken 402 times.
✗ Branch 1 not taken.
402 while (os->segp < os->nsegs) {
481 402 int seg = os->segments[os->segp++];
482 402 os->pstart += seg;
483
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 232 times.
402 if (seg < 255)
484 170 break;
485 }
486 170 os->sync_pos = os->page_pos;
487 }
488 } else {
489 1174 os->psize = 0;
490 1174 os->sync_pos = os->page_pos;
491 }
492
493 /* This function is always called with sid != NULL */
494 1816 *sid = idx;
495
496 1816 return 0;
497 }
498
499 /**
500 * @brief find the next Ogg packet
501 * @param *sid is set to the stream for the packet or -1 if there is
502 * no matching stream, in that case assume all other return
503 * values to be uninitialized.
504 * @return negative value on error or EOF.
505 */
506 13055 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
507 int64_t *fpos)
508 {
509 13055 FFFormatContext *const si = ffformatcontext(s);
510 13055 struct ogg *ogg = s->priv_data;
511 int idx, i, ret;
512 struct ogg_stream *os;
513 13055 int complete = 0;
514 13055 int segp = 0, psize = 0;
515
516 13055 av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
517
2/2
✓ Branch 0 taken 12845 times.
✓ Branch 1 taken 210 times.
13055 if (sid)
518 12845 *sid = -1;
519
520 do {
521 13507 idx = ogg->curidx;
522
523
2/2
✓ Branch 0 taken 1292 times.
✓ Branch 1 taken 13377 times.
14669 while (idx < 0) {
524 1292 ret = ogg_read_page(s, &idx, 0);
525
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 1162 times.
1292 if (ret < 0)
526 130 return ret;
527 }
528
529 13377 os = ogg->streams + idx;
530
531 13377 av_log(s, AV_LOG_TRACE, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
532 idx, os->pstart, os->psize, os->segp, os->nsegs);
533
534
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 13319 times.
13377 if (!os->codec) {
535
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if (os->header < 0) {
536 58 os->codec = ogg_find_codec(os->buf, os->bufpos);
537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (!os->codec) {
538 ✗ av_log(s, AV_LOG_WARNING, "Codec not found\n");
539 ✗ os->header = 0;
540 ✗ return 0;
541 }
542 } else {
543 ✗ return 0;
544 }
545 }
546
547 13377 segp = os->segp;
548 13377 psize = os->psize;
549
550
2/2
✓ Branch 0 taken 27107 times.
✓ Branch 1 taken 452 times.
27559 while (os->segp < os->nsegs) {
551 27107 int ss = os->segments[os->segp++];
552 27107 os->psize += ss;
553
2/2
✓ Branch 0 taken 12925 times.
✓ Branch 1 taken 14182 times.
27107 if (ss < 255) {
554 12925 complete = 1;
555 12925 break;
556 }
557 }
558
559
3/4
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 12925 times.
✓ Branch 2 taken 452 times.
✗ Branch 3 not taken.
13377 if (!complete && os->segp == os->nsegs) {
560 452 ogg->curidx = -1;
561 // Do not set incomplete for empty packets.
562 // Together with the code in ogg_read_page
563 // that discards all continuation of empty packets
564 // we would get an infinite loop.
565 452 os->incomplete = !!os->psize;
566 }
567
2/2
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 12925 times.
13377 } while (!complete);
568
569
570
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 12747 times.
12925 if (os->granule == -1)
571 178 av_log(s, AV_LOG_WARNING,
572 "Page at %"PRId64" is missing granule\n",
573 os->page_pos);
574
575 12925 ogg->curidx = idx;
576 12925 os->incomplete = 0;
577
578 // the packet started at the first segment of the page it completes on
579 12925 os->page_start = segp == 0;
580
581
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 12711 times.
12925 if (os->header) {
582
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 214 times.
214 if ((ret = os->codec->header(s, idx)) < 0) {
583 ✗ av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret));
584 ✗ return ret;
585 }
586 214 os->header = ret;
587
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 154 times.
214 if (!os->header) {
588 60 os->segp = segp;
589 60 os->psize = psize;
590
591 // We have reached the first non-header packet in this stream.
592 // Unfortunately more header packets may still follow for others,
593 // but if we continue with header parsing we may lose data packets.
594 60 ogg->headers = 1;
595
596 // Update the header state for all streams and
597 // compute the data_offset.
598
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 4 times.
60 if (!si->data_offset)
599 56 si->data_offset = os->sync_pos;
600
601
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 60 times.
126 for (i = 0; i < ogg->nstreams; i++) {
602 66 struct ogg_stream *cur_os = ogg->streams + i;
603
604 // if we have a partial non-header packet, its start is
605 // obviously at or after the data start
606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if (cur_os->incomplete)
607 ✗ si->data_offset = FFMIN(si->data_offset, cur_os->sync_pos);
608 }
609 } else {
610 154 os->nb_header++;
611 154 os->pstart += os->psize;
612 154 os->psize = 0;
613 }
614 } else {
615 12711 os->pflags = 0;
616 12711 os->pduration = 0;
617
618 12711 ret = 0;
619
2/4
✓ Branch 0 taken 12711 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12711 times.
✗ Branch 3 not taken.
12711 if (os->codec && os->codec->packet) {
620
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12711 times.
12711 if ((ret = os->codec->packet(s, idx)) < 0) {
621 ✗ av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret));
622 ✗ return ret;
623 }
624 }
625
626
2/2
✓ Branch 0 taken 12647 times.
✓ Branch 1 taken 64 times.
12711 if (!ret) {
627
1/2
✓ Branch 0 taken 12647 times.
✗ Branch 1 not taken.
12647 if (sid)
628 12647 *sid = idx;
629
2/2
✓ Branch 0 taken 12562 times.
✓ Branch 1 taken 85 times.
12647 if (dstart)
630 12562 *dstart = os->pstart;
631
2/2
✓ Branch 0 taken 12562 times.
✓ Branch 1 taken 85 times.
12647 if (dsize)
632 12562 *dsize = os->psize;
633
2/2
✓ Branch 0 taken 12562 times.
✓ Branch 1 taken 85 times.
12647 if (fpos)
634 12562 *fpos = os->sync_pos;
635 }
636
637 12711 os->pstart += os->psize;
638 12711 os->psize = 0;
639
2/2
✓ Branch 0 taken 596 times.
✓ Branch 1 taken 12115 times.
12711 if(os->pstart == os->bufpos)
640 596 os->bufpos = os->pstart = 0;
641 12711 os->sync_pos = os->page_pos;
642 }
643
644 // determine whether there are more complete packets in this page
645 // if not, the page's granule will apply to this packet
646 12925 os->page_end = 1;
647
2/2
✓ Branch 0 taken 18776 times.
✓ Branch 1 taken 825 times.
19601 for (i = os->segp; i < os->nsegs; i++)
648
2/2
✓ Branch 0 taken 12100 times.
✓ Branch 1 taken 6676 times.
18776 if (os->segments[i] < 255) {
649 12100 os->page_end = 0;
650 12100 break;
651 }
652
653
2/2
✓ Branch 0 taken 579 times.
✓ Branch 1 taken 12346 times.
12925 if (os->segp == os->nsegs)
654 579 ogg->curidx = -1;
655
656 12925 return 0;
657 }
658
659 56 static int ogg_get_length(AVFormatContext *s)
660 {
661 56 struct ogg *ogg = s->priv_data;
662 int i, ret;
663 int64_t size, end;
664 56 int streams_left=0;
665
666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
667 ✗ return 0;
668
669 // already set
670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (s->duration != AV_NOPTS_VALUE)
671 ✗ return 0;
672
673 56 size = avio_size(s->pb);
674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (size < 0)
675 ✗ return 0;
676 56 end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
677
678 56 ret = ogg_save(s);
679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ret < 0)
680 ✗ return ret;
681 56 avio_seek(s->pb, end, SEEK_SET);
682 56 ogg->page_pos = -1;
683
684
2/2
✓ Branch 1 taken 654 times.
✓ Branch 2 taken 56 times.
710 while (!ogg_read_page(s, &i, 1)) {
685
5/6
✓ Branch 0 taken 654 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 619 times.
✓ Branch 3 taken 35 times.
✓ Branch 4 taken 541 times.
✓ Branch 5 taken 78 times.
654 if (i >= 0 && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
686
1/2
✓ Branch 0 taken 541 times.
✗ Branch 1 not taken.
541 ogg->streams[i].codec) {
687 541 s->streams[i]->duration =
688 541 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 541 times.
541 if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
690 ✗ s->streams[i]->duration -= s->streams[i]->start_time;
691 ✗ streams_left-= (ogg->streams[i].got_start==-1);
692 ✗ ogg->streams[i].got_start= 1;
693
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 483 times.
541 } else if(!ogg->streams[i].got_start) {
694 58 ogg->streams[i].got_start= -1;
695 58 streams_left++;
696 }
697 }
698 }
699
700 56 ogg_restore(s);
701
702 56 ret = ogg_save(s);
703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ret < 0)
704 ✗ return ret;
705
706 56 avio_seek (s->pb, ffformatcontext(s)->data_offset, SEEK_SET);
707 56 ogg_reset(s);
708
3/4
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 56 times.
✓ Branch 3 taken 87 times.
✗ Branch 4 not taken.
143 while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
709 int64_t pts;
710
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 85 times.
87 if (i < 0) continue;
711 85 pts = ogg_calc_pts(s, i, NULL);
712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
85 if (s->streams[i]->duration == AV_NOPTS_VALUE)
713 ✗ continue;
714
6/6
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 39 times.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 1 times.
85 if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
715 43 s->streams[i]->duration -= pts;
716 43 ogg->streams[i].got_start= 1;
717 43 streams_left--;
718
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 24 times.
42 }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
719 15 ogg->streams[i].got_start= 1;
720 15 streams_left--;
721 }
722 }
723 56 ogg_restore (s);
724
725 56 return 0;
726 }
727
728 56 static int ogg_read_close(AVFormatContext *s)
729 {
730 56 struct ogg *ogg = s->priv_data;
731 int i;
732
733
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 56 times.
114 for (i = 0; i < ogg->nstreams; i++) {
734 58 free_stream(s, i);
735 }
736
737 56 ogg->nstreams = 0;
738
739 56 av_freep(&ogg->streams);
740 56 return 0;
741 }
742
743 56 static int ogg_read_header(AVFormatContext *s)
744 {
745 56 struct ogg *ogg = s->priv_data;
746 int ret, i;
747
748 56 ogg->curidx = -1;
749
750 //linear headers seek from start
751 do {
752 210 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
753
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (ret < 0)
754 ✗ return ret;
755
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 56 times.
210 } while (!ogg->headers);
756 56 av_log(s, AV_LOG_TRACE, "found headers\n");
757
758
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 56 times.
114 for (i = 0; i < ogg->nstreams; i++) {
759 58 struct ogg_stream *os = ogg->streams + i;
760
761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (ogg->streams[i].header < 0) {
762 ✗ av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
763 ✗ ogg->streams[i].codec = NULL;
764 ✗ av_freep(&ogg->streams[i].private);
765
2/4
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
58 } else if (os->codec && os->nb_header < os->codec->nb_header) {
766 ✗ av_log(s, AV_LOG_WARNING,
767 "Headers mismatch for stream %d: "
768 "expected %d received %d.\n",
769 ✗ i, os->codec->nb_header, os->nb_header);
770 ✗ if (s->error_recognition & AV_EF_EXPLODE)
771 ✗ return AVERROR_INVALIDDATA;
772 }
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (os->start_granule != OGG_NOGRANULE_VALUE)
774 ✗ os->lastpts = s->streams[i]->start_time =
775 ✗ ogg_gptopts(s, i, os->start_granule, NULL);
776 }
777
778 //linear granulepos seek from end
779 56 ret = ogg_get_length(s);
780
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ret < 0)
781 ✗ return ret;
782
783 56 return 0;
784 }
785
786 12647 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
787 {
788 12647 struct ogg *ogg = s->priv_data;
789 12647 struct ogg_stream *os = ogg->streams + idx;
790 12647 int64_t pts = AV_NOPTS_VALUE;
791
792
2/2
✓ Branch 0 taken 12217 times.
✓ Branch 1 taken 430 times.
12647 if (dts)
793 12217 *dts = AV_NOPTS_VALUE;
794
795
2/2
✓ Branch 0 taken 1337 times.
✓ Branch 1 taken 11310 times.
12647 if (os->lastpts != AV_NOPTS_VALUE) {
796 1337 pts = os->lastpts;
797 1337 os->lastpts = AV_NOPTS_VALUE;
798 }
799
2/2
✓ Branch 0 taken 1243 times.
✓ Branch 1 taken 11404 times.
12647 if (os->lastdts != AV_NOPTS_VALUE) {
800
2/2
✓ Branch 0 taken 1189 times.
✓ Branch 1 taken 54 times.
1243 if (dts)
801 1189 *dts = os->lastdts;
802 1243 os->lastdts = AV_NOPTS_VALUE;
803 }
804
2/2
✓ Branch 0 taken 634 times.
✓ Branch 1 taken 12013 times.
12647 if (os->page_end) {
805
2/2
✓ Branch 0 taken 625 times.
✓ Branch 1 taken 9 times.
634 if (os->granule != -1LL) {
806
2/4
✓ Branch 0 taken 625 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 625 times.
625 if (os->codec && os->codec->granule_is_start)
807 ✗ pts = ogg_gptopts(s, idx, os->granule, dts);
808 else
809 625 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
810 625 os->granule = -1LL;
811 }
812 }
813 12647 return pts;
814 }
815
816 12562 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
817 {
818 12562 struct ogg *ogg = s->priv_data;
819 12562 struct ogg_stream *os = ogg->streams + idx;
820 12562 int invalid = 0;
821
2/2
✓ Branch 0 taken 12414 times.
✓ Branch 1 taken 148 times.
12562 if (psize) {
822
3/3
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 181 times.
✓ Branch 2 taken 12193 times.
12414 switch (s->streams[idx]->codecpar->codec_id) {
823 40 case AV_CODEC_ID_THEORA:
824 40 invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
825 40 break;
826 181 case AV_CODEC_ID_VP8:
827 181 invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
828 }
829
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12409 times.
12414 if (invalid) {
830 5 os->pflags ^= AV_PKT_FLAG_KEY;
831 5 av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
832
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
833 }
834 }
835 12562 }
836
837 12265 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
838 {
839 struct ogg *ogg;
840 struct ogg_stream *os;
841 int idx, ret;
842 int pstart, psize;
843 int64_t fpos, pts, dts;
844
845
1/2
✓ Branch 0 taken 12265 times.
✗ Branch 1 not taken.
12265 if (s->io_repositioned) {
846 ✗ ogg_reset(s);
847 ✗ s->io_repositioned = 0;
848 }
849
850 //Get an ogg packet
851 12265 retry:
852 do {
853 12295 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
854
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 12247 times.
12295 if (ret < 0)
855 48 return ret;
856
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12217 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12217 times.
12247 } while (idx < 0 || !s->streams[idx]);
857
858 12217 ogg = s->priv_data;
859 12217 os = ogg->streams + idx;
860
861 // pflags might not be set until after this
862 12217 pts = ogg_calc_pts(s, idx, &dts);
863 12217 ogg_validate_keyframe(s, idx, pstart, psize);
864
865
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12217 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12217 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
866 ✗ goto retry;
867 12217 os->keyframe_seek = 0;
868
869 //Alloc a pkt
870 12217 ret = av_new_packet(pkt, psize);
871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12217 times.
12217 if (ret < 0)
872 ✗ return ret;
873 12217 pkt->stream_index = idx;
874 12217 memcpy(pkt->data, os->buf + pstart, psize);
875
876 12217 pkt->pts = pts;
877 12217 pkt->dts = dts;
878 12217 pkt->flags = os->pflags;
879 12217 pkt->duration = os->pduration;
880 12217 pkt->pos = fpos;
881
882
4/4
✓ Branch 0 taken 12204 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 12185 times.
12217 if (os->start_trimming || os->end_trimming) {
883 32 uint8_t *side_data = av_packet_new_side_data(pkt,
884 AV_PKT_DATA_SKIP_SAMPLES,
885 10);
886
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if(!side_data)
887 ✗ return AVERROR(ENOMEM);
888 32 AV_WL32(side_data + 0, os->start_trimming);
889 32 AV_WL32(side_data + 4, os->end_trimming);
890 32 os->start_trimming = 0;
891 32 os->end_trimming = 0;
892 }
893
894
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12205 times.
12217 if (os->replace) {
895 12 os->replace = 0;
896 12 pkt->dts = pkt->pts = AV_NOPTS_VALUE;
897 }
898
899
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 12171 times.
12217 if (os->new_metadata) {
900 46 ret = av_packet_add_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA,
901 os->new_metadata, os->new_metadata_size);
902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (ret < 0)
903 ✗ return ret;
904
905 46 os->new_metadata = NULL;
906 46 os->new_metadata_size = 0;
907 }
908
909
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12213 times.
12217 if (os->new_extradata) {
910 4 ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
911 os->new_extradata, os->new_extradata_size);
912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
913 ✗ return ret;
914
915 4 os->new_extradata = NULL;
916 4 os->new_extradata_size = 0;
917 }
918
919 12217 return psize;
920 }
921
922 124 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
923 int64_t *pos_arg, int64_t pos_limit)
924 {
925 124 struct ogg *ogg = s->priv_data;
926 124 AVIOContext *bc = s->pb;
927 124 int64_t pts = AV_NOPTS_VALUE;
928 124 int64_t keypos = -1;
929 int i;
930 int pstart, psize;
931 124 avio_seek(bc, *pos_arg, SEEK_SET);
932 124 ogg_reset(s);
933
934 466 while ( avio_tell(bc) <= pos_limit
935
4/4
✓ Branch 0 taken 463 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 381 times.
✓ Branch 4 taken 82 times.
466 && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
936
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 36 times.
381 if (i == stream_index) {
937 345 struct ogg_stream *os = ogg->streams + stream_index;
938 // Do not trust the last timestamps of an ogm video
939
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 317 times.
345 if ( (os->flags & OGG_FLAG_EOS)
940
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 && !(os->flags & OGG_FLAG_BOS)
941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 && os->codec == &ff_ogm_video_codec)
942 ✗ continue;
943 345 pts = ogg_calc_pts(s, i, NULL);
944 345 ogg_validate_keyframe(s, i, pstart, psize);
945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345 times.
345 if (os->pflags & AV_PKT_FLAG_KEY) {
946 ✗ keypos = *pos_arg;
947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345 times.
345 } else if (os->keyframe_seek) {
948 // if we had a previous keyframe but no pts for it,
949 // return that keyframe with this pts value.
950 ✗ if (keypos >= 0)
951 ✗ *pos_arg = keypos;
952 else
953 ✗ pts = AV_NOPTS_VALUE;
954 }
955 }
956
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 342 times.
381 if (pts != AV_NOPTS_VALUE)
957 39 break;
958 }
959 124 ogg_reset(s);
960 124 return pts;
961 }
962
963 29 static int ogg_read_seek(AVFormatContext *s, int stream_index,
964 int64_t timestamp, int flags)
965 {
966 29 struct ogg *ogg = s->priv_data;
967 29 struct ogg_stream *os = ogg->streams + stream_index;
968 int ret;
969
970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 av_assert0(stream_index < ogg->nstreams);
971 // Ensure everything is reset even when seeking via
972 // the generated index.
973 29 ogg_reset(s);
974
975 // Try seeking to a keyframe first. If this fails (very possible),
976 // av_seek_frame will fall back to ignoring keyframes
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
978 ✗ && !(flags & AVSEEK_FLAG_ANY))
979 ✗ os->keyframe_seek = 1;
980
981 29 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
982 29 ogg_reset(s);
983 29 os = ogg->streams + stream_index;
984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (ret < 0)
985 ✗ os->keyframe_seek = 0;
986 29 return ret;
987 }
988
989 8079 static int ogg_probe(const AVProbeData *p)
990 {
991
3/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 8028 times.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
8079 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
992 51 return AVPROBE_SCORE_MAX;
993 8028 return 0;
994 }
995
996 const FFInputFormat ff_ogg_demuxer = {
997 .p.name = "ogg",
998 .p.long_name = NULL_IF_CONFIG_SMALL("Ogg"),
999 .p.extensions = "ogg",
1000 .p.flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,
1001 .priv_data_size = sizeof(struct ogg),
1002 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
1003 .read_probe = ogg_probe,
1004 .read_header = ogg_read_header,
1005 .read_packet = ogg_read_packet,
1006 .read_close = ogg_read_close,
1007 .read_seek = ogg_read_seek,
1008 .read_timestamp = ogg_read_timestamp,
1009 };
1010