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

28 29 30
#undef NDEBUG
#include <assert.h>

31 32 33
#define MOV_INDEX_CLUSTER_SIZE 16384
#define globalTimescale 1000

34 35 36
#define MODE_MP4 0
#define MODE_MOV 1
#define MODE_3GP 2
37
#define MODE_PSP 3 // example working PSP command line:
38
// ffmpeg -i testinput.avi  -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4
39
#define MODE_3G2 4
40
#define MODE_IPOD 5
41

42
typedef struct MOVIentry {
43 44
    unsigned int flags, size;
    uint64_t     pos;
45
    unsigned int samplesInChunk;
46
    char         key_frame;
47
    unsigned int entries;
48
    int64_t      cts;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
49
    int64_t      dts;
50 51 52
} MOVIentry;

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

    int         vosLen;
68
    uint8_t     *vosData;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
69
    MOVIentry   *cluster;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
70
    int         audio_vbr;
71 72
} MOVTrack;

73
typedef struct MOVContext {
74
    int     mode;
75
    int64_t time;
76
    int     nb_streams;
77
    offset_t mdat_pos;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
78
    uint64_t mdat_size;
79 80 81 82
    long    timescale;
    MOVTrack tracks[MAX_STREAMS];
} MOVContext;

Diego Biurrun's avatar
Diego Biurrun committed
83
//FIXME support 64 bit variant with wide placeholders
84
static offset_t updateSize (ByteIOContext *pb, offset_t pos)
85
{
86
    offset_t curpos = url_ftell(pb);
87
    url_fseek(pb, pos, SEEK_SET);
88
    put_be32(pb, curpos - pos); /* rewrite size */
89
    url_fseek(pb, curpos, SEEK_SET);
90 91

    return curpos - pos;
92 93
}

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

117
/* Sample size atom */
118
static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
119
{
120
    int equalChunks = 1;
121
    int i, j, entries = 0, tst = -1, oldtst = -1;
122

123
    offset_t pos = url_ftell(pb);
124
    put_be32(pb, 0); /* size */
125 126 127
    put_tag(pb, "stsz");
    put_be32(pb, 0); /* version & flags */

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

154
/* Sample to chunk atom */
155
static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
156
{
157 158
    int index = 0, oldval = -1, i;
    offset_t entryPos, curpos;
159

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

181
    return updateSize (pb, pos);
182 183
}

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

208
static int mov_write_amr_tag(ByteIOContext *pb, MOVTrack *track)
209 210
{
    put_be32(pb, 0x11); /* size */
211 212
    if (track->mode == MODE_MOV) put_tag(pb, "samr");
    else                         put_tag(pb, "damr");
213
    put_tag(pb, "FFMP");
214
    put_byte(pb, 0); /* decoder version */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
215

Baptiste Coudurier's avatar
Baptiste Coudurier committed
216
    put_be16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
217 218
    put_byte(pb, 0x00); /* Mode change period (no restriction) */
    put_byte(pb, 0x01); /* Frames per sample */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
219 220 221
    return 0x11;
}

222 223 224 225 226 227 228 229
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
230 231
static unsigned int descrLength(unsigned int len)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
232 233 234
    int i;
    for(i=1; len>>(7*i); i++);
    return len + 1 + i;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
235 236
}

Michael Niedermayer's avatar
Michael Niedermayer committed
237
static void putDescr(ByteIOContext *pb, int tag, unsigned int size)
Baptiste Coudurier's avatar
Baptiste Coudurier committed
238
{
Michael Niedermayer's avatar
Michael Niedermayer committed
239 240 241 242 243
    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
244 245 246 247 248
}

static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
{
    offset_t pos = url_ftell(pb);
249
    int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264

    put_be32(pb, 0);               // size
    put_tag(pb, "esds");
    put_be32(pb, 0);               // Version

    // ES descriptor
    putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
             descrLength(1));
    put_be16(pb, track->trackID);
    put_byte(pb, 0x00);            // flags (= no flags)

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

    // Object type indication
