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

24
#include "avformat.h"
25
#include "riff.h"
26
#include "avio.h"
27
#include "isom.h"
28
#include "avc.h"
29
#include "libavcodec/get_bits.h"
30
#include "libavcodec/put_bits.h"
31

32 33 34
#undef NDEBUG
#include <assert.h>

35
#define MOV_INDEX_CLUSTER_SIZE 16384
36
#define MOV_TIMESCALE 1000
37

38 39 40 41
#define MODE_MP4  0x01
#define MODE_MOV  0x02
#define MODE_3GP  0x04
#define MODE_PSP  0x08 // example working PSP command line:
42
// ffmpeg -i testinput.avi  -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4
43 44
#define MODE_3G2  0x10
#define MODE_IPOD 0x20
45

46
typedef struct MOVIentry {
47
    unsigned int size;
48
    uint64_t     pos;
49
    unsigned int samplesInChunk;
50
    unsigned int entries;
51
    int          cts;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
52
    int64_t      dts;
53
#define MOV_SYNC_SAMPLE         0x0001
54
#define MOV_PARTIAL_SYNC_SAMPLE 0x0002
55
    uint32_t     flags;
56 57 58
} MOVIentry;

typedef struct MOVIndex {
59
    int         mode;
60
    int         entry;
61
    unsigned    timescale;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
62
    uint64_t    time;
63
    int64_t     trackDuration;
64
    long        sampleCount;
65
    long        sampleSize;
66
    int         hasKeyframes;
67 68 69
#define MOV_TRACK_CTTS         0x0001
#define MOV_TRACK_STPS         0x0002
    uint32_t    flags;
70
    int         language;
71
    int         trackID;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
72
    int         tag; ///< stsd fourcc
73 74 75
    AVCodecContext *enc;

    int         vosLen;
76
    uint8_t     *vosData;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
77
    MOVIentry   *cluster;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
78
    int         audio_vbr;
79
    int         height; ///< active picture (w/o VBI) height for D-10/IMX
80 81
    uint32_t    tref_tag;
    int         tref_id; ///< trackID of the referenced track
82 83
} MOVTrack;

84
typedef struct MOVMuxContext {
85
    int     mode;
86
    int64_t time;
87
    int     nb_streams;
88
    int     chapter_track; ///< qt chapter track number
89
    int64_t mdat_pos;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
90
    uint64_t mdat_size;
91
    MOVTrack *tracks;
92
} MOVMuxContext;
93

Diego Biurrun's avatar
Diego Biurrun committed
94
//FIXME support 64 bit variant with wide placeholders
95
static int64_t updateSize(ByteIOContext *pb, int64_t pos)
96
{
97
    int64_t curpos = url_ftell(pb);
98
    url_fseek(pb, pos, SEEK_SET);
99
    put_be32(pb, curpos - pos); /* rewrite size */
100
    url_fseek(pb, curpos, SEEK_SET);
101 102

    return curpos - pos;
103 104
}

105
/* Chunk offset atom */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
106
static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack *track)
107 108
{
    int i;
Benjamin Larsson's avatar
Benjamin Larsson committed
109
    int mode64 = 0; //   use 32 bit size variant if possible
110
    int64_t pos = url_ftell(pb);
111
    put_be32(pb, 0); /* size */
112 113 114 115 116
    if (pos > UINT32_MAX) {
        mode64 = 1;
        put_tag(pb, "co64");
    } else
        put_tag(pb, "stco");
117 118 119
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, track->entry); /* entry count */
    for (i=0; i<track->entry; i++) {
120
        if(mode64 == 1)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
121
            put_be64(pb, track->cluster[i].pos);
122
        else
Baptiste Coudurier's avatar
Baptiste Coudurier committed
123
            put_be32(pb, track->cluster[i].pos);
124
    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
125
    return updateSize(pb, pos);
126 127
}

