movenc.c 76.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
#include "internal.h"
#include "libavutil/avstring.h"
34

35 36 37
#undef NDEBUG
#include <assert.h>

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

    return curpos - pos;
47 48
}

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

72
/* Sample size atom */
73
static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
74
{
75
    int equalChunks = 1;
76
    int i, j, entries = 0, tst = -1, oldtst = -1;
77

78
    int64_t pos = url_ftell(pb);
79
    avio_wb32(pb, 0); /* size */
80
    put_tag(pb, "stsz");
81
    avio_wb32(pb, 0); /* version & flags */
82

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

109
/* Sample to chunk atom */
110
static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
111
{
112
    int index = 0, oldval = -1, i;
113
    int64_t entryPos, curpos;
114

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

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

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

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

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

177
static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track)
178 179 180 181 182 183 184 185 186
{
    GetBitContext gbc;
    PutBitContext pbc;
    uint8_t buf[3];
    int fscod, bsid, bsmod, acmod, lfeon, frmsizecod;

    if (track->vosLen < 7)
        return -1;

187
    avio_wb32(pb, 11);
188 189
    put_tag(pb, "dac3");

190
    init_get_bits(&gbc, track->vosData+4, track->vosLen-4);
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
    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);
216
    avio_write(pb, buf, sizeof(buf));
217 218 219 220

    return 11;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
221 222 223 224
/**
 * This function writes extradata "as is".
 * Extradata must be formated like a valid atom (with size and tag)
 */
225
static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
226
{
227
    avio_write(pb, track->enc->extradata, track->enc->extradata_size);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
228 229 230
    return track->enc->extradata_size;
}

231
static int mov_write_enda_tag(AVIOContext *pb)
232
{
233
    avio_wb32(pb, 10);
234
    put_tag(pb, "enda");
235
    avio_wb16(pb, 1); /* little endian */
236 237 238
    return 10;
}

Baptiste Coudurier's avatar
Baptiste Coudurier committed
239 240
static unsigned int descrLength(unsigned int len)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
241 242 243
    int i;
    for(i=1; len>>(7*i); i++);
    return len + 1 + i;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
244 245
}

246
static void putDescr(AVIOContext *pb, int tag, unsigned int size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
247
{
Michael Niedermayer's avatar
Michael Niedermayer committed
248
    int i= descrLength(size) - size - 2;
249
    avio_w8(pb, tag);
Michael Niedermayer's avatar
Michael Niedermayer committed
250
    for(; i>0; i--)
251 252
        avio_w8(pb, (size>>(7*i)) | 0x80);
    avio_w8(pb, size & 0x7F);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
253 254
}

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

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

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

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

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

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

288 289
    avio_w8(pb,  track->enc->rc_buffer_size>>(3+16));      // Buffersize DB (24 bits)
    avio_wb16(pb, (track->enc->rc_buffer_size>>3)&0xFFFF); // Buffersize DB
Baptiste Coudurier's avatar
Baptiste Coudurier committed
290

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

297
    if (track->vosLen) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
298 299
        // DecoderSpecific info descriptor
        putDescr(pb, 0x05, track->vosLen);
300
        avio_write(pb, track->vosData, track->vosLen);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
301 302 303 304
    }

    // SL descriptor
    putDescr(pb, 0x06, 1);
305
    avio_w8(pb, 0x02);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
306
    return updateSize(pb, pos);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
307 308
}

309 310 311 312 313 314 315 316
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;
}

317
static int mov_write_ms_tag(AVIOContext *pb, MOVTrack *track)
318 319
{
    int64_t pos = url_ftell(pb);
320 321
    avio_wb32(pb, 0);
    avio_wl32(pb, track->tag); // store it byteswapped
322
    track->enc->codec_tag = av_bswap16(track->tag >> 16);
323 324 325 326
    ff_put_wav_header(pb, track->enc);
    return updateSize(pb, pos);
}

