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