movenc.c 52.9 KB
Newer Older
1 2 3
/*
 * MOV, 3GP, MP4 encoder.
 * Copyright (c) 2003 Thomas Raivio.
4
 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>.
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * 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
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 20
 */
#include "avformat.h"
21
#include "avi.h"
22
#include "avio.h"
23
#include "mov.h"
24

25 26 27
#undef NDEBUG
#include <assert.h>

28 29 30
#define MOV_INDEX_CLUSTER_SIZE 16384
#define globalTimescale 1000

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

38
typedef struct MOVIentry {
39 40
    unsigned int flags, size;
    uint64_t     pos;
41
    unsigned int samplesInChunk;
42
    char         key_frame;
43
    unsigned int entries;
44
    int64_t      cts;
45 46 47
} MOVIentry;

typedef struct MOVIndex {
48
    int         mode;
49 50 51 52
    int         entry;
    int         ents_allocated;
    long        timescale;
    long        time;
53
    int64_t     trackDuration;
54 55
    long        sampleCount;
    long        sampleDuration;
56
    int         hasKeyframes;
57
    int         hasBframes;
58
    int         language;
59
    int         trackID;
bcoudurier's avatar
bcoudurier committed
60
    int         tag;
61 62 63
    AVCodecContext *enc;

    int         vosLen;
64
    uint8_t     *vosData;
65 66 67
    MOVIentry** cluster;
} MOVTrack;

68
typedef struct MOVContext {
69
    int     mode;
70
    int64_t time;
71
    int     nb_streams;
72
    offset_t mdat_pos;
bcoudurier's avatar
bcoudurier committed
73
    uint64_t mdat_size;
74 75 76 77
    long    timescale;
    MOVTrack tracks[MAX_STREAMS];
} MOVContext;

78
//FIXME supprt 64bit varaint with wide placeholders
79
static offset_t updateSize (ByteIOContext *pb, offset_t pos)
80
{
81
    offset_t curpos = url_ftell(pb);
82
    url_fseek(pb, pos, SEEK_SET);
83
    put_be32(pb, curpos - pos); /* rewrite size */
84
    url_fseek(pb, curpos, SEEK_SET);
85 86

    return curpos - pos;
87 88
}

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

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

120
    offset_t pos = url_ftell(pb);
121
    put_be32(pb, 0); /* size */
122 123 124
    put_tag(pb, "stsz");
    put_be32(pb, 0); /* version & flags */

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

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

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

184
    return updateSize (pb, pos);
185 186
}

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

213
static int mov_write_damr_tag(ByteIOContext *pb)
214 215 216 217 218
{
    put_be32(pb, 0x11); /* size */
    put_tag(pb, "damr");
    put_tag(pb, "FFMP");
    put_byte(pb, 0);
219

220 221 222 223
    //put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */
    //put_be16(pb, 0xa); /* Mode change period (no restriction) */
    put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */
    put_be16(pb, 1); /* Mode change period (no restriction) */
224 225 226
    return 0x11;
}

bcoudurier's avatar
bcoudurier committed
227 228 229 230 231 232 233 234 235 236 237 238
static int mov_write_samr_tag(ByteIOContext *pb)
{
    put_be32(pb, 0x11); /* size */
    put_tag(pb, "samr");
    put_tag(pb, "FFMP");
    put_byte(pb, 1);

    put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */
    put_be16(pb, 0x5); /* Mode change period (no restriction) */
    return 0x11;
}

bcoudurier's avatar
bcoudurier committed
239 240 241 242 243 244 245 246
static int mov_write_enda_tag(ByteIOContext *pb)
{
    put_be32(pb, 10);
    put_tag(pb, "enda");
    put_be16(pb, 1); /* little endian */
    return 10;
}

bcoudurier's avatar
bcoudurier committed
247 248
static unsigned int descrLength(unsigned int len)
{
michael's avatar
michael committed
249 250 251
    int i;
    for(i=1; len>>(7*i); i++);
    return len + 1 + i;
bcoudurier's avatar
bcoudurier committed
252 253
}

michael's avatar
michael committed
254
static void putDescr(ByteIOContext *pb, int tag, unsigned int size)
bcoudurier's avatar
bcoudurier committed
255
{
michael's avatar
michael committed
256 257 258 259 260
    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);
bcoudurier's avatar
bcoudurier committed
261 262 263 264 265
}

static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
{
    offset_t pos = url_ftell(pb);
bcoudurier's avatar
bcoudurier committed
266
    int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
bcoudurier's avatar
bcoudurier committed
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 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

    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
    put_byte(pb, codec_get_tag(ff_mov_obj_type, track->enc->codec_id));

    // 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);
}

314 315
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track)
{
316
    offset_t pos = url_ftell(pb);
317 318 319 320 321 322

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

    put_be32(pb, 12);    /* size */
    put_tag(pb, "frma");
bcoudurier's avatar
bcoudurier committed
323
    put_le32(pb, track->tag);
324

bcoudurier's avatar
bcoudurier committed
325 326 327 328 329
    if (track->enc->codec_id == CODEC_ID_AAC) {
        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);
bcoudurier's avatar
bcoudurier committed
330 331
    } else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
        mov_write_samr_tag(pb);
bcoudurier's avatar
bcoudurier committed
332
    }
333 334 335 336 337 338 339

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

    return updateSize (pb, pos);
}

