movenc.c 49.2 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
    int         entry;
50
    uint64_t    mdat_size;
51 52 53
    int         ents_allocated;
    long        timescale;
    long        time;
54
    long        trackDuration;
55 56
    long        sampleCount;
    long        sampleDuration;
57
    int         hasKeyframes;
58
    int         hasBframes;
59
    int         language;
60 61 62 63
    int         trackID;
    AVCodecContext *enc;

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

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

78 79
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track);

80 81 82
/* output language code from iso639 language name */
extern int ff_mov_iso639_to_lang(const char *lang, int mp4);

83
//FIXME supprt 64bit varaint with wide placeholders
84
static offset_t updateSize (ByteIOContext *pb, offset_t pos)
85
{
86
    offset_t curpos = url_ftell(pb);
87
    url_fseek(pb, pos, SEEK_SET);
88
    put_be32(pb, curpos - pos); /* rewrite size */
89
    url_fseek(pb, curpos, SEEK_SET);
90 91

    return curpos - pos;
92 93
}

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

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

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

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

160
/* Sample to chunk atom */
161
static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
162
{
163 164
    int index = 0, oldval = -1, i;
    offset_t entryPos, curpos;
165

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

189
    return updateSize (pb, pos);
190 191
}

192
/* Sync sample atom */
193
static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
194
{
195 196 197
    offset_t curpos, entryPos;
    int i, index = 0;
    offset_t pos = url_ftell(pb);
198
    put_be32(pb, 0); // size
199
    put_tag(pb, "stss");
200
    put_be32(pb, 0); // version & flags
201
    entryPos = url_ftell(pb);
202
    put_be32(pb, track->entry); // entry count
203 204 205 206 207 208 209 210 211 212
    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);
213
    put_be32(pb, index); // rewrite size
214 215
    url_fseek(pb, curpos, SEEK_SET);
    return updateSize (pb, pos);
216 217
}

218
static int mov_write_damr_tag(ByteIOContext *pb)
219 220 221 222 223
{
    put_be32(pb, 0x11); /* size */
    put_tag(pb, "damr");
    put_tag(pb, "FFMP");
    put_byte(pb, 0);
224 225 226 227 228

    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) */
229 230 231
    return 0x11;
}

232 233
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track)
{
234
    offset_t pos = url_ftell(pb);
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

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

259
static const CodecTag codec_movaudio_tags[] = {
260 261 262 263 264 265 266
    { 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') },
267
    { CODEC_ID_AMR_WB, MKTAG('s', 'a', 'w', 'b') },
268 269 270 271 272 273
    { 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 },
};

274
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
275
{
276
    offset_t pos = url_ftell(pb);
277
    int tag;
278

279
    put_be32(pb, 0); /* size */
280

281 282
    tag = track->enc->codec_tag;
    if (!tag)
283 284 285 286
    tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
    // if no mac fcc found, try with Microsoft tags
    if (!tag)
    {
287
        int tmp = codec_get_tag(codec_wav_tags, track->enc->codec_id);
288
        tag = MKTAG('m', 's', ((tmp >> 8) & 0xff), (tmp & 0xff));
289
    }
290
    put_le32(pb, tag); // store it byteswapped
291

292 293 294
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
295

296
    /* SoundDescription */
297 298 299 300
    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 */
301
    put_be16(pb, 0); /* Revision level */
302 303
    put_be32(pb, 0); /* Reserved */

304 305
    put_be16(pb, track->enc->channels); /* Number of channels */
    /* TODO: Currently hard-coded to 16-bit, there doesn't seem
306
                 to be a good way to get number of bits of audio */
307
    put_be16(pb, 0x10); /* Reserved */
308 309 310 311 312 313 314 315 316 317

    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) */
    }
318
    put_be16(pb, 0); /* packet size (= 0) */
319 320 321
    put_be16(pb, track->timescale); /* Time scale */
    put_be16(pb, 0); /* Reserved */

322 323 324 325 326 327 328 329 330 331 332 333 334
    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);
    }
335 336
    if(track->enc->codec_id == CODEC_ID_AMR_NB)
        mov_write_damr_tag(pb);
337
    return updateSize (pb, pos);
338 339
}

340
static int mov_write_d263_tag(ByteIOContext *pb)
341 342 343 344 345 346 347 348 349
{
    put_be32(pb, 0xf); /* size */
    put_tag(pb, "d263");
    put_tag(pb, "FFMP");
    put_be16(pb, 0x0a);
    put_byte(pb, 0);
    return 0xf;
}

350 351
/* TODO: No idea about these values */
static int mov_write_svq3_tag(ByteIOContext *pb)
352
{
353 354 355 356 357 358
    put_be32(pb, 0x15);
    put_tag(pb, "SMI ");
    put_tag(pb, "SEQH");
    put_be32(pb, 0x5);
    put_be32(pb, 0xe2c0211d);
    put_be32(pb, 0xc0000000);
359
    put_byte(pb, 0);
360
    return 0x15;
361 362
}

