movenc.c 74.8 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(ByteIOContext *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 */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
50
static int mov_write_stco_tag(ByteIOContext *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 */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
73
static int mov_write_stsz_tag(ByteIOContext *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 */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
110
static int mov_write_stsc_tag(ByteIOContext *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(ByteIOContext *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(ByteIOContext *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 178 179 180 181 182 183 184 185 186 187 188 189
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");

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 225 226 227 228 229 230
/**
 * 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;
}

231 232 233 234 235 236 237 238
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
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
}

Michael Niedermayer's avatar
Michael Niedermayer committed
246
static void putDescr(ByteIOContext *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
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
255
static int mov_write_esds_tag(ByteIOContext *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;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
317
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack *track)
318
{
319
    int64_t pos = url_ftell(pb);
320 321 322 323 324 325

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

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

328
    if (track->enc->codec_id == CODEC_ID_AAC) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
329 330 331 332
        /* useless atom needed by mplayer, ipod, not needed by quicktime */
        put_be32(pb, 12); /* size */
        put_tag(pb, "mp4a");
        put_be32(pb, 0);
333
        mov_write_esds_tag(pb, track);
334
    } else if (mov_pcm_le_gt16(track->enc->codec_id)) {
335
        mov_write_enda_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
336
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
337
        mov_write_amr_tag(pb, track);
338 339
    } else if (track->enc->codec_id == CODEC_ID_AC3) {
        mov_write_ac3_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
340 341
    } else if (track->enc->codec_id == CODEC_ID_ALAC) {
        mov_write_extradata_tag(pb, track);
342
    }
343 344 345 346

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
347
    return updateSize(pb, pos);
348 349
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
350
static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack *track)
351 352 353 354 355 356 357
{
    put_be32(pb, track->vosLen+8);
    put_tag(pb, "glbl");
    put_buffer(pb, track->vosData, track->vosLen);
    return 8+track->vosLen;
}

358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
/**
 * 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
387
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack *track)
388
{
389
    int64_t pos = url_ftell(pb);
390 391 392 393 394 395 396 397
    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;
398
        } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id)) {
399 400 401
            version = 1;
        }
    }
402

403
    put_be32(pb, 0); /* size */
404
    put_le32(pb, tag); // store it byteswapped
405 406 407
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
408

409
    /* SoundDescription */
410
    put_be16(pb, version); /* Version */
411
    put_be16(pb, 0); /* Revision level */
412 413
    put_be32(pb, 0); /* Reserved */

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
    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 {
429 430 431 432 433 434 435 436 437 438
        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
439
            put_be16(pb, 16);
440 441
            put_be16(pb, 0);
        }
442

443 444 445
        put_be16(pb, 0); /* packet size (= 0) */
        put_be16(pb, track->timescale); /* Time scale */
        put_be16(pb, 0); /* Reserved */
446
    }
447

448 449
    if(version == 1) { /* SoundDescription V1 extended info */
        put_be32(pb, track->enc->frame_size); /* Samples per packet */
450
        put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
451
        put_be32(pb, track->sampleSize); /* Bytes per frame */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
452
        put_be32(pb, 2); /* Bytes per sample */
453 454
    }

455 456
    if(track->mode == MODE_MOV &&
       (track->enc->codec_id == CODEC_ID_AAC ||
457
        track->enc->codec_id == CODEC_ID_AC3 ||
458
        track->enc->codec_id == CODEC_ID_AMR_NB ||
459 460
        track->enc->codec_id == CODEC_ID_ALAC ||
        mov_pcm_le_gt16(track->enc->codec_id)))
461
        mov_write_wave_tag(pb, track);
462
    else if(track->tag == MKTAG('m','p','4','a'))
Baptiste Coudurier's avatar
Baptiste Coudurier committed
463 464
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
465
        mov_write_amr_tag(pb, track);
466 467
    else if(track->enc->codec_id == CODEC_ID_AC3)
        mov_write_ac3_tag(pb, track);
468
    else if(track->enc->codec_id == CODEC_ID_ALAC)
469
        mov_write_extradata_tag(pb, track);
470 471
    else if(track->vosLen > 0)
        mov_write_glbl_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
472

Baptiste Coudurier's avatar
Baptiste Coudurier committed
473
    return updateSize(pb, pos);
474 475
}

476
static int mov_write_d263_tag(ByteIOContext *pb)
477 478 479 480
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
481 482 483 484
    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 */
485 486 487
    return 0xf;
}

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

501 502
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
503
    int64_t pos = url_ftell(pb);
504 505 506

    put_be32(pb, 0);
    put_tag(pb, "avcC");
507
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
508 509 510
    return updateSize(pb, pos);
}

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 540 541 542 543 544
/* 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 */
545 546 547 548
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
549 550 551 552 553 554 555 556 557 558
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

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

