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