movenc.c 66.7 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 36 37
#define MOV_INDEX_CLUSTER_SIZE 16384
#define globalTimescale 1000

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 61 62
    int         entry;
    long        timescale;
    long        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
} MOVTrack;

82
typedef struct MOVMuxContext {
83
    int     mode;
84
    int64_t time;
85
    int     nb_streams;
86
    int64_t mdat_pos;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
87
    uint64_t mdat_size;
88
    long    timescale;
89
    MOVTrack *tracks;
90
} MOVMuxContext;
91

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

    return curpos - pos;
101 102
}

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

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

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

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

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

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

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

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

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

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

231 232 233 234 235 236 237 238 239 240 241 242 243
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");

244
    init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
245 246 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
    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
275 276 277 278 279 280 281 282 283 284
/**
 * 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;
}

285 286 287 288 289 290 291 292
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
293 294
static unsigned int descrLength(unsigned int len)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
295 296 297
    int i;
    for(i=1; len>>(7*i); i++);
    return len + 1 + i;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
298 299
}

Michael Niedermayer's avatar
Michael Niedermayer committed
300
static void putDescr(ByteIOContext *pb, int tag, unsigned int size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
301
{
Michael Niedermayer's avatar
Michael Niedermayer committed
302 303 304 305 306
    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
307 308
}

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

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

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

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

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

    // 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)
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
338
        put_byte(pb, 0x15); // flags (= Audiostream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
339
    else
340
        put_byte(pb, 0x11); // flags (= Visualstream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
341

342 343
    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
344

345
    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
346
    if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0)
347
        put_be32(pb, 0); // vbr
Baptiste Coudurier's avatar
Baptiste Coudurier committed
348
    else
349
        put_be32(pb, track->enc->rc_max_rate); // avg bitrate
Baptiste Coudurier's avatar
Baptiste Coudurier committed
350

351
    if (track->vosLen) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
352 353 354 355 356 357 358 359
        // 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
360
    return updateSize(pb, pos);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
361 362
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
363
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack *track)
364
{
365
    int64_t pos = url_ftell(pb);
366 367 368 369 370 371

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

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

374
    if (track->enc->codec_id == CODEC_ID_AAC) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
375 376 377 378
        /* useless atom needed by mplayer, ipod, not needed by quicktime */
        put_be32(pb, 12); /* size */
        put_tag(pb, "mp4a");
        put_be32(pb, 0);
379 380 381 382
        mov_write_esds_tag(pb, track);
    } else if (track->enc->codec_id == CODEC_ID_PCM_S24LE ||
               track->enc->codec_id == CODEC_ID_PCM_S32LE) {
        mov_write_enda_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
383
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
384
        mov_write_amr_tag(pb, track);
385 386
    } else if (track->enc->codec_id == CODEC_ID_AC3) {
        mov_write_ac3_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
387 388
    } else if (track->enc->codec_id == CODEC_ID_ALAC) {
        mov_write_extradata_tag(pb, track);
389
    }
390 391 392 393

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
394
    return updateSize(pb, pos);
395 396
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
397
static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack *track)
398 399 400 401 402 403 404
{
    put_be32(pb, track->vosLen+8);
    put_tag(pb, "glbl");
    put_buffer(pb, track->vosData, track->vosLen);
    return 8+track->vosLen;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
405
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack *track)
406
{
407
    int64_t pos = url_ftell(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
408 409 410 411
    int version = track->mode == MODE_MOV &&
        (track->audio_vbr ||
         track->enc->codec_id == CODEC_ID_PCM_S32LE ||
         track->enc->codec_id == CODEC_ID_PCM_S24LE);
412

413
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
414
    put_le32(pb, track->tag); // store it byteswapped
415 416 417
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
418

419
    /* SoundDescription */
420
    put_be16(pb, version); /* Version */
421
    put_be16(pb, 0); /* Revision level */
422 423
    put_be32(pb, 0); /* Reserved */

424 425
    if (track->mode == MODE_MOV) {
        put_be16(pb, track->enc->channels);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
426 427 428 429 430
        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);
431 432 433 434 435 436
        put_be16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
    } else { /* reserved for mp4/3gp */
        put_be16(pb, 2);
        put_be16(pb, 16);
        put_be16(pb, 0);
    }
437

438
    put_be16(pb, 0); /* packet size (= 0) */
439 440 441
    put_be16(pb, track->timescale); /* Time scale */
    put_be16(pb, 0); /* Reserved */

442 443
    if(version == 1) { /* SoundDescription V1 extended info */
        put_be32(pb, track->enc->frame_size); /* Samples per packet */
444
        put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
445
        put_be32(pb, track->sampleSize); /* Bytes per frame */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
446
        put_be32(pb, 2); /* Bytes per sample */
447 448
    }

449 450
    if(track->mode == MODE_MOV &&
       (track->enc->codec_id == CODEC_ID_AAC ||
451
        track->enc->codec_id == CODEC_ID_AC3 ||
452 453
        track->enc->codec_id == CODEC_ID_AMR_NB ||
        track->enc->codec_id == CODEC_ID_PCM_S24LE ||
Baptiste Coudurier's avatar
Baptiste Coudurier committed
454 455
        track->enc->codec_id == CODEC_ID_PCM_S32LE ||
        track->enc->codec_id == CODEC_ID_ALAC))
456
        mov_write_wave_tag(pb, track);
457
    else if(track->tag == MKTAG('m','p','4','a'))
Baptiste Coudurier's avatar
Baptiste Coudurier committed
458 459
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
460
        mov_write_amr_tag(pb, track);
461 462
    else if(track->enc->codec_id == CODEC_ID_AC3)
        mov_write_ac3_tag(pb, track);
463
    else if(track->enc->codec_id == CODEC_ID_ALAC)
464
        mov_write_extradata_tag(pb, track);
465 466
    else if(track->vosLen > 0)
        mov_write_glbl_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
467

Baptiste Coudurier's avatar
Baptiste Coudurier committed
468
    return updateSize(pb, pos);
469 470
}

