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