movenc.c 70.4 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 "movenc.h"
25
#include "avformat.h"
26
#include "riff.h"
27
#include "avio.h"
28
#include "isom.h"
29
#include "avc.h"
30
#include "libavcodec/get_bits.h"
31
#include "libavcodec/put_bits.h"
32

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

Diego Biurrun's avatar
Diego Biurrun committed
36
//FIXME support 64 bit variant with wide placeholders
37
static int64_t updateSize(ByteIOContext *pb, int64_t pos)
38
{
39
    int64_t curpos = url_ftell(pb);
40
    url_fseek(pb, pos, SEEK_SET);
41
    put_be32(pb, curpos - pos); /* rewrite size */
42
    url_fseek(pb, curpos, SEEK_SET);
43 44

    return curpos - pos;
45 46
}

47
/* Chunk offset atom */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
48
static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack *track)
49 50
{
    int i;
Benjamin Larsson's avatar
Benjamin Larsson committed
51
    int mode64 = 0; //   use 32 bit size variant if possible
52
    int64_t pos = url_ftell(pb);
53
    put_be32(pb, 0); /* size */
54 55 56 57 58
    if (pos > UINT32_MAX) {
        mode64 = 1;
        put_tag(pb, "co64");
    } else
        put_tag(pb, "stco");
59 60 61
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, track->entry); /* entry count */
    for (i=0; i<track->entry; i++) {
62
        if(mode64 == 1)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
63
            put_be64(pb, track->cluster[i].pos);
64
        else
Baptiste Coudurier's avatar
Baptiste Coudurier committed
65
            put_be32(pb, track->cluster[i].pos);
66
    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
67
    return updateSize(pb, pos);
68 69
}

70
/* Sample size atom */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
71
static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack *track)
72
{
73
    int equalChunks = 1;
74
    int i, j, entries = 0, tst = -1, oldtst = -1;
75

76
    int64_t pos = url_ftell(pb);
77
    put_be32(pb, 0); /* size */
78 79 80
    put_tag(pb, "stsz");
    put_be32(pb, 0); /* version & flags */

81
    for (i=0; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
82
        tst = track->cluster[i].size/track->cluster[i].entries;
83 84
        if(oldtst != -1 && tst != oldtst) {
            equalChunks = 0;
85 86
        }
        oldtst = tst;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
87
        entries += track->cluster[i].entries;
88
    }
89
    if (equalChunks) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
90
        int sSize = track->cluster[0].size/track->cluster[0].entries;
91
        put_be32(pb, sSize); // sample size
92
        put_be32(pb, entries); // sample count
93
    }
94
    else {
95 96
        put_be32(pb, 0); // sample size
        put_be32(pb, entries); // sample count
97
        for (i=0; i<track->entry; i++) {
98
            for (j=0; j<track->cluster[i].entries; j++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
99 100
                put_be32(pb, track->cluster[i].size /
                         track->cluster[i].entries);
101
            }
102 103
        }
    }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
104
    return updateSize(pb, pos);
105 106
}

107
/* Sample to chunk atom */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
108
static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack *track)
109
{
110
    int index = 0, oldval = -1, i;
111
    int64_t entryPos, curpos;
112

113
    int64_t pos = url_ftell(pb);
114
    put_be32(pb, 0); /* size */
115
    put_tag(pb, "stsc");
116
    put_be32(pb, 0); // version & flags
117
    entryPos = url_ftell(pb);
118
    put_be32(pb, track->entry); // entry count
119
    for (i=0; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
120
        if(oldval != track->cluster[i].samplesInChunk)
121
        {
122
            put_be32(pb, i+1); // first chunk
Baptiste Coudurier's avatar
Baptiste Coudurier committed
123
            put_be32(pb, track->cluster[i].samplesInChunk); // samples per chunk
124
            put_be32(pb, 0x1); // sample description index
Baptiste Coudurier's avatar
Baptiste Coudurier committed
125
            oldval = track->cluster[i].samplesInChunk;
126
            index++;
127 128
        }
    }
129 130
    curpos = url_ftell(pb);
    url_fseek(pb, entryPos, SEEK_SET);
131
    put_be32(pb, index); // rewrite size
132
    url_fseek(pb, curpos, SEEK_SET);
133

Baptiste Coudurier's avatar
Baptiste Coudurier committed
134
    return updateSize(pb, pos);
135 136
}

