]> 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_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     while (!ogg_packet(s, &i, NULL, NULL, NULL)) {
529         int64_t pts = ogg_calc_pts(s, i, NULL);
530         if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
531             s->streams[i]->duration -= pts;
532             ogg->streams[i].got_start= 1;
533             streams_left--;
534         }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start){
535             ogg->streams[i].got_start= 1;
536             streams_left--;
537         }
538             if(streams_left<=0)
539                 break;
540     }
541     ogg_restore (s, 0);
542
543     return 0;
544 }
545
546 static int ogg_read_header(AVFormatContext *s)
547 {
548     struct ogg *ogg = s->priv_data;
549     int ret, i;
550     ogg->curidx = -1;
551     //linear headers seek from start
552     ret = ogg_get_headers(s);
553     if (ret < 0)
554         return ret;
555
556     for (i = 0; i < ogg->nstreams; i++)
557         if (ogg->streams[i].header < 0)
558             ogg->streams[i].codec = NULL;
559
560     //linear granulepos seek from end
561     ogg_get_length (s);
562
563     //fill the extradata in the per codec callbacks
564     return 0;
565 }
566
567 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
568 {
569     struct ogg *ogg = s->priv_data;
570     struct ogg_stream *os = ogg->streams + idx;
571     int64_t pts = AV_NOPTS_VALUE;
572
573     if (dts)
574         *dts = AV_NOPTS_VALUE;
575
576     if (os->lastpts != AV_NOPTS_VALUE) {
577         pts = os->lastpts;
578         os->lastpts = AV_NOPTS_VALUE;
579     }
580     if (os->lastdts != AV_NOPTS_VALUE) {
581         if (dts)
582             *dts = os->lastdts;
583         os->lastdts = AV_NOPTS_VALUE;
584     }
585     if (os->page_end) {
586         if (os->granule != -1LL) {
587             if (os->codec && os->codec->granule_is_start)
588                 pts = ogg_gptopts(s, idx, os->granule, dts);
589             else
590                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
591             os->granule = -1LL;
592         }
593     }
594     return pts;
595 }
596
597 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
598 {
599     struct ogg *ogg = s->priv_data;
600     struct ogg_stream *os = ogg->streams + idx;
601     if (psize && s->streams[idx]->codec->codec_id == CODEC_ID_THEORA) {
602         if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
603             os->pflags ^= AV_PKT_FLAG_KEY;
604             av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
605                    (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
606         }
607     }
608 }
609
610 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
611 {
612     struct ogg *ogg;
613     struct ogg_stream *os;
614     int idx = -1, ret;
615     int pstart, psize;
616     int64_t fpos, pts, dts;
617
618     //Get an ogg packet
619 retry:
620     do{
621         ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
622         if (ret < 0)
623             return ret;
624     }while (idx < 0 || !s->streams[idx]);
625
626     ogg = s->priv_data;
627     os = ogg->streams + idx;
628
629     // pflags might not be set until after this
630     pts = ogg_calc_pts(s, idx, &dts);
631     ogg_validate_keyframe(s, idx, pstart, psize);
632
633     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
634         goto retry;
635     os->keyframe_seek = 0;
636
637     //Alloc a pkt
638     ret = av_new_packet(pkt, psize);
639     if (ret < 0)
640         return ret;
641     pkt->stream_index = idx;
642     memcpy (pkt->data, os->buf + pstart, psize);
643
644     pkt->pts = pts;
645     pkt->dts = dts;
646     pkt->flags = os->pflags;
647     pkt->duration = os->pduration;
648     pkt->pos = fpos;
649
650     return psize;
651 }
652
653 static int ogg_read_close(AVFormatContext *s)
654 {
655     struct ogg *ogg = s->priv_data;
656     int i;
657
658     for (i = 0; i < ogg->nstreams; i++){
659         av_free (ogg->streams[i].buf);
660         av_free (ogg->streams[i].private);
661     }
662     av_free (ogg->streams);
663     return 0;
664 }
665
666 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
667                                   int64_t *pos_arg, int64_t pos_limit)
668 {
669     struct ogg *ogg = s->priv_data;
670     AVIOContext *bc = s->pb;
671     int64_t pts = AV_NOPTS_VALUE;
672     int64_t keypos = -1;
673     int i = -1;
674     int pstart, psize;
675     avio_seek(bc, *pos_arg, SEEK_SET);
676     ogg_reset(s);
677
678     while (avio_tell(bc) <= pos_limit && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
679         if (i == stream_index) {
680             struct ogg_stream *os = ogg->streams + stream_index;
681             pts = ogg_calc_pts(s, i, NULL);
682             ogg_validate_keyframe(s, i, pstart, psize);
683             if (os->pflags & AV_PKT_FLAG_KEY) {
684                 keypos = *pos_arg;
685             } else if (os->keyframe_seek) {
686                 // if we had a previous keyframe but no pts for it,
687                 // return that keyframe with this pts value.
688                 if (keypos >= 0)
689                     *pos_arg = keypos;
690                 else
691                     pts = AV_NOPTS_VALUE;
692             }
693         }
694         if (pts != AV_NOPTS_VALUE)
695             break;
696     }
697     ogg_reset(s);
698     return pts;
699 }
700
701 static int ogg_read_seek(AVFormatContext *s, int stream_index,
702                          int64_t timestamp, int flags)
703 {
704     struct ogg *ogg = s->priv_data;
705     struct ogg_stream *os = ogg->streams + stream_index;
706     int ret;
707
708     av_assert0(stream_index < ogg->nstreams);
709     // Ensure everything is reset even when seeking via
710     // the generated index.
711     ogg_reset(s);
712
713     // Try seeking to a keyframe first. If this fails (very possible),
714     // av_seek_frame will fall back to ignoring keyframes
715     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
716         && !(flags & AVSEEK_FLAG_ANY))
717         os->keyframe_seek = 1;
718
719     ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
720     os = ogg->streams + stream_index;
721     if (ret < 0)
722         os->keyframe_seek = 0;
723     return ret;
724 }
725
726 static int ogg_probe(AVProbeData *p)
727 {
728     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
729         return AVPROBE_SCORE_MAX;
730     return 0;
731 }
732
733 AVInputFormat ff_ogg_demuxer = {
734     .name           = "ogg",
735     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
736     .priv_data_size = sizeof(struct ogg),
737     .read_probe     = ogg_probe,
738     .read_header    = ogg_read_header,
739     .read_packet    = ogg_read_packet,
740     .read_close     = ogg_read_close,
741     .read_seek      = ogg_read_seek,
742     .read_timestamp = ogg_read_timestamp,
743     .extensions     = "ogg",
744     .flags          = AVFMT_GENERIC_INDEX,
745 };