]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
mmsh_read_seek: skip header
[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 /**
9     Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
10
11     Permission is hereby granted, free of charge, to any person
12     obtaining a copy of this software and associated documentation
13     files (the "Software"), to deal in the Software without
14     restriction, including without limitation the rights to use, copy,
15     modify, merge, publish, distribute, sublicense, and/or sell copies
16     of the Software, and to permit persons to whom the Software is
17     furnished to do so, subject to the following conditions:
18
19     The above copyright notice and this permission notice shall be
20     included in all copies or substantial portions of the Software.
21
22     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29     DEALINGS IN THE SOFTWARE.
30 **/
31
32 #include <stdio.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_old_dirac_codec,
50     &ff_old_flac_codec,
51     &ff_ogm_video_codec,
52     &ff_ogm_audio_codec,
53     &ff_ogm_text_codec,
54     &ff_ogm_old_codec,
55     NULL
56 };
57
58 //FIXME We could avoid some structure duplication
59 static int ogg_save(AVFormatContext *s)
60 {
61     struct ogg *ogg = s->priv_data;
62     struct ogg_state *ost =
63         av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
64     int i;
65     ost->pos = avio_tell (s->pb);
66     ost->curidx = ogg->curidx;
67     ost->next = ogg->state;
68     ost->nstreams = ogg->nstreams;
69     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70
71     for (i = 0; i < ogg->nstreams; i++){
72         struct ogg_stream *os = ogg->streams + i;
73         os->buf = av_malloc (os->bufsize);
74         memset (os->buf, 0, os->bufsize);
75         memcpy (os->buf, ost->streams[i].buf, os->bufpos);
76     }
77
78     ogg->state = ost;
79
80     return 0;
81 }
82
83 static int ogg_restore(AVFormatContext *s, int discard)
84 {
85     struct ogg *ogg = s->priv_data;
86     AVIOContext *bc = s->pb;
87     struct ogg_state *ost = ogg->state;
88     int i;
89
90     if (!ost)
91         return 0;
92
93     ogg->state = ost->next;
94
95     if (!discard){
96         struct ogg_stream *old_streams = ogg->streams;
97
98         for (i = 0; i < ogg->nstreams; i++)
99             av_free (ogg->streams[i].buf);
100
101         avio_seek (bc, ost->pos, SEEK_SET);
102         ogg->curidx = ost->curidx;
103         ogg->nstreams = ost->nstreams;
104         ogg->streams = av_realloc (ogg->streams,
105                                    ogg->nstreams * sizeof (*ogg->streams));
106
107         if (ogg->streams) {
108             memcpy(ogg->streams, ost->streams,
109                    ost->nstreams * sizeof(*ogg->streams));
110         } else {
111             av_free(old_streams);
112             ogg->nstreams = 0;
113         }
114     }
115
116     av_free (ost);
117
118     return 0;
119 }
120
121 static int ogg_reset(struct ogg *ogg)
122 {
123     int i;
124
125     for (i = 0; i < ogg->nstreams; i++){
126         struct ogg_stream *os = ogg->streams + i;
127         os->bufpos = 0;
128         os->pstart = 0;
129         os->psize = 0;
130         os->granule = -1;
131         os->lastpts = AV_NOPTS_VALUE;
132         os->lastdts = AV_NOPTS_VALUE;
133         os->sync_pos = -1;
134         os->page_pos = 0;
135         os->nsegs = 0;
136         os->segp = 0;
137         os->incomplete = 0;
138     }
139
140     ogg->curidx = -1;
141
142     return 0;
143 }
144
145 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
146 {
147     int i;
148
149     for (i = 0; ogg_codecs[i]; i++)
150         if (size >= ogg_codecs[i]->magicsize &&
151             !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
152             return ogg_codecs[i];
153
154     return NULL;
155 }
156
157 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
158 {
159
160     struct ogg *ogg = s->priv_data;
161     int idx = ogg->nstreams++;
162     AVStream *st;
163     struct ogg_stream *os;
164
165     ogg->streams = av_realloc (ogg->streams,
166                                ogg->nstreams * sizeof (*ogg->streams));
167     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
168     os = ogg->streams + idx;
169     os->serial = serial;
170     os->bufsize = DECODER_BUFFER_SIZE;
171     os->buf = av_malloc(os->bufsize);
172     os->header = -1;
173
174     if (new_avstream) {
175         st = avformat_new_stream(s, NULL);
176         if (!st)
177             return AVERROR(ENOMEM);
178
179         st->id = idx;
180         av_set_pts_info(st, 64, 1, 1000000);
181     }
182
183     return idx;
184 }
185
186 static int ogg_new_buf(struct ogg *ogg, int idx)
187 {
188     struct ogg_stream *os = ogg->streams + idx;
189     uint8_t *nb = av_malloc(os->bufsize);
190     int size = os->bufpos - os->pstart;
191     if(os->buf){
192         memcpy(nb, os->buf + os->pstart, size);
193         av_free(os->buf);
194     }
195     os->buf = nb;
196     os->bufpos = size;
197     os->pstart = 0;
198
199     return 0;
200 }
201
202 static int ogg_read_page(AVFormatContext *s, int *str)
203 {
204     AVIOContext *bc = s->pb;
205     struct ogg *ogg = s->priv_data;
206     struct ogg_stream *os;
207     int ret, i = 0;
208     int flags, nsegs;
209     uint64_t gp;
210     uint32_t serial;
211     int size, idx;
212     uint8_t sync[4];
213     int sp = 0;
214
215     ret = avio_read(bc, sync, 4);
216     if (ret < 4)
217         return ret < 0 ? ret : AVERROR_EOF;
218
219     do{
220         int c;
221
222         if (sync[sp & 3] == 'O' &&
223             sync[(sp + 1) & 3] == 'g' &&
224             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
225             break;
226
227         c = avio_r8(bc);
228         if (url_feof(bc))
229             return AVERROR_EOF;
230         sync[sp++ & 3] = c;
231     }while (i++ < MAX_PAGE_SIZE);
232
233     if (i >= MAX_PAGE_SIZE){
234         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
235         return AVERROR_INVALIDDATA;
236     }
237
238     if (avio_r8(bc) != 0)      /* version */
239         return AVERROR_INVALIDDATA;
240
241     flags = avio_r8(bc);
242     gp = avio_rl64 (bc);
243     serial = avio_rl32 (bc);
244     avio_skip(bc, 8); /* seq, crc */
245     nsegs = avio_r8(bc);
246
247     idx = ogg_find_stream (ogg, serial);
248     if (idx < 0){
249         if (ogg->headers) {
250             int n;
251
252             for (n = 0; n < ogg->nstreams; n++) {
253                 av_freep(&ogg->streams[n].buf);
254                 if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
255                     av_freep(&ogg->streams[n].private);
256             }
257             ogg->curidx   = -1;
258             ogg->nstreams = 0;
259             idx = ogg_new_stream(s, serial, 0);
260         } else {
261             idx = ogg_new_stream(s, serial, 1);
262         }
263         if (idx < 0)
264             return idx;
265     }
266
267     os = ogg->streams + idx;
268     os->page_pos = avio_tell(bc) - 27;
269
270     if(os->psize > 0)
271         ogg_new_buf(ogg, idx);
272
273     ret = avio_read(bc, os->segments, nsegs);
274     if (ret < nsegs)
275         return ret < 0 ? ret : AVERROR_EOF;
276
277     os->nsegs = nsegs;
278     os->segp = 0;
279
280     size = 0;
281     for (i = 0; i < nsegs; i++)
282         size += os->segments[i];
283
284     if (flags & OGG_FLAG_CONT || os->incomplete){
285         if (!os->psize){
286             while (os->segp < os->nsegs){
287                 int seg = os->segments[os->segp++];
288                 os->pstart += seg;
289                 if (seg < 255)
290                     break;
291             }
292             os->sync_pos = os->page_pos;
293         }
294     }else{
295         os->psize = 0;
296         os->sync_pos = os->page_pos;
297     }
298
299     if (os->bufsize - os->bufpos < size){
300         uint8_t *nb = av_malloc (os->bufsize *= 2);
301         memcpy (nb, os->buf, os->bufpos);
302         av_free (os->buf);
303         os->buf = nb;
304     }
305
306     ret = avio_read(bc, os->buf + os->bufpos, size);
307     if (ret < size)
308         return ret < 0 ? ret : AVERROR_EOF;
309
310     os->bufpos += size;
311     os->granule = gp;
312     os->flags = flags;
313
314     if (str)
315         *str = idx;
316
317     return 0;
318 }
319
320 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
321                       int64_t *fpos)
322 {
323     struct ogg *ogg = s->priv_data;
324     int idx, i, ret;
325     struct ogg_stream *os;
326     int complete = 0;
327     int segp = 0, psize = 0;
328
329     av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
330
331     do{
332         idx = ogg->curidx;
333
334         while (idx < 0){
335             ret = ogg_read_page(s, &idx);
336             if (ret < 0)
337                 return ret;
338         }
339
340         os = ogg->streams + idx;
341
342         av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
343                 idx, os->pstart, os->psize, os->segp, os->nsegs);
344
345         if (!os->codec){
346             if (os->header < 0){
347                 os->codec = ogg_find_codec (os->buf, os->bufpos);
348                 if (!os->codec){
349                     av_log(s, AV_LOG_WARNING, "Codec not found\n");
350                     os->header = 0;
351                     return 0;
352                 }
353             }else{
354                 return 0;
355             }
356         }
357
358         segp = os->segp;
359         psize = os->psize;
360
361         while (os->segp < os->nsegs){
362             int ss = os->segments[os->segp++];
363             os->psize += ss;
364             if (ss < 255){
365                 complete = 1;
366                 break;
367             }
368         }
369
370         if (!complete && os->segp == os->nsegs){
371             ogg->curidx = -1;
372             os->incomplete = 1;
373         }
374     }while (!complete);
375
376
377     if (os->granule == -1)
378         av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
379
380     ogg->curidx = idx;
381     os->incomplete = 0;
382
383     if (os->header) {
384         os->header = os->codec->header (s, idx);
385         if (!os->header){
386             os->segp = segp;
387             os->psize = psize;
388
389             // We have reached the first non-header packet in this stream.
390             // Unfortunately more header packets may still follow for others,
391             // but if we continue with header parsing we may lose data packets.
392             ogg->headers = 1;
393
394             // Update the header state for all streams and
395             // compute the data_offset.
396             if (!s->data_offset)
397                 s->data_offset = os->sync_pos;
398             for (i = 0; i < ogg->nstreams; i++) {
399                 struct ogg_stream *cur_os = ogg->streams + i;
400
401                 // if we have a partial non-header packet, its start is
402                 // obviously at or after the data start
403                 if (cur_os->incomplete)
404                     s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
405             }
406         }else{
407             os->pstart += os->psize;
408             os->psize = 0;
409         }
410     } else {
411         os->pflags = 0;
412         os->pduration = 0;
413         if (os->codec && os->codec->packet)
414             os->codec->packet (s, idx);
415         if (str)
416             *str = idx;
417         if (dstart)
418             *dstart = os->pstart;
419         if (dsize)
420             *dsize = os->psize;
421         if (fpos)
422             *fpos = os->sync_pos;
423         os->pstart += os->psize;
424         os->psize = 0;
425         if(os->pstart == os->bufpos)
426             os->bufpos = os->pstart = 0;
427         os->sync_pos = os->page_pos;
428     }
429
430     // determine whether there are more complete packets in this page
431     // if not, the page's granule will apply to this packet
432     os->page_end = 1;
433     for (i = os->segp; i < os->nsegs; i++)
434         if (os->segments[i] < 255) {
435             os->page_end = 0;
436             break;
437         }
438
439     if (os->segp == os->nsegs)
440         ogg->curidx = -1;
441
442     return 0;
443 }
444
445 static int ogg_get_headers(AVFormatContext *s)
446 {
447     struct ogg *ogg = s->priv_data;
448     int ret;
449
450     do{
451         ret = ogg_packet(s, NULL, NULL, NULL, NULL);
452         if (ret < 0)
453             return ret;
454     }while (!ogg->headers);
455
456     av_dlog(s, "found headers\n");
457
458     return 0;
459 }
460
461 static int ogg_get_length(AVFormatContext *s)
462 {
463     struct ogg *ogg = s->priv_data;
464     int i;
465     int64_t size, end;
466     int streams_left=0;
467
468     if(!s->pb->seekable)
469         return 0;
470
471 // already set
472     if (s->duration != AV_NOPTS_VALUE)
473         return 0;
474
475     size = avio_size(s->pb);
476     if(size < 0)
477         return 0;
478     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
479
480     ogg_save (s);
481     avio_seek (s->pb, end, SEEK_SET);
482
483     while (!ogg_read_page (s, &i)){
484         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
485             ogg->streams[i].codec) {
486             s->streams[i]->duration =
487                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
488             if (s->streams[i]->start_time != AV_NOPTS_VALUE){
489                 s->streams[i]->duration -= s->streams[i]->start_time;
490                 streams_left-= (ogg->streams[i].got_start==-1);
491                 ogg->streams[i].got_start= 1;
492             }else if(!ogg->streams[i].got_start){
493                 ogg->streams[i].got_start= -1;
494                 streams_left++;
495             }
496         }
497     }
498
499     ogg_restore (s, 0);
500
501     ogg_save (s);
502     avio_seek (s->pb, 0, SEEK_SET);
503     while (!ogg_read_page (s, &i)){
504         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
505             ogg->streams[i].codec) {
506             if(s->streams[i]->duration && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
507                 int64_t start= ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
508                 if(av_rescale_q(start, s->streams[i]->time_base, AV_TIME_BASE_Q) > AV_TIME_BASE)
509                     s->streams[i]->duration -= start;
510                 ogg->streams[i].got_start= 1;
511                 streams_left--;
512             }
513             if(streams_left<=0)
514                 break;
515         }
516     }
517     ogg_restore (s, 0);
518
519     return 0;
520 }
521
522 static int ogg_read_header(AVFormatContext *s, AVFormatParameters *ap)
523 {
524     struct ogg *ogg = s->priv_data;
525     int ret, i;
526     ogg->curidx = -1;
527     //linear headers seek from start
528     ret = ogg_get_headers(s);
529     if (ret < 0)
530         return ret;
531
532     for (i = 0; i < ogg->nstreams; i++)
533         if (ogg->streams[i].header < 0)
534             ogg->streams[i].codec = NULL;
535
536     //linear granulepos seek from end
537     ogg_get_length (s);
538
539     //fill the extradata in the per codec callbacks
540     return 0;
541 }
542
543 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
544 {
545     struct ogg *ogg = s->priv_data;
546     struct ogg_stream *os = ogg->streams + idx;
547     int64_t pts = AV_NOPTS_VALUE;
548
549     if (dts)
550         *dts = AV_NOPTS_VALUE;
551
552     if (os->lastpts != AV_NOPTS_VALUE) {
553         pts = os->lastpts;
554         os->lastpts = AV_NOPTS_VALUE;
555     }
556     if (os->lastdts != AV_NOPTS_VALUE) {
557         if (dts)
558             *dts = os->lastdts;
559         os->lastdts = AV_NOPTS_VALUE;
560     }
561     if (os->page_end) {
562         if (os->granule != -1LL) {
563             if (os->codec && os->codec->granule_is_start)
564                 pts = ogg_gptopts(s, idx, os->granule, dts);
565             else
566                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
567             os->granule = -1LL;
568         }
569     }
570     return pts;
571 }
572
573 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
574 {
575     struct ogg *ogg;
576     struct ogg_stream *os;
577     int idx = -1, ret;
578     int pstart, psize;
579     int64_t fpos, pts, dts;
580
581     //Get an ogg packet
582 retry:
583     do{
584         ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
585         if (ret < 0)
586             return ret;
587     }while (idx < 0 || !s->streams[idx]);
588
589     ogg = s->priv_data;
590     os = ogg->streams + idx;
591
592     // pflags might not be set until after this
593     pts = ogg_calc_pts(s, idx, &dts);
594
595     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
596         goto retry;
597     os->keyframe_seek = 0;
598
599     //Alloc a pkt
600     ret = av_new_packet(pkt, psize);
601     if (ret < 0)
602         return ret;
603     pkt->stream_index = idx;
604     memcpy (pkt->data, os->buf + pstart, psize);
605
606     pkt->pts = pts;
607     pkt->dts = dts;
608     pkt->flags = os->pflags;
609     pkt->duration = os->pduration;
610     pkt->pos = fpos;
611
612     return psize;
613 }
614
615 static int ogg_read_close(AVFormatContext *s)
616 {
617     struct ogg *ogg = s->priv_data;
618     int i;
619
620     for (i = 0; i < ogg->nstreams; i++){
621         av_free (ogg->streams[i].buf);
622         av_free (ogg->streams[i].private);
623     }
624     av_free (ogg->streams);
625     return 0;
626 }
627
628 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
629                                   int64_t *pos_arg, int64_t pos_limit)
630 {
631     struct ogg *ogg = s->priv_data;
632     AVIOContext *bc = s->pb;
633     int64_t pts = AV_NOPTS_VALUE;
634     int i = -1;
635     avio_seek(bc, *pos_arg, SEEK_SET);
636     ogg_reset(ogg);
637
638     while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
639         if (i == stream_index) {
640             struct ogg_stream *os = ogg->streams + stream_index;
641             pts = ogg_calc_pts(s, i, NULL);
642             if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
643                 pts = AV_NOPTS_VALUE;
644         }
645         if (pts != AV_NOPTS_VALUE)
646             break;
647     }
648     ogg_reset(ogg);
649     return pts;
650 }
651
652 static int ogg_read_seek(AVFormatContext *s, int stream_index,
653                          int64_t timestamp, int flags)
654 {
655     struct ogg *ogg = s->priv_data;
656     struct ogg_stream *os = ogg->streams + stream_index;
657     int ret;
658
659     // Try seeking to a keyframe first. If this fails (very possible),
660     // av_seek_frame will fall back to ignoring keyframes
661     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
662         && !(flags & AVSEEK_FLAG_ANY))
663         os->keyframe_seek = 1;
664
665     ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
666     os = ogg->streams + stream_index;
667     if (ret < 0)
668         os->keyframe_seek = 0;
669     return ret;
670 }
671
672 static int ogg_probe(AVProbeData *p)
673 {
674     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
675         return AVPROBE_SCORE_MAX;
676     return 0;
677 }
678
679 AVInputFormat ff_ogg_demuxer = {
680     .name           = "ogg",
681     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
682     .priv_data_size = sizeof(struct ogg),
683     .read_probe     = ogg_probe,
684     .read_header    = ogg_read_header,
685     .read_packet    = ogg_read_packet,
686     .read_close     = ogg_read_close,
687     .read_seek      = ogg_read_seek,
688     .read_timestamp = ogg_read_timestamp,
689     .extensions     = "ogg",
690     .flags          = AVFMT_GENERIC_INDEX,
691 };