]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
avformat/oggdec: remove unused parameter of ogg_restore()
[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);
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);
99
100     return ret;
101 }
102
103 static int ogg_restore(AVFormatContext *s)
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         for (i = 0; i < ogg->nstreams; i++)
116             av_freep(&ogg->streams[i].buf);
117
118         avio_seek(bc, ost->pos, SEEK_SET);
119         ogg->page_pos = -1;
120         ogg->curidx   = ost->curidx;
121         ogg->nstreams = ost->nstreams;
122         if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
123                                      sizeof(*ogg->streams))) < 0) {
124             ogg->nstreams = 0;
125             return err;
126         } else
127             memcpy(ogg->streams, ost->streams,
128                    ost->nstreams * sizeof(*ogg->streams));
129
130     av_free(ost);
131
132     return 0;
133 }
134
135 static int ogg_reset(AVFormatContext *s)
136 {
137     struct ogg *ogg = s->priv_data;
138     int i;
139     int64_t start_pos = avio_tell(s->pb);
140
141     for (i = 0; i < ogg->nstreams; i++) {
142         struct ogg_stream *os = ogg->streams + i;
143         os->bufpos     = 0;
144         os->pstart     = 0;
145         os->psize      = 0;
146         os->granule    = -1;
147         os->lastpts    = AV_NOPTS_VALUE;
148         os->lastdts    = AV_NOPTS_VALUE;
149         os->sync_pos   = -1;
150         os->page_pos   = 0;
151         os->nsegs      = 0;
152         os->segp       = 0;
153         os->incomplete = 0;
154         os->got_data = 0;
155         if (start_pos <= s->internal->data_offset) {
156             os->lastpts = 0;
157         }
158         os->end_trimming = 0;
159         av_freep(&os->new_metadata);
160         os->new_metadata_size = 0;
161     }
162
163     ogg->page_pos = -1;
164     ogg->curidx = -1;
165
166     return 0;
167 }
168
169 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
170 {
171     int i;
172
173     for (i = 0; ogg_codecs[i]; i++)
174         if (size >= ogg_codecs[i]->magicsize &&
175             !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
176             return ogg_codecs[i];
177
178     return NULL;
179 }
180
181 /**
182  * Replace the current stream with a new one. This is a typical webradio
183  * situation where a new audio stream spawn (identified with a new serial) and
184  * must replace the previous one (track switch).
185  */
186 static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
187 {
188     struct ogg *ogg = s->priv_data;
189     struct ogg_stream *os;
190     const struct ogg_codec *codec;
191     int i = 0;
192
193     if (s->pb->seekable) {
194         uint8_t magic[8];
195         int64_t pos = avio_tell(s->pb);
196         avio_skip(s->pb, nsegs);
197         avio_read(s->pb, magic, sizeof(magic));
198         avio_seek(s->pb, pos, SEEK_SET);
199         codec = ogg_find_codec(magic, sizeof(magic));
200         if (!codec) {
201             av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
202             return AVERROR_INVALIDDATA;
203         }
204         for (i = 0; i < ogg->nstreams; i++) {
205             if (ogg->streams[i].codec == codec)
206                 break;
207         }
208         if (i >= ogg->nstreams)
209             return ogg_new_stream(s, serial);
210     } else if (ogg->nstreams != 1) {
211         avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
212         return AVERROR_PATCHWELCOME;
213     }
214
215     os = &ogg->streams[i];
216
217     os->serial  = serial;
218     return i;
219
220 #if 0
221     buf     = os->buf;
222     bufsize = os->bufsize;
223     codec   = os->codec;
224
225     if (!ogg->state || ogg->state->streams[i].private != os->private)
226         av_freep(&ogg->streams[i].private);
227
228     /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
229      * also re-use the ogg_stream allocated buffer */
230     memset(os, 0, sizeof(*os));
231     os->serial  = serial;
232     os->bufsize = bufsize;
233     os->buf     = buf;
234     os->header  = -1;
235     os->codec   = codec;
236
237     return i;
238 #endif
239 }
240
241 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
242 {
243     struct ogg *ogg = s->priv_data;
244     int idx         = ogg->nstreams;
245     AVStream *st;
246     struct ogg_stream *os;
247     size_t size;
248
249     if (ogg->state) {
250         av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
251                "in between Ogg context save/restore operations.\n");
252         return AVERROR_BUG;
253     }
254
255     /* Allocate and init a new Ogg Stream */
256     if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
257         !(os = av_realloc(ogg->streams, size)))
258         return AVERROR(ENOMEM);
259     ogg->streams = os;
260     os           = ogg->streams + idx;
261     memset(os, 0, sizeof(*os));
262     os->serial        = serial;
263     os->bufsize       = DECODER_BUFFER_SIZE;
264     os->buf           = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
265     os->header        = -1;
266     os->start_granule = OGG_NOGRANULE_VALUE;
267     if (!os->buf)
268         return AVERROR(ENOMEM);
269
270     /* Create the associated AVStream */
271     st = avformat_new_stream(s, NULL);
272     if (!st) {
273         av_freep(&os->buf);
274         return AVERROR(ENOMEM);
275     }
276     st->id = idx;
277     avpriv_set_pts_info(st, 64, 1, 1000000);
278
279     ogg->nstreams++;
280     return idx;
281 }
282
283 static int ogg_new_buf(struct ogg *ogg, int idx)
284 {
285     struct ogg_stream *os = ogg->streams + idx;
286     uint8_t *nb = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
287     int size = os->bufpos - os->pstart;
288
289     if (!nb)
290         return AVERROR(ENOMEM);
291
292     if (os->buf) {
293         memcpy(nb, os->buf + os->pstart, size);
294         av_free(os->buf);
295     }
296
297     os->buf    = nb;
298     os->bufpos = size;
299     os->pstart = 0;
300
301     return 0;
302 }
303
304 static int data_packets_seen(const struct ogg *ogg)
305 {
306     int i;
307
308     for (i = 0; i < ogg->nstreams; i++)
309         if (ogg->streams[i].got_data)
310             return 1;
311     return 0;
312 }
313
314 static int ogg_read_page(AVFormatContext *s, int *sid)
315 {
316     AVIOContext *bc = s->pb;
317     struct ogg *ogg = s->priv_data;
318     struct ogg_stream *os;
319     int ret, i = 0;
320     int flags, nsegs;
321     uint64_t gp;
322     uint32_t serial;
323     int size, idx;
324     uint8_t sync[4];
325     int sp = 0;
326
327     ret = avio_read(bc, sync, 4);
328     if (ret < 4)
329         return ret < 0 ? ret : AVERROR_EOF;
330
331     do {
332         int c;
333
334         if (sync[sp & 3] == 'O' &&
335             sync[(sp + 1) & 3] == 'g' &&
336             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
337             break;
338
339         if(!i && bc->seekable && ogg->page_pos > 0) {
340             memset(sync, 0, 4);
341             avio_seek(bc, ogg->page_pos+4, SEEK_SET);
342             ogg->page_pos = -1;
343         }
344
345         c = avio_r8(bc);
346
347         if (avio_feof(bc))
348             return AVERROR_EOF;
349
350         sync[sp++ & 3] = c;
351     } while (i++ < MAX_PAGE_SIZE);
352
353     if (i >= MAX_PAGE_SIZE) {
354         av_log(s, AV_LOG_INFO, "cannot find sync word\n");
355         return AVERROR_INVALIDDATA;
356     }
357
358     if (avio_r8(bc) != 0) {      /* version */
359         av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
360         return AVERROR_INVALIDDATA;
361     }
362
363     flags  = avio_r8(bc);
364     gp     = avio_rl64(bc);
365     serial = avio_rl32(bc);
366     avio_skip(bc, 8); /* seq, crc */
367     nsegs  = avio_r8(bc);
368
369     idx = ogg_find_stream(ogg, serial);
370     if (idx < 0) {
371         if (data_packets_seen(ogg))
372             idx = ogg_replace_stream(s, serial, nsegs);
373         else
374             idx = ogg_new_stream(s, serial);
375
376         if (idx < 0) {
377             av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
378             return idx;
379         }
380     }
381
382     os = ogg->streams + idx;
383     ogg->page_pos =
384     os->page_pos = avio_tell(bc) - 27;
385
386     if (os->psize > 0) {
387         ret = ogg_new_buf(ogg, idx);
388         if (ret < 0)
389             return ret;
390     }
391
392     ret = avio_read(bc, os->segments, nsegs);
393     if (ret < nsegs)
394         return ret < 0 ? ret : AVERROR_EOF;
395
396     os->nsegs = nsegs;
397     os->segp  = 0;
398
399     size = 0;
400     for (i = 0; i < nsegs; i++)
401         size += os->segments[i];
402
403     if (!(flags & OGG_FLAG_BOS))
404         os->got_data = 1;
405
406     if (flags & OGG_FLAG_CONT || os->incomplete) {
407         if (!os->psize) {
408             // If this is the very first segment we started
409             // playback in the middle of a continuation packet.
410             // Discard it since we missed the start of it.
411             while (os->segp < os->nsegs) {
412                 int seg = os->segments[os->segp++];
413                 os->pstart += seg;
414                 if (seg < 255)
415                     break;
416             }
417             os->sync_pos = os->page_pos;
418         }
419     } else {
420         os->psize    = 0;
421         os->sync_pos = os->page_pos;
422     }
423
424     if (os->bufsize - os->bufpos < size) {
425         uint8_t *nb = av_malloc((os->bufsize *= 2) + AV_INPUT_BUFFER_PADDING_SIZE);
426         if (!nb)
427             return AVERROR(ENOMEM);
428         memcpy(nb, os->buf, os->bufpos);
429         av_free(os->buf);
430         os->buf = nb;
431     }
432
433     ret = avio_read(bc, os->buf + os->bufpos, size);
434     if (ret < size)
435         return ret < 0 ? ret : AVERROR_EOF;
436
437     os->bufpos += size;
438     os->granule = gp;
439     os->flags   = flags;
440
441     memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
442     if (sid)
443         *sid = idx;
444
445     return 0;
446 }
447
448 /**
449  * @brief find the next Ogg packet
450  * @param *sid is set to the stream for the packet or -1 if there is
451  *             no matching stream, in that case assume all other return
452  *             values to be uninitialized.
453  * @return negative value on error or EOF.
454  */
455 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
456                       int64_t *fpos)
457 {
458     struct ogg *ogg = s->priv_data;
459     int idx, i, ret;
460     struct ogg_stream *os;
461     int complete = 0;
462     int segp     = 0, psize = 0;
463
464     av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
465     if (sid)
466         *sid = -1;
467
468     do {
469         idx = ogg->curidx;
470
471         while (idx < 0) {
472             ret = ogg_read_page(s, &idx);
473             if (ret < 0)
474                 return ret;
475         }
476
477         os = ogg->streams + idx;
478
479         av_log(s, AV_LOG_TRACE, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
480                 idx, os->pstart, os->psize, os->segp, os->nsegs);
481
482         if (!os->codec) {
483             if (os->header < 0) {
484                 os->codec = ogg_find_codec(os->buf, os->bufpos);
485                 if (!os->codec) {
486                     av_log(s, AV_LOG_WARNING, "Codec not found\n");
487                     os->header = 0;
488                     return 0;
489                 }
490             } else {
491                 return 0;
492             }
493         }
494
495         segp  = os->segp;
496         psize = os->psize;
497
498         while (os->segp < os->nsegs) {
499             int ss = os->segments[os->segp++];
500             os->psize += ss;
501             if (ss < 255) {
502                 complete = 1;
503                 break;
504             }
505         }
506
507         if (!complete && os->segp == os->nsegs) {
508             ogg->curidx    = -1;
509             // Do not set incomplete for empty packets.
510             // Together with the code in ogg_read_page
511             // that discards all continuation of empty packets
512             // we would get an infinite loop.
513             os->incomplete = !!os->psize;
514         }
515     } while (!complete);
516
517
518     if (os->granule == -1)
519         av_log(s, AV_LOG_WARNING,
520                "Page at %"PRId64" is missing granule\n",
521                os->page_pos);
522
523     ogg->curidx    = idx;
524     os->incomplete = 0;
525
526     if (os->header) {
527         os->header = os->codec->header(s, idx);
528         if (!os->header) {
529             os->segp  = segp;
530             os->psize = psize;
531
532             // We have reached the first non-header packet in this stream.
533             // Unfortunately more header packets may still follow for others,
534             // but if we continue with header parsing we may lose data packets.
535             ogg->headers = 1;
536
537             // Update the header state for all streams and
538             // compute the data_offset.
539             if (!s->internal->data_offset)
540                 s->internal->data_offset = os->sync_pos;
541
542             for (i = 0; i < ogg->nstreams; i++) {
543                 struct ogg_stream *cur_os = ogg->streams + i;
544
545                 // if we have a partial non-header packet, its start is
546                 // obviously at or after the data start
547                 if (cur_os->incomplete)
548                     s->internal->data_offset = FFMIN(s->internal->data_offset, cur_os->sync_pos);
549             }
550         } else {
551             os->nb_header++;
552             os->pstart += os->psize;
553             os->psize   = 0;
554         }
555     } else {
556         os->pflags    = 0;
557         os->pduration = 0;
558         if (os->codec && os->codec->packet)
559             os->codec->packet(s, idx);
560         if (sid)
561             *sid = idx;
562         if (dstart)
563             *dstart = os->pstart;
564         if (dsize)
565             *dsize = os->psize;
566         if (fpos)
567             *fpos = os->sync_pos;
568         os->pstart  += os->psize;
569         os->psize    = 0;
570         if(os->pstart == os->bufpos)
571             os->bufpos = os->pstart = 0;
572         os->sync_pos = os->page_pos;
573     }
574
575     // determine whether there are more complete packets in this page
576     // if not, the page's granule will apply to this packet
577     os->page_end = 1;
578     for (i = os->segp; i < os->nsegs; i++)
579         if (os->segments[i] < 255) {
580             os->page_end = 0;
581             break;
582         }
583
584     if (os->segp == os->nsegs)
585         ogg->curidx = -1;
586
587     return 0;
588 }
589
590 static int ogg_get_length(AVFormatContext *s)
591 {
592     struct ogg *ogg = s->priv_data;
593     int i, ret;
594     int64_t size, end;
595     int streams_left=0;
596
597     if (!s->pb->seekable)
598         return 0;
599
600 // already set
601     if (s->duration != AV_NOPTS_VALUE)
602         return 0;
603
604     size = avio_size(s->pb);
605     if (size < 0)
606         return 0;
607     end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
608
609     ret = ogg_save(s);
610     if (ret < 0)
611         return ret;
612     avio_seek(s->pb, end, SEEK_SET);
613     ogg->page_pos = -1;
614
615     while (!ogg_read_page(s, &i)) {
616         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
617             ogg->streams[i].codec) {
618             s->streams[i]->duration =
619                 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
620             if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
621                 s->streams[i]->duration -= s->streams[i]->start_time;
622                 streams_left-= (ogg->streams[i].got_start==-1);
623                 ogg->streams[i].got_start= 1;
624             } else if(!ogg->streams[i].got_start) {
625                 ogg->streams[i].got_start= -1;
626                 streams_left++;
627             }
628         }
629     }
630
631     ogg_restore(s);
632
633     ret = ogg_save(s);
634     if (ret < 0)
635         return ret;
636
637     avio_seek (s->pb, s->internal->data_offset, SEEK_SET);
638     ogg_reset(s);
639     while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
640         int64_t pts;
641         if (i < 0) continue;
642         pts = ogg_calc_pts(s, i, NULL);
643         if (s->streams[i]->duration == AV_NOPTS_VALUE)
644             continue;
645         if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
646             s->streams[i]->duration -= pts;
647             ogg->streams[i].got_start= 1;
648             streams_left--;
649         }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
650             ogg->streams[i].got_start= 1;
651             streams_left--;
652         }
653     }
654     ogg_restore (s);
655
656     return 0;
657 }
658
659 static int ogg_read_close(AVFormatContext *s)
660 {
661     struct ogg *ogg = s->priv_data;
662     int i;
663
664     for (i = 0; i < ogg->nstreams; i++) {
665         av_freep(&ogg->streams[i].buf);
666         if (ogg->streams[i].codec &&
667             ogg->streams[i].codec->cleanup) {
668             ogg->streams[i].codec->cleanup(s, i);
669         }
670         av_freep(&ogg->streams[i].private);
671         av_freep(&ogg->streams[i].new_metadata);
672     }
673
674     ogg->nstreams = 0;
675
676     av_freep(&ogg->streams);
677     return 0;
678 }
679
680 static int ogg_read_header(AVFormatContext *s)
681 {
682     struct ogg *ogg = s->priv_data;
683     int ret, i;
684
685     ogg->curidx = -1;
686
687     //linear headers seek from start
688     do {
689         ret = ogg_packet(s, NULL, NULL, NULL, NULL);
690         if (ret < 0) {
691             ogg_read_close(s);
692             return ret;
693         }
694     } while (!ogg->headers);
695     av_log(s, AV_LOG_TRACE, "found headers\n");
696
697     for (i = 0; i < ogg->nstreams; i++) {
698         struct ogg_stream *os = ogg->streams + i;
699
700         if (ogg->streams[i].header < 0) {
701             av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
702             ogg->streams[i].codec = NULL;
703             av_freep(&ogg->streams[i].private);
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 };