128
/* Sample size atom */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
129
static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack *track)
130
{
131
    int equalChunks = 1;
132
    int i, j, entries = 0, tst = -1, oldtst = -1;
133

134
    int64_t pos = url_ftell(pb);
135
    put_be32(pb, 0); /* size */
136 137 138
    put_tag(pb, "stsz");
    put_be32(pb, 0); /* version & flags */

139
    for (i=0; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
140
        tst = track->cluster[i].size/track->cluster[i].entries;
141 142
        if(oldtst != -1 && tst != oldtst) {
            equalChunks = 0;
143 144
        }
        oldtst = tst;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
145
        entries += track->cluster[i].entries;
146
    }
147
    if (equalChunks) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
148
        int sSize = track->cluster[0].size/track->cluster[0].entries;
149
        put_be32(pb, sSize); // sample size
150
        put_be32(pb, entries); // sample count
151
    }
152
    else {
153 154
        put_be32(pb, 0); // sample size
        put_be32(pb, entries); // sample count
155
        for (i=0; i<track->entry; i++) {
156
            for (j=0; j<track->cluster[i].entries; j++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
157 158
                put_be32(pb, track->cluster[i].size /
                         track->cluster[i].entries);
159
            }
160 161
        }
    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
162
    return updateSize(pb, pos);
163 164
}

165
/* Sample to chunk atom */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
166
static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack *track)
167
{
168
    int index = 0, oldval = -1, i;
169
    int64_t entryPos, curpos;
170

171
    int64_t pos = url_ftell(pb);
172
    put_be32(pb, 0); /* size */
173
    put_tag(pb, "stsc");
174
    put_be32(pb, 0); // version & flags
175
    entryPos = url_ftell(pb);
176
    put_be32(pb, track->entry); // entry count
177
    for (i=0; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
178
        if(oldval != track->cluster[i].samplesInChunk)
179
        {
180
            put_be32(pb, i+1); // first chunk
Baptiste Coudurier's avatar
Baptiste Coudurier committed
181
            put_be32(pb, track->cluster[i].samplesInChunk); // samples per chunk
182
            put_be32(pb, 0x1); // sample description index
Baptiste Coudurier's avatar
Baptiste Coudurier committed
183
            oldval = track->cluster[i].samplesInChunk;
184
            index++;
185 186
        }
    }
187 188
    curpos = url_ftell(pb);
    url_fseek(pb, entryPos, SEEK_SET);
189
    put_be32(pb, index); // rewrite size
190
    url_fseek(pb, curpos, SEEK_SET);
191

Baptiste Coudurier's avatar
Baptiste Coudurier committed
192
    return updateSize(pb, pos);
193 194
}

