movenc.c 58.7 KB
Newer Older
1
/*
2
 * MOV, 3GP, MP4 muxer
3
 * Copyright (c) 2003 Thomas Raivio.
4
 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>.
5
 *
6 7 8
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
9 10
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
14 15 16 17 18
 * 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
19
 * License along with FFmpeg; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 22
 */
#include "avformat.h"
23
#include "riff.h"
24
#include "avio.h"
25
#include "isom.h"
26
#include "avc.h"
27
#include "libavcodec/bitstream.h"
28

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

32 33 34
#define MOV_INDEX_CLUSTER_SIZE 16384
#define globalTimescale 1000

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

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

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

    int         vosLen;
69
    uint8_t     *vosData;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
70
    MOVIentry   *cluster;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
71
    int         audio_vbr;
72 73
} MOVTrack;

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

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

    return curpos - pos;
93 94
}

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

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

124
    offset_t pos = url_ftell(pb);
125
    put_be32(pb, 0); /* size */
126 127 128
    put_tag(pb, "stsz");
    put_be32(pb, 0); /* version & flags */

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

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

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

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

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

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

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

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

    init_get_bits(&gbc, track->vosData+2, track->vosLen-2);
    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
267 268 269 270 271 272 273 274 275 276
/**
 * 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;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
458
    return updateSize(pb, pos);
459 460
}

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

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

486 487 488 489 490 491
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
    offset_t pos = url_ftell(pb);

    put_be32(pb, 0);
    put_tag(pb, "avcC");
492
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
493 494 495
    return updateSize(pb, pos);
}

496 497 498 499 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
/* 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 */
530 531 532 533
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
534 535 536 537 538 539 540 541 542 543
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

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

544 545 546 547 548 549 550 551 552
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
553 554
static const AVCodecTag mov_pix_fmt_tags[] = {
    { PIX_FMT_YUYV422, MKTAG('y','u','v','s') },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
555
    { PIX_FMT_UYVY422, MKTAG('2','v','u','y') },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
556 557 558 559 560
    { PIX_FMT_BGR555,  MKTAG('r','a','w',' ') },
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' ') },
    { PIX_FMT_BGR32_1, MKTAG('r','a','w',' ') },
};

561 562 563 564 565
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') },
566
    { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
567 568
};

569
static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
570
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
571
    int tag = track->enc->codec_tag;
572
    if (track->mode == MODE_MP4 || track->mode == MODE_PSP) {
573 574
        if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
            return 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
575
        if      (track->enc->codec_id == CODEC_ID_H264)      tag = MKTAG('a','v','c','1');
576
        else if (track->enc->codec_id == CODEC_ID_AC3)       tag = MKTAG('a','c','-','3');
577
        else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag = MKTAG('d','r','a','c');
578 579
        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');
580 581 582 583 584
    } else if (track->mode == MODE_IPOD) {
        tag = codec_get_tag(codec_ipod_tags, track->enc->codec_id);
        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
585
    } else if (track->mode & MODE_3GP) {
586
        tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id);
587
    } else if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
Baptiste Coudurier's avatar
Baptiste Coudurier committed
588 589
                        (tag == MKTAG('d','v','c','p') ||
                         track->enc->codec_id == CODEC_ID_RAWVIDEO))) {
590
        if (track->enc->codec_id == CODEC_ID_DVVIDEO) {
591 592 593 594 595 596
            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
597 598 599 600
        } 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;
601
        } else {
602
            if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
603
                tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
604
                if (!tag) { // if no mac fcc found, try with Microsoft tags
Baptiste Coudurier's avatar
Baptiste Coudurier committed
605
                    tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
606 607 608
                    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
609
                }
610
            } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
611
                tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
612
                if (!tag) { // if no mac fcc found, try with Microsoft tags
Baptiste Coudurier's avatar
Baptiste Coudurier committed
613 614 615
                    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));
616 617
                        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
618 619
                    }
                }
620 621 622
            }
        }
    }
623 624 625
    return tag;
}

626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
/** 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;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
642
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
643
{
644
    offset_t pos = url_ftell(pb);
645
    char compressor_name[32];
646

647
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
648
    put_le32(pb, track->tag); // store it byteswapped
649 650 651 652
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

653 654
    put_be16(pb, 0); /* Codec stream version */
    put_be16(pb, 0); /* Codec stream revision (=0) */
655
    if (track->mode == MODE_MOV) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
