movenc.c 47.5 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 23
#include "avio.h"

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

27 28 29
#define MOV_INDEX_CLUSTER_SIZE 16384
#define globalTimescale 1000

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

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

typedef struct MOVIndex {
46
    int         mode;
47
    int         entry;
48
    uint64_t    mdat_size;
49 50 51
    int         ents_allocated;
    long        timescale;
    long        time;
52
    long        trackDuration;
53 54
    long        sampleCount;
    long        sampleDuration;
55
    int         hasKeyframes;
56
    int         language;
57 58 59 60
    int         trackID;
    AVCodecContext *enc;

    int         vosLen;
61
    uint8_t     *vosData;
62 63 64
    MOVIentry** cluster;
} MOVTrack;

65
typedef struct MOVContext {
66
    int     mode;
67 68
    long    time;
    int     nb_streams;
69 70
    int     mdat_written;
    offset_t mdat_pos;
71 72 73 74
    long    timescale;
    MOVTrack tracks[MAX_STREAMS];
} MOVContext;

75 76
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track);

77 78 79
/* output language code from iso639 language name */
extern int ff_mov_iso639_to_lang(const char *lang, int mp4);

80 81 82 83 84 85 86
const CodecTag ff_mov_obj_type[] = {
    { CODEC_ID_MPEG4     ,  32 },
    { CODEC_ID_AAC       ,  64 },
    { CODEC_ID_MPEG1VIDEO, 106 },
    { CODEC_ID_MPEG2VIDEO,  96 },//mpeg2 profiles
    { CODEC_ID_MP2       , 107 },//FIXME mpeg2 mpeg audio -> 105
    { CODEC_ID_MP3       , 107 },//FIXME mpeg2 mpeg audio -> 105
87
    { CODEC_ID_H264      ,  33 },
88 89 90 91 92 93 94 95 96 97 98 99
    { CODEC_ID_H263      , 242 },
    { CODEC_ID_H261      , 243 },
    { CODEC_ID_MJPEG     , 108 },
    { CODEC_ID_PCM_S16LE , 224 },
    { CODEC_ID_VORBIS    , 225 },
    { CODEC_ID_AC3       , 226 },
    { CODEC_ID_PCM_ALAW  , 227 },
    { CODEC_ID_PCM_MULAW , 228 },
    { CODEC_ID_PCM_S16BE , 230 },
    { 0,0  },
};

100
//FIXME supprt 64bit varaint with wide placeholders
101
static offset_t updateSize (ByteIOContext *pb, offset_t pos)
102
{
103
    offset_t curpos = url_ftell(pb);
104
    url_fseek(pb, pos, SEEK_SET);
105
    put_be32(pb, curpos - pos); /* rewrite size */
106
    url_fseek(pb, curpos, SEEK_SET);
107 108

    return curpos - pos;
109 110
}

111
/* Chunk offset atom */
112
static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
113 114
{
    int i;
115
    offset_t pos = url_ftell(pb);
116
    put_be32(pb, 0); /* size */
117 118 119 120 121 122
    int mode64 = 0; //   use 32 bit size variant if possible
    if (pos > UINT32_MAX) {
        mode64 = 1;
        put_tag(pb, "co64");
    } else
        put_tag(pb, "stco");
123 124 125 126 127
    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;
128 129 130 131
        if(mode64 == 1)
            put_be64(pb, track->cluster[cl][id].pos);
        else
            put_be32(pb, track->cluster[cl][id].pos);
132
    }
133
    return updateSize (pb, pos);
134 135
}

136
/* Sample size atom */
137
static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
138
{
139
    int equalChunks = 1;
140
    int i, j, entries = 0, tst = -1, oldtst = -1;
141

142
    offset_t pos = url_ftell(pb);
143
    put_be32(pb, 0); /* size */
144 145 146
    put_tag(pb, "stsz");
    put_be32(pb, 0); /* version & flags */

147 148 149
    for (i=0; i<track->entry; i++) {
        int cl = i / MOV_INDEX_CLUSTER_SIZE;
        int id = i % MOV_INDEX_CLUSTER_SIZE;
150 151 152
        tst = track->cluster[cl][id].size/track->cluster[cl][id].entries;
        if(oldtst != -1 && tst != oldtst) {
            equalChunks = 0;
153 154
        }
        oldtst = tst;
155
        entries += track->cluster[cl][id].entries;
156
    }
157 158
    if (equalChunks) {
        int sSize = track->cluster[0][0].size/track->cluster[0][0].entries;
159
        put_be32(pb, sSize); // sample size
160
        put_be32(pb, entries); // sample count
161
    }
162
    else {
163 164
        put_be32(pb, 0); // sample size
        put_be32(pb, entries); // sample count
165
        for (i=0; i<track->entry; i++) {
166 167
            int cl = i / MOV_INDEX_CLUSTER_SIZE;
            int id = i % MOV_INDEX_CLUSTER_SIZE;
168 169 170 171
            for ( j=0; j<track->cluster[cl][id].entries; j++) {
                put_be32(pb, track->cluster[cl][id].size /
                         track->cluster[cl][id].entries);
            }
172 173
        }
    }
174
    return updateSize (pb, pos);
175 176
}

