]> git.sesse.net Git - ffmpeg/blob - libavformat/oggdec.c
dv: use AVStream.index instead of abusing AVStream.id
[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
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_mallocz (os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
74         memcpy (os->buf, ost->streams[i].buf, os->bufpos);
75     }
76
77     ogg->state = ost;
78
79     return 0;
80 }
81
82 static int ogg_restore(AVFormatContext *s, int discard)
83 {
84     struct ogg *ogg = s->priv_data;
85     AVIOContext *bc = s->pb;
86     struct ogg_state *ost = ogg->state;
87     int i;
88
89     if (!ost)
90         return 0;
91
92     ogg->state = ost->next;
93
94     if (!discard){
95         struct ogg_stream *old_streams = ogg->streams;
96
97         for (i = 0; i < ogg->nstreams; i++)
98             av_free (ogg->streams[i].buf);
99
100         avio_seek (bc, ost->pos, SEEK_SET);
101         ogg->curidx = ost->curidx;
102         ogg->nstreams = ost->nstreams;
103         ogg->streams = av_realloc (ogg->streams,
104                                    ogg->nstreams * sizeof (*ogg->streams));
105
106         if (ogg->streams) {
107             memcpy(ogg->streams, ost->streams,
108                    ost->nstreams * sizeof(*ogg->streams));
109         } else {
110             av_free(old_streams);
111             ogg->nstreams = 0;
112         }
113     }
114
115     av_free (ost);
116
117     return 0;
118 }
119
120 static int ogg_reset(struct ogg *ogg)
121 {
122     int i;
123
124     for (i = 0; i < ogg->nstreams; i++){
125         struct ogg_stream *os = ogg->streams + i;
126         os->bufpos = 0;
127         os->pstart = 0;
128         os->psize = 0;
129         os->granule = -1;
130         os->lastpts = AV_NOPTS_VALUE;
131         os->lastdts = AV_NOPTS_VALUE;
132         os->sync_pos = -1;
133         os->page_pos = 0;
134         os->nsegs = 0;
135         os->segp = 0;
136         os->incomplete = 0;
137     }
138
139     ogg->curidx = -1;
140
141     return 0;
142 }
143
144 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
145 {
146     int i;
147
148     for (i = 0; ogg_codecs[i]; i++)
149         if (size >= ogg_codecs[i]->magicsize &&
150             !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
151             return ogg_codecs[i];
152
153     return NULL;
154 }
155
156 static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
157 {
158
159     struct ogg *ogg = s->priv_data;
160     int idx = ogg->nstreams++;
161     AVStream *st;
162     struct ogg_stream *os;
163
164     ogg->streams = av_realloc (ogg->streams,
165                                ogg->nstreams * sizeof (*ogg->streams));
166     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
167     os = ogg->streams + idx;
168     os->serial = serial;
169     os->bufsize = DECODER_BUFFER_SIZE;
170     os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
171     os->header = -1;
172     os->start_granule = OGG_NOGRANULE_VALUE;
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         avpriv_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 + FF_INPUT_BUFFER_PADDING_SIZE);
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 (bc->eof_reached)
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) + FF_INPUT_BUFFER_PADDING_SIZE);
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     memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
315     if (str)
316         *str = idx;
317
318     return 0;
319 }
320
321 static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
322                       int64_t *fpos)
323 {
324     struct ogg *ogg = s->priv_data;
325     int idx, i, ret;
326     struct ogg_stream *os;
327     int complete = 0;
328     int segp = 0, psize = 0;
329
330     av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
331
332     do{
333         idx = ogg->curidx;
334
335         while (idx < 0){
336             ret = ogg_read_page(s, &idx);
337             if (ret < 0)
338                 return ret;
339         }
340
341         os = ogg->streams + idx;
342
343         av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
344                 idx, os->pstart, os->psize, os->segp, os->nsegs);
345
346         if (!os->codec){
347             if (os->header < 0){
348                 os->codec = ogg_find_codec (os->buf, os->bufpos);
349                 if (!os->codec){
350                     av_log(s, AV_LOG_WARNING, "Codec not found\n");
351                     os->header = 0;
352                     return 0;
353                 }
354             }else{
355                 return 0;
356             }
357         }
358
359         segp = os->segp;
360         psize = os->psize;
361
362         while (os->segp < os->nsegs){
363             int ss = os->segments[os->segp++];
364             os->psize += ss;
365             if (ss < 255){
366                 complete = 1;
367                 break;
368             }
369         }
370
371         if (!complete && os->segp == os->nsegs){
372             ogg->curidx = -1;
373             os->incomplete = 1;
374         }
375     }while (!complete);
376
377     av_dlog(s, "ogg_packet: idx %i, frame size %i, start %i\n",
378             idx, os->psize, os->pstart);
379
380     if (os->granule == -1)
381         av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
382
383     ogg->curidx = idx;
384     os->incomplete = 0;
385
386     if (os->header) {
387         os->header = os->codec->header (s, idx);
388         if (!os->header){
389             os->segp = segp;
390             os->psize = psize;
391
392             // We have reached the first non-header packet in this stream.
393             // Unfortunately more header packets may still follow for others,
394             // but if we continue with header parsing we may lose data packets.
395             ogg->headers = 1;
396
397             // Update the header state for all streams and
398             // compute the data_offset.
399             if (!s->data_offset)
400                 s->data_offset = os->sync_pos;
401             for (i = 0; i < ogg->nstreams; i++) {
402                 struct ogg_stream *cur_os = ogg->streams + i;
403
404                 // if we have a partial non-header packet, its start is
405                 // obviously at or after the data start
406                 if (cur_os->incomplete)
407                     s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
408             }
409         }else{
410             os->nb_header++;
411             os->pstart += os->psize;
412             os->psize = 0;
413         }
414     } else {
415         os->pflags = 0;
416         os->pduration = 0;
417         if (os->codec && os->codec->packet)
418             os->codec->packet (s, idx);
419         if (str)
420             *str = idx;
421         if (dstart)
422             *dstart = os->pstart;
423         if (dsize)
424             *dsize = os->psize;
425         if (fpos)
426             *fpos = os->sync_pos;
427         os->pstart += os->psize;
428         os->psize = 0;
429         os->sync_pos = os->page_pos;
430     }
431
432     // determine whether there are more complete packets in this page
433     // if not, the page's granule will apply to this packet
434     os->page_end = 1;
435     for (i = os->segp; i < os->nsegs; i++)
436         if (os->segments[i] < 255) {
437             os->page_end = 0;
438             break;
439         }
440
441     if (os->segp == os->nsegs)
442         ogg->curidx = -1;
443
444     return 0;
445 }
446
447 static int ogg_get_headers(AVFormatContext *s)
448 {
449     struct ogg *ogg = s->priv_data;
450     int ret, i;
451
452     do{
453         ret = ogg_packet(s, NULL, NULL, NULL, NULL);
454         if (ret < 0)
455             return ret;
456     }while (!ogg->headers);
457
458     for (i = 0; i < ogg->nstreams; i++) {
459         struct ogg_stream *os = ogg->streams + i;
460
461         if (os->codec && os->codec->nb_header &&
462             os->nb_header < os->codec->nb_header) {
463             av_log(s, AV_LOG_ERROR,
464                    "Headers mismatch for stream %d\n", i);
465             return AVERROR_INVALIDDATA;
466         }
467         if (os->start_granule != OGG_NOGRANULE_VALUE)
468             os->lastpts = s->streams[i]->start_time =
469                 ogg_gptopts(s, i, os->start_granule, NULL);
470     }
471     av_dlog(s, "found headers\n");
472
473     return 0;
474 }
475
476 static int ogg_get_length(AVFormatContext *s)
477 {
478     struct ogg *ogg = s->priv_data;
479     int i;
480     int64_t size, end;
481
482     if(!s->pb->seekable)
483         return 0;
484
485 // already set
486     if (s->duration != AV_NOPTS_VALUE)
487         return 0;
488
489     size = avio_size(s->pb);
490     if(size < 0)
491         return 0;
492     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
493
494     ogg_save (s);
495     avio_seek (s->pb, end, SEEK_SET);
496
497     while (!ogg_read_page (s, &i)){
498         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
499             ogg->streams[i].codec) {
500             s->streams[i]->duration =
501                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
502             if (s->streams[i]->start_time != AV_NOPTS_VALUE)
503                 s->streams[i]->duration -= s->streams[i]->start_time;
504         }
505     }
506
507     ogg_restore (s, 0);
508
509     return 0;
510 }
511
512 static int ogg_read_header(AVFormatContext *s)
513 {
514     struct ogg *ogg = s->priv_data;
515     int ret, i;
516     ogg->curidx = -1;
517     //linear headers seek from start
518     ret = ogg_get_headers(s);
519     if (ret < 0)
520         return ret;
521
522     for (i = 0; i < ogg->nstreams; i++)
523         if (ogg->streams[i].header < 0)
524             ogg->streams[i].codec = NULL;
525
526     //linear granulepos seek from end
527     ogg_get_length (s);
528
529     //fill the extradata in the per codec callbacks
530     return 0;
531 }
532
533 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
534 {
535     struct ogg *ogg = s->priv_data;
536     struct ogg_stream *os = ogg->streams + idx;
537     int64_t pts = AV_NOPTS_VALUE;
538
539     if (dts)
540         *dts = AV_NOPTS_VALUE;
541
542     if (os->lastpts != AV_NOPTS_VALUE) {
543         pts = os->lastpts;
544         os->lastpts = AV_NOPTS_VALUE;
545     }
546     if (os->lastdts != AV_NOPTS_VALUE) {
547         if (dts)
548             *dts = os->lastdts;
549         os->lastdts = AV_NOPTS_VALUE;
550     }
551     if (os->page_end) {
552         if (os->granule != -1LL) {
553             if (os->codec && os->codec->granule_is_start)
554                 pts = ogg_gptopts(s, idx, os->granule, dts);
555             else
556                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
557             os->granule = -1LL;
558         }
559     }
560     return pts;
561 }
562
563 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
564 {
565     struct ogg *ogg;
566     struct ogg_stream *os;
567     int idx = -1, ret;
568     int pstart, psize;
569     int64_t fpos, pts, dts;
570
571     //Get an ogg packet
572 retry:
573     do{
574         ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
575         if (ret < 0)
576             return ret;
577     }while (idx < 0 || !s->streams[idx]);
578
579     ogg = s->priv_data;
580     os = ogg->streams + idx;
581
582     // pflags might not be set until after this
583     pts = ogg_calc_pts(s, idx, &dts);
584
585     if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
586         goto retry;
587     os->keyframe_seek = 0;
588
589     //Alloc a pkt
590     ret = av_new_packet(pkt, psize);
591     if (ret < 0)
592         return ret;
593     pkt->stream_index = idx;
594     memcpy (pkt->data, os->buf + pstart, psize);
595
596     pkt->pts = pts;
597     pkt->dts = dts;
598     pkt->flags = os->pflags;
599     pkt->duration = os->pduration;
600     pkt->pos = fpos;
601
602     return psize;
603 }
604
605 static int ogg_read_close(AVFormatContext *s)
606 {
607     struct ogg *ogg = s->priv_data;
608     int i;
609
610     for (i = 0; i < ogg->nstreams; i++){
611         av_free (ogg->streams[i].buf);
612         av_free (ogg->streams[i].private);
613     }
614     av_free (ogg->streams);
615     return 0;
616 }
617
618 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
619                                   int64_t *pos_arg, int64_t pos_limit)
620 {
621     struct ogg *ogg = s->priv_data;
622     AVIOContext *bc = s->pb;
623     int64_t pts = AV_NOPTS_VALUE;
624     int i = -1;
625     avio_seek(bc, *pos_arg, SEEK_SET);
626     ogg_reset(ogg);
627
628     while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
629         if (i == stream_index) {
630             struct ogg_stream *os = ogg->streams + stream_index;
631             pts = ogg_calc_pts(s, i, NULL);
632             if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
633                 pts = AV_NOPTS_VALUE;
634         }
635         if (pts != AV_NOPTS_VALUE)
636             break;
637     }
638     ogg_reset(ogg);
639     return pts;
640 }
641
642 static int ogg_read_seek(AVFormatContext *s, int stream_index,
643                          int64_t timestamp, int flags)
644 {
645     struct ogg *ogg = s->priv_data;
646     struct ogg_stream *os = ogg->streams + stream_index;
647     int ret;
648
649     // Try seeking to a keyframe first. If this fails (very possible),
650     // av_seek_frame will fall back to ignoring keyframes
651     if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
652         && !(flags & AVSEEK_FLAG_ANY))
653         os->keyframe_seek = 1;
654
655     ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
656     os = ogg->streams + stream_index;
657     if (ret < 0)
658         os->keyframe_seek = 0;
659     return ret;
660 }
661
662 static int ogg_probe(AVProbeData *p)
663 {
664     if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
665         return AVPROBE_SCORE_MAX;
666     return 0;
667 }
668
669 AVInputFormat ff_ogg_demuxer = {
670     .name           = "ogg",
671     .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
672     .priv_data_size = sizeof(struct ogg),
673     .read_probe     = ogg_probe,
674     .read_header    = ogg_read_header,
675     .read_packet    = ogg_read_packet,
676     .read_close     = ogg_read_close,
677     .read_seek      = ogg_read_seek,
678     .read_timestamp = ogg_read_timestamp,
679     .extensions     = "ogg",
680     .flags          = AVFMT_GENERIC_INDEX,
681 };