mov.c 79.1 KB
Newer Older
1
/*
2
 * MOV demuxer
3
 * Copyright (c) 2001 Fabrice Bellard
4
 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
5
 *
6 7 8
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
Fabrice Bellard's avatar
Fabrice Bellard committed
9 10
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Fabrice Bellard's avatar
Fabrice Bellard committed
15 16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
17
 *
Fabrice Bellard's avatar
Fabrice Bellard committed
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with FFmpeg; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22 23

#include <limits.h>
24

Baptiste Coudurier's avatar
Baptiste Coudurier committed
25
//#define DEBUG
26 27
//#define DEBUG_METADATA
//#define MOV_EXPORT_ALL_METADATA
28

29
#include "libavutil/intreadwrite.h"
30
#include "libavutil/avstring.h"
31
#include "avformat.h"
32
#include "riff.h"
33
#include "isom.h"
34 35
#include "libavcodec/mpeg4audio.h"
#include "libavcodec/mpegaudiodata.h"
36
#include "libavcodec/get_bits.h"
37

38
#if CONFIG_ZLIB
39 40 41
#include <zlib.h>
#endif

42 43
/*
 * First version by Francois Revol revol@free.fr
44
 * Seek function by Gael Chardon gael.dev@4now.net
45
 *
46
 * Features and limitations:
47
 * - reads most of the QT files I have (at least the structure),
48 49
 *   Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html
 * - the code is quite ugly... maybe I won't do it recursive next time :-)
50
 *
51 52
 * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/
 * when coding this :) (it's a writer anyway)
53
 *
54 55 56
 * Reference documents:
 * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
 * Apple:
Gael Chardon's avatar
Gael Chardon committed
57
 *  http://developer.apple.com/documentation/QuickTime/QTFF/
58
 *  http://developer.apple.com/documentation/QuickTime/QTFF/qtff.pdf
59 60 61
 * QuickTime is a trademark of Apple (AFAIK :))
 */

62 63
#include "qtpalette.h"

Gael Chardon's avatar
Gael Chardon committed
64

65 66 67
#undef NDEBUG
#include <assert.h>

68 69 70 71
/* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */

/* those functions parse an atom */
/* return code:
Baptiste Coudurier's avatar
Baptiste Coudurier committed
72
  0: continue to parse next atom
Diego Biurrun's avatar
Diego Biurrun committed
73
 <0: error occurred, exit
Baptiste Coudurier's avatar
Baptiste Coudurier committed
74
*/
75 76
/* links atom IDs to parse functions */
typedef struct MOVParseTableEntry {
77
    uint32_t type;
78
    int (*parse)(MOVContext *ctx, ByteIOContext *pb, MOVAtom atom);
79 80
} MOVParseTableEntry;

81 82
static const MOVParseTableEntry mov_default_parse_table[];

Baptiste Coudurier's avatar
Baptiste Coudurier committed
83 84 85 86 87 88 89 90 91 92 93 94 95
static int mov_metadata_trkn(MOVContext *c, ByteIOContext *pb, unsigned len)
{
    char buf[16];

    get_be16(pb); // unknown
    snprintf(buf, sizeof(buf), "%d", get_be16(pb));
    av_metadata_set(&c->fc->metadata, "track", buf);

    get_be16(pb); // total tracks

    return 0;
}