177
/* Sample to chunk atom */
178
static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
179
{
180 181
    int index = 0, oldval = -1, i;
    offset_t entryPos, curpos;
182

183
    offset_t pos = url_ftell(pb);
184
    put_be32(pb, 0); /* size */
185
    put_tag(pb, "stsc");
186
    put_be32(pb, 0); // version & flags
187
    entryPos = url_ftell(pb);
188
    put_be32(pb, track->entry); // entry count
189 190 191
    for (i=0; i<track->entry; i++) {
        int cl = i / MOV_INDEX_CLUSTER_SIZE;
        int id = i % MOV_INDEX_CLUSTER_SIZE;
192
        if(oldval != track->cluster[cl][id].samplesInChunk)
193
        {
194
            put_be32(pb, i+1); // first chunk
195
            put_be32(pb, track->cluster[cl][id].samplesInChunk); // samples per chunk
196
            put_be32(pb, 0x1); // sample description index
197
            oldval = track->cluster[cl][id].samplesInChunk;
198
            index++;
199 200
        }
    }
201 202
    curpos = url_ftell(pb);
    url_fseek(pb, entryPos, SEEK_SET);
203
    put_be32(pb, index); // rewrite size
204
    url_fseek(pb, curpos, SEEK_SET);
205

206
    return updateSize (pb, pos);
207 208
}

209
/* Sync sample atom */
210
static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
211
{
212 213 214
    offset_t curpos, entryPos;
    int i, index = 0;
    offset_t pos = url_ftell(pb);
215
    put_be32(pb, 0); // size
216
    put_tag(pb, "stss");
217
    put_be32(pb, 0); // version & flags
218
    entryPos = url_ftell(pb);
219
    put_be32(pb, track->entry); // entry count
220 221 222 223 224 225 226 227 228 229
    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);
230
    put_be32(pb, index); // rewrite size
231 232
    url_fseek(pb, curpos, SEEK_SET);
    return updateSize (pb, pos);
233 234
}

235
static int mov_write_damr_tag(ByteIOContext *pb)
236 237 238 239 240
{
    put_be32(pb, 0x11); /* size */
    put_tag(pb, "damr");
    put_tag(pb, "FFMP");
    put_byte(pb, 0);
241 242 243 244 245

    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) */
246 247 248
    return 0x11;
}

249 250
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track)
{
251
    offset_t pos = url_ftell(pb);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

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

    put_be32(pb, 12);    /* size */
    put_tag(pb, "frma");
    put_tag(pb, "mp4a");

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

    mov_write_esds_tag(pb, track);

    put_be32(pb, 12);    /* size */
    put_tag(pb, "srcq");
    put_be32(pb, 0x40);

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

    return updateSize (pb, pos);
}