559
static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
560
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
561
    int tag = track->enc->codec_tag;
562

563
    if (!ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
564 565 566 567 568 569
        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');
570 571
    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');
572 573 574 575

    return tag;
}

576 577 578 579 580 581 582 583 584 585 586
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 },
};

587 588 589 590
static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

591
    // keep original tag for subs, ipod supports both formats
592
    if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE &&
593
        (tag == MKTAG('t','x','3','g') ||
594
         tag == MKTAG('t','e','x','t'))))
595
        tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
596

597
    if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v"))
598 599
        av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
               "Quicktime/Ipod might not play the file\n");
600 601 602 603 604 605 606 607

    return tag;
}

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

608 609 610 611 612 613
    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');
614 615 616 617

    return tag;
}

618 619 620 621 622 623 624
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 },
625
    { PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
626 627 628
    { 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 },
629
    { PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
630
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
631
    { PIX_FMT_BGR24,   MKTAG('2','4','B','G'), 24 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
632
    { PIX_FMT_ARGB,    MKTAG('r','a','w',' '), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
633
    { PIX_FMT_BGRA,    MKTAG('B','G','R','A'), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
634
    { PIX_FMT_RGBA,    MKTAG('R','G','B','A'), 32 },
635
    { PIX_FMT_ABGR,    MKTAG('A','B','G','R'), 32 },
636
    { PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
637 638
};

639 640 641
static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
642 643 644 645 646 647 648 649 650
    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;
        }
    }
651 652 653 654 655 656 657 658 659

    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 &&
660
                 (track->enc->codec_id == CODEC_ID_DVVIDEO ||
661
                  track->enc->codec_id == CODEC_ID_RAWVIDEO ||
662
                  track->enc->codec_id == CODEC_ID_H263 ||
663
                  av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
664
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
665
            tag = mov_get_dv_codec_tag(s, track);
666
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
667
            tag = mov_get_rawvideo_codec_tag(s, track);
668
        else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
669
            tag = ff_codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
670
            if (!tag) { // if no mac fcc found, try with Microsoft tags
671
                tag = ff_codec_get_tag(ff_codec_bmp_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
672 673 674 675
                if (tag)
                    av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                           "the file may be unplayable!\n");
            }
676
        } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
677
            tag = ff_codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
678
            if (!tag) { // if no mac fcc found, try with Microsoft tags
679
                int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
680 681 682 683
                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
684
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
685
            }
686
        } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
687
            tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
688
    }
689

690 691 692
    return tag;
}

693 694 695 696 697 698 699 700 701 702 703
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 },
};

704 705 706 707 708 709 710 711 712
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)
713
        tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id);
714 715 716 717 718 719
    else
        tag = mov_get_codec_tag(s, track);

    return tag;
}

720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
/** 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;
}

736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
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);
}

751 752 753 754 755 756 757 758
static int mov_write_pasp_tag(ByteIOContext *pb, MOVTrack *track)
{
    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");
759 760
    put_be32(pb, sar.num);
    put_be32(pb, sar.den);
761 762 763
    return 16;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
764
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
765
{
766
    int64_t pos = url_ftell(pb);
767
    char compressor_name[32];
768

769
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
770
    put_le32(pb, track->tag); // store it byteswapped
771 772 773 774
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

775 776
    put_be16(pb, 0); /* Codec stream version */
    put_be16(pb, 0); /* Codec stream revision (=0) */
777
    if (track->mode == MODE_MOV) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
778 779 780 781 782 783 784 785
        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 */
        }
786 787 788 789 790
    } else {
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
    }
791
    put_be16(pb, track->enc->width); /* Video width */
792
    put_be16(pb, track->height); /* Video height */
793 794
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
795 796
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
797

798
    memset(compressor_name,0,32);
799 800
    /* 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)
801
        strncpy(compressor_name,track->enc->codec->name,31);
802
    put_byte(pb, strlen(compressor_name));
803
    put_buffer(pb, compressor_name, 31);
804

805 806
    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
807 808
    else
        put_be16(pb, 0x18); /* Reserved */
809
    put_be16(pb, 0xffff); /* Reserved */
810
    if(track->tag == MKTAG('m','p','4','v'))
811 812 813 814
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_H263)
        mov_write_d263_tag(pb);
    else if(track->enc->codec_id == CODEC_ID_SVQ3)
815
        mov_write_svq3_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
816 817
    else if(track->enc->codec_id == CODEC_ID_DNXHD)
        mov_write_avid_tag(pb, track);
818
    else if(track->enc->codec_id == CODEC_ID_H264) {
819
        mov_write_avcc_tag(pb, track);