movenc.c 76 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 "movenc.h"
25
#include "avformat.h"
26
#include "riff.h"
27
#include "avio.h"
28
#include "isom.h"
29
#include "avc.h"
30
#include "libavcodec/get_bits.h"
31
#include "libavcodec/put_bits.h"
32 33
#include "internal.h"
#include "libavutil/avstring.h"
34

35 36 37
#undef NDEBUG
#include <assert.h>

Diego Biurrun's avatar
Diego Biurrun committed
38
//FIXME support 64 bit variant with wide placeholders
39
static int64_t updateSize(AVIOContext *pb, int64_t pos)
40
{
41
    int64_t curpos = url_ftell(pb);
42
    url_fseek(pb, pos, SEEK_SET);
43
    put_be32(pb, curpos - pos); /* rewrite size */
44
    url_fseek(pb, curpos, SEEK_SET);
45 46

    return curpos - pos;
47 48
}

49
/* Chunk offset atom */
50
static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
51 52
{
    int i;
Benjamin Larsson's avatar
Benjamin Larsson committed
53
    int mode64 = 0; //   use 32 bit size variant if possible
54
    int64_t pos = url_ftell(pb);
55
    put_be32(pb, 0); /* size */
56 57 58 59 60
    if (pos > UINT32_MAX) {
        mode64 = 1;
        put_tag(pb, "co64");
    } else
        put_tag(pb, "stco");
61 62 63
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, track->entry); /* entry count */
    for (i=0; i<track->entry; i++) {
64
        if(mode64 == 1)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
65
            put_be64(pb, track->cluster[i].pos);
66
        else
Baptiste Coudurier's avatar
Baptiste Coudurier committed
67
            put_be32(pb, track->cluster[i].pos);
68
    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
69
    return updateSize(pb, pos);
70 71
}

72
/* Sample size atom */
73
static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
74
{
75
    int equalChunks = 1;
76
    int i, j, entries = 0, tst = -1, oldtst = -1;
77

78
    int64_t pos = url_ftell(pb);
79
    put_be32(pb, 0); /* size */
80 81 82
    put_tag(pb, "stsz");
    put_be32(pb, 0); /* version & flags */

83
    for (i=0; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
84
        tst = track->cluster[i].size/track->cluster[i].entries;
85 86
        if(oldtst != -1 && tst != oldtst) {
            equalChunks = 0;
87 88
        }
        oldtst = tst;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
89
        entries += track->cluster[i].entries;
90
    }
91
    if (equalChunks) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
92
        int sSize = track->cluster[0].size/track->cluster[0].entries;
93
        put_be32(pb, sSize); // sample size
94
        put_be32(pb, entries); // sample count
95
    }
96
    else {
97 98
        put_be32(pb, 0); // sample size
        put_be32(pb, entries); // sample count
99
        for (i=0; i<track->entry; i++) {
100
            for (j=0; j<track->cluster[i].entries; j++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
101 102
                put_be32(pb, track->cluster[i].size /
                         track->cluster[i].entries);
103
            }
104 105
        }
    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
106
    return updateSize(pb, pos);
107 108
}

109
/* Sample to chunk atom */
110
static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
111
{
112
    int index = 0, oldval = -1, i;
113
    int64_t entryPos, curpos;
114

115
    int64_t pos = url_ftell(pb);
116
    put_be32(pb, 0); /* size */
117
    put_tag(pb, "stsc");
118
    put_be32(pb, 0); // version & flags
119
    entryPos = url_ftell(pb);
120
    put_be32(pb, track->entry); // entry count
121
    for (i=0; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
122
        if(oldval != track->cluster[i].samplesInChunk)
123
        {
124
            put_be32(pb, i+1); // first chunk
Baptiste Coudurier's avatar
Baptiste Coudurier committed
125
            put_be32(pb, track->cluster[i].samplesInChunk); // samples per chunk
126
            put_be32(pb, 0x1); // sample description index
Baptiste Coudurier's avatar
Baptiste Coudurier committed
127
            oldval = track->cluster[i].samplesInChunk;
128
            index++;
129 130
        }
    }
131 132
    curpos = url_ftell(pb);
    url_fseek(pb, entryPos, SEEK_SET);
133
    put_be32(pb, index); // rewrite size
134
    url_fseek(pb, curpos, SEEK_SET);
135

Baptiste Coudurier's avatar
Baptiste Coudurier committed
136
    return updateSize(pb, pos);
137 138
}

