Partially revert "Simplify code by using av_metadata_set2()."
[libav.git] / libavformat / oggdec.c
CommitLineData
9146ca37
MR
1/*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
115329f1 5 *
9146ca37
MR
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>
a0ddef24 34#include "oggdec.h"
9146ca37 35#include "avformat.h"
66061a12 36#include "vorbiscomment.h"
9146ca37
MR
37
38#define MAX_PAGE_SIZE 65307
39#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40
77be08ee 41static const struct ogg_codec * const ogg_codecs[] = {
32ad8692 42 &ff_skeleton_codec,
24ca518b 43 &ff_dirac_codec,
547ea47d
RD
44 &ff_speex_codec,
45 &ff_vorbis_codec,
46 &ff_theora_codec,
47 &ff_flac_codec,
24ca518b 48 &ff_old_dirac_codec,
547ea47d
RD
49 &ff_old_flac_codec,
50 &ff_ogm_video_codec,
51 &ff_ogm_audio_codec,
52 &ff_ogm_text_codec,
53 &ff_ogm_old_codec,
9146ca37
MR
54 NULL
55};
56
9146ca37
MR
57//FIXME We could avoid some structure duplication
58static int
59ogg_save (AVFormatContext * s)
60{
77be08ee
MR
61 struct ogg *ogg = s->priv_data;
62 struct ogg_state *ost =
ad3aa874 63 av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
9146ca37 64 int i;
899681cd 65 ost->pos = url_ftell (s->pb);
9146ca37
MR
66 ost->curidx = ogg->curidx;
67 ost->next = ogg->state;
20be72c8 68 ost->nstreams = ogg->nstreams;
9146ca37
MR
69 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70
71 for (i = 0; i < ogg->nstreams; i++){
77be08ee 72 struct ogg_stream *os = ogg->streams + i;
9146ca37
MR
73 os->buf = av_malloc (os->bufsize);
74 memset (os->buf, 0, os->bufsize);
75 memcpy (os->buf, ost->streams[i].buf, os->bufpos);
76 }
77
78 ogg->state = ost;
79
80 return 0;
81}
82
83static int
84ogg_restore (AVFormatContext * s, int discard)
85{
77be08ee 86 struct ogg *ogg = s->priv_data;
899681cd 87 ByteIOContext *bc = s->pb;
77be08ee 88 struct ogg_state *ost = ogg->state;
9146ca37
MR
89 int i;
90
91 if (!ost)
92 return 0;
93
94 ogg->state = ost->next;
95
96 if (!discard){
97 for (i = 0; i < ogg->nstreams; i++)
98 av_free (ogg->streams[i].buf);
99
100 url_fseek (bc, ost->pos, SEEK_SET);
101 ogg->curidx = ost->curidx;
20be72c8
MR
102 ogg->nstreams = ost->nstreams;
103 memcpy(ogg->streams, ost->streams,
104 ost->nstreams * sizeof(*ogg->streams));
9146ca37
MR
105 }
106
107 av_free (ost);
108
109 return 0;
110}
111
112static int
77be08ee 113ogg_reset (struct ogg * ogg)
9146ca37
MR
114{
115 int i;
116
117 for (i = 0; i < ogg->nstreams; i++){
77be08ee 118 struct ogg_stream *os = ogg->streams + i;
9146ca37
MR
119 os->bufpos = 0;
120 os->pstart = 0;
121 os->psize = 0;
122 os->granule = -1;
5e15c7d9 123 os->lastpts = AV_NOPTS_VALUE;
2d4970d8 124 os->lastdts = AV_NOPTS_VALUE;
73823cb9
DC
125 os->sync_pos = -1;
126 os->page_pos = 0;
9146ca37
MR
127 os->nsegs = 0;
128 os->segp = 0;
ecc0027b 129 os->incomplete = 0;
9146ca37
MR
130 }
131
132 ogg->curidx = -1;
133
134 return 0;
135}
136
77be08ee 137static const struct ogg_codec *
2d2f443d 138ogg_find_codec (uint8_t * buf, int size)
9146ca37
MR
139{
140 int i;
141
142 for (i = 0; ogg_codecs[i]; i++)
143 if (size >= ogg_codecs[i]->magicsize &&
144 !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
145 return ogg_codecs[i];
146
147 return NULL;
148}
149
150static int
9146ca37
MR
151ogg_new_stream (AVFormatContext * s, uint32_t serial)
152{
153
77be08ee 154 struct ogg *ogg = s->priv_data;
9146ca37
MR
155 int idx = ogg->nstreams++;
156 AVStream *st;
77be08ee 157 struct ogg_stream *os;
9146ca37
MR
158
159 ogg->streams = av_realloc (ogg->streams,
160 ogg->nstreams * sizeof (*ogg->streams));
161 memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
162 os = ogg->streams + idx;
163 os->serial = serial;
164 os->bufsize = DECODER_BUFFER_SIZE;
40c5e1fa 165 os->buf = av_malloc(os->bufsize);
9146ca37
MR
166 os->header = -1;
167
168 st = av_new_stream (s, idx);
169 if (!st)
769e10f0 170 return AVERROR(ENOMEM);
9146ca37
MR
171
172 av_set_pts_info(st, 64, 1, 1000000);
9146ca37
MR
173
174 return idx;
175}
176
177static int
77be08ee 178ogg_new_buf(struct ogg *ogg, int idx)
12a195e3 179{
77be08ee 180 struct ogg_stream *os = ogg->streams + idx;
ea02862a 181 uint8_t *nb = av_malloc(os->bufsize);
12a195e3
MR
182 int size = os->bufpos - os->pstart;
183 if(os->buf){
184 memcpy(nb, os->buf + os->pstart, size);
185 av_free(os->buf);
186 }
187 os->buf = nb;
188 os->bufpos = size;
189 os->pstart = 0;
190
191 return 0;
192}
193
194static int
9146ca37
MR
195ogg_read_page (AVFormatContext * s, int *str)
196{
899681cd 197 ByteIOContext *bc = s->pb;
77be08ee
MR
198 struct ogg *ogg = s->priv_data;
199 struct ogg_stream *os;
9146ca37
MR
200 int i = 0;
201 int flags, nsegs;
202 uint64_t gp;
203 uint32_t serial;
204 uint32_t seq;
205 uint32_t crc;
206 int size, idx;
191e8ca7 207 uint8_t sync[4];
9146ca37
MR
208 int sp = 0;
209
210 if (get_buffer (bc, sync, 4) < 4)
211 return -1;
212
213 do{
214 int c;
215
216 if (sync[sp & 3] == 'O' &&
217 sync[(sp + 1) & 3] == 'g' &&
218 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
219 break;
220
221 c = url_fgetc (bc);
222 if (c < 0)
223 return -1;
224 sync[sp++ & 3] = c;
225 }while (i++ < MAX_PAGE_SIZE);
226
227 if (i >= MAX_PAGE_SIZE){
228 av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
229 return -1;
230 }
231
232 if (url_fgetc (bc) != 0) /* version */
233 return -1;
234
235 flags = url_fgetc (bc);
236 gp = get_le64 (bc);
237 serial = get_le32 (bc);
238 seq = get_le32 (bc);
239 crc = get_le32 (bc);
240 nsegs = url_fgetc (bc);
241
242 idx = ogg_find_stream (ogg, serial);
243 if (idx < 0){
244 idx = ogg_new_stream (s, serial);
245 if (idx < 0)
246 return -1;
247 }
248
249 os = ogg->streams + idx;
73823cb9 250 os->page_pos = url_ftell(bc) - 27;
9146ca37 251
40c5e1fa 252 if(os->psize > 0)
12a195e3
MR
253 ogg_new_buf(ogg, idx);
254
9146ca37
MR
255 if (get_buffer (bc, os->segments, nsegs) < nsegs)
256 return -1;
257
258 os->nsegs = nsegs;
259 os->segp = 0;
260
261 size = 0;
262 for (i = 0; i < nsegs; i++)
263 size += os->segments[i];
264
ecc0027b 265 if (flags & OGG_FLAG_CONT || os->incomplete){
9146ca37
MR
266 if (!os->psize){
267 while (os->segp < os->nsegs){
268 int seg = os->segments[os->segp++];
269 os->pstart += seg;
270 if (seg < 255)
bad4a6bb 271 break;
9146ca37 272 }
73823cb9 273 os->sync_pos = os->page_pos;
9146ca37
MR
274 }
275 }else{
bad4a6bb 276 os->psize = 0;
73823cb9 277 os->sync_pos = os->page_pos;
9146ca37
MR
278 }
279
280 if (os->bufsize - os->bufpos < size){
2d2f443d 281 uint8_t *nb = av_malloc (os->bufsize *= 2);
9146ca37
MR
282 memcpy (nb, os->buf, os->bufpos);
283 av_free (os->buf);
284 os->buf = nb;
285 }
286
287 if (get_buffer (bc, os->buf + os->bufpos, size) < size)
288 return -1;
289
9146ca37
MR
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
300static int
73823cb9 301ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
9146ca37 302{
77be08ee 303 struct ogg *ogg = s->priv_data;
5e15c7d9 304 int idx, i;
77be08ee 305 struct ogg_stream *os;
9146ca37
MR
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){
9146ca37 354 ogg->curidx = -1;
ecc0027b 355 os->incomplete = 1;
9146ca37
MR
356 }
357 }while (!complete);
358
359#if 0
360 av_log (s, AV_LOG_DEBUG,
361 "ogg_packet: idx %i, frame size %i, start %i\n",
362 idx, os->psize, os->pstart);
363#endif
364
adc725b5 365 if (os->granule == -1)
461628c6 366 av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
adc725b5 367
9146ca37 368 ogg->curidx = idx;
ecc0027b 369 os->incomplete = 0;
9146ca37 370
81b743eb
DC
371 if (os->header) {
372 os->header = os->codec->header (s, idx);
373 if (!os->header){
bad4a6bb
PR
374 os->segp = segp;
375 os->psize = psize;
81b743eb
DC
376 if (!ogg->headers)
377 s->data_offset = os->sync_pos;
bad4a6bb 378 ogg->headers = 1;
9146ca37 379 }else{
bad4a6bb
PR
380 os->pstart += os->psize;
381 os->psize = 0;
9146ca37 382 }
81b743eb 383 } else {
e1a794b2 384 os->pflags = 0;
15299b38 385 os->pduration = 0;
9146ca37
MR
386 if (os->codec && os->codec->packet)
387 os->codec->packet (s, idx);
388 if (str)
389 *str = idx;
12a195e3
MR
390 if (dstart)
391 *dstart = os->pstart;
392 if (dsize)
393 *dsize = os->psize;
73823cb9
DC
394 if (fpos)
395 *fpos = os->sync_pos;
12a195e3
MR
396 os->pstart += os->psize;
397 os->psize = 0;
73823cb9 398 os->sync_pos = os->page_pos;
9146ca37
MR
399 }
400
5e15c7d9
DC
401 // determine whether there are more complete packets in this page
402 // if not, the page's granule will apply to this packet
403 os->page_end = 1;
404 for (i = os->segp; i < os->nsegs; i++)
405 if (os->segments[i] < 255) {
406 os->page_end = 0;
407 break;
408 }
409
9146ca37
MR
410 if (os->segp == os->nsegs)
411 ogg->curidx = -1;
412
413 return 0;
414}
415
416static int
417ogg_get_headers (AVFormatContext * s)
418{
77be08ee 419 struct ogg *ogg = s->priv_data;
9146ca37
MR
420
421 do{
73823cb9 422 if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
9146ca37
MR
423 return -1;
424 }while (!ogg->headers);
425
426#if 0
427 av_log (s, AV_LOG_DEBUG, "found headers\n");
428#endif
429
430 return 0;
431}
432
9146ca37
MR
433static int
434ogg_get_length (AVFormatContext * s)
435{
77be08ee 436 struct ogg *ogg = s->priv_data;
44a088ea 437 int i;
bc5c918e 438 int64_t size, end;
69599eea 439
ceeacce6 440 if(url_is_streamed(s->pb))
69599eea 441 return 0;
9146ca37
MR
442
443// already set
444 if (s->duration != AV_NOPTS_VALUE)
445 return 0;
446
899681cd 447 size = url_fsize(s->pb);
56466d7b
MR
448 if(size < 0)
449 return 0;
ddd94932 450 end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
56466d7b 451
9146ca37 452 ogg_save (s);
899681cd 453 url_fseek (s->pb, end, SEEK_SET);
9146ca37
MR
454
455 while (!ogg_read_page (s, &i)){
e22f2aaf 456 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
44a088ea
DC
457 ogg->streams[i].codec) {
458 s->streams[i]->duration =
459 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
460 if (s->streams[i]->start_time != AV_NOPTS_VALUE)
461 s->streams[i]->duration -= s->streams[i]->start_time;
462 }
9146ca37
MR
463 }
464
9146ca37
MR
465 ogg_restore (s, 0);
466
467 return 0;
468}
469
470
471static int
472ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
473{
77be08ee 474 struct ogg *ogg = s->priv_data;
c9da676d 475 int i;
9146ca37
MR
476 ogg->curidx = -1;
477 //linear headers seek from start
478 if (ogg_get_headers (s) < 0){
bad4a6bb 479 return -1;
9146ca37
MR
480 }
481
c9da676d
RD
482 for (i = 0; i < ogg->nstreams; i++)
483 if (ogg->streams[i].header < 0)
484 ogg->streams[i].codec = NULL;
485
9146ca37
MR
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
6abaa272
DC
493static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
494{
495 struct ogg *ogg = s->priv_data;
496 struct ogg_stream *os = ogg->streams + idx;
497 int64_t pts = AV_NOPTS_VALUE;
498
499 if (dts)
500 *dts = AV_NOPTS_VALUE;
501
502 if (os->lastpts != AV_NOPTS_VALUE) {
503 pts = os->lastpts;
504 os->lastpts = AV_NOPTS_VALUE;
505 }
506 if (os->lastdts != AV_NOPTS_VALUE) {
507 if (dts)
508 *dts = os->lastdts;
509 os->lastdts = AV_NOPTS_VALUE;
510 }
511 if (os->page_end) {
512 if (os->granule != -1LL) {
513 if (os->codec && os->codec->granule_is_start)
514 pts = ogg_gptopts(s, idx, os->granule, dts);
515 else
516 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
517 os->granule = -1LL;
adc725b5 518 }
6abaa272
DC
519 }
520 return pts;
521}
9146ca37
MR
522
523static int
524ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
525{
77be08ee
MR
526 struct ogg *ogg;
527 struct ogg_stream *os;
9146ca37 528 int idx = -1;
12a195e3 529 int pstart, psize;
d8b91fae 530 int64_t fpos, pts, dts;
9146ca37 531
115329f1 532 //Get an ogg packet
d8b91fae 533retry:
9146ca37 534 do{
73823cb9 535 if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
6f3e0b21 536 return AVERROR(EIO);
9146ca37
MR
537 }while (idx < 0 || !s->streams[idx]);
538
539 ogg = s->priv_data;
540 os = ogg->streams + idx;
541
d8b91fae
DC
542 // pflags might not be set until after this
543 pts = ogg_calc_pts(s, idx, &dts);
544
cc947f04 545 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
d8b91fae
DC
546 goto retry;
547 os->keyframe_seek = 0;
548
9146ca37 549 //Alloc a pkt
12a195e3 550 if (av_new_packet (pkt, psize) < 0)
6f3e0b21 551 return AVERROR(EIO);
9146ca37 552 pkt->stream_index = idx;
12a195e3 553 memcpy (pkt->data, os->buf + pstart, psize);
5e15c7d9 554
d8b91fae
DC
555 pkt->pts = pts;
556 pkt->dts = dts;
e1a794b2 557 pkt->flags = os->pflags;
15299b38 558 pkt->duration = os->pduration;
73823cb9 559 pkt->pos = fpos;
e1a794b2 560
12a195e3 561 return psize;
9146ca37
MR
562}
563
564
565static int
566ogg_read_close (AVFormatContext * s)
567{
77be08ee 568 struct ogg *ogg = s->priv_data;
9146ca37
MR
569 int i;
570
571 for (i = 0; i < ogg->nstreams; i++){
572 av_free (ogg->streams[i].buf);
1ed923ea 573 av_free (ogg->streams[i].private);
9146ca37
MR
574 }
575 av_free (ogg->streams);
576 return 0;
577}
578
579
9146ca37
MR
580static int64_t
581ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
582 int64_t pos_limit)
583{
77be08ee 584 struct ogg *ogg = s->priv_data;
d8b91fae 585 struct ogg_stream *os = ogg->streams + stream_index;
899681cd 586 ByteIOContext *bc = s->pb;
a1f29b95
RD
587 int64_t pts = AV_NOPTS_VALUE;
588 int i;
589 url_fseek(bc, *pos_arg, SEEK_SET);
873d117e
DC
590 ogg_reset(ogg);
591
592 while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
593 if (i == stream_index) {
594 pts = ogg_calc_pts(s, i, NULL);
cc947f04 595 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
d8b91fae 596 pts = AV_NOPTS_VALUE;
a1f29b95 597 }
873d117e
DC
598 if (pts != AV_NOPTS_VALUE)
599 break;
a1f29b95
RD
600 }
601 ogg_reset(ogg);
602 return pts;
9146ca37 603}
9146ca37 604
d8b91fae
DC
605static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
606{
607 struct ogg *ogg = s->priv_data;
608 struct ogg_stream *os = ogg->streams + stream_index;
609 int ret;
610
611 // Try seeking to a keyframe first. If this fails (very possible),
612 // av_seek_frame will fall back to ignoring keyframes
72415b2a 613 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
d8b91fae
DC
614 && !(flags & AVSEEK_FLAG_ANY))
615 os->keyframe_seek = 1;
616
617 ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
618 if (ret < 0)
619 os->keyframe_seek = 0;
620 return ret;
621}
622
2e70e4aa
MR
623static int ogg_probe(AVProbeData *p)
624{
2e70e4aa
MR
625 if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
626 p->buf[2] == 'g' && p->buf[3] == 'S' &&
627 p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
628 return AVPROBE_SCORE_MAX;
629 else
630 return 0;
631}
632
ff70e601 633AVInputFormat ogg_demuxer = {
9146ca37 634 "ogg",
bde15e74 635 NULL_IF_CONFIG_SMALL("Ogg"),
77be08ee 636 sizeof (struct ogg),
2e70e4aa 637 ogg_probe,
9146ca37
MR
638 ogg_read_header,
639 ogg_read_packet,
640 ogg_read_close,
d8b91fae 641 ogg_read_seek,
a1f29b95 642 ogg_read_timestamp,
9146ca37 643 .extensions = "ogg",
f1a05185 644 .flags = AVFMT_GENERIC_INDEX,
9146ca37 645};