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