340
static const CodecTag codec_movaudio_tags[] = {
alex's avatar
alex committed
341 342 343 344 345 346 347
    { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') },
    { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') },
    { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') },
    { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') },
    { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') },
    { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
    { CODEC_ID_AMR_NB, MKTAG('s', 'a', 'm', 'r') },
348
    { CODEC_ID_AMR_WB, MKTAG('s', 'a', 'w', 'b') },
alex's avatar
alex committed
349 350
    { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') },
    { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') },
bcoudurier's avatar
bcoudurier committed
351 352 353 354
    { CODEC_ID_PCM_S24BE, MKTAG('i', 'n', '2', '4') },
    { CODEC_ID_PCM_S24LE, MKTAG('i', 'n', '2', '4') },
    { CODEC_ID_PCM_S32BE, MKTAG('i', 'n', '3', '2') },
    { CODEC_ID_PCM_S32LE, MKTAG('i', 'n', '3', '2') },
alex's avatar
alex committed
355
    { CODEC_ID_MP3, MKTAG('.', 'm', 'p', '3') },
356
    { CODEC_ID_NONE, 0 },
alex's avatar
alex committed
357 358
};

359
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
360
{
361
    offset_t pos = url_ftell(pb);
bcoudurier's avatar
bcoudurier committed
362 363
    int version = track->mode == MODE_MOV &&
        (track->enc->codec_id == CODEC_ID_AAC ||
bcoudurier's avatar
bcoudurier committed
364
         track->enc->codec_id == CODEC_ID_MP3 ||
bcoudurier's avatar
bcoudurier committed
365 366
         track->enc->codec_id == CODEC_ID_PCM_S32LE ||
         track->enc->codec_id == CODEC_ID_PCM_S24LE);
367

368
    put_be32(pb, 0); /* size */
bcoudurier's avatar
bcoudurier committed
369
    put_le32(pb, track->tag); // store it byteswapped
370 371 372
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
373

374
    /* SoundDescription */
bcoudurier's avatar
bcoudurier committed
375
    put_be16(pb, version); /* Version */
376
    put_be16(pb, 0); /* Revision level */
377 378
    put_be32(pb, 0); /* Reserved */

379 380
    put_be16(pb, track->enc->channels); /* Number of channels */
    /* TODO: Currently hard-coded to 16-bit, there doesn't seem
381
                 to be a good way to get number of bits of audio */
382
    put_be16(pb, 0x10); /* Reserved */
383 384

    if(track->enc->codec_id == CODEC_ID_AAC ||
bcoudurier's avatar
bcoudurier committed
385 386
       track->enc->codec_id == CODEC_ID_MP3 ||
       track->enc->codec_id == CODEC_ID_AMR_NB) {
387
        put_be16(pb, 0xfffe); /* compression ID (vbr)*/
bcoudurier's avatar
bcoudurier committed
388
    } else {
389 390
        put_be16(pb, 0); /* compression ID (= 0) */
    }
romansh's avatar
 
romansh committed
391
    put_be16(pb, 0); /* packet size (= 0) */
392 393 394
    put_be16(pb, track->timescale); /* Time scale */
    put_be16(pb, 0); /* Reserved */

bcoudurier's avatar
bcoudurier committed
395
    if(version == 1) {
396 397
        /* SoundDescription V1 extended info */
        put_be32(pb, track->enc->frame_size); /* Samples per packet  */
bcoudurier's avatar
bcoudurier committed
398 399
        put_be32(pb, track->sampleDuration); /* Bytes per frame */
        put_be32(pb, 8); /* Bytes per sample */
bcoudurier's avatar
bcoudurier committed
400
        put_be32(pb, 2);
401 402
    }

bcoudurier's avatar
bcoudurier committed
403 404 405 406 407
    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))
bcoudurier's avatar
bcoudurier committed
408
        mov_write_wave_tag(pb, track);
bcoudurier's avatar
bcoudurier committed
409 410 411 412 413
    else if(track->enc->codec_id == CODEC_ID_AAC)
        mov_write_esds_tag(pb, track);
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
        mov_write_damr_tag(pb);

414
    return updateSize (pb, pos);
415 416
}

417
static int mov_write_d263_tag(ByteIOContext *pb)
418 419 420 421 422 423 424 425 426
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
    put_be16(pb, 0x0a);
    put_byte(pb, 0);
    return 0xf;
}

427 428
/* TODO: No idea about these values */
static int mov_write_svq3_tag(ByteIOContext *pb)
429
{
430 431 432 433 434 435
    put_be32(pb, 0x15);
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
    put_be32(pb, 0x5);
    put_be32(pb, 0xe2c0211d);
    put_be32(pb, 0xc0000000);
436
    put_byte(pb, 0);
437
    return 0x15;
438 439
}

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
static uint8_t *avc_find_startcode( uint8_t *p, uint8_t *end )
{
    uint8_t *a = p + 4 - ((int)p & 3);

    for( end -= 3; p < a && p < end; p++ ) {
        if( p[0] == 0 && p[1] == 0 && p[2] == 1 )
            return p;
    }

    for( end -= 3; p < end; p += 4 ) {
        uint32_t x = *(uint32_t*)p;
//      if( (x - 0x01000100) & (~x) & 0x80008000 ) // little endian
//      if( (x - 0x00010001) & (~x) & 0x00800080 ) // big endian
        if( (x - 0x01010101) & (~x) & 0x80808080 ) { // generic
            if( p[1] == 0 ) {
                if( p[0] == 0 && p[2] == 1 )
bcoudurier's avatar
bcoudurier committed
456
                    return p-1;
457
                if( p[2] == 0 && p[3] == 1 )
bcoudurier's avatar
bcoudurier committed
458
                    return p;
459 460 461
            }
            if( p[3] == 0 ) {
                if( p[2] == 0 && p[4] == 1 )
bcoudurier's avatar
bcoudurier committed
462
                    return p+1;
463
                if( p[4] == 0 && p[5] == 1 )
bcoudurier's avatar
bcoudurier committed
464
                    return p+2;
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
            }
        }
    }

    for( end += 3; p < end; p++ ) {
        if( p[0] == 0 && p[1] == 0 && p[2] == 1 )
            return p;
    }

    return end + 3;
}

static void avc_parse_nal_units(uint8_t **buf, int *size)
{
    ByteIOContext pb;
    uint8_t *p = *buf;
    uint8_t *end = p + *size;
    uint8_t *nal_start, *nal_end;

    url_open_dyn_buf(&pb);
    nal_start = avc_find_startcode(p, end);
    while (nal_start < end) {
        while(!*(nal_start++));
        nal_end = avc_find_startcode(nal_start, end);
        put_be32(&pb, nal_end - nal_start);
        put_buffer(&pb, nal_start, nal_end - nal_start);
        nal_start = nal_end;
    }
    av_freep(buf);
    *size = url_close_dyn_buf(&pb, buf);
}

static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
{
    offset_t pos = url_ftell(pb);

    put_be32(pb, 0);
    put_tag(pb, "avcC");
    if (track->vosLen > 6) {
        /* check for h264 start code */
        if (BE_32(track->vosData) == 0x00000001) {
            uint8_t *buf, *end;
            uint32_t sps_size=0, pps_size=0;
            uint8_t *sps=0, *pps=0;

            avc_parse_nal_units(&track->vosData, &track->vosLen);
            buf = track->vosData;
            end = track->vosData + track->vosLen;

            /* look for sps and pps */
            while (buf < end) {
                unsigned int size;
                uint8_t nal_type;
                size = BE_32(buf);
                nal_type = buf[4] & 0x1f;
                if (nal_type == 7) { /* SPS */
                    sps = buf + 4;
                    sps_size = size;
                } else if (nal_type == 8) { /* PPS */
                    pps = buf + 4;
                    pps_size = size;
                }
                buf += size + 4;
            }
            assert(sps);
            assert(pps);
531 532 533 534 535 536 537 538

            put_byte(pb, 1); /* version */
            put_byte(pb, sps[1]); /* profile */
            put_byte(pb, sps[2]); /* profile compat */
            put_byte(pb, sps[3]); /* level */
            put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
            put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */

539 540 541 542 543 544 545 546 547 548 549 550
            put_be16(pb, sps_size);
            put_buffer(pb, sps, sps_size);
            put_byte(pb, 1); /* number of pps */
            put_be16(pb, pps_size);
            put_buffer(pb, pps, pps_size);
        } else {
            put_buffer(pb, track->vosData, track->vosLen);
        }
    }
    return updateSize(pb, pos);
}

551
static const CodecTag codec_movvideo_tags[] = {
alex's avatar
alex committed
552 553 554 555
    { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') },
    { CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') },
    { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
    { CODEC_ID_H263, MKTAG('s', '2', '6', '3') },
556
    { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
557 558 559 560 561 562 563
    /* special handling in mov_find_video_codec_tag */
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'p', 'p') }, /* DVCPRO PAL */
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'n') }, /* DVCPRO50 NTSC */
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'p') }, /* DVCPRO50 PAL */
    { CODEC_ID_NONE, 0 },
alex's avatar
alex committed
564 565
};

bcoudurier's avatar
bcoudurier committed
566
static int mov_find_video_codec_tag(AVFormatContext *s, MOVTrack *track)
567
{
bcoudurier's avatar
bcoudurier committed
568
    int tag = track->enc->codec_tag;
569 570 571 572 573 574 575 576 577 578 579 580
    if (!tag) {
        if (track->enc->codec_id == CODEC_ID_DVVIDEO) {
            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 { /* assume PAL */
                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');
bcoudurier's avatar
bcoudurier committed
581 582
                else
                    tag = MKTAG('d', 'v', 'p', 'p');
583 584 585 586 587 588
            }
        } else {
            tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
        }
    }
    // if no mac fcc found, try with Microsoft tags
bcoudurier's avatar
bcoudurier committed
589
    if (!tag) {
590
        tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
bcoudurier's avatar
bcoudurier committed
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
        if (tag) {
            av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, the file may be unplayable!\n");
        }
    }
    assert(tag);
    return tag;
}

static int mov_find_audio_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag = track->enc->codec_tag;
    if (!tag) {
        tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
    }
    // if no mac fcc found, try with Microsoft tags
    if (!tag) {
        int ms_tag = codec_get_tag(codec_wav_tags, track->enc->codec_id);
        if (ms_tag) {
            tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
            av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, the file may be unplayable!\n");
        }
    }
613 614 615 616
    assert(tag);
    return tag;
}

617
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
618
{
619
    offset_t pos = url_ftell(pb);
620
    char compressor_name[32];
alex's avatar
alex committed
621

622
    put_be32(pb, 0); /* size */
bcoudurier's avatar
bcoudurier committed
623
    put_le32(pb, track->tag); // store it byteswapped
624 625 626 627
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

628 629 630 631 632 633 634 635 636 637
    put_be16(pb, 0); /* Codec stream version */
    put_be16(pb, 0); /* Codec stream revision (=0) */
    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 */
    }
638 639
    put_be16(pb, track->enc->width); /* Video width */
    put_be16(pb, track->enc->height); /* Video height */
640 641
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
romansh's avatar
 
romansh committed
642 643
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
644

645
    memset(compressor_name,0,32);
646
    if (track->enc->codec && track->enc->codec->name)
647
        strncpy(compressor_name,track->enc->codec->name,31);
648
    put_byte(pb, strlen(compressor_name));
649
    put_buffer(pb, compressor_name, 31);
650

651 652 653 654 655 656 657
    put_be16(pb, 0x18); /* Reserved */
    put_be16(pb, 0xffff); /* Reserved */
    if(track->enc->codec_id == CODEC_ID_MPEG4)
        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)
658
        mov_write_svq3_tag(pb);
659 660
    else if(track->enc->codec_id == CODEC_ID_H264)
        mov_write_avcc_tag(pb, track);
661 662

    return updateSize (pb, pos);
663 664
}

