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