FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggdec.c
Date: 2026-04-24 19:58:39
Exec Total Coverage
Lines: 475 565 84.1%
Functions: 20 20 100.0%
Branches: 236 333 70.9%

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