support theora in ogg, plus required ogg core changes
[libav.git] / 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 NULL
44 };
45
46 #if 0 // CONFIG_ENCODERS
47 static int
48 ogg_write_header (AVFormatContext * avfcontext)
49 {
50 }
51
52 static int
53 ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
54 {
55 }
56
57
58 static int
59 ogg_write_trailer (AVFormatContext * avfcontext)
60 {
61 }
62
63
64 static AVOutputFormat ogg_oformat = {
65 "ogg",
66 "Ogg Vorbis",
67 "audio/x-vorbis",
68 "ogg",
69 sizeof (OggContext),
70 CODEC_ID_VORBIS,
71 0,
72 ogg_write_header,
73 ogg_write_packet,
74 ogg_write_trailer,
75 };
76 #endif //CONFIG_ENCODERS
77
78 //FIXME We could avoid some structure duplication
79 static int
80 ogg_save (AVFormatContext * s)
81 {
82 ogg_t *ogg = s->priv_data;
83 ogg_state_t *ost =
84 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
85 int i;
86 ost->pos = url_ftell (&s->pb);;
87 ost->curidx = ogg->curidx;
88 ost->next = ogg->state;
89 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
90
91 for (i = 0; i < ogg->nstreams; i++){
92 ogg_stream_t *os = ogg->streams + i;
93 os->buf = av_malloc (os->bufsize);
94 memset (os->buf, 0, os->bufsize);
95 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
96 }
97
98 ogg->state = ost;
99
100 return 0;
101 }
102
103 static int
104 ogg_restore (AVFormatContext * s, int discard)
105 {
106 ogg_t *ogg = s->priv_data;
107 ByteIOContext *bc = &s->pb;
108 ogg_state_t *ost = ogg->state;
109 int i;
110
111 if (!ost)
112 return 0;
113
114 ogg->state = ost->next;
115
116 if (!discard){
117 for (i = 0; i < ogg->nstreams; i++)
118 av_free (ogg->streams[i].buf);
119
120 url_fseek (bc, ost->pos, SEEK_SET);
121 ogg->curidx = ost->curidx;
122 memcpy (ogg->streams, ost->streams,
123 ogg->nstreams * sizeof (*ogg->streams));
124 }
125
126 av_free (ost);
127
128 return 0;
129 }
130
131 static int
132 ogg_reset (ogg_t * ogg)
133 {
134 int i;
135
136 for (i = 0; i < ogg->nstreams; i++){
137 ogg_stream_t *os = ogg->streams + i;
138 os->bufpos = 0;
139 os->pstart = 0;
140 os->psize = 0;
141 os->granule = -1;
142 os->lastgp = -1;
143 os->nsegs = 0;
144 os->segp = 0;
145 }
146
147 ogg->curidx = -1;
148
149 return 0;
150 }
151
152 static ogg_codec_t *
153 ogg_find_codec (uint8_t * buf, int size)
154 {
155 int i;
156
157 for (i = 0; ogg_codecs[i]; i++)
158 if (size >= ogg_codecs[i]->magicsize &&
159 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
160 return ogg_codecs[i];
161
162 return NULL;
163 }
164
165 static int
166 ogg_find_stream (ogg_t * ogg, int serial)
167 {
168 int i;
169
170 for (i = 0; i < ogg->nstreams; i++)
171 if (ogg->streams[i].serial == serial)
172 return i;
173
174 return -1;
175 }
176
177 static int
178 ogg_new_stream (AVFormatContext * s, uint32_t serial)
179 {
180
181 ogg_t *ogg = s->priv_data;
182 int idx = ogg->nstreams++;
183 AVStream *st;
184 ogg_stream_t *os;
185
186 ogg->streams = av_realloc (ogg->streams,
187 ogg->nstreams * sizeof (*ogg->streams));
188 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
189 os = ogg->streams + idx;
190 os->serial = serial;
191 os->bufsize = DECODER_BUFFER_SIZE;
192 os->buf = av_malloc (os->bufsize);
193 memset (os->buf, 0, os->bufsize);
194 os->header = -1;
195
196 st = av_new_stream (s, idx);
197 if (!st)
198 return AVERROR_NOMEM;
199
200 av_set_pts_info(st, 64, 1, 1000000);
201 st->start_time = 0;
202
203 return idx;
204 }
205
206 static int
207 ogg_read_page (AVFormatContext * s, int *str)
208 {
209 ByteIOContext *bc = &s->pb;
210 ogg_t *ogg = s->priv_data;
211 ogg_stream_t *os;
212 int i = 0;
213 int flags, nsegs;
214 uint64_t gp;
215 uint32_t serial;
216 uint32_t seq;
217 uint32_t crc;
218 int size, idx;
219 char sync[4];
220 int sp = 0;
221
222 if (get_buffer (bc, sync, 4) < 4)
223 return -1;
224
225 do{
226 int c;
227
228 if (sync[sp & 3] == 'O' &&
229 sync[(sp + 1) & 3] == 'g' &&
230 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
231 break;
232
233 c = url_fgetc (bc);
234 if (c < 0)
235 return -1;
236 sync[sp++ & 3] = c;
237 }while (i++ < MAX_PAGE_SIZE);
238
239 if (i >= MAX_PAGE_SIZE){
240 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
241 return -1;
242 }
243
244 if (url_fgetc (bc) != 0) /* version */
245 return -1;
246
247 flags = url_fgetc (bc);
248 gp = get_le64 (bc);
249 serial = get_le32 (bc);
250 seq = get_le32 (bc);
251 crc = get_le32 (bc);
252 nsegs = url_fgetc (bc);
253
254 idx = ogg_find_stream (ogg, serial);
255 if (idx < 0){
256 idx = ogg_new_stream (s, serial);
257 if (idx < 0)
258 return -1;
259 }
260
261 os = ogg->streams + idx;
262
263 if (get_buffer (bc, os->segments, nsegs) < nsegs)
264 return -1;
265
266 os->nsegs = nsegs;
267 os->segp = 0;
268
269 size = 0;
270 for (i = 0; i < nsegs; i++)
271 size += os->segments[i];
272
273 if (flags & OGG_FLAG_CONT){
274 if (!os->psize){
275 while (os->segp < os->nsegs){
276 int seg = os->segments[os->segp++];
277 os->pstart += seg;
278 if (seg < 255)
279 break;
280 }
281 }
282 }else{
283 os->psize = 0;
284 }
285
286 if (os->bufsize - os->bufpos < size){
287 uint8_t *nb = av_malloc (os->bufsize *= 2);
288 memset (nb, 0, os->bufsize);
289 memcpy (nb, os->buf, os->bufpos);
290 av_free (os->buf);
291 os->buf = nb;
292 }
293
294 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
295 return -1;
296
297 os->lastgp = os->granule;
298 os->bufpos += size;
299 os->granule = gp;
300 os->flags = flags;
301
302 if (str)
303 *str = idx;
304
305 return 0;
306 }
307
308 static int
309 ogg_packet (AVFormatContext * s, int *str)
310 {
311 ogg_t *ogg = s->priv_data;
312 int idx;
313 ogg_stream_t *os;
314 int complete = 0;
315 int segp = 0, psize = 0;
316
317 #if 0
318 av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
319 #endif
320
321 do{
322 idx = ogg->curidx;
323
324 while (idx < 0){
325 if (ogg_read_page (s, &idx) < 0)
326 return -1;
327 }
328
329 os = ogg->streams + idx;
330
331 #if 0
332 av_log (s, AV_LOG_DEBUG,
333 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
334 idx, os->pstart, os->psize, os->segp, os->nsegs);
335 #endif
336
337 if (!os->codec){
338 if (os->header < 0){
339 os->codec = ogg_find_codec (os->buf, os->bufpos);
340 if (!os->codec){
341 os->header = 0;
342 return 0;
343 }
344 }else{
345 return 0;
346 }
347 }
348
349 segp = os->segp;
350 psize = os->psize;
351
352 while (os->segp < os->nsegs){
353 int ss = os->segments[os->segp++];
354 os->psize += ss;
355 if (ss < 255){
356 complete = 1;
357 break;
358 }
359 }
360
361 if (!complete && os->segp == os->nsegs){
362 uint8_t *nb = av_malloc (os->bufsize);
363 int size = os->bufpos - os->pstart;
364 memset (nb, 0, os->bufsize);
365 memcpy (nb, os->buf + os->pstart, size);
366 av_free (os->buf);
367 os->buf = nb;
368 os->bufpos = size;
369 os->pstart = 0;
370 ogg->curidx = -1;
371 }
372 }while (!complete);
373
374 #if 0
375 av_log (s, AV_LOG_DEBUG,
376 "ogg_packet: idx %i, frame size %i, start %i\n",
377 idx, os->psize, os->pstart);
378 #endif
379
380 ogg->curidx = idx;
381
382 if (os->header < 0){
383 int hdr = os->codec->header (s, idx);
384 if (!hdr){
385 os->header = os->seq;
386 os->segp = segp;
387 os->psize = psize;
388 ogg->headers = 1;
389 }else{
390 os->pstart += os->psize;
391 os->psize = 0;
392 }
393 }
394
395 if (os->header > -1 && os->seq > os->header){
396 if (os->codec && os->codec->packet)
397 os->codec->packet (s, idx);
398 if (str)
399 *str = idx;
400 }
401
402 os->seq++;
403 if (os->segp == os->nsegs)
404 ogg->curidx = -1;
405
406 return 0;
407 }
408
409 static int
410 ogg_get_headers (AVFormatContext * s)
411 {
412 ogg_t *ogg = s->priv_data;
413
414 do{
415 if (ogg_packet (s, NULL) < 0)
416 return -1;
417 }while (!ogg->headers);
418
419 #if 0
420 av_log (s, AV_LOG_DEBUG, "found headers\n");
421 #endif
422
423 return 0;
424 }
425
426 static uint64_t
427 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
428 {
429 ogg_t *ogg = s->priv_data;
430 ogg_stream_t *os = ogg->streams + i;
431 AVStream *st = s->streams[i];
432 AVCodecContext *codec = &st->codec;
433 uint64_t pts = AV_NOPTS_VALUE;
434
435 if(os->codec->gptopts){
436 pts = os->codec->gptopts(s, i, gp);
437 } else if (codec->codec_type == CODEC_TYPE_AUDIO){
438 pts = gp * 1000000LL / codec->sample_rate;
439 }else if (codec->codec_type == CODEC_TYPE_VIDEO){
440 pts = gp;
441 }
442
443 return pts;
444 }
445
446
447 static int
448 ogg_get_length (AVFormatContext * s)
449 {
450 ogg_t *ogg = s->priv_data;
451 URLContext *h = url_fileno (&s->pb);
452 int idx = -1, i;
453 //FIXME: get the right ctx flag to know if is seekable or not
454 // if(ogg->f->flags & URL_FLAG_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_seek (h, -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_filesize(h);
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 AVInputFormat ogg_iformat = {
626 "ogg",
627 "Ogg",
628 sizeof (ogg_t),
629 NULL,
630 ogg_read_header,
631 ogg_read_packet,
632 ogg_read_close,
633 ogg_read_seek,
634 // ogg_read_timestamp,
635 .extensions = "ogg",
636 };
637
638 int
639 ogg_init (void)
640 {
641 #if 0 // CONFIG_ENCODERS
642 av_register_output_format (&ogg_oformat);
643 #endif
644 av_register_input_format (&ogg_iformat);
645 return 0;
646 }