Statistics
| Branch: | Revision:

ffmpeg / libavformat / movenc.c @ 5a757507

History | View | Annotate | Download (32.3 KB)

1 1cb5f7fd Michael Niedermayer
/*
2
 * MOV, 3GP, MP4 encoder.
3
 * Copyright (c) 2003 Thomas Raivio.
4 69dde1ad Gildas Bazin
 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>.
5 1cb5f7fd Michael Niedermayer
 *
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 f578f938 Thomas Raivio
#include "avi.h"
22 1cb5f7fd Michael Niedermayer
#include "avio.h"
23
24 6e6d6dc0 Michael Niedermayer
#undef NDEBUG
25
#include <assert.h>
26
27 1cb5f7fd Michael Niedermayer
#define MOV_INDEX_CLUSTER_SIZE 16384
28
#define globalTimescale 1000
29
30 69dde1ad Gildas Bazin
#define MODE_MP4 0
31
#define MODE_MOV 1
32
#define MODE_3GP 2
33
34 1cb5f7fd Michael Niedermayer
typedef struct MOVIentry {
35 e45ccf79 Gildas Bazin
    unsigned int flags, pos, size;
36
    unsigned int samplesInChunk;
37 f578f938 Thomas Raivio
    char         key_frame;
38 1cb5f7fd Michael Niedermayer
    unsigned int entries;
39
} MOVIentry;
40
41
typedef struct MOVIndex {
42 69dde1ad Gildas Bazin
    int         mode;
43 1cb5f7fd Michael Niedermayer
    int         entry;
44
    int         mdat_size;
45
    int         ents_allocated;
46
    long        timescale;
47
    long        time;
48 f578f938 Thomas Raivio
    long        trackDuration;
49 e45ccf79 Gildas Bazin
    long        sampleCount;
50
    long        sampleDuration;
51 f578f938 Thomas Raivio
    int         hasKeyframes;
52 1cb5f7fd Michael Niedermayer
    int         trackID;
53
    AVCodecContext *enc;
54
55
    int         vosLen;
56 6e6d6dc0 Michael Niedermayer
    uint8_t     *vosData;
57 1cb5f7fd Michael Niedermayer
    MOVIentry** cluster;
58
} MOVTrack;
59
60
typedef struct {
61 69dde1ad Gildas Bazin
    int     mode;
62 1cb5f7fd Michael Niedermayer
    long    time;
63
    int     nb_streams;
64 f578f938 Thomas Raivio
    int     mdat_written;
65
    offset_t mdat_pos;
66 1cb5f7fd Michael Niedermayer
    long    timescale;
67
    MOVTrack tracks[MAX_STREAMS];
68
} MOVContext;
69
70 e45ccf79 Gildas Bazin
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track);
71
72 6e6d6dc0 Michael Niedermayer
//FIXME supprt 64bit varaint with wide placeholders
73
static int updateSize (ByteIOContext *pb, int pos)
74 1cb5f7fd Michael Niedermayer
{
75
    long curpos = url_ftell(pb);
76
    url_fseek(pb, pos, SEEK_SET);
77 6e6d6dc0 Michael Niedermayer
    put_be32(pb, curpos - pos); /* rewrite size */
78 1cb5f7fd Michael Niedermayer
    url_fseek(pb, curpos, SEEK_SET);
79 6e6d6dc0 Michael Niedermayer
80
    return curpos - pos;
81 1cb5f7fd Michael Niedermayer
}
82
83 e45ccf79 Gildas Bazin
/* Chunk offset atom */
84 6e6d6dc0 Michael Niedermayer
static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
85 1cb5f7fd Michael Niedermayer
{
86
    int i;
87 f578f938 Thomas Raivio
    int pos = url_ftell(pb);
88
    put_be32(pb, 0); /* size */
89 1cb5f7fd Michael Niedermayer
    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 f578f938 Thomas Raivio
    return updateSize (pb, pos);
98 1cb5f7fd Michael Niedermayer
}
99
100 e45ccf79 Gildas Bazin
/* Sample size atom */
101 6e6d6dc0 Michael Niedermayer
static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
102 1cb5f7fd Michael Niedermayer
{
103 f578f938 Thomas Raivio
    int equalChunks = 1;
104 e45ccf79 Gildas Bazin
    int i, j, entries = 0, tst = -1, oldtst = -1;
105 1cb5f7fd Michael Niedermayer
106 f578f938 Thomas Raivio
    int pos = url_ftell(pb);
107
    put_be32(pb, 0); /* size */
108 1cb5f7fd Michael Niedermayer
    put_tag(pb, "stsz");
109
    put_be32(pb, 0); /* version & flags */
110
111 f578f938 Thomas Raivio
    for (i=0; i<track->entry; i++) {
112
        int cl = i / MOV_INDEX_CLUSTER_SIZE;
113
        int id = i % MOV_INDEX_CLUSTER_SIZE;
114 e45ccf79 Gildas Bazin
        tst = track->cluster[cl][id].size/track->cluster[cl][id].entries;
115
        if(oldtst != -1 && tst != oldtst) {
116
            equalChunks = 0;
117 f578f938 Thomas Raivio
        }
118
        oldtst = tst;
119 e45ccf79 Gildas Bazin
        entries += track->cluster[cl][id].entries;
120 f578f938 Thomas Raivio
    }
121 e45ccf79 Gildas Bazin
    if (equalChunks) {
122
        int sSize = track->cluster[0][0].size/track->cluster[0][0].entries;
123 f578f938 Thomas Raivio
        put_be32(pb, sSize); // sample size 
124 e45ccf79 Gildas Bazin
        put_be32(pb, entries); // sample count
125 1cb5f7fd Michael Niedermayer
    }
126 f578f938 Thomas Raivio
    else {
127
        put_be32(pb, 0); // sample size 
128 e45ccf79 Gildas Bazin
        put_be32(pb, entries); // sample count 
129 f578f938 Thomas Raivio
        for (i=0; i<track->entry; i++) {
130 1cb5f7fd Michael Niedermayer
            int cl = i / MOV_INDEX_CLUSTER_SIZE;
131
            int id = i % MOV_INDEX_CLUSTER_SIZE;
132 e45ccf79 Gildas Bazin
            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 1cb5f7fd Michael Niedermayer
        }
137
    }
138 f578f938 Thomas Raivio
    return updateSize (pb, pos);
139 1cb5f7fd Michael Niedermayer
}
140
141 e45ccf79 Gildas Bazin
/* Sample to chunk atom */
142 6e6d6dc0 Michael Niedermayer
static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
143 1cb5f7fd Michael Niedermayer
{
144 f578f938 Thomas Raivio
    int index = 0, oldval = -1, i, entryPos, curpos;
145
146
    int pos = url_ftell(pb);
147
    put_be32(pb, 0); /* size */
148 1cb5f7fd Michael Niedermayer
    put_tag(pb, "stsc");
149
    put_be32(pb, 0); // version & flags 
150 f578f938 Thomas Raivio
    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 e45ccf79 Gildas Bazin
        if(oldval != track->cluster[cl][id].samplesInChunk)
156 f578f938 Thomas Raivio
        {
157 1cb5f7fd Michael Niedermayer
            put_be32(pb, i+1); // first chunk 
158 e45ccf79 Gildas Bazin
            put_be32(pb, track->cluster[cl][id].samplesInChunk); // samples per chunk
159 1cb5f7fd Michael Niedermayer
            put_be32(pb, 0x1); // sample description index 
160 e45ccf79 Gildas Bazin
            oldval = track->cluster[cl][id].samplesInChunk;
161 f578f938 Thomas Raivio
            index++;
162 1cb5f7fd Michael Niedermayer
        }
163
    }