327
static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track)
328
{
329
    int64_t pos = url_ftell(pb);
330

331
    avio_wb32(pb, 0);     /* size */
332 333
    put_tag(pb, "wave");

334
    avio_wb32(pb, 12);    /* size */
335
    put_tag(pb, "frma");
336
    avio_wl32(pb, track->tag);
337

338
    if (track->enc->codec_id == CODEC_ID_AAC) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
339
        /* useless atom needed by mplayer, ipod, not needed by quicktime */
340
        avio_wb32(pb, 12); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
341
        put_tag(pb, "mp4a");
342
        avio_wb32(pb, 0);
343
        mov_write_esds_tag(pb, track);
344
    } else if (mov_pcm_le_gt16(track->enc->codec_id)) {
345
        mov_write_enda_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
346
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
347
        mov_write_amr_tag(pb, track);
348 349
    } else if (track->enc->codec_id == CODEC_ID_AC3) {
        mov_write_ac3_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
350 351
    } else if (track->enc->codec_id == CODEC_ID_ALAC) {
        mov_write_extradata_tag(pb, track);
352 353 354
    } else if (track->enc->codec_id == CODEC_ID_ADPCM_MS ||
               track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
        mov_write_ms_tag(pb, track);
355
    }
356

357 358
    avio_wb32(pb, 8);     /* size */
    avio_wb32(pb, 0);     /* null tag */
359

Baptiste Coudurier's avatar
Baptiste Coudurier committed
360
    return updateSize(pb, pos);
361 362
}

363
static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
364
{
365
    avio_wb32(pb, track->vosLen+8);
366
    put_tag(pb, "glbl");
367
    avio_write(pb, track->vosData, track->vosLen);
368 369 370
    return 8+track->vosLen;
}

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
/**
 * 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;
    }
}

400
static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
401
{
402
    int64_t pos = url_ftell(pb);
403 404 405 406 407 408 409 410
    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;
411 412 413
        } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id) ||
                   track->enc->codec_id == CODEC_ID_ADPCM_MS ||
                   track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) {
414 415 416
            version = 1;
        }
    }
417

418 419 420 421 422
    avio_wb32(pb, 0); /* size */
    avio_wl32(pb, tag); // store it byteswapped
    avio_wb32(pb, 0); /* Reserved */
    avio_wb16(pb, 0); /* Reserved */
    avio_wb16(pb, 1); /* Data-reference index, XXX  == 1 */
423

424
    /* SoundDescription */
425 426 427
    avio_wb16(pb, version); /* Version */
    avio_wb16(pb, 0); /* Revision level */
    avio_wb32(pb, 0); /* Reserved */
428

429
    if (version == 2) {
430 431 432 433 434 435 436 437 438 439 440 441 442
        avio_wb16(pb, 3);
        avio_wb16(pb, 16);
        avio_wb16(pb, 0xfffe);
        avio_wb16(pb, 0);
        avio_wb32(pb, 0x00010000);
        avio_wb32(pb, 72);
        avio_wb64(pb, av_dbl2int(track->timescale));
        avio_wb32(pb, track->enc->channels);
        avio_wb32(pb, 0x7F000000);
        avio_wb32(pb, av_get_bits_per_sample(track->enc->codec_id));
        avio_wb32(pb, mov_get_lpcm_flags(track->enc->codec_id));
        avio_wb32(pb, track->sampleSize);
        avio_wb32(pb, track->enc->frame_size);
443
    } else {
444
        if (track->mode == MODE_MOV) {
445
            avio_wb16(pb, track->enc->channels);
446 447
            if (track->enc->codec_id == CODEC_ID_PCM_U8 ||
                track->enc->codec_id == CODEC_ID_PCM_S8)
448
                avio_wb16(pb, 8); /* bits per sample */
449
            else
450 451
                avio_wb16(pb, 16);
            avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
452
        } else { /* reserved for mp4/3gp */
453 454 455
            avio_wb16(pb, 2);
            avio_wb16(pb, 16);
            avio_wb16(pb, 0);
456
        }
457

458 459 460
        avio_wb16(pb, 0); /* packet size (= 0) */
        avio_wb16(pb, track->timescale); /* Time scale */
        avio_wb16(pb, 0); /* Reserved */
461
    }
