]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavformat/oggdec.c
If custom sampling rate is set in WavPack file, parse first block to find
[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 const struct ogg_codec * const ogg_codecs[] = {
41     &ff_speex_codec,
42     &ff_vorbis_codec,
43     &ff_theora_codec,
44     &ff_flac_codec,
45     &ff_old_flac_codec,
46     &ff_ogm_video_codec,
47     &ff_ogm_audio_codec,
48     &ff_ogm_text_codec,
49     &ff_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     struct ogg *ogg = s->priv_data;
58     struct ogg_state *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         struct ogg_stream *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     struct ogg *ogg = s->priv_data;
83     ByteIOContext *bc = s->pb;
84     struct ogg_state *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 (struct ogg * ogg)
110 {
111     int i;
112
113     for (i = 0; i < ogg->nstreams; i++){
114         struct ogg_stream *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 const struct ogg_codec *
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 (struct ogg * 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     struct ogg *ogg = s->priv_data;
159     int idx = ogg->nstreams++;
160     AVStream *st;
161     struct ogg_stream *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(struct ogg *ogg, int idx)
183 {
184     struct ogg_stream *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     struct ogg *ogg = s->priv_data;
203     struct ogg_stream *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     struct ogg *ogg = s->priv_data;
306     int idx;
307     struct ogg_stream *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         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         os->pstart += os->psize;
393         os->psize = 0;
394     }
395
396     os->seq++;
397     if (os->segp == os->nsegs)
398         ogg->curidx = -1;
399
400     return 0;
401 }
402
403 static int
404 ogg_get_headers (AVFormatContext * s)
405 {
406     struct ogg *ogg = s->priv_data;
407
408     do{
409         if (ogg_packet (s, NULL, NULL, NULL) < 0)
410             return -1;
411     }while (!ogg->headers);
412
413 #if 0
414     av_log (s, AV_LOG_DEBUG, "found headers\n");
415 #endif
416
417     return 0;
418 }
419
420 static uint64_t
421 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
422 {
423     struct ogg *ogg = s->priv_data;
424     struct ogg_stream *os = ogg->streams + i;
425     uint64_t pts = AV_NOPTS_VALUE;
426
427     if(os->codec->gptopts){
428         pts = os->codec->gptopts(s, i, gp);
429     } else {
430         pts = gp;
431     }
432
433     return pts;
434 }
435
436
437 static int
438 ogg_get_length (AVFormatContext * s)
439 {
440     struct ogg *ogg = s->priv_data;
441     int idx = -1, i;
442     int64_t size, end;
443
444     if(url_is_streamed(s->pb))
445         return 0;
446
447 // already set
448     if (s->duration != AV_NOPTS_VALUE)
449         return 0;
450
451     size = url_fsize(s->pb);
452     if(size < 0)
453         return 0;
454     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
455
456     ogg_save (s);
457     url_fseek (s->pb, end, SEEK_SET);
458
459     while (!ogg_read_page (s, &i)){
460         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
461             ogg->streams[i].codec)
462             idx = i;
463     }
464
465     if (idx != -1){
466         s->streams[idx]->duration =
467             ogg_gptopts (s, idx, ogg->streams[idx].granule);
468     }
469
470     ogg->size = size;
471     ogg_restore (s, 0);
472
473     return 0;
474 }
475
476
477 static int
478 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
479 {
480     struct ogg *ogg = s->priv_data;
481     int i;
482     ogg->curidx = -1;
483     //linear headers seek from start
484     if (ogg_get_headers (s) < 0){
485         return -1;
486     }
487
488     for (i = 0; i < ogg->nstreams; i++)
489         if (ogg->streams[i].header < 0)
490             ogg->streams[i].codec = NULL;
491
492     //linear granulepos seek from end
493     ogg_get_length (s);
494
495     //fill the extradata in the per codec callbacks
496     return 0;
497 }
498
499
500 static int
501 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
502 {
503     struct ogg *ogg;
504     struct ogg_stream *os;
505     int idx = -1;
506     int pstart, psize;
507
508     //Get an ogg packet
509     do{
510         if (ogg_packet (s, &idx, &pstart, &psize) < 0)
511             return AVERROR(EIO);
512     }while (idx < 0 || !s->streams[idx]);
513
514     ogg = s->priv_data;
515     os = ogg->streams + idx;
516
517     //Alloc a pkt
518     if (av_new_packet (pkt, psize) < 0)
519         return AVERROR(EIO);
520     pkt->stream_index = idx;
521     memcpy (pkt->data, os->buf + pstart, psize);
522     if (os->lastgp != -1LL){
523         pkt->pts = ogg_gptopts (s, idx, os->lastgp);
524         os->lastgp = -1;
525     }
526
527     pkt->flags = os->pflags;
528     pkt->duration = os->pduration;
529
530     return psize;
531 }
532
533
534 static int
535 ogg_read_close (AVFormatContext * s)
536 {
537     struct ogg *ogg = s->priv_data;
538     int i;
539
540     for (i = 0; i < ogg->nstreams; i++){
541         av_free (ogg->streams[i].buf);
542         av_free (ogg->streams[i].private);
543     }
544     av_free (ogg->streams);
545     return 0;
546 }
547
548
549 static int64_t
550 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
551                     int64_t pos_limit)
552 {
553     struct ogg *ogg = s->priv_data;
554     ByteIOContext *bc = s->pb;
555     int64_t pts = AV_NOPTS_VALUE;
556     int i;
557     url_fseek(bc, *pos_arg, SEEK_SET);
558     while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
559         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
560             ogg->streams[i].codec && i == stream_index) {
561             pts = ogg_gptopts(s, i, ogg->streams[i].granule);
562             // FIXME: this is the position of the packet after the one with above
563             // pts.
564             *pos_arg = url_ftell(bc);
565             break;
566         }
567     }
568     ogg_reset(ogg);
569     return pts;
570 }
571
572 static int ogg_probe(AVProbeData *p)
573 {
574     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
575         p->buf[2] == 'g' && p->buf[3] == 'S' &&
576         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
577         return AVPROBE_SCORE_MAX;
578     else
579         return 0;
580 }
581
582 AVInputFormat ogg_demuxer = {
583     "ogg",
584     NULL_IF_CONFIG_SMALL("Ogg"),
585     sizeof (struct ogg),
586     ogg_probe,
587     ogg_read_header,
588     ogg_read_packet,
589     ogg_read_close,
590     NULL,
591     ogg_read_timestamp,
592     .extensions = "ogg",
593     .metadata_conv = ff_vorbiscomment_metadata_conv,
594 };