FFmpeg coverage


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