Baptiste Coudurier's avatar
Baptiste Coudurier committed
265
    put_byte(pb, codec_get_tag(ff_mp4_obj_type, track->enc->codec_id));
Baptiste Coudurier's avatar
Baptiste Coudurier committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

    // 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)
        put_byte(pb, 0x15);            // flags (= Audiostream)
    else
        put_byte(pb, 0x11);            // flags (= Visualstream)

    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

    put_be32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate));     // maxbitrate  (FIXME should be max rate in any 1 sec window)
    if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0)
        put_be32(pb, 0);     // vbr
    else
        put_be32(pb, track->enc->rc_max_rate);     // avg bitrate

    if (track->vosLen)
    {
        // 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);
    return updateSize (pb, pos);
}

297 298
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track)
{
299
    offset_t pos = url_ftell(pb);
300 301 302 303 304 305

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

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

308
    if (track->enc->codec_id == CODEC_ID_AAC) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
309 310 311 312
        /* useless atom needed by mplayer, ipod, not needed by quicktime */
        put_be32(pb, 12); /* size */
        put_tag(pb, "mp4a");
        put_be32(pb, 0);
313 314 315 316
        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
317
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
318
        mov_write_amr_tag(pb, track);
319
    }
320 321 322 323 324 325 326

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

    return updateSize (pb, pos);
}

327 328 329 330 331 332 333 334
static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack* track)
{
    put_be32(pb, track->vosLen+8);
    put_tag(pb, "glbl");
    put_buffer(pb, track->vosData, track->vosLen);
    return 8+track->vosLen;
}

335
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
336
{
337
    offset_t pos = url_ftell(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
338 339 340 341
    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);
342

343
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
344
    put_le32(pb, track->tag); // store it byteswapped
345 346 347
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
348

349
    /* SoundDescription */
350
    put_be16(pb, version); /* Version */
351
    put_be16(pb, 0); /* Revision level */
352 353
    put_be32(pb, 0); /* Reserved */

354 355
    if (track->mode == MODE_MOV) {
        put_be16(pb, track->enc->channels);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
356 357 358 359 360
        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);
361 362 363 364 365 366
        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);
    }
367

368
    put_be16(pb, 0); /* packet size (= 0) */
369 370 371
    put_be16(pb, track->timescale); /* Time scale */
    put_be16(pb, 0); /* Reserved */

372 373
    if(version == 1) { /* SoundDescription V1 extended info */
        put_be32(pb, track->enc->frame_size); /* Samples per packet */
374
        put_be32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
375
        put_be32(pb, track->sampleSize); /* Bytes per frame */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
376
        put_be32(pb, 2); /* Bytes per sample */
377 378
    }

379 380 381 382 383
    if(track->mode == MODE_MOV &&
       (track->enc->codec_id == CODEC_ID_AAC ||
        track->enc->codec_id == CODEC_ID_AMR_NB ||
        track->enc->codec_id == CODEC_ID_PCM_S24LE ||
        track->enc->codec_id == CODEC_ID_PCM_S32LE))
384
        mov_write_wave_tag(pb, track);
385
    else if(track->tag == MKTAG('m','p','4','a'))
Baptiste Coudurier's avatar
Baptiste Coudurier committed
386 387
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
388
        mov_write_amr_tag(pb, track);
389 390
    else if(track->vosLen > 0)
        mov_write_glbl_tag(pb, track);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
391

392
    return updateSize (pb, pos);
393 394
}

395
static int mov_write_d263_tag(ByteIOContext *pb)
396 397 398 399
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
400 401 402 403
    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 */
404 405 406
    return 0xf;
}

407 408
/* TODO: No idea about these values */
static int mov_write_svq3_tag(ByteIOContext *pb)
409
{
410 411 412 413 414 415
    put_be32(pb, 0x15);
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
    put_be32(pb, 0x5);
    put_be32(pb, 0xe2c0211d);
    put_be32(pb, 0xc0000000);
416
    put_byte(pb, 0);
417
    return 0x15;
418 419
}

420 421 422 423 424 425
static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
    offset_t pos = url_ftell(pb);

    put_be32(pb, 0);
    put_tag(pb, "avcC");