164 f578f938 Thomas Raivio
    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 1cb5f7fd Michael Niedermayer
169 f578f938 Thomas Raivio
    return updateSize (pb, pos);
170 1cb5f7fd Michael Niedermayer
}
171
172 e45ccf79 Gildas Bazin
/* Sync sample atom */
173 f578f938 Thomas Raivio
static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
174 1cb5f7fd Michael Niedermayer
{
175 f578f938 Thomas Raivio
    long curpos;
176
    int i, index = 0, entryPos;
177
    int pos = url_ftell(pb);
178
    put_be32(pb, 0); // size 
179 1cb5f7fd Michael Niedermayer
    put_tag(pb, "stss");
180 f578f938 Thomas Raivio
    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 1cb5f7fd Michael Niedermayer
}
197
198 6e6d6dc0 Michael Niedermayer
static int mov_write_damr_tag(ByteIOContext *pb)
199 1cb5f7fd Michael Niedermayer
{
200
    put_be32(pb, 0x11); /* size */
201
    put_tag(pb, "damr");
202
    put_tag(pb, "FFMP");
203
    put_byte(pb, 0);
204 f578f938 Thomas Raivio
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 1cb5f7fd Michael Niedermayer
    return 0x11;
210
}
211
212 69dde1ad Gildas Bazin
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 f578f938 Thomas Raivio
static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
240 1cb5f7fd Michael Niedermayer
{
241 6e6d6dc0 Michael Niedermayer
    int pos = url_ftell(pb);
242 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* size */
243 f578f938 Thomas Raivio
244
    if(track->enc->codec_id == CODEC_ID_PCM_MULAW)
245
      put_tag(pb, "ulaw");
246
    else if(track->enc->codec_id == CODEC_ID_PCM_ALAW)
247
      put_tag(pb, "alaw");
248
    else if(track->enc->codec_id == CODEC_ID_ADPCM_IMA_QT)
249
      put_tag(pb, "ima4");
250
    else if(track->enc->codec_id == CODEC_ID_MACE3)
251
      put_tag(pb, "MAC3");
252
    else if(track->enc->codec_id == CODEC_ID_MACE6)
253
      put_tag(pb, "MAC6");
254
    else if(track->enc->codec_id == CODEC_ID_AAC)
255
      put_tag(pb, "mp4a");
256
    else if(track->enc->codec_id == CODEC_ID_AMR_NB)
257
      put_tag(pb, "samr");
258 ca20f118 Roman Shaposhnik
    else if(track->enc->codec_id == CODEC_ID_PCM_S16BE)
259
      put_tag(pb, "twos");
260
    else if(track->enc->codec_id == CODEC_ID_PCM_S16LE)
261
      put_tag(pb, "sowt");
262 f578f938 Thomas Raivio
    else
263
      put_tag(pb, "    ");
264
265 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* Reserved */
266
    put_be16(pb, 0); /* Reserved */
267
    put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
268 69dde1ad Gildas Bazin
269 e45ccf79 Gildas Bazin
    /* SoundDescription */
270 69dde1ad Gildas Bazin
    if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
271
        put_be16(pb, 1); /* Version 1 */
272
    else
273
        put_be16(pb, 0); /* Version 0 */
274 e45ccf79 Gildas Bazin
    put_be16(pb, 0); /* Revision level */
275 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* Reserved */
276
277 f578f938 Thomas Raivio
    put_be16(pb, track->enc->channels); /* Number of channels */
278
    /* TODO: Currently hard-coded to 16-bit, there doesn't seem
279 e45ccf79 Gildas Bazin
                 to be a good way to get number of bits of audio */
280 1cb5f7fd Michael Niedermayer
    put_be16(pb, 0x10); /* Reserved */
281 9a4d9388 Roman Shaposhnik
    put_be16(pb, 0); /* compression ID (= 0) */
282
    put_be16(pb, 0); /* packet size (= 0) */
283 1cb5f7fd Michael Niedermayer
    put_be16(pb, track->timescale); /* Time scale */
284
    put_be16(pb, 0); /* Reserved */
285
286 69dde1ad Gildas Bazin
    if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
287
    {
288
        /* SoundDescription V1 extended info */
289
        put_be32(pb, track->enc->frame_size); /* Samples per packet  */
290
        put_be32(pb, 1536); /* Bytes per packet */
291
        put_be32(pb, 2); /* Bytes per frame */
292
        put_be32(pb, 2); /* Bytes per sample */
293
    }
294
295
    if(track->enc->codec_id == CODEC_ID_AAC) {
296
        if( track->mode == MODE_MOV ) mov_write_wave_tag(pb, track);
297
        else mov_write_esds_tag(pb, track);
298
    }
299 f578f938 Thomas Raivio
    if(track->enc->codec_id == CODEC_ID_AMR_NB)
300
        mov_write_damr_tag(pb);
301 6e6d6dc0 Michael Niedermayer
    return updateSize (pb, pos);
302 1cb5f7fd Michael Niedermayer
}
303
304 6e6d6dc0 Michael Niedermayer
static int mov_write_d263_tag(ByteIOContext *pb)
305 1cb5f7fd Michael Niedermayer
{
306
    put_be32(pb, 0xf); /* size */
307
    put_tag(pb, "d263");
308
    put_tag(pb, "FFMP");
309
    put_be16(pb, 0x0a);
310
    put_byte(pb, 0);
311
    return 0xf;
312
}
313
314 f578f938 Thomas Raivio
/* TODO: No idea about these values */
315
static int mov_write_svq3_tag(ByteIOContext *pb)
316 1cb5f7fd Michael Niedermayer
{
317 f578f938 Thomas Raivio
    put_be32(pb, 0x15);
318
    put_tag(pb, "SMI ");
319
    put_tag(pb, "SEQH");
320
    put_be32(pb, 0x5);
321
    put_be32(pb, 0xe2c0211d);
322
    put_be32(pb, 0xc0000000);
323
    put_byte(pb, 0);   
324
    return 0x15;
325 1cb5f7fd Michael Niedermayer
}
326
327 e45ccf79 Gildas Bazin
static unsigned int descrLength(unsigned int len)
328
{
329
    if (len < 0x00000080)
330
        return 2 + len;
331
    else if (len < 0x00004000)
332
        return 3 + len;
333
    else if(len < 0x00200000)
334
        return 4 + len;
335
    else
336
        return 5 + len;
337
}
338
339
static void putDescr(ByteIOContext *pb, int tag, int size)
340 1cb5f7fd Michael Niedermayer
{
341 e45ccf79 Gildas Bazin
    uint32_t len;
342
    uint8_t  vals[4];
343
344
    len = size;
345
    vals[3] = (uint8_t)(len & 0x7f);
346
    len >>= 7;
347
    vals[2] = (uint8_t)((len & 0x7f) | 0x80); 
348
    len >>= 7;
349
    vals[1] = (uint8_t)((len & 0x7f) | 0x80); 
350
    len >>= 7;
351
    vals[0] = (uint8_t)((len & 0x7f) | 0x80);
352
353
    put_byte(pb, tag); // DescriptorTag
354
355
    if (size < 0x00000080)
356
    {
357
        put_byte(pb, vals[3]);
358
    }
359
    else if (size < 0x00004000)
360
    {
361
        put_byte(pb, vals[2]);
362
        put_byte(pb, vals[3]);
363
    }
364
    else if (size < 0x00200000)
365
    {
366
        put_byte(pb, vals[1]);
367
        put_byte(pb, vals[2]);
368
        put_byte(pb, vals[3]);
369
    }
370
    else if (size < 0x10000000)
371
    {
372
        put_byte(pb, vals[0]);
373
        put_byte(pb, vals[1]);
374
        put_byte(pb, vals[2]);
375
        put_byte(pb, vals[3]);
376
    }
377 1cb5f7fd Michael Niedermayer
}
378
379 6e6d6dc0 Michael Niedermayer
static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
380 1cb5f7fd Michael Niedermayer
{
381 e45ccf79 Gildas Bazin
    int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
382
    int pos = url_ftell(pb);
383
384
    put_be32(pb, 0);               // size
385 1cb5f7fd Michael Niedermayer
    put_tag(pb, "esds");
386 e45ccf79 Gildas Bazin
    put_be32(pb, 0);               // Version
387 1cb5f7fd Michael Niedermayer
388 e45ccf79 Gildas Bazin
    // ES descriptor
389
    putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
390
             descrLength(1));