665
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
666
{
667
    offset_t pos = url_ftell(pb);
668 669 670 671
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
672 673 674 675
    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);
676
    return updateSize(pb, pos);
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 703 704 705 706 707 708 709 710 711 712 713
static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack* track)
{
    Time2Sample *ctts_entries;
    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;
    ctts_entries[0].duration = track->cluster[0][0].cts;
    for (i=1; i<track->entry; i++) {
        int cl = i / MOV_INDEX_CLUSTER_SIZE;
        int id = i % MOV_INDEX_CLUSTER_SIZE;
        if (track->cluster[cl][id].cts == ctts_entries[entries].duration) {
            ctts_entries[entries].count++; /* compress */
        } else {
            entries++;
            ctts_entries[entries].duration = track->cluster[cl][id].cts;
            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;
}

michael's avatar
michael committed
714
/* TODO: */
715
/* Time to sample atom */
716
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
717 718 719 720 721 722
{
    put_be32(pb, 0x18); /* size */
    put_tag(pb, "stts");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */

723 724
    put_be32(pb, track->sampleCount); /* sample count */
    put_be32(pb, track->sampleDuration); /* sample duration */
725 726 727
    return 0x18;
}

728
static int mov_write_dref_tag(ByteIOContext *pb)
729 730 731 732 733 734 735 736 737 738 739 740 741
{
    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;
}

742
static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
743
{
744
    offset_t pos = url_ftell(pb);
745 746
    put_be32(pb, 0); /* size */
    put_tag(pb, "stbl");
747 748
    mov_write_stsd_tag(pb, track);
    mov_write_stts_tag(pb, track);
749
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
750
        track->hasKeyframes < track->entry)
751
        mov_write_stss_tag(pb, track);
752 753 754
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
        track->hasBframes)
        mov_write_ctts_tag(pb, track);
755 756 757 758
    mov_write_stsc_tag(pb, track);
    mov_write_stsz_tag(pb, track);
    mov_write_stco_tag(pb, track);
    return updateSize(pb, pos);
759 760
}

761
static int mov_write_dinf_tag(ByteIOContext *pb)
762
{
763
    offset_t pos = url_ftell(pb);
764 765
    put_be32(pb, 0); /* size */
    put_tag(pb, "dinf");
766 767
    mov_write_dref_tag(pb);
    return updateSize(pb, pos);
768 769
}

770
static int mov_write_smhd_tag(ByteIOContext *pb)
771 772 773 774 775 776 777 778 779
{
    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;
}

780
static int mov_write_vmhd_tag(ByteIOContext *pb)
781 782 783 784 785 786 787 788
{
    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;
}

789
static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
790
{
romansh's avatar
 
romansh committed
791
    char *descr, *hdlr, *hdlr_type;
792
    offset_t pos = url_ftell(pb);
793

romansh's avatar
 
romansh committed
794
    if (!track) { /* no media --> data handler */
795 796 797
        hdlr = "dhlr";
        hdlr_type = "url ";
        descr = "DataHandler";
romansh's avatar
 
romansh committed
798
    } else {
799 800 801 802 803 804 805 806
        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";
        }
romansh's avatar
 
romansh committed
807
    }
808

809
    put_be32(pb, 0); /* size */
810 811
    put_tag(pb, "hdlr");
    put_be32(pb, 0); /* Version & flags */
romansh's avatar
 
romansh committed
812
    put_buffer(pb, hdlr, 4); /* handler */
romansh's avatar
 
romansh committed
813
    put_tag(pb, hdlr_type); /* handler type */
814 815 816
    put_be32(pb ,0); /* reserved */
    put_be32(pb ,0); /* reserved */
    put_be32(pb ,0); /* reserved */
romansh's avatar
 
