movenc.c 63.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 org>
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 23
 */
#include "avformat.h"
24
#include "riff.h"
25
#include "avio.h"
26
#include "isom.h"
27
#include "avc.h"
28
#include "libavcodec/bitstream.h"
29

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

33 34 35
#define MOV_INDEX_CLUSTER_SIZE 16384
#define globalTimescale 1000

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

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

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

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

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

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

    return curpos - pos;
95 96
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

548 549 550 551 552 553 554
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') },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
555
    { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
556
    { CODEC_ID_NONE, 0 },
557 558
};

Baptiste Coudurier's avatar
Baptiste Coudurier committed
559 560
static const AVCodecTag mov_pix_fmt_tags[] = {
    { PIX_FMT_YUYV422, MKTAG('y','u','v','s') },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
561
    { PIX_FMT_UYVY422, MKTAG('2','v','u','y') },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
562 563 564 565 566
    { PIX_FMT_BGR555,  MKTAG('r','a','w',' ') },
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' ') },
    { PIX_FMT_BGR32_1, MKTAG('r','a','w',' ') },
};

567 568 569 570 571
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') },
572
    { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
573
    { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
574
    { CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
575
    { CODEC_ID_NONE, 0 },
576 577
};

578
static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
579
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
580
    int tag = track->enc->codec_tag;
581
    if (track->mode == MODE_MP4 || track->mode == MODE_PSP) {
582 583
        if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
            return 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
584
        if      (track->enc->codec_id == CODEC_ID_H264)      tag = MKTAG('a','v','c','1');
585
        else if (track->enc->codec_id == CODEC_ID_AC3)       tag = MKTAG('a','c','-','3');
586
        else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag = MKTAG('d','r','a','c');
587
        else if (track->enc->codec_id == CODEC_ID_MOV_TEXT)  tag = MKTAG('t','x','3','g');
588 589
        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');
590
    } else if (track->mode == MODE_IPOD) {
591 592 593 594 595
        if (track->enc->codec_type == CODEC_TYPE_SUBTITLE &&
            (tag == MKTAG('t','x','3','g') ||
             tag == MKTAG('t','e','x','t')))
            track->tag = tag; // keep original tag
        else
Baptiste Coudurier's avatar
Baptiste Coudurier committed
596
            tag = codec_get_tag(codec_ipod_tags, track->enc->codec_id);
597 598 599
        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");
Michael Niedermayer's avatar
Michael Niedermayer committed
600
    } else if (track->mode & MODE_3GP) {
601
        tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id);
602
    } else if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
Baptiste Coudurier's avatar
Baptiste Coudurier committed
603 604
                        (tag == MKTAG('d','v','c','p') ||
                         track->enc->codec_id == CODEC_ID_RAWVIDEO))) {
605
        if (track->enc->codec_id == CODEC_ID_DVVIDEO) {
606 607 608 609 610 611
            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');
Baptiste Coudurier's avatar
Baptiste Coudurier committed
612 613 614 615
        } else if (track->enc->codec_id == CODEC_ID_RAWVIDEO) {
            tag = codec_get_tag(mov_pix_fmt_tags, track->enc->pix_fmt);
            if (!tag) // restore tag
                tag = track->enc->codec_tag;
616
        } else {
617
            if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
618
                tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
619
                if (!tag) { // if no mac fcc found, try with Microsoft tags
Baptiste Coudurier's avatar
Baptiste Coudurier committed
620
                    tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
621 622 623
                    if (tag)
                        av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                               "the file may be unplayable!\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
624
                }
625
            } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
626
                tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
627
                if (!tag) { // if no mac fcc found, try with Microsoft tags
Baptiste Coudurier's avatar
Baptiste Coudurier committed
628 629 630
                    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));
631 632
                        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
633 634
                    }
                }
635 636
            } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE) {
                tag = codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
637 638 639
            }
        }
    }
640 641 642
    return tag;
}

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
/** 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;
}

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
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
674
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
675
{
676
    int64_t pos = url_ftell(pb);
677
    char compressor_name[32];
678

679
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
680
    put_le32(pb, track->tag); // store it byteswapped
681 682 683 684
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

685 686
    put_be16(pb, 0); /* Codec stream version */
    put_be16(pb, 0); /* Codec stream revision (=0) */
687
    if (track->mode == MODE_MOV) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
688 689 690 691 692 693 694 695
        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 */
        }
696 697 698 699 700
    } else {
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
    }
701
    put_be16(pb, track->enc->width); /* Video width */
702
    put_be16(pb, track->height); /* Video height */
703 704
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
705 706
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
707

708
    memset(compressor_name,0,32);
709 710
    /* 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)
711
        strncpy(compressor_name,track->enc->codec->name,31);
712
    put_byte(pb, strlen(compressor_name));
713
    put_buffer(pb, compressor_name, 31);
714

715 716
    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
717 718
    else
        put_be16(pb, 0x18); /* Reserved */
719
    put_be16(pb, 0xffff); /* Reserved */
720
    if(track->tag == MKTAG('m','p','4','v'))
721 722 723 724
        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)
725
        mov_write_svq3_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
726 727
    else if(track->enc->codec_id == CODEC_ID_DNXHD)
        mov_write_avid_tag(pb, track);
728
    else if(track->enc->codec_id == CODEC_ID_H264) {
729
        mov_write_avcc_tag(pb, track);
730 731
        if(track->mode == MODE_IPOD)
            mov_write_uuid_tag_ipod(pb);
732
    } else if(track->vosLen > 0)
733
        mov_write_glbl_tag(pb, track);
734

Baptiste Coudurier's avatar
Baptiste Coudurier committed
735
    return updateSize(pb, pos);
736 737
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
738
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track)
739
{
740
    int64_t pos = url_ftell(pb);
741 742 743 744
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
745 746 747 748
    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);
749 750
    else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
        mov_write_subtitle_tag(pb, track);
751
    return updateSize(pb, pos);
752 753
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
754
static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track)
755
{