391
    put_be16(pb, 0x0001);          // ID (= 1)
392 1cb5f7fd Michael Niedermayer
    put_byte(pb, 0x00);            // flags (= no flags)
393
394 e45ccf79 Gildas Bazin
    // DecoderConfig descriptor
395
    putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);
396
397
    if(track->enc->codec_id == CODEC_ID_AAC)
398
        put_byte(pb, 0x40);        // Object type indication
399
    else if(track->enc->codec_id == CODEC_ID_MPEG4)
400
        put_byte(pb, 0x20);        // Object type indication (Visual 14496-2)
401
402
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
403
        put_byte(pb, 0x15);            // flags (= Audiostream)
404
    else
405
        put_byte(pb, 0x11);            // flags (= Visualstream)
406
407 1cb5f7fd Michael Niedermayer
    put_byte(pb, 0x0);             // Buffersize DB (24 bits)
408
    put_be16(pb, 0x0dd2);          // Buffersize DB
409
410
    // TODO: find real values for these
411
    put_be32(pb, 0x0002e918);     // maxbitrate
412
    put_be32(pb, 0x00017e6b);     // avg bitrate
413
414 e45ccf79 Gildas Bazin
    if (track->vosLen)
415
    {
416
        // DecoderSpecific info descriptor
417
        putDescr(pb, 0x05, track->vosLen);
418
        put_buffer(pb, track->vosData, track->vosLen);
419
    }
420
421
    // SL descriptor
422 4bfc029f Michael Niedermayer
    putDescr(pb, 0x06, 1);
423 1cb5f7fd Michael Niedermayer
    put_byte(pb, 0x02);
424 e45ccf79 Gildas Bazin
    return updateSize (pb, pos);