96 97 98 99 100 101 102 103
static int mov_read_udta_string(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
#ifdef MOV_EXPORT_ALL_METADATA
    char tmp_key[5];
#endif
    char str[1024], key2[16], language[4] = {0};
    const char *key = NULL;
    uint16_t str_size;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
104
    int (*parse)(MOVContext*, ByteIOContext*, unsigned) = NULL;
105 106 107 108

    switch (atom.type) {
    case MKTAG(0xa9,'n','a','m'): key = "title";     break;
    case MKTAG(0xa9,'a','u','t'):
109 110
    case MKTAG(0xa9,'A','R','T'): key = "author";    break;
    case MKTAG(0xa9,'w','r','t'): key = "composer";  break;
111
    case MKTAG( 'c','p','r','t'):
112 113 114 115
    case MKTAG(0xa9,'c','p','y'): key = "copyright"; break;
    case MKTAG(0xa9,'c','m','t'):
    case MKTAG(0xa9,'i','n','f'): key = "comment";   break;
    case MKTAG(0xa9,'a','l','b'): key = "album";     break;
116
    case MKTAG(0xa9,'d','a','y'): key = "date";      break;
117 118
    case MKTAG(0xa9,'g','e','n'): key = "genre";     break;
    case MKTAG(0xa9,'t','o','o'):
119
    case MKTAG(0xa9,'e','n','c'): key = "encoder";   break;
120 121 122 123 124
    case MKTAG( 'd','e','s','c'): key = "description";break;
    case MKTAG( 'l','d','e','s'): key = "synopsis";  break;
    case MKTAG( 't','v','s','h'): key = "show";      break;
    case MKTAG( 't','v','e','n'): key = "episode_id";break;
    case MKTAG( 't','v','n','n'): key = "network";   break;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
125 126
    case MKTAG( 't','r','k','n'): key = "track";
        parse = mov_metadata_trkn; break;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
    }

    if (c->itunes_metadata && atom.size > 8) {
        int data_size = get_be32(pb);
        int tag = get_le32(pb);
        if (tag == MKTAG('d','a','t','a')) {
            get_be32(pb); // type
            get_be32(pb); // unknown
            str_size = data_size - 16;
            atom.size -= 16;
        } else return 0;
    } else if (atom.size > 4 && key && !c->itunes_metadata) {
        str_size = get_be16(pb); // string length
        ff_mov_lang_to_iso639(get_be16(pb), language);
        atom.size -= 4;
    } else
        str_size = atom.size;

#ifdef MOV_EXPORT_ALL_METADATA
    if (!key) {
        snprintf(tmp_key, 5, "%.4s", (char*)&atom.type);
        key = tmp_key;
    }
#endif

    if (!key)
        return 0;
    if (atom.size < 0)
        return -1;

    str_size = FFMIN3(sizeof(str)-1, str_size, atom.size);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
158 159 160 161

    if (parse)
        parse(c, pb, str_size);
    else {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
162 163 164 165 166 167 168
        get_buffer(pb, str, str_size);
        str[str_size] = 0;
        av_metadata_set(&c->fc->metadata, key, str);
        if (*language && strcmp(language, "und")) {
            snprintf(key2, sizeof(key2), "%s-%s", key, language);
            av_metadata_set(&c->fc->metadata, key2, str);
        }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
169
    }
170 171 172 173 174 175 176 177
#ifdef DEBUG_METADATA
    av_log(c->fc, AV_LOG_DEBUG, "lang \"%3s\" ", language);
    av_log(c->fc, AV_LOG_DEBUG, "tag \"%s\" value \"%s\" atom \"%.4s\" %d %lld\n",
           key, str, (char*)&atom.type, str_size, atom.size);
#endif

    return 0;
}
178