139
/* Sync sample atom */
140
static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
141
{
142
    int64_t curpos, entryPos;
143
    int i, index = 0;
144
    int64_t pos = url_ftell(pb);
145
    put_be32(pb, 0); // size
146
    put_tag(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
147
    put_be32(pb, 0); // version & flags
148
    entryPos = url_ftell(pb);
149
    put_be32(pb, track->entry); // entry count
150
    for (i=0; i<track->entry; i++) {
151
        if (track->cluster[i].flags & flag) {
152 153 154 155 156 157
            put_be32(pb, i+1);
            index++;
        }
    }
    curpos = url_ftell(pb);
    url_fseek(pb, entryPos, SEEK_SET);
158
    put_be32(pb, index); // rewrite size
159
    url_fseek(pb, curpos, SEEK_SET);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
160
    return updateSize(pb, pos);
161 162
}

163
static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
164 165
{
    put_be32(pb, 0x11); /* size */
166 167
    if (track->mode == MODE_MOV) put_tag(pb, "samr");
    else                         put_tag(pb, "damr");
168
    put_tag(pb, "FFMP");
169
    put_byte(pb, 0); /* decoder version */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
170

Baptiste Coudurier's avatar
Baptiste Coudurier committed
171
    put_be16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
172 173
    put_byte(pb, 0x00); /* Mode change period (no restriction) */
    put_byte(pb, 0x01); /* Frames per sample */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
174 175 176
    return 0x11;
}

177
static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track)
178 179 180 181 182 183 184 185 186 187 188 189
{
    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");

190
    init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    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
221 222 223 224
/**
 * This function writes extradata "as is".
 * Extradata must be formated like a valid atom (with size and tag)
 */
225
static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
226 227 228 229 230
{
    put_buffer(pb, track->enc->extradata, track->enc->extradata_size);
    return track->enc->extradata_size;
}

231
static int mov_write_enda_tag(AVIOContext *pb)
232 233 234 235 236 237 238
{
    put_be32(pb, 10);
    put_tag(pb, "enda");
    put_be16(pb, 1); /* little endian */
    return 10;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
239 240
static unsigned int descrLength(unsigned int len)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
241 242 243
    int i;
    for(i=1; len>>(7*i); i++);
    return len + 1 + i;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
244 245
}

246
static void putDescr(AVIOContext *pb, int tag, unsigned int size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
247
{
Michael Niedermayer's avatar
Michael Niedermayer committed
248 249 250 251 252
    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
253 254
}

255
static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
Baptiste Coudurier's avatar
Baptiste Coudurier committed
256
{
257
    int64_t pos = url_ftell(pb);
258
    int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
259

260
    put_be32(pb, 0); // size
Baptiste Coudurier's avatar
Baptiste Coudurier committed
261
    put_tag(pb, "esds");
262
    put_be32(pb, 0); // Version
Baptiste Coudurier's avatar
Baptiste Coudurier committed
263 264 265 266 267

    // ES descriptor
    putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
             descrLength(1));
    put_be16(pb, track->trackID);
268
    put_byte(pb, 0x00); // flags (= no flags)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
269 270 271 272 273

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

    // Object type indication
274 275
    if ((track->enc->codec_id == CODEC_ID_MP2 ||
         track->enc->codec_id == CODEC_ID_MP3) &&
276 277
        track->enc->sample_rate > 24000)
        put_byte(pb, 0x6B); // 11172-3
278
    else
279
        put_byte(pb, ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id));
Baptiste Coudurier's avatar
Baptiste Coudurier committed
280 281 282

    // 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)
283
    if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
284
        put_byte(pb, 0x15); // flags (= Audiostream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
285
    else
286
        put_byte(pb, 0x11); // flags (= Visualstream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
287

288 289
    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
290

291
    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
292
    if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0)
293
        put_be32(pb, 0); // vbr
Baptiste Coudurier's avatar
Baptiste Coudurier committed
294
    else
295
        put_be32(pb, track->enc->rc_max_rate); // avg bitrate
Baptiste Coudurier's avatar
Baptiste Coudurier committed
296

297
    if (track->vosLen) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
298 299 300 301 302 303 304 305
        // 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
306
    return updateSize(pb, pos);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
307 308
}

309 310 311 312 313 314 315 316
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;
}

317
static int mov_write_ms_tag(AVIOContext *pb, MOVTrack *track)
318 319 320
{
    int64_t pos = url_ftell(pb);
    put_be32(pb, 0);
321 322
    put_le32(pb, track->tag); // store it byteswapped
    track->enc->codec_tag = av_bswap16(track->tag >> 16);
323 324 325 326
    ff_put_wav_header(pb, track->enc);
    return updateSize(pb, pos);
}

