Statistics
| Branch: | Revision:

ffmpeg / libavformat / movenc.c @ 53ffdd14

History | View | Annotate | Download (39.9 KB)

1
/*
2
 * MOV, 3GP, MP4 encoder.
3
 * Copyright (c) 2003 Thomas Raivio.
4
 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>.
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
#include "avformat.h"
21
#include "avi.h"
22
#include "avio.h"
23

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

    
27
#define MOV_INDEX_CLUSTER_SIZE 16384
28
#define globalTimescale 1000
29

    
30
#define MODE_MP4 0
31
#define MODE_MOV 1
32
#define MODE_3GP 2
33

    
34
typedef struct MOVIentry {
35
    unsigned int flags, pos, size;
36
    unsigned int samplesInChunk;
37
    char         key_frame;
38
    unsigned int entries;
39
} MOVIentry;
40

    
41
typedef struct MOVIndex {
42
    int         mode;
43
    int         entry;
44
    int         mdat_size;
45
    int         ents_allocated;
46
    long        timescale;
47
    long        time;
48
    long        trackDuration;
49
    long        sampleCount;
50
    long        sampleDuration;
51
    int         hasKeyframes;
52
    int         trackID;
53
    AVCodecContext *enc;
54

    
55
    int         vosLen;
56
    uint8_t     *vosData;
57
    MOVIentry** cluster;
58
} MOVTrack;
59

    
60
typedef struct {
61
    int     mode;
62
    long    time;
63
    int     nb_streams;
64
    int     mdat_written;
65
    offset_t mdat_pos;
66
    long    timescale;
67
    MOVTrack tracks[MAX_STREAMS];
68
} MOVContext;
69

    
70
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track);
71

    
72
//FIXME supprt 64bit varaint with wide placeholders
73
static int updateSize (ByteIOContext *pb, int pos)
74
{
75
    long curpos = url_ftell(pb);
76
    url_fseek(pb, pos, SEEK_SET);
77
    put_be32(pb, curpos - pos); /* rewrite size */
78
    url_fseek(pb, curpos, SEEK_SET);
79

    
80
    return curpos - pos;
