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