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