movenc.c 61.3 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
    int64_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
85
static int64_t updateSize(ByteIOContext *pb, int64_t pos)
86
{
87
    int64_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
    int64_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
    int64_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
    int index = 0, oldval = -1, i;
159
    int64_t entryPos, curpos;
160

161
    int64_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
    int64_t curpos, entryPos;
189
    int i, index = 0;
190
    int64_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
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");

236
    init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
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
    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
    int64_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
    if ((track->enc->codec_id == CODEC_ID_MP2 ||
         track->enc->codec_id == CODEC_ID_MP3) &&
322 323
        track->enc->sample_rate > 24000)
        put_byte(pb, 0x6B); // 11172-3
324 325
    else
        put_byte(pb, codec_get_tag(ff_mp4_obj_type, track->enc->codec_id));
Baptiste Coudurier's avatar
Baptiste Coudurier committed
326 327 328 329

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

441 442
    if(track->mode == MODE_MOV &&
       (track->enc->codec_id == CODEC_ID_AAC ||
443
        track->enc->codec_id == CODEC_ID_AC3 ||
444 445
        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_AC3)
        mov_write_ac3_tag(pb, track);
455
    else if(track->enc->codec_id == CODEC_ID_ALAC)
456
        mov_write_extradata_tag(pb, track);
457 458
    else if(track->vosLen > 0)
        mov_write_glbl_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
459

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

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

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

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

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

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

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

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
    { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
554
    { CODEC_ID_NONE, 0 },
555 556
};

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

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

575
static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
576
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
577
    int tag = track->enc->codec_tag;
578
    if (track->mode == MODE_MP4 || track->mode == MODE_PSP) {
579 580
        if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
            return 0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
581
        if      (track->enc->codec_id == CODEC_ID_H264)      tag = MKTAG('a','v','c','1');
582
        else if (track->enc->codec_id == CODEC_ID_AC3)       tag = MKTAG('a','c','-','3');
583
        else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag = MKTAG('d','r','a','c');
584
        else if (track->enc->codec_id == CODEC_ID_MOV_TEXT)  tag = MKTAG('t','x','3','g');
585 586
        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');
587 588 589 590 591
    } 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
592
    } else if (track->mode & MODE_3GP) {
593
        tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id);
594
    } else if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
Baptiste Coudurier's avatar
Baptiste Coudurier committed
595 596
                        (tag == MKTAG('d','v','c','p') ||
                         track->enc->codec_id == CODEC_ID_RAWVIDEO))) {
597
        if (track->enc->codec_id == CODEC_ID_DVVIDEO) {
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');
Baptiste Coudurier's avatar
Baptiste Coudurier committed
604 605 606 607
        } 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;
608
        } else {
609
            if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
610
                tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
611
                if (!tag) { // if no mac fcc found, try with Microsoft tags
Baptiste Coudurier's avatar
Baptiste Coudurier committed
612
                    tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
613 614 615
                    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
616
                }
617
            } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
618
                tag = codec_get_tag(codec_movaudio_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 621 622
                    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));
623 624
                        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
625 626
                    }
                }
627 628
            } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE) {
                tag = codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
629 630 631
            }
        }
    }
632 633 634
    return tag;
}

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
/** 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;
}

651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
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
666
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
667
{
668
    int64_t pos = url_ftell(pb);
669
    char compressor_name[32];
670

671
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
672
    put_le32(pb, track->tag); // store it byteswapped
673 674 675 676
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

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

700
    memset(compressor_name,0,32);
701 702
    /* 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)
703
        strncpy(compressor_name,track->enc->codec->name,31);
704
    put_byte(pb, strlen(compressor_name));
705
    put_buffer(pb, compressor_name, 31);
706

707 708
    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
709 710
    else
        put_be16(pb, 0x18); /* Reserved */
711
    put_be16(pb, 0xffff); /* Reserved */
712
    if(track->tag == MKTAG('m','p','4','v'))
713 714 715 716
        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)
717
        mov_write_svq3_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
718 719
    else if(track->enc->codec_id == CODEC_ID_DNXHD)
        mov_write_avid_tag(pb, track);
720
    else if(track->enc->codec_id == CODEC_ID_H264) {
721
        mov_write_avcc_tag(pb, track);
722 723
        if(track->mode == MODE_IPOD)
            mov_write_uuid_tag_ipod(pb);
724
    } else if(track->vosLen > 0)
725
        mov_write_glbl_tag(pb, track);
726

Baptiste Coudurier's avatar
Baptiste Coudurier committed
727
    return updateSize(pb, pos);
728 729
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
730
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track)
731
{
732
    int64_t pos = url_ftell(pb);
733 734 735 736
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
737 738 739 740
    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);
741 742
    else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
        mov_write_subtitle_tag(pb, track);
743
    return updateSize(pb, pos);
744 745
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
746
static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track)
747
{
748
    MOVStts *ctts_entries;
749 750 751 752 753 754
    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
755
    ctts_entries[0].duration = track->cluster[0].cts;
756
    for (i=1; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
757
        if (track->cluster[i].cts == ctts_entries[entries].duration) {
758 759 760
            ctts_entries[entries].count++; /* compress */
        } else {
            entries++;
Baptiste Coudurier's avatar