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