327
static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track)
328
{
329
    int64_t pos = url_ftell(pb);
330 331 332 333 334 335

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

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

338
    if (track->enc->codec_id == CODEC_ID_AAC) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
339 340 341 342
        /* useless atom needed by mplayer, ipod, not needed by quicktime */
        put_be32(pb, 12); /* size */
        put_tag(pb, "mp4a");
        put_be32(pb, 0);
343
        mov_write_esds_tag(pb, track);
344
    } else if (mov_pcm_le_gt16(track->enc->codec_id)) {
345
        mov_write_enda_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
346
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
347
        mov_write_amr_tag(pb, track);
348 349
    } else if (track->enc->codec_id == CODEC_ID_AC3) {
        mov_write_ac3_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
350 351
    } else if (track->enc->codec_id == CODEC_ID_ALAC) {
        mov_write_extradata_tag(pb, track);
352 353 354
    } else if (track->enc->codec_id == CODEC_ID_ADPCM_MS ||
               track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
        mov_write_ms_tag(pb, track);
355
    }
356 357 358 359

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
360
    return updateSize(pb, pos);
361 362
}

363
static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
364 365 366 367 368 369 370
{
    put_be32(pb, track->vosLen+8);
    put_tag(pb, "glbl");
    put_buffer(pb, track->vosData, track->vosLen);
    return 8+track->vosLen;
}

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
/**
 * 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;
    }
}

400
static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
401
{
402
    int64_t pos = url_ftell(pb);
403 404 405 406 407 408 409 410
    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;
411 412 413
        } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id) ||
                   track->enc->codec_id == CODEC_ID_ADPCM_MS ||
                   track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
414 415 416
            version = 1;
        }
    }
417

418
    put_be32(pb, 0); /* size */
419
    put_le32(pb, tag); // store it byteswapped
420 421 422
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
423

424
    /* SoundDescription */
425
    put_be16(pb, version); /* Version */
426
    put_be16(pb, 0); /* Revision level */
427 428
    put_be32(pb, 0); /* Reserved */

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
    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 {
444 445 446 447 448 449 450 451 452 453
        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
454
            put_be16(pb, 16);
455 456
            put_be16(pb, 0);
        }
457

458 459 460
        put_be16(pb, 0); /* packet size (= 0) */
        put_be16(pb, track->timescale); /* Time scale */
        put_be16(pb, 0); /* Reserved */
461
    }
462

463 464
    if(version == 1) { /* SoundDescription V1 extended info */
        put_be32(pb, track->enc->frame_size); /* Samples per packet */
465
        put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
466
        put_be32(pb, track->sampleSize); /* Bytes per frame */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
467
        put_be32(pb, 2); /* Bytes per sample */
468 469
    }

470 471
    if(track->mode == MODE_MOV &&
       (track->enc->codec_id == CODEC_ID_AAC ||
472
        track->enc->codec_id == CODEC_ID_AC3 ||
473
        track->enc->codec_id == CODEC_ID_AMR_NB ||
474
        track->enc->codec_id == CODEC_ID_ALAC ||
475 476
        track->enc->codec_id == CODEC_ID_ADPCM_MS ||
        track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV ||
477
        mov_pcm_le_gt16(track->enc->codec_id)))
478
        mov_write_wave_tag(pb, track);
479
    else if(track->tag == MKTAG('m','p','4','a'))
Baptiste Coudurier's avatar
Baptiste Coudurier committed
480 481
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
482
        mov_write_amr_tag(pb, track);
483 484
    else if(track->enc->codec_id == CODEC_ID_AC3)
        mov_write_ac3_tag(pb, track);
485
    else if(track->enc->codec_id == CODEC_ID_ALAC)
486
        mov_write_extradata_tag(pb, track);
487 488
    else if(track->vosLen > 0)
        mov_write_glbl_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
489

Baptiste Coudurier's avatar
Baptiste Coudurier committed
490
    return updateSize(pb, pos);
491 492
}

493
static int mov_write_d263_tag(AVIOContext *pb)
494 495 496 497
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
498 499 500 501
    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 */
502 503 504
    return 0xf;
}

505
/* TODO: No idea about these values */
506
static int mov_write_svq3_tag(AVIOContext *pb)
507
{
508 509 510 511 512 513
    put_be32(pb, 0x15);
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
    put_be32(pb, 0x5);
    put_be32(pb, 0xe2c0211d);
    put_be32(pb, 0xc0000000);
514
    put_byte(pb, 0);
515
    return 0x15;
516 517
}

518
static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
519
{
520
    int64_t pos = url_ftell(pb);
521 522 523

    put_be32(pb, 0);
    put_tag(pb, "avcC");
524
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
525 526 527
    return updateSize(pb, pos);
}

