Statistics
| Branch: | Revision:

ffmpeg / libavformat / mov.c @ 5cd62665

History | View | Annotate | Download (48.1 KB)

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
}