276
static const CodecTag codec_movaudio_tags[] = {
277 278 279 280 281 282 283
    { 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') },
284
    { CODEC_ID_AMR_WB, MKTAG('s', 'a', 'w', 'b') },
285 286 287 288 289 290
    { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') },
    { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') },
    { CODEC_ID_MP3, MKTAG('.', 'm', 'p', '3') },
    { 0, 0 },
};

291
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
292
{
293
    offset_t pos = url_ftell(pb);
294
    int tag;
295

296
    put_be32(pb, 0); /* size */
297

298 299
    tag = track->enc->codec_tag;
    if (!tag)
300 301 302 303
    tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
    // if no mac fcc found, try with Microsoft tags
    if (!tag)
    {
304
        int tmp = codec_get_tag(codec_wav_tags, track->enc->codec_id);
305
        tag = MKTAG('m', 's', ((tmp >> 8) & 0xff), (tmp & 0xff));
306
    }
307
    put_le32(pb, tag); // store it byteswapped
308

309 310 311
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
312

313
    /* SoundDescription */
314 315 316 317
    if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
        put_be16(pb, 1); /* Version 1 */
    else
        put_be16(pb, 0); /* Version 0 */
318
    put_be16(pb, 0); /* Revision level */
319 320
    put_be32(pb, 0); /* Reserved */

321 322
    put_be16(pb, track->enc->channels); /* Number of channels */
    /* TODO: Currently hard-coded to 16-bit, there doesn't seem
323
                 to be a good way to get number of bits of audio */
324
    put_be16(pb, 0x10); /* Reserved */
325 326 327 328 329 330 331 332 333 334

    if(track->enc->codec_id == CODEC_ID_AAC ||
       track->enc->codec_id == CODEC_ID_MP3)
    {
        put_be16(pb, 0xfffe); /* compression ID (vbr)*/
    }
    else
    {
        put_be16(pb, 0); /* compression ID (= 0) */
    }
335
    put_be16(pb, 0); /* packet size (= 0) */
336 337 338
    put_be16(pb, track->timescale); /* Time scale */
    put_be16(pb, 0); /* Reserved */

339 340 341 342 343 344 345 346 347 348 349 350 351
    if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
    {
        /* SoundDescription V1 extended info */
        put_be32(pb, track->enc->frame_size); /* Samples per packet  */
        put_be32(pb, 1536); /* Bytes per packet */
        put_be32(pb, 2); /* Bytes per frame */
        put_be32(pb, 2); /* Bytes per sample */
    }

    if(track->enc->codec_id == CODEC_ID_AAC) {
        if( track->mode == MODE_MOV ) mov_write_wave_tag(pb, track);
        else mov_write_esds_tag(pb, track);
    }
352 353
    if(track->enc->codec_id == CODEC_ID_AMR_NB)
        mov_write_damr_tag(pb);
354
    return updateSize (pb, pos);
355 356
}

357
static int mov_write_d263_tag(ByteIOContext *pb)
358 359 360 361 362 363 364 365 366
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
    put_be16(pb, 0x0a);
    put_byte(pb, 0);
    return 0xf;
}

367 368
/* TODO: No idea about these values */
static int mov_write_svq3_tag(ByteIOContext *pb)
369
{
370 371 372 373 374 375
    put_be32(pb, 0x15);
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
    put_be32(pb, 0x5);
    put_be32(pb, 0xe2c0211d);
    put_be32(pb, 0xc0000000);
376
    put_byte(pb, 0);
377
    return 0x15;
378 379
}

380 381 382 383 384 385 386 387 388 389 390 391 392
static unsigned int descrLength(unsigned int len)
{
    if (len < 0x00000080)
        return 2 + len;
    else if (len < 0x00004000)
        return 3 + len;
    else if(len < 0x00200000)
        return 4 + len;
    else
        return 5 + len;
}

static void putDescr(ByteIOContext *pb, int tag, int size)
393
{
394 395 396 397 398 399
    uint32_t len;
    uint8_t  vals[4];

    len = size;
    vals[3] = (uint8_t)(len & 0x7f);
    len >>= 7;
400
    vals[2] = (uint8_t)((len & 0x7f) | 0x80);
401
    len >>= 7;
402
    vals[1] = (uint8_t)((len & 0x7f) | 0x80);
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
    len >>= 7;
    vals[0] = (uint8_t)((len & 0x7f) | 0x80);

    put_byte(pb, tag); // DescriptorTag

    if (size < 0x00000080)
    {
        put_byte(pb, vals[3]);
    }
    else if (size < 0x00004000)
    {
        put_byte(pb, vals[2]);
        put_byte(pb, vals[3]);
    }
    else if (size < 0x00200000)
    {
        put_byte(pb, vals[1]);
        put_byte(pb, vals[2]);
        put_byte(pb, vals[3]);
    }
    else if (size < 0x10000000)
    {
        put_byte(pb, vals[0]);
        put_byte(pb, vals[1]);
        put_byte(pb, vals[2]);
        put_byte(pb, vals[3]);
    }
430 431
}

432
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
433
{
434
    int decoderSpecificInfoLen;
435
    offset_t pos = url_ftell(pb);
436 437
    void *vosDataBackup=track->vosData;
    int vosLenBackup=track->vosLen;
438

439 440 441
    // we should be able to have these passed in, via vosData, then we wouldn't need to attack this routine at all
    static const char PSPAACData[]={0x13,0x10};
    static const char PSPMP4Data[]={0x00,0x00,0x01,0xB0,0x03,0x00,0x00,0x01,0xB5,0x09,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x20,0x00,0x84,0x5D,0x4C,0x28,0x50,0x20,0xF0,0xA3,0x1F };
442 443


444 445 446 447 448
    if (track->mode == MODE_PSP)  // fails on psp if this is not here
    {
        if (track->enc->codec_id == CODEC_ID_AAC)
        {
            track->vosLen = 2;
449
            track->vosData = (uint8_t *) PSPAACData;
450 451 452 453 454
        }

        if (track->enc->codec_id == CODEC_ID_MPEG4)
        {
            track->vosLen = 28;
455
            track->vosData = (uint8_t *) PSPMP4Data;
456 457
        }
    }
458

459 460
    decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;

461
    put_be32(pb, 0);               // size
462
    put_tag(pb, "esds");
463
    put_be32(pb, 0);               // Version
464

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

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

474 475
    // Object type indication
    put_byte(pb, codec_get_tag(ff_mov_obj_type, track->enc->codec_id));
476

477 478
    // 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)
479 480 481 482 483
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
        put_byte(pb, 0x15);            // flags (= Audiostream)
    else
        put_byte(pb, 0x11);            // flags (= Visualstream)

484 485
    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
486

487 488 489 490 491
    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
492

493 494 495 496 497 498 499
    if (track->vosLen)
    {
        // DecoderSpecific info descriptor
        putDescr(pb, 0x05, track->vosLen);
        put_buffer(pb, track->vosData, track->vosLen);
    }

500 501 502
    track->vosData = vosDataBackup;
    track->vosLen = vosLenBackup;

503
    // SL descriptor
504
    putDescr(pb, 0x06, 1);
505
    put_byte(pb, 0x02);
506
    return updateSize (pb, pos);
507 508
}

509
static const CodecTag codec_movvideo_tags[] = {
510 511 512 513
    { 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') },
514
    { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
515 516 517 518
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') },
    { 0, 0 },
};

519
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
520
{
521
    offset_t pos = url_ftell(pb);
522
    char compressor_name[32];
523
    int tag;
524

525
    put_be32(pb, 0); /* size */
526

527 528
    tag = track->enc->codec_tag;
    if (!tag)
529 530 531
    tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
    // if no mac fcc found, try with Microsoft tags
    if (!tag)
532
        tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
533
    put_le32(pb, tag); // store it byteswapped
534

535 536 537 538
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

539 540 541 542 543 544 545 546 547 548
    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 */
    }
549 550
    put_be16(pb, track->enc->width); /* Video width */
    put_be16(pb, track->enc->height); /* Video height */
551 552
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
553 554
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
555

556
    memset(compressor_name,0,32);
557
    if (track->enc->codec && track->enc->codec->name)
558
        strncpy(compressor_name,track->enc->codec->name,31);
559
    put_byte(pb, strlen(compressor_name));
560
    put_buffer(pb, compressor_name, 31);
561

562 563 564 565 566 567 568
    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)
569
        mov_write_svq3_tag(pb);
570 571

    return updateSize (pb, pos);
572 573
}

574
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
575
{
576
    offset_t pos = url_ftell(pb);
577 578 579 580
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
581 582 583 584
    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);
585
    return updateSize(pb, pos);
586 587
}

Michael Niedermayer's avatar
Michael Niedermayer committed
588
/* TODO: */
589
/* Time to sample atom */
590
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
591 592 593 594 595 596
{
    put_be32(pb, 0x18); /* size */
    put_tag(pb, "stts");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */

597 598
    put_be32(pb, track->sampleCount); /* sample count */
    put_be32(pb, track->sampleDuration); /* sample duration */
599 600 601
    return 0x18;
}

602
static int mov_write_dref_tag(ByteIOContext *pb)
603 604 605 606 607 608 609 610 611 612 613 614 615
{
    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;
}

616
static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
617
{
618
    offset_t pos = url_ftell(pb);
619 620
    put_be32(pb, 0); /* size */
    put_tag(pb, "stbl");
621 622
    mov_write_stsd_tag(pb, track);
    mov_write_stts_tag(pb, track);
623 624 625
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
        track->hasKeyframes)
        mov_write_stss_tag(pb, track);
626 627 628 629
    mov_write_stsc_tag(pb, track);
    mov_write_stsz_tag(pb, track);
    mov_write_stco_tag(pb, track);
    return updateSize(pb, pos);
630 631
}