425 1cb5f7fd Michael Niedermayer
}
426
427 f578f938 Thomas Raivio
static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
428 1cb5f7fd Michael Niedermayer
{
429 6e6d6dc0 Michael Niedermayer
    int pos = url_ftell(pb);
430 f578f938 Thomas Raivio
    put_be32(pb, 0); /* size */
431
    if(track->enc->codec_id == CODEC_ID_SVQ1)
432
      put_tag(pb, "SVQ1");
433
    else if(track->enc->codec_id == CODEC_ID_SVQ3)
434
      put_tag(pb, "SVQ3");
435
    else if(track->enc->codec_id == CODEC_ID_MPEG4)
436
      put_tag(pb, "mp4v");
437
    else if(track->enc->codec_id == CODEC_ID_H263)
438
      put_tag(pb, "s263");
439 ca20f118 Roman Shaposhnik
    else if(track->enc->codec_id == CODEC_ID_DVVIDEO)
440
      put_tag(pb, "dvc ");
441 f578f938 Thomas Raivio
    else
442
      put_tag(pb, "    "); /* Unknown tag */
443 6e6d6dc0 Michael Niedermayer
444 f578f938 Thomas Raivio
    put_be32(pb, 0); /* Reserved */
445
    put_be16(pb, 0); /* Reserved */
446
    put_be16(pb, 1); /* Data-reference index */
447
448
    put_be32(pb, 0); /* Reserved (= 02000c) */
449
    put_be32(pb, 0); /* Reserved ("SVis")*/
450
    put_be32(pb, 0); /* Reserved */
451
    put_be32(pb, 0); /* Reserved (400)*/
452
    put_be16(pb, track->enc->width); /* Video width */
453
    put_be16(pb, track->enc->height); /* Video height */
454
    put_be32(pb, 0x00480000); /* Reserved */
455
    put_be32(pb, 0x00480000); /* Reserved */
456 9a4d9388 Roman Shaposhnik
    put_be32(pb, 0); /* Data size (= 0) */
457
    put_be16(pb, 1); /* Frame count (= 1) */
458
    
459 f578f938 Thomas Raivio
    put_be32(pb, 0); /* Reserved */
460
    put_be32(pb, 0); /* Reserved */
461
    put_be32(pb, 0); /* Reserved */
462
    put_be32(pb, 0); /* Reserved */
463
    put_be32(pb, 0); /* Reserved */
464
    put_be32(pb, 0); /* Reserved */
465
    put_be32(pb, 0); /* Reserved */
466
    put_be32(pb, 0); /* Reserved */
467 9a4d9388 Roman Shaposhnik
    
468 f578f938 Thomas Raivio
    put_be16(pb, 0x18); /* Reserved */
469
    put_be16(pb, 0xffff); /* Reserved */
470
    if(track->enc->codec_id == CODEC_ID_MPEG4)
471
        mov_write_esds_tag(pb, track);
472
    else if(track->enc->codec_id == CODEC_ID_H263)
473
        mov_write_d263_tag(pb);
474
    else if(track->enc->codec_id == CODEC_ID_SVQ3)
475
        mov_write_svq3_tag(pb);    
476
477
    return updateSize (pb, pos);
478 1cb5f7fd Michael Niedermayer
}
479
480 6e6d6dc0 Michael Niedermayer
static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
481 1cb5f7fd Michael Niedermayer
{
482 6e6d6dc0 Michael Niedermayer
    int pos = url_ftell(pb);
483 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* size */
484
    put_tag(pb, "stsd");
485
    put_be32(pb, 0); /* version & flags */
486
    put_be32(pb, 1); /* entry count */
487 f578f938 Thomas Raivio
    if (track->enc->codec_type == CODEC_TYPE_VIDEO)
488
        mov_write_video_tag(pb, track);
489
    else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
490
        mov_write_audio_tag(pb, track);
491 6e6d6dc0 Michael Niedermayer
    return updateSize(pb, pos);
492 1cb5f7fd Michael Niedermayer
}
493
494 f578f938 Thomas Raivio
/* TODO?: Currently all samples/frames seem to have same duration */
495 e45ccf79 Gildas Bazin
/* Time to sample atom */
496 6e6d6dc0 Michael Niedermayer
static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
497 1cb5f7fd Michael Niedermayer
{
498
    put_be32(pb, 0x18); /* size */
499
    put_tag(pb, "stts");
500
    put_be32(pb, 0); /* version & flags */
501
    put_be32(pb, 1); /* entry count */
502
503 e45ccf79 Gildas Bazin
    put_be32(pb, track->sampleCount); /* sample count */
504
    put_be32(pb, track->sampleDuration); /* sample duration */
505 1cb5f7fd Michael Niedermayer
    return 0x18;
506
}
507
508 6e6d6dc0 Michael Niedermayer
static int mov_write_dref_tag(ByteIOContext *pb)
509 1cb5f7fd Michael Niedermayer
{
510
    put_be32(pb, 28); /* size */
511
    put_tag(pb, "dref");
512
    put_be32(pb, 0); /* version & flags */
513
    put_be32(pb, 1); /* entry count */
514
515
    put_be32(pb, 0xc); /* size */
516
    put_tag(pb, "url ");
517
    put_be32(pb, 1); /* version & flags */
518
519
    return 28;
520
}
521
522 6e6d6dc0 Michael Niedermayer
static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
523 1cb5f7fd Michael Niedermayer
{
524 6e6d6dc0 Michael Niedermayer
    int pos = url_ftell(pb);
525 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* size */
526
    put_tag(pb, "stbl");
527 6e6d6dc0 Michael Niedermayer
    mov_write_stsd_tag(pb, track);
528
    mov_write_stts_tag(pb, track);
529 f578f938 Thomas Raivio
    if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
530
        track->hasKeyframes)
531
        mov_write_stss_tag(pb, track);
532 6e6d6dc0 Michael Niedermayer
    mov_write_stsc_tag(pb, track);
533
    mov_write_stsz_tag(pb, track);
534
    mov_write_stco_tag(pb, track);
535
    return updateSize(pb, pos);
536 1cb5f7fd Michael Niedermayer
}
537
538 6e6d6dc0 Michael Niedermayer
static int mov_write_dinf_tag(ByteIOContext *pb)
539 1cb5f7fd Michael Niedermayer
{
540 6e6d6dc0 Michael Niedermayer
    int pos = url_ftell(pb);
541 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* size */
542
    put_tag(pb, "dinf");
543 6e6d6dc0 Michael Niedermayer
    mov_write_dref_tag(pb);
544
    return updateSize(pb, pos);
545 1cb5f7fd Michael Niedermayer
}
546
547 6e6d6dc0 Michael Niedermayer
static int mov_write_smhd_tag(ByteIOContext *pb)
548 1cb5f7fd Michael Niedermayer
{
549
    put_be32(pb, 16); /* size */
550
    put_tag(pb, "smhd");
551
    put_be32(pb, 0); /* version & flags */
552
    put_be16(pb, 0); /* reserved (balance, normally = 0) */
553
    put_be16(pb, 0); /* reserved */
554
    return 16;
555
}
556
557 6e6d6dc0 Michael Niedermayer
static int mov_write_vmhd_tag(ByteIOContext *pb)
558 1cb5f7fd Michael Niedermayer
{
559
    put_be32(pb, 0x14); /* size (always 0x14) */
560
    put_tag(pb, "vmhd");
561
    put_be32(pb, 0x01); /* version & flags */
562
    put_be64(pb, 0); /* reserved (graphics mode = copy) */
563
    return 0x14;
564
}
565
566 6e6d6dc0 Michael Niedermayer
static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
567 1cb5f7fd Michael Niedermayer
{
568 9a4d9388 Roman Shaposhnik
    char *descr, *hdlr, *hdlr_type;
569 f578f938 Thomas Raivio
    int pos = url_ftell(pb);
570 9a4d9388 Roman Shaposhnik
    
571
    if (!track) { /* no media --> data handler */
572
        hdlr = "dhlr";
573
        hdlr_type = "url ";
574
        descr = "DataHandler";
575
    } else {
576
        hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
577
        if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
578
            hdlr_type = "vide";
579
            descr = "VideoHandler";
580
        } else {
581
            hdlr_type = "soun";
582
            descr = "SoundHandler";
583
        }
584
    }
