oggdec: Move ogg_find_stream and ogg_gptopts to oggdec.h
[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_new_stream (AVFormatContext * s, uint32_t serial)
150 {
151
152     struct ogg *ogg = s->priv_data;
153     int idx = ogg->nstreams++;
154     AVStream *st;
155     struct ogg_stream *os;
156
157     ogg->streams = av_realloc (ogg->streams,
158                                ogg->nstreams * sizeof (*ogg->streams));
159     memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
160     os = ogg->streams + idx;
161     os->serial = serial;
162     os->bufsize = DECODER_BUFFER_SIZE;
163     os->buf = av_malloc(os->bufsize);
164     os->header = -1;
165
166     st = av_new_stream (s, idx);
167     if (!st)
168         return AVERROR(ENOMEM);
169
170     av_set_pts_info(st, 64, 1, 1000000);
171
172     return idx;
173 }
174
175 static int
176 ogg_new_buf(struct ogg *ogg, int idx)
177 {
178     struct ogg_stream *os = ogg->streams + idx;
179     uint8_t *nb = av_malloc(os->bufsize);
180     int size = os->bufpos - os->pstart;
181     if(os->buf){
182         memcpy(nb, os->buf + os->pstart, size);
183         av_free(os->buf);
184     }
185     os->buf = nb;
186     os->bufpos = size;
187     os->pstart = 0;
188
189     return 0;
190 }
191
192 static int
193 ogg_read_page (AVFormatContext * s, int *str)
194 {
195     ByteIOContext *bc = s->pb;
196     struct ogg *ogg = s->priv_data;
197     struct ogg_stream *os;
198     int i = 0;
199     int flags, nsegs;
200     uint64_t gp;
201     uint32_t serial;
202     uint32_t seq;
203     uint32_t crc;
204     int size, idx;
205     uint8_t sync[4];
206     int sp = 0;
207
208     if (get_buffer (bc, sync, 4) < 4)
209         return -1;
210
211     do{
212         int c;
213
214         if (sync[sp & 3] == 'O' &&
215             sync[(sp + 1) & 3] == 'g' &&
216             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
217             break;
218
219         c = url_fgetc (bc);
220         if (c < 0)
221             return -1;
222         sync[sp++ & 3] = c;
223     }while (i++ < MAX_PAGE_SIZE);
224
225     if (i >= MAX_PAGE_SIZE){
226         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
227         return -1;
228     }
229
230     if (url_fgetc (bc) != 0)      /* version */
231         return -1;
232
233     flags = url_fgetc (bc);
234     gp = get_le64 (bc);
235     serial = get_le32 (bc);
236     seq = get_le32 (bc);
237     crc = get_le32 (bc);
238     nsegs = url_fgetc (bc);
239
240     idx = ogg_find_stream (ogg, serial);
241     if (idx < 0){
242         idx = ogg_new_stream (s, serial);
243         if (idx < 0)
244             return -1;
245     }
246
247     os = ogg->streams + idx;
248     os->page_pos = url_ftell(bc) - 27;
249
250     if(os->psize > 0)
251         ogg_new_buf(ogg, idx);
252
253     if (get_buffer (bc, os->segments, nsegs) < nsegs)
254         return -1;
255
256     os->nsegs = nsegs;
257     os->segp = 0;
258
259     size = 0;
260     for (i = 0; i < nsegs; i++)
261         size += os->segments[i];
262
263     if (flags & OGG_FLAG_CONT || os->incomplete){
264         if (!os->psize){
265             while (os->segp < os->nsegs){
266                 int seg = os->segments[os->segp++];
267                 os->pstart += seg;
268                 if (seg < 255)
269                     break;
270             }
271             os->sync_pos = os->page_pos;
272         }
273     }else{
274         os->psize = 0;
275         os->sync_pos = os->page_pos;
276     }
277
278     if (os->bufsize - os->bufpos < size){
279         uint8_t *nb = av_malloc (os->bufsize *= 2);
280         memcpy (nb, os->buf, os->bufpos);
281         av_free (os->buf);
282         os->buf = nb;
283     }
284
285     if (get_buffer (bc, os->buf + os->bufpos, size) < size)
286         return -1;
287
288     os->bufpos += size;
289     os->granule = gp;
290     os->flags = flags;
291
292     if (str)
293         *str = idx;
294
295     return 0;
296 }
297
298 static int
299 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
300 {
301     struct ogg *ogg = s->priv_data;
302     int idx, i;
303     struct ogg_stream *os;
304     int complete = 0;
305     int segp = 0, psize = 0;
306
307 #if 0
308     av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
309 #endif
310
311     do{
312         idx = ogg->curidx;
313
314         while (idx < 0){
315             if (ogg_read_page (s, &idx) < 0)
316                 return -1;
317         }
318
319         os = ogg->streams + idx;
320
321 #if 0
322         av_log (s, AV_LOG_DEBUG,
323                 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
324                 idx, os->pstart, os->psize, os->segp, os->nsegs);
325 #endif
326
327         if (!os->codec){
328             if (os->header < 0){
329                 os->codec = ogg_find_codec (os->buf, os->bufpos);
330                 if (!os->codec){
331                     os->header = 0;
332                     return 0;
333                 }
334             }else{
335                 return 0;
336             }
337         }
338
339         segp = os->segp;
340         psize = os->psize;
341
342         while (os->segp < os->nsegs){
343             int ss = os->segments[os->segp++];
344             os->psize += ss;
345             if (ss < 255){
346                 complete = 1;
347                 break;
348             }
349         }
350
351         if (!complete && os->segp == os->nsegs){
352             ogg->curidx = -1;
353             os->incomplete = 1;
354         }
355     }while (!complete);
356
357 #if 0
358     av_log (s, AV_LOG_DEBUG,
359             "ogg_packet: idx %i, frame size %i, start %i\n",
360             idx, os->psize, os->pstart);
361 #endif
362
363     ogg->curidx = idx;
364     os->incomplete = 0;
365
366     if (!ogg->headers){
367         int hdr = os->codec->header (s, idx);
368         os->header = os->seq;
369         if (!hdr){
370             os->segp = segp;
371             os->psize = psize;
372             ogg->headers = 1;
373             s->data_offset = os->sync_pos;
374         }else{
375             os->pstart += os->psize;
376             os->psize = 0;
377         }
378     }
379
380     if (os->header > -1 && os->seq > os->header){
381         os->pflags = 0;
382         os->pduration = 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         if (fpos)
392             *fpos = os->sync_pos;
393         os->pstart += os->psize;
394         os->psize = 0;
395         os->sync_pos = os->page_pos;
396     }
397
398     // determine whether there are more complete packets in this page
399     // if not, the page's granule will apply to this packet
400     os->page_end = 1;
401     for (i = os->segp; i < os->nsegs; i++)
402         if (os->segments[i] < 255) {
403             os->page_end = 0;
404             break;
405         }
406
407     os->seq++;
408     if (os->segp == os->nsegs)
409         ogg->curidx = -1;
410
411     return 0;
412 }
413
414 static int
415 ogg_get_headers (AVFormatContext * s)
416 {
417     struct ogg *ogg = s->priv_data;
418
419     do{
420         if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
421             return -1;
422     }while (!ogg->headers);
423
424 #if 0
425     av_log (s, AV_LOG_DEBUG, "found headers\n");
426 #endif
427
428     return 0;
429 }
430
431 static int
432 ogg_get_length (AVFormatContext * s)
433 {
434     struct ogg *ogg = s->priv_data;
435     int idx = -1, i;
436     int64_t size, end;
437
438     if(url_is_streamed(s->pb))
439         return 0;
440
441 // already set
442     if (s->duration != AV_NOPTS_VALUE)
443         return 0;
444
445     size = url_fsize(s->pb);
446     if(size < 0)
447         return 0;
448     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
449
450     ogg_save (s);
451     url_fseek (s->pb, end, SEEK_SET);
452
453     while (!ogg_read_page (s, &i)){
454         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
455             ogg->streams[i].codec)
456             idx = i;
457     }
458
459     if (idx != -1){
460         s->streams[idx]->duration =
461             ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
462     }
463
464     ogg->size = size;
465     ogg_restore (s, 0);
466
467     return 0;
468 }
469
470
471 static int
472 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
473 {
474     struct ogg *ogg = s->priv_data;
475     int i;
476     ogg->curidx = -1;
477     //linear headers seek from start
478     if (ogg_get_headers (s) < 0){
479         return -1;
480     }
481
482     for (i = 0; i < ogg->nstreams; i++)
483         if (ogg->streams[i].header < 0)
484             ogg->streams[i].codec = NULL;
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     int64_t fpos;
502
503     //Get an ogg packet
504     do{
505         if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
506             return AVERROR(EIO);
507     }while (idx < 0 || !s->streams[idx]);
508
509     ogg = s->priv_data;
510     os = ogg->streams + idx;
511
512     //Alloc a pkt
513     if (av_new_packet (pkt, psize) < 0)
514         return AVERROR(EIO);
515     pkt->stream_index = idx;
516     memcpy (pkt->data, os->buf + pstart, psize);
517
518     if (os->lastpts != AV_NOPTS_VALUE) {
519         pkt->pts = os->lastpts;
520         os->lastpts = AV_NOPTS_VALUE;
521     }
522     if (os->lastdts != AV_NOPTS_VALUE) {
523         pkt->dts = os->lastdts;
524         os->lastdts = AV_NOPTS_VALUE;
525     }
526     if (os->page_end) {
527         if (os->granule != -1LL) {
528             if (os->codec && os->codec->granule_is_start)
529                 pkt->pts    = ogg_gptopts(s, idx, os->granule, &pkt->dts);
530             else
531                 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
532             os->granule = -1LL;
533         } else
534             av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
535     }
536
537     pkt->flags = os->pflags;
538     pkt->duration = os->pduration;
539     pkt->pos = fpos;
540
541     return psize;
542 }
543
544
545 static int
546 ogg_read_close (AVFormatContext * s)
547 {
548     struct ogg *ogg = s->priv_data;
549     int i;
550
551     for (i = 0; i < ogg->nstreams; i++){
552         av_free (ogg->streams[i].buf);
553         av_free (ogg->streams[i].private);
554     }
555     av_free (ogg->streams);
556     return 0;
557 }
558
559
560 static int64_t
561 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
562                     int64_t pos_limit)
563 {
564     struct ogg *ogg = s->priv_data;
565     ByteIOContext *bc = s->pb;
566     int64_t pts = AV_NOPTS_VALUE;
567     int i;
568     url_fseek(bc, *pos_arg, SEEK_SET);
569     while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
570         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
571             ogg->streams[i].codec && i == stream_index) {
572             pts = ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
573             // FIXME: this is the position of the packet after the one with above
574             // pts.
575             *pos_arg = url_ftell(bc);
576             break;
577         }
578     }
579     ogg_reset(ogg);
580     return pts;
581 }
582
583 static int ogg_probe(AVProbeData *p)
584 {
585     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
586         p->buf[2] == 'g' && p->buf[3] == 'S' &&
587         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
588         return AVPROBE_SCORE_MAX;
589     else
590         return 0;
591 }
592
593 AVInputFormat ogg_demuxer = {
594     "ogg",
595     NULL_IF_CONFIG_SMALL("Ogg"),
596     sizeof (struct ogg),
597     ogg_probe,
598     ogg_read_header,
599     ogg_read_packet,
600     ogg_read_close,
601     NULL,
602     ogg_read_timestamp,
603     .extensions = "ogg",
604     .metadata_conv = ff_vorbiscomment_metadata_conv,
605 };