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