656 657 658 659 660 661 662 663
        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 */
        }
664 665 666 667 668
    } else {
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
    }
669 670
    put_be16(pb, track->enc->width); /* Video width */
    put_be16(pb, track->enc->height); /* Video height */
671 672
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
673 674
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
675

676
    memset(compressor_name,0,32);
677 678
    /* 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)
679
        strncpy(compressor_name,track->enc->codec->name,31);
680
    put_byte(pb, strlen(compressor_name));
681
    put_buffer(pb, compressor_name, 31);
682

Baptiste Coudurier's avatar
Baptiste Coudurier committed
683 684 685 686
    if (track->mode == MODE_MOV && track->enc->bits_per_sample)
        put_be16(pb, track->enc->bits_per_sample);
    else
        put_be16(pb, 0x18); /* Reserved */
687
    put_be16(pb, 0xffff); /* Reserved */
688
    if(track->tag == MKTAG('m','p','4','v'))
689 690 691 692
        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)
693
        mov_write_svq3_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
694 695
    else if(track->enc->codec_id == CODEC_ID_DNXHD)
        mov_write_avid_tag(pb, track);
696
    else if(track->enc->codec_id == CODEC_ID_H264) {
697
        mov_write_avcc_tag(pb, track);
698 699
        if(track->mode == MODE_IPOD)
            mov_write_uuid_tag_ipod(pb);
700
    } else if(track->vosLen > 0)
701
        mov_write_glbl_tag(pb, track);
702

Baptiste Coudurier's avatar
Baptiste Coudurier committed
703
    return updateSize(pb, pos);
704 705
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
706
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track)
707
{
708
    offset_t pos = url_ftell(pb);
709 710 711 712
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
713 714 715 716
    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);
717
    return updateSize(pb, pos);
718 719
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
720
static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track)
721
{
722
    MOV_stts_t *ctts_entries;
723 724 725 726 727 728
    uint32_t entries = 0;
    uint32_t atom_size;
    int i;

    ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */
    ctts_entries[0].count = 1;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
729
    ctts_entries[0].duration = track->cluster[0].cts;
730
    for (i=1; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
731
        if (track->cluster[i].cts == ctts_entries[entries].duration) {
732 733 734
            ctts_entries[entries].count++; /* compress */
        } else {
            entries++;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
735
            ctts_entries[entries].duration = track->cluster[i].cts;
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
            ctts_entries[entries].count = 1;
        }
    }
    entries++; /* last one */
    atom_size = 16 + (entries * 8);
    put_be32(pb, atom_size); /* size */
    put_tag(pb, "ctts");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, entries); /* entry count */
    for (i=0; i<entries; i++) {
        put_be32(pb, ctts_entries[i].count);
        put_be32(pb, ctts_entries[i].duration);
    }
    av_free(ctts_entries);
    return atom_size;
}

753
/* Time to sample atom */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
754
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack *track)
755
{
756
    MOV_stts_t *stts_entries;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
    uint32_t entries = -1;
    uint32_t atom_size;
    int i;

    if (track->enc->codec_type == CODEC_TYPE_AUDIO && !track->audio_vbr) {
        stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
        stts_entries[0].count = track->sampleCount;
        stts_entries[0].duration = 1;
        entries = 1;
    } else {
        stts_entries = av_malloc(track->entry * sizeof(*stts_entries)); /* worst case */
        for (i=0; i<track->entry; i++) {
            int64_t duration = i + 1 == track->entry ?
                track->trackDuration - track->cluster[i].dts + track->cluster[0].dts : /* readjusting */
                track->cluster[i+1].dts - track->cluster[i].dts;
            if (i && duration == stts_entries[entries].duration) {
                stts_entries[entries].count++; /* compress */
            } else {
                entries++;
                stts_entries[entries].duration = duration;
                stts_entries[entries].count = 1;
            }
        }
        entries++; /* last one */
    }
    atom_size = 16 + (entries * 8);
    put_be32(pb, atom_size); /* size */
784 785
    put_tag(pb, "stts");
    put_be32(pb, 0); /* version & flags */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
786 787 788 789 790 791 792
    put_be32(pb, entries); /* entry count */
    for (i=0; i<entries; i++) {
        put_be32(pb, stts_entries[i].count);
        put_be32(pb, stts_entries[i].duration);
    }
    av_free(stts_entries);
    return atom_size;
793 794
}

795
static int mov_write_dref_tag(ByteIOContext *pb)
796 797 798 799