romansh committed
817 818 819 820 821 822 823
    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)
{
824
    offset_t pos = url_ftell(pb);
romansh's avatar
 
romansh committed
825 826
    put_be32(pb, 0); /* size */
    put_tag(pb, "minf");
827
    if(track->enc->codec_type == CODEC_TYPE_VIDEO)
romansh's avatar
 
romansh committed
828
        mov_write_vmhd_tag(pb);
829
    else
romansh's avatar
 
romansh committed
830 831 832 833 834
        mov_write_smhd_tag(pb);
    if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
        mov_write_hdlr_tag(pb, NULL);
    mov_write_dinf_tag(pb);
    mov_write_stbl_tag(pb, track);
835
    return updateSize(pb, pos);
836 837
}

838
static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
839
{
840 841 842
    int version = track->trackDuration < INT32_MAX ? 0 : 1;

    (version == 1) ? put_be32(pb, 44) : put_be32(pb, 32); /* size */
843
    put_tag(pb, "mdhd");
844 845 846 847 848 849 850 851 852
    put_byte(pb, version);
    put_be24(pb, 0); /* flags */
    if (version == 1) {
        put_be64(pb, track->time);
        put_be64(pb, track->time);
    } else {
        put_be32(pb, track->time); /* creation time */
        put_be32(pb, track->time); /* modification time */
    }
853
    put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
854
    (version == 1) ? put_be64(pb, track->trackDuration) : put_be32(pb, track->trackDuration); /* duration */
855
    put_be16(pb, track->language); /* language */
856 857 858 859
    put_be16(pb, 0); /* reserved (quality) */
    return 32;
}

860
static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
861
{
862
    offset_t pos = url_ftell(pb);
863 864
    put_be32(pb, 0); /* size */
    put_tag(pb, "mdia");
865 866 867 868
    mov_write_mdhd_tag(pb, track);
    mov_write_hdlr_tag(pb, track);
    mov_write_minf_tag(pb, track);
    return updateSize(pb, pos);
869 870
}

871
static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
872
{
873 874 875 876
    int64_t duration = av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP);
    int version = duration < INT32_MAX ? 0 : 1;

    (version == 1) ? put_be32(pb, 104) : put_be32(pb, 92); /* size */
877
    put_tag(pb, "tkhd");
878 879 880 881 882 883 884 885 886
    put_byte(pb, version);
    put_be24(pb, 0xf); /* flags (track enabled) */
    if (version == 1) {
        put_be64(pb, track->time);
        put_be64(pb, track->time);
    } else {
        put_be32(pb, track->time); /* creation time */
        put_be32(pb, track->time); /* modification time */
    }
887 888
    put_be32(pb, track->trackID); /* track-id */
    put_be32(pb, 0); /* reserved */
889
    (version == 1) ? put_be64(pb, duration) : put_be32(pb, duration);
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913

    put_be32(pb, 0); /* reserved */
    put_be32(pb, 0); /* reserved */
    put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
    /* Volume, only for audio */
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
        put_be16(pb, 0x0100);
    else
        put_be16(pb, 0);
    put_be16(pb, 0); /* reserved */

    /* Matrix structure */
    put_be32(pb, 0x00010000); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x00010000); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x40000000); /* reserved */

    /* Track width and height, for visual only */
    if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
914 915 916
        double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio);
        if( !sample_aspect_ratio ) sample_aspect_ratio = 1;
        put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
917
        put_be32(pb, track->enc->height*0x10000);
918 919 920 921 922 923 924 925
    }
    else {
        put_be32(pb, 0);
        put_be32(pb, 0);
    }
    return 0x5c;
}

926 927 928 929 930 931 932 933 934 935
// This box seems important for the psp playback ... without it the movie seems to hang
static int mov_write_edts_tag(ByteIOContext *pb, MOVTrack *track)
{
    put_be32(pb, 0x24); /* size  */
    put_tag(pb, "edts");
    put_be32(pb, 0x1c); /* size  */
    put_tag(pb, "elst");
    put_be32(pb, 0x0);
    put_be32(pb, 0x1);

michael's avatar
michael committed
936
    put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration   ... doesn't seem to effect psp */
937

938 939 940 941
    if (track->hasBframes)
        put_be32(pb, track->sampleDuration); /* first pts is 1 */
    else
        put_be32(pb, 0);
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
    put_be32(pb, 0x00010000);
    return 0x24;
}

// goes at the end of each track!  ... Critical for PSP playback ("Incompatible data" without it)
static int mov_write_uuid_tag_psp(ByteIOContext *pb, MOVTrack *mov)
{
    put_be32(pb, 0x34); /* size ... reports as 28 in mp4box! */
    put_tag(pb, "uuid");
    put_tag(pb, "USMT");
    put_be32(pb, 0x21d24fce);
    put_be32(pb, 0xbb88695c);
    put_be32(pb, 0xfac9c740);
    put_be32(pb, 0x1c);     // another size here!
    put_tag(pb, "MTDT");
    put_be32(pb, 0x00010012);
    put_be32(pb, 0x0a);
    put_be32(pb, 0x55c40000);
    put_be32(pb, 0x1);
    put_be32(pb, 0x0);
    return 0x34;
}

965
static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
966
{
967
    offset_t pos = url_ftell(pb);
968 969
    put_be32(pb, 0); /* size */
    put_tag(pb, "trak");
970
    mov_write_tkhd_tag(pb, track);
971
    if (track->mode == MODE_PSP || track->hasBframes)
972
        mov_write_edts_tag(pb, track);  // PSP Movies require edts box
973
    mov_write_mdia_tag(pb, track);
974
    if (track->mode == MODE_PSP)
975
        mov_write_uuid_tag_psp(pb,track);  // PSP Movies require this uuid box
976
    return updateSize(pb, pos);
977 978
}

979
#if 0
980
/* TODO: Not sorted out, but not necessary either */
981
static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
982 983 984 985 986 987 988 989 990 991 992
{
    put_be32(pb, 0x15); /* size */
    put_tag(pb, "iods");
    put_be32(pb, 0);    /* version & flags */
    put_be16(pb, 0x1007);
    put_byte(pb, 0);
    put_be16(pb, 0x4fff);
    put_be16(pb, 0xfffe);
    put_be16(pb, 0x01ff);
    return 0x15;
}
993
#endif
994