179
static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
180
{
181
    int64_t total_size = 0;
182
    MOVAtom a;
183
    int i;
184

185
    if (atom.size < 0)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
186
        atom.size = INT64_MAX;
187
    while (total_size + 8 < atom.size && !url_feof(pb)) {
188
        int (*parse)(MOVContext*, ByteIOContext*, MOVAtom) = NULL;
189
        a.size = atom.size;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
190
        a.type=0;
191
        if(atom.size >= 8) {
192
            a.size = get_be32(pb);
193
            a.type = get_le32(pb);
194
        }
195
        total_size += 8;
196 197
        dprintf(c->fc, "type: %08x  %.4s  sz: %"PRIx64"  %"PRIx64"   %"PRIx64"\n",
                a.type, (char*)&a.type, a.size, atom.size, total_size);
198
        if (a.size == 1) { /* 64 bit extended size */
199
            a.size = get_be64(pb) - 8;
200
            total_size += 8;
201
        }
202 203 204
        if (a.size == 0) {
            a.size = atom.size - total_size;
            if (a.size <= 8)
205
                break;
206 207
        }
        a.size -= 8;
208
        if(a.size < 0)
209
            break;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
210
        a.size = FFMIN(a.size, atom.size - total_size);
211

212 213 214 215 216
        for (i = 0; mov_default_parse_table[i].type; i++)
            if (mov_default_parse_table[i].type == a.type) {
                parse = mov_default_parse_table[i].parse;
                break;
            }
217

218 219 220 221 222 223
        // container is user data
        if (!parse && (atom.type == MKTAG('u','d','t','a') ||
                       atom.type == MKTAG('i','l','s','t')))
            parse = mov_read_udta_string;

        if (!parse) { /* skip leaf atoms data */
224
            url_fskip(pb, a.size);
225
        } else {
226
            int64_t start_pos = url_ftell(pb);
227
            int64_t left;
228 229 230
            int err = parse(c, pb, a);
            if (err < 0)
                return err;
231 232 233
            if (c->found_moov && c->found_mdat &&
                (url_is_streamed(pb) || start_pos + a.size == url_fsize(pb)))
                return 0;
234 235 236
            left = a.size - url_ftell(pb) + start_pos;
            if (left > 0) /* skip garbage at atom end */
                url_fskip(pb, left);
237
        }
238

239
        total_size += a.size;
240 241
    }

242
    if (total_size < atom.size && atom.size < 0x7ffff)
243
        url_fskip(pb, atom.size - total_size);
244

245
    return 0;
246 247
}

