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