995
static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
996
{
997 998
    int maxTrackID = 1, i;
    int64_t maxTrackLenTemp, maxTrackLen = 0;
999
    int version;
1000 1001 1002

    for (i=0; i<MAX_STREAMS; i++) {
        if(mov->tracks[i].entry > 0) {
michael's avatar
michael committed
1003
            maxTrackLenTemp = av_rescale_rnd(mov->tracks[i].trackDuration, globalTimescale, mov->tracks[i].timescale, AV_ROUND_UP);
1004 1005
            if(maxTrackLen < maxTrackLenTemp)
                maxTrackLen = maxTrackLenTemp;
1006 1007 1008 1009
            if(maxTrackID < mov->tracks[i].trackID)
                maxTrackID = mov->tracks[i].trackID;
        }
    }
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024

    version = maxTrackLen < UINT32_MAX ? 0 : 1;
    (version == 1) ? put_be32(pb, 120) : put_be32(pb, 108); /* size */
    put_tag(pb, "mvhd");
    put_byte(pb, version);
    put_be24(pb, 0); /* flags */
    if (version == 1) {
        put_be64(pb, mov->time);
        put_be64(pb, mov->time);
    } else {
        put_be32(pb, mov->time); /* creation time */
        put_be32(pb, mov->time); /* modification time */
    }
    put_be32(pb, mov->timescale); /* timescale */
    (version == 1) ? put_be64(pb, maxTrackLen) : put_be32(pb, maxTrackLen); /* duration of longest track */
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052

    put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
    put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
    put_be16(pb, 0); /* reserved */
    put_be32(pb, 0); /* reserved */
    put_be32(pb, 0); /* reserved */

    /* Matrix structure */
    put_be32(pb, 0x00010000); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x00010000); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x0); /* reserved */
    put_be32(pb, 0x40000000); /* reserved */

    put_be32(pb, 0); /* reserved (preview time) */
    put_be32(pb, 0); /* reserved (preview duration) */
    put_be32(pb, 0); /* reserved (poster time) */
    put_be32(pb, 0); /* reserved (selection time) */
    put_be32(pb, 0); /* reserved (selection duration) */
    put_be32(pb, 0); /* reserved (current time) */
    put_be32(pb, maxTrackID+1); /* Next track id */
    return 0x6c;
}

1053 1054 1055
static int mov_write_itunes_hdlr_tag(ByteIOContext *pb, MOVContext* mov,
                                     AVFormatContext *s)
{
1056
    offset_t pos = url_ftell(pb);
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
    put_be32(pb, 0); /* size */
    put_tag(pb, "hdlr");
    put_be32(pb, 0);
    put_be32(pb, 0);
    put_tag(pb, "mdir");
    put_tag(pb, "appl");
    put_be32(pb, 0);
    put_be32(pb, 0);
    put_be16(pb, 0);
    return updateSize(pb, pos);
}

/* helper function to write a data tag with the specified string as data */
michael's avatar
michael committed
1070
static int mov_write_string_data_tag(ByteIOContext *pb, const char *data, int long_style)
1071
{
michael's avatar
michael committed
1072
    if(long_style){
1073
        offset_t pos = url_ftell(pb);
1074
        put_be32(pb, 0); /* size */
michael's avatar
michael committed
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
        put_tag(pb, "data");
        put_be32(pb, 1);
        put_be32(pb, 0);
        put_buffer(pb, data, strlen(data));
        return updateSize(pb, pos);
    }else{
        put_be16(pb, strlen(data)); /* string length */
        put_be16(pb, 0);
        put_buffer(pb, data, strlen(data));
        return strlen(data) + 4;
1085 1086 1087
    }
}

michael's avatar
michael committed
1088
static int mov_write_string_tag(ByteIOContext *pb, char *name, char *value, int long_style){
1089
    int size = 0;
michael's avatar
michael committed
1090
    if ( value && value[0] ) {
1091
        offset_t pos = url_ftell(pb);
1092
        put_be32(pb, 0); /* size */
michael's avatar
michael committed
1093 1094 1095
        put_tag(pb, name);
        mov_write_string_data_tag(pb, value, long_style);
        size= updateSize(pb, pos);
1096 1097 1098 1099 1100
    }
    return size;
}

/* iTunes year */
michael's avatar
michael committed
1101
static int mov_write_day_tag(ByteIOContext *pb, int year, int long_style)
1102
{
michael's avatar
michael committed
1103 1104 1105 1106 1107 1108
    if(year){
        char year_str[5];
        snprintf(year_str, sizeof(year_str), "%04d", year);
        return mov_write_string_tag(pb, "\251day", year_str, long_style);
    }else
        return 0;
1109 1110 1111 1112 1113 1114 1115 1116
}

/* iTunes track number */
static int mov_write_trkn_tag(ByteIOContext *pb, MOVContext* mov,
                              AVFormatContext *s)
{
    int size = 0;
    if ( s->track ) {
1117
        offset_t pos = url_ftell(pb);
1118 1119 1120
        put_be32(pb, 0); /* size */
        put_tag(pb, "trkn");
        {
1121
            offset_t pos = url_ftell(pb);
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
            put_be32(pb, 0); /* size */
            put_tag(pb, "data");
            put_be32(pb, 0);        // 8 bytes empty
            put_be32(pb, 0);
            put_be16(pb, 0);        // empty
            put_be16(pb, s->track); // track number
            put_be16(pb, 0);        // total track number
            put_be16(pb, 0);        // empty
            updateSize(pb, pos);
        }
        size = updateSize(pb, pos);
    }
    return size;
}

/* iTunes meta data list */
static int mov_write_ilst_tag(ByteIOContext *pb, MOVContext* mov,
                              AVFormatContext *s)
{
1141
    offset_t pos = url_ftell(pb);
1142 1143
    put_be32(pb, 0); /* size */
    put_tag(pb, "ilst");
michael's avatar
michael committed
1144 1145 1146 1147 1148
    mov_write_string_tag(pb, "\251nam", s->title         , 1);
    mov_write_string_tag(pb, "\251ART", s->author        , 1);
    mov_write_string_tag(pb, "\251wrt", s->author        , 1);
    mov_write_string_tag(pb, "\251alb", s->album         , 1);
    mov_write_day_tag(pb, s->year ,1);
1149 1150
    if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT))
        mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 1);
michael's avatar
michael committed
1151 1152
    mov_write_string_tag(pb, "\251cmt", s->comment       , 1);
    mov_write_string_tag(pb, "\251gen", s->genre         , 1);
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
    mov_write_trkn_tag(pb, mov, s);
    return updateSize(pb, pos);
}

/* iTunes meta data tag */
static int mov_write_meta_tag(ByteIOContext *pb, MOVContext* mov,
                              AVFormatContext *s)
{
    int size = 0;

    // only save meta tag if required
1164
    if ( s->title[0] || s->author[0] || s->album[0] || s->year ||
1165
         s->comment[0] || s->genre[0] || s->track ) {
1166
        offset_t pos = url_ftell(pb);
1167 1168 1169 1170 1171 1172 1173 1174 1175
        put_be32(pb, 0); /* size */
        put_tag(pb, "meta");
        put_be32(pb, 0);
        mov_write_itunes_hdlr_tag(pb, mov, s);
        mov_write_ilst_tag(pb, mov, s);
        size = updateSize(pb, pos);
    }
    return size;
}
1176

