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