movenc.c 50.4 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
    { 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') },
271
    { CODEC_ID_NONE, 0 },
272 273
};

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 478 479 480
    /* 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 },
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
static int mov_find_video_codec_tag(MOVTrack* track)
{
    int tag;

    tag = track->enc->codec_tag;
    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', 'p', 'p');
                else
                    tag = MKTAG('d', 'v', 'c', 'p');
            }
        } else {
            tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
        }
    }
    // if no mac fcc found, try with Microsoft tags
    if (!tag)
        tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
    assert(tag);
    return tag;
}

514
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
515
{
516
    offset_t pos = url_ftell(pb);
517
    char compressor_name[32];
518
    int tag;
519

520
    put_be32(pb, 0); /* size */
521

522
    tag = mov_find_video_codec_tag(track);
523
    put_le32(pb, tag); // store it byteswapped
524

525 526 527 528
    put_be32(pb, 0); /* Reserved */
    put_be16(pb, 0); /* Reserved */
    put_be16(pb, 1); /* Data-reference index */

529 530 531 532 533 534 535 536 537 538
    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 */
    }
539 540
    put_be16(pb, track->enc->width); /* Video width */
    put_be16(pb, track->enc->height); /* Video height */
541 542
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
543 544
    put_be32(pb, 0); /* Data size (= 0) */
    put_be16(pb, 1); /* Frame count (= 1) */
545

546
    memset(compressor_name,0,32);
547
    if (track->enc->codec && track->enc->codec->name)
548
        strncpy(compressor_name,track->enc->codec->name,31);
549
    put_byte(pb, strlen(compressor_name));
550
    put_buffer(pb, compressor_name, 31);
551

552 553 554 555 556 557 558
    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)
559
        mov_write_svq3_tag(pb);
560 561

    return updateSize (pb, pos);
562 563
}

564
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
565
{
566
    offset_t pos = url_ftell(pb);
567 568 569 570
    put_be32(pb, 0); /* size */
    put_tag(pb, "stsd");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */
571 572 573 574
    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);
575
    return updateSize(pb, pos);
576 577
}

578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
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
613
/* TODO: */
614
/* Time to sample atom */
615
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
616 617 618 619 620 621
{
    put_be32(pb, 0x18); /* size */
    put_tag(pb, "stts");
    put_be32(pb, 0); /* version & flags */
    put_be32(pb, 1); /* entry count */

622 623
    put_be32(pb, track->sampleCount); /* sample count */
    put_be32(pb, track->sampleDuration); /* sample duration */
624 625 626
    return 0x18;
}

627
static int mov_write_dref_tag(ByteIOContext *pb)
628 629 630 631 632 633 634 635 636 637 638 639 640
{
    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;
}

641
static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
642
{
643
    offset_t pos = url_ftell(pb);
644 645
    put_be32(pb, 0); /* size */
    put_tag(pb, "stbl");
646 647
    mov_write_stsd_tag(pb, track);
    mov_write_stts_tag(pb, track);
648 649 650
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
        track->hasKeyframes)
        mov_write_stss_tag(pb, track);
651 652 653
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
        track->hasBframes)
        mov_write_ctts_tag(pb, track);
654 655 656 657
    mov_write_stsc_tag(pb, track);
    mov_write_stsz_tag(pb, track);
    mov_write_stco_tag(pb, track);
    return updateSize(pb, pos);
658 659
}

660
static int mov_write_dinf_tag(ByteIOContext *pb)
661
{
662
    offset_t pos = url_ftell(pb);
663 664
    put_be32(pb, 0); /* size */
    put_tag(pb, "dinf");
665 666
    mov_write_dref_tag(pb);
    return updateSize(pb, pos);
667 668
}

669
static int mov_write_smhd_tag(ByteIOContext *pb)
670 671 672 673 674 675 676 677 678
{
    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;
}

679
static int mov_write_vmhd_tag(ByteIOContext *pb)
680 681 682 683 684 685 686 687
{
    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;
}

688
static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
689
{
690
    char *descr, *hdlr, *hdlr_type;
691
    offset_t pos = url_ftell(pb);
692

693
    if (!track) { /* no media --> data handler */
694 695 696
        hdlr = "dhlr";
        hdlr_type = "url ";
        descr = "DataHandler";
697
    } else {
698 699 700 701 702 703 704 705
        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";
        }
706
    }
707

708
    put_be32(pb, 0); /* size */
709 710
    put_tag(pb, "hdlr");
    put_be32(pb, 0); /* Version & flags */
711
    put_buffer(pb, hdlr, 4); /* handler */
712
    put_tag(pb, hdlr_type); /* handler type */
713 714 715
    put_be32(pb ,0); /* reserved */
    put_be32(pb ,0); /* reserved */
    put_be32(pb ,0); /* reserved */
716 717 718 719 720 721 722
    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)
{
723
    offset_t pos = url_ftell(pb);
724 725
    put_be32(pb, 0); /* size */
    put_tag(pb, "minf");
726
    if(track->enc->codec_type == CODEC_TYPE_VIDEO)
727
        mov_write_vmhd_tag(pb);
728
    else
729 730 731 732 733
        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);
734
    return updateSize(pb, pos);
735 736
}

737
static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
738 739 740 741 742 743
{
    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 */
744
    put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
745
    put_be32(pb, track->trackDuration); /* duration */
746
    put_be16(pb, track->language); /* language */
747 748 749 750
    put_be16(pb, 0); /* reserved (quality) */
    return 32;
}

751
static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
752
{
753
    offset_t pos = url_ftell(pb);
754 755
    put_be32(pb, 0); /* size */
    put_tag(pb, "mdia");
756 757 758 759
    mov_write_mdhd_tag(pb, track);
    mov_write_hdlr_tag(pb, track);
    mov_write_minf_tag(pb, track);
    return updateSize(pb, pos);
760 761
}

762
static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
763 764 765
{
    put_be32(pb, 0x5c); /* size (always 0x5c) */
    put_tag(pb, "tkhd");
766
    put_be32(pb, 0xf); /* version & flags (track enabled) */
767 768 769 770
    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
771
    put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration */
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795

    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) {
796 797 798
        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);
799
        put_be32(pb, track->enc->height*0x10000);
800 801 802 803 804 805 806 807
    }
    else {
        put_be32(pb, 0);
        put_be32(pb, 0);
    }
    return 0x5c;
}

808 809 810 811 812 813 814 815 816 817
// 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
818
    put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration   ... doesn't seem to effect psp */
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843

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

844
static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
845
{
846
    offset_t pos = url_ftell(pb);
847 848
    put_be32(pb, 0); /* size */
    put_tag(pb, "trak");
849
    mov_write_tkhd_tag(pb, track);
850
    if (track->mode == MODE_PSP)
851
        mov_write_edts_tag(pb, track);  // PSP Movies require edts box
852
    mov_write_mdia_tag(pb, track);
853
    if (track->mode == MODE_PSP)
854
        mov_write_uuid_tag_psp(pb,track);  // PSP Movies require this uuid box
855
    return updateSize(pb, pos);
856 857
}

858
#if 0
859
/* TODO: Not sorted out, but not necessary either */
860
static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
861 862 863 864 865 866 867 868 869 870 871
{
    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;
}
872
#endif