1177 1178 1179
static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov,
                              AVFormatContext *s)
{
1180
    offset_t pos = url_ftell(pb);
1181 1182 1183 1184 1185
    int i;

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

1186 1187 1188
    /* iTunes meta data */
    mov_write_meta_tag(pb, mov, s);

1189
  if(mov->mode == MODE_MOV){ // the title field breaks gtkpod with mp4 and my suspicion is that stuff isnt valid in mp4
1190 1191 1192 1193 1194
    /* Requirements */
    for (i=0; i<MAX_STREAMS; i++) {
        if(mov->tracks[i].entry <= 0) continue;
        if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC ||
            mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) {
michael's avatar
michael committed
1195
            mov_write_string_tag(pb, "\251req", "QuickTime 6.0 or greater", 0);
1196 1197 1198 1199
            break;
        }
    }

michael's avatar
michael committed
1200 1201 1202 1203
    mov_write_string_tag(pb, "\251nam", s->title         , 0);
    mov_write_string_tag(pb, "\251aut", s->author        , 0);
    mov_write_string_tag(pb, "\251alb", s->album         , 0);
    mov_write_day_tag(pb, s->year, 0);
1204
    if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT))
michael's avatar
michael committed
1205 1206 1207
        mov_write_string_tag(pb, "\251enc", LIBAVFORMAT_IDENT, 0);
    mov_write_string_tag(pb, "\251des", s->comment       , 0);
    mov_write_string_tag(pb, "\251gen", s->genre         , 0);
1208
  }
1209 1210 1211 1212

    return updateSize(pb, pos);
}

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229

static size_t ascii_to_wc (ByteIOContext *pb, char *b, size_t n)
{
    size_t i;
    unsigned char c;
    for (i = 0; i < n - 1; i++) {
        c = b[i];
        if (! (0x20 <= c && c <= 0x7f ))
            c = 0x3f;  /* '?' */
        put_be16(pb, c);
    }
    put_be16(pb, 0x00);
    return 2*n;
}

static uint16_t language_code (char *str)
{
1230
    return ((((str[0]-0x60) & 0x1F)<<10) + (((str[1]-0x60) & 0x1F)<<5) + ((str[2]-0x60) & 0x1F));
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
}

static int mov_write_uuidusmt_tag (ByteIOContext *pb, AVFormatContext *s)
{
    size_t len, size;
    offset_t pos, curpos;

    size = 0;
    if (s->title[0]) {
        pos = url_ftell(pb);
        put_be32(pb, 0); /* size placeholder*/
        put_tag(pb, "uuid");
        put_tag(pb, "USMT");
        put_be32(pb, 0x21d24fce ); /* 96 bit UUID */
        put_be32(pb, 0xbb88695c );
        put_be32(pb, 0xfac9c740 );
        size += 24;

        put_be32(pb, 0); /* size placeholder*/
        put_tag(pb, "MTDT");
1251
        put_be16(pb, 4);
1252 1253
        size += 10;

1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
        // ?
        put_be16(pb, 0x0C);                 /* size */
        put_be32(pb, 0x0B);                 /* type */
        put_be16(pb, language_code("und")); /* language */
        put_be16(pb, 0x0);                  /* ? */
        put_be16(pb, 0x021C);               /* data */
        size += 12;

        // Encoder
        len = strlen(LIBAVCODEC_IDENT)+1;
        put_be16(pb, len*2+10);             /* size */
        put_be32(pb, 0x04);                 /* type */
        put_be16(pb, language_code("eng")); /* language */
        put_be16(pb, 0x01);                 /* ? */
        ascii_to_wc(pb, LIBAVCODEC_IDENT, len);
        size += len*2+10;

1271 1272 1273 1274
        // Title
        len = strlen(s->title)+1;
        put_be16(pb, len*2+10);             /* size */
        put_be32(pb, 0x01);                 /* type */
1275
        put_be16(pb, language_code("eng")); /* language */
1276 1277 1278 1279
        put_be16(pb, 0x01);                 /* ? */
        ascii_to_wc (pb, s->title, len);
        size += len*2+10;

1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
        // Date
//        snprintf(dt,32,"%04d/%02d/%02d %02d:%02d:%02d",t_st->tm_year+1900,t_st->tm_mon+1,t_st->tm_mday,t_st->tm_hour,t_st->tm_min,t_st->tm_sec);
        len = strlen("2006/04/01 11:11:11")+1;
        put_be16(pb, len*2+10);    /* size */
        put_be32(pb, 0x03);        /* type */
        put_be16(pb, language_code("und")); /* language */
        put_be16(pb, 0x01);        /* ? */
        ascii_to_wc (pb, "2006/04/01 11:11:11", len);
        size += len*2+10;

1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301
        // size
        curpos = url_ftell(pb);
        url_fseek(pb, pos, SEEK_SET);
        put_be32(pb, size);
        url_fseek(pb, pos+24, SEEK_SET);
        put_be32(pb, size-24);
        url_fseek(pb, curpos, SEEK_SET);
    }

    return size;
}

1302 1303
static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov,
                              AVFormatContext *s)
1304
{
1305 1306
    int i;
    offset_t pos = url_ftell(pb);
1307 1308 1309 1310 1311
    put_be32(pb, 0); /* size placeholder*/
    put_tag(pb, "moov");
    mov->timescale = globalTimescale;

    for (i=0; i<MAX_STREAMS; i++) {
1312 1313 1314
        if(mov->tracks[i].entry <= 0) continue;

        if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
michael's avatar
michael committed
1315 1316
            mov->tracks[i].timescale = mov->tracks[i].enc->time_base.den;
            mov->tracks[i].sampleDuration = mov->tracks[i].enc->time_base.num;
1317 1318 1319
        } else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
            mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
            mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size;
1320
        }
1321

1322
        mov->tracks[i].trackDuration =
1323
            (int64_t)mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration;
1324 1325
        mov->tracks[i].time = mov->time;
        mov->tracks[i].trackID = i+1;
1326 1327
    }

1328 1329
    mov_write_mvhd_tag(pb, mov);
    //mov_write_iods_tag(pb, mov);
1330 1331
    for (i=0; i<MAX_STREAMS; i++) {
        if(mov->tracks[i].entry > 0) {
1332
            mov_write_trak_tag(pb, &(mov->tracks[i]));
1333 1334 1335
        }
    }

1336 1337 1338
    if (mov->mode == MODE_PSP)
        mov_write_uuidusmt_tag(pb, s);
    else
1339 1340
    mov_write_udta_tag(pb, mov, s);

1341
    return updateSize(pb, pos);
1342 1343
}

1344
int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
1345
{
1346 1347 1348
    put_be32(pb, 8);    // placeholder for extended size field (64 bit)
    put_tag(pb, "wide");

1349
    mov->mdat_pos = url_ftell(pb);
1350 1351 1352 1353 1354 1355
    put_be32(pb, 0); /* size placeholder*/
    put_tag(pb, "mdat");
    return 0;
}