248
static int mov_read_dref(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
249
{
250 251
    AVStream *st;
    MOVStreamContext *sc;
252 253
    int entries, i, j;

254 255 256 257 258
    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
    sc = st->priv_data;

259 260 261 262 263
    get_be32(pb); // version + flags
    entries = get_be32(pb);
    if (entries >= UINT_MAX / sizeof(*sc->drefs))
        return -1;
    sc->drefs = av_mallocz(entries * sizeof(*sc->drefs));
264 265 266
    if (!sc->drefs)
        return AVERROR(ENOMEM);
    sc->drefs_count = entries;
267 268

    for (i = 0; i < sc->drefs_count; i++) {
269
        MOVDref *dref = &sc->drefs[i];
270
        uint32_t size = get_be32(pb);
271
        int64_t next = url_ftell(pb) + size - 4;
272 273 274 275 276 277 278 279 280 281 282 283 284 285

        dref->type = get_le32(pb);
        get_be32(pb); // version + flags
        dprintf(c->fc, "type %.4s size %d\n", (char*)&dref->type, size);

        if (dref->type == MKTAG('a','l','i','s') && size > 150) {
            /* macintosh alias record */
            uint16_t volume_len, len;
            int16_t type;

            url_fskip(pb, 10);

            volume_len = get_byte(pb);
            volume_len = FFMIN(volume_len, 27);
286 287 288
            get_buffer(pb, dref->volume, 27);
            dref->volume[volume_len] = 0;
            av_log(c->fc, AV_LOG_DEBUG, "volume %s, len %d\n", dref->volume, volume_len);
289

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
            url_fskip(pb, 12);

            len = get_byte(pb);
            len = FFMIN(len, 63);
            get_buffer(pb, dref->filename, 63);
            dref->filename[len] = 0;
            av_log(c->fc, AV_LOG_DEBUG, "filename %s, len %d\n", dref->filename, len);

            url_fskip(pb, 16);

            /* read next level up_from_alias/down_to_target */
            dref->nlvl_from = get_be16(pb);
            dref->nlvl_to   = get_be16(pb);
            av_log(c->fc, AV_LOG_DEBUG, "nlvl from %d, nlvl to %d\n",
                   dref->nlvl_from, dref->nlvl_to);

            url_fskip(pb, 16);
307 308 309 310 311 312 313 314

            for (type = 0; type != -1 && url_ftell(pb) < next; ) {
                type = get_be16(pb);
                len = get_be16(pb);
                av_log(c->fc, AV_LOG_DEBUG, "type %d, len %d\n", type, len);
                if (len&1)
                    len += 1;
                if (type == 2) { // absolute path
315
                    av_free(dref->path);
316
                    dref->path = av_mallocz(len+1);
317 318
                    if (!dref->path)
                        return AVERROR(ENOMEM);
319
                    get_buffer(pb, dref->path, len);
320
                    if (len > volume_len && !strncmp(dref->path, dref->volume, volume_len)) {
321 322 323 324 325 326 327 328
                        len -= volume_len;
                        memmove(dref->path, dref->path+volume_len, len);
                        dref->path[len] = 0;
                    }
                    for (j = 0; j < len; j++)
                        if (dref->path[j] == ':')
                            dref->path[j] = '/';
                    av_log(c->fc, AV_LOG_DEBUG, "path %s\n", dref->path);
329 330 331 332 333 334 335 336 337 338 339
                } else if (type == 0) { // directory name
                    av_free(dref->dir);
                    dref->dir = av_malloc(len+1);
                    if (!dref->dir)
                        return AVERROR(ENOMEM);
                    get_buffer(pb, dref->dir, len);
                    dref->dir[len] = 0;
                    for (j = 0; j < len; j++)
                        if (dref->dir[j] == ':')
                            dref->dir[j] = '/';
                    av_log(c->fc, AV_LOG_DEBUG, "dir %s\n", dref->dir);
340 341 342 343 344 345 346 347 348
                } else
                    url_fskip(pb, len);
            }
        }
        url_fseek(pb, next, SEEK_SET);
    }
    return 0;
}

349
static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
350
{
351
    AVStream *st;
352 353
    uint32_t type;
    uint32_t ctype;
354

355 356 357 358 359
    if (c->fc->nb_streams < 1) // meta before first trak
        return 0;

    st = c->fc->streams[c->fc->nb_streams-1];

360
    get_byte(pb); /* version */
361
    get_be24(pb); /* flags */
362 363 364 365 366

    /* component type */
    ctype = get_le32(pb);
    type = get_le32(pb); /* component subtype */

Baptiste Coudurier's avatar
Baptiste Coudurier committed
367 368
    dprintf(c->fc, "ctype= %.4s (0x%08x)\n", (char*)&ctype, ctype);
    dprintf(c->fc, "stype= %.4s\n", (char*)&type);
369

370
    if     (type == MKTAG('v','i','d','e'))
371
        st->codec->codec_type = CODEC_TYPE_VIDEO;
372
    else if(type == MKTAG('s','o','u','n'))
373
        st->codec->codec_type = CODEC_TYPE_AUDIO;
374
    else if(type == MKTAG('m','1','a',' '))
375
        st->codec->codec_id = CODEC_ID_MP2;
376
    else if(type == MKTAG('s','u','b','p'))
377
        st->codec->codec_type = CODEC_TYPE_SUBTITLE;
378

379 380 381 382 383 384 385
    get_be32(pb); /* component  manufacture */
    get_be32(pb); /* component flags */
    get_be32(pb); /* component flags mask */

    return 0;
}

386
int ff_mp4_read_descr_len(ByteIOContext *pb)
387
{
388
    int len = 0;
389 390
    int count = 4;
    while (count--) {
391
        int c = get_byte(pb);
392 393 394
        len = (len << 7) | (c & 0x7f);
        if (!(c & 0x80))
            break;
395 396 397 398
    }
    return len;
}

399
int mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag)
400 401 402
{
    int len;
    *tag = get_byte(pb);
403 404
    len = ff_mp4_read_descr_len(pb);
    dprintf(fc, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len);
405 406 407
    return len;
}