426
    ff_isom_write_avcc(pb, track->vosData, track->vosLen);
427 428 429
    return updateSize(pb, pos);
}

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
/* 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 */
464 465 466 467
        if (track->enc->height == 1080)
            put_be32(pb, 5); /* unknown */
        else
            put_be32(pb, 6); /* unknown */
468 469 470 471 472 473 474 475 476 477
    }
    /* padding */
    for (i = 0; i < 10; i++)
        put_be64(pb, 0);

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

478 479 480 481 482 483 484 485 486
static const AVCodecTag codec_3gp_tags[] = {
    { CODEC_ID_H263,   MKTAG('s','2','6','3') },
    { CODEC_ID_H264,   MKTAG('a','v','c','1') },
    { CODEC_ID_MPEG4,  MKTAG('m','p','4','v') },
    { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
    { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
    { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
};

Baptiste Coudurier's avatar
Baptiste Coudurier committed
487 488
static const AVCodecTag mov_pix_fmt_tags[] = {
    { PIX_FMT_YUYV422, MKTAG('y','u','v','s') },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
489
    { PIX_FMT_UYVY422, MKTAG('2','v','u','y') },
Baptiste Coudurier's avatar
Baptiste Coudurier committed
490 491 492 493 494
    { PIX_FMT_BGR555,  MKTAG('r','a','w',' ') },
    { PIX_FMT_RGB24,   MKTAG('r','a','w',' ') },
    { PIX_FMT_BGR32_1, MKTAG('r','a','w',' ') },
};

495
static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
496
{
Baptiste Coudurier's avatar
Baptiste Coudurier committed
497
    int tag = track->enc->codec_tag;
498
    if (track->mode == MODE_MP4 || track->mode == MODE_PSP || track->mode == MODE_IPOD) {
499 500 501 502 503 504 505
        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_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');
    } else if (track->mode == MODE_3GP || track->mode == MODE_3G2) {
        tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id);
506
    } else if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
Baptiste Coudurier's avatar
Baptiste Coudurier committed
507 508
                        (tag == MKTAG('d','v','c','p') ||
                         track->enc->codec_id == CODEC_ID_RAWVIDEO))) {
509
        if (track->enc->codec_id == CODEC_ID_DVVIDEO) {
510 511 512 513 514 515
            if (track->enc->height == 480) /* NTSC */
                if  (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
                else                                         tag = MKTAG('d','v','c',' ');
            else if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
            else if (track->enc->pix_fmt == PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
            else                                             tag = MKTAG('d','v','p','p');
Baptiste Coudurier's avatar
Baptiste Coudurier committed
516 517 518 519
        } else if (track->enc->codec_id == CODEC_ID_RAWVIDEO) {
            tag = codec_get_tag(mov_pix_fmt_tags, track->enc->pix_fmt);
            if (!tag) // restore tag
                tag = track->enc->codec_tag;
520
        } else {
521
            if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
522
                tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
523
                if (!tag) { // if no mac fcc found, try with Microsoft tags
Baptiste Coudurier's avatar
Baptiste Coudurier committed
524
                    tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
525 526 527
                    if (tag)
                        av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
                               "the file may be unplayable!\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
528
                }
529
            } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
530
                tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
531
                if (!tag) { // if no mac fcc found, try with Microsoft tags
Baptiste Coudurier's avatar
Baptiste Coudurier committed
532 533 534
                    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));
535 536
                        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
537 538
                    }
                }
539 540 541
            }
        }
    }
542 543 544
    return tag;
}

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
/** 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;
}

561
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
562
{
563
    offset_t pos = url_ftell(pb);
564
    char compressor_name[32];
565

566
    put_be32(pb, 0); /* size */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
567
    put_le32(pb, track->tag); // store it byteswapped
568 569 570 571
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

572 573
    put_be16(pb, 0); /* Codec stream version */
    put_be16(pb, 0); /* Codec stream revision (=0) */
574
    if (track->mode == MODE_MOV) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
575 576 577 578 579 580 581 582
        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 */
        }
