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