oggdec: Parse skeleton to determine the start time of each stream
[ffmpeg.git] / 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
33 #include <stdio.h>
34 #include "oggdec.h"
35 #include "avformat.h"
36
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
39
40 static const struct ogg_codec * const ogg_codecs[] = {
41     &ff_skeleton_codec,
42     &ff_dirac_codec,
43     &ff_speex_codec,
44     &ff_vorbis_codec,
45     &ff_theora_codec,
46     &ff_flac_codec,
47     &ff_old_dirac_codec,
48     &ff_old_flac_codec,
49     &ff_ogm_video_codec,
50     &ff_ogm_audio_codec,
51     &ff_ogm_text_codec,
52     &ff_ogm_old_codec,
53     NULL
54 };
55
56 //FIXME We could avoid some structure duplication
57 static int
58 ogg_save (AVFormatContext * s)
59 {
60     struct ogg *ogg = s->priv_data;
61     struct ogg_state *ost =
62         av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
63     int i;
64     ost->pos = url_ftell (s->pb);
65     ost->curidx = ogg->curidx;
66     ost->next = ogg->state;
67     ost->nstreams = ogg->nstreams;
68     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
69
70     for (i = 0; i < ogg->nstreams; i++){
71         struct ogg_stream *os = ogg->streams + i;
72         os->buf = av_malloc (os->bufsize);
73         memset (os->buf, 0, os->bufsize);
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
83 ogg_restore (AVFormatContext * s, int discard)
84 {
85     struct ogg *ogg = s->priv_data;
86     ByteIOContext *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         for (i = 0; i < ogg->nstreams; i++)
97             av_free (ogg->streams[i].buf);
98
99         url_fseek (bc, ost->pos, SEEK_SET);
100         ogg->curidx = ost->curidx;
101         ogg->nstreams = ost->nstreams;
102         memcpy(ogg->streams, ost->streams,
103                ost->nstreams * sizeof(*ogg->streams));
104     }
105
106     av_free (ost);
107
108     return 0;
109 }
110
111 static int
112 ogg_reset (struct ogg * ogg)
113 {
114     int i;
115
116     for (i = 0; i < ogg->nstreams; i++){
117         struct ogg_stream *os = ogg->streams + i;
118         os->bufpos = 0;
119         os->pstart = 0;
120         os->psize = 0;
121         os->granule = -1;
122         os->lastpts = AV_NOPTS_VALUE;
123         os->lastdts = AV_NOPTS_VALUE;
124         os->sync_pos = -1;
125         os->page_pos = 0;
126         os->nsegs = 0;
127         os->segp = 0;
128         os->incomplete = 0;
129     }
130
131     ogg->curidx = -1;
132
133     return 0;
134 }
135
136 static const struct ogg_codec *
137 ogg_find_codec (uint8_t * buf, int size)
138 {
139     int i;
140
141     for (i = 0; ogg_codecs[i]; i++)
142         if (size >= ogg_codecs[i]->magicsize &&
143             !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
144             return ogg_codecs[i];
145
146     return NULL;
147 }
148
149 static int
150 ogg_new_stream (AVFormatContext * s, uint32_t serial)
151 {
152
153     struct ogg *ogg = s->priv_data;
154     int idx = ogg->nstreams++;
155     AVStream *st;
156     struct ogg_stream *os;
157
158     ogg->streams = av_realloc (ogg->streams,
159                                ogg->nstreams * sizeof (*ogg->streams));
160     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
161     os = ogg->streams + idx;
162     os->serial = serial;
163     os->bufsize = DECODER_BUFFER_SIZE;
164     os->buf = av_malloc(os->bufsize);
165     os->header = -1;
166
167     st = av_new_stream (s, idx);
168     if (!st)
169         return AVERROR(ENOMEM);
170
171     av_set_pts_info(st, 64, 1, 1000000);
172
173     return idx;
174 }
175
176 static int
177 ogg_new_buf(struct ogg *ogg, int idx)
178 {
179     struct ogg_stream *os = ogg->streams + idx;
180     uint8_t *nb = av_malloc(os->bufsize);
181     int size = os->bufpos - os->pstart;
182     if(os->buf){
183         memcpy(nb, os->buf + os->pstart, size);
184         av_free(os->buf);
185     }
186     os->buf = nb;
187     os->bufpos = size;
188     os->pstart = 0;
189
190     return 0;
191 }
192
193 static int
194 ogg_read_page (AVFormatContext * s, int *str)
195 {
196     ByteIOContext *bc = s->pb;
197     struct ogg *ogg = s->priv_data;
198     struct ogg_stream *os;
199     int i = 0;
200     int flags, nsegs;
201     uint64_t gp;
202     uint32_t serial;
203     uint32_t seq;
204     uint32_t crc;
205     int size, idx;
206     uint8_t sync[4];
207     int sp = 0;
208
209     if (get_buffer (bc, sync, 4) < 4)
210         return -1;
211
212     do{
213         int c;
214
215         if (sync[sp & 3] == 'O' &&
216             sync[(sp + 1) & 3] == 'g' &&
217             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
218             break;
219
220         c = url_fgetc (bc);
221         if (c < 0)
222             return -1;
223         sync[sp++ & 3] = c;
224     }while (i++ < MAX_PAGE_SIZE);
225
226     if (i >= MAX_PAGE_SIZE){
227         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
228         return -1;
229     }
230
231     if (url_fgetc (bc) != 0)      /* version */
232         return -1;
233
234     flags = url_fgetc (bc);
235     gp = get_le64 (bc);
236     serial = get_le32 (bc);
237     seq = get_le32 (bc);
238     crc = get_le32 (bc);
239     nsegs = url_fgetc (bc);
240
241     idx = ogg_find_stream (ogg, serial);
242     if (idx < 0){
243         idx = ogg_new_stream (s, serial);
244         if (idx < 0)
245             return -1;
246     }
247
248     os = ogg->streams + idx;
249     os->page_pos = url_ftell(bc) - 27;
250
251     if(os->psize > 0)
252         ogg_new_buf(ogg, idx);
253
254     if (get_buffer (bc, os->segments, nsegs) < nsegs)
255         return -1;
256
257     os->nsegs = nsegs;
258     os->segp = 0;
259
260     size = 0;
261     for (i = 0; i < nsegs; i++)
262         size += os->segments[i];
263
264     if (flags & OGG_FLAG_CONT || os->incomplete){
265         if (!os->psize){
266             while (os->segp < os->nsegs){
267                 int seg = os->segments[os->segp++];
268                 os->pstart += seg;
269                 if (seg < 255)
270                     break;
271             }
272             os->sync_pos = os->page_pos;
273         }
274     }else{
275         os->psize = 0;
276         os->sync_pos = os->page_pos;
277     }
278
279     if (os->bufsize - os->bufpos < size){
280         uint8_t *nb = av_malloc (os->bufsize *= 2);
281         memcpy (nb, os->buf, os->bufpos);
282         av_free (os->buf);
283         os->buf = nb;
284     }
285
286     if (get_buffer (bc, os->buf + os->bufpos, size) < size)
287         return -1;
288
289     os->bufpos += size;
290     os->granule = gp;
291     os->flags = flags;
292
293     if (str)
294         *str = idx;
295
296     return 0;
297 }
298
299 static int
300 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
301 {
302     struct ogg *ogg = s->priv_data;
303     int idx, i;
304     struct ogg_stream *os;
305     int complete = 0;
306     int segp = 0, psize = 0;
307
308 #if 0
309     av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
310 #endif
311
312     do{
313         idx = ogg->curidx;
314
315         while (idx < 0){
316             if (ogg_read_page (s, &idx) < 0)
317                 return -1;
318         }
319
320         os = ogg->streams + idx;
321
322 #if 0
323         av_log (s, AV_LOG_DEBUG,
324                 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
325                 idx, os->pstart, os->psize, os->segp, os->nsegs);
326 #endif
327
328         if (!os->codec){
329             if (os->header < 0){
330                 os->codec = ogg_find_codec (os->buf, os->bufpos);
331                 if (!os->codec){
332                     os->header = 0;
333                     return 0;
334                 }
335             }else{
336                 return 0;
337             }
338         }
339
340         segp = os->segp;
341         psize = os->psize;
342
343         while (os->segp < os->nsegs){
344             int ss = os->segments[os->segp++];
345             os->psize += ss;
346             if (ss < 255){
347                 complete = 1;
348                 break;
349             }
350         }
351
352         if (!complete && os->segp == os->nsegs){
353             ogg->curidx = -1;
354             os->incomplete = 1;
355         }
356     }while (!complete);
357
358 #if 0
359     av_log (s, AV_LOG_DEBUG,
360             "ogg_packet: idx %i, frame size %i, start %i\n",
361             idx, os->psize, os->pstart);
362 #endif
363
364     ogg->curidx = idx;
365     os->incomplete = 0;
366
367     if (!ogg->headers){
368         int hdr = os->codec->header (s, idx);
369         os->header = os->seq;
370         if (!hdr){
371             os->segp = segp;
372             os->psize = psize;
373             ogg->headers = 1;
374             s->data_offset = os->sync_pos;
375         }else{
376             os->pstart += os->psize;
377             os->psize = 0;
378         }
379     }
380
381     if (os->header > -1 && os->seq > os->header){
382         os->pflags = 0;
383         os->pduration = 0;
384         if (os->codec && os->codec->packet)
385             os->codec->packet (s, idx);
386         if (str)
387             *str = idx;
388         if (dstart)
389             *dstart = os->pstart;
390         if (dsize)
391             *dsize = os->psize;
392         if (fpos)
393             *fpos = os->sync_pos;
394         os->pstart += os->psize;
395         os->psize = 0;
396         os->sync_pos = os->page_pos;
397     }
398
399     // determine whether there are more complete packets in this page
400     // if not, the page's granule will apply to this packet
401     os->page_end = 1;
402     for (i = os->segp; i < os->nsegs; i++)
403         if (os->segments[i] < 255) {
404             os->page_end = 0;
405             break;
406         }
407
408     os->seq++;
409     if (os->segp == os->nsegs)
410         ogg->curidx = -1;
411
412     return 0;
413 }
414
415 static int
416 ogg_get_headers (AVFormatContext * s)
417 {
418     struct ogg *ogg = s->priv_data;
419
420     do{
421         if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
422             return -1;
423     }while (!ogg->headers);
424
425 #if 0
426     av_log (s, AV_LOG_DEBUG, "found headers\n");
427 #endif
428
429     return 0;
430 }
431
432 static int
433 ogg_get_length (AVFormatContext * s)
434 {
435     struct ogg *ogg = s->priv_data;
436     int idx = -1, i;
437     int64_t size, end;
438
439     if(url_is_streamed(s->pb))
440         return 0;
441
442 // already set
443     if (s->duration != AV_NOPTS_VALUE)
444         return 0;
445
446     size = url_fsize(s->pb);
447     if(size < 0)
448         return 0;
449     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
450
451     ogg_save (s);
452     url_fseek (s->pb, end, SEEK_SET);
453
454     while (!ogg_read_page (s, &i)){
455         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
456             ogg->streams[i].codec)
457             idx = i;
458     }
459
460     if (idx != -1){
461         s->streams[idx]->duration =
462             ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
463     }
464
465     ogg->size = size;
466     ogg_restore (s, 0);
467
468     return 0;
469 }
470
471
472 static int
473 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
474 {
475     struct ogg *ogg = s->priv_data;
476     int i;
477     ogg->curidx = -1;
478     //linear headers seek from start
479     if (ogg_get_headers (s) < 0){
480         return -1;
481     }
482
483     for (i = 0; i < ogg->nstreams; i++)
484         if (ogg->streams[i].header < 0)
485             ogg->streams[i].codec = NULL;
486
487     //linear granulepos seek from end
488     ogg_get_length (s);
489
490     //fill the extradata in the per codec callbacks
491     return 0;
492 }
493
494
495 static int
496 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
497 {
498     struct ogg *ogg;
499     struct ogg_stream *os;
500     int idx = -1;
501     int pstart, psize;
502     int64_t fpos;
503
504     //Get an ogg packet
505     do{
506         if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
507             return AVERROR(EIO);
508     }while (idx < 0 || !s->streams[idx]);
509
510     ogg = s->priv_data;
511     os = ogg->streams + idx;
512
513     //Alloc a pkt
514     if (av_new_packet (pkt, psize) < 0)
515         return AVERROR(EIO);
516     pkt->stream_index = idx;
517     memcpy (pkt->data, os->buf + pstart, psize);
518
519     if (os->lastpts != AV_NOPTS_VALUE) {
520         pkt->pts = os->lastpts;
521         os->lastpts = AV_NOPTS_VALUE;
522     }
523     if (os->lastdts != AV_NOPTS_VALUE) {
524         pkt->dts = os->lastdts;
525         os->lastdts = AV_NOPTS_VALUE;
526     }
527     if (os->page_end) {
528         if (os->granule != -1LL) {
529             if (os->codec && os->codec->granule_is_start)
530                 pkt->pts    = ogg_gptopts(s, idx, os->granule, &pkt->dts);
531             else
532                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
533             os->granule = -1LL;
534         } else
535             av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
536     }
537
538     pkt->flags = os->pflags;
539     pkt->duration = os->pduration;
540     pkt->pos = fpos;
541
542     return psize;
543 }
544
545
546 static int
547 ogg_read_close (AVFormatContext * s)
548 {
549     struct ogg *ogg = s->priv_data;
550     int i;
551
552     for (i = 0; i < ogg->nstreams; i++){
553         av_free (ogg->streams[i].buf);
554         av_free (ogg->streams[i].private);
555     }
556     av_free (ogg->streams);
557     return 0;
558 }
559
560
561 static int64_t
562 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
563                     int64_t pos_limit)
564 {
565     struct ogg *ogg = s->priv_data;
566     ByteIOContext *bc = s->pb;
567     int64_t pts = AV_NOPTS_VALUE;
568     int i;
569     url_fseek(bc, *pos_arg, SEEK_SET);
570     while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
571         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
572             ogg->streams[i].codec && i == stream_index) {
573             pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
574             // FIXME: this is the position of the packet after the one with above
575             // pts.
576             *pos_arg = url_ftell(bc);
577             break;
578         }
579     }
580     ogg_reset(ogg);
581     return pts;
582 }
583
584 static int ogg_probe(AVProbeData *p)
585 {
586     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
587         p->buf[2] == 'g' && p->buf[3] == 'S' &&
588         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
589         return AVPROBE_SCORE_MAX;
590     else
591         return 0;
592 }
593
594 AVInputFormat ogg_demuxer = {
595     "ogg",
596     NULL_IF_CONFIG_SMALL("Ogg"),
597     sizeof (struct ogg),
598     ogg_probe,
599     ogg_read_header,
600     ogg_read_packet,
601     ogg_read_close,
602     NULL,
603     ogg_read_timestamp,
604     .extensions = "ogg",
605     .metadata_conv = ff_vorbiscomment_metadata_conv,
606 };