583 584 585 586 587
    } else {
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
        put_be32(pb, 0); /* Reserved */
    }
588 589
    put_be16(pb, track->enc->width); /* Video width */
    put_be16(pb, track->enc->height); /* Video height */
590 591
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
592 593
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
594

595
    memset(compressor_name,0,32);
596 597
    /* 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)
598
        strncpy(compressor_name,track->enc->codec->name,31);
599
    put_byte(pb, strlen(compressor_name));
600
    put_buffer(pb, compressor_name, 31);
601

Baptiste Coudurier's avatar
Baptiste Coudurier committed
602 603 604 605
    if (track->mode == MODE_MOV && track->enc->bits_per_sample)
        put_be16(pb, track->enc->bits_per_sample);
    else
        put_be16(pb, 0x18); /* Reserved */
606
    put_be16(pb, 0xffff); /* Reserved */
607
    if(track->tag == MKTAG('m','p','4','v'))
608 609 610 611
        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)
612
        mov_write_svq3_tag(pb);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
613 614
    else if(track->enc->codec_id == CODEC_ID_DNXHD)
        mov_write_avid_tag(pb, track);
615
    else if(track->enc->codec_id == CODEC_ID_H264) {
616
        mov_write_avcc_tag(pb, track);
617 618
        if(track->mode == MODE_IPOD)
            mov_write_uuid_tag_ipod(pb);
619
    } else if(track->vosLen > 0)
620
        mov_write_glbl_tag(pb, track);
621 622

    return updateSize (pb, pos);
623 624
}

625
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
626
{
627
    offset_t pos = url_ftell(pb);
628 629 630 631
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
632 633 634 635
    if (track->enc->codec_type == CODEC_TYPE_VIDEO)
        mov_write_video_tag(pb, track);
    else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
        mov_write_audio_tag(pb, track);
636
    return updateSize(pb, pos);
637 638
}

639 640
static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack* track)
{
641
    MOV_stts_t *ctts_entries;
642 643 644 645 646 647
    uint32_t entries = 0;
    uint32_t atom_size;
    int i;

    ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */
    ctts_entries[0].count = 1;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
648
    ctts_entries[0].duration = track->cluster[0].cts;
649
    for (i=1; i<track->entry; i++) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
650
        if (track->cluster[i].cts == ctts_entries[entries].duration) {
651 652 653
            ctts_entries[entries].count++; /* compress */
        } else {
            entries++;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
654
            ctts_entries[entries].duration = track->cluster[i].cts;
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
            ctts_entries[entries].count = 1;
        }
    }
    entries++; /* last one */
    atom_size = 16 + (entries * 8);
    put_be32(pb, atom_size); /* size */
    put_tag(pb, "ctts");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, entries); /* entry count */
    for (i=0; i<entries; i++) {
        put_be32(pb, ctts_entries[i].count);
        put_be32(pb, ctts_entries[i].duration);
    }
    av_free(ctts_entries);
    return atom_size;
}

672
/* Time to sample atom */
673
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
674
{
675
    MOV_stts_t *stts_entries;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
    uint32_t entries = -1;
    uint32_t atom_size;
    int i;

    if (track->enc->codec_type == CODEC_TYPE_AUDIO && !track->audio_vbr) {
        stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
        stts_entries[0].count = track->sampleCount;
        stts_entries[0].duration = 1;
        entries = 1;
    } else {
        stts_entries = av_malloc(track->entry * sizeof(*stts_entries)); /* worst case */
        for (i=0; i<track->entry; i++) {
            int64_t duration = i + 1 == track->entry ?
                track->trackDuration - track->cluster[i].dts + track->cluster[0].dts : /* readjusting */
                track->cluster[i+1].dts - track->cluster[i].dts;
            if (i && duration == stts_entries[entries].duration) {
                stts_entries[entries].count++; /* compress */
            } else {
                entries++;
                stts_entries[entries].duration = duration;
                stts_entries[entries].count = 1;
            }
        }
        entries++; /* last one */
    }
    atom_size = 16 + (entries * 8);
    put_be32(pb, atom_size); /* size */
703 704
    put_tag(pb, "stts");
    put_be32(pb, 0); /* version & flags */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
705 706 707 708 709 710 711
    put_be32(pb, entries); /* entry count */
    for (i=0; i<entries; i++) {
        put_be32(pb, stts_entries[i].count);
        put_be32(pb, stts_entries[i].duration);
    }
    av_free(stts_entries);
    return atom_size;
712 713
}