137
/* Sync sample atom */
138
static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack *track, uint32_t flag)
139
{
140
    int64_t curpos, entryPos;
141
    int i, index = 0;
142
    int64_t pos = url_ftell(pb);
143
    put_be32(pb, 0); // size
144
    put_tag(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
145
    put_be32(pb, 0); // version & flags
146
    entryPos = url_ftell(pb);
147
    put_be32(pb, track->entry); // entry count
148
    for (i=0; i<track->entry; i++) {
149
        if (track->cluster[i].flags & flag) {
150 151 152 153 154 155
            put_be32(pb, i+1);
            index++;
        }
    }
    curpos = url_ftell(pb);
    url_fseek(pb, entryPos, SEEK_SET);
156
    put_be32(pb, index); // rewrite size
157
    url_fseek(pb, curpos, SEEK_SET);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
158
    return updateSize(pb, pos);
159 160
}

161
static int mov_write_amr_tag(ByteIOContext *pb, MOVTrack *track)
162 163
{
    put_be32(pb, 0x11); /* size */
164 165
    if (track->mode == MODE_MOV) put_tag(pb, "samr");
    else                         put_tag(pb, "damr");
166
    put_tag(pb, "FFMP");
167
    put_byte(pb, 0); /* decoder version */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
168

Baptiste Coudurier's avatar
Baptiste Coudurier committed
169
    put_be16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
170 171
    put_byte(pb, 0x00); /* Mode change period (no restriction) */
    put_byte(pb, 0x01); /* Frames per sample */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
172 173 174
    return 0x11;
}

175 176 177 178 179 180 181 182 183 184 185 186 187
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");

188
    init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
    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
219 220 221 222 223 224 225 226 227 228
/**
 * 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;
}

229 230 231 232 233 234 235 236
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
237 238
static unsigned int descrLength(unsigned int len)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
239 240 241
    int i;
    for(i=1; len>>(7*i); i++);
    return len + 1 + i;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
242 243
}

Michael Niedermayer's avatar
Michael Niedermayer committed
244
static void putDescr(ByteIOContext *pb, int tag, unsigned int size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
245
{
Michael Niedermayer's avatar
Michael Niedermayer committed
246 247 248 249 250
    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
251 252
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
253
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack *track) // Basic
Baptiste Coudurier's avatar
Baptiste Coudurier committed
254
{
255
    int64_t pos = url_ftell(pb);
256
    int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
257

258
    put_be32(pb, 0); // size
Baptiste Coudurier's avatar
Baptiste Coudurier committed
259
    put_tag(pb, "esds");
260
    put_be32(pb, 0); // Version
Baptiste Coudurier's avatar
Baptiste Coudurier committed
261 262 263 264 265

    // ES descriptor
    putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
             descrLength(1));
    put_be16(pb, track->trackID);
266
    put_byte(pb, 0x00); // flags (= no flags)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
267 268 269 270 271

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

    // Object type indication
272 273
    if ((track->enc->codec_id == CODEC_ID_MP2 ||
         track->enc->codec_id == CODEC_ID_MP3) &&
274 275
        track->enc->sample_rate > 24000)
        put_byte(pb, 0x6B); // 11172-3
276
    else
277
        put_byte(pb, ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id));
Baptiste Coudurier's avatar
Baptiste Coudurier committed
278 279 280

    // 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)
281
    if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
282
        put_byte(pb, 0x15); // flags (= Audiostream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
283
    else
284
        put_byte(pb, 0x11); // flags (= Visualstream)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
285

286 287
    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
288

289
    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
290
    if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0)
291
        put_be32(pb, 0); // vbr
Baptiste Coudurier's avatar
Baptiste Coudurier committed
292
    else
293
        put_be32(pb, track->enc->rc_max_rate); // avg bitrate
Baptiste Coudurier's avatar
Baptiste Coudurier committed
294

295
    if (track->vosLen) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
296 297 298 299 300 301 302 303
        // 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
304
    return updateSize(pb, pos);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
305 306
}

307 308 309 310 311 312 313 314
static int mov_pcm_le_gt16(enum CodecID codec_id)
{
    return codec_id == CODEC_ID_PCM_S24LE ||
           codec_id == CODEC_ID_PCM_S32LE ||
           codec_id == CODEC_ID_PCM_F32LE ||
           codec_id == CODEC_ID_PCM_F64LE;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
315
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack *track)
316
{
317
    int64_t pos = url_ftell(pb);
318 319 320 321 322 323

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

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

326
    if (track->enc->codec_id == CODEC_ID_AAC) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
327 328 329 330
        /* useless atom needed by mplayer, ipod, not needed by quicktime */
        put_be32(pb, 12); /* size */
        put_tag(pb, "mp4a");
        put_be32(pb, 0);
331
        mov_write_esds_tag(pb, track);
332
    } else if (mov_pcm_le_gt16(track->enc->codec_id)) {
333
        mov_write_enda_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
334
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
335
        mov_write_amr_tag(pb, track);
336 337
    } else if (track->enc->codec_id == CODEC_ID_AC3) {
        mov_write_ac3_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
338 339
    } else if (track->enc->codec_id == CODEC_ID_ALAC) {
        mov_write_extradata_tag(pb, track);
340
    }
