comparison src/alac/demux.c @ 56:56c88eee9802 trunk

[svn] - experimental ALAC plugin -- don't use this, it crashes
author nenolod
date Sat, 30 Sep 2006 19:26:34 -0700
parents
children 41e2dc106f4e
comparison
equal deleted inserted replaced
55:4423278dc9ae 56:56c88eee9802
1 /*
2 * ALAC (Apple Lossless Audio Codec) decoder
3 * Copyright (c) 2005 David Hammerton
4 * All rights reserved.
5 *
6 * This is the quicktime container demuxer.
7 *
8 * http://crazney.net/programs/itunes/alac.html
9 *
10 * Permission is hereby granted, free of charge, to any person
11 * obtaining a copy of this software and associated documentation
12 * files (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use,
14 * copy, modify, merge, publish, distribute, sublicense, and/or
15 * sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 *
30 */
31
32
33 #include <string.h>
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37
38 #include "stream.h"
39 #include "demux.h"
40
41 typedef struct
42 {
43 stream_t *stream;
44 demux_res_t *res;
45 long saved_mdat_pos;
46 } qtmovie_t;
47
48
49 /* chunk handlers */
50 static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len)
51 {
52 fourcc_t type;
53 uint32_t minor_ver;
54 size_t size_remaining = chunk_len - 8; /* FIXME: can't hardcode 8, size may be 64bit */
55
56 type = stream_read_uint32(qtmovie->stream);
57 size_remaining-=4;
58 if (type != MAKEFOURCC('M','4','A',' '))
59 {
60 fprintf(stderr, "not M4A file\n");
61 return;
62 }
63 minor_ver = stream_read_uint32(qtmovie->stream);
64 size_remaining-=4;
65
66 /* compatible brands */
67 while (size_remaining)
68 {
69 /* unused */
70 /*fourcc_t cbrand =*/ stream_read_uint32(qtmovie->stream);
71 size_remaining-=4;
72 }
73 }
74
75 static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len)
76 {
77 /* don't need anything from here atm, skip */
78 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
79
80 stream_skip(qtmovie->stream, size_remaining);
81 }
82
83 static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len)
84 {
85 /* don't need anything from here atm, skip */
86 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
87
88 stream_skip(qtmovie->stream, size_remaining);
89 }
90
91 static void read_chunk_edts(qtmovie_t *qtmovie, size_t chunk_len)
92 {
93 /* don't need anything from here atm, skip */
94 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
95
96 stream_skip(qtmovie->stream, size_remaining);
97 }
98
99 static void read_chunk_elst(qtmovie_t *qtmovie, size_t chunk_len)
100 {
101 /* don't need anything from here atm, skip */
102 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
103
104 stream_skip(qtmovie->stream, size_remaining);
105 }
106
107 /* media handler inside mdia */
108 static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len)
109 {
110 fourcc_t comptype, compsubtype;
111 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
112
113 int strlen;
114 char str[256] = {0};
115
116 /* version */
117 stream_read_uint8(qtmovie->stream);
118 size_remaining -= 1;
119 /* flags */
120 stream_read_uint8(qtmovie->stream);
121 stream_read_uint8(qtmovie->stream);
122 stream_read_uint8(qtmovie->stream);
123 size_remaining -= 3;
124
125 /* component type */
126 comptype = stream_read_uint32(qtmovie->stream);
127 compsubtype = stream_read_uint32(qtmovie->stream);
128 size_remaining -= 8;
129
130 /* component manufacturer */
131 stream_read_uint32(qtmovie->stream);
132 size_remaining -= 4;
133
134 /* flags */
135 stream_read_uint32(qtmovie->stream);
136 stream_read_uint32(qtmovie->stream);
137 size_remaining -= 8;
138
139 /* name */
140 strlen = stream_read_uint8(qtmovie->stream);
141 stream_read(qtmovie->stream, strlen, str);
142 size_remaining -= 1 + strlen;
143
144 if (size_remaining)
145 {
146 stream_skip(qtmovie->stream, size_remaining);
147 }
148
149 }
150
151 static void read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
152 {
153 unsigned int i;
154 uint32_t numentries;
155 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
156
157 /* version */
158 stream_read_uint8(qtmovie->stream);
159 size_remaining -= 1;
160 /* flags */
161 stream_read_uint8(qtmovie->stream);
162 stream_read_uint8(qtmovie->stream);
163 stream_read_uint8(qtmovie->stream);
164 size_remaining -= 3;
165
166 numentries = stream_read_uint32(qtmovie->stream);
167 size_remaining -= 4;
168
169 if (numentries != 1)
170 {
171 fprintf(stderr, "only expecting one entry in sample description atom!\n");
172 return;
173 }
174
175 for (i = 0; i < numentries; i++)
176 {
177 uint32_t entry_size;
178 uint16_t version;
179
180 uint32_t entry_remaining;
181
182 entry_size = stream_read_uint32(qtmovie->stream);
183 qtmovie->res->format = stream_read_uint32(qtmovie->stream);
184 entry_remaining = entry_size;
185 entry_remaining -= 8;
186
187 /* sound info: */
188
189 stream_skip(qtmovie->stream, 6); /* reserved */
190 entry_remaining -= 6;
191
192 version = stream_read_uint16(qtmovie->stream);
193 if (version != 1)
194 fprintf(stderr, "unknown version??\n");
195 entry_remaining -= 2;
196
197 /* revision level */
198 stream_read_uint16(qtmovie->stream);
199 /* vendor */
200 stream_read_uint32(qtmovie->stream);
201 entry_remaining -= 6;
202
203 /* EH?? spec doesn't say theres an extra 16 bits here.. but there is! */
204 stream_read_uint16(qtmovie->stream);
205 entry_remaining -= 2;
206
207 qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream);
208
209 qtmovie->res->sample_size = stream_read_uint16(qtmovie->stream);
210 entry_remaining -= 4;
211
212 /* compression id */
213 stream_read_uint16(qtmovie->stream);
214 /* packet size */
215 stream_read_uint16(qtmovie->stream);
216 entry_remaining -= 4;
217
218 /* sample rate - 32bit fixed point = 16bit?? */
219 qtmovie->res->sample_rate = stream_read_uint16(qtmovie->stream);
220 entry_remaining -= 2;
221
222 /* skip 2 */
223 stream_skip(qtmovie->stream, 2);
224 entry_remaining -= 2;
225
226 /* remaining is codec data */
227
228 #if 0
229 qtmovie->res->codecdata_len = stream_read_uint32(qtmovie->stream);
230 if (qtmovie->res->codecdata_len != entry_remaining)
231 fprintf(stderr, "perhaps not? %i vs %i\n",
232 qtmovie->res->codecdata_len, entry_remaining);
233 entry_remaining -= 4;
234 stream_read_uint32(qtmovie->stream); /* 'alac' */
235 entry_remaining -= 4;
236
237 qtmovie->res->codecdata = malloc(qtmovie->res->codecdata_len - 8);
238
239 stream_read(qtmovie->stream,
240 entry_remaining,
241 qtmovie->res->codecdata);
242 entry_remaining = 0;
243
244 #else
245 /* 12 = audio format atom, 8 = padding */
246 qtmovie->res->codecdata_len = entry_remaining + 12 + 8;
247 qtmovie->res->codecdata = malloc(qtmovie->res->codecdata_len);
248 memset(qtmovie->res->codecdata, 0, qtmovie->res->codecdata_len);
249 /* audio format atom */
250 ((unsigned int*)qtmovie->res->codecdata)[0] = 0x0c000000;
251 ((unsigned int*)qtmovie->res->codecdata)[1] = MAKEFOURCC('a','m','r','f');
252 ((unsigned int*)qtmovie->res->codecdata)[2] = MAKEFOURCC('c','a','l','a');
253
254 stream_read(qtmovie->stream,
255 entry_remaining,
256 ((char*)qtmovie->res->codecdata) + 12);
257 entry_remaining -= entry_remaining;
258
259 #endif
260 if (entry_remaining)
261 stream_skip(qtmovie->stream, entry_remaining);
262
263 if (qtmovie->res->format != MAKEFOURCC('a','l','a','c'))
264 {
265 fprintf(stderr, "expecting 'alac' data format, got %c%c%c%c\n",
266 SPLITFOURCC(qtmovie->res->format));
267 return;
268 }
269 }
270 }
271
272 static void read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
273 {
274 unsigned int i;
275 uint32_t numentries;
276 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
277
278 /* version */
279 stream_read_uint8(qtmovie->stream);
280 size_remaining -= 1;
281 /* flags */
282 stream_read_uint8(qtmovie->stream);
283 stream_read_uint8(qtmovie->stream);
284 stream_read_uint8(qtmovie->stream);
285 size_remaining -= 3;
286
287 numentries = stream_read_uint32(qtmovie->stream);
288 size_remaining -= 4;
289
290 qtmovie->res->num_time_to_samples = numentries;
291 qtmovie->res->time_to_sample = malloc(numentries * sizeof(*qtmovie->res->time_to_sample));
292
293 for (i = 0; i < numentries; i++)
294 {
295 qtmovie->res->time_to_sample[i].sample_count = stream_read_uint32(qtmovie->stream);
296 qtmovie->res->time_to_sample[i].sample_duration = stream_read_uint32(qtmovie->stream);
297 size_remaining -= 8;
298 }
299
300 if (size_remaining)
301 {
302 fprintf(stderr, "ehm, size remianing?\n");
303 stream_skip(qtmovie->stream, size_remaining);
304 }
305 }
306
307 static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
308 {
309 unsigned int i;
310 uint32_t numentries;
311 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
312
313 /* version */
314 stream_read_uint8(qtmovie->stream);
315 size_remaining -= 1;
316 /* flags */
317 stream_read_uint8(qtmovie->stream);
318 stream_read_uint8(qtmovie->stream);
319 stream_read_uint8(qtmovie->stream);
320 size_remaining -= 3;
321
322 /* default sample size */
323 if (stream_read_uint32(qtmovie->stream) != 0)
324 {
325 fprintf(stderr, "i was expecting variable samples sizes\n");
326 stream_read_uint32(qtmovie->stream);
327 size_remaining -= 4;
328 return;
329 }
330 size_remaining -= 4;
331
332 numentries = stream_read_uint32(qtmovie->stream);
333 size_remaining -= 4;
334
335 qtmovie->res->num_sample_byte_sizes = numentries;
336 qtmovie->res->sample_byte_size = malloc(numentries * sizeof(*qtmovie->res->sample_byte_size));
337
338 for (i = 0; i < numentries; i++)
339 {
340 qtmovie->res->sample_byte_size[i] = stream_read_uint32(qtmovie->stream);
341 size_remaining -= 4;
342 }
343
344 if (size_remaining)
345 {
346 fprintf(stderr, "ehm, size remianing?\n");
347 stream_skip(qtmovie->stream, size_remaining);
348 }
349 }
350
351 static void read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
352 {
353 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
354
355 while (size_remaining)
356 {
357 size_t sub_chunk_len;
358 fourcc_t sub_chunk_id;
359
360 sub_chunk_len = stream_read_uint32(qtmovie->stream);
361 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
362 {
363 fprintf(stderr, "strange size for chunk inside stbl (%i) (remaining: %i)\n",
364 sub_chunk_len, size_remaining);
365 return;
366 }
367
368 sub_chunk_id = stream_read_uint32(qtmovie->stream);
369
370 switch (sub_chunk_id)
371 {
372 case MAKEFOURCC('s','t','s','d'):
373 read_chunk_stsd(qtmovie, sub_chunk_len);
374 break;
375 case MAKEFOURCC('s','t','t','s'):
376 read_chunk_stts(qtmovie, sub_chunk_len);
377 break;
378 case MAKEFOURCC('s','t','s','z'):
379 read_chunk_stsz(qtmovie, sub_chunk_len);
380 break;
381 case MAKEFOURCC('s','t','s','c'):
382 case MAKEFOURCC('s','t','c','o'):
383 /* skip these, no indexing for us! */
384 stream_skip(qtmovie->stream, sub_chunk_len - 8);
385 break;
386 default:
387 fprintf(stderr, "(stbl) unknown chunk id: %c%c%c%c\n",
388 SPLITFOURCC(sub_chunk_id));
389 return;
390 }
391
392 size_remaining -= sub_chunk_len;
393 }
394 }
395
396 static void read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len)
397 {
398 size_t dinf_size, stbl_size;
399 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
400
401 /**** SOUND HEADER CHUNK ****/
402 if (stream_read_uint32(qtmovie->stream) != 16)
403 {
404 fprintf(stderr, "unexpected size in media info\n");
405 return;
406 }
407 if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('s','m','h','d'))
408 {
409 fprintf(stderr, "not a sound header! can't handle this.\n");
410 return;
411 }
412 /* now skip the rest */
413 stream_skip(qtmovie->stream, 16 - 8);
414 size_remaining -= 16;
415 /****/
416
417 /**** DINF CHUNK ****/
418 dinf_size = stream_read_uint32(qtmovie->stream);
419 if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('d','i','n','f'))
420 {
421 fprintf(stderr, "expected dinf, didn't get it.\n");
422 return;
423 }
424 /* skip it */
425 stream_skip(qtmovie->stream, dinf_size - 8);
426 size_remaining -= dinf_size;
427 /****/
428
429
430 /**** SAMPLE TABLE ****/
431 stbl_size = stream_read_uint32(qtmovie->stream);
432 if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('s','t','b','l'))
433 {
434 fprintf(stderr, "expected stbl, didn't get it.\n");
435 return;
436 }
437 read_chunk_stbl(qtmovie, stbl_size);
438 size_remaining -= stbl_size;
439
440 if (size_remaining)
441 {
442 fprintf(stderr, "oops\n");
443 stream_skip(qtmovie->stream, size_remaining);
444 }
445 }
446
447 static void read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len)
448 {
449 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
450
451 while (size_remaining)
452 {
453 size_t sub_chunk_len;
454 fourcc_t sub_chunk_id;
455
456 sub_chunk_len = stream_read_uint32(qtmovie->stream);
457 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
458 {
459 fprintf(stderr, "strange size for chunk inside mdia\n");
460 return;
461 }
462
463 sub_chunk_id = stream_read_uint32(qtmovie->stream);
464
465 switch (sub_chunk_id)
466 {
467 case MAKEFOURCC('m','d','h','d'):
468 read_chunk_mdhd(qtmovie, sub_chunk_len);
469 break;
470 case MAKEFOURCC('h','d','l','r'):
471 read_chunk_hdlr(qtmovie, sub_chunk_len);
472 break;
473 case MAKEFOURCC('m','i','n','f'):
474 read_chunk_minf(qtmovie, sub_chunk_len);
475 break;
476 default:
477 fprintf(stderr, "(mdia) unknown chunk id: %c%c%c%c\n",
478 SPLITFOURCC(sub_chunk_id));
479 return;
480 }
481
482 size_remaining -= sub_chunk_len;
483 }
484 }
485
486 /* 'trak' - a movie track - contains other atoms */
487 static void read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len)
488 {
489 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
490
491 while (size_remaining)
492 {
493 size_t sub_chunk_len;
494 fourcc_t sub_chunk_id;
495
496 sub_chunk_len = stream_read_uint32(qtmovie->stream);
497 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
498 {
499 fprintf(stderr, "strange size for chunk inside trak\n");
500 return;
501 }
502
503 sub_chunk_id = stream_read_uint32(qtmovie->stream);
504
505 switch (sub_chunk_id)
506 {
507 case MAKEFOURCC('t','k','h','d'):
508 read_chunk_tkhd(qtmovie, sub_chunk_len);
509 break;
510 case MAKEFOURCC('m','d','i','a'):
511 read_chunk_mdia(qtmovie, sub_chunk_len);
512 break;
513 case MAKEFOURCC('e','d','t','s'):
514 read_chunk_edts(qtmovie, sub_chunk_len);
515 break;
516 default:
517 fprintf(stderr, "(trak) unknown chunk id: %c%c%c%c\n",
518 SPLITFOURCC(sub_chunk_id));
519 return;
520 }
521
522 size_remaining -= sub_chunk_len;
523 }
524 }
525
526 /* 'mvhd' movie header atom */
527 static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len)
528 {
529 /* don't need anything from here atm, skip */
530 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
531
532 stream_skip(qtmovie->stream, size_remaining);
533 }
534
535 /* 'udta' user data.. contains tag info */
536 static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
537 {
538 /* don't need anything from here atm, skip */
539 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
540
541 stream_skip(qtmovie->stream, size_remaining);
542 }
543
544 /* 'moov' movie atom - contains other atoms */
545 static void read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
546 {
547 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
548
549 while (size_remaining)
550 {
551 size_t sub_chunk_len;
552 fourcc_t sub_chunk_id;
553
554 sub_chunk_len = stream_read_uint32(qtmovie->stream);
555 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
556 {
557 fprintf(stderr, "strange size for chunk inside moov\n");
558 return;
559 }
560
561 sub_chunk_id = stream_read_uint32(qtmovie->stream);
562
563 switch (sub_chunk_id)
564 {
565 case MAKEFOURCC('m','v','h','d'):
566 read_chunk_mvhd(qtmovie, sub_chunk_len);
567 break;
568 case MAKEFOURCC('t','r','a','k'):
569 read_chunk_trak(qtmovie, sub_chunk_len);
570 break;
571 case MAKEFOURCC('u','d','t','a'):
572 read_chunk_udta(qtmovie, sub_chunk_len);
573 break;
574 case MAKEFOURCC('e','l','s','t'):
575 read_chunk_elst(qtmovie, sub_chunk_len);
576 break;
577 default:
578 fprintf(stderr, "(moov) unknown chunk id: %c%c%c%c\n",
579 SPLITFOURCC(sub_chunk_id));
580 return;
581 }
582
583 size_remaining -= sub_chunk_len;
584 }
585 }
586
587 static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len, int skip_mdat)
588 {
589 size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
590
591 qtmovie->res->mdat_len = (uint32_t)size_remaining;
592 if (skip_mdat)
593 {
594 qtmovie->saved_mdat_pos = stream_tell(qtmovie->stream);
595 stream_skip(qtmovie->stream, size_remaining);
596 }
597 #if 0
598 qtmovie->res->mdat = malloc(size_remaining);
599
600 stream_read(qtmovie->stream, size_remaining, qtmovie->res->mdat);
601 #endif
602 }
603
604 static int set_saved_mdat(qtmovie_t *qtmovie)
605 {
606 if (qtmovie->saved_mdat_pos == -1)
607 {
608 fprintf(stderr, "stream contains mdat before moov but is not seekable\n");
609 return 0;
610 }
611
612 if (stream_setpos(qtmovie->stream, qtmovie->saved_mdat_pos))
613 {
614 fprintf(stderr, "error while seeking stream to mdat pos\n");
615 return 0;
616 }
617
618 return 1;
619 }
620
621 int qtmovie_read(stream_t *file, demux_res_t *demux_res)
622 {
623 int found_moov = 0;
624 int found_mdat = 0;
625 qtmovie_t *qtmovie;
626
627 qtmovie = (qtmovie_t*)malloc(sizeof(qtmovie_t));
628
629 /* construct the stream */
630 qtmovie->stream = file;
631
632 qtmovie->res = demux_res;
633
634 memset(demux_res, 0, sizeof(demux_res_t));
635
636 /* read the chunks */
637 while (1)
638 {
639 size_t chunk_len;
640 fourcc_t chunk_id;
641
642 chunk_len = stream_read_uint32(qtmovie->stream);
643 if (stream_eof(qtmovie->stream))
644 {
645 return 0;
646 }
647
648 if (chunk_len == 1)
649 {
650 fprintf(stderr, "need 64bit support\n");
651 return 0;
652 }
653 chunk_id = stream_read_uint32(qtmovie->stream);
654
655 switch (chunk_id)
656 {
657 case MAKEFOURCC('f','t','y','p'):
658 read_chunk_ftyp(qtmovie, chunk_len);
659 break;
660 case MAKEFOURCC('m','o','o','v'):
661 read_chunk_moov(qtmovie, chunk_len);
662 if (found_mdat)
663 {
664 return set_saved_mdat(qtmovie);
665 }
666 found_moov = 1;
667 break;
668 /* if we hit mdat before we've found moov, record the position
669 * and move on. We can then come back to mdat later.
670 * This presumes the stream supports seeking backwards.
671 */
672 case MAKEFOURCC('m','d','a','t'):
673 read_chunk_mdat(qtmovie, chunk_len, !found_moov);
674 if (found_moov)
675 return 1;
676 found_mdat = 1;
677 break;
678
679 /* these following atoms can be skipped !!!! */
680 case MAKEFOURCC('f','r','e','e'):
681 stream_skip(qtmovie->stream, chunk_len - 8); /* FIXME not 8 */
682 break;
683 default:
684 fprintf(stderr, "(top) unknown chunk id: %c%c%c%c\n",
685 SPLITFOURCC(chunk_id));
686 return 0;
687 }
688
689 }
690 return 0;
691 }
692
693