195
/* Sync sample atom */
196
static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack *track, uint32_t flag)
197
{
198
    int64_t curpos, entryPos;
199
    int i, index = 0;
200
    int64_t pos = url_ftell(pb);
201
    put_be32(pb, 0); // size
202
    put_tag(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
203
    put_be32(pb, 0); // version & flags
204
    entryPos = url_ftell(pb);
205
    put_be32(pb, track->entry); // entry count
206
    for (i=0; i<track->entry; i++) {
207
        if (track->cluster[i].flags & flag) {
208 209 210 211 212 213
            put_be32(pb, i+1);
            index++;
        }
    }
    curpos = url_ftell(pb);
    url_fseek(pb, entryPos, SEEK_SET);
214
    put_be32(pb, index); // rewrite size
215
    url_fseek(pb, curpos, SEEK_SET);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
216
    return updateSize(pb, pos);
217 218
}

219
static int mov_write_amr_tag(ByteIOContext *pb, MOVTrack *track)
220 221
{
    put_be32(pb, 0x11); /* size */
222 223
    if (track->mode == MODE_MOV) put_tag(pb, "samr");
    else                         put_tag(pb, "damr");
224
    put_tag(pb, "FFMP");
225
    put_byte(pb, 0); /* decoder version */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
226

Baptiste Coudurier's avatar
Baptiste Coudurier committed
227
    put_be16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
228 229
    put_byte(pb, 0x00); /* Mode change period (no restriction) */
    put_byte(pb, 0x01); /* Frames per sample */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
230 231 232
    return 0x11;
}

233 234 235 236 237 238 239 240 241 242 243 244 245
static int mov_write_ac3_tag(ByteIOContext *pb, MOVTrack *track)
{
    GetBitContext gbc;
    PutBitContext pbc;
    uint8_t buf[3];
    int fscod, bsid, bsmod, acmod, lfeon, frmsizecod;

    if (track->vosLen < 7)
        return -1;

    put_be32(pb, 11);
    put_tag(pb, "dac3");

246
    init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
    fscod      = get_bits(&gbc, 2);
    frmsizecod = get_bits(&gbc, 6);
    bsid       = get_bits(&gbc, 5);
    bsmod      = get_bits(&gbc, 3);
    acmod      = get_bits(&gbc, 3);
    if (acmod == 2) {
        skip_bits(&gbc, 2); // dsurmod
    } else {
        if ((acmod & 1) && acmod != 1)
            skip_bits(&gbc, 2); // cmixlev
        if (acmod & 4)
            skip_bits(&gbc, 2); // surmixlev
    }
    lfeon = get_bits1(&gbc);

    init_put_bits(&pbc, buf, sizeof(buf));
    put_bits(&pbc, 2, fscod);
    put_bits(&pbc, 5, bsid);
    put_bits(&pbc, 3, bsmod);
    put_bits(&pbc, 3, acmod);
    put_bits(&pbc, 1, lfeon);
    put_bits(&pbc, 5, frmsizecod>>1); // bit_rate_code
    put_bits(&pbc, 5, 0); // reserved

    flush_put_bits(&pbc);
    put_buffer(pb, buf, sizeof(buf));

    return 11;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
277 278 279 280 281 282 283 284 285 286
/**
 * This function writes extradata "as is".
 * Extradata must be formated like a valid atom (with size and tag)
 */
static int mov_write_extradata_tag(ByteIOContext *pb, MOVTrack *track)
{
    put_buffer(pb, track->enc->extradata, track->enc->extradata_size);
    return track->enc->extradata_size;
}

287 288 289 290 291 292 293 294
static int mov_write_enda_tag(ByteIOContext *pb)
{
    put_be32(pb, 10);
    put_tag(pb, "enda");
    put_be16(pb, 1); /* little endian */
    return 10;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
295 296
static unsigned int descrLength(unsigned int len)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
297 298 299
    int i;
    for(i=1; len>>(7*i); i++);
    return len + 1 + i;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
300 301
}

Michael Niedermayer's avatar
Michael Niedermayer committed
302
static void putDescr(ByteIOContext *pb, int tag, unsigned int size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
303
{
Michael Niedermayer's avatar
Michael Niedermayer committed
304 305 306 307 308
    int i= descrLength(size) - size - 2;
    put_byte(pb, tag);
    for(; i>0; i--)
        put_byte(pb, (size>>(7*i)) | 0x80);
    put_byte(pb, size & 0x7F);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
309 310
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
311
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack *track) // Basic
Baptiste Coudurier's avatar
Baptiste Coudurier committed
312
{
313
    int64_t pos = url_ftell(pb);
314
    int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
315

316
    put_be32(pb, 0); // size
Baptiste Coudurier's avatar
Baptiste Coudurier committed
317
    put_tag(pb, "esds");
318
    put_be32(pb, 0); // Version
Baptiste Coudurier's avatar
Baptiste Coudurier committed
319 320 321 322 323

    // ES descriptor
    putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
             descrLength(1));
    put_be16(pb, track->trackID);
324
    put_byte(pb, 0x00); // flags (= no flags)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
325 326 327 328 329

    // DecoderConfig descriptor
    putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);

    // Object type indication
330 331
    if ((track->enc->codec_id == CODEC_ID_MP2 ||
         track->enc->codec_id == CODEC_ID_MP3) &&
332 333
        track->enc->sample_rate > 24000)
        put_byte(pb, 0x6B); // 11172-3
334
    else
335
        put_byte(pb, ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id));
Baptiste Coudurier's avatar
Baptiste Coudurier committed
336 337 338

    // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
    // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
339
    if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
340
        put_byte(pb, 0x15); // flags (= Audiostream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
341
    else
342
        put_byte(pb, 0x11); // flags (= Visualstream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
343

344 345
    put_byte(pb,  track->enc->rc_buffer_size>>(3+16));    // Buffersize DB (24 bits)
    put_be16(pb, (track->enc->rc_buffer_size>>3)&0xFFFF); // Buffersize DB
Baptiste Coudurier's avatar
Baptiste Coudurier committed
346

347
    put_be32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate)); // maxbitrate (FIXME should be max rate in any 1 sec window)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
