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