471
static int mov_write_d263_tag(ByteIOContext *pb)
472 473 474 475
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
476 477 478 479
    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 */
480 481 482
    return 0xf;
}

483 484
/* TODO: No idea about these values */
static int mov_write_svq3_tag(ByteIOContext *pb)
485
{
486 487 488 489 490 491
    put_be32(pb, 0x15);
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
    put_be32(pb, 0x5);
    put_be32(pb, 0xe2c0211d);
    put_be32(pb, 0xc0000000);
492
    put_byte(pb, 0);
493
    return 0x15;
494 495
}

496 497
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
498
    int64_t pos = url_ftell(pb);
499 500 501

    put_be32(pb, 0);
    put_tag(pb, "avcC");
502
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
503 504 505
    return updateSize(pb, pos);
}

506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
/* 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 */
540 541 542 543
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
544 545 546 547 548 549 550 551 552 553
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

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

554
static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
555
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
556
    int tag = track->enc->codec_tag;
557

558
    if (!ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
559 560 561 562 563 564 565 566
        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');
    else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag = MKTAG('m','p','4','v');
    else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag = MKTAG('m','p','4','a');
567 568 569 570

    return tag;
}

571 572 573 574 575 576 577 578 579 580 581
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 },
};

582 583 584 585
static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

586
    // keep original tag for subs, ipod supports both formats
587
    if (!(track->enc->codec_type == CODEC_TYPE_SUBTITLE &&
588
        (tag == MKTAG('t','x','3','g') ||
589
         tag == MKTAG('t','e','x','t'))))
590
        tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
591

592 593 594
    if (!match_ext(s->filename, "m4a") && !match_ext(s->filename, "m4v"))
        av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
               "Quicktime/Ipod might not play the file\n");
595 596 597 598 599 600 601 602

    return tag;
}

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

603 604 605 606 607 608
    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');
609 610 611 612

    return tag;
}

613 614 615 616 617 618 619 620
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 },
621 622 623
    { 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 },
624
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
625
    { PIX_FMT_BGR24,   MKTAG('2','4','B','G'), 24 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
626
    { PIX_FMT_ARGB,    MKTAG('r','a','w',' '), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
627
    { PIX_FMT_BGRA,    MKTAG('B','G','R','A'), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
628
    { PIX_FMT_RGBA,    MKTAG('R','G','B','A'), 32 },
629 630
};

631 632 633
static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
634 635 636 637 638 639 640 641 642
    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;
        }
    }
643 644 645 646 647 648 649 650 651 652 653 654

    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
655
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
656
            tag = mov_get_dv_codec_tag(s, track);
657
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
658
            tag = mov_get_rawvideo_codec_tag(s, track);
659
        else if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
660
            tag = ff_codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
661
            if (!tag) { // if no mac fcc found, try with Microsoft tags
662
                tag = ff_codec_get_tag(ff_codec_bmp_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
663 664 665 666 667
                if (tag)
                    av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                           "the file may be unplayable!\n");
            }
        } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
668
            tag = ff_codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
669
            if (!tag) { // if no mac fcc found, try with Microsoft tags
670
                int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
671 672 673 674
                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
675
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
676 677
            }
        } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
678
            tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
679
    }
680

681 682 683
    return tag;
}

684 685 686 687 688 689 690 691 692 693 694
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 },
};

695 696 697 698 699 700 701 702 703
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)
704
        tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id);
705 706 707 708 709 710
    else
        tag = mov_get_codec_tag(s, track);

    return tag;
}

711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
/** 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;
}

727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
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
742
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
743
{
744
    int64_t pos = url_ftell(pb);
745
    char compressor_name[32];
746

747
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
748
    put_le32(pb, track->tag); // store it byteswapped
749 750 751 752
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

753 754
    put_be16(pb, 0); /* Codec stream version */
    put_be16(pb, 0); /* Codec stream revision (=0) */
755
    if (track->mode == MODE_MOV) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
756 757 758 759 760 761 762 763
        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 */
        }
764 765 766 767 768
    } else {
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
    }
769
    put_be16(pb, track->enc->width); /* Video width */
770
    put_be16(pb, track->height); /* Video height */
771 772
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
773 774
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
775

776
    memset(compressor_name,0,32);
777 778
    /* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */
    if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name)
779
        strncpy(compressor_name,track->enc->codec->name,31);
780
    put_byte(pb, strlen(compressor_name));
781
    put_buffer(pb, compressor_name, 31);
782

783 784
    if (track->mode == MODE_MOV && track->enc->bits_per_coded_sample)
        put_be16(pb, track->enc->bits_per_coded_sample);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
785 786
    else
        put_be16(pb, 0x18); /* Reserved */
787
    put_be16(pb, 0xffff); /* Reserved */
788
    if(track->tag == MKTAG('m','p','4','v'))
789 790 791