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