movenc.c 64.9 KB
Newer Older
1
/*
2
 * MOV, 3GP, MP4 muxer
3 4
 * Copyright (c) 2003 Thomas Raivio
 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5
 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6
 *
7 8 9
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * FFmpeg is distributed in the hope that it will be useful,
15 16 17 18 19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with FFmpeg; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
 */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
23

24
#include "avformat.h"
25
#include "riff.h"
26
#include "avio.h"
27
#include "isom.h"
28
#include "avc.h"
29
#include "libavcodec/get_bits.h"
30
#include "libavcodec/put_bits.h"
31

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

35 36 37
#define MOV_INDEX_CLUSTER_SIZE 16384
#define globalTimescale 1000

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

46
typedef struct MOVIentry {
47
    unsigned int size;
48
    uint64_t     pos;
49
    unsigned int samplesInChunk;
50
    unsigned int entries;
51
    int          cts;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
52
    int64_t      dts;
53 54
#define MOV_SYNC_SAMPLE         0x0001
    uint32_t     flags;
55 56 57
} MOVIentry;

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

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

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

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

    return curpos - pos;
98 99
}

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

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

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

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

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

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

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

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

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

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

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

241
    init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    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
272 273 274 275 276 277 278 279 280 281
/**
 * 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;
}

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

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

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

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

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

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

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

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

339 340
    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
341

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
/* 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 */
537 538 539 540
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
541 542 543 544 545 546 547 548 549 550
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

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

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

    if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
        return 0;

    if      (track->enc->codec_id == CODEC_ID_H264)      tag = MKTAG('a','v','c','1');
    else if (track->enc->codec_id == CODEC_ID_AC3)       tag = MKTAG('a','c','-','3');
    else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag = MKTAG('d','r','a','c');
    else if (track->enc->codec_id == CODEC_ID_MOV_TEXT)  tag = MKTAG('t','x','3','g');
    else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag = MKTAG('m','p','4','v');
    else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag = MKTAG('m','p','4','a');
564 565 566 567

    return tag;
}

568 569 570 571 572 573 574 575 576 577 578
static const AVCodecTag codec_ipod_tags[] = {
    { CODEC_ID_H264,   MKTAG('a','v','c','1') },
    { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
    { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
    { CODEC_ID_ALAC,   MKTAG('a','l','a','c') },
    { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
    { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
    { CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
    { CODEC_ID_NONE, 0 },
};

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

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

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

    return tag;
}

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

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

    return tag;
}

610 611 612 613 614 615 616 617
static const struct {
    enum PixelFormat pix_fmt;
    uint32_t tag;
    unsigned bps;
} mov_pix_fmt_tags[] = {
    { PIX_FMT_YUYV422, MKTAG('y','u','v','s'),  0 },
    { PIX_FMT_UYVY422, MKTAG('2','v','u','y'),  0 },
    { PIX_FMT_BGR555,  MKTAG('r','a','w',' '), 16 },
618 619 620
    { PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
    { PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
    { PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
621
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
622
    { PIX_FMT_BGR24,   MKTAG('2','4','B','G'), 24 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
623
    { PIX_FMT_ARGB,    MKTAG('r','a','w',' '), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
624
    { PIX_FMT_BGRA,    MKTAG('B','G','R','A'), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
625
    { PIX_FMT_RGBA,    MKTAG('R','G','B','A'), 32 },
626 627
};

628 629 630
static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
631 632 633 634 635 636 637 638 639
    int i;

    for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
        if (track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) {
            tag = mov_pix_fmt_tags[i].tag;
            track->enc->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
            break;
        }
    }
640 641 642 643 644 645 646 647 648 649 650 651

    return tag;
}

static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

    if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
                 (tag == MKTAG('d','v','c','p') ||
                  track->enc->codec_id == CODEC_ID_RAWVIDEO ||
                  av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
652
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
653
            tag = mov_get_dv_codec_tag(s, track);
654
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
655
            tag = mov_get_rawvideo_codec_tag(s, track);
656
        else if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
            tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
            if (!tag) { // if no mac fcc found, try with Microsoft tags
                tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
                if (tag)
                    av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                           "the file may be unplayable!\n");
            }
        } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
            tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
            if (!tag) { // if no mac fcc found, try with Microsoft tags
                int ms_tag = codec_get_tag(codec_wav_tags, track->enc->codec_id);
                if (ms_tag) {
                    tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
                    av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, "
                           "the file may be unplayable!\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
672
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
673 674 675
            }
        } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
            tag = codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
676
    }
677

678 679 680
    return tag;
}

681 682 683 684 685 686 687 688 689 690 691
static const AVCodecTag codec_3gp_tags[] = {
    { CODEC_ID_H263,   MKTAG('s','2','6','3') },
    { CODEC_ID_H264,   MKTAG('a','v','c','1') },
    { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
    { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
    { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
    { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
    { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
    { CODEC_ID_NONE, 0 },
};

692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

    if (track->mode == MODE_MP4 || track->mode == MODE_PSP)
        tag = mp4_get_codec_tag(s, track);
    else if (track->mode == MODE_IPOD)
        tag = ipod_get_codec_tag(s, track);
    else if (track->mode & MODE_3GP)
        tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id);
    else
        tag = mov_get_codec_tag(s, track);

    return tag;
}

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
/** 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;
}

724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
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
739
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
740
{
741
    int64_t pos = url_ftell(pb);
742
    char compressor_name[32];
743

744
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
745
    put_le32(pb, track->tag); // store it byteswapped
746 747 748 749
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

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

773
    memset(compressor_name,0,32);
774 775
    /* 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)
776
        strncpy(compressor_name,track->enc->codec->name,31);
777
    put_byte(pb, strlen(compressor_name));
778
    put_buffer(pb, compressor_name, 31);
779

780 781
    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
782 783
    else
        put_be16(pb, 0x18); /* Reserved */
784
    put_be16(pb, 0xffff); /* Reserved */
785
    if(track->tag == MKTAG('m','p','4','v'))
786 787 788 789
        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)
790
        mov_write_svq3_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
791 792
    else if(track->enc->codec_id == CODEC_ID_DNXHD)
        mov_write_avid_tag(pb, track);
793
    else if(track->enc->codec_id == CODEC_ID_H264) {
794
        mov_write_avcc_tag(pb, track);
795 796
        if(track->mode == MODE_IPOD)
            mov_write_uuid_tag_ipod(pb);
797
    } else if(track->vosLen > 0)
798
        mov_write_glbl_tag(pb, track);
799

Baptiste Coudurier's avatar
Baptiste Coudurier committed
800
    return updateSize(pb, pos);
801 802
}