81
}
82

    
83
/* Chunk offset atom */
84
static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
85
{
86
    int i;
87
    int pos = url_ftell(pb);
88
    put_be32(pb, 0); /* size */
89
    put_tag(pb, "stco");
90
    put_be32(pb, 0); /* version & flags */
91
    put_be32(pb, track->entry); /* entry count */
92
    for (i=0; i<track->entry; i++) {
93
        int cl = i / MOV_INDEX_CLUSTER_SIZE;
94
        int id = i % MOV_INDEX_CLUSTER_SIZE;
95
        put_be32(pb, track->cluster[cl][id].pos);
96
    }
97
    return updateSize (pb, pos);
98
}
99

    
100
/* Sample size atom */
101
static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
102
{
103
    int equalChunks = 1;
104
    int i, j, entries = 0, tst = -1, oldtst = -1;
105

    
106
    int pos = url_ftell(pb);
107
    put_be32(pb, 0); /* size */
108
    put_tag(pb, "stsz");
109
    put_be32(pb, 0); /* version & flags */
110

    
111
    for (i=0; i<track->entry; i++) {
112
        int cl = i / MOV_INDEX_CLUSTER_SIZE;
113
        int id = i % MOV_INDEX_CLUSTER_SIZE;
114
        tst = track->cluster[cl][id].size/track->cluster[cl][id].entries;
115
        if(oldtst != -1 && tst != oldtst) {
116
            equalChunks = 0;
117
        }
118
        oldtst = tst;
119
        entries += track->cluster[cl][id].entries;
120
    }
121
    if (equalChunks) {
122
        int sSize = track->cluster[0][0].size/track->cluster[0][0].entries;
123
        put_be32(pb, sSize); // sample size 
124
        put_be32(pb, entries); // sample count
125
    }
126
    else {
127
        put_be32(pb, 0); // sample size 
128
        put_be32(pb, entries); // sample count 
129
        for (i=0; i<track->entry; i++) {
130
            int cl = i / MOV_INDEX_CLUSTER_SIZE;
131
            int id = i % MOV_INDEX_CLUSTER_SIZE;
132
            for ( j=0; j<track->cluster[cl][id].entries; j++) {
133
                put_be32(pb, track->cluster[cl][id].size /
134
                         track->cluster[cl][id].entries);
135
            }
136
        }
137
    }
138
    return updateSize (pb, pos);
139
}
140

    
141
/* Sample to chunk atom */
142
static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
143
{
144
    int index = 0, oldval = -1, i, entryPos, curpos;
145

    
146
    int pos = url_ftell(pb);
147
    put_be32(pb, 0); /* size */
148
    put_tag(pb, "stsc");
149
    put_be32(pb, 0); // version & flags 
150
    entryPos = url_ftell(pb);
151
    put_be32(pb, track->entry); // entry count 
152
    for (i=0; i<track->entry; i++) {
153
        int cl = i / MOV_INDEX_CLUSTER_SIZE;
154
        int id = i % MOV_INDEX_CLUSTER_SIZE;
155
        if(oldval != track->cluster[cl][id].samplesInChunk)
156
        {
157
            put_be32(pb, i+1); // first chunk 
158
            put_be32(pb, track->cluster[cl][id].samplesInChunk); // samples per chunk
159
            put_be32(pb, 0x1); // sample description index 
160
            oldval = track->cluster[cl][id].samplesInChunk;
161
            index++;
162
        }
163
    }
164
    curpos = url_ftell(pb);
165
    url_fseek(pb, entryPos, SEEK_SET);
166
    put_be32(pb, index); // rewrite size 
167
    url_fseek(pb, curpos, SEEK_SET);
168

    
169
    return updateSize (pb, pos);
170
}
171

    
172
/* Sync sample atom */
173
static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
174
{
175
    long curpos;
176
    int i, index = 0, entryPos;
177
    int pos = url_ftell(pb);
178
    put_be32(pb, 0); // size 
179
    put_tag(pb, "stss");
180
    put_be32(pb, 0); // version & flags 
181
    entryPos = url_ftell(pb);
182
    put_be32(pb, track->entry); // entry count 
183
    for (i=0; i<track->entry; i++) {
184
        int cl = i / MOV_INDEX_CLUSTER_SIZE;
185
        int id = i % MOV_INDEX_CLUSTER_SIZE;
186
        if(track->cluster[cl][id].key_frame == 1) {
187
            put_be32(pb, i+1);
188
            index++;
189
        }
190
    }
191
    curpos = url_ftell(pb);
192
    url_fseek(pb, entryPos, SEEK_SET);
193
    put_be32(pb, index); // rewrite size 
194
    url_fseek(pb, curpos, SEEK_SET);
195
    return updateSize (pb, pos);
196
}
197

    
198
static int mov_write_damr_tag(ByteIOContext *pb)
199
{
200
    put_be32(pb, 0x11); /* size */
201
    put_tag(pb, "damr");
202
    put_tag(pb, "FFMP");
203
    put_byte(pb, 0);
204

    
205
    put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */
206
    put_be16(pb, 0xa); /* Mode change period (no restriction) */
207
    //put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */
208
    //put_be16(pb, 1); /* Mode change period (no restriction) */
209
    return 0x11;
210
}
211

    
212
static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track)
213
{
214
    int pos = url_ftell(pb);
215

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

    
219
    put_be32(pb, 12);    /* size */
220
    put_tag(pb, "frma");
221
    put_tag(pb, "mp4a");
222

    
223
    put_be32(pb, 12);    /* size */
224
    put_tag(pb, "mp4a");
225
    put_be32(pb, 0);
226

    
227
    mov_write_esds_tag(pb, track);
228

    
229
    put_be32(pb, 12);    /* size */
230
    put_tag(pb, "srcq");
231
    put_be32(pb, 0x40);
232

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

    
236
    return updateSize (pb, pos);
237
}
238

    
239
const CodecTag codec_movaudio_tags[] = {
240
    { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') },
241
    { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') },
242
    { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') },
243
    { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') },
244
    { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') },
245
    { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
246
    { CODEC_ID_AMR_NB, MKTAG('s', 'a', 'm', 'r') },
247
    { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') },
248
    { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') },
249
    { CODEC_ID_MP3, MKTAG('.', 'm', 'p', '3') },
250
    { 0, 0 },
251
};
252

    
253
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
254
{
255
    int pos = url_ftell(pb);
256
    int tag;
257
    
258
    put_be32(pb, 0); /* size */
259

    
260
    tag = track->enc->codec_tag;
261
    if (!tag)
262
    tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
263
    // if no mac fcc found, try with Microsoft tags
264
    if (!tag)
265
    {
266
        int tmp = codec_get_tag(codec_wav_tags, track->enc->codec_id);
267
        tag = MKTAG('m', 's', ((tmp >> 8) & 0xff), (tmp & 0xff));
268
    }
269
    put_le32(pb, tag); // store it byteswapped
270

    
271
    put_be32(pb, 0); /* Reserved */
272
    put_be16(pb, 0); /* Reserved */
273
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
274

    
275
    /* SoundDescription */
276
    if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
277
        put_be16(pb, 1); /* Version 1 */
278
    else
279
        put_be16(pb, 0); /* Version 0 */
280
    put_be16(pb, 0); /* Revision level */
281
    put_be32(pb, 0); /* Reserved */
282

    
283
    put_be16(pb, track->enc->channels); /* Number of channels */
284
    /* TODO: Currently hard-coded to 16-bit, there doesn't seem
285
                 to be a good way to get number of bits of audio */
286
    put_be16(pb, 0x10); /* Reserved */
287

    
288
    if(track->enc->codec_id == CODEC_ID_AAC ||
289
       track->enc->codec_id == CODEC_ID_MP3)
290
    {
291
        put_be16(pb, 0xfffe); /* compression ID (vbr)*/
292
    }
293
    else
294
    {
295
        put_be16(pb, 0); /* compression ID (= 0) */
296
    }
297
    put_be16(pb, 0); /* packet size (= 0) */
298
    put_be16(pb, track->timescale); /* Time scale */
299
    put_be16(pb, 0); /* Reserved */
300

    
301
    if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
302
    {
303
        /* SoundDescription V1 extended info */
304
        put_be32(pb, track->enc->frame_size); /* Samples per packet  */
305
        put_be32(pb, 1536); /* Bytes per packet */
306
        put_be32(pb, 2); /* Bytes per frame */
307
        put_be32(pb, 2); /* Bytes per sample */
308
    }
309

    
310
    if(track->enc->codec_id == CODEC_ID_AAC) {
311
        if( track->mode == MODE_MOV ) mov_write_wave_tag(pb, track);
312
        else mov_write_esds_tag(pb, track);
313
    }
314
    if(track->enc->codec_id == CODEC_ID_AMR_NB)
315
        mov_write_damr_tag(pb);
316
    return updateSize (pb, pos);
317
}
318

    
319
static int mov_write_d263_tag(ByteIOContext *pb)
320
{
321
    put_be32(pb, 0xf); /* size */
322
    put_tag(pb, "d263");
323
    put_tag(pb, "FFMP");
324
    put_be16(pb, 0x0a);
325
    put_byte(pb, 0);
326
    return 0xf;
327
}
328

    
329
/* TODO: No idea about these values */
330
static int mov_write_svq3_tag(ByteIOContext *pb)
331
{
332
    put_be32(pb, 0x15);
333
    put_tag(pb, "SMI ");
334
    put_tag(pb, "SEQH");
335
    put_be32(pb, 0x5);
336
    put_be32(pb, 0xe2c0211d);
337
    put_be32(pb, 0xc0000000);
338
    put_byte(pb, 0);   
339
    return 0x15;
340
}
341

    
342
static unsigned int descrLength(unsigned int len)
343
{
344
    if (len < 0x00000080)
345
        return 2 + len;
346
    else if (len < 0x00004000)
347
        return 3 + len;
348
    else if(len < 0x00200000)
349
        return 4 + len;
350
    else
351
        return 5 + len;
352
}
353

    
354
static void putDescr(ByteIOContext *pb, int tag, int size)
355
{
356
    uint32_t len;
357
    uint8_t  vals[4];
358

    
359
    len = size;
360
    vals[3] = (uint8_t)(len & 0x7f);
361
    len >>= 7;
362
    vals[2] = (uint8_t)((len & 0x7f) | 0x80); 
363
    len >>= 7;
364
    vals[1] = (uint8_t)((len & 0x7f) | 0x80); 
365
    len >>= 7;
366
    vals[0] = (uint8_t)((len & 0x7f) | 0x80);
367

    
368
    put_byte(pb, tag); // DescriptorTag
369

    
370
    if (size < 0x00000080)
371
    {
372
        put_byte(pb, vals[3]);
373
    }
374
    else if (size < 0x00004000)
375
    {
376
        put_byte(pb, vals[2]);
377
        put_byte(pb, vals[3]);
378
    }
379
    else if (size < 0x00200000)
380
    {
381
        put_byte(pb, vals[1]);
382
        put_byte(pb, vals[2]);
383
        put_byte(pb, vals[3]);
384
    }
385
    else if (size < 0x10000000)
386
    {
387
        put_byte(pb, vals[0]);
388
        put_byte(pb, vals[1]);
389
        put_byte(pb, vals[2]);
390
        put_byte(pb, vals[3]);
391
    }
392
}
393

    
394
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
395
{
396
    int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
397
    int pos = url_ftell(pb);
398

    
399
    put_be32(pb, 0);               // size
400
    put_tag(pb, "esds");
401
    put_be32(pb, 0);               // Version
402

    
403
    // ES descriptor
404
    putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
405
             descrLength(1));
406
    put_be16(pb, 0x0001);          // ID (= 1)
407
    put_byte(pb, 0x00);            // flags (= no flags)
408

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

    
412
    if(track->enc->codec_id == CODEC_ID_AAC)
413
        put_byte(pb, 0x40);        // Object type indication
414
    else if(track->enc->codec_id == CODEC_ID_MPEG4)
415
        put_byte(pb, 0x20);        // Object type indication (Visual 14496-2)
416

    
417
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
418
        put_byte(pb, 0x15);            // flags (= Audiostream)
419
    else
420
        put_byte(pb, 0x11);            // flags (= Visualstream)
421

    
422
    put_byte(pb, 0x0);             // Buffersize DB (24 bits)
423
    put_be16(pb, 0x0dd2);          // Buffersize DB
424

    
425
    // TODO: find real values for these
426
    put_be32(pb, 0x0002e918);     // maxbitrate
427
    put_be32(pb, 0x00017e6b);     // avg bitrate
428

    
429
    if (track->vosLen)
430
    {
431
        // DecoderSpecific info descriptor
432
        putDescr(pb, 0x05, track->vosLen);
433
        put_buffer(pb, track->vosData, track->vosLen);
434
    }
435

    
436
    // SL descriptor
437
    putDescr(pb, 0x06, 1);
438
    put_byte(pb, 0x02);
439
    return updateSize (pb, pos);
440
}
441

    
442
const CodecTag codec_movvideo_tags[] = {
443
    { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') },
444
    { CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') },
445
    { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
446
    { CODEC_ID_H263, MKTAG('s', '2', '6', '3') },
447
    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') },
448
    { 0, 0 },
449
};
450

    
451
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
452
{
453
    int pos = url_ftell(pb);
454
    char compressor_name[32];
455
    int tag;
456

    
457
    put_be32(pb, 0); /* size */
458

    
459
    tag = track->enc->codec_tag;
460
    if (!tag)
461
    tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
462
    // if no mac fcc found, try with Microsoft tags
463
    if (!tag)
464
        tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
465
    put_le32(pb, tag); // store it byteswapped
466

    
467
    put_be32(pb, 0); /* Reserved */
468
    put_be16(pb, 0); /* Reserved */
469
    put_be16(pb, 1); /* Data-reference index */
470

    
471
    put_be16(pb, 0); /* Codec stream version */
472
    put_be16(pb, 0); /* Codec stream revision (=0) */
473
    put_tag(pb, "FFMP"); /* Vendor */
474
    if(track->enc->codec_id == CODEC_ID_RAWVIDEO) {
475
        put_be32(pb, 0); /* Temporal Quality */
476
        put_be32(pb, 0x400); /* Spatial Quality = lossless*/
477
    } else {
478
        put_be32(pb, 0x200); /* Temporal Quality = normal */
479
        put_be32(pb, 0x200); /* Spatial Quality = normal */
480
    }
481
    put_be16(pb, track->enc->width); /* Video width */
482
    put_be16(pb, track->enc->height); /* Video height */
483
    put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
484
    put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
485
    put_be32(pb, 0); /* Data size (= 0) */
486
    put_be16(pb, 1); /* Frame count (= 1) */
487
    
488
    memset(compressor_name,0,32);
489
    if (track->enc->codec->name)
490
        strncpy(compressor_name,track->enc->codec->name,31);
491
    put_byte(pb, FFMAX(strlen(compressor_name),32) );
492
    put_buffer(pb, compressor_name, 31);
493
    
494
    put_be16(pb, 0x18); /* Reserved */
495
    put_be16(pb, 0xffff); /* Reserved */
496
    if(track->enc->codec_id == CODEC_ID_MPEG4)
497
        mov_write_esds_tag(pb, track);
498
    else if(track->enc->codec_id == CODEC_ID_H263)
499
        mov_write_d263_tag(pb);
500
    else if(track->enc->codec_id == CODEC_ID_SVQ3)
501
        mov_write_svq3_tag(pb);    
502

    
503
    return updateSize (pb, pos);
504
}
505

    
506
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
507
{
508
    int pos = url_ftell(pb);
509
    put_be32(pb, 0); /* size */
510
    put_tag(pb, "stsd");
511
    put_be32(pb, 0); /* version & flags */
512
    put_be32(pb, 1); /* entry count */
513
    if (track->enc->codec_type == CODEC_TYPE_VIDEO)
514
        mov_write_video_tag(pb, track);
515
    else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
516
        mov_write_audio_tag(pb, track);
517
    return updateSize(pb, pos);
518
}
519

    
520
/* TODO?: Currently all samples/frames seem to have same duration */
521
/* Time to sample atom */
522
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
523
{
524
    put_be32(pb, 0x18); /* size */
525
    put_tag(pb, "stts");
526
    put_be32(pb, 0); /* version & flags */
527
    put_be32(pb, 1); /* entry count */
528

    
529
    put_be32(pb, track->sampleCount); /* sample count */
530
    put_be32(pb, track->sampleDuration); /* sample duration */
531
    return 0x18;
532
}
533

    
534
static int mov_write_dref_tag(ByteIOContext *pb)
535
{
536
    put_be32(pb, 28); /* size */
537
    put_tag(pb, "dref");
538
    put_be32(pb, 0); /* version & flags */
539
    put_be32(pb, 1); /* entry count */
540

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

    
545
    return 28;
546
}
547

    
548
static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
549
{
550
    int pos = url_ftell(pb);
551
    put_be32(pb, 0); /* size */
552
    put_tag(pb, "stbl");
553
    mov_write_stsd_tag(pb, track);
554
    mov_write_stts_tag(pb, track);
555
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
556
        track->hasKeyframes)
557
        mov_write_stss_tag(pb, track);
558
    mov_write_stsc_tag(pb, track);
559
    mov_write_stsz_tag(pb, track);
560
    mov_write_stco_tag(pb, track);
561
    return updateSize(pb, pos);
562
}
563

    
564
static int mov_write_dinf_tag(ByteIOContext *pb)
565
{
566
    int pos = url_ftell(pb);
567
    put_be32(pb, 0); /* size */
568
    put_tag(pb, "dinf");
569
    mov_write_dref_tag(pb);
570
    return updateSize(pb, pos);
571
}
572

    
573
static int mov_write_smhd_tag(ByteIOContext *pb)
574
{
575
    put_be32(pb, 16); /* size */
576
    put_tag(pb, "smhd");
577
    put_be32(pb, 0); /* version & flags */
578
    put_be16(pb, 0); /* reserved (balance, normally = 0) */
579
    put_be16(pb, 0); /* reserved */
580
    return 16;
581
}
582

    
583
static int mov_write_vmhd_tag(ByteIOContext *pb)
584
{
585
    put_be32(pb, 0x14); /* size (always 0x14) */
586
    put_tag(pb, "vmhd");
587
    put_be32(pb, 0x01); /* version & flags */
588
    put_be64(pb, 0); /* reserved (graphics mode = copy) */
589
    return 0x14;
590
}
591

    
592
static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
593
{
594
    char *descr, *hdlr, *hdlr_type;
595
    int pos = url_ftell(pb);
596
    
597
    if (!track) { /* no media --> data handler */
598
        hdlr = "dhlr";
599
        hdlr_type = "url ";
600
        descr = "DataHandler";
601
    } else {
602
        hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
603
        if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
604
            hdlr_type = "vide";
605
            descr = "VideoHandler";
606
        } else {
607
            hdlr_type = "soun";
608
            descr = "SoundHandler";
609
        }
610
    }
611
    
612
    put_be32(pb, 0); /* size */
613
    put_tag(pb, "hdlr");
614
    put_be32(pb, 0); /* Version & flags */
615
    put_buffer(pb, hdlr, 4); /* handler */
616
    put_tag(pb, hdlr_type); /* handler type */
617
    put_be32(pb ,0); /* reserved */
618
    put_be32(pb ,0); /* reserved */
619
    put_be32(pb ,0); /* reserved */
620
    put_byte(pb, strlen(descr)); /* string counter */
621
    put_buffer(pb, descr, strlen(descr)); /* handler description */
622
    return updateSize(pb, pos);
623
}
624

    
625
static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
626
{
627
    int pos = url_ftell(pb);
628
    put_be32(pb, 0); /* size */
629
    put_tag(pb, "minf");
630
    if(track->enc->codec_type == CODEC_TYPE_VIDEO)
631
        mov_write_vmhd_tag(pb);
632
    else
633
        mov_write_smhd_tag(pb);
634
    if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
635
        mov_write_hdlr_tag(pb, NULL);
636
    mov_write_dinf_tag(pb);
637
    mov_write_stbl_tag(pb, track);
638
    return updateSize(pb, pos);
639
}
640

    
641
static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
642
{
643
    put_be32(pb, 32); /* size */
644
    put_tag(pb, "mdhd");
645
    put_be32(pb, 0); /* Version & flags */
646
    put_be32(pb, track->time); /* creation time */
647
    put_be32(pb, track->time); /* modification time */
648
    put_be32(pb, track->timescale); /* time scale (sample rate for audio) */ 
649
    put_be32(pb, track->trackDuration); /* duration */
650
    put_be16(pb, 0); /* language, 0 = english */
651
    put_be16(pb, 0); /* reserved (quality) */
652
    return 32;
653
}
654

    
655
static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
656
{
657
    int pos = url_ftell(pb);
658
    put_be32(pb, 0); /* size */
659
    put_tag(pb, "mdia");
660
    mov_write_mdhd_tag(pb, track);
661
    mov_write_hdlr_tag(pb, track);
662
    mov_write_minf_tag(pb, track);
663
    return updateSize(pb, pos);
664
}
665

    
666
static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
667
{
668
    int64_t maxTrackLenTemp;
669
    put_be32(pb, 0x5c); /* size (always 0x5c) */
670
    put_tag(pb, "tkhd");
671
    put_be32(pb, 0xf); /* version & flags (track enabled) */
672
    put_be32(pb, track->time); /* creation time */
673
    put_be32(pb, track->time); /* modification time */
674
    put_be32(pb, track->trackID); /* track-id */
675
    put_be32(pb, 0); /* reserved */
676
    maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale;
677
    put_be32(pb, (long)maxTrackLenTemp); /* duration */
678

    
679
    put_be32(pb, 0); /* reserved */
680
    put_be32(pb, 0); /* reserved */
681
    put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
682
    /* Volume, only for audio */
683
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
684
        put_be16(pb, 0x0100);
685
    else
686
        put_be16(pb, 0);
687
    put_be16(pb, 0); /* reserved */
688

    
689
    /* Matrix structure */
690
    put_be32(pb, 0x00010000); /* reserved */
691
    put_be32(pb, 0x0); /* reserved */
692
    put_be32(pb, 0x0); /* reserved */
693
    put_be32(pb, 0x0); /* reserved */
694
    put_be32(pb, 0x00010000); /* reserved */
695
    put_be32(pb, 0x0); /* reserved */
696
    put_be32(pb, 0x0); /* reserved */
697
    put_be32(pb, 0x0); /* reserved */
698
    put_be32(pb, 0x40000000); /* reserved */
699

    
700
    /* Track width and height, for visual only */
701
    if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
702
        double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio);
703
        if( !sample_aspect_ratio ) sample_aspect_ratio = 1;
704
        put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
705
        put_be32(pb, track->enc->height*0x10000);
706
    }
707
    else {
708
        put_be32(pb, 0);
709
        put_be32(pb, 0);
710
    }
711
    return 0x5c;
712
}
713

    
714
static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
715
{
716
    int pos = url_ftell(pb);
717
    put_be32(pb, 0); /* size */
718
    put_tag(pb, "trak");
719
    mov_write_tkhd_tag(pb, track);
720
    mov_write_mdia_tag(pb, track);
721
    return updateSize(pb, pos);
722
}
723

    
724
/* TODO: Not sorted out, but not necessary either */
725
static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
726
{
727
    put_be32(pb, 0x15); /* size */
728
    put_tag(pb, "iods");
729
    put_be32(pb, 0);    /* version & flags */
730
    put_be16(pb, 0x1007);
731
    put_byte(pb, 0);
732
    put_be16(pb, 0x4fff);
733
    put_be16(pb, 0xfffe);
734
    put_be16(pb, 0x01ff);
735
    return 0x15;
736
}
737

    
738
static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
739
{
740
    int maxTrackID = 1, maxTrackLen = 0, i;
741
    int64_t maxTrackLenTemp;
742

    
743
    put_be32(pb, 0x6c); /* size (always 0x6c) */
744
    put_tag(pb, "mvhd");
745
    put_be32(pb, 0); /* version & flags */
746
    put_be32(pb, mov->time); /* creation time */
747
    put_be32(pb, mov->time); /* modification time */
748
    put_be32(pb, mov->timescale); /* timescale */
749
    for (i=0; i<MAX_STREAMS; i++) {
750
        if(mov->tracks[i].entry > 0) {
751
            maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale;
752
            if(maxTrackLen < maxTrackLenTemp)
753
                maxTrackLen = maxTrackLenTemp;
754
            if(maxTrackID < mov->tracks[i].trackID)
755
                maxTrackID = mov->tracks[i].trackID;
756
        }
757
    }
758
    put_be32(pb, maxTrackLen); /* duration of longest track */
759

    
760
    put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
761
    put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
762
    put_be16(pb, 0); /* reserved */
763
    put_be32(pb, 0); /* reserved */
764
    put_be32(pb, 0); /* reserved */
765

    
766
    /* Matrix structure */
767
    put_be32(pb, 0x00010000); /* reserved */
768
    put_be32(pb, 0x0); /* reserved */
769
    put_be32(pb, 0x0); /* reserved */
770
    put_be32(pb, 0x0); /* reserved */
771
    put_be32(pb, 0x00010000); /* reserved */
772
    put_be32(pb, 0x0); /* reserved */
773
    put_be32(pb, 0x0); /* reserved */
774
    put_be32(pb, 0x0); /* reserved */
775
    put_be32(pb, 0x40000000); /* reserved */
776

    
777
    put_be32(pb, 0); /* reserved (preview time) */
778
    put_be32(pb, 0); /* reserved (preview duration) */
779
    put_be32(pb, 0); /* reserved (poster time) */
780
    put_be32(pb, 0); /* reserved (selection time) */
781
    put_be32(pb, 0); /* reserved (selection duration) */
782
    put_be32(pb, 0); /* reserved (current time) */
783
    put_be32(pb, maxTrackID+1); /* Next track id */
784
    return 0x6c;
785
}
786

    
787
static int mov_write_itunes_hdlr_tag(ByteIOContext *pb, MOVContext* mov,
788
                                     AVFormatContext *s)
789
{
790
    int pos = url_ftell(pb);
791
    put_be32(pb, 0); /* size */
792
    put_tag(pb, "hdlr");
793
    put_be32(pb, 0);
794
    put_be32(pb, 0);
795
    put_tag(pb, "mdir");
796
    put_tag(pb, "appl");
797
    put_be32(pb, 0);
798
    put_be32(pb, 0);
799
    put_be16(pb, 0);
800
    return updateSize(pb, pos);
801
}
802

    
803
/* helper function to write a data tag with the specified string as data */
804
static int mov_write_string_data_tag(ByteIOContext *pb, MOVContext* mov,
805
                                     AVFormatContext *s, const char *data)
806
{
807
    int pos = url_ftell(pb);
808
    put_be32(pb, 0); /* size */
809
    put_tag(pb, "data");
810
    put_be32(pb, 1);
811
    put_be32(pb, 0);
812
    put_buffer(pb, data, strlen(data));
813
    return updateSize(pb, pos);
814
}
815

    
816
/* iTunes name of the song/movie */
817
static int mov_write_nam_tag(ByteIOContext *pb, MOVContext* mov,
818
                             AVFormatContext *s)
819
{
820
    int size = 0;
821
    if ( s->title[0] ) {
822
        int pos = url_ftell(pb);
823
        put_be32(pb, 0); /* size */
824
        put_tag(pb, "\251nam");
825
        mov_write_string_data_tag(pb, mov, s, s->title);
826
        size = updateSize(pb, pos);
827
    }
828
    return size;
829
}
830

    
831
/* iTunes name of the artist/performer */
832
static int mov_write_ART_tag(ByteIOContext *pb, MOVContext* mov,
833
                             AVFormatContext *s)
834
{
835
    int size = 0;
836
    if ( s->author[0] ) {
837
        int pos = url_ftell(pb);
838
        put_be32(pb, 0); /* size */
839
        put_tag(pb, "\251ART");
840
        // we use the author here as this is the only thing that we have...
841
        mov_write_string_data_tag(pb, mov, s, s->author);
842
        size = updateSize(pb, pos);
843
    }
844
    return size;
845
}
846

    
847
/* iTunes name of the writer */
848
static int mov_write_wrt_tag(ByteIOContext *pb, MOVContext* mov,
849
                             AVFormatContext *s)
850
{
851
    int size = 0;
852
    if ( s->author[0] ) {
853
        int pos = url_ftell(pb);
854
        put_be32(pb, 0); /* size */
855
        put_tag(pb, "\251wrt");
856
        mov_write_string_data_tag(pb, mov, s, s->author);
857
        size = updateSize(pb, pos);
858
    }
859
    return size;
860
}
861

    
862
/* iTunes name of the album */
863
static int mov_write_alb_tag(ByteIOContext *pb, MOVContext* mov,
864
                             AVFormatContext *s)
865
{
866
    int size = 0;
867
    if ( s->album[0] ) {
868
        int pos = url_ftell(pb);
869
        put_be32(pb, 0); /* size */
870
        put_tag(pb, "\251alb");
871
        mov_write_string_data_tag(pb, mov, s, s->album);
872
        size = updateSize(pb, pos);
873
    }
874
    return size;
875
}
876

    
877
/* iTunes year */
878
static int mov_write_day_tag(ByteIOContext *pb, MOVContext* mov,
879
                             AVFormatContext *s)
880
{
881
    char year[5];
882
    int size = 0;
883
    if ( s->year ) {
884
        int pos = url_ftell(pb);
885
        put_be32(pb, 0); /* size */
886
        put_tag(pb, "\251day");
887
        snprintf(year, 5, "%04d", s->year);
888
        mov_write_string_data_tag(pb, mov, s, year);
889
        size = updateSize(pb, pos);
890
    }
891
    return size;
892
}
893

    
894
/* iTunes tool used to create the file */
895
static int mov_write_too_tag(ByteIOContext *pb, MOVContext* mov,
896
                             AVFormatContext *s)
897
{
898
    int pos = url_ftell(pb);
899
    put_be32(pb, 0); /* size */
900
    put_tag(pb, "\251too");
901
    mov_write_string_data_tag(pb, mov, s, LIBAVFORMAT_IDENT);
902
    return updateSize(pb, pos);
903
}
904

    
905
/* iTunes comment */
906
static int mov_write_cmt_tag(ByteIOContext *pb, MOVContext* mov,
907
                             AVFormatContext *s)
908
{
909
    int size = 0;
910
    if ( s->comment[0] ) {
911
        int pos = url_ftell(pb);
912
        put_be32(pb, 0); /* size */
913
        put_tag(pb, "\251cmt");
914
        mov_write_string_data_tag(pb, mov, s, s->comment);
915
        size = updateSize(pb, pos);
916
    }
917
    return size;
918
}
919

    
920
/* iTunes custom genre */
921
static int mov_write_gen_tag(ByteIOContext *pb, MOVContext* mov,
922
                             AVFormatContext *s)
923
{
924
    int size = 0;
925
    if ( s->genre[0] ) {
926
        int pos = url_ftell(pb);
927
        put_be32(pb, 0); /* size */
928
        put_tag(pb, "\251gen");
929
        mov_write_string_data_tag(pb, mov, s, s->genre);
930
        size = updateSize(pb, pos);
931
    }
932
    return size;
933
}
934

    
935
/* iTunes track number */
936
static int mov_write_trkn_tag(ByteIOContext *pb, MOVContext* mov,
937
                              AVFormatContext *s)
938
{
939
    int size = 0;
940
    if ( s->track ) {
941
        int pos = url_ftell(pb);
942
        put_be32(pb, 0); /* size */
943
        put_tag(pb, "trkn");
944
        {
945
            int pos = url_ftell(pb);
946
            put_be32(pb, 0); /* size */
947
            put_tag(pb, "data");
948
            put_be32(pb, 0);        // 8 bytes empty
949
            put_be32(pb, 0);
950
            put_be16(pb, 0);        // empty
951
            put_be16(pb, s->track); // track number
952
            put_be16(pb, 0);        // total track number
953
            put_be16(pb, 0);        // empty
954
            updateSize(pb, pos);
955
        }
956
        size = updateSize(pb, pos);
957
    }
958
    return size;
959
}
960

    
961
/* iTunes meta data list */
962
static int mov_write_ilst_tag(ByteIOContext *pb, MOVContext* mov,
963
                              AVFormatContext *s)
964
{
965
    int pos = url_ftell(pb);
966
    put_be32(pb, 0); /* size */
967
    put_tag(pb, "ilst");
968
    mov_write_nam_tag(pb, mov, s);
969
    mov_write_ART_tag(pb, mov, s);
970
    mov_write_wrt_tag(pb, mov, s);
971
    mov_write_alb_tag(pb, mov, s);
972
    mov_write_day_tag(pb, mov, s);
973
    mov_write_too_tag(pb, mov, s);
974
    mov_write_cmt_tag(pb, mov, s);
975
    mov_write_gen_tag(pb, mov, s);
976
    mov_write_trkn_tag(pb, mov, s);
977
    return updateSize(pb, pos);
978
}
979

    
980
/* iTunes meta data tag */
981
static int mov_write_meta_tag(ByteIOContext *pb, MOVContext* mov,
982
                              AVFormatContext *s)
983
{
984
    int size = 0;
985

    
986
    // only save meta tag if required
987
    if ( s->title[0] || s->author[0] || s->album[0] || s->year || 
988
         s->comment[0] || s->genre[0] || s->track ) {
989
        int pos = url_ftell(pb);
990
        put_be32(pb, 0); /* size */
991
        put_tag(pb, "meta");
992
        put_be32(pb, 0);
993
        mov_write_itunes_hdlr_tag(pb, mov, s);
994
        mov_write_ilst_tag(pb, mov, s);
995
        size = updateSize(pb, pos);
996
    }
997
    return size;
998
}
999
    
1000
static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov,
1001
                              AVFormatContext *s)
1002
{
1003
    int pos = url_ftell(pb);
1004
    int i;
1005

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

    
1009
    /* iTunes meta data */
1010
    mov_write_meta_tag(pb, mov, s);
1011

    
1012
    /* Requirements */
1013
    for (i=0; i<MAX_STREAMS; i++) {
1014
        if(mov->tracks[i].entry <= 0) continue;
1015
        if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC ||
1016
            mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) {
1017
            int pos = url_ftell(pb);
1018
            put_be32(pb, 0); /* size */
1019
            put_tag(pb, "\251req");
1020
            put_be16(pb, sizeof("QuickTime 6.0 or greater") - 1);
1021
            put_be16(pb, 0);
1022
            put_buffer(pb, "QuickTime 6.0 or greater",
1023
                       sizeof("QuickTime 6.0 or greater") - 1);
1024
            updateSize(pb, pos);
1025
            break;
1026
        }
1027
    }
1028

    
1029
    /* Encoder */
1030
    if(!(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT))
1031
    {
1032
        int pos = url_ftell(pb);
1033
        put_be32(pb, 0); /* size */
1034
        put_tag(pb, "\251enc");
1035
        put_be16(pb, sizeof(LIBAVFORMAT_IDENT) - 1); /* string length */
1036
        put_be16(pb, 0);
1037
        put_buffer(pb, LIBAVFORMAT_IDENT, sizeof(LIBAVFORMAT_IDENT) - 1);
1038
        updateSize(pb, pos);
1039
    }
1040

    
1041
    if( s->title[0] )
1042
    {
1043
        int pos = url_ftell(pb);
1044
        put_be32(pb, 0); /* size */
1045
        put_tag(pb, "\251nam");
1046
        put_be16(pb, strlen(s->title)); /* string length */
1047
        put_be16(pb, 0);
1048
        put_buffer(pb, s->title, strlen(s->title));
1049
        updateSize(pb, pos);
1050
    }
1051

    
1052
    if( s->author[0] )
1053
    {
1054
        int pos = url_ftell(pb);
1055
        put_be32(pb, 0); /* size */
1056
        put_tag(pb, /*"\251aut"*/ "\251day" );
1057
        put_be16(pb, strlen(s->author)); /* string length */
1058
        put_be16(pb, 0);
1059
        put_buffer(pb, s->author, strlen(s->author));
1060
        updateSize(pb, pos);
1061
    }
1062

    
1063
    if( s->comment[0] )
1064
    {
1065
        int pos = url_ftell(pb);
1066
        put_be32(pb, 0); /* size */
1067
        put_tag(pb, "\251des");
1068
        put_be16(pb, strlen(s->comment)); /* string length */
1069
        put_be16(pb, 0);
1070
        put_buffer(pb, s->comment, strlen(s->comment));
1071
        updateSize(pb, pos);
1072
    }
1073

    
1074
    return updateSize(pb, pos);
1075
}
1076

    
1077
static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov,
1078
                              AVFormatContext *s)
1079
{
1080
    int pos, i;
1081
    pos = url_ftell(pb);
1082
    put_be32(pb, 0); /* size placeholder*/
1083
    put_tag(pb, "moov");
1084
    mov->timescale = globalTimescale;
1085

    
1086
    for (i=0; i<MAX_STREAMS; i++) {
1087
        if(mov->tracks[i].entry <= 0) continue;
1088

    
1089
        if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
1090
            mov->tracks[i].timescale = mov->tracks[i].enc->frame_rate;
1091
            mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_rate_base;
1092
        }
1093
        else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
1094
            /* If AMR, track timescale = 8000, AMR_WB = 16000 */
1095
            if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
1096
                mov->tracks[i].sampleDuration = 160;  // Bytes per chunk
1097
                mov->tracks[i].timescale = 8000;
1098
            }
1099
            else {
1100
                mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
1101
                mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size;
1102
            }
1103
        }
1104

    
1105
        mov->tracks[i].trackDuration = 
1106
            mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration;
1107
        mov->tracks[i].time = mov->time;
1108
        mov->tracks[i].trackID = i+1;
1109
    }
1110

    
1111
    mov_write_mvhd_tag(pb, mov);
1112
    //mov_write_iods_tag(pb, mov);
1113
    for (i=0; i<MAX_STREAMS; i++) {
1114
        if(mov->tracks[i].entry > 0) {
1115
            mov_write_trak_tag(pb, &(mov->tracks[i]));
1116
        }
1117
    }
1118

    
1119
    mov_write_udta_tag(pb, mov, s);
1120

    
1121
    return updateSize(pb, pos);
1122
}
1123

    
1124
int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
1125
{
1126
    mov->mdat_pos = url_ftell(pb); 
1127
    put_be32(pb, 0); /* size placeholder*/
1128
    put_tag(pb, "mdat");
1129
    return 0;
1130
}
1131

    
1132
/* TODO: This needs to be more general */
1133
int mov_write_ftyp_tag(ByteIOContext *pb, AVFormatContext *s)
1134
{
1135
    MOVContext *mov = s->priv_data;
1136

    
1137
    put_be32(pb, 0x14 ); /* size */
1138
    put_tag(pb, "ftyp");
1139

    
1140
    if ( mov->mode == MODE_3GP )
1141
        put_tag(pb, "3gp4");
1142
    else
1143
        put_tag(pb, "isom");
1144

    
1145
    put_be32(pb, 0x200 );
1146

    
1147
    if ( mov->mode == MODE_3GP )
1148
        put_tag(pb, "3gp4");
1149
    else
1150
        put_tag(pb, "mp41");
1151

    
1152
    return 0x14;
1153
}
1154

    
1155
static int mov_write_header(AVFormatContext *s)
1156
{
1157
    ByteIOContext *pb = &s->pb;
1158
    MOVContext *mov = s->priv_data;
1159
    int i;
1160

    
1161
    for(i=0; i<s->nb_streams; i++){
1162
        AVCodecContext *c= &s->streams[i]->codec;
1163

    
1164
        if      (c->codec_type == CODEC_TYPE_VIDEO){
1165
            if (!codec_get_tag(codec_movvideo_tags, c->codec_id)){
1166
                if(!codec_get_tag(codec_bmp_tags, c->codec_id))
1167
                    return -1;
1168
                else
1169
                    av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, the file may be unplayable!\n");
1170
            }
1171
        }else if(c->codec_type == CODEC_TYPE_AUDIO){
1172
            if (!codec_get_tag(codec_movaudio_tags, c->codec_id)){
1173
                if(!codec_get_tag(codec_wav_tags, c->codec_id))
1174
                    return -1;
1175
                else
1176
                    av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, the file may be unplayable!\n");
1177
            }
1178
        }
1179
    }
1180

    
1181
    /* Default mode == MP4 */
1182
    mov->mode = MODE_MP4;
1183

    
1184
    if (s->oformat != NULL) {
1185
        if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
1186
        else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
1187

    
1188
        if ( mov->mode == MODE_3GP || mov->mode == MODE_MP4 )
1189
            mov_write_ftyp_tag(pb,s);
1190
    }
1191

    
1192
    for (i=0; i<MAX_STREAMS; i++) {
1193
        mov->tracks[i].mode = mov->mode;
1194
    }
1195

    
1196
    put_flush_packet(pb);
1197

    
1198
    return 0;
1199
}
1200

    
1201
static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
1202
{
1203
    MOVContext *mov = s->priv_data;
1204
    ByteIOContext *pb = &s->pb;
1205
    AVCodecContext *enc = &s->streams[pkt->stream_index]->codec;
1206
    MOVTrack* trk = &mov->tracks[pkt->stream_index];
1207
    int cl, id;
1208
    unsigned int samplesInChunk = 0;
1209
    int size= pkt->size;
1210

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

    
1214
    if (enc->codec_type == CODEC_TYPE_VIDEO ) {
1215
        samplesInChunk = 1;
1216
    }
1217
    else if (enc->codec_type == CODEC_TYPE_AUDIO ) {
1218
        if( enc->codec_id == CODEC_ID_AMR_NB) {
1219
            /* We must find out how many AMR blocks there are in one packet */
1220
            static uint16_t packed_size[16] =
1221
                {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
1222
            int len = 0;
1223

    
1224
            while (len < size && samplesInChunk < 100) {
1225
                len += packed_size[(pkt->data[len] >> 3) & 0x0F];
1226
                samplesInChunk++;
1227
            }
1228
        }
1229
        else if(enc->codec_id == CODEC_ID_PCM_ALAW) {
1230
            samplesInChunk = size/enc->channels;
1231
        }
1232
        else if(enc->codec_id == CODEC_ID_PCM_S16BE || enc->codec_id == CODEC_ID_PCM_S16LE) {
1233
            samplesInChunk = size/(2*enc->channels);
1234
        }            
1235
        else {
1236
            samplesInChunk = 1;
1237
        }
1238
    }
1239

    
1240
    if ((enc->codec_id == CODEC_ID_MPEG4 || enc->codec_id == CODEC_ID_AAC)
1241
        && trk->vosLen == 0) {
1242
//        assert(enc->extradata_size);
1243

    
1244
        trk->vosLen = enc->extradata_size;
1245
        trk->vosData = av_malloc(trk->vosLen);
1246
        memcpy(trk->vosData, enc->extradata, trk->vosLen);
1247
    }
1248

    
1249
    cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
1250
    id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
1251

    
1252
    if (trk->ents_allocated <= trk->entry) {
1253
        trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*)); 
1254
        if (!trk->cluster)
1255
            return -1;
1256
        trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
1257
        if (!trk->cluster[cl])
1258
            return -1;
1259
        trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
1260
    }