408 409 410 411
#define MP4ESDescrTag                   0x03
#define MP4DecConfigDescrTag            0x04
#define MP4DecSpecificDescrTag          0x05

412
static const AVCodecTag mp4_audio_types[] = {
413 414 415 416
    { CODEC_ID_MP3ON4, AOT_PS   }, /* old mp3on4 draft */
    { CODEC_ID_MP3ON4, AOT_L1   }, /* layer 1 */
    { CODEC_ID_MP3ON4, AOT_L2   }, /* layer 2 */
    { CODEC_ID_MP3ON4, AOT_L3   }, /* layer 3 */
417
    { CODEC_ID_MP4ALS, AOT_ALS  }, /* MPEG-4 ALS */
418
    { CODEC_ID_NONE,   AOT_NULL },
419 420
};

421
int ff_mov_read_esds(AVFormatContext *fc, ByteIOContext *pb, MOVAtom atom)
422
{
423
    AVStream *st;
424
    int tag, len;
425

426
    if (fc->nb_streams < 1)
427
        return 0;
428
    st = fc->streams[fc->nb_streams-1];
429

430
    get_be32(pb); /* version + flags */
431
    len = mp4_read_descr(fc, pb, &tag);
432
    if (tag == MP4ESDescrTag) {
433 434
        get_be16(pb); /* ID */
        get_byte(pb); /* priority */
435
    } else
436
        get_be16(pb); /* ID */
437

438
    len = mp4_read_descr(fc, pb, &tag);
439
    if (tag == MP4DecConfigDescrTag) {
440 441 442 443 444 445
        int object_type_id = get_byte(pb);
        get_byte(pb); /* stream type */
        get_be24(pb); /* buffer size db */
        get_be32(pb); /* max bitrate */
        get_be32(pb); /* avg bitrate */

446
        st->codec->codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id);
447
        dprintf(fc, "esds object type id 0x%02x\n", object_type_id);
448
        len = mp4_read_descr(fc, pb, &tag);
449
        if (tag == MP4DecSpecificDescrTag) {
450
            dprintf(fc, "Specific MPEG4 header len=%d\n", len);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
451 452
            if((uint64_t)len > (1<<30))
                return -1;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
453
            st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
454 455
            if (!st->codec->extradata)
                return AVERROR(ENOMEM);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
456 457
            get_buffer(pb, st->codec->extradata, len);
            st->codec->extradata_size = len;
458 459 460 461
            if (st->codec->codec_id == CODEC_ID_AAC) {
                MPEG4AudioConfig cfg;
                ff_mpeg4audio_get_config(&cfg, st->codec->extradata,
                                         st->codec->extradata_size);
462
                st->codec->channels = cfg.channels;
463 464 465 466
                if (cfg.object_type == 29 && cfg.sampling_index < 3) // old mp3on4
                    st->codec->sample_rate = ff_mpa_freq_tab[cfg.sampling_index];
                else
                    st->codec->sample_rate = cfg.sample_rate; // ext sample rate ?
467
                dprintf(fc, "mp4a config channels %d obj %d ext obj %d "
468 469 470
                        "sample rate %d ext sample rate %d\n", st->codec->channels,
                        cfg.object_type, cfg.ext_object_type,
                        cfg.sample_rate, cfg.ext_sample_rate);
471 472
                if (!(st->codec->codec_id = ff_codec_get_id(mp4_audio_types,
                                                            cfg.object_type)))
473
                    st->codec->codec_id = CODEC_ID_AAC;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
474
            }
475
        }
476 477 478 479
    }
    return 0;
}

480 481 482 483 484
static int mov_read_esds(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
    return ff_mov_read_esds(c->fc, pb, atom);
}