585
    
586 f578f938 Thomas Raivio
    put_be32(pb, 0); /* size */
587 1cb5f7fd Michael Niedermayer
    put_tag(pb, "hdlr");
588
    put_be32(pb, 0); /* Version & flags */
589 906b578f Roman Shaposhnik
    put_buffer(pb, hdlr, 4); /* handler */
590 9a4d9388 Roman Shaposhnik
    put_tag(pb, hdlr_type); /* handler type */
591 f578f938 Thomas Raivio
    put_be32(pb ,0); /* reserved */
592
    put_be32(pb ,0); /* reserved */
593
    put_be32(pb ,0); /* reserved */
594 9a4d9388 Roman Shaposhnik
    put_byte(pb, strlen(descr)); /* string counter */
595
    put_buffer(pb, descr, strlen(descr)); /* handler description */
596
    return updateSize(pb, pos);
597
}
598
599
static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
600
{
601
    int pos = url_ftell(pb);
602
    put_be32(pb, 0); /* size */
603
    put_tag(pb, "minf");
604 1cb5f7fd Michael Niedermayer
    if(track->enc->codec_type == CODEC_TYPE_VIDEO)
605 9a4d9388 Roman Shaposhnik
        mov_write_vmhd_tag(pb);
606 1cb5f7fd Michael Niedermayer
    else
607 9a4d9388 Roman Shaposhnik
        mov_write_smhd_tag(pb);
608
    if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
609
        mov_write_hdlr_tag(pb, NULL);
610
    mov_write_dinf_tag(pb);
611
    mov_write_stbl_tag(pb, track);
612 f578f938 Thomas Raivio
    return updateSize(pb, pos);
613 1cb5f7fd Michael Niedermayer
}
614
615 6e6d6dc0 Michael Niedermayer
static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
616 1cb5f7fd Michael Niedermayer
{
617
    put_be32(pb, 32); /* size */
618
    put_tag(pb, "mdhd");
619
    put_be32(pb, 0); /* Version & flags */
620
    put_be32(pb, track->time); /* creation time */
621
    put_be32(pb, track->time); /* modification time */
622 e45ccf79 Gildas Bazin
    put_be32(pb, track->timescale); /* time scale (sample rate for audio) */ 
623
    put_be32(pb, track->trackDuration); /* duration */
624 1cb5f7fd Michael Niedermayer
    put_be16(pb, 0); /* language, 0 = english */
625
    put_be16(pb, 0); /* reserved (quality) */
626
    return 32;
627
}
628
629 6e6d6dc0 Michael Niedermayer
static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
630 1cb5f7fd Michael Niedermayer
{
631 6e6d6dc0 Michael Niedermayer
    int pos = url_ftell(pb);
632 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* size */
633
    put_tag(pb, "mdia");
634 6e6d6dc0 Michael Niedermayer
    mov_write_mdhd_tag(pb, track);
635
    mov_write_hdlr_tag(pb, track);
636
    mov_write_minf_tag(pb, track);
637
    return updateSize(pb, pos);
638 1cb5f7fd Michael Niedermayer
}
639
640 6e6d6dc0 Michael Niedermayer
static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
641 1cb5f7fd Michael Niedermayer
{
642 f578f938 Thomas Raivio
    int64_t maxTrackLenTemp;
643 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0x5c); /* size (always 0x5c) */
644
    put_tag(pb, "tkhd");
645 f578f938 Thomas Raivio
    put_be32(pb, 0xf); /* version & flags (track enabled) */
646 1cb5f7fd Michael Niedermayer
    put_be32(pb, track->time); /* creation time */
647
    put_be32(pb, track->time); /* modification time */
648
    put_be32(pb, track->trackID); /* track-id */
649
    put_be32(pb, 0); /* reserved */
650 f578f938 Thomas Raivio
    maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale;
651
    put_be32(pb, (long)maxTrackLenTemp); /* duration */
652 1cb5f7fd Michael Niedermayer
653
    put_be32(pb, 0); /* reserved */
654
    put_be32(pb, 0); /* reserved */
655
    put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
656
    /* Volume, only for audio */
657
    if(track->enc->codec_type == CODEC_TYPE_AUDIO)
658
        put_be16(pb, 0x0100);
659
    else
660
        put_be16(pb, 0);
661
    put_be16(pb, 0); /* reserved */
662
663
    /* Matrix structure */
664
    put_be32(pb, 0x00010000); /* reserved */
665
    put_be32(pb, 0x0); /* reserved */
666
    put_be32(pb, 0x0); /* reserved */
667
    put_be32(pb, 0x0); /* reserved */
668
    put_be32(pb, 0x00010000); /* reserved */
669
    put_be32(pb, 0x0); /* reserved */
670
    put_be32(pb, 0x0); /* reserved */
671
    put_be32(pb, 0x0); /* reserved */
672
    put_be32(pb, 0x40000000); /* reserved */
673
674
    /* Track width and height, for visual only */
675
    if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
676 69dde1ad Gildas Bazin
        double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio);
677
        if( !sample_aspect_ratio ) sample_aspect_ratio = 1;
678
        put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
679 f578f938 Thomas Raivio
        put_be32(pb, track->enc->height*0x10000);
680 1cb5f7fd Michael Niedermayer
    }
681
    else {
682
        put_be32(pb, 0);
683
        put_be32(pb, 0);
684
    }
685
    return 0x5c;