528
/* also used by all avid codecs (dv, imx, meridien) and their variants */
529
static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
{
    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 */
562 563 564 565
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
566 567 568 569 570 571 572 573 574 575
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

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

576
static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
577
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
578
    int tag = track->enc->codec_tag;
579

580
    if (!ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
581 582 583 584 585 586
        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');
587 588
    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');
589 590 591 592

    return tag;
}

593 594 595 596 597 598 599 600 601 602 603
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 },
};

604 605 606 607
static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

608
    // keep original tag for subs, ipod supports both formats
609
    if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE &&
610
        (tag == MKTAG('t','x','3','g') ||
611
         tag == MKTAG('t','e','x','t'))))
612
        tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
613

614
    if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v"))
615 616
        av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
               "Quicktime/Ipod might not play the file\n");
617 618 619 620 621 622 623 624

    return tag;
}

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

625 626 627 628 629 630
    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');
631 632 633 634

    return tag;
}

635 636 637 638 639 640 641
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 },
642
    { PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
643 644 645
    { 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 },
646
    { PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
647
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
648
    { PIX_FMT_BGR24,   MKTAG('2','4','B','G'), 24 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
649
    { PIX_FMT_ARGB,    MKTAG('r','a','w',' '), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
650
    { PIX_FMT_BGRA,    MKTAG('B','G','R','A'), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
651
    { PIX_FMT_RGBA,    MKTAG('R','G','B','A'), 32 },
652
    { PIX_FMT_ABGR,    MKTAG('A','B','G','R'), 32 },
653
    { PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
654 655
};

656 657 658
static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
659 660 661 662 663 664 665 666 667
    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;
        }
    }
668 669 670 671 672 673 674 675 676

    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 &&
677
                 (track->enc->codec_id == CODEC_ID_DVVIDEO ||
678
                  track->enc->codec_id == CODEC_ID_RAWVIDEO ||
679
                  track->enc->codec_id == CODEC_ID_H263 ||
680
                  av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
681
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
682
            tag = mov_get_dv_codec_tag(s, track);
683
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
684
            tag = mov_get_rawvideo_codec_tag(s, track);
685
        else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
686
            tag = ff_codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
687
            if (!tag) { // if no mac fcc found, try with Microsoft tags
688
                tag = ff_codec_get_tag(ff_codec_bmp_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
689 690 691 692
                if (tag)
                    av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                           "the file may be unplayable!\n");
            }
693
        } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
694
            tag = ff_codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
695
            if (!tag) { // if no mac fcc found, try with Microsoft tags
696
                int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
697 698 699 700
                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
701
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
702
            }
703
        } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
704
            tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
705
    }
706

707 708 709
    return tag;
}

710 711 712 713 714 715 716 717 718 719 720
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 },
};

721 722 723 724 725 726 727 728 729
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)
730
        tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id);
731 732 733 734 735 736
    else
        tag = mov_get_codec_tag(s, track);

    return tag;
}

737 738 739 740
/** 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
 */
741
static int mov_write_uuid_tag_ipod(AVIOContext *pb)
742 743 744 745 746 747 748 749 750 751 752
{
    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;
}

753
static int mov_write_subtitle_tag(AVIOContext *pb, MOVTrack *track)
754 755 756 757 758 759 760 761 762 763 764 765 766 767
{
    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);
}

768
static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
769 770 771 772 773 774 775
{
    AVRational sar;
    av_reduce(&sar.num, &sar.den, track->enc->sample_aspect_ratio.num,
              track->enc->sample_aspect_ratio.den, INT_MAX);

    put_be32(pb, 16);
    put_tag(pb, "pasp");
776 777
    put_be32(pb, sar.num);
    put_be32(pb, sar.den);
778 779 780
    return 16;
}

781
static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
782
{
783
    int64_t pos = url_ftell(pb);
784
    char compressor_name[32];
785

786
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
787
    put_le32(pb, track->tag); // store it byteswapped
788 789 790 791
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

792 793
    put_be16(pb, 0); /* Codec stream version */
    put_be16(pb, 0); /* Codec stream revision (=0) */
794
    if (track->mode == MODE_MOV) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
795 796 797 798 799 800 801 802
        put_tag(pb, "FFMP"); /* Vendor */
        if(track->enc->codec_id == CODEC_ID_RAWVIDEO) {
            put_be32(pb, 0); /* Temporal Quality */
            put_be32(pb, 0x400); /* Spatial Quality = lossless*/
        } else {
            put_be32(pb, 0x200); /* Temporal Quality = normal */
            put_be32(pb, 0x200); /* Spatial Quality = normal */
        }
803 804 805 806 807
    } else {
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
    }
808
    put_be16(pb, track->enc->width); /* Video width */
809
    put_be16(pb, track->height); /* Video height */
810 811
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
812 813
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */