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