]> git.sesse.net Git - ffmpeg/blob - libavformat/ogg2.c
give AVInput/OutputFormat structs consistent names
[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 static 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     st->start_time = 0;
205
206     return idx;
207 }
208
209 static int
210 ogg_new_buf(ogg_t *ogg, int idx)
211 {
212     ogg_stream_t *os = ogg->streams + idx;
213     uint8_t *nb = av_malloc(os->bufsize);
214     int size = os->bufpos - os->pstart;
215     if(os->buf){
216         memcpy(nb, os->buf + os->pstart, size);
217         av_free(os->buf);
218     }
219     os->buf = nb;
220     os->bufpos = size;
221     os->pstart = 0;
222
223     return 0;
224 }
225
226 static int
227 ogg_read_page (AVFormatContext * s, int *str)
228 {
229     ByteIOContext *bc = &s->pb;
230     ogg_t *ogg = s->priv_data;
231     ogg_stream_t *os;
232     int i = 0;
233     int flags, nsegs;
234     uint64_t gp;
235     uint32_t serial;
236     uint32_t seq;
237     uint32_t crc;
238     int size, idx;
239     char sync[4];
240     int sp = 0;
241
242     if (get_buffer (bc, sync, 4) < 4)
243         return -1;
244
245     do{
246         int c;
247
248         if (sync[sp & 3] == 'O' &&
249             sync[(sp + 1) & 3] == 'g' &&
250             sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
251             break;
252
253         c = url_fgetc (bc);
254         if (c < 0)
255             return -1;
256         sync[sp++ & 3] = c;
257     }while (i++ < MAX_PAGE_SIZE);
258
259     if (i >= MAX_PAGE_SIZE){
260         av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
261         return -1;
262     }
263
264     if (url_fgetc (bc) != 0)      /* version */
265         return -1;
266
267     flags = url_fgetc (bc);
268     gp = get_le64 (bc);
269     serial = get_le32 (bc);
270     seq = get_le32 (bc);
271     crc = get_le32 (bc);
272     nsegs = url_fgetc (bc);
273
274     idx = ogg_find_stream (ogg, serial);
275     if (idx < 0){
276         idx = ogg_new_stream (s, serial);
277         if (idx < 0)
278             return -1;
279     }
280
281     os = ogg->streams + idx;
282
283     if(os->psize > 0)
284         ogg_new_buf(ogg, idx);
285
286     if (get_buffer (bc, os->segments, nsegs) < nsegs)
287         return -1;
288
289     os->nsegs = nsegs;
290     os->segp = 0;
291
292     size = 0;
293     for (i = 0; i < nsegs; i++)
294         size += os->segments[i];
295
296     if (flags & OGG_FLAG_CONT){
297         if (!os->psize){
298             while (os->segp < os->nsegs){
299                 int seg = os->segments[os->segp++];
300                 os->pstart += seg;
301                 if (seg < 255)
302                   break;
303             }
304         }
305     }else{
306       os->psize = 0;
307     }
308
309     if (os->bufsize - os->bufpos < size){
310         uint8_t *nb = av_malloc (os->bufsize *= 2);
311         memset (nb, 0, os->bufsize);
312         memcpy (nb, os->buf, os->bufpos);
313         av_free (os->buf);
314         os->buf = nb;
315     }
316
317     if (get_buffer (bc, os->buf + os->bufpos, size) < size)
318         return -1;
319
320     os->lastgp = os->granule;
321     os->bufpos += size;
322     os->granule = gp;
323     os->flags = flags;
324
325     if (str)
326         *str = idx;
327
328     return 0;
329 }
330
331 static int
332 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
333 {
334     ogg_t *ogg = s->priv_data;
335     int idx;
336     ogg_stream_t *os;
337     int complete = 0;
338     int segp = 0, psize = 0;
339
340 #if 0
341     av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
342 #endif
343
344     do{
345         idx = ogg->curidx;
346
347         while (idx < 0){
348             if (ogg_read_page (s, &idx) < 0)
349                 return -1;
350         }
351
352         os = ogg->streams + idx;
353
354 #if 0
355         av_log (s, AV_LOG_DEBUG,
356                 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
357                 idx, os->pstart, os->psize, os->segp, os->nsegs);
358 #endif
359
360         if (!os->codec){
361             if (os->header < 0){
362                 os->codec = ogg_find_codec (os->buf, os->bufpos);
363                 if (!os->codec){
364                     os->header = 0;
365                     return 0;
366                 }
367             }else{
368                 return 0;
369             }
370         }
371
372         segp = os->segp;
373         psize = os->psize;
374
375         while (os->segp < os->nsegs){
376             int ss = os->segments[os->segp++];
377             os->psize += ss;
378             if (ss < 255){
379                 complete = 1;
380                 break;
381             }
382         }
383
384         if (!complete && os->segp == os->nsegs){
385             ogg->curidx = -1;
386         }
387     }while (!complete);
388
389 #if 0
390     av_log (s, AV_LOG_DEBUG,
391             "ogg_packet: idx %i, frame size %i, start %i\n",
392             idx, os->psize, os->pstart);
393 #endif
394
395     ogg->curidx = idx;
396
397     if (os->header < 0){
398         int hdr = os->codec->header (s, idx);
399         if (!hdr){
400           os->header = os->seq;
401           os->segp = segp;
402           os->psize = psize;
403           ogg->headers = 1;
404         }else{
405           os->pstart += os->psize;
406           os->psize = 0;
407         }
408     }
409
410     if (os->header > -1 && os->seq > os->header){
411         if (os->codec && os->codec->packet)
412             os->codec->packet (s, idx);
413         if (str)
414             *str = idx;
415         if (dstart)
416             *dstart = os->pstart;
417         if (dsize)
418             *dsize = os->psize;
419         os->pstart += os->psize;
420         os->psize = 0;
421     }
422
423     os->seq++;
424     if (os->segp == os->nsegs)
425         ogg->curidx = -1;
426
427     return 0;
428 }
429
430 static int
431 ogg_get_headers (AVFormatContext * s)
432 {
433     ogg_t *ogg = s->priv_data;
434
435     do{
436         if (ogg_packet (s, NULL, NULL, NULL) < 0)
437             return -1;
438     }while (!ogg->headers);
439
440 #if 0
441     av_log (s, AV_LOG_DEBUG, "found headers\n");
442 #endif
443
444     return 0;
445 }
446
447 static uint64_t
448 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
449 {
450     ogg_t *ogg = s->priv_data;
451     ogg_stream_t *os = ogg->streams + i;
452     uint64_t pts = AV_NOPTS_VALUE;
453
454     if(os->codec->gptopts){
455         pts = os->codec->gptopts(s, i, gp);
456     } else {
457         pts = gp;
458     }
459
460     return pts;
461 }
462
463
464 static int
465 ogg_get_length (AVFormatContext * s)
466 {
467     ogg_t *ogg = s->priv_data;
468     int idx = -1, i;
469     offset_t size, end;
470
471     if(s->pb.is_streamed)
472         return 0;
473
474 // already set
475     if (s->duration != AV_NOPTS_VALUE)
476         return 0;
477
478     size = url_fsize(&s->pb);
479     if(size < 0)
480         return 0;
481     end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
482
483     ogg_save (s);
484     url_fseek (&s->pb, end, SEEK_SET);
485
486     while (!ogg_read_page (s, &i)){
487         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
488             idx = i;
489     }
490
491     if (idx != -1){
492         s->streams[idx]->duration =
493             ogg_gptopts (s, idx, ogg->streams[idx].granule);
494     }
495
496     ogg->size = size;
497     ogg_restore (s, 0);
498
499     return 0;
500 }
501
502
503 static int
504 ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
505 {
506     ogg_t *ogg = s->priv_data;
507     ogg->curidx = -1;
508     //linear headers seek from start
509     if (ogg_get_headers (s) < 0){
510       return -1;
511     }
512
513     //linear granulepos seek from end
514     ogg_get_length (s);
515
516     //fill the extradata in the per codec callbacks
517     return 0;
518 }
519
520
521 static int
522 ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
523 {
524     ogg_t *ogg;
525     ogg_stream_t *os;
526     int idx = -1;
527     int pstart, psize;
528
529     //Get an ogg packet
530     do{
531         if (ogg_packet (s, &idx, &pstart, &psize) < 0)
532             return AVERROR_IO;
533     }while (idx < 0 || !s->streams[idx]);
534
535     ogg = s->priv_data;
536     os = ogg->streams + idx;
537
538     //Alloc a pkt
539     if (av_new_packet (pkt, psize) < 0)
540         return AVERROR_IO;
541     pkt->stream_index = idx;
542     memcpy (pkt->data, os->buf + pstart, psize);
543     if (os->lastgp != -1LL){
544         pkt->pts = ogg_gptopts (s, idx, os->lastgp);
545         os->lastgp = -1;
546     }
547
548     return psize;
549 }
550
551
552 static int
553 ogg_read_close (AVFormatContext * s)
554 {
555     ogg_t *ogg = s->priv_data;
556     int i;
557
558     for (i = 0; i < ogg->nstreams; i++){
559         av_free (ogg->streams[i].buf);
560         av_free (ogg->streams[i].private);
561     }
562     av_free (ogg->streams);
563     return 0;
564 }
565
566
567 static int
568 ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
569                int flags)
570 {
571     AVStream *st = s->streams[stream_index];
572     ogg_t *ogg = s->priv_data;
573     ByteIOContext *bc = &s->pb;
574     uint64_t min = 0, max = ogg->size;
575     uint64_t tmin = 0, tmax = st->duration;
576     int64_t pts = AV_NOPTS_VALUE;
577
578     ogg_save (s);
579
580     while (min <= max){
581         uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
582         int i = -1;
583
584         url_fseek (bc, p, SEEK_SET);
585
586         while (!ogg_read_page (s, &i)){
587             if (i == stream_index && ogg->streams[i].granule != 0 &&
588                 ogg->streams[i].granule != -1)
589                 break;
590         }
591
592         if (i == -1)
593             break;
594
595         pts = ogg_gptopts (s, i, ogg->streams[i].granule);
596         p = url_ftell (bc);
597
598         if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
599             break;
600
601         if (pts > target_ts){
602             max = p;
603             tmax = pts;
604         }else{
605             min = p;
606             tmin = pts;
607         }
608     }
609
610     if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
611         ogg_restore (s, 1);
612         ogg_reset (ogg);
613     }else{
614         ogg_restore (s, 0);
615         pts = AV_NOPTS_VALUE;
616     }
617
618     return pts;
619
620 #if 0
621     //later...
622     int64_t pos;
623     if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
624         return -1;
625     pos = url_ftell (&s->pb);
626     ogg_read_timestamp (s, stream_index, &pos, pos - 1);
627 #endif
628
629 }
630
631 #if 0
632 static int64_t
633 ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
634                     int64_t pos_limit)
635 {
636     ogg_t *ogg = s->priv_data;
637     ByteIOContext *bc = &s->pb;
638     int64_t pos, pts;
639
640     if (*pos_arg < 0)
641         return AV_NOPTS_VALUE;
642
643     pos = *pos_arg;
644 }
645 #endif
646
647 static int ogg_probe(AVProbeData *p)
648 {
649     if (p->buf_size < 6)
650         return 0;
651     if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
652         p->buf[2] == 'g' && p->buf[3] == 'S' &&
653         p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
654         return AVPROBE_SCORE_MAX;
655     else
656         return 0;
657 }
658
659 static AVInputFormat ogg_demuxer = {
660     "ogg",
661     "Ogg",
662     sizeof (ogg_t),
663     ogg_probe,
664     ogg_read_header,
665     ogg_read_packet,
666     ogg_read_close,
667     ogg_read_seek,
668 // ogg_read_timestamp,
669     .extensions = "ogg",
670 };
671
672 int
673 ogg_init (void)
674 {
675 #if 0 // CONFIG_MUXERS
676     av_register_output_format (&ogg_muxer);
677 #endif
678     av_register_input_format (&ogg_demuxer);
679     return 0;
680 }