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