changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext...
[libav.git] / libavformat / ogg2.c
CommitLineData
9146ca37
MR
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
40static ogg_codec_t *ogg_codecs[] = {
41 &vorbis_codec,
1ed923ea 42 &theora_codec,
bcfc40ae 43 &flac_codec,
9146ca37
MR
44 NULL
45};
46
47#if 0 // CONFIG_ENCODERS
48static int
49ogg_write_header (AVFormatContext * avfcontext)
50{
51}
52
53static int
54ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
55{
56}
57
58
59static int
60ogg_write_trailer (AVFormatContext * avfcontext)
61{
62}
63
64
65static 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_ENCODERS
78
79//FIXME We could avoid some structure duplication
80static int
81ogg_save (AVFormatContext * s)
82{
83 ogg_t *ogg = s->priv_data;
84 ogg_state_t *ost =
ad3aa874 85 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
9146ca37
MR
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
104static int
105ogg_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
132static int
133ogg_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
153static ogg_codec_t *
2d2f443d 154ogg_find_codec (uint8_t * buf, int size)
9146ca37
MR
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
166static int
167ogg_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
178static int
179ogg_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
207static int
208ogg_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){
2d2f443d 288 uint8_t *nb = av_malloc (os->bufsize *= 2);
9146ca37
MR
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
309static int
310ogg_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){
2d2f443d 363 uint8_t *nb = av_malloc (os->bufsize);
9146ca37
MR
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
410static int
411ogg_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
427static uint64_t
428ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
429{
1ed923ea
MR
430 ogg_t *ogg = s->priv_data;
431 ogg_stream_t *os = ogg->streams + i;
9146ca37 432 AVStream *st = s->streams[i];
01f4895c 433 AVCodecContext *codec = st->codec;
9146ca37
MR
434 uint64_t pts = AV_NOPTS_VALUE;
435
1ed923ea
MR
436 if(os->codec->gptopts){
437 pts = os->codec->gptopts(s, i, gp);
438 } else if (codec->codec_type == CODEC_TYPE_AUDIO){
9146ca37
MR
439 pts = gp * 1000000LL / codec->sample_rate;
440 }else if (codec->codec_type == CODEC_TYPE_VIDEO){
1ed923ea 441 pts = gp;
9146ca37
MR
442 }
443
444 return pts;
445}
446
447
448static int
449ogg_get_length (AVFormatContext * s)
450{
451 ogg_t *ogg = s->priv_data;
9146ca37 452 int idx = -1, i;
69599eea
MR
453
454 if(s->pb.is_streamed)
455 return 0;
9146ca37
MR
456
457// already set
458 if (s->duration != AV_NOPTS_VALUE)
459 return 0;
460
461 ogg_save (s);
a965c478 462 url_fseek (&s->pb, -MAX_PAGE_SIZE, SEEK_END);
9146ca37
MR
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
a965c478 474 ogg->size = url_fsize(&s->pb);
9146ca37
MR
475 ogg_restore (s, 0);
476
477 return 0;
478}
479
480
481static int
482ogg_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
499static int
500ogg_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
531static int
532ogg_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);
1ed923ea 539 av_free (ogg->streams[i].private);
01f4895c 540 av_freep (&s->streams[i]->codec->extradata);
9146ca37
MR
541 }
542 av_free (ogg->streams);
543 return 0;
544}
545
546
547static int
548ogg_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){
17929c04 560 uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
9146ca37
MR
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
610static int64_t
611ogg_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
625static 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
638int
639ogg_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}