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