462

463
    if(version == 1) { /* SoundDescription V1 extended info */
464 465 466 467
        avio_wb32(pb, track->enc->frame_size); /* Samples per packet */
        avio_wb32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
        avio_wb32(pb, track->sampleSize); /* Bytes per frame */
        avio_wb32(pb, 2); /* Bytes per sample */
468 469
    }

470 471
    if(track->mode == MODE_MOV &&
       (track->enc->codec_id == CODEC_ID_AAC ||
472
        track->enc->codec_id == CODEC_ID_AC3 ||
473
        track->enc->codec_id == CODEC_ID_AMR_NB ||
474
        track->enc->codec_id == CODEC_ID_ALAC ||
475 476
        track->enc->codec_id == CODEC_ID_ADPCM_MS ||
        track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV ||
477
        mov_pcm_le_gt16(track->enc->codec_id)))
478
        mov_write_wave_tag(pb, track);
479
    else if(track->tag == MKTAG('m','p','4','a'))
Baptiste Coudurier's avatar
Baptiste Coudurier committed
480 481
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
482
        mov_write_amr_tag(pb, track);
483 484
    else if(track->enc->codec_id == CODEC_ID_AC3)
        mov_write_ac3_tag(pb, track);
485
    else if(track->enc->codec_id == CODEC_ID_ALAC)
486
        mov_write_extradata_tag(pb, track);
487 488
    else if(track->vosLen > 0)
        mov_write_glbl_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
489

Baptiste Coudurier's avatar
Baptiste Coudurier committed
490
    return updateSize(pb, pos);
491 492
}

493
static int mov_write_d263_tag(AVIOContext *pb)
494
{
495
    avio_wb32(pb, 0xf); /* size */
496 497
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
498
    avio_w8(pb, 0); /* decoder version */
499
    /* FIXME use AVCodecContext level/profile, when encoder will set values */
500 501
    avio_w8(pb, 0xa); /* level */
    avio_w8(pb, 0); /* profile */
502 503 504
    return 0xf;
}

505
/* TODO: No idea about these values */
506
static int mov_write_svq3_tag(AVIOContext *pb)
507
{
508
    avio_wb32(pb, 0x15);
509 510
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
511 512 513 514
    avio_wb32(pb, 0x5);
    avio_wb32(pb, 0xe2c0211d);
    avio_wb32(pb, 0xc0000000);
    avio_w8(pb, 0);
515
    return 0x15;
516 517
}

518
static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
519
{
520
    int64_t pos = url_ftell(pb);
521

522
    avio_wb32(pb, 0);
523
    put_tag(pb, "avcC");
524
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
525 526 527
    return updateSize(pb, pos);
}

