FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggdec.c
Date: 2024-03-29 01:21:52
Exec Total Coverage
Lines: 438 546 80.2%
Functions: 19 20 95.0%
Branches: 221 325 68.0%

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