686
}
687
688 6e6d6dc0 Michael Niedermayer
static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
689 1cb5f7fd Michael Niedermayer
{
690 6e6d6dc0 Michael Niedermayer
    int pos = url_ftell(pb);
691 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* size */
692
    put_tag(pb, "trak");
693 6e6d6dc0 Michael Niedermayer
    mov_write_tkhd_tag(pb, track);
694
    mov_write_mdia_tag(pb, track);
695
    return updateSize(pb, pos);
696 1cb5f7fd Michael Niedermayer
}
697
698
/* TODO: Not sorted out, but not necessary either */
699 6e6d6dc0 Michael Niedermayer
static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
700 1cb5f7fd Michael Niedermayer
{
701
    put_be32(pb, 0x15); /* size */
702
    put_tag(pb, "iods");
703
    put_be32(pb, 0);    /* version & flags */
704
    put_be16(pb, 0x1007);
705
    put_byte(pb, 0);
706
    put_be16(pb, 0x4fff);
707
    put_be16(pb, 0xfffe);
708
    put_be16(pb, 0x01ff);
709
    return 0x15;
710
}
711
712 6e6d6dc0 Michael Niedermayer
static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
713 1cb5f7fd Michael Niedermayer
{
714
    int maxTrackID = 1, maxTrackLen = 0, i;
715 f578f938 Thomas Raivio
    int64_t maxTrackLenTemp;
716 1cb5f7fd Michael Niedermayer
717
    put_be32(pb, 0x6c); /* size (always 0x6c) */
718
    put_tag(pb, "mvhd");
719
    put_be32(pb, 0); /* version & flags */
720
    put_be32(pb, mov->time); /* creation time */
721
    put_be32(pb, mov->time); /* modification time */
722
    put_be32(pb, mov->timescale); /* timescale */
723
    for (i=0; i<MAX_STREAMS; i++) {
724
        if(mov->tracks[i].entry > 0) {
725 f578f938 Thomas Raivio
            maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale;
726
            if(maxTrackLen < maxTrackLenTemp)
727
                maxTrackLen = maxTrackLenTemp;
728 1cb5f7fd Michael Niedermayer
            if(maxTrackID < mov->tracks[i].trackID)
729
                maxTrackID = mov->tracks[i].trackID;
730
        }
731
    }
732
    put_be32(pb, maxTrackLen); /* duration of longest track */
733
734
    put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
735
    put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
736
    put_be16(pb, 0); /* reserved */
737
    put_be32(pb, 0); /* reserved */
738
    put_be32(pb, 0); /* reserved */
739
740
    /* Matrix structure */
741
    put_be32(pb, 0x00010000); /* reserved */
742
    put_be32(pb, 0x0); /* reserved */
743
    put_be32(pb, 0x0); /* reserved */
744
    put_be32(pb, 0x0); /* reserved */
745
    put_be32(pb, 0x00010000); /* reserved */
746
    put_be32(pb, 0x0); /* reserved */
747
    put_be32(pb, 0x0); /* reserved */
748
    put_be32(pb, 0x0); /* reserved */
749
    put_be32(pb, 0x40000000); /* reserved */
750
751
    put_be32(pb, 0); /* reserved (preview time) */
752
    put_be32(pb, 0); /* reserved (preview duration) */
753
    put_be32(pb, 0); /* reserved (poster time) */
754
    put_be32(pb, 0); /* reserved (selection time) */
755
    put_be32(pb, 0); /* reserved (selection duration) */
756
    put_be32(pb, 0); /* reserved (current time) */
757
    put_be32(pb, maxTrackID+1); /* Next track id */
758
    return 0x6c;
759
}
760
761 69dde1ad Gildas Bazin
static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov,
762
                              AVFormatContext *s)
763
{
764
    int pos = url_ftell(pb);
765
    int i;
766
767
    put_be32(pb, 0); /* size */
768
    put_tag(pb, "udta");
769
770
    /* Requirements */
771
    for (i=0; i<MAX_STREAMS; i++) {
772
        if(mov->tracks[i].entry <= 0) continue;
773
        if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC ||
774
            mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) {
775
            int pos = url_ftell(pb);
776
            put_be32(pb, 0); /* size */
777
            put_tag(pb, "\251req");
778
            put_be16(pb, sizeof("QuickTime 6.0 or greater") - 1);
779
            put_be16(pb, 0);
780
            put_buffer(pb, "QuickTime 6.0 or greater",
781
                       sizeof("QuickTime 6.0 or greater") - 1);
782
            updateSize(pb, pos);
783
            break;
784
        }
785
    }
786
787
    /* Encoder */
788
    {
789
        int pos = url_ftell(pb);
790
        put_be32(pb, 0); /* size */
791
        put_tag(pb, "\251enc");
792
        put_be16(pb, sizeof(LIBAVFORMAT_IDENT) - 1); /* string length */
793
        put_be16(pb, 0);
794
        put_buffer(pb, LIBAVFORMAT_IDENT, sizeof(LIBAVFORMAT_IDENT) - 1);
795
        updateSize(pb, pos);
796
    }
797
798
    if( s->title[0] )
799
    {
800
        int pos = url_ftell(pb);
801
        put_be32(pb, 0); /* size */
802
        put_tag(pb, "\251nam");
803
        put_be16(pb, strlen(s->title)); /* string length */
804
        put_be16(pb, 0);
805
        put_buffer(pb, s->title, strlen(s->title));
806
        updateSize(pb, pos);
807
    }
808
809
    if( s->author[0] )
810
    {
811
        int pos = url_ftell(pb);
812
        put_be32(pb, 0); /* size */
813
        put_tag(pb, /*"\251aut"*/ "\251day" );
814
        put_be16(pb, strlen(s->author)); /* string length */
815
        put_be16(pb, 0);
816
        put_buffer(pb, s->author, strlen(s->author));
817
        updateSize(pb, pos);
818
    }
819
820
    if( s->comment[0] )
821
    {
822
        int pos = url_ftell(pb);
823
        put_be32(pb, 0); /* size */
824
        put_tag(pb, "\251des");
825
        put_be16(pb, strlen(s->comment)); /* string length */
826
        put_be16(pb, 0);
827
        put_buffer(pb, s->comment, strlen(s->comment));
828
        updateSize(pb, pos);
829
    }
830
831
    return updateSize(pb, pos);
832
}
833
834
static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov,
835
                              AVFormatContext *s)