528
/* also used by all avid codecs (dv, imx, meridien) and their variants */
529
static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
530 531
{
    int i;
532
    avio_wb32(pb, 24); /* size */
533 534 535
    put_tag(pb, "ACLR");
    put_tag(pb, "ACLR");
    put_tag(pb, "0001");
536 537
    avio_wb32(pb, 1); /* yuv 1 / rgb 2 ? */
    avio_wb32(pb, 0); /* unknown */
538

539
    avio_wb32(pb, 24); /* size */
540 541 542
    put_tag(pb, "APRG");
    put_tag(pb, "APRG");
    put_tag(pb, "0001");
543 544
    avio_wb32(pb, 1); /* unknown */
    avio_wb32(pb, 0); /* unknown */
545

546
    avio_wb32(pb, 120); /* size */
547 548 549
    put_tag(pb, "ARES");
    put_tag(pb, "ARES");
    put_tag(pb, "0001");
550 551
    avio_wb32(pb, AV_RB32(track->vosData + 0x28)); /* dnxhd cid, some id ? */
    avio_wb32(pb, track->enc->width);
552 553
    /* values below are based on samples created with quicktime and avid codecs */
    if (track->vosData[5] & 2) { // interlaced
554 555 556 557
        avio_wb32(pb, track->enc->height/2);
        avio_wb32(pb, 2); /* unknown */
        avio_wb32(pb, 0); /* unknown */
        avio_wb32(pb, 4); /* unknown */
558
    } else {
559 560 561
        avio_wb32(pb, track->enc->height);
        avio_wb32(pb, 1); /* unknown */
        avio_wb32(pb, 0); /* unknown */
562
        if (track->enc->height == 1080)
563
            avio_wb32(pb, 5); /* unknown */
564
        else
565
            avio_wb32(pb, 6); /* unknown */
566 567 568
    }
    /* padding */
    for (i = 0; i < 10; i++)
569
        avio_wb64(pb, 0);
570 571

    /* extra padding for stsd needed */
572
    avio_wb32(pb, 0);
573 574 575
    return 0;
}

576
static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
577
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
578
    int tag = track->enc->codec_tag;
579

580
    if (!ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
581 582 583 584 585 586
        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');
587 588
    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');
589 590 591 592

    return tag;
}

593 594 595 596 597 598 599 600 601 602 603
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 },
};

604 605 606 607
static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;

608
    // keep original tag for subs, ipod supports both formats
609
    if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE &&
610
        (tag == MKTAG('t','x','3','g') ||
611
         tag == MKTAG('t','e','x','t'))))
612
        tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
613

614
    if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v"))
615 616
        av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
               "Quicktime/Ipod might not play the file\n");
617 618 619 620 621 622 623 624

    return tag;
}

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

625 626 627 628 629 630
    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');
631 632 633 634

    return tag;
}

635 636 637 638 639 640 641
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 },
642
    { PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
643 644 645
    { 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 },
646
    { PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
647
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' '), 24 },
648
    { PIX_FMT_BGR24,   MKTAG('2','4','B','G'), 24 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
649
    { PIX_FMT_ARGB,    MKTAG('r','a','w',' '), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
650
    { PIX_FMT_BGRA,    MKTAG('B','G','R','A'), 32 },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
651
    { PIX_FMT_RGBA,    MKTAG('R','G','B','A'), 32 },
652
    { PIX_FMT_ABGR,    MKTAG('A','B','G','R'), 32 },
653
    { PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
654 655
};

656 657 658
static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
659 660 661 662 663 664 665 666 667
    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;
        }
    }
668 669 670 671 672 673 674 675 676

    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 &&
677
                 (track->enc->codec_id == CODEC_ID_DVVIDEO ||
678
                  track->enc->codec_id == CODEC_ID_RAWVIDEO ||
679
                  track->enc->codec_id == CODEC_ID_H263 ||
680
                  av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
681
        if (track->enc->codec_id == CODEC_ID_DVVIDEO)
682
            tag = mov_get_dv_codec_tag(s, track);
683
        else if (track->enc->codec_id == CODEC_ID_RAWVIDEO)
684
            tag = mov_get_rawvideo_codec_tag(s, track);
685
        else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
686
            tag = ff_codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
687
            if (!tag) { // if no mac fcc found, try with Microsoft tags
688
                tag = ff_codec_get_tag(ff_codec_bmp_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
689 690 691 692
                if (tag)
                    av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                           "the file may be unplayable!\n");
            }
693
        } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) {
694
            tag = ff_codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
695
            if (!tag) { // if no mac fcc found, try with Microsoft tags
696
                int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->enc->codec_id);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
697 698 699 700
                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
701
                }
Baptiste Coudurier's avatar
Baptiste Coudurier committed
702
            }
703
        } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
704
            tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
705
    }
706

707 708 709
    return tag;
}

Baptiste Coudurier's avatar