]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavformat/oggdec.c
OGG demuxer: ensure that there's pages to read for duration calculation in
[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         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     struct ogg *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     struct ogg *ogg = s->priv_data;
423     struct ogg_stream *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     struct ogg *ogg = s->priv_data;
440     int idx = -1, i;
441     int64_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: 0;
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
472     return 0;
473 }
474
475
476 static int
477 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
478 {
479     struct ogg *ogg = s->priv_data;
480     ogg->curidx = -1;
481     //linear headers seek from start
482     if (ogg_get_headers (s) < 0){
483         return -1;
484     }
485
486     //linear granulepos seek from end
487     ogg_get_length (s);
488
489     //fill the extradata in the per codec callbacks
490     return 0;
491 }
492
493
494 static int
495 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
496 {
497     struct ogg *ogg;
498     struct ogg_stream *os;
499     int idx = -1;
500     int pstart, psize;
501
502     //Get an ogg packet
503     do{
504         if (ogg_packet (s, &idx, &pstart, &psize) < 0)
505             return AVERROR(EIO);
506     }while (idx < 0 || !s->streams[idx]);
507
508     ogg = s->priv_data;
509     os = ogg->streams + idx;
510
511     //Alloc a pkt
512     if (av_new_packet (pkt, psize) < 0)
513         return AVERROR(EIO);
514     pkt->stream_index = idx;
515     memcpy (pkt->data, os->buf + pstart, psize);
516     if (os->lastgp != -1LL){
517         pkt->pts = ogg_gptopts (s, idx, os->lastgp);
518         os->lastgp = -1;
519     }
520
521     pkt->flags = os->pflags;
522
523     return psize;
524 }
525
526
527 static int
528 ogg_read_close (AVFormatContext * s)
529 {
530     struct ogg *ogg = s->priv_data;
531     int i;
532
533     for (i = 0; i < ogg->nstreams; i++){
534         av_free (ogg->streams[i].buf);
535         av_free (ogg->streams[i].private);
536     }
537     av_free (ogg->streams);
538     return 0;
539 }
540
541
542 static int64_t
543 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
544                     int64_t pos_limit)
545 {
546     struct ogg *ogg = s->priv_data;
547     ByteIOContext *bc = s->pb;
548     int64_t pts = AV_NOPTS_VALUE;
549     int i;
550     url_fseek(bc, *pos_arg, SEEK_SET);
551     while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
552         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
553             ogg->streams[i].codec && i == stream_index) {
554             pts = ogg_gptopts(s, i, ogg->streams[i].granule);
555             // FIXME: this is the position of the packet after the one with above
556             // pts.
557             *pos_arg = url_ftell(bc);
558             break;
559         }
560     }
561     ogg_reset(ogg);
562     return pts;
563 }
564
565 static int ogg_probe(AVProbeData *p)
566 {
567     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
568         p->buf[2] == 'g' && p->buf[3] == 'S' &&
569         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
570         return AVPROBE_SCORE_MAX;
571     else
572         return 0;
573 }
574
575 AVInputFormat ogg_demuxer = {
576     "ogg",
577     NULL_IF_CONFIG_SMALL("Ogg"),
578     sizeof (struct ogg),
579     ogg_probe,
580     ogg_read_header,
581     ogg_read_packet,
582     ogg_read_close,
583     NULL,
584     ogg_read_timestamp,
585     .extensions = "ogg",
586 };