movenc.c 59.2 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
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
{
    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
    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
    offset_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
    offset_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 490 491 492 493
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
    offset_t pos = url_ftell(pb);

    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') },
553
    { CODEC_ID_NONE, 0 },
554 555
};

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

564 565 566 567 568
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') },
569
    { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
570
    { CODEC_ID_NONE, 0 },
571 572
};

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

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
/** 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
646
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
647
{
648
    offset_t pos = url_ftell(pb);
649
    char compressor_name[32];
650

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

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

680
    memset(compressor_name,0,32);
681 682
    /* 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)
683
        strncpy(compressor_name,track->enc->codec->name,31);
684
    put_byte(pb, strlen(compressor_name));
685
    put_buffer(pb, compressor_name, 31);
686

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
707
    return updateSize(pb, pos);
708 709
}

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
724
static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track)
725
{
726
    MOV_stts_t *ctts_entries;
727 728 729 730 731 732
    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
733
    ctts_entries[0].duration = track->cluster[0].cts;
734
    for (i=1; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
735
        if (track->cluster[i].cts == ctts_entries[entries].duration) {
736 737 738
            ctts_entries[entries].count++; /* compress */
        } else {
            entries++;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
739
            ctts_entries[entries].duration = track->cluster[i].cts;
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
            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;
}

757
/* Time to sample atom */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
758
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack *track)
759
{
760
    MOV_stts_t *stts_entries;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
    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