348
    if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0)
349
        put_be32(pb, 0); // vbr
Baptiste Coudurier's avatar
Baptiste Coudurier committed
350
    else
351
        put_be32(pb, track->enc->rc_max_rate); // avg bitrate
Baptiste Coudurier's avatar
Baptiste Coudurier committed
352

353
    if (track->vosLen) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
354 355 356 357 358 359 360 361
        // DecoderSpecific info descriptor
        putDescr(pb, 0x05, track->vosLen);
        put_buffer(pb, track->vosData, track->vosLen);
    }

    // SL descriptor
    putDescr(pb, 0x06, 1);
    put_byte(pb, 0x02);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
362
    return updateSize(pb, pos);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
363 364
}

365 366 367 368 369 370 371 372
static int mov_pcm_le_gt16(enum CodecID codec_id)
{
    return codec_id == CODEC_ID_PCM_S24LE ||
           codec_id == CODEC_ID_PCM_S32LE ||
           codec_id == CODEC_ID_PCM_F32LE ||
           codec_id == CODEC_ID_PCM_F64LE;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
373
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack *track)
374
{
375
    int64_t pos = url_ftell(pb);
376 377 378 379 380 381

    put_be32(pb, 0);     /* size */
    put_tag(pb, "wave");

    put_be32(pb, 12);    /* size */
    put_tag(pb, "frma");
382
    put_le32(pb, track->tag);
383

384
    if (track->enc->codec_id == CODEC_ID_AAC) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
385 386 387 388
        /* useless atom needed by mplayer, ipod, not needed by quicktime */
        put_be32(pb, 12); /* size */
        put_tag(pb, "mp4a");
        put_be32(pb, 0);
389
        mov_write_esds_tag(pb, track);
390
    } else if (mov_pcm_le_gt16(track->enc->codec_id)) {
391
        mov_write_enda_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
392
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
393
        mov_write_amr_tag(pb, track);
394 395
    } else if (track->enc->codec_id == CODEC_ID_AC3) {
        mov_write_ac3_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
396 397
    } else if (track->enc->codec_id == CODEC_ID_ALAC) {
        mov_write_extradata_tag(pb, track);
398
    }
399 400 401 402

    put_be32(pb, 8);     /* size */
    put_be32(pb, 0);     /* null tag */

Baptiste Coudurier's avatar
Baptiste Coudurier committed
403
    return updateSize(pb, pos);
404 405
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
406
static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack *track)
407 408 409 410 411 412 413
{
    put_be32(pb, track->vosLen+8);
    put_tag(pb, "glbl");
    put_buffer(pb, track->vosData, track->vosLen);
    return 8+track->vosLen;
}

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
/**
 * Compute flags for 'lpcm' tag.
 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
 */
static int mov_get_lpcm_flags(enum CodecID codec_id)
{
    switch (codec_id) {
    case CODEC_ID_PCM_F32BE:
    case CODEC_ID_PCM_F64BE:
        return 11;
    case CODEC_ID_PCM_F32LE:
    case CODEC_ID_PCM_F64LE:
        return 9;
    case CODEC_ID_PCM_U8:
        return 10;
    case CODEC_ID_PCM_S16BE:
    case CODEC_ID_PCM_S24BE:
    case CODEC_ID_PCM_S32BE:
        return 14;
    case CODEC_ID_PCM_S8:
    case CODEC_ID_PCM_S16LE:
    case CODEC_ID_PCM_S24LE:
    case CODEC_ID_PCM_S32LE:
        return 12;
    default:
        return 0;
    }
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
443
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack *track)
444
{
445
    int64_t pos = url_ftell(pb);
446 447 448 449 450 451 452 453
    int version = 0;
    uint32_t tag = track->tag;

    if (track->mode == MODE_MOV) {
        if (track->timescale > UINT16_MAX) {
            if (mov_get_lpcm_flags(track->enc->codec_id))
                tag = AV_RL32("lpcm");
            version = 2;
454
        } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id)) {
455 456 457
            version = 1;
        }
    }
