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