oggdec: check stream index before using it in ogg_get_length()
[ffmpeg.git] / libavformat / oggdec.c
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 "oggdec.h"
34 #include "avformat.h"
35 #include "internal.h"
36 #include "vorbiscomment.h"
37
38 #define MAX_PAGE_SIZE 65307
39 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40
41 static const struct ogg_codec * const ogg_codecs[] = {
42     &ff_skeleton_codec,
43     &ff_dirac_codec,
44     &ff_speex_codec,
45     &ff_vorbis_codec,
46     &ff_theora_codec,
47     &ff_flac_codec,
48     &ff_celt_codec,
49     &ff_opus_codec,
50     &ff_old_dirac_codec,
51     &ff_old_flac_codec,
52     &ff_ogm_video_codec,
53     &ff_ogm_audio_codec,
54     &ff_ogm_text_codec,
55     &ff_ogm_old_codec,
56     NULL
57 };
58
59 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
60
61 //FIXME We could avoid some structure duplication
62 static int ogg_save(AVFormatContext *s)
63 {
64     struct ogg *ogg = s->priv_data;
65     struct ogg_state *ost =
66         av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
67     int i;
68     ost->pos = avio_tell (s->pb);
69     ost->curidx = ogg->curidx;
70     ost->next = ogg->state;
71     ost->nstreams = ogg->nstreams;
72     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
73
74     for (i = 0; i < ogg->nstreams; i++){
75         struct ogg_stream *os = ogg->streams + i;
76         os->buf = av_mallocz (os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
77         memcpy (os->buf, ost->streams[i].buf, os->bufpos);
78     }
79
80     ogg->state = ost;
81
82     return 0;
83 }
84
85 static int ogg_restore(AVFormatContext *s, int discard)
86 {
87     struct ogg *ogg = s->priv_data;
88     AVIOContext *bc = s->pb;
89     struct ogg_state *ost = ogg->state;
90     int i;
91
92     if (!ost)
93         return 0;
94
95     ogg->state = ost->next;
96
97     if (!discard){
98         struct ogg_stream *old_streams = ogg->streams;
99
100         for (i = 0; i < ogg->nstreams; i++)
101             av_free (ogg->streams[i].buf);
102
103         avio_seek (bc, ost->pos, SEEK_SET);
104         ogg->curidx = ost->curidx;
105         ogg->nstreams = ost->nstreams;
106         ogg->streams = av_realloc (ogg->streams,
107                                    ogg->nstreams * sizeof (*ogg->streams));
108
109         if (ogg->streams) {
110             memcpy(ogg->streams, ost->streams,
111                    ost->nstreams * sizeof(*ogg->streams));
112         } else {
113             av_free(old_streams);
114             ogg->nstreams = 0;
115         }
116     }
117
118     av_free (ost);
119
120     return 0;
121 }
122
123 static int ogg_reset(AVFormatContext *s)
124 {
125     struct ogg *ogg = s->priv_data;
126     int i;
127     int64_t start_pos = avio_tell(s->pb);
128
129     for (i = 0; i < ogg->nstreams; i++){
130         struct ogg_stream *os = ogg->streams + i;
131         os->bufpos = 0;
132         os->pstart = 0;
133         os->psize = 0;
134         os->granule = -1;
135         os->lastpts = AV_NOPTS_VALUE;
136         os->lastdts = AV_NOPTS_VALUE;
137         os->sync_pos = -1;
138         os->page_pos = 0;
139         os->nsegs = 0;
140         os->segp = 0;
141         os->incomplete = 0;
142         if (start_pos <= s->data_offset) {
143             os->lastpts = 0;
144         }
145     }
146
147     ogg->curidx = -1;
148
149     return 0;
150 }
151
152 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
153 {
154     int i;
155
156     for (i = 0; ogg_codecs[i]; i++)
157         if (size >= ogg_codecs[i]->magicsize &&
158             !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
159             return ogg_codecs[i];
160
161     return NULL;
162 }
163
164 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
165 {
166
167     struct ogg *ogg = s->priv_data;
168     int idx = ogg->nstreams++;
169     AVStream *st;
170     struct ogg_stream *os;
171
172     ogg->streams = av_realloc (ogg->streams,
173                                ogg->nstreams * sizeof (*ogg->streams));
174     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
175     os = ogg->streams + idx;
176     os->serial = serial;
177     os->bufsize = DECODER_BUFFER_SIZE;
178     os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
179     os->header = -1;
180
181     if (new_avstream) {
182         st = avformat_new_stream(s, NULL);
183         if (!st)
184             return AVERROR(ENOMEM);
185
186         st->id = idx;
187         avpriv_set_pts_info(st, 64, 1, 1000000);
188     }
189
190     return idx;
191 }
192
193 static int ogg_new_buf(struct ogg *ogg, int idx)
194 {
195     struct ogg_stream *os = ogg->streams + idx;
196     uint8_t *nb = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
197     int size = os->bufpos - os->pstart;
198     if(os->buf){
199         memcpy(nb, os->buf + os->pstart, size);
200         av_free(os->buf);
201     }
202     os->buf = nb;
203     os->bufpos = size;
204     os->pstart = 0;
205
206     return 0;
207 }
208
209 static int ogg_read_page(AVFormatContext *s, int *str)
210 {
211     AVIOContext *bc = s->pb;
212     struct ogg *ogg = s->priv_data;
213     struct ogg_stream *os;
214     int ret, i = 0;
215     int flags, nsegs;
216     uint64_t gp;
217     uint32_t serial;
218     int size, idx;
219     uint8_t sync[4];
220     int sp = 0;
221
222     ret = avio_read(bc, sync, 4);
223     if (ret < 4)
224         return ret < 0 ? ret : AVERROR_EOF;
225
226     do{
227         int c;
228
229         if (sync[sp & 3] == 'O' &&
230             sync[(sp + 1) & 3] == 'g' &&
231             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
232             break;
233
234         c = avio_r8(bc);
235         if (url_feof(bc))
236             return AVERROR_EOF;
237         sync[sp++ & 3] = c;
238     }while (i++ < MAX_PAGE_SIZE);
239
240     if (i >= MAX_PAGE_SIZE){
241         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
242         return AVERROR_INVALIDDATA;
243     }
244
245     if (avio_r8(bc) != 0){      /* version */
246         av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
247         return AVERROR_INVALIDDATA;
248     }
249
250     flags = avio_r8(bc);
251     gp = avio_rl64 (bc);
252     serial = avio_rl32 (bc);
253     avio_skip(bc, 8); /* seq, crc */
254     nsegs = avio_r8(bc);
255
256     idx = ogg_find_stream (ogg, serial);
257     if (idx < 0){
258         if (ogg->headers) {
259             int n;
260
261             if (ogg->nstreams != 1) {
262                 av_log_missing_feature(s, "Changing stream parameters in multistream ogg is", 0);
263                 return idx;
264             }
265
266             for (n = 0; n < ogg->nstreams; n++) {
267                 av_freep(&ogg->streams[n].buf);
268                 if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
269                     av_freep(&ogg->streams[n].private);
270             }
271             ogg->curidx   = -1;
272             ogg->nstreams = 0;
273             idx = ogg_new_stream(s, serial, 0);
274         } else {
275             idx = ogg_new_stream(s, serial, 1);
276         }
277         if (idx < 0) {
278             av_log (s, AV_LOG_ERROR, "failed to create stream (OOM?)\n");
279             return idx;
280         }
281     }
282
283     os = ogg->streams + idx;
284     os->page_pos = avio_tell(bc) - 27;
285
286     if(os->psize > 0)
287         ogg_new_buf(ogg, idx);
288
289     ret = avio_read(bc, os->segments, nsegs);
290     if (ret < nsegs)
291         return ret < 0 ? ret : AVERROR_EOF;
292
293     os->nsegs = nsegs;
294     os->segp = 0;
295
296     size = 0;
297     for (i = 0; i < nsegs; i++)
298         size += os->segments[i];
299
300     if (flags & OGG_FLAG_CONT || os->incomplete){
301         if (!os->psize){
302             // If this is the very first segment we started
303             // playback in the middle of a continuation packet.
304             // Discard it since we missed the start of it.
305             while (os->segp < os->nsegs){
306                 int seg = os->segments[os->segp++];
307                 os->pstart += seg;
308                 if (seg < 255)
309                     break;
310             }
311             os->sync_pos = os->page_pos;
312         }
313     }else{
314         os->psize = 0;
315         os->sync_pos = os->page_pos;
316     }
317
318     if (os->bufsize - os->bufpos < size){
319         uint8_t *nb = av_malloc ((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
320         memcpy (nb, os->buf, os->bufpos);
321         av_free (os->buf);
322         os->buf = nb;
323     }
324
325     ret = avio_read(bc, os->buf + os->bufpos, size);
326     if (ret < size)
327         return ret < 0 ? ret : AVERROR_EOF;
328
329     os->bufpos += size;
330     os->granule = gp;
331     os->flags = flags;
332
333     memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
334     if (str)
335         *str = idx;
336
337     return 0;
338 }
339
340 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
341                       int64_t *fpos)
342 {
343     struct ogg *ogg = s->priv_data;
344     int idx, i, ret;
345     struct ogg_stream *os;
346     int complete = 0;
347     int segp = 0, psize = 0;
348
349     av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
350
351     do{
352         idx = ogg->curidx;
353
354         while (idx < 0){
355             ret = ogg_read_page(s, &idx);
356             if (ret < 0)
357                 return ret;
358         }
359
360         os = ogg->streams + idx;
361
362         av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
363                 idx, os->pstart, os->psize, os->segp, os->nsegs);
364
365         if (!os->codec){
366             if (os->header < 0){
367                 os->codec = ogg_find_codec (os->buf, os->bufpos);
368                 if (!os->codec){
369                     av_log(s, AV_LOG_WARNING, "Codec not found\n");
370                     os->header = 0;
371                     return 0;
372                 }
373             }else{
374                 return 0;
375             }
376         }
377
378         segp = os->segp;
379         psize = os->psize;
380
381         while (os->segp < os->nsegs){
382             int ss = os->segments[os->segp++];
383             os->psize += ss;
384             if (ss < 255){
385                 complete = 1;
386                 break;
387             }
388         }
389
390         if (!complete && os->segp == os->nsegs){
391             ogg->curidx = -1;
392             // Do not set incomplete for empty packets.
393             // Together with the code in ogg_read_page
394             // that discards all continuation of empty packets
395             // we would get an infinite loop.
396             os->incomplete = !!os->psize;
397         }
398     }while (!complete);
399
400
401     if (os->granule == -1)
402         av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
403
404     ogg->curidx = idx;
405     os->incomplete = 0;
406
407     if (os->header) {
408         os->header = os->codec->header (s, idx);
409         if (!os->header){
410             os->segp = segp;
411             os->psize = psize;
412
413             // We have reached the first non-header packet in this stream.
414             // Unfortunately more header packets may still follow for others,
415             // but if we continue with header parsing we may lose data packets.
416             ogg->headers = 1;
417
418             // Update the header state for all streams and
419             // compute the data_offset.
420             if (!s->data_offset)
421                 s->data_offset = os->sync_pos;
422             for (i = 0; i < ogg->nstreams; i++) {
423                 struct ogg_stream *cur_os = ogg->streams + i;
424
425                 // if we have a partial non-header packet, its start is
426                 // obviously at or after the data start
427                 if (cur_os->incomplete)
428                     s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
429             }
430         }else{
431             os->pstart += os->psize;
432             os->psize = 0;
433         }
434     } else {
435         os->pflags = 0;
436         os->pduration = 0;
437         if (os->codec && os->codec->packet)
438             os->codec->packet (s, idx);
439         if (str)
440             *str = idx;
441         if (dstart)
442             *dstart = os->pstart;
443         if (dsize)
444             *dsize = os->psize;
445         if (fpos)
446             *fpos = os->sync_pos;
447         os->pstart += os->psize;
448         os->psize = 0;
449         if(os->pstart == os->bufpos)
450             os->bufpos = os->pstart = 0;
451         os->sync_pos = os->page_pos;
452     }
453
454     // determine whether there are more complete packets in this page
455     // if not, the page's granule will apply to this packet
456     os->page_end = 1;
457     for (i = os->segp; i < os->nsegs; i++)
458         if (os->segments[i] < 255) {
459             os->page_end = 0;
460             break;
461         }
462
463     if (os->segp == os->nsegs)
464         ogg->curidx = -1;
465
466     return 0;
467 }
468
469 static int ogg_get_headers(AVFormatContext *s)
470 {
471     struct ogg *ogg = s->priv_data;
472     int ret;
473
474     do{
475         ret = ogg_packet(s, NULL, NULL, NULL, NULL);
476         if (ret < 0)
477             return ret;
478     }while (!ogg->headers);
479
480     av_dlog(s, "found headers\n");
481
482     return 0;
483 }
484
485 static int ogg_get_length(AVFormatContext *s)
486 {
487     struct ogg *ogg = s->priv_data;
488     int i;
489     int64_t size, end;
490     int streams_left=0;
491
492     if(!s->pb->seekable)
493         return 0;
494
495 // already set
496     if (s->duration != AV_NOPTS_VALUE)
497         return 0;
498
499     size = avio_size(s->pb);
500     if(size < 0)
501         return 0;
502     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
503
504     ogg_save (s);
505     avio_seek (s->pb, end, SEEK_SET);
506
507     while (!ogg_read_page (s, &i)){
508         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
509             ogg->streams[i].codec) {
510             s->streams[i]->duration =
511                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
512             if (s->streams[i]->start_time != AV_NOPTS_VALUE){
513                 s->streams[i]->duration -= s->streams[i]->start_time;
514                 streams_left-= (ogg->streams[i].got_start==-1);
515                 ogg->streams[i].got_start= 1;
516             }else if(!ogg->streams[i].got_start){
517                 ogg->streams[i].got_start= -1;
518                 streams_left++;
519             }
520         }
521     }
522
523     ogg_restore (s, 0);
524
525     ogg_save (s);
526     avio_seek (s->pb, s->data_offset, SEEK_SET);
527     ogg_reset(s);
528     i = -1;
529     while (!ogg_packet(s, &i, NULL, NULL, NULL)) {
530         if(i>=0) {
531         int64_t pts = ogg_calc_pts(s, i, NULL);
532         if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
533             s->streams[i]->duration -= pts;
534             ogg->streams[i].got_start= 1;
535             streams_left--;
536         }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start){
537             ogg->streams[i].got_start= 1;
538             streams_left--;
539         }
540         }
541             if(streams_left<=0)
542                 break;
543     }
544     ogg_restore (s, 0);
545
546     return 0;
547 }
548
549 static int ogg_read_header(AVFormatContext *s)
550 {
551     struct ogg *ogg = s->priv_data;
552     int ret, i;
553     ogg->curidx = -1;
554     //linear headers seek from start
555     ret = ogg_get_headers(s);
556     if (ret < 0)
557         return ret;
558
559     for (i = 0; i < ogg->nstreams; i++)
560         if (ogg->streams[i].header < 0)
561             ogg->streams[i].codec = NULL;
562
563     //linear granulepos seek from end
564     ogg_get_length (s);
565
566     //fill the extradata in the per codec callbacks
567     return 0;
568 }
569
570 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
571 {
572     struct ogg *ogg = s->priv_data;
573     struct ogg_stream *os = ogg->streams + idx;
574     int64_t pts = AV_NOPTS_VALUE;
575
576     if (dts)
577         *dts = AV_NOPTS_VALUE;
578
579     if (os->lastpts != AV_NOPTS_VALUE) {
580         pts = os->lastpts;
581         os->lastpts = AV_NOPTS_VALUE;
582     }
583     if (os->lastdts != AV_NOPTS_VALUE) {
584         if (dts)
585             *dts = os->lastdts;
586         os->lastdts = AV_NOPTS_VALUE;
587     }
588     if (os->page_end) {
589         if (os->granule != -1LL) {
590             if (os->codec && os->codec->granule_is_start)
591                 pts = ogg_gptopts(s, idx, os->granule, dts);
592             else
593                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
594             os->granule = -1LL;
595         }
596     }
597     return pts;
598 }
599
600 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
601 {
602     struct ogg *ogg = s->priv_data;
603     struct ogg_stream *os = ogg->streams + idx;
604     if (psize && s->streams[idx]->codec->codec_id == CODEC_ID_THEORA) {
605         if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
606             os->pflags ^= AV_PKT_FLAG_KEY;
607             av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
608                    (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
609         }
610     }
611 }
612
613 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
614 {
615     struct ogg *ogg;
616     struct ogg_stream *os;
617     int idx = -1, ret;
618     int pstart, psize;
619     int64_t fpos, pts, dts;
620
621     //Get an ogg packet
622 retry:
623     do{
624         ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
625         if (ret < 0)
626             return ret;
627     }while (idx < 0 || !s->streams[idx]);
628
629     ogg = s->priv_data;
630     os = ogg->streams + idx;
631
632     // pflags might not be set until after this
633     pts = ogg_calc_pts(s, idx, &dts);
634     ogg_validate_keyframe(s, idx, pstart, psize);
635
636     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
637         goto retry;
638     os->keyframe_seek = 0;
639
640     //Alloc a pkt
641     ret = av_new_packet(pkt, psize);
642     if (ret < 0)
643         return ret;
644     pkt->stream_index = idx;
645     memcpy (pkt->data, os->buf + pstart, psize);
646
647     pkt->pts = pts;
648     pkt->dts = dts;
649     pkt->flags = os->pflags;
650     pkt->duration = os->pduration;
651     pkt->pos = fpos;
652
653     return psize;
654 }
655
656 static int ogg_read_close(AVFormatContext *s)
657 {
658     struct ogg *ogg = s->priv_data;
659     int i;
660
661     for (i = 0; i < ogg->nstreams; i++){
662         av_free (ogg->streams[i].buf);
663         av_free (ogg->streams[i].private);
664     }
665     av_free (ogg->streams);
666     return 0;
667 }
668
669 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
670                                   int64_t *pos_arg, int64_t pos_limit)
671 {
672     struct ogg *ogg = s->priv_data;
673     AVIOContext *bc = s->pb;
674     int64_t pts = AV_NOPTS_VALUE;
675     int64_t keypos = -1;
676     int i = -1;
677     int pstart, psize;
678     avio_seek(bc, *pos_arg, SEEK_SET);
679     ogg_reset(s);
680
681     while (avio_tell(bc) <= pos_limit && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
682         if (i == stream_index) {
683             struct ogg_stream *os = ogg->streams + stream_index;
684             pts = ogg_calc_pts(s, i, NULL);
685             ogg_validate_keyframe(s, i, pstart, psize);
686             if (os->pflags & AV_PKT_FLAG_KEY) {
687                 keypos = *pos_arg;
688             } else if (os->keyframe_seek) {
689                 // if we had a previous keyframe but no pts for it,
690                 // return that keyframe with this pts value.
691                 if (keypos >= 0)
692                     *pos_arg = keypos;
693                 else
694                     pts = AV_NOPTS_VALUE;
695             }
696         }
697         if (pts != AV_NOPTS_VALUE)
698             break;
699     }
700     ogg_reset(s);
701     return pts;
702 }
703
704 static int ogg_read_seek(AVFormatContext *s, int stream_index,
705                          int64_t timestamp, int flags)
706 {
707     struct ogg *ogg = s->priv_data;
708     struct ogg_stream *os = ogg->streams + stream_index;
709     int ret;
710
711     av_assert0(stream_index < ogg->nstreams);
712     // Ensure everything is reset even when seeking via
713     // the generated index.
714     ogg_reset(s);
715
716     // Try seeking to a keyframe first. If this fails (very possible),
717     // av_seek_frame will fall back to ignoring keyframes
718     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
719         && !(flags & AVSEEK_FLAG_ANY))
720         os->keyframe_seek = 1;
721
722     ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
723     os = ogg->streams + stream_index;
724     if (ret < 0)
725         os->keyframe_seek = 0;
726     return ret;
727 }
728
729 static int ogg_probe(AVProbeData *p)
730 {
731     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
732         return AVPROBE_SCORE_MAX;
733     return 0;
734 }
735
736 AVInputFormat ff_ogg_demuxer = {
737     .name           = "ogg",
738     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
739     .priv_data_size = sizeof(struct ogg),
740     .read_probe     = ogg_probe,
741     .read_header    = ogg_read_header,
742     .read_packet    = ogg_read_packet,
743     .read_close     = ogg_read_close,
744     .read_seek      = ogg_read_seek,
745     .read_timestamp = ogg_read_timestamp,
746     .extensions     = "ogg",
747     .flags          = AVFMT_GENERIC_INDEX,
748 };