485 486 487 488
static int mov_read_pasp(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
    const int num = get_be32(pb);
    const int den = get_be32(pb);
489 490 491 492 493 494
    AVStream *st;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];

495
    if (den != 0) {
496 497
        if ((st->sample_aspect_ratio.den != 1 || st->sample_aspect_ratio.num) && // default
            (den != st->sample_aspect_ratio.den || num != st->sample_aspect_ratio.num))
498
            av_log(c->fc, AV_LOG_WARNING,
499 500
                   "sample aspect ratio already set to %d:%d, overriding by 'pasp' atom\n",
                   st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
501 502 503 504 505 506
        st->sample_aspect_ratio.num = num;
        st->sample_aspect_ratio.den = den;
    }
    return 0;
}

507
/* this atom contains actual media data */
508
static int mov_read_mdat(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
509
{
510 511 512 513 514 515
    if(atom.size == 0) /* wrong one (MP4) */
        return 0;
    c->found_mdat=1;
    return 0; /* now go for moov */
}

516
/* read major brand, minor version and compatible brands and store them as metadata */
517
static int mov_read_ftyp(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
518
{
519 520 521 522 523 524 525
    uint32_t minor_ver;
    int comp_brand_size;
    char minor_ver_str[11]; /* 32 bit integer -> 10 digits + null */
    char* comp_brands_str;
    uint8_t type[5] = {0};

    get_buffer(pb, type, 4);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
526
    if (strcmp(type, "qt  "))
527
        c->isom = 1;
528
    av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type);
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
    av_metadata_set(&c->fc->metadata, "major_brand", type);
    minor_ver = get_be32(pb); /* minor version */
    snprintf(minor_ver_str, sizeof(minor_ver_str), "%d", minor_ver);
    av_metadata_set(&c->fc->metadata, "minor_version", minor_ver_str);

    comp_brand_size = atom.size - 8;
    if (comp_brand_size < 0)
        return -1;
    comp_brands_str = av_malloc(comp_brand_size + 1); /* Add null terminator */
    if (!comp_brands_str)
        return AVERROR(ENOMEM);
    get_buffer(pb, comp_brands_str, comp_brand_size);
    comp_brands_str[comp_brand_size] = 0;
    av_metadata_set(&c->fc->metadata, "compatible_brands", comp_brands_str);
    av_freep(&comp_brands_str);

545 546 547
    return 0;
}

548
/* this atom should contain all header atoms */
549
static int mov_read_moov(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
550
{
551 552
    if (mov_read_default(c, pb, atom) < 0)
        return -1;
553 554 555 556 557 558
    /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */
    /* so we don't parse the whole file if over a network */
    c->found_moov=1;
    return 0; /* now go for mdat */
}

559
static int mov_read_moof(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
560 561 562 563 564
{
    c->fragment.moof_offset = url_ftell(pb) - 8;
    dprintf(c->fc, "moof offset %llx\n", c->fragment.moof_offset);
    return mov_read_default(c, pb, atom);
}
565

566
static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
567
{
568 569 570
    AVStream *st;
    MOVStreamContext *sc;
    int version;
571
    char language[4] = {0};
572
    unsigned lang;
573

574 575 576 577 578 579
    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
    sc = st->priv_data;

    version = get_byte(pb);
580
    if (version > 1)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
581
        return -1; /* unsupported */
582

583
    get_be24(pb); /* flags */
Baptiste Coudurier's avatar
clean  
Baptiste Coudurier committed
584 585 586 587 588 589 590
    if (version == 1) {
        get_be64(pb);
        get_be64(pb);
    } else {
        get_be32(pb); /* creation time */
        get_be32(pb); /* modification time */
    }
591

Baptiste Coudurier's avatar
clean  
Baptiste Coudurier committed
592 593
    sc->time_scale = get_be32(pb);
    st->duration = (version == 1) ? get_be64(pb) : get_be32(pb); /* duration */
594

595
    lang = get_be16(pb); /* language */
596 597
    if (ff_mov_lang_to_iso639(lang, language))
        av_metadata_set(&st->metadata, "language", language);
598 599 600 601 602
    get_be16(pb); /* quality */

    return 0;
}

603
static int mov_read_mvhd(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
604
{
605
    int version = get_byte(pb); /* version */
606
    get_be24(pb); /* flags */
607

608 609 610 611 612 613 614
    if (version == 1) {
        get_be64(pb);
        get_be64(pb);
    } else {
        get_be32(pb); /* creation time */
        get_be32(pb); /* modification time */
    }
615
    c->time_scale = get_be32(pb); /* time scale */
616 617 618

    dprintf(c->fc, "time scale = %i\n", c->time_scale);

619
    c->duration = (version == 1) ? get_be64(pb) : get_be32(pb); /* duration */
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
    get_be32(pb); /* preferred scale */

    get_be16(pb); /* preferred volume */

    url_fskip(pb, 10); /* reserved */

    url_fskip(pb, 36); /* display matrix */

    get_be32(pb); /* preview time */
    get_be32(pb); /* preview duration */
    get_be32(pb); /* poster time */
    get_be32(pb); /* selection time */
    get_be32(pb); /* selection duration */
    get_be32(pb); /* current time */
    get_be32(pb); /* next track ID */

    return 0;
}

639
static int mov_read_smi(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
640
{
641 642 643 644 645
    AVStream *st;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
646

647 648
    if((uint64_t)atom.size > (1<<30))
        return -1;
649

650 651
    // currently SVQ3 decoder expect full STSD header - so let's fake it
    // this should be fixed and just SMI header should be passed
652
    av_free(st->codec->extradata);
653 654 655
    st->codec->extradata = av_mallocz(atom.size + 0x5a + FF_INPUT_BUFFER_PADDING_SIZE);
    if (!st->codec->extradata)
        return AVERROR(ENOMEM);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
656 657 658 659
    st->codec->extradata_size = 0x5a + atom.size;
    memcpy(st->codec->extradata, "SVQ3", 4); // fake
    get_buffer(pb, st->codec->extradata + 0x5a, atom.size);
    dprintf(c->fc, "Reading SMI %"PRId64"  %s\n", atom.size, st->codec->extradata + 0x5a);
660 661
    return 0;
}
662

663
static int mov_read_enda(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
664
{
665 666 667 668 669 670
    AVStream *st;
    int little_endian;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
671

672
    little_endian = get_be16(pb);
673 674
    dprintf(c->fc, "enda %d\n", little_endian);
    if (little_endian == 1) {
675 676 677 678 679 680 681
        switch (st->codec->codec_id) {
        case CODEC_ID_PCM_S24BE:
            st->codec->codec_id = CODEC_ID_PCM_S24LE;
            break;
        case CODEC_ID_PCM_S32BE:
            st->codec->codec_id = CODEC_ID_PCM_S32LE;
            break;
682 683 684 685 686 687
        case CODEC_ID_PCM_F32BE:
            st->codec->codec_id = CODEC_ID_PCM_F32LE;
            break;
        case CODEC_ID_PCM_F64BE:
            st->codec->codec_id = CODEC_ID_PCM_F64LE;
            break;
688 689 690 691 692 693 694
        default:
            break;
        }
    }
    return 0;
}

695
/* FIXME modify qdm2/svq3/h264 decoders to take full atom as extradata */
696
static int mov_read_extradata(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
697
{
698 699
    AVStream *st;
    uint64_t size;
700
    uint8_t *buf;
701 702 703 704 705

    if (c->fc->nb_streams < 1) // will happen with jp2 files
        return 0;
    st= c->fc->streams[c->fc->nb_streams-1];
    size= (uint64_t)st->codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE;
706
    if(size > INT_MAX || (uint64_t)atom.size > INT_MAX)
707
        return -1;
708 709 710 711 712 713 714 715 716
    buf= av_realloc(st->codec->extradata, size);
    if(!buf)
        return -1;
    st->codec->extradata= buf;
    buf+= st->codec->extradata_size;
    st->codec->extradata_size= size - FF_INPUT_BUFFER_PADDING_SIZE;
    AV_WB32(       buf    , atom.size + 8);
    AV_WL32(       buf + 4, atom.type);
    get_buffer(pb, buf + 8, atom.size);
717 718 719
    return 0;
}

720
static int mov_read_wave(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
Roberto Togni's avatar
Roberto Togni committed
721
{
722 723 724 725 726
    AVStream *st;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
Roberto Togni's avatar
Roberto Togni committed
727 728 729

    if((uint64_t)atom.size > (1<<30))
        return -1;
730

731 732 733
    if (st->codec->codec_id == CODEC_ID_QDM2) {
        // pass all frma atom to codec, needed at least for QDM2
        av_free(st->codec->extradata);
734 735 736
        st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
        if (!st->codec->extradata)
            return AVERROR(ENOMEM);
737
        st->codec->extradata_size = atom.size;
738
        get_buffer(pb, st->codec->extradata, atom.size);
739
    } else if (atom.size > 8) { /* to read frma, esds atoms */
740 741
        if (mov_read_default(c, pb, atom) < 0)
            return -1;
742
    } else
743
        url_fskip(pb, atom.size);
Roberto Togni's avatar
Roberto Togni committed
744 745 746
    return 0;
}

747 748 749 750
/**
 * This function reads atom content and puts data in extradata without tag
 * nor size unlike mov_read_extradata.
 */
751
static int mov_read_glbl(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
752
{
753 754 755 756 757
    AVStream *st;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
758

759 760 761
    if((uint64_t)atom.size > (1<<30))
        return -1;

762
    av_free(st->codec->extradata);
763 764 765
    st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
    if (!st->codec->extradata)
        return AVERROR(ENOMEM);
766
    st->codec->extradata_size = atom.size;
767
    get_buffer(pb, st->codec->extradata, atom.size);
768 769 770
    return 0;
}

771
static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
772
{
773 774
    AVStream *st;
    MOVStreamContext *sc;
775
    unsigned int i, entries;
776

777 778 779 780 781
    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
    sc = st->priv_data;

782
    get_byte(pb); /* version */
783
    get_be24(pb); /* flags */
784 785

    entries = get_be32(pb);
786

787 788
    if(entries >= UINT_MAX/sizeof(int64_t))
        return -1;
789

Baptiste Coudurier's avatar
Baptiste Coudurier committed
790
    sc->chunk_offsets = av_malloc(entries * sizeof(int64_t));
791
    if (!sc->chunk_offsets)
792 793 794
        return AVERROR(ENOMEM);
    sc->chunk_count = entries;

795 796
    if      (atom.type == MKTAG('s','t','c','o'))
        for(i=0; i<entries; i++)
797
            sc->chunk_offsets[i] = get_be32(pb);
798 799
    else if (atom.type == MKTAG('c','o','6','4'))
        for(i=0; i<entries; i++)
800
            sc->chunk_offsets[i] = get_be64(pb);
801
    else
802
        return -1;
803

804 805 806
    return 0;
}

807 808 809 810
/**
 * Compute codec id for 'lpcm' tag.
 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
 */
811
enum CodecID ff_mov_get_lpcm_codec_id(int bps, int flags)
812 813 814 815
{
    if (flags & 1) { // floating point
        if (flags & 2) { // big endian
            if      (bps == 32) return CODEC_ID_PCM_F32BE;
816
            else if (bps == 64) return CODEC_ID_PCM_F64BE;
817
        } else {
818 819
            if      (bps == 32) return CODEC_ID_PCM_F32LE;
            else if (bps == 64) return CODEC_ID_PCM_F64LE;
820 821 822 823 824 825 826 827 828 829 830 831