/* TODO: This needs to be more general */
1356
static void mov_write_ftyp_tag (ByteIOContext *pb, AVFormatContext *s)
1357
{
1358 1359
    MOVContext *mov = s->priv_data;

1360 1361
    put_be32(pb, 0x14 ); /* size */
    put_tag(pb, "ftyp");
1362

1363
    if ( mov->mode == MODE_3GP )
1364
        put_tag(pb, "3gp4");
1365 1366
    else if ( mov->mode == MODE_3G2 )
        put_tag(pb, "3g2a");
1367 1368
    else if ( mov->mode == MODE_PSP )
        put_tag(pb, "MSNV");
1369
    else if ( mov->mode == MODE_MP4 )
1370
        put_tag(pb, "isom");
1371 1372
    else
        put_tag(pb, "qt  ");
1373

1374
    put_be32(pb, 0x200 );
1375

1376
    if ( mov->mode == MODE_3GP )
1377
        put_tag(pb, "3gp4");
1378 1379
    else if ( mov->mode == MODE_3G2 )
        put_tag(pb, "3g2a");
1380 1381
    else if ( mov->mode == MODE_PSP )
        put_tag(pb, "MSNV");
1382
    else if ( mov->mode == MODE_MP4 )
1383
        put_tag(pb, "mp41");
1384 1385
    else
        put_tag(pb, "qt  ");
1386 1387
}

1388
static void mov_write_uuidprof_tag(ByteIOContext *pb, AVFormatContext *s)
1389
{
1390 1391 1392 1393
    AVCodecContext *VideoCodec = s->streams[0]->codec;
    AVCodecContext *AudioCodec = s->streams[1]->codec;
    int AudioRate = AudioCodec->sample_rate;
    int FrameRate = ((VideoCodec->time_base.den) * (0x10000))/ (VideoCodec->time_base.num);
1394 1395
    int audio_kbitrate= AudioCodec->bit_rate / 1000;
    int video_kbitrate= FFMIN(VideoCodec->bit_rate / 1000, 800 - audio_kbitrate);
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416

    put_be32(pb, 0x94 ); /* size */
    put_tag(pb, "uuid");
    put_tag(pb, "PROF");

    put_be32(pb, 0x21d24fce ); /* 96 bit UUID */
    put_be32(pb, 0xbb88695c );
    put_be32(pb, 0xfac9c740 );

    put_be32(pb, 0x0 );  /* ? */
    put_be32(pb, 0x3 );  /* 3 sections ? */

    put_be32(pb, 0x14 ); /* size */
    put_tag(pb, "FPRF");
    put_be32(pb, 0x0 );  /* ? */
    put_be32(pb, 0x0 );  /* ? */
    put_be32(pb, 0x0 );  /* ? */

    put_be32(pb, 0x2c );  /* size */
    put_tag(pb, "APRF");   /* audio */
    put_be32(pb, 0x0 );
1417
    put_be32(pb, 0x2 );   /* TrackID */
1418 1419 1420
    put_tag(pb, "mp4a");
    put_be32(pb, 0x20f );
    put_be32(pb, 0x0 );
1421 1422
    put_be32(pb, audio_kbitrate);
    put_be32(pb, audio_kbitrate);
1423 1424
    put_be32(pb, AudioRate );
    put_be32(pb, AudioCodec->channels );
1425 1426 1427 1428

    put_be32(pb, 0x34 );  /* size */
    put_tag(pb, "VPRF");   /* video */
    put_be32(pb, 0x0 );
1429
    put_be32(pb, 0x1 );    /* TrackID */
1430 1431 1432 1433 1434 1435 1436 1437 1438
    if (VideoCodec->codec_id == CODEC_ID_H264) {
        put_tag(pb, "avc1");
        put_be16(pb, 0x014D );
        put_be16(pb, 0x0015 );
    } else {
        put_tag(pb, "mp4v");
        put_be16(pb, 0x0000 );
        put_be16(pb, 0x0103 );
    }
1439
    put_be32(pb, 0x0 );
1440 1441
    put_be32(pb, video_kbitrate);
    put_be32(pb, video_kbitrate);
1442 1443 1444 1445 1446
    put_be32(pb, FrameRate);
    put_be32(pb, FrameRate);
    put_be16(pb, VideoCodec->width);
    put_be16(pb, VideoCodec->height);
    put_be32(pb, 0x010001); /* ? */
1447 1448
}

1449 1450 1451
static int mov_write_header(AVFormatContext *s)
{
    ByteIOContext *pb = &s->pb;
1452 1453
    MOVContext *mov = s->priv_data;
    int i;
1454

1455 1456 1457 1458 1459 1460 1461 1462 1463
    /* Default mode == MP4 */
    mov->mode = MODE_MP4;

    if (s->oformat != NULL) {
        if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
        else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3G2;
        else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
        else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP;

1464
        mov_write_ftyp_tag(pb,s);
1465 1466 1467 1468 1469 1470 1471 1472 1473
        if ( mov->mode == MODE_PSP ) {
            if ( s->nb_streams != 2 ) {
                av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
                return -1;
            }
            mov_write_uuidprof_tag(pb,s);
        }
    }

1474
    for(i=0; i<s->nb_streams; i++){
bcoudurier's avatar
bcoudurier committed
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
        AVStream *st= s->streams[i];
        MOVTrack *track= &mov->tracks[i];

        track->enc = st->codec;
        if(st->codec->codec_type == CODEC_TYPE_VIDEO){
            track->tag = mov_find_video_codec_tag(s, track);
            av_set_pts_info(st, 64, 1, st->codec->time_base.den);
        }else if(st->codec->codec_type == CODEC_TYPE_AUDIO){
            track->tag = mov_find_audio_codec_tag(s, track);
            av_set_pts_info(st, 64, 1, st->codec->sample_rate);
1485
        }
bcoudurier's avatar
bcoudurier committed
1486 1487
        track->language = ff_mov_iso639_to_lang(st->language, mov->mode != MODE_MOV);
        track->mode = mov->mode;
1488 1489
    }

1490 1491 1492
    mov_write_mdat_tag(pb, mov);
    mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based

1493 1494 1495 1496 1497
    put_flush_packet(pb);

    return 0;
}

