comparison mov.c @ 130:f607ed6aa365 libavformat

* support for AAC audio (esds decoding - using extradata) * using MOV_atom_t instead of 3 args * chunk parsers ordered alphabeticaly
author kabi
date Mon, 12 May 2003 10:59:18 +0000
parents b1843685a8f7
children 5bb5f3d201d6
comparison
equal deleted inserted replaced
129:b1843685a8f7 130:f607ed6aa365
23 #include <zlib.h> 23 #include <zlib.h>
24 #endif 24 #endif
25 25
26 /* 26 /*
27 * First version by Francois Revol revol@free.fr 27 * First version by Francois Revol revol@free.fr
28 * 28 *
29 * Features and limitations: 29 * Features and limitations:
30 * - reads most of the QT files I have (at least the structure), 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. 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 32 * FIXED, Francois Revol, 07/17/2002
33 * - ffmpeg has nearly none of the usual QuickTime codecs, 33 * - ffmpeg has nearly none of the usual QuickTime codecs,
34 * although I succesfully dumped raw and mp3 audio tracks off .mov files. 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 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 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 37 * (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at
38 * http://mpeg.telecomitalialab.com/faq.htm 38 * http://mpeg.telecomitalialab.com/faq.htm
39 * - the code is quite ugly... maybe I won't do it recursive next time :-) 39 * - the code is quite ugly... maybe I won't do it recursive next time :-)
40 * 40 *
41 * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/ 41 * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/
42 * when coding this :) (it's a writer anyway) 42 * when coding this :) (it's a writer anyway)
43 * 43 *
44 * Reference documents: 44 * Reference documents:
45 * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt 45 * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
46 * Apple: 46 * Apple:
47 * http://developer.apple.com/techpubs/quicktime/qtdevdocs/QTFF/qtff.html 47 * http://developer.apple.com/techpubs/quicktime/qtdevdocs/QTFF/qtff.html
48 * http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf 48 * http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf
52 //#define DEBUG 52 //#define DEBUG
53 53
54 /* allows chunk splitting - should work now... */ 54 /* allows chunk splitting - should work now... */
55 /* in case you can't read a file, try commenting */ 55 /* in case you can't read a file, try commenting */
56 #define MOV_SPLIT_CHUNKS 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 #else
83 #define print_atom(a,b,c,d)
84 #endif
85 57
86 /* some streams in QT (and in MP4 mostly) aren't either video nor audio */ 58 /* some streams in QT (and in MP4 mostly) aren't either video nor audio */
87 /* so we first list them as this, then clean up the list of streams we give back, */ 59 /* so we first list them as this, then clean up the list of streams we give back, */
88 /* getting rid of these */ 60 /* getting rid of these */
89 #define CODEC_TYPE_MOV_OTHER (enum CodecType) 2 61 #define CODEC_TYPE_MOV_OTHER (enum CodecType) 2
115 { CODEC_ID_H263, MKTAG('h', '2', '6', '3') }, /* H263 */ 87 { CODEC_ID_H263, MKTAG('h', '2', '6', '3') }, /* H263 */
116 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */ 88 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */
117 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */ 89 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */
118 /* { CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', 'v') }, *//* AVID dv */ 90 /* { CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', 'v') }, *//* AVID dv */
119 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, /* On2 VP3 */ 91 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, /* On2 VP3 */
120 { 0, 0 }, 92 { CODEC_ID_NONE, 0 },
121 }; 93 };
122 94
123 static const CodecTag mov_audio_tags[] = { 95 static const CodecTag mov_audio_tags[] = {
124 /* { CODEC_ID_PCM_S16BE, MKTAG('N', 'O', 'N', 'E') }, *//* uncompressed */ 96 /* { CODEC_ID_PCM_S16BE, MKTAG('N', 'O', 'N', 'E') }, *//* uncompressed */
125 { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, /* 16 bits */ 97 { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, /* 16 bits */
126 { CODEC_ID_PCM_S8, MKTAG('t', 'w', 'o', 's') }, /* 8 bits */ 98 /* { CODEC_ID_PCM_S8, MKTAG('t', 'w', 'o', 's') },*/ /* 8 bits */
127 { CODEC_ID_PCM_U8, MKTAG('r', 'a', 'w', ' ') }, /* 8 bits unsigned */ 99 { CODEC_ID_PCM_U8, MKTAG('r', 'a', 'w', ' ') }, /* 8 bits unsigned */
128 { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, /* */ 100 { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, /* */
129 { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, /* */ 101 { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, /* */
130 { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, /* */ 102 { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, /* */
131 { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') }, /* IMA-4 ADPCM */ 103 { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') }, /* IMA-4 ADPCM */
135 { CODEC_ID_MP2, MKTAG('.', 'm', 'p', '3') }, /* MPEG layer 3 */ /* sample files at http://www.3ivx.com/showcase.html use this tag */ 107 { CODEC_ID_MP2, MKTAG('.', 'm', 'p', '3') }, /* MPEG layer 3 */ /* sample files at http://www.3ivx.com/showcase.html use this tag */
136 { CODEC_ID_MP2, 0x6D730055 }, /* MPEG layer 3 */ 108 { CODEC_ID_MP2, 0x6D730055 }, /* MPEG layer 3 */
137 { CODEC_ID_MP2, 0x5500736D }, /* MPEG layer 3 *//* XXX: check endianness */ 109 { CODEC_ID_MP2, 0x5500736D }, /* MPEG layer 3 *//* XXX: check endianness */
138 /* { CODEC_ID_OGG_VORBIS, MKTAG('O', 'g', 'g', 'S') }, *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */ 110 /* { CODEC_ID_OGG_VORBIS, MKTAG('O', 'g', 'g', 'S') }, *//* sample files at http://heroinewarrior.com/xmovie.php3 use this tag */
139 /* MP4 tags */ 111 /* MP4 tags */
140 /* { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') }, *//* MPEG 4 AAC or audio ? */ 112 { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') }, /* MPEG 4 AAC or audio ? */
141 /* The standard for mpeg4 audio is still not normalised AFAIK anyway */ 113 /* The standard for mpeg4 audio is still not normalised AFAIK anyway */
142 { 0, 0 }, 114 { CODEC_ID_NONE, 0 },
143 }; 115 };
144 116
145 /* the QuickTime file format is quite convoluted... 117 /* the QuickTime file format is quite convoluted...
146 * it has lots of index tables, each indexing something in another one... 118 * it has lots of index tables, each indexing something in another one...
147 * Here we just use what is needed to read the chunks 119 * Here we just use what is needed to read the chunks
150 typedef struct MOV_sample_to_chunk_tbl { 122 typedef struct MOV_sample_to_chunk_tbl {
151 long first; 123 long first;
152 long count; 124 long count;
153 long id; 125 long id;
154 } MOV_sample_to_chunk_tbl; 126 } MOV_sample_to_chunk_tbl;
127
128 typedef struct {
129 uint32_t type;
130 int64_t offset;
131 int64_t size; /* total size (excluding the size and type fields) */
132 } MOV_atom_t;
133
134 typedef struct {
135 int seed;
136 int flags;
137 int size;
138 void* clrs;
139 } MOV_ctab_t;
155 140
156 typedef struct { 141 typedef struct {
157 uint8_t version; 142 uint8_t version;
158 uint32_t flags; // 24bit 143 uint32_t flags; // 24bit
159 144
218 int time_scale; 203 int time_scale;
219 long current_sample; 204 long current_sample;
220 long left_in_chunk; /* how many samples before next chunk */ 205 long left_in_chunk; /* how many samples before next chunk */
221 /* specific MPEG4 header which is added at the beginning of the stream */ 206 /* specific MPEG4 header which is added at the beginning of the stream */
222 int header_len; 207 int header_len;
208 uint8_t *header_data;
223 MOV_esds_t esds; 209 MOV_esds_t esds;
224 uint8_t *header_data;
225 } MOVStreamContext; 210 } MOVStreamContext;
226 211
227 typedef struct MOVContext { 212 typedef struct MOVContext {
228 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) */ 213 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) */
229 AVFormatContext *fc; 214 AVFormatContext *fc;
239 */ 224 */
240 MOVStreamContext *streams[MAX_STREAMS]; 225 MOVStreamContext *streams[MAX_STREAMS];
241 226
242 int64_t next_chunk_offset; 227 int64_t next_chunk_offset;
243 MOVStreamContext *partial; /* != 0 : there is still to read in the current chunk */ 228 MOVStreamContext *partial; /* != 0 : there is still to read in the current chunk */
229 int ctab_size;
230 MOV_ctab_t **ctab; /* color tables */
244 const struct MOVParseTableEntry *parse_table; /* could be eventually used to change the table */ 231 const struct MOVParseTableEntry *parse_table; /* could be eventually used to change the table */
245 /* NOTE: for recursion save to/ restore from local variable! */ 232 /* NOTE: for recursion save to/ restore from local variable! */
246 } MOVContext; 233 } MOVContext;
247 234
248 235
252 /* return code: 239 /* return code:
253 1: found what I wanted, exit 240 1: found what I wanted, exit
254 0: continue to parse next atom 241 0: continue to parse next atom
255 -1: error occured, exit 242 -1: error occured, exit
256 */ 243 */
257 typedef int (*mov_parse_function)(MOVContext *ctx, 244 typedef int (*mov_parse_function)(MOVContext *ctx, ByteIOContext *pb, MOV_atom_t atom);
258 ByteIOContext *pb,
259 uint32_t atom_type,
260 int64_t atom_offset, /* after the size and type field (and eventually the extended size) */
261 int64_t atom_size); /* total size (excluding the size and type fields) */
262 245
263 /* links atom IDs to parse functions */ 246 /* links atom IDs to parse functions */
264 typedef struct MOVParseTableEntry { 247 typedef struct MOVParseTableEntry {
265 uint32_t type; 248 uint32_t type;
266 mov_parse_function func; 249 mov_parse_function func;
267 } MOVParseTableEntry; 250 } MOVParseTableEntry;
268 251
269 static int parse_leaf(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 252 #ifdef DEBUG
270 { 253 /*
271 print_atom("leaf", atom_type, atom_offset, atom_size); 254 * XXX: static sux, even more in a multithreaded environment...
272 255 * Avoid them. This is here just to help debugging.
273 if(atom_size>1) 256 */
274 url_fskip(pb, atom_size); 257 static int debug_indent = 0;
275 /* url_seek(pb, atom_offset+atom_size, SEEK_SET); */ 258 void print_atom(const char *str, MOV_atom_t atom)
276 return 0; 259 {
277 } 260 unsigned int tag, i;
278 261 tag = (unsigned int) atom.type;
279 static int parse_default(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 262 i=debug_indent;
280 { 263 if(tag == 0) tag = MKTAG('N', 'U', 'L', 'L');
281 uint32_t type, foo=0; 264 while(i--)
282 uint64_t offset, size; 265 printf("|");
266 printf("parse:");
267 printf(" %s: tag=%c%c%c%c offset=0x%x size=0x%x\n",
268 str, tag & 0xff,
269 (tag >> 8) & 0xff,
270 (tag >> 16) & 0xff,
271 (tag >> 24) & 0xff,
272 (unsigned int)atom.offset,
273 (unsigned int)atom.size);
274 assert((unsigned int)atom.size < 0x7fffffff);// catching errors
275 }
276 #else
277 #define print_atom(a,b)
278 #endif
279
280
281 static int mov_read_leaf(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
282 {
283 print_atom("leaf", atom);
284
285 if (atom.size>1)
286 url_fskip(pb, atom.size);
287 /* url_seek(pb, atom_offset+atom.size, SEEK_SET); */
288 return 0;
289 }
290
291 static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
292 {
283 int64_t total_size = 0; 293 int64_t total_size = 0;
294 MOV_atom_t a;
284 int i; 295 int i;
285 int err = 0; 296 int err = 0;
286 foo=0; 297
287 #ifdef DEBUG 298 #ifdef DEBUG
288 print_atom("default", atom_type, atom_offset, atom_size); 299 print_atom("default", atom);
289 debug_indent++; 300 debug_indent++;
290 #endif 301 #endif
291 302
292 offset = atom_offset; 303 a.offset = atom.offset;
293 304
294 if(atom_size < 0) 305 if(atom.size < 0)
295 atom_size = 0x0FFFFFFFFFFFFFFF; 306 atom.size = 0x0FFFFFFFFFFFFFFF;
296 while(((total_size + 8) < atom_size) && !url_feof(pb) && !err) { 307 while(((total_size + 8) < atom.size) && !url_feof(pb) && !err) {
297 size=atom_size; 308 a.size = atom.size;
298 type=0L; 309 a.type=0L;
299 if(atom_size >= 8) { 310 if(atom.size >= 8) {
300 size = get_be32(pb); 311 a.size = get_be32(pb);
301 type = get_le32(pb); 312 a.type = get_le32(pb);
302 } 313 }
303 total_size += 8; 314 total_size += 8;
304 offset += 8; 315 a.offset += 8;
305 //printf("type: %08x %.4s sz: %Lx %Lx %Lx\n", type, (char*)&type, size, atom_size, total_size); 316 //printf("type: %08x %.4s sz: %Lx %Lx %Lx\n", type, (char*)&type, size, atom.size, total_size);
306 if(size == 1) { /* 64 bit extended size */ 317 if (a.size == 1) { /* 64 bit extended size */
307 size = get_be64(pb) - 8; 318 a.size = get_be64(pb) - 8;
308 offset+=8; 319 a.offset += 8;
309 total_size+=8; 320 total_size += 8;
310 } 321 }
311 if(size == 0) { 322 if (a.size == 0) {
312 size = atom_size - total_size; 323 a.size = atom.size - total_size;
313 if (size <= 8) 324 if (a.size <= 8)
314 break; 325 break;
315 } 326 }
316 for (i=0; c->parse_table[i].type != 0L && c->parse_table[i].type != type; i++) 327 for (i = 0; c->parse_table[i].type != 0L
328 && c->parse_table[i].type != a.type; i++)
317 /* empty */; 329 /* empty */;
318 330
319 size -= 8; 331 a.size -= 8;
320 // printf(" i=%ld\n", i); 332 // printf(" i=%ld\n", i);
321 if (c->parse_table[i].type == 0) { /* skip leaf atoms data */ 333 if (c->parse_table[i].type == 0) { /* skip leaf atoms data */
322 // url_seek(pb, atom_offset+atom_size, SEEK_SET); 334 // url_seek(pb, atom.offset+atom.size, SEEK_SET);
323 #ifdef DEBUG 335 #ifdef DEBUG
324 print_atom("unknown", type, offset, size); 336 print_atom("unknown", a);
325 #endif 337 #endif
326 url_fskip(pb, size); 338 url_fskip(pb, a.size);
327 } else { 339 } else {
328 #ifdef DEBUG 340 #ifdef DEBUG
329 //char b[5] = { type & 0xff, (type >> 8) & 0xff, (type >> 16) & 0xff, (type >> 24) & 0xff, 0 }; 341 //char b[5] = { type & 0xff, (type >> 8) & 0xff, (type >> 16) & 0xff, (type >> 24) & 0xff, 0 };
330 //print_atom(b, type, offset, size); 342 //print_atom(b, type, offset, size);
331 #endif 343 #endif
332 err = (c->parse_table[i].func)(c, pb, type, offset, size); 344 err = (c->parse_table[i].func)(c, pb, a);
333 } 345 }
334 346
335 offset+=size; 347 a.offset += a.size;
336 total_size+=size; 348 total_size += a.size;
337 } 349 }
338 350
339 if (!err && total_size < atom_size && atom_size < 0x7ffff) { 351 if (!err && total_size < atom.size && atom.size < 0x7ffff) {
340 printf("RESET %Ld %Ld err:%d\n", atom_size, total_size, err); 352 //printf("RESET %Ld %Ld err:%d\n", atom.size, total_size, err);
341 url_fskip(pb, atom_size - total_size); 353 url_fskip(pb, atom.size - total_size);
342 } 354 }
343 355
344 #ifdef DEBUG 356 #ifdef DEBUG
345 debug_indent--; 357 debug_indent--;
346 #endif 358 #endif
347 return err; 359 return err;
348 } 360 }
349 361
350 static int parse_ctab(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 362 static int mov_read_ctab(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
351 { 363 {
352 url_fskip(pb, atom_size); // for now 364 unsigned int len;
353 return 0; 365 MOV_ctab_t *t;
354 } 366 //url_fskip(pb, atom.size); // for now
355 367 c->ctab = av_realloc(c->ctab, ++c->ctab_size);
356 static int parse_mvhd(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 368 t = c->ctab[c->ctab_size];
357 { 369 t->seed = get_be32(pb);
358 print_atom("mvhd", atom_type, atom_offset, atom_size); 370 t->flags = get_be16(pb);
359 371 t->size = get_be16(pb) + 1;
360 get_byte(pb); /* version */ 372 len = 2 * t->size * 4;
361 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 373 if (len > 0) {
362 374 t->clrs = av_malloc(len); // 16bit A R G B
363 get_be32(pb); /* creation time */ 375 if (t->clrs)
364 get_be32(pb); /* modification time */ 376 get_buffer(pb, t->clrs, len);
365 c->time_scale = get_be32(pb); /* time scale */ 377 }
366 #ifdef DEBUG 378
367 printf("time scale = %i\n", c->time_scale); 379 return 0;
368 #endif 380 }
369 c->duration = get_be32(pb); /* duration */ 381
370 get_be32(pb); /* preferred scale */ 382 static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
371 383 {
372 get_be16(pb); /* preferred volume */ 384 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
373
374 url_fskip(pb, 10); /* reserved */
375
376 url_fskip(pb, 36); /* display matrix */
377
378 get_be32(pb); /* preview time */
379 get_be32(pb); /* preview duration */
380 get_be32(pb); /* poster time */
381 get_be32(pb); /* selection time */
382 get_be32(pb); /* selection duration */
383 get_be32(pb); /* current time */
384 get_be32(pb); /* next track ID */
385
386 return 0;
387 }
388
389 /* this atom should contain all header atoms */
390 static int parse_moov(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
391 {
392 int err;
393
394 print_atom("moov", atom_type, atom_offset, atom_size);
395
396 err = parse_default(c, pb, atom_type, atom_offset, atom_size);
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(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
407 {
408 print_atom("mdat", atom_type, atom_offset, atom_size);
409
410 if(atom_size == 0) /* wrong one (MP4) */
411 return 0;
412 c->found_mdat=1;
413 c->mdat_offset = atom_offset;
414 c->mdat_size = atom_size;
415 if(c->found_moov)
416 return 1; /* found both, just go */
417 url_fskip(pb, atom_size);
418 return 0; /* now go for moov */
419 }
420
421 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */
422 /* like the files created with Adobe Premiere 5.0, for samples see */
423 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */
424 static int parse_wide(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
425 {
426 int err;
427 uint32_t type;
428
429 #ifdef DEBUG
430 print_atom("wide", atom_type, atom_offset, atom_size);
431 debug_indent++;
432 #endif
433 if (atom_size < 8)
434 return 0; /* continue */
435 if (get_be32(pb) != 0) { /* 0 sized mdat atom... use the 'wide' atom size */
436 url_fskip(pb, atom_size - 4);
437 return 0;
438 }
439 type = get_le32(pb);
440 if (type != MKTAG('m', 'd', 'a', 't')) {
441 url_fskip(pb, atom_size - 8);
442 return 0;
443 }
444 err = parse_mdat(c, pb, type, atom_offset + 8, atom_size - 8);
445 #ifdef DEBUG
446 debug_indent--;
447 #endif
448 return err;
449 }
450
451 static int parse_trak(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
452 {
453 AVStream *st;
454 MOVStreamContext *sc;
455
456 print_atom("trak", atom_type, atom_offset, atom_size);
457
458 st = av_new_stream(c->fc, c->fc->nb_streams);
459 if (!st) return -2;
460 sc = (MOVStreamContext*) av_mallocz(sizeof(MOVStreamContext));
461 if (!sc) {
462 av_free(st);
463 return -1;
464 }
465
466 sc->sample_to_chunk_index = -1;
467 st->priv_data = sc;
468 st->codec.codec_type = CODEC_TYPE_MOV_OTHER;
469 st->time_length = (c->duration * 1000) / c->time_scale; // time in miliseconds
470 c->streams[c->fc->nb_streams-1] = sc;
471 return parse_default(c, pb, atom_type, atom_offset, atom_size);
472 }
473
474 static int parse_tkhd(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
475 {
476 AVStream *st;
477
478 print_atom("tkhd", atom_type, atom_offset, atom_size);
479
480 st = c->fc->streams[c->fc->nb_streams-1];
481
482 get_byte(pb); /* version */
483
484 get_byte(pb); get_byte(pb);
485 get_byte(pb); /* flags */
486 /*
487 MOV_TRACK_ENABLED 0x0001
488 MOV_TRACK_IN_MOVIE 0x0002
489 MOV_TRACK_IN_PREVIEW 0x0004
490 MOV_TRACK_IN_POSTER 0x0008
491 */
492
493 get_be32(pb); /* creation time */
494 get_be32(pb); /* modification time */
495 st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/
496 get_be32(pb); /* reserved */
497 st->time_length = get_be32(pb) * 1000 / c->time_scale; /* duration */
498 get_be32(pb); /* reserved */
499 get_be32(pb); /* reserved */
500
501 get_be16(pb); /* layer */
502 get_be16(pb); /* alternate group */
503 get_be16(pb); /* volume */
504 get_be16(pb); /* reserved */
505
506 url_fskip(pb, 36); /* display matrix */
507
508 /* those are fixed-point */
509 st->codec.width = get_be32(pb) >> 16; /* track width */
510 st->codec.height = get_be32(pb) >> 16; /* track height */
511
512 return 0;
513 }
514
515 static int parse_mdhd(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
516 {
517 AVStream *st;
518
519 print_atom("mdhd", atom_type, atom_offset, atom_size);
520
521 st = c->fc->streams[c->fc->nb_streams-1];
522
523 get_byte(pb); /* version */
524
525 get_byte(pb); get_byte(pb);
526 get_byte(pb); /* flags */
527
528 get_be32(pb); /* creation time */
529 get_be32(pb); /* modification time */
530
531 c->streams[c->total_streams]->time_scale = get_be32(pb);
532
533 #ifdef DEBUG
534 printf("track[%i].time_scale = %i\n", c->fc->nb_streams-1, c->streams[c->total_streams]->time_scale); /* time scale */
535 #endif
536 get_be32(pb); /* duration */
537
538 get_be16(pb); /* language */
539 get_be16(pb); /* quality */
540
541 return 0;
542 }
543
544 static int parse_hdlr(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
545 {
546 int len = 0; 385 int len = 0;
547 uint8_t *buf; 386 uint8_t *buf;
548 uint32_t type; 387 uint32_t type;
549 AVStream *st;
550 uint32_t ctype; 388 uint32_t ctype;
551 389
552 print_atom("hdlr", atom_type, atom_offset, atom_size); 390 print_atom("hdlr", atom);
553
554 st = c->fc->streams[c->fc->nb_streams-1];
555 391
556 get_byte(pb); /* version */ 392 get_byte(pb); /* version */
557 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 393 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
558 394
559 /* component type */ 395 /* component type */
600 } 436 }
601 get_be32(pb); /* component manufacture */ 437 get_be32(pb); /* component manufacture */
602 get_be32(pb); /* component flags */ 438 get_be32(pb); /* component flags */
603 get_be32(pb); /* component flags mask */ 439 get_be32(pb); /* component flags mask */
604 440
605 if(atom_size <= 24) 441 if(atom.size <= 24)
606 return 0; /* nothing left to read */ 442 return 0; /* nothing left to read */
607 /* XXX: MP4 uses a C string, not a pascal one */ 443 /* XXX: MP4 uses a C string, not a pascal one */
608 /* component name */ 444 /* component name */
609 445
610 if(c->mp4) { 446 if(c->mp4) {
611 /* .mp4: C string */ 447 /* .mp4: C string */
612 while(get_byte(pb) && (++len < (atom_size - 24))); 448 while(get_byte(pb) && (++len < (atom.size - 24)));
613 } else { 449 } else {
614 /* .mov: PASCAL string */ 450 /* .mov: PASCAL string */
615 len = get_byte(pb); 451 len = get_byte(pb);
452 #ifdef DEBUG
616 buf = (uint8_t*) av_malloc(len+1); 453 buf = (uint8_t*) av_malloc(len+1);
617 if (buf) { 454 if (buf) {
618 get_buffer(pb, buf, len); 455 get_buffer(pb, buf, len);
619 #ifdef DEBUG
620 buf[len] = '\0'; 456 buf[len] = '\0';
621 printf("**buf='%s'\n", buf); 457 printf("**buf='%s'\n", buf);
622 #endif
623 av_free(buf); 458 av_free(buf);
624 } else 459 } else
460 #endif
625 url_fskip(pb, len); 461 url_fskip(pb, len);
626 } 462 }
627 #if 0 463
628 len = get_byte(pb); 464 return 0;
629 /* XXX: use a better heuristic */ 465 }
630 if(len < 32) { 466
631 /* assume that it is a Pascal like string */ 467 static int mov_mp4_read_descr_len(ByteIOContext *pb)
632 buf = av_malloc(len+1);
633 if (buf) {
634 get_buffer(pb, buf, len);
635 buf[len] = '\0';
636 #ifdef DEBUG
637 printf("**buf='%s'\n", buf);
638 #endif
639 av_free(buf);
640 } else
641 url_fskip(pb, len)l
642 } else {
643 /* MP4 string */
644 for(;;) {
645 if (len == 0)
646 break;
647 len = get_byte(pb);
648 }
649 }
650 #endif
651
652 return 0;
653 }
654
655 static int mp4_read_descr_len(ByteIOContext *pb)
656 { 468 {
657 int len = 0; 469 int len = 0;
658 int count = 0; 470 int count = 4;
659 for(;;) { 471 while (count--) {
660 int c = get_byte(pb); 472 int c = get_byte(pb);
661 len = (len << 7) | (c & 0x7f); 473 len = (len << 7) | (c & 0x7f);
662 if ((c & 0x80) == 0) 474 if (!(c & 0x80))
663 break; 475 break;
664 if (++count == 4)
665 break;
666 } 476 }
667 return len; 477 return len;
668 } 478 }
669 479
670 static int mp4_read_descr(ByteIOContext *pb, int *tag) 480 static int mov_mp4_read_descr(ByteIOContext *pb, int *tag)
671 { 481 {
672 int len; 482 int len;
673 *tag = get_byte(pb); 483 *tag = get_byte(pb);
674 len = mp4_read_descr_len(pb); 484 len = mov_mp4_read_descr_len(pb);
675 #ifdef DEBUG 485 #ifdef DEBUG
676 printf("MPEG4 description: tag=0x%02x len=%d\n", *tag, len); 486 printf("MPEG4 description: tag=0x%02x len=%d\n", *tag, len);
677 #endif 487 #endif
678 return len; 488 return len;
679 } 489 }
685 val |= get_byte(s) << 8; 495 val |= get_byte(s) << 8;
686 val |= get_byte(s); 496 val |= get_byte(s);
687 return val; 497 return val;
688 } 498 }
689 499
690 static int parse_esds(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 500 static int mov_read_esds(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
691 { 501 {
692
693 int64_t start_pos = url_ftell(pb);
694 AVStream *st = c->fc->streams[c->fc->nb_streams-1]; 502 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
695 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; 503 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
504 int64_t start_pos = url_ftell(pb);
696 int tag, len; 505 int tag, len;
697 506
698 print_atom("esds", atom_type, atom_offset, atom_size); 507 print_atom("esds", atom);
699 508
700 /* Well, broken but suffisant for some MP4 streams */ 509 /* Well, broken but suffisant for some MP4 streams */
701 get_be32(pb); /* version + flags */ 510 get_be32(pb); /* version + flags */
702 len = mp4_read_descr(pb, &tag); 511 len = mov_mp4_read_descr(pb, &tag);
703 if (tag == MP4ESDescrTag) { 512 if (tag == MP4ESDescrTag) {
704 get_be16(pb); /* ID */ 513 get_be16(pb); /* ID */
705 get_byte(pb); /* priority */ 514 get_byte(pb); /* priority */
706 } else 515 } else
707 get_be16(pb); /* ID */ 516 get_be16(pb); /* ID */
708 517
709 len = mp4_read_descr(pb, &tag); 518 len = mov_mp4_read_descr(pb, &tag);
710 if (tag == MP4DecConfigDescrTag) { 519 if (tag == MP4DecConfigDescrTag) {
711 sc->esds.object_type_id = get_byte(pb); 520 sc->esds.object_type_id = get_byte(pb);
712 sc->esds.stream_type = get_be24(pb); 521 sc->esds.stream_type = get_byte(pb);
522 sc->esds.buffer_size_db = get_be24(pb);
713 sc->esds.max_bitrate = get_be32(pb); 523 sc->esds.max_bitrate = get_be32(pb);
714 sc->esds.avg_bitrate = get_be32(pb); 524 sc->esds.avg_bitrate = get_be32(pb);
715 525
716 len = mp4_read_descr(pb, &tag); 526 len = mov_mp4_read_descr(pb, &tag);
717 printf("LEN %d TAG %d m:%d a:%d\n", len, tag, sc->esds.max_bitrate, sc->esds.avg_bitrate); 527 //printf("LEN %d TAG %d m:%d a:%d\n", len, tag, sc->esds.max_bitrate, sc->esds.avg_bitrate);
718 if (tag == MP4DecSpecificDescrTag) { 528 if (tag == MP4DecSpecificDescrTag) {
719 #ifdef DEBUG 529 #ifdef DEBUG
720 printf("Specific MPEG4 header len=%d\n", len); 530 printf("Specific MPEG4 header len=%d\n", len);
721 #endif 531 #endif
722 sc->header_data = (uint8_t*) av_mallocz(len); 532 st->codec.extradata = (uint8_t*) av_mallocz(len);
723 if (sc->header_data) { 533 if (st->codec.extradata) {
724 get_buffer(pb, sc->header_data, len); 534 get_buffer(pb, st->codec.extradata, len);
725 sc->header_len = len; 535 st->codec.extradata_size = len;
726 } 536 }
727 } 537 }
728 } 538 }
729 /* in any case, skip garbage */ 539 /* in any case, skip garbage */
730 url_fskip(pb, (atom_size - 8) - ((url_ftell(pb) - start_pos))); 540 url_fskip(pb, atom.size - ((url_ftell(pb) - start_pos)));
731 return 0; 541 return 0;
732 } 542 }
733 543
734 static int parse_stsd(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 544 /* this atom contains actual media data */
735 { 545 static int mov_read_mdat(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
736 int entries, size, frames_per_sample; 546 {
737 uint32_t format; 547 print_atom("mdat", atom);
738 AVStream *st; 548
739 MOVStreamContext *sc; 549 if(atom.size == 0) /* wrong one (MP4) */
740 550 return 0;
741 print_atom("stsd", atom_type, atom_offset, atom_size); 551 c->found_mdat=1;
742 552 c->mdat_offset = atom.offset;
743 st = c->fc->streams[c->fc->nb_streams-1]; 553 c->mdat_size = atom.size;
744 sc = (MOVStreamContext *)st->priv_data; 554 if(c->found_moov)
555 return 1; /* found both, just go */
556 url_fskip(pb, atom.size);
557 return 0; /* now go for moov */
558 }
559
560 /* this atom should contain all header atoms */
561 static int mov_read_moov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
562 {
563 int err;
564
565 print_atom("moov", atom);
566
567 err = mov_read_default(c, pb, atom);
568 /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */
569 /* so we don't parse the whole file if over a network */
570 c->found_moov=1;
571 if(c->found_mdat)
572 return 1; /* found both, just go */
573 return 0; /* now go for mdat */
574 }
575
576
577 static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
578 {
579 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
580
581 print_atom("mdhd", atom);
582
583 get_byte(pb); /* version */
584
585 get_byte(pb); get_byte(pb);
586 get_byte(pb); /* flags */
587
588 get_be32(pb); /* creation time */
589 get_be32(pb); /* modification time */
590
591 c->streams[c->total_streams]->time_scale = get_be32(pb);
592
593 #ifdef DEBUG
594 printf("track[%i].time_scale = %i\n", c->fc->nb_streams-1, c->streams[c->total_streams]->time_scale); /* time scale */
595 #endif
596 get_be32(pb); /* duration */
597
598 get_be16(pb); /* language */
599 get_be16(pb); /* quality */
600
601 return 0;
602 }
603
604 static int mov_read_mvhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
605 {
606 print_atom("mvhd", atom);
745 607
746 get_byte(pb); /* version */ 608 get_byte(pb); /* version */
747 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 609 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
748 610
611 get_be32(pb); /* creation time */
612 get_be32(pb); /* modification time */
613 c->time_scale = get_be32(pb); /* time scale */
614 #ifdef DEBUG
615 printf("time scale = %i\n", c->time_scale);
616 #endif
617 c->duration = get_be32(pb); /* duration */
618 get_be32(pb); /* preferred scale */
619
620 get_be16(pb); /* preferred volume */
621
622 url_fskip(pb, 10); /* reserved */
623
624 url_fskip(pb, 36); /* display matrix */
625
626 get_be32(pb); /* preview time */
627 get_be32(pb); /* preview duration */
628 get_be32(pb); /* poster time */
629 get_be32(pb); /* selection time */
630 get_be32(pb); /* selection duration */
631 get_be32(pb); /* current time */
632 get_be32(pb); /* next track ID */
633
634 return 0;
635 }
636
637
638 static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
639 {
640 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
641 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
642 int entries, i;
643
644 print_atom("stco", atom);
645
646 get_byte(pb); /* version */
647 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
648
649 entries = get_be32(pb);
650 sc->chunk_count = entries;
651 sc->chunk_offsets = (int64_t*) av_malloc(entries * sizeof(int64_t));
652 if (!sc->chunk_offsets)
653 return -1;
654 if (atom.type == MKTAG('s', 't', 'c', 'o')) {
655 for(i=0; i<entries; i++) {
656 sc->chunk_offsets[i] = get_be32(pb);
657 }
658 } else if (atom.type == MKTAG('c', 'o', '6', '4')) {
659 for(i=0; i<entries; i++) {
660 sc->chunk_offsets[i] = get_be64(pb);
661 }
662 } else
663 return -1;
664 #ifdef DEBUG
665 /*
666 for(i=0; i<entries; i++) {
667 printf("chunk offset=0x%Lx\n", sc->chunk_offsets[i]);
668 }
669 */
670 #endif
671 return 0;
672 }
673
674 static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
675 {
676 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
677 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
678 int entries, frames_per_sample;
679 uint32_t format;
680
681 print_atom("stsd", atom);
682
683 get_byte(pb); /* version */
684 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
685
749 entries = get_be32(pb); 686 entries = get_be32(pb);
750 687
751 while(entries--) { 688 while(entries--) {
752 enum CodecID id; 689 enum CodecID id;
753 size = get_be32(pb); /* size */ 690 int size = get_be32(pb); /* size */
754 format = get_le32(pb); /* data format */ 691 format = get_le32(pb); /* data format */
755 692
756 get_be32(pb); /* reserved */ 693 get_be32(pb); /* reserved */
757 get_be16(pb); /* reserved */ 694 get_be16(pb); /* reserved */
758 get_be16(pb); /* index */ 695 get_be16(pb); /* index */
773 (format >> 16) & 0xff, 710 (format >> 16) & 0xff,
774 (format >> 24) & 0xff, 711 (format >> 24) & 0xff,
775 st->codec.codec_type); 712 st->codec.codec_type);
776 #endif 713 #endif
777 st->codec.codec_tag = format; 714 st->codec.codec_tag = format;
778 if(st->codec.codec_type==CODEC_TYPE_VIDEO) { 715 if(st->codec.codec_type==CODEC_TYPE_VIDEO) {
779 st->codec.codec_id = codec_get_id(mov_video_tags, format); 716 MOV_atom_t a = { 0, 0, 0 };
717 st->codec.codec_id = id;
780 get_be16(pb); /* version */ 718 get_be16(pb); /* version */
781 get_be16(pb); /* revision level */ 719 get_be16(pb); /* revision level */
782 get_be32(pb); /* vendor */ 720 get_be32(pb); /* vendor */
783 get_be32(pb); /* temporal quality */ 721 get_be32(pb); /* temporal quality */
784 get_be32(pb); /* spacial quality */ 722 get_be32(pb); /* spacial quality */
805 st->codec.color_table_id = get_be16(pb); /* colortable id */ 743 st->codec.color_table_id = get_be16(pb); /* colortable id */
806 744
807 st->codec.frame_rate = 25; 745 st->codec.frame_rate = 25;
808 st->codec.frame_rate_base = 1; 746 st->codec.frame_rate_base = 1;
809 747
810 size -= (16+8*4+2+32+2*2); 748 size -= (16+8*4+2+32+2*2);
811 #if 0 749 #if 0
812 while (size >= 8) { 750 while (size >= 8) {
813 int atom_size, atom_type; 751 MOV_atom_t a;
814 int64_t start_pos; 752 int64_t start_pos;
815 753
816 atom_size = get_be32(pb); 754 a.size = get_be32(pb);
817 atom_type = get_le32(pb); 755 a.type = get_le32(pb);
818 size -= 8; 756 size -= 8;
819 printf("NEWSIZE %d\n", size); 757 #ifdef DEBUG
820 #ifdef DEBUG 758 printf("VIDEO: atom_type=%c%c%c%c atom.size=%Ld size_left=%d\n",
821 printf("VIDEO: atom_type=%c%c%c%c atom_size=%d size_left=%d\n", 759 (a.type >> 0) & 0xff,
822 (atom_type >> 0) & 0xff, 760 (a.type >> 8) & 0xff,
823 (atom_type >> 8) & 0xff, 761 (a.type >> 16) & 0xff,
824 (atom_type >> 16) & 0xff, 762 (a.type >> 24) & 0xff,
825 (atom_type >> 24) & 0xff, 763 a.size, size);
826 atom_size, size);
827 #endif 764 #endif
828 start_pos = url_ftell(pb); 765 start_pos = url_ftell(pb);
829 766
830 switch(atom_type) { 767 switch(a.type) {
831 case MKTAG('e', 's', 'd', 's'): 768 case MKTAG('e', 's', 'd', 's'):
832 { 769 {
833 int tag, len; 770 int tag, len;
834 /* Well, broken but suffisant for some MP4 streams */ 771 /* Well, broken but suffisant for some MP4 streams */
835 get_be32(pb); /* version + flags */ 772 get_be32(pb); /* version + flags */
836 len = mp4_read_descr(pb, &tag); 773 len = mov_mp4_read_descr(pb, &tag);
837 if (tag == 0x03) { 774 if (tag == 0x03) {
838 /* MP4ESDescrTag */ 775 /* MP4ESDescrTag */
839 get_be16(pb); /* ID */ 776 get_be16(pb); /* ID */
840 get_byte(pb); /* priority */ 777 get_byte(pb); /* priority */
841 len = mp4_read_descr(pb, &tag); 778 len = mov_mp4_read_descr(pb, &tag);
842 if (tag != 0x04) 779 if (tag != 0x04)
843 goto fail; 780 goto fail;
844 /* MP4DecConfigDescrTag */ 781 /* MP4DecConfigDescrTag */
845 get_byte(pb); /* objectTypeId */ 782 get_byte(pb); /* objectTypeId */
846 get_be32(pb); /* streamType + buffer size */ 783 get_be32(pb); /* streamType + buffer size */
864 break; 801 break;
865 default: 802 default:
866 break; 803 break;
867 } 804 }
868 fail: 805 fail:
869 printf("ATOMENEWSIZE %d %d\n", atom_size, url_ftell(pb) - start_pos); 806 printf("ATOMENEWSIZE %Ld %d\n", atom.size, url_ftell(pb) - start_pos);
870 if (atom_size > 8) { 807 if (atom.size > 8) {
871 url_fskip(pb, (atom_size - 8) - 808 url_fskip(pb, (atom.size - 8) -
872 ((url_ftell(pb) - start_pos))); 809 ((url_ftell(pb) - start_pos)));
873 size -= atom_size - 8; 810 size -= atom.size - 8;
874 printf("NEWSIZE %d\n", size);
875 } 811 }
876 } 812 }
877 if (size > 0) { 813 if (size > 0) {
878 /* unknown extension */ 814 /* unknown extension */
879 url_fskip(pb, size); 815 url_fskip(pb, size);
880 } 816 }
881 #else 817 #else
882 parse_default(c, pb, 0L, 0LL, size); 818 a.size = size;
819 mov_read_default(c, pb, a);
883 #endif 820 #endif
884 } else { 821 } else {
885 get_be16(pb); /* version */ 822 get_be16(pb); /* version */
886 get_be16(pb); /* revision level */ 823 get_be16(pb); /* revision level */
887 get_be32(pb); /* vendor */ 824 get_be32(pb); /* vendor */
888 825
889 st->codec.channels = get_be16(pb);/* channel count */ 826 st->codec.channels = get_be16(pb); /* channel count */
890 st->codec.bits_per_sample = get_be16(pb); /* sample size */ 827 st->codec.bits_per_sample = get_be16(pb); /* sample size */
891 828
892 st->codec.codec_id = codec_get_id(mov_audio_tags, format); 829 st->codec.codec_id = codec_get_id(mov_audio_tags, format);
893 /* handle specific s8 codec */ 830 /* handle specific s8 codec */
894 get_be16(pb); /* compression id = 0*/ 831 get_be16(pb); /* compression id = 0*/
895 get_be16(pb); /* packet size = 0 */ 832 get_be16(pb); /* packet size = 0 */
896 833
897 st->codec.sample_rate = ((get_be32(pb) >> 16)); 834 st->codec.sample_rate = ((get_be32(pb) >> 16));
898 printf("CODECID %d %d %.4s\n", st->codec.codec_id, CODEC_ID_PCM_S16BE, (char*)&format); 835 //printf("CODECID %d %d %.4s\n", st->codec.codec_id, CODEC_ID_PCM_S16BE, (char*)&format);
899 836
900 switch (st->codec.codec_id) { 837 switch (st->codec.codec_id) {
901 case CODEC_ID_PCM_S16BE: 838 case CODEC_ID_PCM_S16BE:
902 if (st->codec.bits_per_sample == 8) 839 if (st->codec.bits_per_sample == 8)
903 st->codec.codec_id = CODEC_ID_PCM_S8; 840 st->codec.codec_id = CODEC_ID_PCM_S8;
911 get_be32(pb); /* samples per packet */ 848 get_be32(pb); /* samples per packet */
912 get_be32(pb); /* bytes per packet */ 849 get_be32(pb); /* bytes per packet */
913 get_be32(pb); /* bytes per frame */ 850 get_be32(pb); /* bytes per frame */
914 get_be32(pb); /* bytes per sample */ 851 get_be32(pb); /* bytes per sample */
915 852
916 //if (size > 16) url_fskip(pb, size-(16+20)); 853 {
917 #if 1 854 MOV_atom_t a = { format, url_ftell(pb), size - (16 + 20 + 16 + 8) };
918 if (size >= 44 + 8) { 855 mov_read_default(c, pb, a);
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 if (st->codec.extradata)
925 get_buffer(pb, st->codec.extradata, st->codec.extradata_size); // FIXME url_fskip
926 url_fskip(pb, size-(16 + 20 + 16 + 8 + st->codec.extradata_size));
927 } 856 }
928 else
929 url_fskip(pb, size-(16 + 20 + 16));
930 #else
931 parse_default(c, pb, 0L, 0LL, size - (16 + 20 + 16 + 8));
932 #endif
933 } 857 }
934 } 858 }
935 /* 859
936 if(len) { 860 return 0;
937 buf = av_malloc(len+1); 861 }
938 get_buffer(pb, buf, len); 862
939 buf[len] = '\0'; 863 static int mov_read_stsc(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
940 puts(buf); 864 {
941 av_free(buf); 865 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
942 } 866 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
943 */
944 return 0;
945 }
946
947 static int parse_stco(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
948 {
949 int entries, i; 867 int entries, i;
950 AVStream *st; 868
951 MOVStreamContext *sc; 869 print_atom("stsc", atom);
952
953 print_atom("stco", atom_type, atom_offset, atom_size);
954
955 st = c->fc->streams[c->fc->nb_streams-1];
956 sc = (MOVStreamContext *)st->priv_data;
957
958 get_byte(pb); /* version */
959 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
960
961 entries = get_be32(pb);
962 sc->chunk_count = entries;
963 sc->chunk_offsets = (int64_t*) av_malloc(entries * sizeof(int64_t));
964 if (!sc->chunk_offsets)
965 return -1;
966 if(atom_type == MKTAG('s', 't', 'c', 'o')) {
967 for(i=0; i<entries; i++) {
968 sc->chunk_offsets[i] = get_be32(pb);
969 }
970 } else if(atom_type == MKTAG('c', 'o', '6', '4')) {
971 for(i=0; i<entries; i++) {
972 sc->chunk_offsets[i] = get_be64(pb);
973 }
974 } else
975 return -1;
976 #ifdef DEBUG
977 /*
978 for(i=0; i<entries; i++) {
979 printf("chunk offset=0x%Lx\n", sc->chunk_offsets[i]);
980 }
981 */
982 #endif
983 return 0;
984 }
985
986 static int parse_stsc(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size)
987 {
988 int entries, i;
989 AVStream *st;
990 MOVStreamContext *sc;
991
992 print_atom("stsc", atom_type, atom_offset, atom_size);
993
994 st = c->fc->streams[c->fc->nb_streams-1];
995 sc = (MOVStreamContext *)st->priv_data;
996 870
997 get_byte(pb); /* version */ 871 get_byte(pb); /* version */
998 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 872 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
999 873
1000 entries = get_be32(pb); 874 entries = get_be32(pb);
1014 #endif 888 #endif
1015 } 889 }
1016 return 0; 890 return 0;
1017 } 891 }
1018 892
1019 static int parse_stsz(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 893 static int mov_read_stsz(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1020 { 894 {
895 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
896 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
1021 int entries, i; 897 int entries, i;
1022 AVStream *st; 898
1023 MOVStreamContext *sc; 899 print_atom("stsz", atom);
1024
1025 print_atom("stsz", atom_type, atom_offset, atom_size);
1026
1027 st = c->fc->streams[c->fc->nb_streams-1];
1028 sc = (MOVStreamContext *)st->priv_data;
1029 900
1030 get_byte(pb); /* version */ 901 get_byte(pb); /* version */
1031 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 902 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1032 903
1033 sc->sample_size = get_be32(pb); 904 sc->sample_size = get_be32(pb);
1048 #endif 919 #endif
1049 } 920 }
1050 return 0; 921 return 0;
1051 } 922 }
1052 923
1053 static int parse_stts(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 924 static int mov_read_stts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1054 { 925 {
926 AVStream *st = c->fc->streams[c->fc->nb_streams-1];
927 MOVStreamContext *sc = (MOVStreamContext *)st->priv_data;
1055 int entries, i; 928 int entries, i;
1056 AVStream *st; 929
1057 MOVStreamContext *sc; 930 print_atom("stts", atom);
1058
1059 print_atom("stts", atom_type, atom_offset, atom_size);
1060
1061 st = c->fc->streams[c->fc->nb_streams-1];
1062 sc = (MOVStreamContext *)st->priv_data;
1063 931
1064 get_byte(pb); /* version */ 932 get_byte(pb); /* version */
1065 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ 933 get_byte(pb); get_byte(pb); get_byte(pb); /* flags */
1066 entries = get_be32(pb); 934 entries = get_be32(pb);
1067 #ifdef DEBUG 935 #ifdef DEBUG
1082 } 950 }
1083 } 951 }
1084 return 0; 952 return 0;
1085 } 953 }
1086 954
955 static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
956 {
957 AVStream *st;
958 MOVStreamContext *sc;
959
960 print_atom("trak", atom);
961
962 st = av_new_stream(c->fc, c->fc->nb_streams);
963 if (!st) return -2;
964 sc = (MOVStreamContext*) av_mallocz(sizeof(MOVStreamContext));
965 if (!sc) {
966 av_free(st);
967 return -1;
968 }
969
970 sc->sample_to_chunk_index = -1;
971 st->priv_data = sc;
972 st->codec.codec_type = CODEC_TYPE_MOV_OTHER;
973 st->time_length = (c->duration * 1000) / c->time_scale; // time in miliseconds
974 c->streams[c->fc->nb_streams-1] = sc;
975
976 return mov_read_default(c, pb, atom);
977 }
978
979 static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
980 {
981 AVStream *st;
982
983 print_atom("tkhd", atom);
984
985 st = c->fc->streams[c->fc->nb_streams-1];
986
987 get_byte(pb); /* version */
988
989 get_byte(pb); get_byte(pb);
990 get_byte(pb); /* flags */
991 /*
992 MOV_TRACK_ENABLED 0x0001
993 MOV_TRACK_IN_MOVIE 0x0002
994 MOV_TRACK_IN_PREVIEW 0x0004
995 MOV_TRACK_IN_POSTER 0x0008
996 */
997
998 get_be32(pb); /* creation time */
999 get_be32(pb); /* modification time */
1000 st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/
1001 get_be32(pb); /* reserved */
1002 st->time_length = get_be32(pb) * 1000 / c->time_scale; /* duration */
1003 get_be32(pb); /* reserved */
1004 get_be32(pb); /* reserved */
1005
1006 get_be16(pb); /* layer */
1007 get_be16(pb); /* alternate group */
1008 get_be16(pb); /* volume */
1009 get_be16(pb); /* reserved */
1010
1011 url_fskip(pb, 36); /* display matrix */
1012
1013 /* those are fixed-point */
1014 st->codec.width = get_be32(pb) >> 16; /* track width */
1015 st->codec.height = get_be32(pb) >> 16; /* track height */
1016
1017 return 0;
1018 }
1019
1020 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */
1021 /* like the files created with Adobe Premiere 5.0, for samples see */
1022 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */
1023 static int mov_read_wide(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1024 {
1025 int err;
1026 uint32_t type;
1027
1028 #ifdef DEBUG
1029 print_atom("wide", atom);
1030 debug_indent++;
1031 #endif
1032 if (atom.size < 8)
1033 return 0; /* continue */
1034 if (get_be32(pb) != 0) { /* 0 sized mdat atom... use the 'wide' atom size */
1035 url_fskip(pb, atom.size - 4);
1036 return 0;
1037 }
1038 atom.type = get_le32(pb);
1039 atom.offset += 8;
1040 atom.size -= 8;
1041 if (type != MKTAG('m', 'd', 'a', 't')) {
1042 url_fskip(pb, atom.size);
1043 return 0;
1044 }
1045 err = mov_read_mdat(c, pb, atom);
1046 #ifdef DEBUG
1047 debug_indent--;
1048 #endif
1049 return err;
1050 }
1051
1052
1087 #ifdef CONFIG_ZLIB 1053 #ifdef CONFIG_ZLIB
1088 static int null_read_packet(void *opaque, uint8_t *buf, int buf_size) 1054 static int null_read_packet(void *opaque, uint8_t *buf, int buf_size)
1089 { 1055 {
1090 return -1; 1056 return -1;
1091 } 1057 }
1092 1058
1093 static int parse_cmov(MOVContext *c, ByteIOContext *pb, uint32_t atom_type, int64_t atom_offset, int64_t atom_size) 1059 static int mov_read_cmov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom)
1094 { 1060 {
1095 ByteIOContext ctx; 1061 ByteIOContext ctx;
1096 uint8_t *cmov_data; 1062 uint8_t *cmov_data;
1097 uint8_t *moov_data; /* uncompressed data */ 1063 uint8_t *moov_data; /* uncompressed data */
1098 long cmov_len, moov_len; 1064 long cmov_len, moov_len;
1099 int ret; 1065 int ret;
1100 1066
1101 print_atom("cmov", atom_type, atom_offset, atom_size); 1067 print_atom("cmov", atom);
1102 1068
1103 get_be32(pb); /* dcom atom */ 1069 get_be32(pb); /* dcom atom */
1104 if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' )) 1070 if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' ))
1105 return -1; 1071 return -1;
1106 if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) { 1072 if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) {
1107 puts("unknown compression for cmov atom !"); 1073 dprintf("unknown compression for cmov atom !");
1108 return -1; 1074 return -1;
1109 } 1075 }
1110 get_be32(pb); /* cmvd atom */ 1076 get_be32(pb); /* cmvd atom */
1111 if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' )) 1077 if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' ))
1112 return -1; 1078 return -1;
1113 moov_len = get_be32(pb); /* uncompressed size */ 1079 moov_len = get_be32(pb); /* uncompressed size */
1114 cmov_len = atom_size - 6 * 4; 1080 cmov_len = atom.size - 6 * 4;
1115 1081
1116 cmov_data = (uint8_t *) av_malloc(cmov_len); 1082 cmov_data = (uint8_t *) av_malloc(cmov_len);
1117 if (!cmov_data) 1083 if (!cmov_data)
1118 return -1; 1084 return -1;
1119 moov_data = (uint8_t *) av_malloc(moov_len); 1085 moov_data = (uint8_t *) av_malloc(moov_len);
1125 if(uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) 1091 if(uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK)
1126 return -1; 1092 return -1;
1127 if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, null_read_packet, NULL, NULL) != 0) 1093 if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, null_read_packet, NULL, NULL) != 0)
1128 return -1; 1094 return -1;
1129 ctx.buf_end = ctx.buffer + moov_len; 1095 ctx.buf_end = ctx.buffer + moov_len;
1130 ret = parse_default(c, &ctx, MKTAG( 'm', 'o', 'o', 'v' ), 0, moov_len); 1096 atom.type = MKTAG( 'm', 'o', 'o', 'v' );
1097 atom.offset = 0;
1098 atom.size = moov_len;
1099 ret = mov_read_default(c, &ctx, atom);
1131 av_free(moov_data); 1100 av_free(moov_data);
1132 av_free(cmov_data); 1101 av_free(cmov_data);
1133 return ret; 1102 return ret;
1134 } 1103 }
1135 #endif 1104 #endif
1136 1105
1137 static const MOVParseTableEntry mov_default_parse_table[] = { 1106 static const MOVParseTableEntry mov_default_parse_table[] = {
1138 /* mp4 atoms */ 1107 /* mp4 atoms */
1139 { MKTAG( 'm', 'p', '4', 'a' ), parse_default }, 1108 { MKTAG( 'c', 'o', '6', '4' ), mov_read_stco },
1140 { MKTAG( 'c', 'o', '6', '4' ), parse_stco }, 1109 { MKTAG( 'c', 'p', 'r', 't' ), mov_read_default },
1141 { MKTAG( 's', 't', 'c', 'o' ), parse_stco }, 1110 { MKTAG( 'c', 'r', 'h', 'd' ), mov_read_default },
1142 { MKTAG( 'c', 'r', 'h', 'd' ), parse_default }, 1111 { MKTAG( 'c', 't', 't', 's' ), mov_read_leaf }, /* composition time to sample */
1143 { MKTAG( 'c', 't', 't', 's' ), parse_leaf }, 1112 { MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, /* data information */
1144 { MKTAG( 'c', 'p', 'r', 't' ), parse_default }, 1113 { MKTAG( 'd', 'p', 'n', 'd' ), mov_read_leaf },
1145 { MKTAG( 'u', 'r', 'l', ' ' ), parse_leaf }, 1114 { MKTAG( 'd', 'r', 'e', 'f' ), mov_read_leaf },
1146 { MKTAG( 'u', 'r', 'n', ' ' ), parse_leaf }, 1115 { MKTAG( 'e', 'd', 't', 's' ), mov_read_default },
1147 { MKTAG( 'd', 'i', 'n', 'f' ), parse_default }, 1116 { MKTAG( 'e', 'l', 's', 't' ), mov_read_leaf },
1148 { MKTAG( 'd', 'r', 'e', 'f' ), parse_leaf }, 1117 { MKTAG( 'f', 'r', 'e', 'e' ), mov_read_leaf },
1149 { MKTAG( 's', 't', 'd', 'p' ), parse_default }, 1118 { MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr },
1150 { MKTAG( 'e', 'd', 't', 's' ), parse_default }, 1119 { MKTAG( 'h', 'i', 'n', 't' ), mov_read_leaf },
1151 { MKTAG( 'e', 'l', 's', 't' ), parse_leaf }, 1120 { MKTAG( 'h', 'm', 'h', 'd' ), mov_read_leaf },
1152 { MKTAG( 'u', 'u', 'i', 'd' ), parse_default }, 1121 { MKTAG( 'i', 'o', 'd', 's' ), mov_read_leaf },
1153 { MKTAG( 'f', 'r', 'e', 'e' ), parse_leaf }, 1122 { MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat },
1154 { MKTAG( 'h', 'd', 'l', 'r' ), parse_hdlr }, 1123 { MKTAG( 'm', 'd', 'h', 'd' ), mov_read_mdhd },
1155 { MKTAG( 'h', 'm', 'h', 'd' ), parse_leaf }, 1124 { MKTAG( 'm', 'd', 'i', 'a' ), mov_read_default },
1156 { MKTAG( 'h', 'i', 'n', 't' ), parse_leaf }, 1125 { MKTAG( 'm', 'i', 'n', 'f' ), mov_read_default },
1157 { MKTAG( 'n', 'm', 'h', 'd' ), parse_leaf }, 1126 { MKTAG( 'm', 'o', 'o', 'v' ), mov_read_moov },
1158 { MKTAG( 'm', 'p', '4', 's' ), parse_default }, 1127 { MKTAG( 'm', 'p', '4', 'a' ), mov_read_default },
1159 { MKTAG( 'm', 'd', 'i', 'a' ), parse_default }, 1128 { MKTAG( 'm', 'p', '4', 's' ), mov_read_default },
1160 { MKTAG( 'm', 'd', 'a', 't' ), parse_mdat }, 1129 { MKTAG( 'm', 'p', '4', 'v' ), mov_read_default },
1161 { MKTAG( 'm', 'd', 'h', 'd' ), parse_mdhd }, 1130 { MKTAG( 'm', 'p', 'o', 'd' ), mov_read_leaf },
1162 { MKTAG( 'm', 'i', 'n', 'f' ), parse_default }, 1131 { MKTAG( 'm', 'v', 'h', 'd' ), mov_read_mvhd },
1163 { MKTAG( 'm', 'o', 'o', 'v' ), parse_moov }, 1132 { MKTAG( 'n', 'm', 'h', 'd' ), mov_read_leaf },
1164 { MKTAG( 'm', 'v', 'h', 'd' ), parse_mvhd }, 1133 { MKTAG( 'o', 'd', 'h', 'd' ), mov_read_default },
1165 { MKTAG( 'i', 'o', 'd', 's' ), parse_leaf }, 1134 { MKTAG( 's', 'd', 'h', 'd' ), mov_read_default },
1166 { MKTAG( 'o', 'd', 'h', 'd' ), parse_default }, 1135 { MKTAG( 's', 'k', 'i', 'p' ), mov_read_default },
1167 { MKTAG( 'm', 'p', 'o', 'd' ), parse_leaf }, 1136 { MKTAG( 's', 'm', 'h', 'd' ), mov_read_leaf }, /* sound media info header */
1168 { MKTAG( 's', 't', 's', 'd' ), parse_stsd }, 1137 { MKTAG( 's', 't', 'b', 'l' ), mov_read_default },
1169 { MKTAG( 's', 't', 's', 'z' ), parse_stsz }, 1138 { MKTAG( 's', 't', 'c', 'o' ), mov_read_stco },
1170 { MKTAG( 's', 't', 'b', 'l' ), parse_default }, 1139 { MKTAG( 's', 't', 'd', 'p' ), mov_read_default },
1171 { MKTAG( 's', 't', 's', 'c' ), parse_stsc }, 1140 { MKTAG( 's', 't', 's', 'c' ), mov_read_stsc },
1172 { MKTAG( 's', 'd', 'h', 'd' ), parse_default }, 1141 { MKTAG( 's', 't', 's', 'd' ), mov_read_stsd }, /* sample description */
1173 { MKTAG( 's', 't', 's', 'h' ), parse_default }, 1142 { MKTAG( 's', 't', 's', 'h' ), mov_read_default },
1174 { MKTAG( 's', 'k', 'i', 'p' ), parse_default }, 1143 { MKTAG( 's', 't', 's', 's' ), mov_read_leaf }, /* sync sample */
1175 { MKTAG( 's', 'm', 'h', 'd' ), parse_leaf }, 1144 { MKTAG( 's', 't', 's', 'z' ), mov_read_stsz }, /* sample size */
1176 { MKTAG( 'd', 'p', 'n', 'd' ), parse_leaf }, 1145 { MKTAG( 's', 't', 't', 's' ), mov_read_stts },
1177 { MKTAG( 's', 't', 's', 's' ), parse_leaf }, 1146 { MKTAG( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */
1178 { MKTAG( 's', 't', 't', 's' ), parse_stts }, 1147 { MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak },
1179 { MKTAG( 't', 'r', 'a', 'k' ), parse_trak }, 1148 { MKTAG( 't', 'r', 'e', 'f' ), mov_read_default }, /* not really */
1180 { MKTAG( 't', 'k', 'h', 'd' ), parse_tkhd }, 1149 { MKTAG( 'u', 'd', 't', 'a' ), mov_read_leaf },
1181 { MKTAG( 't', 'r', 'e', 'f' ), parse_default }, /* not really */ 1150 { MKTAG( 'u', 'r', 'l', ' ' ), mov_read_leaf },
1182 { MKTAG( 'u', 'd', 't', 'a' ), parse_leaf }, 1151 { MKTAG( 'u', 'r', 'n', ' ' ), mov_read_leaf },
1183 { MKTAG( 'v', 'm', 'h', 'd' ), parse_leaf }, 1152 { MKTAG( 'u', 'u', 'i', 'd' ), mov_read_default },
1184 { MKTAG( 'm', 'p', '4', 'v' ), parse_default }, 1153 { MKTAG( 'v', 'm', 'h', 'd' ), mov_read_leaf }, /* video media info header */
1154 { MKTAG( 'w', 'a', 'v', 'e' ), mov_read_default },
1185 /* extra mp4 */ 1155 /* extra mp4 */
1186 { MKTAG( 'M', 'D', 'E', 'S' ), parse_leaf }, 1156 { MKTAG( 'M', 'D', 'E', 'S' ), mov_read_leaf },
1187 /* QT atoms */ 1157 /* QT atoms */
1188 { MKTAG( 'c', 'h', 'a', 'p' ), parse_leaf }, 1158 { MKTAG( 'c', 'h', 'a', 'p' ), mov_read_leaf },
1189 { MKTAG( 'c', 'l', 'i', 'p' ), parse_default }, 1159 { MKTAG( 'c', 'l', 'i', 'p' ), mov_read_default },
1190 { MKTAG( 'c', 'r', 'g', 'n' ), parse_leaf }, 1160 { MKTAG( 'c', 'r', 'g', 'n' ), mov_read_leaf },
1191 { MKTAG( 'k', 'm', 'a', 't' ), parse_leaf }, 1161 { MKTAG( 'c', 't', 'a', 'b' ), mov_read_ctab },
1192 { MKTAG( 'm', 'a', 't', 't' ), parse_default }, 1162 { MKTAG( 'e', 's', 'd', 's' ), mov_read_esds },
1193 { MKTAG( 'r', 'd', 'r', 'f' ), parse_leaf }, 1163 { MKTAG( 'k', 'm', 'a', 't' ), mov_read_leaf },
1194 { MKTAG( 'r', 'm', 'd', 'a' ), parse_default }, 1164 { MKTAG( 'm', 'a', 't', 't' ), mov_read_default },
1195 { MKTAG( 'r', 'm', 'd', 'r' ), parse_leaf }, 1165 { MKTAG( 'r', 'd', 'r', 'f' ), mov_read_leaf },
1196 //{ MKTAG( 'r', 'm', 'q', 'u' ), parse_leaf }, 1166 { MKTAG( 'r', 'm', 'd', 'a' ), mov_read_default },
1197 { MKTAG( 'r', 'm', 'r', 'a' ), parse_default }, 1167 { MKTAG( 'r', 'm', 'd', 'r' ), mov_read_leaf },
1198 { MKTAG( 's', 'c', 'p', 't' ), parse_leaf }, 1168 { MKTAG( 'r', 'm', 'r', 'a' ), mov_read_default },
1199 { MKTAG( 's', 'y', 'n', 'c' ), parse_leaf }, 1169 { MKTAG( 's', 'c', 'p', 't' ), mov_read_leaf },
1200 { MKTAG( 's', 's', 'r', 'c' ), parse_leaf }, 1170 { MKTAG( 's', 's', 'r', 'c' ), mov_read_leaf },
1201 { MKTAG( 't', 'c', 'm', 'd' ), parse_leaf }, 1171 { MKTAG( 's', 'y', 'n', 'c' ), mov_read_leaf },
1202 { MKTAG( 'w', 'i', 'd', 'e' ), parse_wide }, /* place holder */ 1172 { MKTAG( 't', 'c', 'm', 'd' ), mov_read_leaf },
1203 { MKTAG( 'c', 't', 'a', 'b' ), parse_ctab }, 1173 { MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder */
1204 { MKTAG( 'e', 's', 'd', 's' ), parse_esds }, 1174 //{ MKTAG( 'r', 'm', 'q', 'u' ), mov_read_leaf },
1205 #ifdef CONFIG_ZLIB 1175 #ifdef CONFIG_ZLIB
1206 { MKTAG( 'c', 'm', 'o', 'v' ), parse_cmov }, 1176 { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov },
1207 #else 1177 #else
1208 { MKTAG( 'c', 'm', 'o', 'v' ), parse_leaf }, 1178 { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_leaf },
1209 #endif 1179 #endif
1210 { 0L, parse_leaf } 1180 { 0L, mov_read_leaf }
1211 }; 1181 };
1212 1182
1213 static void mov_free_stream_context(MOVStreamContext *sc) 1183 static void mov_free_stream_context(MOVStreamContext *sc)
1214 { 1184 {
1215 if(sc) { 1185 if(sc) {
1219 av_free(sc->header_data); 1189 av_free(sc->header_data);
1220 av_free(sc); 1190 av_free(sc);
1221 } 1191 }
1222 } 1192 }
1223 1193
1224 static inline uint32_t to_tag(uint8_t *buf) 1194 static inline uint32_t mov_to_tag(uint8_t *buf)
1225 { 1195 {
1226 return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 1196 return MKTAG(buf[0], buf[1], buf[2], buf[3]);
1227 } 1197 }
1228 1198
1229 static inline uint32_t to_be32(uint8_t *buf) 1199 static inline uint32_t to_be32(uint8_t *buf)
1230 { 1200 {
1231 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 1201 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
1243 offset = 0; 1213 offset = 0;
1244 for(;;) { 1214 for(;;) {
1245 /* ignore invalid offset */ 1215 /* ignore invalid offset */
1246 if ((offset + 8) > (unsigned int)p->buf_size) 1216 if ((offset + 8) > (unsigned int)p->buf_size)
1247 return 0; 1217 return 0;
1248 tag = to_tag(p->buf + offset + 4); 1218 tag = mov_to_tag(p->buf + offset + 4);
1249 switch(tag) { 1219 switch(tag) {
1250 case MKTAG( 'm', 'o', 'o', 'v' ): 1220 case MKTAG( 'm', 'o', 'o', 'v' ):
1251 case MKTAG( 'w', 'i', 'd', 'e' ): 1221 case MKTAG( 'w', 'i', 'd', 'e' ):
1252 case MKTAG( 'f', 'r', 'e', 'e' ): 1222 case MKTAG( 'f', 'r', 'e', 'e' ):
1253 case MKTAG( 'm', 'd', 'a', 't' ): 1223 case MKTAG( 'm', 'd', 'a', 't' ):
1254 case MKTAG( 'p', 'n', 'o', 't' ): /* detect movs with preview pics like ew.mov and april.mov */ 1224 case MKTAG( 'p', 'n', 'o', 't' ): /* detect movs with preview pics like ew.mov and april.mov */
1255 return AVPROBE_SCORE_MAX; 1225 return AVPROBE_SCORE_MAX;
1256 case MKTAG( 'f', 't', 'y', 'p' ): 1226 case MKTAG( 'f', 't', 'y', 'p' ):
1257 case MKTAG( 's', 'k', 'i', 'p' ): 1227 case MKTAG( 's', 'k', 'i', 'p' ):
1258 offset = to_be32(p->buf) + offset; 1228 offset = to_be32(p->buf) + offset;
1259 break; 1229 break;
1260 default: 1230 default:
1261 /* unrecognized tag */ 1231 /* unrecognized tag */
1262 return 0; 1232 return 0;
1268 static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) 1238 static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap)
1269 { 1239 {
1270 MOVContext *mov = (MOVContext *) s->priv_data; 1240 MOVContext *mov = (MOVContext *) s->priv_data;
1271 ByteIOContext *pb = &s->pb; 1241 ByteIOContext *pb = &s->pb;
1272 int i, j, nb, err; 1242 int i, j, nb, err;
1273 int64_t size; 1243 MOV_atom_t atom = { 0, 0, 0 };
1274 1244
1275 mov->fc = s; 1245 mov->fc = s;
1276 mov->parse_table = mov_default_parse_table; 1246 mov->parse_table = mov_default_parse_table;
1277 #if 0 1247 #if 0
1278 /* XXX: I think we should auto detect */ 1248 /* XXX: I think we should auto detect */
1279 if(s->iformat->name[1] == 'p') 1249 if(s->iformat->name[1] == 'p')
1280 mov->mp4 = 1; 1250 mov->mp4 = 1;
1281 #endif 1251 #endif
1282 if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ 1252 if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */
1283 size = url_filesize(url_fileno(pb)); 1253 atom.size = url_filesize(url_fileno(pb));
1284 else 1254 else
1285 size = 0x7FFFFFFFFFFFFFFF; 1255 atom.size = 0x7FFFFFFFFFFFFFFF;
1286 1256
1287 #ifdef DEBUG 1257 #ifdef DEBUG
1288 printf("filesz=%Ld\n", size); 1258 printf("filesz=%Ld\n", atom.size);
1289 #endif 1259 #endif
1290 1260
1291 /* check MOV header */ 1261 /* check MOV header */
1292 err = parse_default(mov, pb, 0L, 0LL, size); 1262 err = mov_read_default(mov, pb, atom);
1293 if(err<0 || (!mov->found_moov || !mov->found_mdat)) { 1263 if(err<0 || (!mov->found_moov || !mov->found_mdat)) {
1294 puts("header not found !!!"); 1264 puts("header not found !!!");
1295 exit(1); 1265 exit(1);
1296 } 1266 }
1297 #ifdef DEBUG 1267 #ifdef DEBUG
1309 1279
1310 #ifdef DEBUG 1280 #ifdef DEBUG
1311 printf("streams= %d\n", s->nb_streams); 1281 printf("streams= %d\n", s->nb_streams);
1312 #endif 1282 #endif
1313 mov->total_streams = nb = s->nb_streams; 1283 mov->total_streams = nb = s->nb_streams;
1314 1284
1315 #if 1 1285 #if 1
1316 for(i=0; i<s->nb_streams;) { 1286 for(i=0; i<s->nb_streams;) {
1317 if(s->streams[i]->codec.codec_type == CODEC_TYPE_MOV_OTHER) {/* not audio, not video, delete */ 1287 if(s->streams[i]->codec.codec_type == CODEC_TYPE_MOV_OTHER) {/* not audio, not video, delete */
1318 av_free(s->streams[i]); 1288 av_free(s->streams[i]);
1319 for(j=i+1; j<s->nb_streams; j++) 1289 for(j=i+1; j<s->nb_streams; j++)
1472 MOVContext *mov = (MOVContext *) s->priv_data; 1442 MOVContext *mov = (MOVContext *) s->priv_data;
1473 for(i=0; i<mov->total_streams; i++) 1443 for(i=0; i<mov->total_streams; i++)
1474 mov_free_stream_context(mov->streams[i]); 1444 mov_free_stream_context(mov->streams[i]);
1475 for(i=0; i<s->nb_streams; i++) 1445 for(i=0; i<s->nb_streams; i++)
1476 av_freep(&s->streams[i]); 1446 av_freep(&s->streams[i]);
1447 /* free color tabs */
1448 for(i=0; i<mov->ctab_size; i++)
1449 av_freep(&mov->ctab[i]);
1450 av_freep(&mov->ctab);
1477 return 0; 1451 return 0;
1478 } 1452 }
1479 1453
1480 static AVInputFormat mov_iformat = { 1454 static AVInputFormat mov_iformat = {
1481 "mov", 1455 "mov",