632
static int mov_write_dinf_tag(ByteIOContext *pb)
633
{
634
    offset_t pos = url_ftell(pb);
635 636
    put_be32(pb, 0); /* size */
    put_tag(pb, "dinf");
637 638
    mov_write_dref_tag(pb);
    return updateSize(pb, pos);
639 640
}

641
static int mov_write_smhd_tag(ByteIOContext *pb)
642 643 644 645 646 647 648 649 650
{
    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;
}

651
static int mov_write_vmhd_tag(ByteIOContext *pb)
652 653 654 655 656 657 658 659
{
    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;
}

660
static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
661
{
662
    char *descr, *hdlr, *hdlr_type;
663
    offset_t pos = url_ftell(pb);
664

665
    if (!track) { /* no media --> data handler */
666 667 668
        hdlr = "dhlr";
        hdlr_type = "url ";
        descr = "DataHandler";
669
    } else {
670 671 672 673 674 675 676 677
        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";
        }
678
    }
679

680
    put_be32(pb, 0); /* size */
681 682
    put_tag(pb, "hdlr");
    put_be32(pb, 0); /* Version & flags */
683
    put_buffer(pb, hdlr, 4); /* handler */
684
    put_tag(pb, hdlr_type); /* handler type */
685 686 687
    put_be32(pb ,0); /* reserved */
    put_be32(pb ,0); /* reserved */
    put_be32(pb ,0); /* reserved */
