]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
latmenc: Check for LOAS sync word
[ffmpeg] / libavformat / oggdec.c
1 /*
2  * Ogg bitstream support
3  * Luca Barbato <lu_zero@gentoo.org>
4  * Based on tcvp implementation
5  */
6
7 /*
8     Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
9
10     Permission is hereby granted, free of charge, to any person
11     obtaining a copy of this software and associated documentation
12     files (the "Software"), to deal in the Software without
13     restriction, including without limitation the rights to use, copy,
14     modify, merge, publish, distribute, sublicense, and/or sell copies
15     of the Software, and to permit persons to whom the Software is
16     furnished to do so, subject to the following conditions:
17
18     The above copyright notice and this permission notice shall be
19     included in all copies or substantial portions of the Software.
20
21     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28     DEALINGS IN THE SOFTWARE.
29  */
30
31 #include <stdio.h>
32 #include "libavutil/avassert.h"
33 #include "oggdec.h"
34 #include "avformat.h"
35 #include "internal.h"
36 #include "vorbiscomment.h"
37
38 #define MAX_PAGE_SIZE 65307
39 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40
41 static const struct ogg_codec * const ogg_codecs[] = {
42     &ff_skeleton_codec,
43     &ff_dirac_codec,
44     &ff_speex_codec,
45     &ff_vorbis_codec,
46     &ff_theora_codec,
47     &ff_flac_codec,
48     &ff_celt_codec,
49     &ff_opus_codec,
50     &ff_old_dirac_codec,
51     &ff_old_flac_codec,
52     &ff_ogm_video_codec,
53     &ff_ogm_audio_codec,
54     &ff_ogm_text_codec,
55     &ff_ogm_old_codec,
56     NULL
57 };
58
59 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
60
61 //FIXME We could avoid some structure duplication
62 static int ogg_save(AVFormatContext *s)
63 {
64     struct ogg *ogg = s->priv_data;
65     struct ogg_state *ost =
66         av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
67     int i;
68     ost->pos      = avio_tell(s->pb);
69     ost->curidx   = ogg->curidx;
70     ost->next     = ogg->state;
71     ost->nstreams = ogg->nstreams;
72     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
73
74     for (i = 0; i < ogg->nstreams; i++) {
75         struct ogg_stream *os = ogg->streams + i;
76         os->buf = av_mallocz(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
77         memcpy(os->buf, ost->streams[i].buf, os->bufpos);
78     }
79
80     ogg->state = ost;
81
82     return 0;
83 }
84
85 static int ogg_restore(AVFormatContext *s, int discard)
86 {
87     struct ogg *ogg = s->priv_data;
88     AVIOContext *bc = s->pb;
89     struct ogg_state *ost = ogg->state;
90     int i;
91
92     if (!ost)
93         return 0;
94
95     ogg->state = ost->next;
96
97     if (!discard) {
98         struct ogg_stream *old_streams = ogg->streams;
99
100         for (i = 0; i < ogg->nstreams; i++)
101             av_free(ogg->streams[i].buf);
102
103         avio_seek(bc, ost->pos, SEEK_SET);
104         ogg->page_pos = -1;
105         ogg->curidx   = ost->curidx;
106         ogg->nstreams = ost->nstreams;
107         ogg->streams  = av_realloc(ogg->streams,
108                                    ogg->nstreams * sizeof(*ogg->streams));
109
110         if (ogg->streams) {
111             memcpy(ogg->streams, ost->streams,
112                    ost->nstreams * sizeof(*ogg->streams));
113         } else {
114             av_free(old_streams);
115             ogg->nstreams = 0;
116         }
117     }
118
119     av_free(ost);
120
121     return 0;
122 }
123
124 static int ogg_reset(AVFormatContext *s)
125 {
126     struct ogg *ogg = s->priv_data;
127     int i;
128     int64_t start_pos = avio_tell(s->pb);
129
130     for (i = 0; i < ogg->nstreams; i++) {
131         struct ogg_stream *os = ogg->streams + i;
132         os->bufpos     = 0;
133         os->pstart     = 0;
134         os->psize      = 0;
135         os->granule    = -1;
136         os->lastpts    = AV_NOPTS_VALUE;
137         os->lastdts    = AV_NOPTS_VALUE;
138         os->sync_pos   = -1;
139         os->page_pos   = 0;
140         os->nsegs      = 0;
141         os->segp       = 0;
142         os->incomplete = 0;
143         os->got_data = 0;
144         if (start_pos <= s->data_offset) {
145             os->lastpts = 0;
146         }
147     }
148
149     ogg->page_pos = -1;
150     ogg->curidx = -1;
151
152     return 0;
153 }
154
155 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
156 {
157     int i;
158
159     for (i = 0; ogg_codecs[i]; i++)
160         if (size >= ogg_codecs[i]->magicsize &&
161             !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
162             return ogg_codecs[i];
163
164     return NULL;
165 }
166
167 /**
168  * Replace the current stream with a new one. This is a typical webradio
169  * situation where a new audio stream spawn (identified with a new serial) and
170  * must replace the previous one (track switch).
171  */
172 static int ogg_replace_stream(AVFormatContext *s, uint32_t serial)
173 {
174     struct ogg *ogg = s->priv_data;
175     struct ogg_stream *os;
176     unsigned bufsize;
177     uint8_t *buf;
178     const struct ogg_codec *codec;
179
180     if (ogg->nstreams != 1) {
181         av_log_missing_feature(s, "Changing stream parameters in multistream ogg", 0);
182         return AVERROR_PATCHWELCOME;
183     }
184
185     os = &ogg->streams[0];
186
187     os->serial  = serial;
188     return 0;
189
190     buf     = os->buf;
191     bufsize = os->bufsize;
192     codec   = os->codec;
193
194     if (!ogg->state || ogg->state->streams[0].private != os->private)
195         av_freep(&ogg->streams[0].private);
196
197     /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
198      * also re-use the ogg_stream allocated buffer */
199     memset(os, 0, sizeof(*os));
200     os->serial  = serial;
201     os->bufsize = bufsize;
202     os->buf     = buf;
203     os->header  = -1;
204     os->codec   = codec;
205
206     return 0;
207 }
208
209 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
210 {
211     struct ogg *ogg = s->priv_data;
212     int idx         = ogg->nstreams;
213     AVStream *st;
214     struct ogg_stream *os;
215     size_t size;
216
217     if (ogg->state) {
218         av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
219                "in between Ogg context save/restore operations.\n");
220         return AVERROR_BUG;
221     }
222
223     /* Allocate and init a new Ogg Stream */
224     if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
225         !(os = av_realloc(ogg->streams, size)))
226         return AVERROR(ENOMEM);
227     ogg->streams = os;
228     os           = ogg->streams + idx;
229     memset(os, 0, sizeof(*os));
230     os->serial        = serial;
231     os->bufsize       = DECODER_BUFFER_SIZE;
232     os->buf           = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
233     os->header        = -1;
234     os->start_granule = OGG_NOGRANULE_VALUE;
235     if (!os->buf)
236         return AVERROR(ENOMEM);
237
238     /* Create the associated AVStream */
239     st = avformat_new_stream(s, NULL);
240     if (!st) {
241         av_freep(&os->buf);
242         return AVERROR(ENOMEM);
243     }
244     st->id = idx;
245     avpriv_set_pts_info(st, 64, 1, 1000000);
246
247     ogg->nstreams++;
248     return idx;
249 }
250
251 static int ogg_new_buf(struct ogg *ogg, int idx)
252 {
253     struct ogg_stream *os = ogg->streams + idx;
254     uint8_t *nb = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
255     int size = os->bufpos - os->pstart;
256
257     if (os->buf) {
258         memcpy(nb, os->buf + os->pstart, size);
259         av_free(os->buf);
260     }
261
262     os->buf    = nb;
263     os->bufpos = size;
264     os->pstart = 0;
265
266     return 0;
267 }
268
269 static int data_packets_seen(const struct ogg *ogg)
270 {
271     int i;
272
273     for (i = 0; i < ogg->nstreams; i++)
274         if (ogg->streams[i].got_data)
275             return 1;
276     return 0;
277 }
278
279 static int ogg_read_page(AVFormatContext *s, int *sid)
280 {
281     AVIOContext *bc = s->pb;
282     struct ogg *ogg = s->priv_data;
283     struct ogg_stream *os;
284     int ret, i = 0;
285     int flags, nsegs;
286     uint64_t gp;
287     uint32_t serial;
288     int size, idx;
289     uint8_t sync[4];
290     int sp = 0;
291
292     ret = avio_read(bc, sync, 4);
293     if (ret < 4)
294         return ret < 0 ? ret : AVERROR_EOF;
295
296     do {
297         int c;
298
299         if (sync[sp & 3] == 'O' &&
300             sync[(sp + 1) & 3] == 'g' &&
301             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
302             break;
303
304         if(!i && bc->seekable && ogg->page_pos > 0) {
305             memset(sync, 0, 4);
306             avio_seek(bc, ogg->page_pos+4, SEEK_SET);
307             ogg->page_pos = -1;
308         }
309
310         c = avio_r8(bc);
311
312         if (url_feof(bc))
313             return AVERROR_EOF;
314
315         sync[sp++ & 3] = c;
316     } while (i++ < MAX_PAGE_SIZE);
317
318     if (i >= MAX_PAGE_SIZE) {
319         av_log(s, AV_LOG_INFO, "cannot find sync word\n");
320         return AVERROR_INVALIDDATA;
321     }
322
323     if (avio_r8(bc) != 0) {      /* version */
324         av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
325         return AVERROR_INVALIDDATA;
326     }
327
328     flags  = avio_r8(bc);
329     gp     = avio_rl64(bc);
330     serial = avio_rl32(bc);
331     avio_skip(bc, 8); /* seq, crc */
332     nsegs  = avio_r8(bc);
333
334     idx = ogg_find_stream(ogg, serial);
335     if (idx < 0) {
336         if (data_packets_seen(ogg))
337             idx = ogg_replace_stream(s, serial);
338         else
339             idx = ogg_new_stream(s, serial);
340
341         if (idx < 0) {
342             av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
343             return idx;
344         }
345     }
346
347     os = ogg->streams + idx;
348     ogg->page_pos =
349     os->page_pos = avio_tell(bc) - 27;
350
351     if (os->psize > 0)
352         ogg_new_buf(ogg, idx);
353
354     ret = avio_read(bc, os->segments, nsegs);
355     if (ret < nsegs)
356         return ret < 0 ? ret : AVERROR_EOF;
357
358     os->nsegs = nsegs;
359     os->segp  = 0;
360
361     size = 0;
362     for (i = 0; i < nsegs; i++)
363         size += os->segments[i];
364
365     if (!(flags & OGG_FLAG_BOS))
366         os->got_data = 1;
367
368     if (flags & OGG_FLAG_CONT || os->incomplete) {
369         if (!os->psize) {
370             // If this is the very first segment we started
371             // playback in the middle of a continuation packet.
372             // Discard it since we missed the start of it.
373             while (os->segp < os->nsegs) {
374                 int seg = os->segments[os->segp++];
375                 os->pstart += seg;
376                 if (seg < 255)
377                     break;
378             }
379             os->sync_pos = os->page_pos;
380         }
381     } else {
382         os->psize    = 0;
383         os->sync_pos = os->page_pos;
384     }
385
386     if (os->bufsize - os->bufpos < size) {
387         uint8_t *nb = av_malloc((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
388         if (!nb)
389             return AVERROR(ENOMEM);
390         memcpy(nb, os->buf, os->bufpos);
391         av_free(os->buf);
392         os->buf = nb;
393     }
394
395     ret = avio_read(bc, os->buf + os->bufpos, size);
396     if (ret < size)
397         return ret < 0 ? ret : AVERROR_EOF;
398
399     os->bufpos += size;
400     os->granule = gp;
401     os->flags   = flags;
402
403     memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
404     if (sid)
405         *sid = idx;
406
407     return 0;
408 }
409
410 /**
411  * @brief find the next Ogg packet
412  * @param *sid is set to the stream for the packet or -1 if there is
413  *             no matching stream, in that case assume all other return
414  *             values to be uninitialized.
415  * @return negative value on error or EOF.
416  */
417 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
418                       int64_t *fpos)
419 {
420     struct ogg *ogg = s->priv_data;
421     int idx, i, ret;
422     struct ogg_stream *os;
423     int complete = 0;
424     int segp     = 0, psize = 0;
425
426     av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
427     if (sid)
428         *sid = -1;
429
430     do {
431         idx = ogg->curidx;
432
433         while (idx < 0) {
434             ret = ogg_read_page(s, &idx);
435             if (ret < 0)
436                 return ret;
437         }
438
439         os = ogg->streams + idx;
440
441         av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
442                 idx, os->pstart, os->psize, os->segp, os->nsegs);
443
444         if (!os->codec) {
445             if (os->header < 0) {
446                 os->codec = ogg_find_codec(os->buf, os->bufpos);
447                 if (!os->codec) {
448                     av_log(s, AV_LOG_WARNING, "Codec not found\n");
449                     os->header = 0;
450                     return 0;
451                 }
452             } else {
453                 return 0;
454             }
455         }
456
457         segp  = os->segp;
458         psize = os->psize;
459
460         while (os->segp < os->nsegs) {
461             int ss = os->segments[os->segp++];
462             os->psize += ss;
463             if (ss < 255) {
464                 complete = 1;
465                 break;
466             }
467         }
468
469         if (!complete && os->segp == os->nsegs) {
470             ogg->curidx    = -1;
471             // Do not set incomplete for empty packets.
472             // Together with the code in ogg_read_page
473             // that discards all continuation of empty packets
474             // we would get an infinite loop.
475             os->incomplete = !!os->psize;
476         }
477     } while (!complete);
478
479
480     if (os->granule == -1)
481         av_log(s, AV_LOG_WARNING,
482                "Page at %"PRId64" is missing granule\n",
483                os->page_pos);
484
485     ogg->curidx    = idx;
486     os->incomplete = 0;
487
488     if (os->header) {
489         os->header = os->codec->header(s, idx);
490         if (!os->header) {
491             os->segp  = segp;
492             os->psize = psize;
493
494             // We have reached the first non-header packet in this stream.
495             // Unfortunately more header packets may still follow for others,
496             // but if we continue with header parsing we may lose data packets.
497             ogg->headers = 1;
498
499             // Update the header state for all streams and
500             // compute the data_offset.
501             if (!s->data_offset)
502                 s->data_offset = os->sync_pos;
503
504             for (i = 0; i < ogg->nstreams; i++) {
505                 struct ogg_stream *cur_os = ogg->streams + i;
506
507                 // if we have a partial non-header packet, its start is
508                 // obviously at or after the data start
509                 if (cur_os->incomplete)
510                     s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
511             }
512         } else {
513             os->nb_header++;
514             os->pstart += os->psize;
515             os->psize   = 0;
516         }
517     } else {
518         os->pflags    = 0;
519         os->pduration = 0;
520         if (os->codec && os->codec->packet)
521             os->codec->packet(s, idx);
522         if (sid)
523             *sid = idx;
524         if (dstart)
525             *dstart = os->pstart;
526         if (dsize)
527             *dsize = os->psize;
528         if (fpos)
529             *fpos = os->sync_pos;
530         os->pstart  += os->psize;
531         os->psize    = 0;
532         if(os->pstart == os->bufpos)
533             os->bufpos = os->pstart = 0;
534         os->sync_pos = os->page_pos;
535     }
536
537     // determine whether there are more complete packets in this page
538     // if not, the page's granule will apply to this packet
539     os->page_end = 1;
540     for (i = os->segp; i < os->nsegs; i++)
541         if (os->segments[i] < 255) {
542             os->page_end = 0;
543             break;
544         }
545
546     if (os->segp == os->nsegs)
547         ogg->curidx = -1;
548
549     return 0;
550 }
551
552 static int ogg_get_length(AVFormatContext *s)
553 {
554     struct ogg *ogg = s->priv_data;
555     int i;
556     int64_t size, end;
557     int streams_left=0;
558
559     if (!s->pb->seekable)
560         return 0;
561
562 // already set
563     if (s->duration != AV_NOPTS_VALUE)
564         return 0;
565
566     size = avio_size(s->pb);
567     if (size < 0)
568         return 0;
569     end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
570
571     ogg_save(s);
572     avio_seek(s->pb, end, SEEK_SET);
573     ogg->page_pos = -1;
574
575     while (!ogg_read_page(s, &i)) {
576         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
577             ogg->streams[i].codec) {
578             s->streams[i]->duration =
579                 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
580             if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
581                 s->streams[i]->duration -= s->streams[i]->start_time;
582                 streams_left-= (ogg->streams[i].got_start==-1);
583                 ogg->streams[i].got_start= 1;
584             } else if(!ogg->streams[i].got_start) {
585                 ogg->streams[i].got_start= -1;
586                 streams_left++;
587             }
588         }
589     }
590
591     ogg_restore(s, 0);
592
593     ogg_save (s);
594     avio_seek (s->pb, s->data_offset, SEEK_SET);
595     ogg_reset(s);
596     while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
597         int64_t pts;
598         if (i < 0) continue;
599         pts = ogg_calc_pts(s, i, NULL);
600         if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
601             s->streams[i]->duration -= pts;
602             ogg->streams[i].got_start= 1;
603             streams_left--;
604         }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
605             ogg->streams[i].got_start= 1;
606             streams_left--;
607         }
608     }
609     ogg_restore (s, 0);
610
611     return 0;
612 }
613
614 static int ogg_read_close(AVFormatContext *s)
615 {
616     struct ogg *ogg = s->priv_data;
617     int i;
618
619     for (i = 0; i < ogg->nstreams; i++) {
620         av_free(ogg->streams[i].buf);
621         if (ogg->streams[i].codec &&
622             ogg->streams[i].codec->cleanup) {
623             ogg->streams[i].codec->cleanup(s, i);
624         }
625         av_free(ogg->streams[i].private);
626     }
627     av_free(ogg->streams);
628     return 0;
629 }
630
631 static int ogg_read_header(AVFormatContext *s)
632 {
633     struct ogg *ogg = s->priv_data;
634     int ret, i;
635
636     ogg->curidx = -1;
637
638     //linear headers seek from start
639     do {
640         ret = ogg_packet(s, NULL, NULL, NULL, NULL);
641         if (ret < 0) {
642             ogg_read_close(s);
643             return ret;
644         }
645     } while (!ogg->headers);
646     av_dlog(s, "found headers\n");
647
648     for (i = 0; i < ogg->nstreams; i++) {
649         struct ogg_stream *os = ogg->streams + i;
650
651         if (ogg->streams[i].header < 0) {
652             av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
653             ogg->streams[i].codec = NULL;
654         } else if (os->codec && os->nb_header < os->codec->nb_header) {
655             av_log(s, AV_LOG_WARNING, "Number of headers (%d) mismatch for stream %d\n", os->nb_header, i);
656         }
657         if (os->start_granule != OGG_NOGRANULE_VALUE)
658             os->lastpts = s->streams[i]->start_time =
659                 ogg_gptopts(s, i, os->start_granule, NULL);
660     }
661
662     //linear granulepos seek from end
663     ogg_get_length(s);
664
665     return 0;
666 }
667
668 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
669 {
670     struct ogg *ogg       = s->priv_data;
671     struct ogg_stream *os = ogg->streams + idx;
672     int64_t pts           = AV_NOPTS_VALUE;
673
674     if (dts)
675         *dts = AV_NOPTS_VALUE;
676
677     if (os->lastpts != AV_NOPTS_VALUE) {
678         pts         = os->lastpts;
679         os->lastpts = AV_NOPTS_VALUE;
680     }
681     if (os->lastdts != AV_NOPTS_VALUE) {
682         if (dts)
683             *dts = os->lastdts;
684         os->lastdts = AV_NOPTS_VALUE;
685     }
686     if (os->page_end) {
687         if (os->granule != -1LL) {
688             if (os->codec && os->codec->granule_is_start)
689                 pts = ogg_gptopts(s, idx, os->granule, dts);
690             else
691                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
692             os->granule = -1LL;
693         }
694     }
695     return pts;
696 }
697
698 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
699 {
700     struct ogg *ogg = s->priv_data;
701     struct ogg_stream *os = ogg->streams + idx;
702     if (psize && s->streams[idx]->codec->codec_id == AV_CODEC_ID_THEORA) {
703         if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
704             os->pflags ^= AV_PKT_FLAG_KEY;
705             av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
706                    (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
707         }
708     }
709 }
710
711 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
712 {
713     struct ogg *ogg;
714     struct ogg_stream *os;
715     int idx, ret;
716     int pstart, psize;
717     int64_t fpos, pts, dts;
718
719     //Get an ogg packet
720 retry:
721     do {
722         ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
723         if (ret < 0)
724             return ret;
725     } while (idx < 0 || !s->streams[idx]);
726
727     ogg = s->priv_data;
728     os  = ogg->streams + idx;
729
730     // pflags might not be set until after this
731     pts = ogg_calc_pts(s, idx, &dts);
732     ogg_validate_keyframe(s, idx, pstart, psize);
733
734     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
735         goto retry;
736     os->keyframe_seek = 0;
737
738     //Alloc a pkt
739     ret = av_new_packet(pkt, psize);
740     if (ret < 0)
741         return ret;
742     pkt->stream_index = idx;
743     memcpy(pkt->data, os->buf + pstart, psize);
744
745     pkt->pts      = pts;
746     pkt->dts      = dts;
747     pkt->flags    = os->pflags;
748     pkt->duration = os->pduration;
749     pkt->pos      = fpos;
750
751     return psize;
752 }
753
754 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
755                                   int64_t *pos_arg, int64_t pos_limit)
756 {
757     struct ogg *ogg = s->priv_data;
758     AVIOContext *bc = s->pb;
759     int64_t pts     = AV_NOPTS_VALUE;
760     int64_t keypos  = -1;
761     int i;
762     int pstart, psize;
763     avio_seek(bc, *pos_arg, SEEK_SET);
764     ogg_reset(s);
765
766     while (   avio_tell(bc) <= pos_limit
767            && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
768         if (i == stream_index) {
769             struct ogg_stream *os = ogg->streams + stream_index;
770             pts = ogg_calc_pts(s, i, NULL);
771             ogg_validate_keyframe(s, i, pstart, psize);
772             if (os->pflags & AV_PKT_FLAG_KEY) {
773                 keypos = *pos_arg;
774             } else if (os->keyframe_seek) {
775                 // if we had a previous keyframe but no pts for it,
776                 // return that keyframe with this pts value.
777                 if (keypos >= 0)
778                     *pos_arg = keypos;
779                 else
780                     pts = AV_NOPTS_VALUE;
781             }
782         }
783         if (pts != AV_NOPTS_VALUE)
784             break;
785     }
786     ogg_reset(s);
787     return pts;
788 }
789
790 static int ogg_read_seek(AVFormatContext *s, int stream_index,
791                          int64_t timestamp, int flags)
792 {
793     struct ogg *ogg       = s->priv_data;
794     struct ogg_stream *os = ogg->streams + stream_index;
795     int ret;
796
797     av_assert0(stream_index < ogg->nstreams);
798     // Ensure everything is reset even when seeking via
799     // the generated index.
800     ogg_reset(s);
801
802     // Try seeking to a keyframe first. If this fails (very possible),
803     // av_seek_frame will fall back to ignoring keyframes
804     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
805         && !(flags & AVSEEK_FLAG_ANY))
806         os->keyframe_seek = 1;
807
808     ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
809     os  = ogg->streams + stream_index;
810     if (ret < 0)
811         os->keyframe_seek = 0;
812     return ret;
813 }
814
815 static int ogg_probe(AVProbeData *p)
816 {
817     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
818         return AVPROBE_SCORE_MAX;
819     return 0;
820 }
821
822 AVInputFormat ff_ogg_demuxer = {
823     .name           = "ogg",
824     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
825     .priv_data_size = sizeof(struct ogg),
826     .read_probe     = ogg_probe,
827     .read_header    = ogg_read_header,
828     .read_packet    = ogg_read_packet,
829     .read_close     = ogg_read_close,
830     .read_seek      = ogg_read_seek,
831     .read_timestamp = ogg_read_timestamp,
832     .extensions     = "ogg",
833     .flags          = AVFMT_GENERIC_INDEX,
834 };