]> git.sesse.net Git - ffmpeg/blob - libavformat/mov.c
renamed libav to libavformat
[ffmpeg] / libavformat / mov.c
1 /*
2  * MOV decoder.
3  * Copyright (c) 2001 Fabrice Bellard.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include "avformat.h"
20 #include "avi.h"
21
22 #ifdef CONFIG_ZLIB
23 #include <zlib.h>
24 #endif
25
26 /*
27  * First version by Francois Revol revol@free.fr
28  * 
29  * Features and limitations:
30  * - reads most of the QT files I have (at least the structure), 
31  *   the exceptions are .mov with zlib compressed headers ('cmov' section). It shouldn't be hard to implement.
32  *   FIXED, Francois Revol, 07/17/2002
33  * - ffmpeg has nearly none of the usual QuickTime codecs,
34  *   although I succesfully dumped raw and mp3 audio tracks off .mov files.
35  *   Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html
36  * - .mp4 parsing is still hazardous, although the format really is QuickTime with some minor changes
37  *   (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at
38  *   http://mpeg.telecomitalialab.com/faq.htm
39  * - the code is quite ugly... maybe I won't do it recursive next time :-)
40  * 
41  * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/
42  * when coding this :) (it's a writer anyway)
43  * 
44  * Reference documents:
45  * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
46  * Apple:
47  *  http://developer.apple.com/techpubs/quicktime/qtdevdocs/QTFF/qtff.html
48  *  http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf
49  * QuickTime is a trademark of Apple (AFAIK :))
50  */
51
52 //#define DEBUG
53
54 /* allows chunk splitting - should work now... */
55 /* in case you can't read a file, try commenting */
56 #define MOV_SPLIT_CHUNKS
57
58 #ifdef DEBUG
59 /*
60  * XXX: static sux, even more in a multithreaded environment...
61  * Avoid them. This is here just to help debugging.
62  */
63 static int debug_indent = 0;
64 void print_atom(const char *str, UINT32 type, UINT64 offset, UINT64 size)
65 {
66     unsigned int tag, i;
67     tag = (unsigned int) type;
68     i=debug_indent;
69     if(tag == 0) tag = MKTAG('N', 'U', 'L', 'L');
70     while(i--)
71         printf("|");
72     printf("parse:");
73     printf(" %s: tag=%c%c%c%c offset=0x%x size=0x%x\n",
74            str, tag & 0xff,
75            (tag >> 8) & 0xff,
76            (tag >> 16) & 0xff,
77            (tag >> 24) & 0xff,
78            (unsigned int)offset,
79            (unsigned int)size);
80 }
81 #endif
82
83 /* some streams in QT (and in MP4 mostly) aren't either video nor audio */
84 /* so we first list them as this, then clean up the list of streams we give back, */
85 /* getting rid of these */
86 #define CODEC_TYPE_MOV_OTHER 2
87
88 static const CodecTag mov_video_tags[] = {
89 /*  { CODEC_ID_, MKTAG('c', 'v', 'i', 'd') }, *//* Cinepak */
90 /*  { CODEC_ID_JPEG, MKTAG('j', 'p', 'e', 'g') }, *//* JPEG */
91 /*  { CODEC_ID_H263, MKTAG('r', 'a', 'w', ' ') }, *//* Uncompressed RGB */
92 /*  { CODEC_ID_H263, MKTAG('Y', 'u', 'v', '2') }, *//* Uncompressed YUV422 */
93 /* Graphics */
94 /* Animation */
95 /* Apple video */
96 /* Kodak Photo CD */
97     { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, /* PhotoJPEG */
98     { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */
99     { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */
100     { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'b') }, /* Motion-JPEG (format B) */
101 /*    { CODEC_ID_GIF, MKTAG('g', 'i', 'f', ' ') }, *//* embedded gif files as frames (usually one "click to play movie" frame) */
102 /* Sorenson video */
103     { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') }, /* Sorenson Video v1 */
104     { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') }, /* Sorenson Video v1 */
105     { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', 'i') }, /* Sorenson Video v1 (from QT specs)*/
106     { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
107     { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') }, /* OpenDiVX *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */
108 /*    { CODEC_ID_, MKTAG('I', 'V', '5', '0') }, *//* Indeo 5.0 */
109     { CODEC_ID_H263, MKTAG('h', '2', '6', '3') }, /* H263 */
110     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */
111     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */
112     { 0, 0 }, 
113 };
114
115 static const CodecTag mov_audio_tags[] = {
116 /*    { CODEC_ID_PCM_S16BE, MKTAG('N', 'O', 'N', 'E') }, *//* uncompressed */
117     { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, /* 16 bits */
118     { CODEC_ID_PCM_S8, MKTAG('t', 'w', 'o', 's') }, /* 8 bits */
119     { CODEC_ID_PCM_U8, 0x20776172 }, /* 8 bits unsigned */
120     { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, /*  */
121     { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, /*  */
122     { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, /*  */
123     { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') }, /* IMA-4 ADPCM */
124     { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') }, /* Macintosh Audio Compression and Expansion 3:1 */
125     { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') }, /* Macintosh Audio Compression and Expansion 6:1 */
126
127     { CODEC_ID_MP2, MKTAG('.', 'm', 'p', '3') }, /* MPEG layer 3 */ /* sample files at http://www.3ivx.com/showcase.html use this tag */
128     { CODEC_ID_MP2, 0x6D730055 }, /* MPEG layer 3 */
129     { CODEC_ID_MP2, 0x5500736D }, /* MPEG layer 3 *//* XXX: check endianness */
130 /*    { CODEC_ID_OGG_VORBIS, MKTAG('O', 'g', 'g', 'S') }, *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */
131 /* MP4 tags */
132 /*    { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') }, *//* MPEG 4 AAC or audio ? */
133                                                      /* The standard for mpeg4 audio is still not normalised AFAIK anyway */
134     { 0, 0 }, 
135 };
136
137 /* the QuickTime file format is quite convoluted...
138  * it has lots of index tables, each indexing something in another one...
139  * Here we just use what is needed to read the chunks
140  */
141
142 typedef struct MOV_sample_to_chunk_tbl {
143     long first;
144     long count;
145     long id;
146 } MOV_sample_to_chunk_tbl;
147
148 typedef struct MOVStreamContext {
149     int ffindex; /* the ffmpeg stream id */
150     int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */
151     long next_chunk;
152     long chunk_count;
153     INT64 *chunk_offsets;
154     long sample_to_chunk_sz;
155     MOV_sample_to_chunk_tbl *sample_to_chunk;
156     long sample_to_chunk_index;
157     long sample_size;
158     long sample_count;
159     long *sample_sizes;
160     long time_scale;
161     long current_sample;
162     long left_in_chunk; /* how many samples before next chunk */
163     /* specific MPEG4 header which is added at the beginning of the stream */
164     int header_len;
165     uint8_t *header_data;
166 } MOVStreamContext;
167
168 typedef struct MOVContext {
169     int mp4; /* set to 1 as soon as we are sure that the file is an .mp4 file (even some header parsing depends on this) */
170     AVFormatContext *fc;
171     long time_scale;
172     int found_moov; /* when both 'moov' and 'mdat' sections has been found */
173     int found_mdat; /* we suppose we have enough data to read the file */
174     INT64 mdat_size;
175     INT64 mdat_offset;
176     int total_streams;
177     /* some streams listed here aren't presented to the ffmpeg API, since they aren't either video nor audio
178      * but we need the info to be able to skip data from those streams in the 'mdat' section
179      */
180     MOVStreamContext *streams[MAX_STREAMS];
181     
182     INT64 next_chunk_offset;
183     int partial; /* != 0 : there is still to read in the current chunk (=id of the stream + 1) */
184 } MOVContext;
185
186
187 struct MOVParseTableEntry;
188
189 /* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */
190
191 /* those functions parse an atom */
192 /* return code:
193  1: found what I wanted, exit
194  0: continue to parse next atom
195  -1: error occured, exit
196  */
197 typedef int (*mov_parse_function)(const struct MOVParseTableEntry *parse_table,
198                                   ByteIOContext *pb,
199                                   UINT32 atom_type,
200                                   INT64 atom_offset, /* after the size and type field (and eventually the extended size) */
201                                   INT64 atom_size, /* total size (excluding the size and type fields) */
202                                   void *param);
203
204 /* links atom IDs to parse functions */
205 typedef struct MOVParseTableEntry {
206     UINT32 type;
207     mov_parse_function func;
208 } MOVParseTableEntry;
209
210 static int parse_leaf(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
211 {
212 #ifdef DEBUG
213     print_atom("leaf", atom_type, atom_offset, atom_size);
214 #endif
215     if(atom_size>1)
216         url_fskip(pb, atom_size);
217 /*        url_seek(pb, atom_offset+atom_size, SEEK_SET); */
218     return 0;
219 }
220
221
222 static int parse_default(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
223 {
224     UINT32 type, foo=0;
225     UINT64 offset, size;
226     UINT64 total_size = 0;
227     int i;
228     int err = 0;
229     foo=0;
230 #ifdef DEBUG
231     print_atom("default", atom_type, atom_offset, atom_size);
232     debug_indent++;
233 #endif
234     
235     offset = atom_offset;
236
237     if(atom_size < 0)
238         atom_size = 0x0FFFFFFFFFFFFFFF;
239     while((total_size < atom_size) && !url_feof(pb) && !err) {
240         size=atom_size;
241         type=0L;
242         if(atom_size >= 8) {
243             size = get_be32(pb);
244             type = get_le32(pb);
245         }
246         total_size += 8;
247         offset+=8;
248 //        printf("type: %08lx  sz: %08lx", type, size);
249         if(size == 1) { /* 64 bit extended size */
250             size = get_be64(pb);
251             offset+=8;
252             total_size+=8;
253             size-=8;
254         }
255         if(size == 0)
256             size = atom_size - total_size;
257         size-=8;
258         for(i=0; parse_table[i].type != 0L && parse_table[i].type != type; i++);
259         
260 //        printf(" i=%ld\n", i);
261         if (parse_table[i].type == 0) { /* skip leaf atoms data */
262 //            url_seek(pb, atom_offset+atom_size, SEEK_SET);
263 #ifdef DEBUG
264             print_atom("unknown", type, offset, size);
265 #endif
266             url_fskip(pb, size);
267         } else
268             err = (parse_table[i].func)(parse_table, pb, type, offset, size, param);
269
270         offset+=size;
271         total_size+=size;
272     }
273
274 #ifdef DEBUG
275     debug_indent--;
276 #endif
277     return err;
278 }
279
280 static int parse_mvhd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
281 {
282     MOVContext *c;
283 #ifdef DEBUG
284     print_atom("mvhd", atom_type, atom_offset, atom_size);
285 #endif
286     c = (MOVContext *)param;
287
288     get_byte(pb); /* version */
289     get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
290
291     get_be32(pb); /* creation time */
292     get_be32(pb); /* modification time */
293     c->time_scale = get_be32(pb); /* time scale */
294 #ifdef DEBUG
295     printf("time scale = %li\n", c->time_scale);
296 #endif
297     get_be32(pb); /* duration */
298     get_be32(pb); /* preferred scale */
299     
300     get_be16(pb); /* preferred volume */
301
302     url_fskip(pb, 10); /* reserved */
303
304     url_fskip(pb, 36); /* display matrix */
305
306     get_be32(pb); /* preview time */
307     get_be32(pb); /* preview duration */
308     get_be32(pb); /* poster time */
309     get_be32(pb); /* selection time */
310     get_be32(pb); /* selection duration */
311     get_be32(pb); /* current time */
312     get_be32(pb); /* next track ID */
313     
314     return 0;
315 }
316
317 /* this atom should contain all header atoms */
318 static int parse_moov(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
319 {
320     int err;
321     MOVContext *c;
322 #ifdef DEBUG
323     print_atom("moov", atom_type, atom_offset, atom_size);
324 #endif
325     c = (MOVContext *)param;
326
327     err = parse_default(parse_table, pb, atom_type, atom_offset, atom_size, param);
328     /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */
329     /* so we don't parse the whole file if over a network */
330     c->found_moov=1;
331     if(c->found_mdat)
332         return 1; /* found both, just go */
333     return 0; /* now go for mdat */
334 }
335
336 /* this atom contains actual media data */
337 static int parse_mdat(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
338 {
339     MOVContext *c;
340 #ifdef DEBUG
341     print_atom("mdat", atom_type, atom_offset, atom_size);
342 #endif
343     c = (MOVContext *)param;
344
345     if(atom_size == 0) /* wrong one (MP4) */
346         return 0;
347     c->found_mdat=1;
348     c->mdat_offset = atom_offset;
349     c->mdat_size = atom_size;
350     if(c->found_moov)
351         return 1; /* found both, just go */
352     url_fskip(pb, atom_size);
353     return 0; /* now go for moov */
354 }
355
356 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */
357 /* like the files created with Adobe Premiere 5.0, for samples see */
358 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */
359 static int parse_wide(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
360 {
361     int err;
362     UINT32 type;
363 #ifdef DEBUG
364     print_atom("wide", atom_type, atom_offset, atom_size);
365     debug_indent++;
366 #endif
367     if (atom_size < 8)
368         return 0; /* continue */
369     if (get_be32(pb) != 0) { /* 0 sized mdat atom... use the 'wide' atom size */
370         url_fskip(pb, atom_size - 4);
371         return 0;
372     }
373     type = get_le32(pb);
374     if (type != MKTAG('m', 'd', 'a', 't')) {
375         url_fskip(pb, atom_size - 8);
376         return 0;
377     }
378     err = parse_mdat(parse_table, pb, type, atom_offset + 8, atom_size - 8, param);
379 #ifdef DEBUG
380     debug_indent--;
381 #endif
382     return err;
383 }
384
385 static int parse_trak(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
386 {
387     MOVContext *c;
388     AVStream *st;
389     MOVStreamContext *sc;
390 #ifdef DEBUG
391     print_atom("trak", atom_type, atom_offset, atom_size);
392 #endif
393
394     c = (MOVContext *)param;
395     st = av_new_stream(c->fc, c->fc->nb_streams);
396     if (!st) return -2;
397     sc = av_malloc(sizeof(MOVStreamContext));
398     sc->sample_to_chunk_index = -1;
399     st->priv_data = sc;
400     st->codec.codec_type = CODEC_TYPE_MOV_OTHER;
401     c->streams[c->fc->nb_streams-1] = sc;
402     return parse_default(parse_table, pb, atom_type, atom_offset, atom_size, param);
403 }
404
405 static int parse_tkhd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
406 {
407     MOVContext *c;
408     AVStream *st;
409 #ifdef DEBUG
410     print_atom("tkhd", atom_type, atom_offset, atom_size);
411 #endif
412
413     c = (MOVContext *)param;
414     st = c->fc->streams[c->fc->nb_streams-1];
415     
416     get_byte(pb); /* version */
417
418     get_byte(pb); get_byte(pb);
419     get_byte(pb); /* flags */
420     /*
421     MOV_TRACK_ENABLED 0x0001
422     MOV_TRACK_IN_MOVIE 0x0002
423     MOV_TRACK_IN_PREVIEW 0x0004
424     MOV_TRACK_IN_POSTER 0x0008
425     */
426
427     get_be32(pb); /* creation time */
428     get_be32(pb); /* modification time */
429     st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/
430     get_be32(pb); /* reserved */
431     get_be32(pb); /* duration */
432     get_be32(pb); /* reserved */
433     get_be32(pb); /* reserved */
434     
435     get_be16(pb); /* layer */
436     get_be16(pb); /* alternate group */
437     get_be16(pb); /* volume */
438     get_be16(pb); /* reserved */
439
440     url_fskip(pb, 36); /* display matrix */
441
442     /* those are fixed-point */
443     st->codec.width = get_be32(pb) >> 16; /* track width */
444     st->codec.height = get_be32(pb) >> 16; /* track height */
445     
446     return 0;
447 }
448
449 static int parse_mdhd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
450 {
451     MOVContext *c;
452     AVStream *st;
453 #ifdef DEBUG
454     print_atom("mdhd", atom_type, atom_offset, atom_size);
455 #endif
456
457     c = (MOVContext *)param;
458     st = c->fc->streams[c->fc->nb_streams-1];
459     
460     get_byte(pb); /* version */
461
462     get_byte(pb); get_byte(pb);
463     get_byte(pb); /* flags */
464
465     get_be32(pb); /* creation time */
466     get_be32(pb); /* modification time */
467
468     c->streams[c->total_streams]->time_scale = get_be32(pb);
469
470 #ifdef DEBUG
471     printf("track[%i].time_scale = %li\n", c->fc->nb_streams-1, c->streams[c->total_streams]->time_scale); /* time scale */
472 #endif
473     get_be32(pb); /* duration */
474
475     get_be16(pb); /* language */
476     get_be16(pb); /* quality */
477     
478     return 0;
479 }
480
481 static int parse_hdlr(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
482 {
483     MOVContext *c;
484     int len = 0;
485     char *buf;
486     UINT32 type;
487     AVStream *st;
488     UINT32 ctype;
489 #ifdef DEBUG
490     print_atom("hdlr", atom_type, atom_offset, atom_size);
491 #endif
492     c = (MOVContext *)param;
493     st = c->fc->streams[c->fc->nb_streams-1];
494
495     get_byte(pb); /* version */
496     get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
497
498     /* component type */
499     ctype = get_le32(pb);
500     type = get_le32(pb); /* component subtype */
501
502 #ifdef DEBUG
503     printf("ctype= %c%c%c%c (0x%08lx)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], (long) ctype);
504     printf("stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]);
505 #endif
506 #ifdef DEBUG
507 /* XXX: yeah this is ugly... */
508     if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */
509         if(type == MKTAG('v', 'i', 'd', 'e'))
510             puts("hdlr: vide");
511         else if(type == MKTAG('s', 'o', 'u', 'n'))
512             puts("hdlr: soun");
513     } else if(ctype == 0) { /* MP4 */
514         if(type == MKTAG('v', 'i', 'd', 'e'))
515             puts("hdlr: vide");
516         else if(type == MKTAG('s', 'o', 'u', 'n'))
517             puts("hdlr: soun");
518         else if(type == MKTAG('o', 'd', 's', 'm'))
519             puts("hdlr: odsm");
520         else if(type == MKTAG('s', 'd', 's', 'm'))
521             puts("hdlr: sdsm");
522     } else puts("hdlr: meta");
523 #endif
524
525     if(ctype == MKTAG('m', 'h', 'l', 'r')) { /* MOV */
526         /* helps parsing the string hereafter... */
527         c->mp4 = 0;
528         if(type == MKTAG('v', 'i', 'd', 'e'))
529             st->codec.codec_type = CODEC_TYPE_VIDEO;
530         else if(type == MKTAG('s', 'o', 'u', 'n'))
531             st->codec.codec_type = CODEC_TYPE_AUDIO;
532     } else if(ctype == 0) { /* MP4 */
533         /* helps parsing the string hereafter... */
534         c->mp4 = 1;
535         if(type == MKTAG('v', 'i', 'd', 'e'))
536             st->codec.codec_type = CODEC_TYPE_VIDEO;
537         else if(type == MKTAG('s', 'o', 'u', 'n'))
538             st->codec.codec_type = CODEC_TYPE_AUDIO;
539     }
540     get_be32(pb); /* component  manufacture */
541     get_be32(pb); /* component flags */
542     get_be32(pb); /* component flags mask */
543
544     if(atom_size <= 24)
545         return 0; /* nothing left to read */
546     /* XXX: MP4 uses a C string, not a pascal one */
547     /* component name */
548
549     if(c->mp4) {
550         /* .mp4: C string */
551         while(get_byte(pb) && (++len < (atom_size - 24)));
552     } else {
553         /* .mov: PASCAL string */
554         len = get_byte(pb);
555         buf = av_malloc(len+1);
556         get_buffer(pb, buf, len);
557         buf[len] = '\0';
558 #ifdef DEBUG
559         printf("**buf='%s'\n", buf);
560 #endif
561         av_free(buf);
562     }
563 #if 0
564     len = get_byte(pb);
565     /* XXX: use a better heuristic */
566     if(len < 32) {
567         /* assume that it is a Pascal like string */
568         buf = av_malloc(len+1);
569         get_buffer(pb, buf, len);
570         buf[len] = '\0';
571 #ifdef DEBUG
572         printf("**buf='%s'\n", buf);
573 #endif
574         av_free(buf);
575     } else {
576         /* MP4 string */
577         for(;;) {
578             if (len == 0)
579                 break;
580             len = get_byte(pb);
581         }
582     }
583 #endif
584     
585     return 0;
586 }
587
588 static int mp4_read_descr_len(ByteIOContext *pb)
589 {
590     int c, len, count;
591
592     len = 0;
593     count = 0;
594     for(;;) {
595         c = get_byte(pb);
596         len = (len << 7) | (c & 0x7f);
597         if ((c & 0x80) == 0)
598             break;
599         if (++count == 4)
600             break;
601     }
602     return len;
603 }
604
605 static int mp4_read_descr(ByteIOContext *pb, int *tag)
606 {
607     int len;
608     *tag = get_byte(pb);
609     len = mp4_read_descr_len(pb);
610 #ifdef DEBUG
611     printf("MPEG4 description: tag=0x%02x len=%d\n", *tag, len);
612 #endif
613     return len;
614 }
615
616 static int parse_stsd(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
617 {
618     MOVContext *c;
619     int entries, size, samp_sz, frames_per_sample, id;
620     UINT32 format;
621     AVStream *st;
622     MOVStreamContext *sc;
623 #ifdef DEBUG
624     print_atom("stsd", atom_type, atom_offset, atom_size);
625 #endif
626     c = (MOVContext *)param;
627     st = c->fc->streams[c->fc->nb_streams-1];
628     sc = (MOVStreamContext *)st->priv_data;
629
630     get_byte(pb); /* version */
631     get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
632
633     entries = get_be32(pb);
634
635     while(entries--) {
636         size = get_be32(pb); /* size */
637         format = get_le32(pb); /* data format */
638         
639         get_be32(pb); /* reserved */
640         get_be16(pb); /* reserved */
641         get_be16(pb); /* index */
642
643         /* for MPEG4: set codec type by looking for it */
644         id = codec_get_id(mov_video_tags, format);
645         if (id >= 0) {
646             AVCodec *codec;
647             codec = avcodec_find_decoder(id);
648             if (codec)
649                 st->codec.codec_type = codec->type;
650         }
651 #ifdef DEBUG
652         printf("size=%d 4CC= %c%c%c%c codec_type=%d\n", 
653                size, 
654                (format >> 0) & 0xff,
655                (format >> 8) & 0xff,
656                (format >> 16) & 0xff,
657                (format >> 24) & 0xff,
658                st->codec.codec_type);
659 #endif
660         if(st->codec.codec_type==CODEC_TYPE_VIDEO) {
661             st->codec.codec_tag = format;
662             st->codec.codec_id = codec_get_id(mov_video_tags, format);
663             get_be16(pb); /* version */
664             get_be16(pb); /* revision level */
665             get_be32(pb); /* vendor */
666             get_be32(pb); /* temporal quality */
667             get_be32(pb); /* spacial quality */
668             st->codec.width = get_be16(pb); /* width */
669             st->codec.height = get_be16(pb); /* height */
670 #if 1
671             if (st->codec.codec_id == CODEC_ID_MPEG4) {
672                 /* in some MPEG4 the width/height are not correct, so
673                    we ignore this info */
674                 st->codec.width = 0;
675                 st->codec.height = 0;
676             }
677 #endif
678             get_be32(pb); /* horiz resolution */
679             get_be32(pb); /* vert resolution */
680             get_be32(pb); /* data size, always 0 */
681             frames_per_sample = get_be16(pb); /* frame per samples */
682 #ifdef DEBUG
683             printf("frames/samples = %d\n", frames_per_sample);
684 #endif
685             url_fskip(pb, 32); /* codec name */
686
687             get_be16(pb); /* depth */
688             get_be16(pb); /* colortable id */
689             
690             st->codec.frame_rate = 25 * FRAME_RATE_BASE;
691             
692             size -= (16+8*4+2+32+2*2);
693             while (size >= 8) {
694                 int atom_size, atom_type;
695                 INT64 start_pos;
696                 
697                 atom_size = get_be32(pb);
698                 atom_type = get_le32(pb);
699                 size -= 8;
700 #ifdef DEBUG
701                 printf("VIDEO: atom_type=%c%c%c%c atom_size=%d size_left=%d\n", 
702                        (atom_type >> 0) & 0xff,
703                        (atom_type >> 8) & 0xff,
704                        (atom_type >> 16) & 0xff,
705                        (atom_type >> 24) & 0xff,
706                        atom_size, size);
707 #endif
708                 start_pos = url_ftell(pb);
709
710                 switch(atom_type) {
711                 case MKTAG('e', 's', 'd', 's'):
712                     {
713                         int tag, len;
714                         /* Well, broken but suffisant for some MP4 streams */
715                         get_be32(pb); /* version + flags */
716                         len = mp4_read_descr(pb, &tag);
717                         if (tag == 0x03) {
718                             /* MP4ESDescrTag */
719                             get_be16(pb); /* ID */
720                             get_byte(pb); /* priority */
721                             len = mp4_read_descr(pb, &tag);
722                             if (tag != 0x04)
723                                 goto fail;
724                             /* MP4DecConfigDescrTag */
725                             get_byte(pb); /* objectTypeId */
726                             get_be32(pb); /* streamType + buffer size */
727                             get_be32(pb); /* max bit rate */
728                             get_be32(pb); /* avg bit rate */
729                             len = mp4_read_descr(pb, &tag);
730                             if (tag != 0x05)
731                                 goto fail;
732                             /* MP4DecSpecificDescrTag */
733 #ifdef DEBUG
734                             printf("Specific MPEG4 header len=%d\n", len);
735 #endif
736                             sc->header_data = av_mallocz(len);
737                             if (sc->header_data) {
738                                 get_buffer(pb, sc->header_data, len);
739                                 sc->header_len = len;
740                             }
741                         }
742                         /* in any case, skip garbage */
743                     }
744                     break;
745                 default:
746                     break;
747                 }
748             fail:
749                 url_fskip(pb, (atom_size - 8) - 
750                           ((url_ftell(pb) - start_pos)));
751                 size -= atom_size - 8;
752             }
753             if (size > 0) {
754                 /* unknown extension */
755                 url_fskip(pb, size);
756             }
757         } else {
758             st->codec.codec_tag = format;
759
760             get_be16(pb); /* version */
761             get_be16(pb); /* revision level */
762             get_be32(pb); /* vendor */
763
764             st->codec.channels = get_be16(pb);/* channel count */
765             samp_sz = get_be16(pb); /* sample size */
766 #ifdef DEBUG
767             if(samp_sz != 16)
768                 puts("!!! stsd: audio sample size is not 16 bit !");
769 #endif            
770             st->codec.codec_id = codec_get_id(mov_audio_tags, format);
771             /* handle specific s8 codec */
772             if (st->codec.codec_id == CODEC_ID_PCM_S16BE && samp_sz == 8)
773             st->codec.codec_id = CODEC_ID_PCM_S8;
774
775             get_be16(pb); /* compression id = 0*/
776             get_be16(pb); /* packet size = 0 */
777             
778             st->codec.sample_rate = ((get_be32(pb) >> 16));
779             st->codec.bit_rate = 0;
780 #if 0
781
782             get_be16(pb); get_be16(pb); /*  */
783             get_be16(pb); /*  */
784             get_be16(pb); /*  */
785             get_be16(pb); /*  */
786             get_be16(pb); /*  */
787 #endif            
788             if(size > 16)
789                 url_fskip(pb, size-(16+20));
790         }
791     }
792 /*
793     if(len) {
794     buf = av_malloc(len+1);
795         get_buffer(pb, buf, len);
796         buf[len] = '\0';
797         puts(buf);
798         av_free(buf);
799     }
800 */
801     return 0;
802 }
803
804 static int parse_stco(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
805 {
806     MOVContext *c;
807     int entries, i;
808     AVStream *st;
809     MOVStreamContext *sc;
810 #ifdef DEBUG
811     print_atom("stco", atom_type, atom_offset, atom_size);
812 #endif
813     c = (MOVContext *)param;
814     st = c->fc->streams[c->fc->nb_streams-1];
815     sc = (MOVStreamContext *)st->priv_data;
816     
817     get_byte(pb); /* version */
818     get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
819
820     entries = get_be32(pb);
821     sc->chunk_count = entries;
822     sc->chunk_offsets = av_malloc(entries * sizeof(INT64));
823     if(atom_type == MKTAG('s', 't', 'c', 'o')) {
824         for(i=0; i<entries; i++) {
825             sc->chunk_offsets[i] = get_be32(pb);
826         }
827     } else if(atom_type == MKTAG('c', 'o', '6', '4')) {
828         for(i=0; i<entries; i++) {
829             sc->chunk_offsets[i] = get_be64(pb);
830         }
831     } else
832         return -1;
833 #ifdef DEBUG
834 /*
835     for(i=0; i<entries; i++) {
836         printf("chunk offset=0x%Lx\n", sc->chunk_offsets[i]);
837     }
838 */
839 #endif
840     return 0;
841 }
842
843 static int parse_stsc(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
844 {
845     MOVContext *c;
846     int entries, i;
847     AVStream *st;
848     MOVStreamContext *sc;
849 #ifdef DEBUG
850     print_atom("stsc", atom_type, atom_offset, atom_size);
851 #endif
852     c = (MOVContext *)param;
853     st = c->fc->streams[c->fc->nb_streams-1];
854     sc = (MOVStreamContext *)st->priv_data;
855     
856     get_byte(pb); /* version */
857     get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
858
859     entries = get_be32(pb);
860 #ifdef DEBUG
861 printf("track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries);
862 #endif
863     sc->sample_to_chunk_sz = entries;
864     sc->sample_to_chunk = av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl));
865     for(i=0; i<entries; i++) {
866         sc->sample_to_chunk[i].first = get_be32(pb);
867         sc->sample_to_chunk[i].count = get_be32(pb);
868         sc->sample_to_chunk[i].id = get_be32(pb);
869 #ifdef DEBUG
870 /*        printf("sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id); */
871 #endif
872     }
873     return 0;
874 }
875
876 static int parse_stsz(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
877 {
878     MOVContext *c;
879     int entries, i;
880     AVStream *st;
881     MOVStreamContext *sc;
882 #ifdef DEBUG
883     print_atom("stsz", atom_type, atom_offset, atom_size);
884 #endif
885     c = (MOVContext *)param;
886     st = c->fc->streams[c->fc->nb_streams-1];
887     sc = (MOVStreamContext *)st->priv_data;
888     
889     get_byte(pb); /* version */
890     get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
891     
892     sc->sample_size = get_be32(pb);
893     entries = get_be32(pb);
894     sc->sample_count = entries;
895 #ifdef DEBUG
896     printf("sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count);
897 #endif
898     if(sc->sample_size)
899         return 0; /* there isn't any table following */
900     sc->sample_sizes = av_malloc(entries * sizeof(long));
901     for(i=0; i<entries; i++) {
902         sc->sample_sizes[i] = get_be32(pb);
903 #ifdef DEBUG
904 /*        printf("sample_sizes[]=%ld\n", sc->sample_sizes[i]); */
905 #endif
906     }
907     return 0;
908 }
909
910 static int parse_stts(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
911 {
912     MOVContext *c;
913     int entries, i;
914     AVStream *st;
915     MOVStreamContext *sc;
916 #ifdef DEBUG
917     print_atom("stts", atom_type, atom_offset, atom_size);
918 #endif
919     c = (MOVContext *)param;
920     st = c->fc->streams[c->fc->nb_streams-1];
921     sc = (MOVStreamContext *)st->priv_data;
922
923     get_byte(pb); /* version */
924     get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
925     entries = get_be32(pb);
926 #ifdef DEBUG
927 printf("track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries);
928 #endif
929     for(i=0; i<entries; i++) {
930         int sample_duration;
931
932         get_be32(pb);
933         sample_duration = get_be32(pb);
934
935         if (!i && st->codec.codec_type==CODEC_TYPE_VIDEO) {
936             st->codec.frame_rate = FRAME_RATE_BASE * c->streams[c->total_streams]->time_scale;
937             if (sample_duration)
938                 st->codec.frame_rate /= sample_duration;
939 #ifdef DEBUG
940             printf("VIDEO FRAME RATE= %i (sd= %i)\n", st->codec.frame_rate, sample_duration);
941 #endif
942         }
943     }
944     return 0;
945 }
946
947 #ifdef CONFIG_ZLIB
948 static int null_read_packet(void *opaque, UINT8 *buf, int buf_size)
949 {
950     return -1;
951 }
952
953 static int parse_cmov(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param)
954 {
955     MOVContext *c;
956     ByteIOContext ctx;
957     char *cmov_data;
958     unsigned char *moov_data; /* uncompressed data */
959     long cmov_len, moov_len;
960     int ret;
961 #ifdef DEBUG
962     print_atom("cmov", atom_type, atom_offset, atom_size);
963 #endif
964     c = (MOVContext *)param;
965
966     get_be32(pb); /* dcom atom */
967     if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' ))
968         return -1;
969     if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) {
970         puts("unknown compression for cmov atom !");
971         return -1;
972     }
973     get_be32(pb); /* cmvd atom */
974     if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' ))
975         return -1;
976     moov_len = get_be32(pb); /* uncompressed size */
977     cmov_len = atom_size - 6 * 4;
978     
979     cmov_data = av_malloc(cmov_len);
980     if (!cmov_data)
981         return -1;
982     moov_data = av_malloc(moov_len);
983     if (!moov_data) {
984         av_free(cmov_data);
985         return -1;
986     }
987     get_buffer(pb, cmov_data, cmov_len);
988     if(uncompress (moov_data, &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK)
989         return -1;
990     if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, null_read_packet, NULL, NULL) != 0)
991         return -1;
992     ctx.buf_end = ctx.buffer + moov_len;
993     ret = parse_default(parse_table, &ctx, MKTAG( 'm', 'o', 'o', 'v' ), 0, moov_len, param);
994     av_free(moov_data);
995     av_free(cmov_data);
996     return ret;
997 }
998 #endif
999
1000 static const MOVParseTableEntry mov_default_parse_table[] = {
1001 /* mp4 atoms */
1002 { MKTAG( 'm', 'p', '4', 'a' ), parse_default },
1003 { MKTAG( 'c', 'o', '6', '4' ), parse_stco },
1004 { MKTAG( 's', 't', 'c', 'o' ), parse_stco },
1005 { MKTAG( 'c', 'r', 'h', 'd' ), parse_default },
1006 { MKTAG( 'c', 't', 't', 's' ), parse_leaf },
1007 { MKTAG( 'c', 'p', 'r', 't' ), parse_default },
1008 { MKTAG( 'u', 'r', 'l', ' ' ), parse_leaf },
1009 { MKTAG( 'u', 'r', 'n', ' ' ), parse_leaf },
1010 { MKTAG( 'd', 'i', 'n', 'f' ), parse_default },
1011 { MKTAG( 'd', 'r', 'e', 'f' ), parse_leaf },
1012 { MKTAG( 's', 't', 'd', 'p' ), parse_default },
1013 { MKTAG( 'e', 's', 'd', 's' ), parse_default },
1014 { MKTAG( 'e', 'd', 't', 's' ), parse_default },
1015 { MKTAG( 'e', 'l', 's', 't' ), parse_leaf },
1016 { MKTAG( 'u', 'u', 'i', 'd' ), parse_default },
1017 { MKTAG( 'f', 'r', 'e', 'e' ), parse_leaf },
1018 { MKTAG( 'h', 'd', 'l', 'r' ), parse_hdlr },
1019 { MKTAG( 'h', 'm', 'h', 'd' ), parse_leaf },
1020 { MKTAG( 'h', 'i', 'n', 't' ), parse_leaf },
1021 { MKTAG( 'n', 'm', 'h', 'd' ), parse_leaf },
1022 { MKTAG( 'm', 'p', '4', 's' ), parse_default },
1023 { MKTAG( 'm', 'd', 'i', 'a' ), parse_default },
1024 { MKTAG( 'm', 'd', 'a', 't' ), parse_mdat },
1025 { MKTAG( 'm', 'd', 'h', 'd' ), parse_mdhd },
1026 { MKTAG( 'm', 'i', 'n', 'f' ), parse_default },
1027 { MKTAG( 'm', 'o', 'o', 'v' ), parse_moov },
1028 { MKTAG( 'm', 'v', 'h', 'd' ), parse_mvhd },
1029 { MKTAG( 'i', 'o', 'd', 's' ), parse_leaf },
1030 { MKTAG( 'o', 'd', 'h', 'd' ), parse_default },
1031 { MKTAG( 'm', 'p', 'o', 'd' ), parse_leaf },
1032 { MKTAG( 's', 't', 's', 'd' ), parse_stsd },
1033 { MKTAG( 's', 't', 's', 'z' ), parse_stsz },
1034 { MKTAG( 's', 't', 'b', 'l' ), parse_default },
1035 { MKTAG( 's', 't', 's', 'c' ), parse_stsc },
1036 { MKTAG( 's', 'd', 'h', 'd' ), parse_default },
1037 { MKTAG( 's', 't', 's', 'h' ), parse_default },
1038 { MKTAG( 's', 'k', 'i', 'p' ), parse_default },
1039 { MKTAG( 's', 'm', 'h', 'd' ), parse_leaf },
1040 { MKTAG( 'd', 'p', 'n', 'd' ), parse_leaf },
1041 { MKTAG( 's', 't', 's', 's' ), parse_leaf },
1042 { MKTAG( 's', 't', 't', 's' ), parse_stts },
1043 { MKTAG( 't', 'r', 'a', 'k' ), parse_trak },
1044 { MKTAG( 't', 'k', 'h', 'd' ), parse_tkhd },
1045 { MKTAG( 't', 'r', 'e', 'f' ), parse_default }, /* not really */
1046 { MKTAG( 'u', 'd', 't', 'a' ), parse_leaf },
1047 { MKTAG( 'v', 'm', 'h', 'd' ), parse_leaf },
1048 { MKTAG( 'm', 'p', '4', 'v' ), parse_default },
1049 /* extra mp4 */
1050 { MKTAG( 'M', 'D', 'E', 'S' ), parse_leaf },
1051 /* QT atoms */
1052 { MKTAG( 'c', 'h', 'a', 'p' ), parse_leaf },
1053 { MKTAG( 'c', 'l', 'i', 'p' ), parse_default },
1054 { MKTAG( 'c', 'r', 'g', 'n' ), parse_leaf },
1055 { MKTAG( 'k', 'm', 'a', 't' ), parse_leaf },
1056 { MKTAG( 'm', 'a', 't', 't' ), parse_default },
1057 { MKTAG( 'r', 'd', 'r', 'f' ), parse_leaf },
1058 { MKTAG( 'r', 'm', 'd', 'a' ), parse_default },
1059 { MKTAG( 'r', 'm', 'd', 'r' ), parse_leaf },
1060 //{ MKTAG( 'r', 'm', 'q', 'u' ), parse_leaf },
1061 { MKTAG( 'r', 'm', 'r', 'a' ), parse_default },
1062 { MKTAG( 's', 'c', 'p', 't' ), parse_leaf },
1063 { MKTAG( 's', 'y', 'n', 'c' ), parse_leaf },
1064 { MKTAG( 's', 's', 'r', 'c' ), parse_leaf },
1065 { MKTAG( 't', 'c', 'm', 'd' ), parse_leaf },
1066 { MKTAG( 'w', 'i', 'd', 'e' ), parse_wide }, /* place holder */
1067 #ifdef CONFIG_ZLIB
1068 { MKTAG( 'c', 'm', 'o', 'v' ), parse_cmov },
1069 #else
1070 { MKTAG( 'c', 'm', 'o', 'v' ), parse_leaf },
1071 #endif
1072 { 0L, parse_leaf }
1073 };
1074
1075 static void mov_free_stream_context(MOVStreamContext *sc)
1076 {
1077     if(sc) {
1078         av_free(sc->chunk_offsets);
1079         av_free(sc->sample_to_chunk);
1080         av_free(sc->header_data);
1081         av_free(sc);
1082     }
1083 }
1084
1085 static uint32_t to_tag(uint8_t *buf)
1086 {
1087     return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
1088 }
1089
1090 static uint32_t to_be32(uint8_t *buf)
1091 {
1092     return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1093 }
1094
1095 /* XXX: is it suffisant ? */
1096 static int mov_probe(AVProbeData *p)
1097 {
1098     unsigned int offset;
1099     uint32_t tag;
1100
1101     /* check file header */
1102     if (p->buf_size <= 12)
1103         return 0;
1104     offset = 0;
1105     for(;;) {
1106         /* ignore invalid offset */
1107         if ((offset + 8) > (unsigned int)p->buf_size)
1108             return 0;
1109         tag = to_tag(p->buf + offset + 4);
1110         switch(tag) {
1111         case MKTAG( 'm', 'o', 'o', 'v' ):
1112         case MKTAG( 'w', 'i', 'd', 'e' ):
1113         case MKTAG( 'f', 'r', 'e', 'e' ):
1114         case MKTAG( 'm', 'd', 'a', 't'):
1115             return AVPROBE_SCORE_MAX;
1116         case MKTAG( 'f', 't', 'y', 'p' ):
1117         case MKTAG( 's', 'k', 'i', 'p' ):            
1118             offset = to_be32(p->buf) + offset;
1119             break;
1120         default:
1121             /* unrecognized tag */
1122             return 0;
1123         }
1124     }
1125     return 0;
1126 }
1127
1128 static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap)
1129 {
1130     MOVContext *mov = s->priv_data;
1131     ByteIOContext *pb = &s->pb;
1132     int i, j, nb, err;
1133     INT64 size;
1134
1135     mov->fc = s;
1136 #if 0
1137     /* XXX: I think we should auto detect */
1138     if(s->iformat->name[1] == 'p')
1139         mov->mp4 = 1;
1140 #endif
1141     if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */
1142         size = url_filesize(url_fileno(pb));
1143     else
1144         size = 0x7FFFFFFFFFFFFFFF;
1145
1146 #ifdef DEBUG
1147     printf("filesz=%Ld\n", size);
1148 #endif
1149
1150     /* check MOV header */
1151     err = parse_default(mov_default_parse_table, pb, 0L, 0LL, size, mov);
1152     if(err<0 || (!mov->found_moov || !mov->found_mdat)) {
1153         puts("header not found !!!");
1154         exit(1);
1155     }
1156 #ifdef DEBUG
1157     printf("on_parse_exit_offset=%d\n", (int) url_ftell(pb));
1158 #endif
1159     /* some cleanup : make sure we are on the mdat atom */
1160     if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset))
1161         url_fseek(pb, mov->mdat_offset, SEEK_SET);
1162
1163     mov->next_chunk_offset = mov->mdat_offset; /* initialise reading */
1164
1165 #ifdef DEBUG
1166     printf("mdat_reset_offset=%d\n", (int) url_ftell(pb));
1167 #endif
1168
1169 #ifdef DEBUG
1170     printf("streams= %d\n", s->nb_streams);
1171 #endif
1172     mov->total_streams = nb = s->nb_streams;
1173     
1174 #if 1
1175     for(i=0; i<s->nb_streams;) {
1176         if(s->streams[i]->codec.codec_type == CODEC_TYPE_MOV_OTHER) {/* not audio, not video, delete */
1177             av_free(s->streams[i]);
1178             for(j=i+1; j<s->nb_streams; j++)
1179                 s->streams[j-1] = s->streams[j];
1180             s->nb_streams--;
1181         } else
1182             i++;
1183     }
1184     for(i=0; i<s->nb_streams;i++) {
1185         MOVStreamContext *sc;
1186         sc = (MOVStreamContext *)s->streams[i]->priv_data;
1187         sc->ffindex = i;
1188         sc->is_ff_stream = 1;
1189     }
1190 #endif
1191 #ifdef DEBUG
1192     printf("real streams= %d\n", s->nb_streams);
1193 #endif
1194     return 0;
1195 }
1196
1197 /* Yes, this is ugly... I didn't write the specs of QT :p */
1198 /* XXX:remove useless commented code sometime */
1199 static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
1200 {
1201     MOVContext *mov = s->priv_data;
1202     MOVStreamContext *sc;
1203     INT64 offset = 0x0FFFFFFFFFFFFFFF;
1204     int i;
1205     int st_id = 0, size;
1206     size = 0x0FFFFFFF;
1207     
1208 #ifdef MOV_SPLIT_CHUNKS
1209     if (mov->partial) {
1210         
1211         int idx;
1212
1213         st_id = mov->partial - 1;
1214         idx = mov->streams[st_id]->sample_to_chunk_index;
1215         if (idx < 0) return 0;
1216         size = mov->streams[st_id]->sample_sizes[mov->streams[st_id]->current_sample];
1217
1218         mov->streams[st_id]->current_sample++;
1219         mov->streams[st_id]->left_in_chunk--;
1220
1221         if(mov->streams[st_id]->left_in_chunk <= 0)
1222             mov->partial = 0;
1223         offset = mov->next_chunk_offset;
1224         /* extract the sample */
1225
1226         goto readchunk;
1227     }
1228 #endif
1229
1230 again:
1231     for(i=0; i<mov->total_streams; i++) {
1232         if((mov->streams[i]->next_chunk < mov->streams[i]->chunk_count)
1233         && (mov->streams[i]->chunk_offsets[mov->streams[i]->next_chunk] < offset)) {
1234             st_id = i;
1235             offset = mov->streams[i]->chunk_offsets[mov->streams[i]->next_chunk];
1236         }
1237     }
1238     mov->streams[st_id]->next_chunk++;
1239     if(offset==0x0FFFFFFFFFFFFFFF)
1240         return -1;
1241     
1242     if(mov->next_chunk_offset < offset) { /* some meta data */
1243         url_fskip(&s->pb, (offset - mov->next_chunk_offset));
1244         mov->next_chunk_offset = offset;
1245     }
1246
1247 //printf("chunk: [%i] %lli -> %lli\n", st_id, mov->next_chunk_offset, offset);
1248     if(!mov->streams[st_id]->is_ff_stream) {
1249         url_fskip(&s->pb, (offset - mov->next_chunk_offset));
1250         mov->next_chunk_offset = offset;
1251         offset = 0x0FFFFFFFFFFFFFFF;
1252         goto again;
1253     }
1254
1255     /* now get the chunk size... */
1256
1257     for(i=0; i<mov->total_streams; i++) {
1258         if((mov->streams[i]->next_chunk < mov->streams[i]->chunk_count)
1259         && ((mov->streams[i]->chunk_offsets[mov->streams[i]->next_chunk] - offset) < size)) {
1260             size = mov->streams[i]->chunk_offsets[mov->streams[i]->next_chunk] - offset;
1261         }
1262     }
1263 #ifdef MOV_SPLIT_CHUNKS
1264     /* split chunks into samples */
1265     if(mov->streams[st_id]->sample_size == 0) {
1266         int idx;
1267         idx = mov->streams[st_id]->sample_to_chunk_index;
1268         if ((idx + 1 < mov->streams[st_id]->sample_to_chunk_sz)
1269                && (mov->streams[st_id]->next_chunk >= mov->streams[st_id]->sample_to_chunk[idx + 1].first))
1270            idx++; 
1271         mov->streams[st_id]->sample_to_chunk_index = idx;
1272         if(idx >= 0 && mov->streams[st_id]->sample_to_chunk[idx].count != 1) {
1273             mov->partial = st_id+1;
1274             /* we'll have to get those samples before next chunk */
1275             mov->streams[st_id]->left_in_chunk = (mov->streams[st_id]->sample_to_chunk[idx].count) - 1;
1276             size = mov->streams[st_id]->sample_sizes[mov->streams[st_id]->current_sample];
1277         }
1278
1279         mov->streams[st_id]->current_sample++;
1280     }
1281 #endif
1282
1283 readchunk:
1284 //printf("chunk: [%i] %lli -> %lli (%i)\n", st_id, offset, offset + size, size);
1285     if(size == 0x0FFFFFFF)
1286         size = mov->mdat_size + mov->mdat_offset - offset;
1287     if(size < 0)
1288         return -1;
1289     if(size == 0)
1290         return -1;
1291     url_fseek(&s->pb, offset, SEEK_SET);
1292     sc = mov->streams[st_id];
1293     if (sc->header_len > 0) {
1294         av_new_packet(pkt, size + sc->header_len);
1295         memcpy(pkt->data, sc->header_data, sc->header_len);
1296         get_buffer(&s->pb, pkt->data + sc->header_len, size);
1297         /* free header */
1298         av_freep(&sc->header_data);
1299         sc->header_len = 0;
1300     } else {
1301         av_new_packet(pkt, size);
1302         get_buffer(&s->pb, pkt->data, pkt->size);
1303     }
1304     pkt->stream_index = sc->ffindex;
1305
1306 #ifdef DEBUG
1307 /*
1308     printf("Packet (%d, %d, %ld) ", pkt->stream_index, st_id, pkt->size);
1309     for(i=0; i<8; i++)
1310         printf("%02x ", pkt->data[i]);
1311     for(i=0; i<8; i++)
1312         printf("%c ", (pkt->data[i]) & 0x7F);
1313     puts("");
1314 */
1315 #endif
1316
1317     mov->next_chunk_offset = offset + size;
1318
1319     return 0;
1320 }
1321
1322 static int mov_read_close(AVFormatContext *s)
1323 {
1324     int i;
1325     MOVContext *mov = s->priv_data;
1326     for(i=0; i<mov->total_streams; i++)
1327         mov_free_stream_context(mov->streams[i]);
1328     for(i=0; i<s->nb_streams; i++)
1329         av_freep(&s->streams[i]);
1330     return 0;
1331 }
1332
1333 static AVInputFormat mov_iformat = {
1334     "mov",
1335     "QuickTime/MPEG4 format",
1336     sizeof(MOVContext),
1337     mov_probe,
1338     mov_read_header,
1339     mov_read_packet,
1340     mov_read_close,
1341 };
1342
1343 int mov_init(void)
1344 {
1345     av_register_input_format(&mov_iformat);
1346     return 0;
1347 }