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