458

459
    put_be32(pb, 0); /* size */
460
    put_le32(pb, tag); // store it byteswapped
461 462 463
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
464

465
    /* SoundDescription */
466
    put_be16(pb, version); /* Version */
467
    put_be16(pb, 0); /* Revision level */
468 469
    put_be32(pb, 0); /* Reserved */

470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
    if (version == 2) {
        put_be16(pb, 3);
        put_be16(pb, 16);
        put_be16(pb, 0xfffe);
        put_be16(pb, 0);
        put_be32(pb, 0x00010000);
        put_be32(pb, 72);
        put_be64(pb, av_dbl2int(track->timescale));
        put_be32(pb, track->enc->channels);
        put_be32(pb, 0x7F000000);
        put_be32(pb, av_get_bits_per_sample(track->enc->codec_id));
        put_be32(pb, mov_get_lpcm_flags(track->enc->codec_id));
        put_be32(pb, track->sampleSize);
        put_be32(pb, track->enc->frame_size);
    } else {
485 486 487 488 489 490 491 492 493 494
        if (track->mode == MODE_MOV) {
            put_be16(pb, track->enc->channels);
            if (track->enc->codec_id == CODEC_ID_PCM_U8 ||
                track->enc->codec_id == CODEC_ID_PCM_S8)
                put_be16(pb, 8); /* bits per sample */
            else
                put_be16(pb, 16);
            put_be16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
        } else { /* reserved for mp4/3gp */
            put_be16(pb, 2);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
495
            put_be16(pb, 16);
496 497
            put_be16(pb, 0);
        }
498

499 500 501
        put_be16(pb, 0); /* packet size (= 0) */
        put_be16(pb, track->timescale); /* Time scale */
        put_be16(pb, 0); /* Reserved */
502
    }
503

504 505
    if(version == 1) { /* SoundDescription V1 extended info */
        put_be32(pb, track->enc->frame_size); /* Samples per packet */
506
        put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
507
        put_be32(pb, track->sampleSize); /* Bytes per frame */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
508
        put_be32(pb, 2); /* Bytes per sample */
509 510
    }

511 512
    if(track->mode == MODE_MOV &&
       (track->enc->codec_id == CODEC_ID_AAC ||
513
        track->enc->codec_id == CODEC_ID_AC3 ||
514
        track->enc->codec_id == CODEC_ID_AMR_NB ||
515 516
        track->enc->codec_id == CODEC_ID_ALAC ||
        mov_pcm_le_gt16(track->enc->codec_id)))
517
        mov_write_wave_tag(pb, track);
518
    else if(track->tag == MKTAG('m','p','4','a'))
Baptiste Coudurier's avatar
Baptiste Coudurier committed
519 520
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
521
        mov_write_amr_tag(pb, track);
522 523
    else if(track->enc->codec_id == CODEC_ID_AC3)
        mov_write_ac3_tag(pb, track);
524
    else if(track->enc->codec_id == CODEC_ID_ALAC)
525
        mov_write_extradata_tag(pb, track);
526 527
    else if(track->vosLen > 0)
        mov_write_glbl_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
528

Baptiste Coudurier's avatar
Baptiste Coudurier committed
529
    return updateSize(pb, pos);
530 531
}

532
static int mov_write_d263_tag(ByteIOContext *pb)
533 534 535 536
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
537 538 539 540
    put_byte(pb, 0); /* decoder version */
    /* FIXME use AVCodecContext level/profile, when encoder will set values */
    put_byte(pb, 0xa); /* level */
    put_byte(pb, 0); /* profile */
541 542 543
    return 0xf;
}