1261
    if (mov->mdat_written == 0) {
1262
        mov_write_mdat_tag(pb, mov);
1263
        mov->mdat_written = 1;
1264
        mov->time = s->timestamp;
1265
    }
1266

    
1267
    trk->cluster[cl][id].pos = url_ftell(pb);
1268
    trk->cluster[cl][id].samplesInChunk = samplesInChunk;
1269
    trk->cluster[cl][id].size = size;
1270
    trk->cluster[cl][id].entries = samplesInChunk;
1271
    if(enc->codec_type == CODEC_TYPE_VIDEO) {
1272
        trk->cluster[cl][id].key_frame = !!(pkt->flags & PKT_FLAG_KEY);
1273
        if(trk->cluster[cl][id].key_frame)
1274
            trk->hasKeyframes = 1;
1275
    }
1276
    trk->enc = enc;
1277
    trk->entry++;
1278
    trk->sampleCount += samplesInChunk;
1279
    trk->mdat_size += size;
1280

    
1281
    put_buffer(pb, pkt->data, size);
1282

    
1283
    put_flush_packet(pb);
1284
    return 0;
1285
}
1286

    
1287
static int mov_write_trailer(AVFormatContext *s)
1288
{
1289
    MOVContext *mov = s->priv_data;
1290
    ByteIOContext *pb = &s->pb;
1291
    int res = 0;
1292
    int i, j;
1293

    
1294
    offset_t moov_pos = url_ftell(pb);
1295

    
1296
    /* Write size of mdat tag */
1297
    for (i=0, j=0; i<MAX_STREAMS; i++) {
1298
        if(mov->tracks[i].ents_allocated > 0) {
1299
            j += mov->tracks[i].mdat_size;
1300
        }
1301
    }
1302
    url_fseek(pb, mov->mdat_pos, SEEK_SET);
1303
    put_be32(pb, j+8);
1304
    url_fseek(pb, moov_pos, SEEK_SET);
1305

    
1306
    mov_write_moov_tag(pb, mov, s);
1307

    
1308
    for (i=0; i<MAX_STREAMS; i++) {
1309
        for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
1310
            av_free(mov->tracks[i].cluster[j]);
1311
        }
1312
        av_free(mov->tracks[i].cluster);
1313
        if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData );
1314

    
1315
        mov->tracks[i].cluster = NULL;
1316
        mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
1317
    }
1318

    
1319
    put_flush_packet(pb);
1320

    
1321
    return res;
1322
}
1323

    
1324
static AVOutputFormat mov_oformat = {
1325
    "mov",
1326
    "mov format",
1327
    NULL,
1328
    "mov",
1329
    sizeof(MOVContext),
1330
    CODEC_ID_AAC,
1331
    CODEC_ID_MPEG4,
1332
    mov_write_header,
1333
    mov_write_packet,
1334
    mov_write_trailer,
1335
};
1336

    
1337
static AVOutputFormat _3gp_oformat = {
1338
    "3gp",
1339
    "3gp format",
1340
    NULL,
1341
    "3gp",
1342
    sizeof(MOVContext),
1343
    CODEC_ID_AMR_NB,
1344
    CODEC_ID_H263,
1345
    mov_write_header,
1346
    mov_write_packet,
1347
    mov_write_trailer,
1348
};
1349

    
1350
static AVOutputFormat mp4_oformat = {
1351
    "mp4",
1352
    "mp4 format",
1353
    "application/mp4",
1354
    "mp4,m4a",
1355
    sizeof(MOVContext),
1356
    CODEC_ID_AAC,
1357
    CODEC_ID_MPEG4,
1358
    mov_write_header,
1359
    mov_write_packet,
1360
    mov_write_trailer,
1361
};
1362

    
1363
int movenc_init(void)
1364
{
1365
    av_register_output_format(&mov_oformat);
1366
    av_register_output_format(&_3gp_oformat);
1367
    av_register_output_format(&mp4_oformat);
1368
    return 0;
1369
}