Fix compiler warnings ('variable set ut not used') with GCC 4.6.0.
[kugel-rb.git] / apps / codecs / libm4a / demux.c
blob7b09074c52051bf1c0078d78598e2c5dce5a7306
1 /*
2 * ALAC (Apple Lossless Audio Codec) decoder
3 * Copyright (c) 2005 David Hammerton
4 * All rights reserved.
6 * This is the quicktime container demuxer.
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:
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
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.
32 #include <string.h>
33 #include <inttypes.h>
34 #include <stdlib.h>
36 #include "codeclib.h"
38 #include "m4a.h"
40 #undef DEBUGF
41 #if defined(DEBUG)
42 #define DEBUGF qtmovie->stream->ci->debugf
43 #else
44 #define DEBUGF(...)
45 #endif
47 typedef struct
49 stream_t *stream;
50 demux_res_t *res;
51 } qtmovie_t;
54 /* chunk handlers */
55 static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len)
57 fourcc_t type;
58 size_t size_remaining = chunk_len - 8;
60 type = stream_read_uint32(qtmovie->stream);
61 size_remaining-=4;
62 if ((type != MAKEFOURCC('M','4','A',' ')) &&
63 (type != MAKEFOURCC('m','4','a',' ')) &&
64 (type != MAKEFOURCC('M','4','B',' ')) &&
65 (type != MAKEFOURCC('m','p','4','2')) &&
66 (type != MAKEFOURCC('3','g','p','6')) &&
67 (type != MAKEFOURCC('q','t',' ',' ')) &&
68 (type != MAKEFOURCC('i','s','o','m')))
70 DEBUGF("not M4A file\n");
71 return;
73 /* minor_ver = */ stream_read_uint32(qtmovie->stream);
74 size_remaining-=4;
76 /* compatible brands */
77 while (size_remaining)
79 /* unused */
80 /*fourcc_t cbrand =*/ stream_read_uint32(qtmovie->stream);
81 size_remaining-=4;
85 static uint32_t mp4ff_read_mp4_descr_length(stream_t* stream)
87 uint8_t b;
88 uint8_t numBytes = 0;
89 uint32_t length = 0;
93 b = stream_read_uint8(stream);
94 numBytes++;
95 length = (length << 7) | (b & 0x7F);
96 } while ((b & 0x80) && numBytes < 4);
98 return length;
101 /* The following function is based on mp4ff */
102 static bool read_chunk_esds(qtmovie_t *qtmovie, size_t chunk_len)
104 uint8_t tag;
105 uint32_t temp;
107 (void)chunk_len;
108 /* version and flags */
109 temp=stream_read_uint32(qtmovie->stream);
111 /* get and verify ES_DescrTag */
112 tag = stream_read_uint8(qtmovie->stream);
113 if (tag == 0x03)
115 /* read length */
116 if (mp4ff_read_mp4_descr_length(qtmovie->stream) < 5 + 15)
118 return false;
120 /* skip 3 bytes */
121 stream_skip(qtmovie->stream,3);
122 } else {
123 /* skip 2 bytes */
124 stream_skip(qtmovie->stream,2);
127 /* get and verify DecoderConfigDescrTab */
128 if (stream_read_uint8(qtmovie->stream) != 0x04)
130 return false;
133 /* read length */
134 temp = mp4ff_read_mp4_descr_length(qtmovie->stream);
135 if (temp < 13) return false;
137 /* audioType = */ stream_read_uint8(qtmovie->stream);
138 /* temp = */ stream_read_int32(qtmovie->stream);//0x15000414 ????
139 /* maxBitrate = */ stream_read_int32(qtmovie->stream);
140 /* avgBitrate = */ stream_read_int32(qtmovie->stream);
142 /* get and verify DecSpecificInfoTag */
143 if (stream_read_uint8(qtmovie->stream) != 0x05)
145 return false;
148 /* read length */
149 qtmovie->res->codecdata_len = mp4ff_read_mp4_descr_length(qtmovie->stream);
150 if (qtmovie->res->codecdata_len > MAX_CODECDATA_SIZE)
152 DEBUGF("codecdata too large (%d) in esds\n",
153 (int)qtmovie->res->codecdata_len);
154 return false;
157 stream_read(qtmovie->stream, qtmovie->res->codecdata_len, qtmovie->res->codecdata);
159 /* will skip the remainder of the atom */
160 return true;
163 static bool read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len)
165 unsigned int i;
166 int j;
167 uint32_t numentries;
168 size_t size_remaining = chunk_len - 8;
169 bool got_codec_data = false;
171 /* version */
172 stream_read_uint8(qtmovie->stream);
173 size_remaining -= 1;
174 /* flags */
175 stream_read_uint8(qtmovie->stream);
176 stream_read_uint8(qtmovie->stream);
177 stream_read_uint8(qtmovie->stream);
178 size_remaining -= 3;
180 numentries = stream_read_uint32(qtmovie->stream);
181 size_remaining -= 4;
183 /* if (numentries != 1)
185 DEBUGF("only expecting one entry in sample description atom!\n");
186 return false;
187 } */
189 for (i = 0; i < numentries; i++)
191 uint32_t entry_size;
193 uint32_t entry_remaining;
195 entry_size = stream_read_uint32(qtmovie->stream);
196 qtmovie->res->format = stream_read_uint32(qtmovie->stream);
197 DEBUGF("format: %c%c%c%c\n",SPLITFOURCC(qtmovie->res->format));
198 entry_remaining = entry_size;
199 entry_remaining -= 8;
201 /* sound info: */
203 /* reserved + data reference index + sound version + reserved */
204 stream_skip(qtmovie->stream, 6 + 2 + 2 + 6);
205 entry_remaining -= 6 + 2 + 2 + 6;
207 qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream);
208 qtmovie->res->sound_sample_size = stream_read_uint16(qtmovie->stream);
209 entry_remaining -= 4;
211 /* packet size */
212 stream_skip(qtmovie->stream, 2);
213 qtmovie->res->sound_sample_rate = stream_read_uint32(qtmovie->stream);
214 /* reserved size */
215 stream_skip(qtmovie->stream, 2);
216 entry_remaining -= 8;
218 /* remaining is codec data */
220 if ((qtmovie->res->format==MAKEFOURCC('a','l','a','c'))) {
221 if (qtmovie->stream->ci->id3->codectype!=AFMT_MP4_ALAC) {
222 return false;
225 /* 12 = audio format atom, 8 = padding */
226 qtmovie->res->codecdata_len = entry_remaining + 12 + 8;
227 if (qtmovie->res->codecdata_len > MAX_CODECDATA_SIZE)
229 DEBUGF("codecdata too large (%d) in stsd\n",
230 (int)qtmovie->res->codecdata_len);
231 return false;
234 memset(qtmovie->res->codecdata, 0, qtmovie->res->codecdata_len);
235 /* audio format atom */
236 #if 0
237 /* The ALAC decoder skips these bytes, so there is no need to store them,
238 and this code isn't endian/alignment safe */
239 ((unsigned int*)qtmovie->res->codecdata)[0] = 0x0c000000;
240 ((unsigned int*)qtmovie->res->codecdata)[1] = MAKEFOURCC('a','m','r','f');
241 ((unsigned int*)qtmovie->res->codecdata)[2] = MAKEFOURCC('c','a','l','a');
242 #endif
244 stream_read(qtmovie->stream,
245 entry_remaining,
246 ((char*)qtmovie->res->codecdata) + 12);
247 entry_remaining -= entry_remaining;
248 got_codec_data = true;
250 if (entry_remaining)
251 stream_skip(qtmovie->stream, entry_remaining);
253 } else if (qtmovie->res->format==MAKEFOURCC('m','p','4','a')) {
254 if (qtmovie->stream->ci->id3->codectype!=AFMT_MP4_AAC &&
255 qtmovie->stream->ci->id3->codectype!=AFMT_MP4_AAC_HE) {
256 return false;
259 size_t sub_chunk_len;
260 fourcc_t sub_chunk_id;
262 sub_chunk_len = stream_read_uint32(qtmovie->stream);
263 if (sub_chunk_len <= 1 || sub_chunk_len > entry_remaining)
265 DEBUGF("strange size (%lu) for chunk inside mp4a\n",
266 (unsigned long)sub_chunk_len);
267 return false;
270 sub_chunk_id = stream_read_uint32(qtmovie->stream);
272 if (sub_chunk_id != MAKEFOURCC('e','s','d','s'))
274 DEBUGF("Expected esds chunk inside mp4a, found %c%c%c%c\n",SPLITFOURCC(sub_chunk_id));
275 return false;
278 j=qtmovie->stream->ci->curpos+sub_chunk_len-8;
279 if (read_chunk_esds(qtmovie,sub_chunk_len)) {
280 if (j!=qtmovie->stream->ci->curpos) {
281 DEBUGF("curpos=%ld, j=%d - Skipping %ld bytes\n",qtmovie->stream->ci->curpos,j,j-qtmovie->stream->ci->curpos);
282 stream_skip(qtmovie->stream,j-qtmovie->stream->ci->curpos);
284 got_codec_data = true;
285 entry_remaining-=sub_chunk_len;
286 } else {
287 DEBUGF("Error reading esds\n");
288 return false;
291 DEBUGF("entry_remaining=%ld\n",(long)entry_remaining);
292 stream_skip(qtmovie->stream,entry_remaining);
294 } else if (qtmovie->res->format==MAKEFOURCC('f','r','e','e')) {
295 /* Skip "filler" atom */
296 stream_skip(qtmovie->stream,entry_remaining);
297 } else {
298 DEBUGF("expecting 'alac', 'mp4a' or 'free' data format, got %c%c%c%c\n",
299 SPLITFOURCC(qtmovie->res->format));
300 return false;
303 return got_codec_data;
306 static bool read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
308 unsigned int i;
309 uint32_t numentries;
310 size_t size_remaining = chunk_len - 8;
312 /* version */
313 stream_read_uint8(qtmovie->stream);
314 size_remaining -= 1;
315 /* flags */
316 stream_read_uint8(qtmovie->stream);
317 stream_read_uint8(qtmovie->stream);
318 stream_read_uint8(qtmovie->stream);
319 size_remaining -= 3;
321 numentries = stream_read_uint32(qtmovie->stream);
322 size_remaining -= 4;
324 qtmovie->res->num_time_to_samples = numentries;
325 qtmovie->res->time_to_sample = malloc(numentries * sizeof(*qtmovie->res->time_to_sample));
327 if (!qtmovie->res->time_to_sample)
329 DEBUGF("stts too large\n");
330 return false;
333 for (i = 0; i < numentries; i++)
335 qtmovie->res->time_to_sample[i].sample_count = stream_read_uint32(qtmovie->stream);
336 qtmovie->res->time_to_sample[i].sample_duration = stream_read_uint32(qtmovie->stream);
337 size_remaining -= 8;
340 if (size_remaining)
342 DEBUGF("ehm, size remianing?\n");
343 stream_skip(qtmovie->stream, size_remaining);
346 return true;
349 static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
351 size_t size_remaining = chunk_len - 8;
353 /* version */
354 stream_read_uint8(qtmovie->stream);
355 size_remaining -= 1;
356 /* flags */
357 stream_read_uint8(qtmovie->stream);
358 stream_read_uint8(qtmovie->stream);
359 stream_read_uint8(qtmovie->stream);
360 size_remaining -= 3;
362 /* default sample size */
363 if (stream_read_uint32(qtmovie->stream) != 0)
365 DEBUGF("i was expecting variable samples sizes\n");
366 stream_read_uint32(qtmovie->stream);
367 size_remaining -= 4;
368 return true;
370 size_remaining -= 4;
372 qtmovie->res->num_sample_byte_sizes = stream_read_uint32(qtmovie->stream);
373 size_remaining -= 4;
375 if (size_remaining)
377 stream_skip(qtmovie->stream, size_remaining);
380 return true;
383 static bool read_chunk_stsc(qtmovie_t *qtmovie, size_t chunk_len)
385 unsigned int i;
386 uint32_t numentries;
387 size_t size_remaining = chunk_len - 8;
389 /* version + flags */
390 stream_read_uint32(qtmovie->stream);
391 size_remaining -= 4;
393 numentries = stream_read_uint32(qtmovie->stream);
394 size_remaining -= 4;
396 qtmovie->res->num_sample_to_chunks = numentries;
397 qtmovie->res->sample_to_chunk = malloc(numentries * sizeof(sample_to_chunk_t));
399 if (!qtmovie->res->sample_to_chunk)
401 DEBUGF("stsc too large\n");
402 return false;
405 for (i = 0; i < numentries; i++)
407 qtmovie->res->sample_to_chunk[i].first_chunk =
408 stream_read_uint32(qtmovie->stream);
409 qtmovie->res->sample_to_chunk[i].num_samples =
410 stream_read_uint32(qtmovie->stream);
411 stream_read_uint32(qtmovie->stream);
412 size_remaining -= 12;
415 if (size_remaining)
417 DEBUGF("ehm, size remianing?\n");
418 stream_skip(qtmovie->stream, size_remaining);
421 return true;
424 static bool read_chunk_stco(qtmovie_t *qtmovie, size_t chunk_len)
426 uint32_t i, k, old_i;
427 uint32_t numentries;
428 uint32_t idx = 0;
429 uint32_t frame;
430 uint32_t offset;
431 uint32_t old_first;
432 uint32_t new_first;
433 uint32_t old_frame;
434 size_t size_remaining = chunk_len - 8;
436 /* version + flags */
437 stream_read_uint32(qtmovie->stream);
438 size_remaining -= 4;
440 numentries = stream_read_uint32(qtmovie->stream);
441 size_remaining -= 4;
443 qtmovie->res->num_lookup_table = numentries;
444 qtmovie->res->lookup_table = malloc(numentries * sizeof(*qtmovie->res->lookup_table));
446 if (!qtmovie->res->lookup_table)
448 DEBUGF("stco too large to allocate lookup_table[]\n");
449 return false;
452 /* read first offset */
453 offset = stream_read_uint32(qtmovie->stream);
454 size_remaining -= 4;
456 /* Build up lookup table. The lookup table contains the sample index and
457 * byte position in the file for each chunk. This table is used to seek
458 * and resume (see m4a_seek() and m4a_seek_raw() in libm4a/m4a.c) and
459 * to skip empty chunks (see m4a_check_sample_offset() in codecs/aac.c and
460 * libm4a/m4a.c).
461 * The seek/resume precision is lower than using sample_byte_size[] and
462 * depends on numentries. Typically the resolution is ~1/10 of all frames
463 * which equals about 1/4-1/2 seconds. The loss of seek precision is
464 * accepted to be able to avoid allocation of the large sample_byte_size[]
465 * table. This reduces the memory consumption by a factor of 2 or even
466 * more. */
467 i = 1;
468 old_i = 1;
469 frame = 0;
470 old_first = qtmovie->res->sample_to_chunk[0].first_chunk;
471 old_frame = qtmovie->res->sample_to_chunk[0].num_samples;
472 new_first = qtmovie->res->sample_to_chunk[1].first_chunk;
473 for (k = 1; k < numentries; ++k)
475 for (; i < qtmovie->res->num_sample_to_chunks; ++i)
477 if (i > old_i)
479 /* Only access sample_to_chunk[] if new data is required. */
480 old_first = qtmovie->res->sample_to_chunk[i-1].first_chunk;
481 old_frame = qtmovie->res->sample_to_chunk[i-1].num_samples;
482 new_first = qtmovie->res->sample_to_chunk[i ].first_chunk;
483 old_i = i;
486 if (new_first > k)
487 break;
489 frame += (new_first - old_first) * old_frame;
491 frame += (k - old_first) * old_frame;
493 qtmovie->res->lookup_table[idx].sample = frame;
494 qtmovie->res->lookup_table[idx].offset = offset;
495 idx++;
497 frame -= (k - old_first) * old_frame;
499 offset = stream_read_uint32(qtmovie->stream);
500 size_remaining -= 4;
502 /* zero-terminate the lookup table */
503 qtmovie->res->lookup_table[idx].sample = 0;
504 qtmovie->res->lookup_table[idx].offset = 0;
506 if (size_remaining)
508 DEBUGF("ehm, size remianing?\n");
509 stream_skip(qtmovie->stream, size_remaining);
512 return true;
515 static bool read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len)
517 size_t size_remaining = chunk_len - 8;
519 while (size_remaining)
521 size_t sub_chunk_len;
522 fourcc_t sub_chunk_id;
524 sub_chunk_len = stream_read_uint32(qtmovie->stream);
525 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
527 DEBUGF("strange size (%lu) for chunk inside stbl\n",
528 (unsigned long)sub_chunk_len);
529 return false;
532 sub_chunk_id = stream_read_uint32(qtmovie->stream);
534 switch (sub_chunk_id)
536 case MAKEFOURCC('s','t','s','d'):
537 if (!read_chunk_stsd(qtmovie, sub_chunk_len)) {
538 return false;
540 break;
541 case MAKEFOURCC('s','t','t','s'):
542 if (!read_chunk_stts(qtmovie, sub_chunk_len))
544 return false;
546 break;
547 case MAKEFOURCC('s','t','s','z'):
548 if (!read_chunk_stsz(qtmovie, sub_chunk_len))
550 return false;
552 break;
553 case MAKEFOURCC('s','t','s','c'):
554 if (!read_chunk_stsc(qtmovie, sub_chunk_len))
556 return false;
558 break;
559 case MAKEFOURCC('s','t','c','o'):
560 if (!read_chunk_stco(qtmovie, sub_chunk_len))
562 return false;
564 break;
565 default:
566 /*DEBUGF("(stbl) unknown chunk id: %c%c%c%c\n",
567 SPLITFOURCC(sub_chunk_id));*/
568 stream_skip(qtmovie->stream, sub_chunk_len - 8);
571 size_remaining -= sub_chunk_len;
573 return true;
576 static bool read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len)
578 size_t size_remaining = chunk_len - 8;
579 uint32_t i;
581 /* Check for smhd, only kind of minf we care about */
583 if ((i = stream_read_uint32(qtmovie->stream)) != 16)
585 DEBUGF("unexpected size in media info: %ld\n", (long)i);
586 stream_skip(qtmovie->stream, size_remaining-4);
587 return true;
590 if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('s','m','h','d'))
592 DEBUGF("not a sound header! can't handle this.\n");
593 return false;
596 /* now skip the rest of the atom */
597 stream_skip(qtmovie->stream, 16 - 8);
598 size_remaining -= 16;
600 while (size_remaining)
602 size_t sub_chunk_len;
603 fourcc_t sub_chunk_id;
605 sub_chunk_len = stream_read_uint32(qtmovie->stream);
607 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
609 DEBUGF("strange size (%lu) for chunk inside minf\n",
610 (unsigned long)sub_chunk_len);
611 return false;
614 sub_chunk_id = stream_read_uint32(qtmovie->stream);
616 switch (sub_chunk_id)
618 case MAKEFOURCC('s','t','b','l'):
619 if (!read_chunk_stbl(qtmovie, sub_chunk_len)) {
620 return false;
622 break;
623 default:
624 /*DEBUGF("(minf) unknown chunk id: %c%c%c%c\n",
625 SPLITFOURCC(sub_chunk_id));*/
626 stream_skip(qtmovie->stream, sub_chunk_len - 8);
627 break;
630 size_remaining -= sub_chunk_len;
632 return true;
635 static bool read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len)
637 size_t size_remaining = chunk_len - 8;
639 while (size_remaining)
641 size_t sub_chunk_len;
642 fourcc_t sub_chunk_id;
644 sub_chunk_len = stream_read_uint32(qtmovie->stream);
645 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
647 DEBUGF("strange size (%lu) for chunk inside mdia\n",
648 (unsigned long)sub_chunk_len);
649 return false;
652 sub_chunk_id = stream_read_uint32(qtmovie->stream);
654 switch (sub_chunk_id)
656 case MAKEFOURCC('m','i','n','f'):
657 if (!read_chunk_minf(qtmovie, sub_chunk_len)) {
658 return false;
660 break;
661 default:
662 /*DEBUGF("(mdia) unknown chunk id: %c%c%c%c\n",
663 SPLITFOURCC(sub_chunk_id));*/
664 stream_skip(qtmovie->stream, sub_chunk_len - 8);
665 break;
668 size_remaining -= sub_chunk_len;
670 return true;
673 /* 'trak' - a movie track - contains other atoms */
674 static bool read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len)
676 size_t size_remaining = chunk_len - 8;
678 while (size_remaining)
680 size_t sub_chunk_len;
681 fourcc_t sub_chunk_id;
683 sub_chunk_len = stream_read_uint32(qtmovie->stream);
684 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
686 DEBUGF("strange size (%lu) for chunk inside trak\n",
687 (unsigned long)sub_chunk_len);
688 return false;
691 sub_chunk_id = stream_read_uint32(qtmovie->stream);
693 switch (sub_chunk_id)
695 case MAKEFOURCC('m','d','i','a'):
696 if (!read_chunk_mdia(qtmovie, sub_chunk_len)) {
697 return false;
699 break;
700 default:
701 /*DEBUGF("(trak) unknown chunk id: %c%c%c%c\n",
702 SPLITFOURCC(sub_chunk_id));*/
703 stream_skip(qtmovie->stream, sub_chunk_len - 8);
704 break;
707 size_remaining -= sub_chunk_len;
709 return true;
712 /* 'moov' movie atom - contains other atoms */
713 static bool read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len)
715 size_t size_remaining = chunk_len - 8;
717 while (size_remaining)
719 size_t sub_chunk_len;
720 fourcc_t sub_chunk_id;
722 sub_chunk_len = stream_read_uint32(qtmovie->stream);
723 if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
725 DEBUGF("strange size (%lu) for chunk inside moov\n",
726 (unsigned long)sub_chunk_len);
727 return false;
730 sub_chunk_id = stream_read_uint32(qtmovie->stream);
732 switch (sub_chunk_id)
734 case MAKEFOURCC('t','r','a','k'):
735 if (!read_chunk_trak(qtmovie, sub_chunk_len)) {
736 return false;
738 break;
739 default:
740 /*DEBUGF("(moov) unknown chunk id: %c%c%c%c\n",
741 SPLITFOURCC(sub_chunk_id));*/
742 stream_skip(qtmovie->stream, sub_chunk_len - 8);
743 break;
746 size_remaining -= sub_chunk_len;
748 return true;
751 static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len)
753 size_t size_remaining = chunk_len - 8;
755 qtmovie->res->mdat_len = size_remaining;
758 int qtmovie_read(stream_t *file, demux_res_t *demux_res)
760 qtmovie_t qtmovie;
762 /* construct the stream */
763 qtmovie.stream = file;
764 qtmovie.res = demux_res;
766 /* read the chunks */
767 while (1)
769 size_t chunk_len;
770 fourcc_t chunk_id;
772 chunk_len = stream_read_uint32(qtmovie.stream);
773 if (stream_eof(qtmovie.stream))
775 if(qtmovie.res->mdat_offset == 0 || qtmovie.res->format == 0)
776 return 0;
777 stream_seek(qtmovie.stream, qtmovie.res->mdat_offset);
778 return 1;
781 if (chunk_len == 1)
783 //DEBUGF("need 64bit support\n");
784 return 0;
786 chunk_id = stream_read_uint32(qtmovie.stream);
788 //DEBUGF("Found a chunk %c%c%c%c, length=%d\n",SPLITFOURCC(chunk_id),chunk_len);
789 switch (chunk_id)
791 case MAKEFOURCC('f','t','y','p'):
792 read_chunk_ftyp(&qtmovie, chunk_len);
793 break;
794 case MAKEFOURCC('m','o','o','v'):
795 if (!read_chunk_moov(&qtmovie, chunk_len)) {
796 return 0;
798 break;
799 case MAKEFOURCC('m','d','a','t'):
800 /* There can be empty mdats before the real one. If so, skip them */
801 if (chunk_len == 8)
802 break;
803 read_chunk_mdat(&qtmovie, chunk_len);
804 qtmovie.res->mdat_offset=stream_tell(qtmovie.stream);
805 /* If we've already seen the format, assume there's nothing
806 interesting after the mdat chunk (the file is "streamable").
807 This avoids having to seek, which might cause rebuffering. */
808 if(qtmovie.res->format > 0)
809 return 1;
810 stream_skip(qtmovie.stream, chunk_len - 8);
811 break;
813 /* these following atoms can be skipped !!!! */
814 case MAKEFOURCC('f','r','e','e'):
815 stream_skip(qtmovie.stream, chunk_len - 8);
816 break;
817 default:
818 //DEBUGF("(top) unknown chunk id: %c%c%c%c\n",SPLITFOURCC(chunk_id));
819 return 0;
823 return 0;