]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
wrap_timestamp: remove unneeded check
[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     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     if(os->buf){
253         memcpy(nb, os->buf + os->pstart, size);
254         av_free(os->buf);
255     }
256     os->buf = nb;
257     os->bufpos = size;
258     os->pstart = 0;
259
260     return 0;
261 }
262
263 static int data_packets_seen(const struct ogg *ogg)
264 {
265     int i;
266
267     for (i = 0; i < ogg->nstreams; i++)
268         if (ogg->streams[i].got_data)
269             return 1;
270     return 0;
271 }
272
273 static int ogg_read_page(AVFormatContext *s, int *sid)
274 {
275     AVIOContext *bc = s->pb;
276     struct ogg *ogg = s->priv_data;
277     struct ogg_stream *os;
278     int ret, i = 0;
279     int flags, nsegs;
280     uint64_t gp;
281     uint32_t serial;
282     int size, idx;
283     uint8_t sync[4];
284     int sp = 0;
285
286     ret = avio_read(bc, sync, 4);
287     if (ret < 4)
288         return ret < 0 ? ret : AVERROR_EOF;
289
290     do{
291         int c;
292
293         if (sync[sp & 3] == 'O' &&
294             sync[(sp + 1) & 3] == 'g' &&
295             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
296             break;
297
298         c = avio_r8(bc);
299         if (url_feof(bc))
300             return AVERROR_EOF;
301         sync[sp++ & 3] = c;
302     }while (i++ < MAX_PAGE_SIZE);
303
304     if (i >= MAX_PAGE_SIZE){
305         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
306         return AVERROR_INVALIDDATA;
307     }
308
309     if (avio_r8(bc) != 0){      /* version */
310         av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
311         return AVERROR_INVALIDDATA;
312     }
313
314     flags = avio_r8(bc);
315     gp = avio_rl64 (bc);
316     serial = avio_rl32 (bc);
317     avio_skip(bc, 8); /* seq, crc */
318     nsegs = avio_r8(bc);
319
320     idx = ogg_find_stream (ogg, serial);
321     if (idx < 0){
322         if (data_packets_seen(ogg))
323             idx = ogg_replace_stream(s, serial);
324         else
325             idx = ogg_new_stream(s, serial);
326
327         if (idx < 0) {
328             av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
329             return idx;
330         }
331     }
332
333     os = ogg->streams + idx;
334     os->page_pos = avio_tell(bc) - 27;
335
336     if(os->psize > 0)
337         ogg_new_buf(ogg, idx);
338
339     ret = avio_read(bc, os->segments, nsegs);
340     if (ret < nsegs)
341         return ret < 0 ? ret : AVERROR_EOF;
342
343     os->nsegs = nsegs;
344     os->segp = 0;
345
346     size = 0;
347     for (i = 0; i < nsegs; i++)
348         size += os->segments[i];
349
350     if (!(flags & OGG_FLAG_BOS))
351         os->got_data = 1;
352
353     if (flags & OGG_FLAG_CONT || os->incomplete){
354         if (!os->psize){
355             // If this is the very first segment we started
356             // playback in the middle of a continuation packet.
357             // Discard it since we missed the start of it.
358             while (os->segp < os->nsegs){
359                 int seg = os->segments[os->segp++];
360                 os->pstart += seg;
361                 if (seg < 255)
362                     break;
363             }
364             os->sync_pos = os->page_pos;
365         }
366     }else{
367         os->psize = 0;
368         os->sync_pos = os->page_pos;
369     }
370
371     if (os->bufsize - os->bufpos < size){
372         uint8_t *nb = av_malloc ((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
373         memcpy (nb, os->buf, os->bufpos);
374         av_free (os->buf);
375         os->buf = nb;
376     }
377
378     ret = avio_read(bc, os->buf + os->bufpos, size);
379     if (ret < size)
380         return ret < 0 ? ret : AVERROR_EOF;
381
382     os->bufpos += size;
383     os->granule = gp;
384     os->flags = flags;
385
386     memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
387     if (sid)
388         *sid = idx;
389
390     return 0;
391 }
392
393 /**
394  * @brief find the next Ogg packet
395  * @param *sid is set to the stream for the packet or -1 if there is
396  *             no matching stream, in that case assume all other return
397  *             values to be uninitialized.
398  * @return negative value on error or EOF.
399  */
400 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
401                       int64_t *fpos)
402 {
403     struct ogg *ogg = s->priv_data;
404     int idx, i, ret;
405     struct ogg_stream *os;
406     int complete = 0;
407     int segp = 0, psize = 0;
408
409     av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
410     if (sid)
411         *sid = -1;
412
413     do{
414         idx = ogg->curidx;
415
416         while (idx < 0){
417             ret = ogg_read_page(s, &idx);
418             if (ret < 0)
419                 return ret;
420         }
421
422         os = ogg->streams + idx;
423
424         av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
425                 idx, os->pstart, os->psize, os->segp, os->nsegs);
426
427         if (!os->codec){
428             if (os->header < 0){
429                 os->codec = ogg_find_codec (os->buf, os->bufpos);
430                 if (!os->codec){
431                     av_log(s, AV_LOG_WARNING, "Codec not found\n");
432                     os->header = 0;
433                     return 0;
434                 }
435             }else{
436                 return 0;
437             }
438         }
439
440         segp = os->segp;
441         psize = os->psize;
442
443         while (os->segp < os->nsegs){
444             int ss = os->segments[os->segp++];
445             os->psize += ss;
446             if (ss < 255){
447                 complete = 1;
448                 break;
449             }
450         }
451
452         if (!complete && os->segp == os->nsegs){
453             ogg->curidx = -1;
454             // Do not set incomplete for empty packets.
455             // Together with the code in ogg_read_page
456             // that discards all continuation of empty packets
457             // we would get an infinite loop.
458             os->incomplete = !!os->psize;
459         }
460     }while (!complete);
461
462
463     if (os->granule == -1)
464         av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
465
466     ogg->curidx = idx;
467     os->incomplete = 0;
468
469     if (os->header) {
470         os->header = os->codec->header (s, idx);
471         if (!os->header){
472             os->segp = segp;
473             os->psize = psize;
474
475             // We have reached the first non-header packet in this stream.
476             // Unfortunately more header packets may still follow for others,
477             // but if we continue with header parsing we may lose data packets.
478             ogg->headers = 1;
479
480             // Update the header state for all streams and
481             // compute the data_offset.
482             if (!s->data_offset)
483                 s->data_offset = os->sync_pos;
484             for (i = 0; i < ogg->nstreams; i++) {
485                 struct ogg_stream *cur_os = ogg->streams + i;
486
487                 // if we have a partial non-header packet, its start is
488                 // obviously at or after the data start
489                 if (cur_os->incomplete)
490                     s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
491             }
492         }else{
493             os->nb_header++;
494             os->pstart += os->psize;
495             os->psize = 0;
496         }
497     } else {
498         os->pflags = 0;
499         os->pduration = 0;
500         if (os->codec && os->codec->packet)
501             os->codec->packet (s, idx);
502         if (sid)
503             *sid = idx;
504         if (dstart)
505             *dstart = os->pstart;
506         if (dsize)
507             *dsize = os->psize;
508         if (fpos)
509             *fpos = os->sync_pos;
510         os->pstart += os->psize;
511         os->psize = 0;
512         if(os->pstart == os->bufpos)
513             os->bufpos = os->pstart = 0;
514         os->sync_pos = os->page_pos;
515     }
516
517     // determine whether there are more complete packets in this page
518     // if not, the page's granule will apply to this packet
519     os->page_end = 1;
520     for (i = os->segp; i < os->nsegs; i++)
521         if (os->segments[i] < 255) {
522             os->page_end = 0;
523             break;
524         }
525
526     if (os->segp == os->nsegs)
527         ogg->curidx = -1;
528
529     return 0;
530 }
531
532 static int ogg_get_length(AVFormatContext *s)
533 {
534     struct ogg *ogg = s->priv_data;
535     int i;
536     int64_t size, end;
537     int streams_left=0;
538
539     if(!s->pb->seekable)
540         return 0;
541
542 // already set
543     if (s->duration != AV_NOPTS_VALUE)
544         return 0;
545
546     size = avio_size(s->pb);
547     if(size < 0)
548         return 0;
549     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
550
551     ogg_save (s);
552     avio_seek (s->pb, end, SEEK_SET);
553
554     while (!ogg_read_page (s, &i)){
555         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
556             ogg->streams[i].codec) {
557             s->streams[i]->duration =
558                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
559             if (s->streams[i]->start_time != AV_NOPTS_VALUE){
560                 s->streams[i]->duration -= s->streams[i]->start_time;
561                 streams_left-= (ogg->streams[i].got_start==-1);
562                 ogg->streams[i].got_start= 1;
563             }else if(!ogg->streams[i].got_start){
564                 ogg->streams[i].got_start= -1;
565                 streams_left++;
566             }
567         }
568     }
569
570     ogg_restore (s, 0);
571
572     ogg_save (s);
573     avio_seek (s->pb, s->data_offset, SEEK_SET);
574     ogg_reset(s);
575     while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
576         int64_t pts;
577         if (i < 0) continue;
578         pts = ogg_calc_pts(s, i, NULL);
579         if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
580             s->streams[i]->duration -= pts;
581             ogg->streams[i].got_start= 1;
582             streams_left--;
583         }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start){
584             ogg->streams[i].got_start= 1;
585             streams_left--;
586         }
587     }
588     ogg_restore (s, 0);
589
590     return 0;
591 }
592
593 static int ogg_read_header(AVFormatContext *s)
594 {
595     struct ogg *ogg = s->priv_data;
596     int ret, i;
597
598     ogg->curidx = -1;
599
600     //linear headers seek from start
601     do {
602         ret = ogg_packet(s, NULL, NULL, NULL, NULL);
603         if (ret < 0) {
604             ogg_read_close(s);
605             return ret;
606         }
607     } while (!ogg->headers);
608     av_dlog(s, "found headers\n");
609
610     for (i = 0; i < ogg->nstreams; i++) {
611         struct ogg_stream *os = ogg->streams + i;
612
613         if (ogg->streams[i].header < 0) {
614             av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
615             ogg->streams[i].codec = NULL;
616         } else if (os->codec && os->nb_header < os->codec->nb_header) {
617             av_log(s, AV_LOG_WARNING, "Number of headers (%d) mismatch for stream %d\n", os->nb_header, i);
618         }
619         if (os->start_granule != OGG_NOGRANULE_VALUE)
620             os->lastpts = s->streams[i]->start_time =
621                 ogg_gptopts(s, i, os->start_granule, NULL);
622     }
623
624     //linear granulepos seek from end
625     ogg_get_length (s);
626
627     return 0;
628 }
629
630 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
631 {
632     struct ogg *ogg = s->priv_data;
633     struct ogg_stream *os = ogg->streams + idx;
634     int64_t pts = AV_NOPTS_VALUE;
635
636     if (dts)
637         *dts = AV_NOPTS_VALUE;
638
639     if (os->lastpts != AV_NOPTS_VALUE) {
640         pts = os->lastpts;
641         os->lastpts = AV_NOPTS_VALUE;
642     }
643     if (os->lastdts != AV_NOPTS_VALUE) {
644         if (dts)
645             *dts = os->lastdts;
646         os->lastdts = AV_NOPTS_VALUE;
647     }
648     if (os->page_end) {
649         if (os->granule != -1LL) {
650             if (os->codec && os->codec->granule_is_start)
651                 pts = ogg_gptopts(s, idx, os->granule, dts);
652             else
653                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
654             os->granule = -1LL;
655         }
656     }
657     return pts;
658 }
659
660 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
661 {
662     struct ogg *ogg = s->priv_data;
663     struct ogg_stream *os = ogg->streams + idx;
664     if (psize && s->streams[idx]->codec->codec_id == AV_CODEC_ID_THEORA) {
665         if (!!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40)) {
666             os->pflags ^= AV_PKT_FLAG_KEY;
667             av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
668                    (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
669         }
670     }
671 }
672
673 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
674 {
675     struct ogg *ogg;
676     struct ogg_stream *os;
677     int idx, ret;
678     int pstart, psize;
679     int64_t fpos, pts, dts;
680
681     //Get an ogg packet
682 retry:
683     do{
684         ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
685         if (ret < 0)
686             return ret;
687     }while (idx < 0 || !s->streams[idx]);
688
689     ogg = s->priv_data;
690     os = ogg->streams + idx;
691
692     // pflags might not be set until after this
693     pts = ogg_calc_pts(s, idx, &dts);
694     ogg_validate_keyframe(s, idx, pstart, psize);
695
696     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
697         goto retry;
698     os->keyframe_seek = 0;
699
700     //Alloc a pkt
701     ret = av_new_packet(pkt, psize);
702     if (ret < 0)
703         return ret;
704     pkt->stream_index = idx;
705     memcpy (pkt->data, os->buf + pstart, psize);
706
707     pkt->pts = pts;
708     pkt->dts = dts;
709     pkt->flags = os->pflags;
710     pkt->duration = os->pduration;
711     pkt->pos = fpos;
712
713     return psize;
714 }
715
716 static int ogg_read_close(AVFormatContext *s)
717 {
718     struct ogg *ogg = s->priv_data;
719     int i;
720
721     for (i = 0; i < ogg->nstreams; i++){
722         av_free (ogg->streams[i].buf);
723         av_free (ogg->streams[i].private);
724     }
725     av_free (ogg->streams);
726     return 0;
727 }
728
729 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
730                                   int64_t *pos_arg, int64_t pos_limit)
731 {
732     struct ogg *ogg = s->priv_data;
733     AVIOContext *bc = s->pb;
734     int64_t pts = AV_NOPTS_VALUE;
735     int64_t keypos = -1;
736     int i;
737     int pstart, psize;
738     avio_seek(bc, *pos_arg, SEEK_SET);
739     ogg_reset(s);
740
741     while (avio_tell(bc) <= pos_limit && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
742         if (i == stream_index) {
743             struct ogg_stream *os = ogg->streams + stream_index;
744             pts = ogg_calc_pts(s, i, NULL);
745             ogg_validate_keyframe(s, i, pstart, psize);
746             if (os->pflags & AV_PKT_FLAG_KEY) {
747                 keypos = *pos_arg;
748             } else if (os->keyframe_seek) {
749                 // if we had a previous keyframe but no pts for it,
750                 // return that keyframe with this pts value.
751                 if (keypos >= 0)
752                     *pos_arg = keypos;
753                 else
754                     pts = AV_NOPTS_VALUE;
755             }
756         }
757         if (pts != AV_NOPTS_VALUE)
758             break;
759     }
760     ogg_reset(s);
761     return pts;
762 }
763
764 static int ogg_read_seek(AVFormatContext *s, int stream_index,
765                          int64_t timestamp, int flags)
766 {
767     struct ogg *ogg = s->priv_data;
768     struct ogg_stream *os = ogg->streams + stream_index;
769     int ret;
770
771     av_assert0(stream_index < ogg->nstreams);
772     // Ensure everything is reset even when seeking via
773     // the generated index.
774     ogg_reset(s);
775
776     // Try seeking to a keyframe first. If this fails (very possible),
777     // av_seek_frame will fall back to ignoring keyframes
778     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
779         && !(flags & AVSEEK_FLAG_ANY))
780         os->keyframe_seek = 1;
781
782     ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
783     os = ogg->streams + stream_index;
784     if (ret < 0)
785         os->keyframe_seek = 0;
786     return ret;
787 }
788
789 static int ogg_probe(AVProbeData *p)
790 {
791     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
792         return AVPROBE_SCORE_MAX;
793     return 0;
794 }
795
796 AVInputFormat ff_ogg_demuxer = {
797     .name           = "ogg",
798     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
799     .priv_data_size = sizeof(struct ogg),
800     .read_probe     = ogg_probe,
801     .read_header    = ogg_read_header,
802     .read_packet    = ogg_read_packet,
803     .read_close     = ogg_read_close,
804     .read_seek      = ogg_read_seek,
805     .read_timestamp = ogg_read_timestamp,
806     .extensions     = "ogg",
807     .flags          = AVFMT_GENERIC_INDEX,
808 };