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