1498
static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
1499 1500 1501
{
    MOVContext *mov = s->priv_data;
    ByteIOContext *pb = &s->pb;
bcoudurier's avatar
bcoudurier committed
1502 1503
    MOVTrack *trk = &mov->tracks[pkt->stream_index];
    AVCodecContext *enc = trk->enc;
1504
    int cl, id;
1505
    unsigned int samplesInChunk = 0;
1506
    int size= pkt->size;
1507

1508 1509
    if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */
    if (!size) return 0; /* Discard 0 sized packets */
1510

1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
    if (enc->codec_type == CODEC_TYPE_AUDIO) {
        switch (enc->codec_id) {
        case CODEC_ID_AMR_NB:
            { /* We must find out how many AMR blocks there are in one packet */
                static uint16_t packed_size[16] =
                    {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
                int len = 0;

                while (len < size && samplesInChunk < 100) {
                    len += packed_size[(pkt->data[len] >> 3) & 0x0F];
                    samplesInChunk++;
                }
1523
            }
1524
            break;
bcoudurier's avatar
bcoudurier committed
1525
        case CODEC_ID_PCM_MULAW:
1526
        case CODEC_ID_PCM_ALAW:
1527
            samplesInChunk = size/enc->channels;
1528 1529 1530
            break;
        case CODEC_ID_PCM_S16BE:
        case CODEC_ID_PCM_S16LE:
1531
            samplesInChunk = size/(2*enc->channels);
1532
            break;
bcoudurier's avatar
bcoudurier committed
1533 1534 1535 1536 1537 1538 1539 1540
        case CODEC_ID_PCM_S24BE:
        case CODEC_ID_PCM_S24LE:
            samplesInChunk = size/(3*enc->channels);
            break;
        case CODEC_ID_PCM_S32BE:
        case CODEC_ID_PCM_S32LE:
            samplesInChunk = size/(4*enc->channels);
            break;
1541
        default:
1542
            samplesInChunk = 1;
1543
        }
1544 1545
    } else {
        samplesInChunk = 1;
1546 1547
    }

1548 1549
    /* copy extradata if it exists */
    if (trk->vosLen == 0 && enc->extradata_size > 0) {
1550 1551 1552 1553 1554
        trk->vosLen = enc->extradata_size;
        trk->vosData = av_malloc(trk->vosLen);
        memcpy(trk->vosData, enc->extradata, trk->vosLen);
    }

1555 1556 1557 1558 1559 1560
    if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) {
        /* from x264 or from bytestream h264 */
        /* nal reformating needed */
        avc_parse_nal_units(&pkt->data, &pkt->size);
        assert(pkt->size);
        size = pkt->size;
1561 1562
    }

1563 1564 1565 1566
    cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
    id = trk->entry % MOV_INDEX_CLUSTER_SIZE;

    if (trk->ents_allocated <= trk->entry) {
1567
        trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*));
1568 1569 1570 1571 1572 1573 1574 1575
        if (!trk->cluster)
            return -1;
        trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
        if (!trk->cluster[cl])
            return -1;
        trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
    }

1576
    trk->cluster[cl][id].pos = url_ftell(pb);
1577 1578 1579 1580
    trk->cluster[cl][id].samplesInChunk = samplesInChunk;
    trk->cluster[cl][id].size = size;
    trk->cluster[cl][id].entries = samplesInChunk;
    if(enc->codec_type == CODEC_TYPE_VIDEO) {
1581 1582 1583
        if (pkt->dts != pkt->pts)
            trk->hasBframes = 1;
        trk->cluster[cl][id].cts = pkt->pts - pkt->dts;
1584 1585
        trk->cluster[cl][id].key_frame = !!(pkt->flags & PKT_FLAG_KEY);
        if(trk->cluster[cl][id].key_frame)
1586
            trk->hasKeyframes++;
1587
    }
1588 1589
    trk->entry++;
    trk->sampleCount += samplesInChunk;
bcoudurier's avatar
bcoudurier committed
1590
    mov->mdat_size += size;
1591

1592
    put_buffer(pb, pkt->data, size);
1593 1594 1595 1596 1597 1598 1599 1600 1601 1602

    put_flush_packet(pb);
    return 0;
}

static int mov_write_trailer(AVFormatContext *s)
{
    MOVContext *mov = s->priv_data;
    ByteIOContext *pb = &s->pb;
    int res = 0;
bcoudurier's avatar
bcoudurier committed
1603
    int i, j;
1604

1605
    offset_t moov_pos = url_ftell(pb);
1606 1607

    /* Write size of mdat tag */
bcoudurier's avatar
bcoudurier committed
1608
    if (mov->mdat_size+8 <= UINT32_MAX) {
1609
        url_fseek(pb, mov->mdat_pos, SEEK_SET);
bcoudurier's avatar
bcoudurier committed
1610
        put_be32(pb, mov->mdat_size+8);
1611 1612 1613 1614 1615
    } else {
        /* overwrite 'wide' placeholder atom */
        url_fseek(pb, mov->mdat_pos - 8, SEEK_SET);
        put_be32(pb, 1); /* special value: real atom size will be 64 bit value after tag field */
        put_tag(pb, "mdat");
bcoudurier's avatar
bcoudurier committed
1616
        put_be64(pb, mov->mdat_size+16);
1617
    }
1618
    url_fseek(pb, moov_pos, SEEK_SET);
1619

1620
    mov_write_moov_tag(pb, mov, s);
1621 1622 1623 1624 1625 1626

    for (i=0; i<MAX_STREAMS; i++) {
        for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
            av_free(mov->tracks[i].cluster[j]);
        }
        av_free(mov->tracks[i].cluster);
1627 1628
        if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData );

1629 1630 1631
        mov->tracks[i].cluster = NULL;
        mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
    }
1632

1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
    put_flush_packet(pb);

    return res;
}

static AVOutputFormat mov_oformat = {
    "mov",
    "mov format",
    NULL,
    "mov",
    sizeof(MOVContext),
1644
    CODEC_ID_AAC,
1645
    CODEC_ID_MPEG4,
1646 1647 1648
    mov_write_header,
    mov_write_packet,
    mov_write_trailer,
1649
    .flags = AVFMT_GLOBALHEADER,
1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
};

static AVOutputFormat _3gp_oformat = {
    "3gp",
    "3gp format",
    NULL,
    "3gp",
    sizeof(MOVContext),
    CODEC_ID_AMR_NB,
    CODEC_ID_H263,
    mov_write_header,
    mov_write_packet,
    mov_write_trailer,
1663
    .flags = AVFMT_GLOBALHEADER,
1664 1665 1666 1667 1668
};

static AVOutputFormat mp4_oformat = {
    "mp4",
    "mp4 format",
1669 1670
    "application/mp4",
    "mp4,m4a",
1671 1672 1673 1674 1675 1676
    sizeof(MOVContext),
    CODEC_ID_AAC,
    CODEC_ID_MPEG4,
    mov_write_header,
    mov_write_packet,
    mov_write_trailer,
1677
    .flags = AVFMT_GLOBALHEADER,
1678 1679
};

1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690
static AVOutputFormat psp_oformat = {
    "psp",
    "psp mp4 format",
    NULL,
    "mp4,psp",
    sizeof(MOVContext),
    CODEC_ID_AAC,
    CODEC_ID_MPEG4,
    mov_write_header,
    mov_write_packet,
    mov_write_trailer,
1691
    .flags = AVFMT_GLOBALHEADER,
1692 1693
};

1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704
static AVOutputFormat _3g2_oformat = {
    "3g2",
    "3gp2 format",
    NULL,
    "3g2",
    sizeof(MOVContext),
    CODEC_ID_AMR_NB,
    CODEC_ID_H263,
    mov_write_header,
    mov_write_packet,
    mov_write_trailer,
1705
    .flags = AVFMT_GLOBALHEADER,
1706 1707
};

1708 1709 1710 1711 1712
int movenc_init(void)
{
    av_register_output_format(&mov_oformat);
    av_register_output_format(&_3gp_oformat);
    av_register_output_format(&mp4_oformat);
1713
    av_register_output_format(&psp_oformat);
1714
    av_register_output_format(&_3g2_oformat);
1715 1716
    return 0;
}