comparison oggdec.c @ 2714:b22ba392ac21 libavformat

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