544 545
/* TODO: No idea about these values */
static int mov_write_svq3_tag(ByteIOContext *pb)
546
{
547 548 549 550 551 552
    put_be32(pb, 0x15);
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
    put_be32(pb, 0x5);
    put_be32(pb, 0xe2c0211d);
    put_be32(pb, 0xc0000000);
553
    put_byte(pb, 0);
554
    return 0x15;
555 556
}

557 558
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
559
    int64_t pos = url_ftell(pb);
560 561 562

    put_be32(pb, 0);
    put_tag(pb, "avcC");
563
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
564 565 566
    return updateSize(pb, pos);
}

567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
/* also used by all avid codecs (dv, imx, meridien) and their variants */
static int mov_write_avid_tag(ByteIOContext *pb, MOVTrack *track)
{
    int i;
    put_be32(pb, 24); /* size */
    put_tag(pb, "ACLR");
    put_tag(pb, "ACLR");
    put_tag(pb, "0001");
    put_be32(pb, 1); /* yuv 1 / rgb 2 ? */
    put_be32(pb, 0); /* unknown */

    put_be32(pb, 24); /* size */
    put_tag(pb, "APRG");
    put_tag(pb, "APRG");
    put_tag(pb, "0001");
    put_be32(pb, 1); /* unknown */
    put_be32(pb, 0); /* unknown */

    put_be32(pb, 120); /* size */
    put_tag(pb, "ARES");
    put_tag(pb, "ARES");
    put_tag(pb, "0001");
    put_be32(pb, AV_RB32(track->vosData + 0x28)); /* dnxhd cid, some id ? */
    put_be32(pb, track->enc->width);
    /* values below are based on samples created with quicktime and avid codecs */
    if (track->vosData[5] & 2) { // interlaced
        put_be32(pb, track->enc->height/2);
        put_be32(pb, 2); /* unknown */
        put_be32(pb, 0); /* unknown */
        put_be32(pb, 4); /* unknown */
    } else {
        put_be32(pb, track->enc->height);
        put_be32(pb, 1); /* unknown */
        put_be32(pb, 0); /* unknown */
601 602 603 604
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
605 606 607 608 609 610 611 612 613 614
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

    /* extra padding for stsd needed */
    put_be32(pb, 0);
    return 0;
}

615
static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
616
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
617
    int tag = track->enc->codec_tag;
618

619
    if (!ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
620 621 622 623 624 625
        return 0;

    if      (track->enc->codec_id == CODEC_ID_H264)      tag = MKTAG('a','v','c','1');
    else if (track->enc->codec_id == CODEC_ID_AC3)       tag = MKTAG('a','c','-','3');
    else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag = MKTAG('d','r','a','c');
    else if (track->enc->codec_id == CODEC_ID_MOV_TEXT)  tag = MKTAG('t','x','3','g');
626 627
    else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) tag = MKTAG('m','p','4','v');
    else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) tag = MKTAG('m','p','4','a');
628 629 630 631

    return tag;
}

