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