341 342 343 344

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
345
    return updateSize(pb, pos);
346 347
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
348
static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack *track)
349 350 351 352 353 354 355
{
    put_be32(pb, track->vosLen+8);
    put_tag(pb, "glbl");
    put_buffer(pb, track->vosData, track->vosLen);
    return 8+track->vosLen;
}

356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
/**
 * Compute flags for 'lpcm' tag.
 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
 */
static int mov_get_lpcm_flags(enum CodecID codec_id)
{
    switch (codec_id) {
    case CODEC_ID_PCM_F32BE:
    case CODEC_ID_PCM_F64BE:
        return 11;
    case CODEC_ID_PCM_F32LE:
    case CODEC_ID_PCM_F64LE:
        return 9;
    case CODEC_ID_PCM_U8:
        return 10;
    case CODEC_ID_PCM_S16BE:
    case CODEC_ID_PCM_S24BE:
    case CODEC_ID_PCM_S32BE:
        return 14;
    case CODEC_ID_PCM_S8:
    case CODEC_ID_PCM_S16LE:
    case CODEC_ID_PCM_S24LE:
    case CODEC_ID_PCM_S32LE:
        return 12;
    default:
        return 0;
    }
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
385
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack *track)
386
{
387
    int64_t pos = url_ftell(pb);
388 389 390 391 392 393 394 395
    int version = 0;
    uint32_t tag = track->tag;

    if (track->mode == MODE_MOV) {
        if (track->timescale > UINT16_MAX) {
            if (mov_get_lpcm_flags(track->enc->codec_id))
                tag = AV_RL32("lpcm");
            version = 2;
396
        } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id)) {
397 398 399
            version = 1;
        }
    }
400

401
    put_be32(pb, 0); /* size */
402
    put_le32(pb, tag); // store it byteswapped
403 404 405
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
406

407
    /* SoundDescription */
408
    put_be16(pb, version); /* Version */
409
    put_be16(pb, 0); /* Revision level */
410 411
    put_be32(pb, 0); /* Reserved */

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    if (version == 2) {
        put_be16(pb, 3);
        put_be16(pb, 16);
        put_be16(pb, 0xfffe);
        put_be16(pb, 0);
        put_be32(pb, 0x00010000);
        put_be32(pb, 72);
        put_be64(pb, av_dbl2int(track->timescale));
        put_be32(pb, track->enc->channels);
        put_be32(pb, 0x7F000000);
        put_be32(pb, av_get_bits_per_sample(track->enc->codec_id));
        put_be32(pb, mov_get_lpcm_flags(track->enc->codec_id));
        put_be32(pb, track->sampleSize);
        put_be32(pb, track->enc->frame_size);
    } else {
427 428 429 430 431 432 433 434 435 436
        if (track->mode == MODE_MOV) {
            put_be16(pb, track->enc->channels);
            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);
            put_be16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
        } else { /* reserved for mp4/3gp */
            put_be16(pb, 2);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
437
            put_be16(pb, 16);
438 439
            put_be16(pb, 0);
        }
440

441 442 443
        put_be16(pb, 0); /* packet size (= 0) */
        put_be16(pb, track->timescale); /* Time scale */
        put_be16(pb, 0); /* Reserved */
444
    }
445

446 447
    if(version == 1) { /* SoundDescription V1 extended info */
        put_be32(pb, track->enc->frame_size); /* Samples per packet */
448
        put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
449
        put_be32(pb, track->sampleSize); /* Bytes per frame */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
450
        put_be32(pb, 2); /* Bytes per sample */
451 452
    }

453 454
    if(track->mode == MODE_MOV &&
       (track->enc->codec_id == CODEC_ID_AAC ||
455
        track->enc->codec_id == CODEC_ID_AC3 ||
456
        track->enc->codec_id == CODEC_ID_AMR_NB ||
457 458
        track->enc->codec_id == CODEC_ID_ALAC ||
        mov_pcm_le_gt16(track->enc->codec_id)))
459
        mov_write_wave_tag(pb, track);
460
    else if(track->tag == MKTAG('m','p','4','a'))
Baptiste Coudurier's avatar
Baptiste Coudurier committed
461 462
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
463
        mov_write_amr_tag(pb, track);
464 465
    else if(track->enc->codec_id == CODEC_ID_AC3)
        mov_write_ac3_tag(pb, track);
466
    else if(track->enc->codec_id == CODEC_ID_ALAC)
467
        mov_write_extradata_tag(pb, track);
