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