836 1cb5f7fd Michael Niedermayer
{
837 6e6d6dc0 Michael Niedermayer
    int pos, i;
838 1cb5f7fd Michael Niedermayer
    pos = url_ftell(pb);
839
    put_be32(pb, 0); /* size placeholder*/
840
    put_tag(pb, "moov");
841
    mov->timescale = globalTimescale;
842
843
    for (i=0; i<MAX_STREAMS; i++) {
844 e45ccf79 Gildas Bazin
        if(mov->tracks[i].entry <= 0) continue;
845
846
        if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
847
            mov->tracks[i].timescale = mov->tracks[i].enc->frame_rate;
848
            mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_rate_base;
849
        }
850
        else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
851
            /* If AMR, track timescale = 8000, AMR_WB = 16000 */
852
            if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
853
                mov->tracks[i].sampleDuration = 160;  // Bytes per chunk
854
                mov->tracks[i].timescale = 8000;
855 1cb5f7fd Michael Niedermayer
            }
856 e45ccf79 Gildas Bazin
            else {
857
                mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
858
                mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size;
859 1cb5f7fd Michael Niedermayer
            }
860
        }
861 e45ccf79 Gildas Bazin
862
        mov->tracks[i].trackDuration = 
863
            mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration;
864
        mov->tracks[i].time = mov->time;
865
        mov->tracks[i].trackID = i+1;
866 1cb5f7fd Michael Niedermayer
    }
867
868 6e6d6dc0 Michael Niedermayer
    mov_write_mvhd_tag(pb, mov);
869
    //mov_write_iods_tag(pb, mov);
870 1cb5f7fd Michael Niedermayer
    for (i=0; i<MAX_STREAMS; i++) {
871
        if(mov->tracks[i].entry > 0) {
872 6e6d6dc0 Michael Niedermayer
            mov_write_trak_tag(pb, &(mov->tracks[i]));
873 1cb5f7fd Michael Niedermayer
        }
874
    }
875
876 69dde1ad Gildas Bazin
    mov_write_udta_tag(pb, mov, s);
877
878 6e6d6dc0 Michael Niedermayer
    return updateSize(pb, pos);
879 1cb5f7fd Michael Niedermayer
}
880
881 f578f938 Thomas Raivio
int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
882 1cb5f7fd Michael Niedermayer
{
883 f578f938 Thomas Raivio
    mov->mdat_pos = url_ftell(pb); 
884 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0); /* size placeholder*/
885
    put_tag(pb, "mdat");
886
    return 0;
887
}
888
889
/* TODO: This needs to be more general */
890 e45ccf79 Gildas Bazin
int mov_write_ftyp_tag(ByteIOContext *pb, AVFormatContext *s)
891 1cb5f7fd Michael Niedermayer
{
892 69dde1ad Gildas Bazin
    MOVContext *mov = s->priv_data;
893
894 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0x14 ); /* size */
895
    put_tag(pb, "ftyp");
896 e45ccf79 Gildas Bazin
897 69dde1ad Gildas Bazin
    if ( mov->mode == MODE_3GP )
898 e45ccf79 Gildas Bazin
        put_tag(pb, "3gp4");
899
    else
900
        put_tag(pb, "isom");
901
902 1cb5f7fd Michael Niedermayer
    put_be32(pb, 0x200 );
903 e45ccf79 Gildas Bazin
904 69dde1ad Gildas Bazin
    if ( mov->mode == MODE_3GP )
905 e45ccf79 Gildas Bazin
        put_tag(pb, "3gp4");
906
    else
907
        put_tag(pb, "mp41");
908
909 1cb5f7fd Michael Niedermayer
    return 0x14;
910
}
911
912
static int mov_write_header(AVFormatContext *s)
913
{
914
    ByteIOContext *pb = &s->pb;
915 69dde1ad Gildas Bazin
    MOVContext *mov = s->priv_data;
916
    int i;
917 1cb5f7fd Michael Niedermayer
918 69dde1ad Gildas Bazin
    /* Default mode == MP4 */
919
    mov->mode = MODE_MP4;
920
921
    if (s->oformat != NULL) {
922
        if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
923
        else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
924
925
        if ( mov->mode == MODE_3GP || mov->mode == MODE_MP4 )
926
            mov_write_ftyp_tag(pb,s);
927
    }
928
929
    for (i=0; i<MAX_STREAMS; i++) {
930
        mov->tracks[i].mode = mov->mode;
931 f578f938 Thomas Raivio
    }
932
933 1cb5f7fd Michael Niedermayer
    put_flush_packet(pb);
934
935
    return 0;
936
}
937
938 7906085f Falk H├╝ffner
static int Timestamp(void) {
939 dd0003fa Michael Niedermayer
    return 1067949799U+(24107*86400); //its the modification time of this line :)
940 1cb5f7fd Michael Niedermayer
}
941
942
static int mov_write_packet(AVFormatContext *s, int stream_index,
943 49057904 Fabrice Bellard
                            const uint8_t *buf, int size, int64_t pts)
