movenc.c 64.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/bitstream.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 48
    unsigned int flags, size;
    uint64_t     pos;
49
    unsigned int samplesInChunk;
50
    char         key_frame;
51
    unsigned int entries;
52
    int64_t      cts;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
53
    int64_t      dts;
54 55 56
} MOVIentry;

typedef struct MOVIndex {
57
    int         mode;
58 59 60
    int         entry;
    long        timescale;
    long        time;
61
    int64_t     trackDuration;
62
    long        sampleCount;
63
    long        sampleSize;
64
    int         hasKeyframes;
65
    int         hasBframes;
66
    int         language;
67
    int         trackID;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
68
    int         tag; ///< stsd fourcc
69 70 71
    AVCodecContext *enc;

    int         vosLen;
72
    uint8_t     *vosData;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
73
    MOVIentry   *cluster;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
74
    int         audio_vbr;
75
    int         height; ///< active picture (w/o VBI) height for D-10/IMX
76 77
} MOVTrack;

78
typedef struct MOVMuxContext {
79
    int     mode;
80
    int64_t time;
81
    int     nb_streams;
82
    int64_t mdat_pos;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
83
    uint64_t mdat_size;
84
    long    timescale;
85
    MOVTrack *tracks;
86
} MOVMuxContext;
87

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

    return curpos - pos;
97 98
}

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

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

128
    int64_t pos = url_ftell(pb);
129
    put_be32(pb, 0); /* size */
130 131 132
    put_tag(pb, "stsz");
    put_be32(pb, 0); /* version & flags */

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

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

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
186
    return updateSize(pb, pos);
187 188
}

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

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

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

227 228 229 230 231 232 233 234 235 236 237 238 239
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");

240
    init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
241 242 243 244 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
    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
271 272 273 274 275 276 277 278 279 280
/**
 * 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;
}

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

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

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

310
    put_be32(pb, 0); // size
Baptiste Coudurier's avatar
Baptiste Coudurier committed
311
    put_tag(pb, "esds");
312
    put_be32(pb, 0); // Version
Baptiste Coudurier's avatar
Baptiste Coudurier committed
313 314 315 316 317

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

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

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

    // 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)
334
        put_byte(pb, 0x15); // flags (= Audiostream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
335
    else
336
        put_byte(pb, 0x11); // flags (= Visualstream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
337

338 339
    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
340

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

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
359
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack *track)
360
{
361
    int64_t pos = url_ftell(pb);
362 363 364 365 366 367

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

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

370
    if (track->enc->codec_id == CODEC_ID_AAC) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
371 372 373 374
        /* useless atom needed by mplayer, ipod, not needed by quicktime */
        put_be32(pb, 12); /* size */
        put_tag(pb, "mp4a");
        put_be32(pb, 0);
375 376 377 378
        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
379
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
380
        mov_write_amr_tag(pb, track);
381 382
    } else if (track->enc->codec_id == CODEC_ID_AC3) {
        mov_write_ac3_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
383 384
    } else if (track->enc->codec_id == CODEC_ID_ALAC) {
        mov_write_extradata_tag(pb, track);
385
    }
386 387 388 389

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
390
    return updateSize(pb, pos);
391 392
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
393
static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack *track)
394 395 396 397 398 399 400
{
    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
401
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack *track)
402
{
403
    int64_t pos = url_ftell(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
404 405 406 407
    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);
408

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

415
    /* SoundDescription */
416
    put_be16(pb, version); /* Version */
417
    put_be16(pb, 0); /* Revision level */
418 419
    put_be32(pb, 0); /* Reserved */

420 421
    if (track->mode == MODE_MOV) {
        put_be16(pb, track->enc->channels);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
422 423 424 425 426
        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);
427 428 429 430 431 432
        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);
    }
433

434
    put_be16(pb, 0); /* packet size (= 0) */
435 436 437
    put_be16(pb, track->timescale); /* Time scale */
    put_be16(pb, 0); /* Reserved */

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

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
464
    return updateSize(pb, pos);
465 466
}

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

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

492 493
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
494
    int64_t pos = url_ftell(pb);
495 496 497

    put_be32(pb, 0);
    put_tag(pb, "avcC");
