movenc.c 64.6 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

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

34 35 36
#define MOV_INDEX_CLUSTER_SIZE 16384
#define globalTimescale 1000

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

45
typedef struct MOVIentry {
46 47
    unsigned int flags, size;
    uint64_t     pos;
48
    unsigned int samplesInChunk;
49
    char         key_frame;
50
    unsigned int entries;
51
    int64_t      cts;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
52
    int64_t      dts;
53 54 55
} MOVIentry;

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

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

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

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

    return curpos - pos;
96 97
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    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');
562 563 564 565

    return tag;
}

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

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

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

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

    return tag;
}

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

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

    return tag;
}

608 609 610 611 612 613 614 615 616 617 618 619
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 },
};

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

    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
644
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
645
            tag = mov_get_dv_codec_tag(s, track);
646
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
647
            tag = mov_get_rawvideo_codec_tag(s, track);
648
        else if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
            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
664
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
665 666 667
            }
        } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
            tag = codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
668
    }
669

670 671 672
    return tag;
}

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

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
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;
}

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

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

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

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

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

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

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

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