944 1cb5f7fd Michael Niedermayer
{
945
    MOVContext *mov = s->priv_data;
946
    ByteIOContext *pb = &s->pb;
947 e45ccf79 Gildas Bazin
    AVCodecContext *enc = &s->streams[stream_index]->codec;
948
    MOVTrack* trk = &mov->tracks[stream_index];
949 1a31840c Mike Melanson
    int cl, id;
950 e45ccf79 Gildas Bazin
    unsigned int samplesInChunk = 0;
951 1cb5f7fd Michael Niedermayer
952 e45ccf79 Gildas Bazin
    if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */
953
    if (!size) return 0; /* Discard 0 sized packets */
954 1cb5f7fd Michael Niedermayer
955 e45ccf79 Gildas Bazin
    if (enc->codec_type == CODEC_TYPE_VIDEO ) {
956
        samplesInChunk = 1;
957
    }
958
    else if (enc->codec_type == CODEC_TYPE_AUDIO ) {
959
        if( enc->codec_id == CODEC_ID_AMR_NB) {
960 f578f938 Thomas Raivio
            /* We must find out how many AMR blocks there are in one packet */
961 e45ccf79 Gildas Bazin
            static uint16_t packed_size[16] =
962
                {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
963
            int len = 0;
964
965
            while (len < size && samplesInChunk < 100) {
966
                len += packed_size[(buf[len] >> 3) & 0x0F];
967
                samplesInChunk++;
968 f578f938 Thomas Raivio
            }
969 1cb5f7fd Michael Niedermayer
        }
970 e45ccf79 Gildas Bazin
        else if(enc->codec_id == CODEC_ID_PCM_ALAW) {
971
            samplesInChunk = size/enc->channels;
972 1cb5f7fd Michael Niedermayer
        }
973 9a4d9388 Roman Shaposhnik
        else if(enc->codec_id == CODEC_ID_PCM_S16BE || enc->codec_id == CODEC_ID_PCM_S16LE) {
974
            samplesInChunk = size/(2*enc->channels);
975
        }            
976 e45ccf79 Gildas Bazin
        else {
977
            samplesInChunk = 1;
978 1cb5f7fd Michael Niedermayer
        }
979 e45ccf79 Gildas Bazin
    }
980
981
    if ((enc->codec_id == CODEC_ID_MPEG4 || enc->codec_id == CODEC_ID_AAC)
982
        && trk->vosLen == 0) {
983
        assert(enc->extradata_size);
984
985
        trk->vosLen = enc->extradata_size;
986
        trk->vosData = av_malloc(trk->vosLen);
987
        memcpy(trk->vosData, enc->extradata, trk->vosLen);
988
    }
989
990
    cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
991
    id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
992
993
    if (trk->ents_allocated <= trk->entry) {
994
        trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*)); 
995
        if (!trk->cluster)
996
            return -1;
997
        trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
998
        if (!trk->cluster[cl])
999
            return -1;
1000
        trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
1001
    }
1002
    if (mov->mdat_written == 0) {
1003
        mov_write_mdat_tag(pb, mov);
1004
        mov->mdat_written = 1;
1005
        mov->time = Timestamp();
1006
    }
1007
1008 69dde1ad Gildas Bazin
    trk->cluster[cl][id].pos = url_ftell(pb);
1009 e45ccf79 Gildas Bazin
    trk->cluster[cl][id].samplesInChunk = samplesInChunk;
1010
    trk->cluster[cl][id].size = size;
1011
    trk->cluster[cl][id].entries = samplesInChunk;
1012
    if(enc->codec_type == CODEC_TYPE_VIDEO) {
1013
        trk->cluster[cl][id].key_frame = enc->coded_frame->key_frame;
1014
        if(enc->coded_frame->pict_type == FF_I_TYPE)
1015 f578f938 Thomas Raivio
            trk->hasKeyframes = 1;
1016 1cb5f7fd Michael Niedermayer
    }
1017 e45ccf79 Gildas Bazin
    trk->enc = enc;
1018
    trk->entry++;
1019
    trk->sampleCount += samplesInChunk;
1020
    trk->mdat_size += size;
1021
1022 1cb5f7fd Michael Niedermayer
    put_buffer(pb, buf, size);
1023
1024
    put_flush_packet(pb);
1025
    return 0;
1026
}
1027
1028
static int mov_write_trailer(AVFormatContext *s)
1029
{
1030
    MOVContext *mov = s->priv_data;
1031
    ByteIOContext *pb = &s->pb;
1032
    int res = 0;
1033
    int i, j;
1034
1035 69dde1ad Gildas Bazin
    offset_t moov_pos = url_ftell(pb);
1036 1cb5f7fd Michael Niedermayer
1037
    /* Write size of mdat tag */
1038 69dde1ad Gildas Bazin
    for (i=0, j=0; i<MAX_STREAMS; i++) {
1039 1cb5f7fd Michael Niedermayer
        if(mov->tracks[i].ents_allocated > 0) {
1040
            j += mov->tracks[i].mdat_size;
1041
        }
1042
    }
1043 f578f938 Thomas Raivio
    url_fseek(pb, mov->mdat_pos, SEEK_SET);
1044 1cb5f7fd Michael Niedermayer
    put_be32(pb, j+8);
1045 69dde1ad Gildas Bazin
    url_fseek(pb, moov_pos, SEEK_SET);
1046 1cb5f7fd Michael Niedermayer
1047 69dde1ad Gildas Bazin
    mov_write_moov_tag(pb, mov, s);
1048 1cb5f7fd Michael Niedermayer
1049
    for (i=0; i<MAX_STREAMS; i++) {
1050
        for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
1051
            av_free(mov->tracks[i].cluster[j]);
1052
        }
1053
        av_free(mov->tracks[i].cluster);
1054 ec7d0d2e Gildas Bazin
        if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData );
1055
1056 1cb5f7fd Michael Niedermayer
        mov->tracks[i].cluster = NULL;
1057
        mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
1058
    }
1059 69dde1ad Gildas Bazin
1060 1cb5f7fd Michael Niedermayer
    put_flush_packet(pb);
1061
1062
    return res;
1063
}
1064
1065
static AVOutputFormat mov_oformat = {
1066
    "mov",
1067
    "mov format",
1068
    NULL,
1069
    "mov",
1070
    sizeof(MOVContext),
1071 69dde1ad Gildas Bazin
    CODEC_ID_AAC,
1072 2187d948 Michael Niedermayer
    CODEC_ID_MPEG4,
1073 1cb5f7fd Michael Niedermayer
    mov_write_header,
1074
    mov_write_packet,
1075
    mov_write_trailer,
1076
};
1077
1078
static AVOutputFormat _3gp_oformat = {
1079
    "3gp",
1080
    "3gp format",
1081
    NULL,
1082
    "3gp",
1083
    sizeof(MOVContext),
1084
    CODEC_ID_AMR_NB,
1085
    CODEC_ID_H263,
1086
    mov_write_header,
1087
    mov_write_packet,
1088
    mov_write_trailer,
1089
};
1090
1091
static AVOutputFormat mp4_oformat = {
1092
    "mp4",
1093
    "mp4 format",
1094 4cb3f3b6 Dan Christiansen
    "application/mp4",
1095
    "mp4,m4a",
1096 1cb5f7fd Michael Niedermayer
    sizeof(MOVContext),
1097
    CODEC_ID_AAC,
1098
    CODEC_ID_MPEG4,
1099
    mov_write_header,
1100
    mov_write_packet,
1101
    mov_write_trailer,
1102
};
1103
1104
int movenc_init(void)
1105
{
1106
    av_register_output_format(&mov_oformat);
1107
    av_register_output_format(&_3gp_oformat);
1108
    av_register_output_format(&mp4_oformat);
1109
    return 0;
1110
}