468 469
    else if(track->vosLen > 0)
        mov_write_glbl_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
470

Baptiste Coudurier's avatar
Baptiste Coudurier committed
471
    return updateSize(pb, pos);
472 473
}

474
static int mov_write_d263_tag(ByteIOContext *pb)
475 476 477 478
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
479 480 481 482
    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 */
483 484 485
    return 0xf;
}

486 487
/* TODO: No idea about these values */
static int mov_write_svq3_tag(ByteIOContext *pb)
488
{
489 490 491 492 493 494
    put_be32(pb, 0x15);
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
    put_be32(pb, 0x5);
    put_be32(pb, 0xe2c0211d);
    put_be32(pb, 0xc0000000);
495
    put_byte(pb, 0);
496
    return 0x15;
497 498
}

499 500
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
501
    int64_t pos = url_ftell(pb);
502 503 504

    put_be32(pb, 0);
    put_tag(pb, "avcC");
505
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
506 507 508
    return updateSize(pb, pos);
}

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 537 538 539 540 541 542
/* 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 */
543 544 545 546
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
547 548 549 550 551 552 553 554 555 556
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

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

557
static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
558
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
559
    int tag = track->enc->codec_tag;
560

561
    if (!ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
562 563 564 565 566 567
        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');
568 569
    else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) tag = MKTAG('m','p','4','v');
    else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) tag = MKTAG('m','p','4','a');
570 571 572 573

    return tag;
}

574 575 576 577 578 579 580 581 582 583 584
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 },
};

585 586 587 588
static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

589
    // keep original tag for subs, ipod supports both formats
590
    if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE &&
591
        (tag == MKTAG('t','x','3','g') ||
592
         tag == MKTAG('t','e','x','t'))))
593
        tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
594

595
    if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v"))
596 597
        av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
               "Quicktime/Ipod might not play the file\n");
598 599 600 601 602 603 604 605

    return tag;
}

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

606 607 608 609 610 611
    if (track->enc->height == 480) /* NTSC */
        if  (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
        else                                         tag = MKTAG('d','v','c',' ');
    else if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
    else if (track->enc->pix_fmt == PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
    else                                             tag = MKTAG('d','v','p','p');
612 613 614 615

    return tag;
}

616 617 618 619 620 621 622 623
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 },
624 625 626
    { 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 },
627
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
628
    { PIX_FMT_BGR24,   MKTAG('2','4','B','G'), 24 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
629
    { PIX_FMT_ARGB,    MKTAG('r','a','w',' '), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
630
    { PIX_FMT_BGRA,    MKTAG('B','G','R','A'), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
631
    { PIX_FMT_RGBA,    MKTAG('R','G','B','A'), 32 },
632 633
};

634 635 636
static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
637 638 639 640 641 642 643 644 645
    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;
        }
    }
646 647 648 649 650 651 652 653 654 655 656 657

    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
658
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
659
            tag = mov_get_dv_codec_tag(s, track);
660
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
661
            tag = mov_get_rawvideo_codec_tag(s, track);
662
        else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
663
            tag = ff_codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
664
            if (!tag) { // if no mac fcc found, try with Microsoft tags
665
                tag = ff_codec_get_tag(ff_codec_bmp_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
666 667 668 669
                if (tag)
                    av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                           "the file may be unplayable!\n");
            }
670
        } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
671
            tag = ff_codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
672
            if (!tag) { // if no mac fcc found, try with Microsoft tags
673
                int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
674 675 676 677
                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
678
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
679
            }
680
        } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
681
            tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
682
    }
683

684 685 686
    return tag;
}

687 688 689 690 691 692 693 694 695 696 697
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 },
};

698 699 700 701 702 703 704 705 706
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)
707
        tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id);
708 709 710 711 712 713
    else
        tag = mov_get_codec_tag(s, track);

    return tag;
}

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
/** 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;
}

730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
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
745
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
746
{
747
    int64_t pos = url_ftell(pb);
748
    char compressor_name[32];
749

750
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
751
    put_le32(pb, track->tag); // store it byteswapped
752 753 754 755
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

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

779
    memset(compressor_name,0,32);
780 781
    /* 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)
782
        strncpy(compressor_name,track->enc->codec->name,31);
783
    put_byte(pb, strlen(compressor_name));
784
    put_buffer(pb, compressor_name, 31);
785

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

Baptiste Coudurier's avatar
Baptiste Coudurier committed
806
    return updateSize(pb, pos);
807 808
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
809
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track)
810
{
811
    int64_t pos = url_ftell(pb);
812 813 814 815
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
816
    if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
817
        mov_write_video_tag(pb, track);
818
    else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
Thomas Raivio's avatar