714
static int mov_write_dref_tag(ByteIOContext *pb)
715 716 717 718 719 720 721 722 723 724 725 726 727
{
    put_be32(pb, 28); /* size */
    put_tag(pb, "dref");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */

    put_be32(pb, 0xc); /* size */
    put_tag(pb, "url ");
    put_be32(pb, 1); /* version & flags */

    return 28;
}

728
static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
729
{
730
    offset_t pos = url_ftell(pb);
731 732
    put_be32(pb, 0); /* size */
    put_tag(pb, "stbl");
733 734
    mov_write_stsd_tag(pb, track);
    mov_write_stts_tag(pb, track);
735
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
736
        track->hasKeyframes && track->hasKeyframes < track->entry)
737
        mov_write_stss_tag(pb, track);
738 739 740
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
        track->hasBframes)
        mov_write_ctts_tag(pb, track);
741 742 743 744
    mov_write_stsc_tag(pb, track);
    mov_write_stsz_tag(pb, track);
    mov_write_stco_tag(pb, track);
    return updateSize(pb, pos);
745 746
}

747
static int mov_write_dinf_tag(ByteIOContext *pb)
748
{
749
    offset_t pos = url_ftell(pb);
750 751
    put_be32(pb, 0); /* size */
    put_tag(pb, "dinf");
752 753
    mov_write_dref_tag(pb);
    return updateSize(pb, pos);
754 755
}

756
static int mov_write_smhd_tag(ByteIOContext *pb)
757 758 759 760 761 762 763 764 765
{
    put_be32(pb, 16); /* size */
    put_tag(pb, "smhd");
    put_be32(pb, 0); /* version & flags */
    put_be16(pb, 0); /* reserved (balance, normally = 0) */
    put_be16(pb, 0); /* reserved */
    return 16;
}

766
static int mov_write_vmhd_tag(ByteIOContext *pb)
767 768 769 770 771 772 773 774
{
    put_be32(pb, 0x14); /* size (always 0x14) */
    put_tag(pb, "vmhd");
    put_be32(pb, 0x01); /* version & flags */
    put_be64(pb, 0); /* reserved (graphics mode = copy) */
    return 0x14;
}

775
static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
776
{
777
    const char *descr, *hdlr, *hdlr_type;
778
    offset_t pos = url_ftell(pb);
779

780
    if (!track) { /* no media --> data handler */
781 782 783
        hdlr = "dhlr";
        hdlr_type = "url ";
        descr = "DataHandler";
784
    } else {
785 786 787 788 789 790 791 792
        hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
        if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
            hdlr_type = "vide";
            descr = "VideoHandler";
        } else {
            hdlr_type = "soun";
            descr = "SoundHandler";
        }
793
    }
794

795
    put_be32(pb, 0); /* size */
796 797
    put_tag(pb, "hdlr");
    put_be32(pb, 0); /* Version & flags */
798
    put_buffer(pb, hdlr, 4); /* handler */
799
    put_tag(pb, hdlr_type); /* handler type */
800 801 802
    put_be32(pb ,0); /* reserved */
    put_be32(pb ,0); /* reserved */
    put_be32(pb ,0); /* reserved */
803 804 805 806 807 808 809
    put_byte(pb, strlen(descr)); /* string counter */
    put_buffer(pb, descr, strlen(descr)); /* handler description */
    return updateSize(pb, pos);
}

static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
{
810
    offset_t pos = url_ftell(pb);
811 812
    put_be32(pb, 0); /* size */
    put_tag(pb, "minf");
813
    if(track->enc->codec_type == CODEC_TYPE_VIDEO)