rmdec: remove unused variable
[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 /**
341  * @brief find the next Ogg packet
342  * @param *str is set to the stream for the packet or -1 if there is
343  *             no matching stream, in that case assume all other return
344  *             values to be uninitialized.
345  * @return negative value on error or EOF.
346  */
347 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
348                       int64_t *fpos)
349 {
350     struct ogg *ogg = s->priv_data;
351     int idx, i, ret;
352     struct ogg_stream *os;
353     int complete = 0;
354     int segp = 0, psize = 0;
355
356     av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
357     if (str)
358         *str = -1;
359
360     do{
361         idx = ogg->curidx;
362
363         while (idx < 0){
364             ret = ogg_read_page(s, &idx);
365             if (ret < 0)
366                 return ret;
367         }
368
369         os = ogg->streams + idx;
370
371         av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
372                 idx, os->pstart, os->psize, os->segp, os->nsegs);
373
374         if (!os->codec){
375             if (os->header < 0){
376                 os->codec = ogg_find_codec (os->buf, os->bufpos);
377                 if (!os->codec){
378                     av_log(s, AV_LOG_WARNING, "Codec not found\n");
379                     os->header = 0;
380                     return 0;
381                 }
382             }else{
383                 return 0;
384             }
385         }
386
387         segp = os->segp;
388         psize = os->psize;
389
390         while (os->segp < os->nsegs){
391             int ss = os->segments[os->segp++];
392             os->psize += ss;
393             if (ss < 255){
394                 complete = 1;
395                 break;
396             }
397         }
398
399         if (!complete && os->segp == os->nsegs){
400             ogg->curidx = -1;
401             // Do not set incomplete for empty packets.
402             // Together with the code in ogg_read_page
403             // that discards all continuation of empty packets
404             // we would get an infinite loop.
405             os->incomplete = !!os->psize;
406         }
407     }while (!complete);
408
409
410     if (os->granule == -1)
411         av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
412
413     ogg->curidx = idx;
414     os->incomplete = 0;
415
416     if (os->header) {
417         os->header = os->codec->header (s, idx);
418         if (!os->header){
419             os->segp = segp;
420             os->psize = psize;
421
422             // We have reached the first non-header packet in this stream.
423             // Unfortunately more header packets may still follow for others,
424             // but if we continue with header parsing we may lose data packets.
425             ogg->headers = 1;
426
427             // Update the header state for all streams and
428             // compute the data_offset.
429             if (!s->data_offset)
430                 s->data_offset = os->sync_pos;
431             for (i = 0; i < ogg->nstreams; i++) {
432                 struct ogg_stream *cur_os = ogg->streams + i;
433
434                 // if we have a partial non-header packet, its start is
435                 // obviously at or after the data start
436                 if (cur_os->incomplete)
437                     s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
438             }
439         }else{
440             os->pstart += os->psize;
441             os->psize = 0;
442         }
443     } else {
444         os->pflags = 0;
445         os->pduration = 0;
446         if (os->codec && os->codec->packet)
447             os->codec->packet (s, idx);
448         if (str)
449             *str = idx;
450         if (dstart)
451             *dstart = os->pstart;
452         if (dsize)
453             *dsize = os->psize;
454         if (fpos)
455             *fpos = os->sync_pos;
456         os->pstart += os->psize;
457         os->psize = 0;
458         if(os->pstart == os->bufpos)
459             os->bufpos = os->pstart = 0;
460         os->sync_pos = os->page_pos;
461     }
462
463     // determine whether there are more complete packets in this page
464     // if not, the page's granule will apply to this packet
465     os->page_end = 1;
466     for (i = os->segp; i < os->nsegs; i++)
467         if (os->segments[i] < 255) {
468             os->page_end = 0;
469             break;
470         }
471
472     if (os->segp == os->nsegs)
473         ogg->curidx = -1;
474
475     return 0;
476 }
477
478 static int ogg_get_headers(AVFormatContext *s)
479 {
480     struct ogg *ogg = s->priv_data;
481     int ret;
482
483     do{
484         ret = ogg_packet(s, NULL, NULL, NULL, NULL);
485         if (ret < 0)
486             return ret;
487     }while (!ogg->headers);
488
489     av_dlog(s, "found headers\n");
490
491     return 0;
492 }
493
494 static int ogg_get_length(AVFormatContext *s)
495 {
496     struct ogg *ogg = s->priv_data;
497     int i;
498     int64_t size, end;
499     int streams_left=0;
500
501     if(!s->pb->seekable)
502         return 0;
503
504 // already set
505     if (s->duration != AV_NOPTS_VALUE)
506         return 0;
507
508     size = avio_size(s->pb);
509     if(size < 0)
510         return 0;
511     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
512
513     ogg_save (s);
514     avio_seek (s->pb, end, SEEK_SET);
515
516     while (!ogg_read_page (s, &i)){
517         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
518             ogg->streams[i].codec) {
519             s->streams[i]->duration =
520                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
521             if (s->streams[i]->start_time != AV_NOPTS_VALUE){
522                 s->streams[i]->duration -= s->streams[i]->start_time;
523                 streams_left-= (ogg->streams[i].got_start==-1);
524                 ogg->streams[i].got_start= 1;
525             }else if(!ogg->streams[i].got_start){
526                 ogg->streams[i].got_start= -1;
527                 streams_left++;
528             }
529         }
530     }
531
532     ogg_restore (s, 0);
533
534     ogg_save (s);
535     avio_seek (s->pb, s->data_offset, SEEK_SET);
536     ogg_reset(s);
537     while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
538         int64_t pts;
539         if (i < 0) continue;
540         pts = ogg_calc_pts(s, i, NULL);
541         if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
542             s->streams[i]->duration -= pts;
543             ogg->streams[i].got_start= 1;
544             streams_left--;
545         }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start){
546             ogg->streams[i].got_start= 1;
547             streams_left--;
548         }
549     }
550     ogg_restore (s, 0);
551
552     return 0;
553 }
554
555 static int ogg_read_header(AVFormatContext *s)
556 {
557     struct ogg *ogg = s->priv_data;
558     int ret, i;
559     ogg->curidx = -1;
560     //linear headers seek from start
561     ret = ogg_get_headers(s);
562     if (ret < 0)
563         return ret;
564
565     for (i = 0; i < ogg->nstreams; i++)
566         if (ogg->streams[i].header < 0)
567             ogg->streams[i].codec = NULL;
568
569     //linear granulepos seek from end
570     ogg_get_length (s);
571
572     //fill the extradata in the per codec callbacks
573     return 0;
574 }
575
576 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
577 {
578     struct ogg *ogg = s->priv_data;
579     struct ogg_stream *os = ogg->streams + idx;
580     int64_t pts = AV_NOPTS_VALUE;
581
582     if (dts)
583         *dts = AV_NOPTS_VALUE;
584
585     if (os->lastpts != AV_NOPTS_VALUE) {
586         pts = os->lastpts;
587         os->lastpts = AV_NOPTS_VALUE;
588     }
589     if (os->lastdts != AV_NOPTS_VALUE) {
590         if (dts)
591             *dts = os->lastdts;
592         os->lastdts = AV_NOPTS_VALUE;
593     }
594     if (os->page_end) {
595         if (os->granule != -1LL) {
596             if (os->codec && os->codec->granule_is_start)
597                 pts = ogg_gptopts(s, idx, os->granule, dts);
598             else
599                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
600             os->granule = -1LL;
601         }
602     }
603     return pts;
604 }
605
606 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
607 {
608     struct ogg *ogg = s->priv_data;
609     struct ogg_stream *os = ogg->streams + idx;
610     if (psize && s->streams[idx]->codec->codec_id == AV_CODEC_ID_THEORA) {
611         if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
612             os->pflags ^= AV_PKT_FLAG_KEY;
613             av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
614                    (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
615         }
616     }
617 }
618
619 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
620 {
621     struct ogg *ogg;
622     struct ogg_stream *os;
623     int idx, ret;
624     int pstart, psize;
625     int64_t fpos, pts, dts;
626
627     //Get an ogg packet
628 retry:
629     do{
630         ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
631         if (ret < 0)
632             return ret;
633     }while (idx < 0 || !s->streams[idx]);
634
635     ogg = s->priv_data;
636     os = ogg->streams + idx;
637
638     // pflags might not be set until after this
639     pts = ogg_calc_pts(s, idx, &dts);
640     ogg_validate_keyframe(s, idx, pstart, psize);
641
642     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
643         goto retry;
644     os->keyframe_seek = 0;
645
646     //Alloc a pkt
647     ret = av_new_packet(pkt, psize);
648     if (ret < 0)
649         return ret;
650     pkt->stream_index = idx;
651     memcpy (pkt->data, os->buf + pstart, psize);
652
653     pkt->pts = pts;
654     pkt->dts = dts;
655     pkt->flags = os->pflags;
656     pkt->duration = os->pduration;
657     pkt->pos = fpos;
658
659     return psize;
660 }
661
662 static int ogg_read_close(AVFormatContext *s)
663 {
664     struct ogg *ogg = s->priv_data;
665     int i;
666
667     for (i = 0; i < ogg->nstreams; i++){
668         av_free (ogg->streams[i].buf);
669         av_free (ogg->streams[i].private);
670     }
671     av_free (ogg->streams);
672     return 0;
673 }
674
675 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
676                                   int64_t *pos_arg, int64_t pos_limit)
677 {
678     struct ogg *ogg = s->priv_data;
679     AVIOContext *bc = s->pb;
680     int64_t pts = AV_NOPTS_VALUE;
681     int64_t keypos = -1;
682     int i;
683     int pstart, psize;
684     avio_seek(bc, *pos_arg, SEEK_SET);
685     ogg_reset(s);
686
687     while (avio_tell(bc) <= pos_limit && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
688         if (i == stream_index) {
689             struct ogg_stream *os = ogg->streams + stream_index;
690             pts = ogg_calc_pts(s, i, NULL);
691             ogg_validate_keyframe(s, i, pstart, psize);
692             if (os->pflags & AV_PKT_FLAG_KEY) {
693                 keypos = *pos_arg;
694             } else if (os->keyframe_seek) {
695                 // if we had a previous keyframe but no pts for it,
696                 // return that keyframe with this pts value.
697                 if (keypos >= 0)
698                     *pos_arg = keypos;
699                 else
700                     pts = AV_NOPTS_VALUE;
701             }
702         }
703         if (pts != AV_NOPTS_VALUE)
704             break;
705     }
706     ogg_reset(s);
707     return pts;
708 }
709
710 static int ogg_read_seek(AVFormatContext *s, int stream_index,
711                          int64_t timestamp, int flags)
712 {
713     struct ogg *ogg = s->priv_data;
714     struct ogg_stream *os = ogg->streams + stream_index;
715     int ret;
716
717     av_assert0(stream_index < ogg->nstreams);
718     // Ensure everything is reset even when seeking via
719     // the generated index.
720     ogg_reset(s);
721
722     // Try seeking to a keyframe first. If this fails (very possible),
723     // av_seek_frame will fall back to ignoring keyframes
724     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
725         && !(flags & AVSEEK_FLAG_ANY))
726         os->keyframe_seek = 1;
727
728     ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
729     os = ogg->streams + stream_index;
730     if (ret < 0)
731         os->keyframe_seek = 0;
732     return ret;
733 }
734
735 static int ogg_probe(AVProbeData *p)
736 {
737     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
738         return AVPROBE_SCORE_MAX;
739     return 0;
740 }
741
742 AVInputFormat ff_ogg_demuxer = {
743     .name           = "ogg",
744     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
745     .priv_data_size = sizeof(struct ogg),
746     .read_probe     = ogg_probe,
747     .read_header    = ogg_read_header,
748     .read_packet    = ogg_read_packet,
749     .read_close     = ogg_read_close,
750     .read_seek      = ogg_read_seek,
751     .read_timestamp = ogg_read_timestamp,
752     .extensions     = "ogg",
753     .flags          = AVFMT_GENERIC_INDEX,
754 };