498
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
499 500 501
    return updateSize(pb, pos);
}

502 503 504 505 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
/* 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 */
536 537 538 539
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
540 541 542 543 544 545 546 547 548 549
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

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

550
static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
551
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
552
    int tag = track->enc->codec_tag;
553 554 555 556 557 558 559 560 561 562

    if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
        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');
563 564 565 566

    return tag;
}

567 568 569 570 571 572 573 574 575 576 577
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 },
};

578 579 580 581
static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

582
    // keep original tag for subs, ipod supports both formats
583
    if (!(track->enc->codec_type == CODEC_TYPE_SUBTITLE &&
584
        (tag == MKTAG('t','x','3','g') ||
585
         tag == MKTAG('t','e','x','t'))))
586
        tag = codec_get_tag(codec_ipod_tags, track->enc->codec_id);
587

588 589 590
    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");
591 592 593 594 595 596 597 598

    return tag;
}

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

599 600 601 602 603 604
    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');
605 606 607 608

    return tag;
}

609 610 611 612 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 },
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
    { PIX_FMT_BGR32_1, MKTAG('r','a','w',' '), 32 },
};

621 622 623
static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
624 625 626 627 628 629 630 631 632
    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;
        }
    }
633 634 635 636 637 638 639 640 641 642 643 644

    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
645
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
646
            tag = mov_get_dv_codec_tag(s, track);
647
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
648
            tag = mov_get_rawvideo_codec_tag(s, track);
649
        else if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
            tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
            if (!tag) { // if no mac fcc found, try with Microsoft tags
                tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
                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) {
            tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
            if (!tag) { // if no mac fcc found, try with Microsoft tags
                int ms_tag = codec_get_tag(codec_wav_tags, track->enc->codec_id);
                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
665
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
666 667 668
            }
        } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
            tag = codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
669
    }
670

671 672 673
    return tag;
}

674 675 676 677 678 679 680 681 682 683 684
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 },
};

685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
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)
        tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id);
    else
        tag = mov_get_codec_tag(s, track);

    return tag;
}

701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
/** 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;
}

717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
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
732
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
733
{
734
    int64_t pos = url_ftell(pb);
735
    char compressor_name[32];
736

737
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
738
    put_le32(pb, track->tag); // store it byteswapped
739 740 741 742
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

743 744
    put_be16(pb, 0); /* Codec stream version */
    put_be16(pb, 0); /* Codec stream revision (=0) */
745
    if (track->mode == MODE_MOV) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
746 747 748 749 750 751 752 753
        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 */
        }
754 755 756 757 758
    } else {
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
    }
759
    put_be16(pb, track->enc->width); /* Video width */
760
    put_be16(pb, track->height); /* Video height */
761 762
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
763 764
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
765

766
    memset(compressor_name,0,32);
767 768
    /* 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)
769
        strncpy(compressor_name,track->enc->codec->name,31);
770
    put_byte(pb, strlen(compressor_name));
771
    put_buffer(pb, compressor_name, 31);
772

773 774
    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
775 776
    else
        put_be16(pb, 0x18); /* Reserved */
777
    put_be16(pb, 0xffff); /* Reserved */
778
    if(track->tag == MKTAG('m','p','4','v'))
779 780 781 782
        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)
783
        mov_write_svq3_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
784 785
    else if(track->enc->codec_id == CODEC_ID_DNXHD)
        mov_write_avid_tag(pb, track);
786
    else if(track->enc->codec_id == CODEC_ID_H264) {
787
        mov_write_avcc_tag(pb, track);
788 789
        if(track->mode == MODE_IPOD)
            mov_write_uuid_tag_ipod(pb);
790
    } else if(track->vosLen > 0)
791
        mov_write_glbl_tag(pb, track);
792

Baptiste Coudurier's avatar
Baptiste Coudurier committed
793
    return updateSize(pb, pos);
794 795
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
796
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track)
797
{
798
    int64_t pos = url_ftell(pb);
799 800 801 802
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
803 804 805 806
    if (track->enc->codec_type == CODEC_TYPE_VIDEO)
        mov_write_video_tag(pb, track);
    else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
        mov_write_audio_tag(pb, track);
807 808
    else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
        mov_write_subtitle_tag(pb, track);
809