632 633 634 635 636 637 638 639 640 641 642
static const AVCodecTag codec_ipod_tags[] = {
    { CODEC_ID_H264,   MKTAG('a','v','c','1') },
    { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
    { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
    { CODEC_ID_ALAC,   MKTAG('a','l','a','c') },
    { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
    { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
    { CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
    { CODEC_ID_NONE, 0 },
};

643 644 645 646
static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

647
    // keep original tag for subs, ipod supports both formats
648
    if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE &&
649
        (tag == MKTAG('t','x','3','g') ||
650
         tag == MKTAG('t','e','x','t'))))
651
        tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
652

653
    if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v"))
654 655
        av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
               "Quicktime/Ipod might not play the file\n");
656 657 658 659 660 661 662 663

    return tag;
}

static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag;

664 665 666 667 668 669
    if (track->enc->height == 480) /* NTSC */
        if  (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
        else                                         tag = MKTAG('d','v','c',' ');
    else if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
    else if (track->enc->pix_fmt == PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
    else                                             tag = MKTAG('d','v','p','p');
670 671 672 673

    return tag;
}

674 675 676 677 678 679 680 681
static const struct {
    enum PixelFormat pix_fmt;
    uint32_t tag;
    unsigned bps;
} mov_pix_fmt_tags[] = {
    { PIX_FMT_YUYV422, MKTAG('y','u','v','s'),  0 },
    { PIX_FMT_UYVY422, MKTAG('2','v','u','y'),  0 },
    { PIX_FMT_BGR555,  MKTAG('r','a','w',' '), 16 },
682 683 684
    { PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
    { PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
    { PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
685
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
686
    { PIX_FMT_BGR24,   MKTAG('2','4','B','G'), 24 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
687
    { PIX_FMT_ARGB,    MKTAG('r','a','w',' '), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
688
    { PIX_FMT_BGRA,    MKTAG('B','G','R','A'), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
689
    { PIX_FMT_RGBA,    MKTAG('R','G','B','A'), 32 },
690 691
};

692 693 694
static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
695 696 697 698 699 700 701 702 703
    int i;

    for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
        if (track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) {
            tag = mov_pix_fmt_tags[i].tag;
            track->enc->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
            break;
        }
    }
704 705 706 707 708 709 710 711 712 713 714 715

    return tag;
}

static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

    if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
                 (tag == MKTAG('d','v','c','p') ||
                  track->enc->codec_id == CODEC_ID_RAWVIDEO ||
                  av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
716
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
717
            tag = mov_get_dv_codec_tag(s, track);
718
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
719
            tag = mov_get_rawvideo_codec_tag(s, track);
720
        else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
721
            tag = ff_codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
722
            if (!tag) { // if no mac fcc found, try with Microsoft tags
723
                tag = ff_codec_get_tag(ff_codec_bmp_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
724 725 726 727
                if (tag)
                    av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                           "the file may be unplayable!\n");
            }
728
        } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
729
            tag = ff_codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
730
            if (!tag) { // if no mac fcc found, try with Microsoft tags
731
                int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
732 733 734 735
                if (ms_tag) {
                    tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
                    av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, "
                           "the file may be unplayable!\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
736
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
737
            }
738
        } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
739
            tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
740
    }
741

742 743 744
    return tag;
}

745 746 747 748 749 750 751 752 753 754 755
static const AVCodecTag codec_3gp_tags[] = {
    { CODEC_ID_H263,   MKTAG('s','2','6','3') },
    { CODEC_ID_H264,   MKTAG('a','v','c','1') },
    { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
    { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
    { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
    { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
    { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
    { CODEC_ID_NONE, 0 },
};

756 757 758 759 760 761 762 763 764
static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

    if (track->mode == MODE_MP4 || track->mode == MODE_PSP)
        tag = mp4_get_codec_tag(s, track);
    else if (track->mode == MODE_IPOD)
        tag = ipod_get_codec_tag(s, track);
    else if (track->mode & MODE_3GP)
765
        tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id);
766 767 768 769 770 771
    else
        tag = mov_get_codec_tag(s, track);

    return tag;
}

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
/** Write uuid atom.
 * Needed to make file play in iPods running newest firmware
 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
 */
static int mov_write_uuid_tag_ipod(ByteIOContext *pb)
{
    put_be32(pb, 28);
    put_tag(pb, "uuid");
    put_be32(pb, 0x6b6840f2);
    put_be32(pb, 0x5f244fc5);
    put_be32(pb, 0xba39a51b);
    put_be32(pb, 0xcf0323f3);
    put_be32(pb, 0x0);
    return 28;
}

788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
static int mov_write_subtitle_tag(ByteIOContext *pb, MOVTrack *track)
{
    int64_t pos = url_ftell(pb);
    put_be32(pb, 0);    /* size */
    put_le32(pb, track->tag); // store it byteswapped
    put_be32(pb, 0);    /* Reserved */
    put_be16(pb, 0);    /* Reserved */
    put_be16(pb, 1);    /* Data-reference index */

    if (track->enc->extradata_size)
        put_buffer(pb, track->enc->extradata, track->enc->extradata_size);

    return updateSize(pb, pos);
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
803
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
804
{
805
    int64_t pos = url_ftell(pb);
806
    char compressor_name[32];
807

808
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
809
    put_le32(pb, track->ta