688 689 690 691 692 693 694
    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)
{
695
    offset_t pos = url_ftell(pb);
696 697
    put_be32(pb, 0); /* size */
    put_tag(pb, "minf");
698
    if(track->enc->codec_type == CODEC_TYPE_VIDEO)
699
        mov_write_vmhd_tag(pb);
700
    else
701 702 703 704 705
        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);
706
    return updateSize(pb, pos);
707 708
}

709
static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
710 711 712 713 714 715
{
    put_be32(pb, 32); /* size */
    put_tag(pb, "mdhd");
    put_be32(pb, 0); /* Version & flags */
    put_be32(pb, track->time); /* creation time */
    put_be32(pb, track->time); /* modification time */
716
    put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
717
    put_be32(pb, track->trackDuration); /* duration */
718
    put_be16(pb, track->language); /* language */
719 720 721 722
    put_be16(pb, 0); /* reserved (quality) */
    return 32;
}

723
static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
724
{
725
    offset_t pos = url_ftell(pb);
726 727
    put_be32(pb, 0); /* size */
    put_tag(pb, "mdia");
728 729 730 731
    mov_write_mdhd_tag(pb, track);
    mov_write_hdlr_tag(pb, track);
    mov_write_minf_tag(pb, track);
    return updateSize(pb, pos);
732 733
}

734
static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
735 736 737
{
    put_be32(pb, 0x5c); /* size (always 0x5c) */
    put_tag(pb, "tkhd");
738
    put_be32(pb, 0xf); /* version & flags (track enabled) */
739 740 741 742
    put_be32(pb, track->time); /* creation time */
    put_be32(pb, track->time); /* modification time */
    put_be32(pb, track->trackID); /* track-id */
    put_be32(pb, 0); /* reserved */
Michael Niedermayer's avatar
Michael Niedermayer committed
743
    put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration */
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767

    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) {
768 769 770
        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);
771
        put_be32(pb, track->enc->height*0x10000);
772 773 774 775 776 777 778 779
    }
    else {
        put_be32(pb, 0);
        put_be32(pb, 0);
    }
    return 0x5c;
}

780 781 782 783 784 785 786 787 788 789
// 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 Niedermayer's avatar
Michael Niedermayer committed
790
    put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration   ... doesn't seem to effect psp */
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815

    put_be32(pb, 0x0);
    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;
}

816
static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
817
{
818
    offset_t pos = url_ftell(pb);
819 820
    put_be32(pb, 0); /* size */
    put_tag(pb, "trak");
821
    mov_write_tkhd_tag(pb, track);
822
    if (track->mode == MODE_PSP)
823
        mov_write_edts_tag(pb, track);  // PSP Movies require edts box
824
    mov_write_mdia_tag(pb, track);
825
    if (track->mode == MODE_PSP)
826
        mov_write_uuid_tag_psp(pb,track);  // PSP Movies require this uuid box
827
    return updateSize(pb, pos);
828 829
}

830
#if 0
831
/* TODO: Not sorted out, but not necessary either */
832
static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
833 834 835 836 837 838 839 840 841 842 843
{
    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;
}
844
#endif
845

846
static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
847
{
848 849
    int maxTrackID = 1, i;
    int64_t maxTrackLenTemp, maxTrackLen = 0;
850 851 852 853 854 855 856 857 858

    put_be32(pb, 0x6c); /* size (always 0x6c) */
    put_tag(pb, "mvhd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, mov->time);