363 364 365 366 367 368 369 370 371 372 373 374 375
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)
376
{
377 378 379 380 381 382
    uint32_t len;
    uint8_t  vals[4];

    len = size;
    vals[3] = (uint8_t)(len & 0x7f);
    len >>= 7;
383
    vals[2] = (uint8_t)((len & 0x7f) | 0x80);
384
    len >>= 7;
385
    vals[1] = (uint8_t)((len & 0x7f) | 0x80);
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
    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]);
    }
413 414
}

415
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
416
{
417
    int decoderSpecificInfoLen;
418
    offset_t pos = url_ftell(pb);
419

420 421
    decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;

422
    put_be32(pb, 0);               // size
423
    put_tag(pb, "esds");
424
    put_be32(pb, 0);               // Version
425

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

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

435 436
    // Object type indication
    put_byte(pb, codec_get_tag(ff_mov_obj_type, track->enc->codec_id));
437

438 439
    // 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)
440 441 442 443 444
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
        put_byte(pb, 0x15);            // flags (= Audiostream)
    else
        put_byte(pb, 0x11);            // flags (= Visualstream)

445 446
    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
447

448 449 450 451 452
    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
453

454 455 456 457 458 459 460
    if (track->vosLen)
    {
        // DecoderSpecific info descriptor
        putDescr(pb, 0x05, track->vosLen);
        put_buffer(pb, track->vosData, track->vosLen);
    }

461

462
    // SL descriptor
463
    putDescr(pb, 0x06, 1);
464
    put_byte(pb, 0x02);
465
    return updateSize (pb, pos);
466 467
}

468
static const CodecTag codec_movvideo_tags[] = {
469 470 471 472
    { 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') },
473
    { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
474 475 476 477
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') },
    { 0, 0 },
};

478
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
479
{
480
    offset_t pos = url_ftell(pb);
481
    char compressor_name[32];
482
    int tag;
483

484
    put_be32(pb, 0); /* size */
485

486 487
    tag = track->enc->codec_tag;
    if (!tag)
488 489 490
    tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
    // if no mac fcc found, try with Microsoft tags
    if (!tag)
491
        tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
492
    put_le32(pb, tag); // store it byteswapped
493

494 495 496 497
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

498 499 500 501 502 503 504 505 506 507
    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 */
    }
508 509
    put_be16(pb, track->enc->width); /* Video width */
    put_be16(pb, track->enc->height); /* Video height */
510 511
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
512 513
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
514

515
    memset(compressor_name,0,32);
516
    if (track->enc->codec && track->enc->codec->name)
517
        strncpy(compressor_name,track->enc->codec->name,31);
518
    put_byte(pb, strlen(compressor_name));
519
    put_buffer(pb, compressor_name, 31);
520

521 522 523 524 525 526 527
    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)
528
        mov_write_svq3_tag(pb);
529 530

    return updateSize (pb, pos);
531 532
}

533
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
534
{
535
    offset_t pos = url_ftell(pb);
536 537 538 539
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
540 541 542 543
    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);
544
    return updateSize(pb, pos);
545 546
}

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
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 Niedermayer's avatar
Michael Niedermayer committed
582
/* TODO: */
583
/* Time to sample atom */
584
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
585 586 587 588 589 590
{
    put_be32(pb, 0x18); /* size */
    put_tag(pb, "stts");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */

591 592
    put_be32(pb, track->sampleCount); /* sample count */
    put_be32(pb, track->sampleDuration); /* sample duration */
593 594 595
    return 0x18;
}

596
static int mov_write_dref_tag(ByteIOContext *pb)
597 598 599 600 601 602 603 604 605 606 607 608 609
{
    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;
}

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

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

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

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

657
static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
658
{
659
    char *descr, *hdlr, *hdlr_type;
660
    offset_t pos = url_ftell(pb);
661

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

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

706
static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
707 708 709 710 711 712
{
    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 */
713
    put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
714
    put_be32(pb, track->trackDuration); /* duration */
715
    put_be16(pb, track->language); /* language */
716 717 718 719
    put_be16(pb, 0); /* reserved (quality) */
    return 32;
}

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

731
static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
732 733 734
{
    put_be32(pb, 0x5c); /* size (always 0x5c) */
    put_tag(pb, "tkhd");
735
    put_be32(pb, 0xf); /* version & flags (track enabled) */
736 737 738 739
    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
740
    put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration */
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764

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

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

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

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

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

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

    put_be32(pb, 0x6c); /* size (always 0x6c) */
    put_tag(pb, "mvhd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, mov->time); /* creation time */
    put_be32(pb, mov->time); /* modification time */
    put_be32(pb, mov->timescale); /* timescale */
    for (i=0; i<MAX_STREAMS; i++) {
        if(mov->tracks[i].entry > 0) {
Michael Niedermayer's avatar
Michael Niedermayer committed
856
            maxTrackLenTemp = av_rescale_rnd(mov->tracks[i].trackDuration, globalTimescale, mov->tracks[i].timescale, AV_ROUND_UP);
857 858
            if(maxTrackLen < maxTrackLenTemp)
                maxTrackLen = maxTrackLenTemp;