]> git.sesse.net Git - ffmpeg/blob - libavformat/movenc.c
some sanity checks on what is muxed, invalid timestamps in mpeg are very common and...
[ffmpeg] / libavformat / movenc.c
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 = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
261     // if no mac fcc found, try with Microsoft tags
262     if (!tag)
263     {
264         int tmp = codec_get_tag(codec_wav_tags, track->enc->codec_id);
265         tag = MKTAG('m', 's', ((tmp >> 8) & 0xff), (tmp & 0xff));
266     }
267     put_le32(pb, tag); // store it byteswapped
268
269     put_be32(pb, 0); /* Reserved */
270     put_be16(pb, 0); /* Reserved */
271     put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
272
273     /* SoundDescription */
274     if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
275         put_be16(pb, 1); /* Version 1 */
276     else
277         put_be16(pb, 0); /* Version 0 */
278     put_be16(pb, 0); /* Revision level */
279     put_be32(pb, 0); /* Reserved */
280
281     put_be16(pb, track->enc->channels); /* Number of channels */
282     /* TODO: Currently hard-coded to 16-bit, there doesn't seem
283                  to be a good way to get number of bits of audio */
284     put_be16(pb, 0x10); /* Reserved */
285
286     if(track->enc->codec_id == CODEC_ID_AAC ||
287        track->enc->codec_id == CODEC_ID_MP3)
288     {
289         put_be16(pb, 0xfffe); /* compression ID (vbr)*/
290     }
291     else
292     {
293         put_be16(pb, 0); /* compression ID (= 0) */
294     }
295     put_be16(pb, 0); /* packet size (= 0) */
296     put_be16(pb, track->timescale); /* Time scale */
297     put_be16(pb, 0); /* Reserved */
298
299     if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
300     {
301         /* SoundDescription V1 extended info */
302         put_be32(pb, track->enc->frame_size); /* Samples per packet  */
303         put_be32(pb, 1536); /* Bytes per packet */
304         put_be32(pb, 2); /* Bytes per frame */
305         put_be32(pb, 2); /* Bytes per sample */
306     }
307
308     if(track->enc->codec_id == CODEC_ID_AAC) {
309         if( track->mode == MODE_MOV ) mov_write_wave_tag(pb, track);
310         else mov_write_esds_tag(pb, track);
311     }
312     if(track->enc->codec_id == CODEC_ID_AMR_NB)
313         mov_write_damr_tag(pb);
314     return updateSize (pb, pos);
315 }
316
317 static int mov_write_d263_tag(ByteIOContext *pb)
318 {
319     put_be32(pb, 0xf); /* size */
320     put_tag(pb, "d263");
321     put_tag(pb, "FFMP");
322     put_be16(pb, 0x0a);
323     put_byte(pb, 0);
324     return 0xf;
325 }
326
327 /* TODO: No idea about these values */
328 static int mov_write_svq3_tag(ByteIOContext *pb)
329 {
330     put_be32(pb, 0x15);
331     put_tag(pb, "SMI ");
332     put_tag(pb, "SEQH");
333     put_be32(pb, 0x5);
334     put_be32(pb, 0xe2c0211d);
335     put_be32(pb, 0xc0000000);
336     put_byte(pb, 0);   
337     return 0x15;
338 }
339
340 static unsigned int descrLength(unsigned int len)
341 {
342     if (len < 0x00000080)
343         return 2 + len;
344     else if (len < 0x00004000)
345         return 3 + len;
346     else if(len < 0x00200000)
347         return 4 + len;
348     else
349         return 5 + len;
350 }
351
352 static void putDescr(ByteIOContext *pb, int tag, int size)
353 {
354     uint32_t len;
355     uint8_t  vals[4];
356
357     len = size;
358     vals[3] = (uint8_t)(len & 0x7f);
359     len >>= 7;
360     vals[2] = (uint8_t)((len & 0x7f) | 0x80); 
361     len >>= 7;
362     vals[1] = (uint8_t)((len & 0x7f) | 0x80); 
363     len >>= 7;
364     vals[0] = (uint8_t)((len & 0x7f) | 0x80);
365
366     put_byte(pb, tag); // DescriptorTag
367
368     if (size < 0x00000080)
369     {
370         put_byte(pb, vals[3]);
371     }
372     else if (size < 0x00004000)
373     {
374         put_byte(pb, vals[2]);
375         put_byte(pb, vals[3]);
376     }
377     else if (size < 0x00200000)
378     {
379         put_byte(pb, vals[1]);
380         put_byte(pb, vals[2]);
381         put_byte(pb, vals[3]);
382     }
383     else if (size < 0x10000000)
384     {
385         put_byte(pb, vals[0]);
386         put_byte(pb, vals[1]);
387         put_byte(pb, vals[2]);
388         put_byte(pb, vals[3]);
389     }
390 }
391
392 static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
393 {
394     int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
395     int pos = url_ftell(pb);
396
397     put_be32(pb, 0);               // size
398     put_tag(pb, "esds");
399     put_be32(pb, 0);               // Version
400
401     // ES descriptor
402     putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
403              descrLength(1));
404     put_be16(pb, 0x0001);          // ID (= 1)
405     put_byte(pb, 0x00);            // flags (= no flags)
406
407     // DecoderConfig descriptor
408     putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);
409
410     if(track->enc->codec_id == CODEC_ID_AAC)
411         put_byte(pb, 0x40);        // Object type indication
412     else if(track->enc->codec_id == CODEC_ID_MPEG4)
413         put_byte(pb, 0x20);        // Object type indication (Visual 14496-2)
414
415     if(track->enc->codec_type == CODEC_TYPE_AUDIO)
416         put_byte(pb, 0x15);            // flags (= Audiostream)
417     else
418         put_byte(pb, 0x11);            // flags (= Visualstream)
419
420     put_byte(pb, 0x0);             // Buffersize DB (24 bits)
421     put_be16(pb, 0x0dd2);          // Buffersize DB
422
423     // TODO: find real values for these
424     put_be32(pb, 0x0002e918);     // maxbitrate
425     put_be32(pb, 0x00017e6b);     // avg bitrate
426
427     if (track->vosLen)
428     {
429         // DecoderSpecific info descriptor
430         putDescr(pb, 0x05, track->vosLen);
431         put_buffer(pb, track->vosData, track->vosLen);
432     }
433
434     // SL descriptor
435     putDescr(pb, 0x06, 1);
436     put_byte(pb, 0x02);
437     return updateSize (pb, pos);
438 }
439
440 const CodecTag codec_movvideo_tags[] = {
441     { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') },
442     { CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') },
443     { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
444     { CODEC_ID_H263, MKTAG('s', '2', '6', '3') },
445     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') },
446     { 0, 0 },
447 };
448
449 static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
450 {
451     int pos = url_ftell(pb);
452     int tag;
453
454     put_be32(pb, 0); /* size */
455
456     tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
457     // if no mac fcc found, try with Microsoft tags
458     if (!tag)
459         tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
460     put_le32(pb, tag); // store it byteswapped
461
462     put_be32(pb, 0); /* Reserved */
463     put_be16(pb, 0); /* Reserved */
464     put_be16(pb, 1); /* Data-reference index */
465
466     put_be32(pb, 0); /* Reserved (= 02000c) */
467     put_be32(pb, 0); /* Reserved ("SVis")*/
468     put_be32(pb, 0); /* Reserved */
469     put_be32(pb, 0); /* Reserved (400)*/
470     put_be16(pb, track->enc->width); /* Video width */
471     put_be16(pb, track->enc->height); /* Video height */
472     put_be32(pb, 0x00480000); /* Reserved */
473     put_be32(pb, 0x00480000); /* Reserved */
474     put_be32(pb, 0); /* Data size (= 0) */
475     put_be16(pb, 1); /* Frame count (= 1) */
476     
477     put_be32(pb, 0); /* Reserved */
478     put_be32(pb, 0); /* Reserved */
479     put_be32(pb, 0); /* Reserved */
480     put_be32(pb, 0); /* Reserved */
481     put_be32(pb, 0); /* Reserved */
482     put_be32(pb, 0); /* Reserved */
483     put_be32(pb, 0); /* Reserved */
484     put_be32(pb, 0); /* Reserved */
485     
486     put_be16(pb, 0x18); /* Reserved */
487     put_be16(pb, 0xffff); /* Reserved */
488     if(track->enc->codec_id == CODEC_ID_MPEG4)
489         mov_write_esds_tag(pb, track);
490     else if(track->enc->codec_id == CODEC_ID_H263)
491         mov_write_d263_tag(pb);
492     else if(track->enc->codec_id == CODEC_ID_SVQ3)
493         mov_write_svq3_tag(pb);    
494
495     return updateSize (pb, pos);
496 }
497
498 static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
499 {
500     int pos = url_ftell(pb);
501     put_be32(pb, 0); /* size */
502     put_tag(pb, "stsd");
503     put_be32(pb, 0); /* version & flags */
504     put_be32(pb, 1); /* entry count */
505     if (track->enc->codec_type == CODEC_TYPE_VIDEO)
506         mov_write_video_tag(pb, track);
507     else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
508         mov_write_audio_tag(pb, track);
509     return updateSize(pb, pos);
510 }
511
512 /* TODO?: Currently all samples/frames seem to have same duration */
513 /* Time to sample atom */
514 static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
515 {
516     put_be32(pb, 0x18); /* size */
517     put_tag(pb, "stts");
518     put_be32(pb, 0); /* version & flags */
519     put_be32(pb, 1); /* entry count */
520
521     put_be32(pb, track->sampleCount); /* sample count */
522     put_be32(pb, track->sampleDuration); /* sample duration */
523     return 0x18;
524 }
525
526 static int mov_write_dref_tag(ByteIOContext *pb)
527 {
528     put_be32(pb, 28); /* size */
529     put_tag(pb, "dref");
530     put_be32(pb, 0); /* version & flags */
531     put_be32(pb, 1); /* entry count */
532
533     put_be32(pb, 0xc); /* size */
534     put_tag(pb, "url ");
535     put_be32(pb, 1); /* version & flags */
536
537     return 28;
538 }
539
540 static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
541 {
542     int pos = url_ftell(pb);
543     put_be32(pb, 0); /* size */
544     put_tag(pb, "stbl");
545     mov_write_stsd_tag(pb, track);
546     mov_write_stts_tag(pb, track);
547     if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
548         track->hasKeyframes)
549         mov_write_stss_tag(pb, track);
550     mov_write_stsc_tag(pb, track);
551     mov_write_stsz_tag(pb, track);
552     mov_write_stco_tag(pb, track);
553     return updateSize(pb, pos);
554 }
555
556 static int mov_write_dinf_tag(ByteIOContext *pb)
557 {
558     int pos = url_ftell(pb);
559     put_be32(pb, 0); /* size */
560     put_tag(pb, "dinf");
561     mov_write_dref_tag(pb);
562     return updateSize(pb, pos);
563 }
564
565 static int mov_write_smhd_tag(ByteIOContext *pb)
566 {
567     put_be32(pb, 16); /* size */
568     put_tag(pb, "smhd");
569     put_be32(pb, 0); /* version & flags */
570     put_be16(pb, 0); /* reserved (balance, normally = 0) */
571     put_be16(pb, 0); /* reserved */
572     return 16;
573 }
574
575 static int mov_write_vmhd_tag(ByteIOContext *pb)
576 {
577     put_be32(pb, 0x14); /* size (always 0x14) */
578     put_tag(pb, "vmhd");
579     put_be32(pb, 0x01); /* version & flags */
580     put_be64(pb, 0); /* reserved (graphics mode = copy) */
581     return 0x14;
582 }
583
584 static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
585 {
586     char *descr, *hdlr, *hdlr_type;
587     int pos = url_ftell(pb);
588     
589     if (!track) { /* no media --> data handler */
590         hdlr = "dhlr";
591         hdlr_type = "url ";
592         descr = "DataHandler";
593     } else {
594         hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
595         if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
596             hdlr_type = "vide";
597             descr = "VideoHandler";
598         } else {
599             hdlr_type = "soun";
600             descr = "SoundHandler";
601         }
602     }
603     
604     put_be32(pb, 0); /* size */
605     put_tag(pb, "hdlr");
606     put_be32(pb, 0); /* Version & flags */
607     put_buffer(pb, hdlr, 4); /* handler */
608     put_tag(pb, hdlr_type); /* handler type */
609     put_be32(pb ,0); /* reserved */
610     put_be32(pb ,0); /* reserved */
611     put_be32(pb ,0); /* reserved */
612     put_byte(pb, strlen(descr)); /* string counter */
613     put_buffer(pb, descr, strlen(descr)); /* handler description */
614     return updateSize(pb, pos);
615 }
616
617 static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
618 {
619     int pos = url_ftell(pb);
620     put_be32(pb, 0); /* size */
621     put_tag(pb, "minf");
622     if(track->enc->codec_type == CODEC_TYPE_VIDEO)
623         mov_write_vmhd_tag(pb);
624     else
625         mov_write_smhd_tag(pb);
626     if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
627         mov_write_hdlr_tag(pb, NULL);
628     mov_write_dinf_tag(pb);
629     mov_write_stbl_tag(pb, track);
630     return updateSize(pb, pos);
631 }
632
633 static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
634 {
635     put_be32(pb, 32); /* size */
636     put_tag(pb, "mdhd");
637     put_be32(pb, 0); /* Version & flags */
638     put_be32(pb, track->time); /* creation time */
639     put_be32(pb, track->time); /* modification time */
640     put_be32(pb, track->timescale); /* time scale (sample rate for audio) */ 
641     put_be32(pb, track->trackDuration); /* duration */
642     put_be16(pb, 0); /* language, 0 = english */
643     put_be16(pb, 0); /* reserved (quality) */
644     return 32;
645 }
646
647 static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
648 {
649     int pos = url_ftell(pb);
650     put_be32(pb, 0); /* size */
651     put_tag(pb, "mdia");
652     mov_write_mdhd_tag(pb, track);
653     mov_write_hdlr_tag(pb, track);
654     mov_write_minf_tag(pb, track);
655     return updateSize(pb, pos);
656 }
657
658 static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
659 {
660     int64_t maxTrackLenTemp;
661     put_be32(pb, 0x5c); /* size (always 0x5c) */
662     put_tag(pb, "tkhd");
663     put_be32(pb, 0xf); /* version & flags (track enabled) */
664     put_be32(pb, track->time); /* creation time */
665     put_be32(pb, track->time); /* modification time */
666     put_be32(pb, track->trackID); /* track-id */
667     put_be32(pb, 0); /* reserved */
668     maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale;
669     put_be32(pb, (long)maxTrackLenTemp); /* duration */
670
671     put_be32(pb, 0); /* reserved */
672     put_be32(pb, 0); /* reserved */
673     put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
674     /* Volume, only for audio */
675     if(track->enc->codec_type == CODEC_TYPE_AUDIO)
676         put_be16(pb, 0x0100);
677     else
678         put_be16(pb, 0);
679     put_be16(pb, 0); /* reserved */
680
681     /* Matrix structure */
682     put_be32(pb, 0x00010000); /* reserved */
683     put_be32(pb, 0x0); /* reserved */
684     put_be32(pb, 0x0); /* reserved */
685     put_be32(pb, 0x0); /* reserved */
686     put_be32(pb, 0x00010000); /* reserved */
687     put_be32(pb, 0x0); /* reserved */
688     put_be32(pb, 0x0); /* reserved */
689     put_be32(pb, 0x0); /* reserved */
690     put_be32(pb, 0x40000000); /* reserved */
691
692     /* Track width and height, for visual only */
693     if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
694         double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio);
695         if( !sample_aspect_ratio ) sample_aspect_ratio = 1;
696         put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
697         put_be32(pb, track->enc->height*0x10000);
698     }
699     else {
700         put_be32(pb, 0);
701         put_be32(pb, 0);
702     }
703     return 0x5c;
704 }
705
706 static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
707 {
708     int pos = url_ftell(pb);
709     put_be32(pb, 0); /* size */
710     put_tag(pb, "trak");
711     mov_write_tkhd_tag(pb, track);
712     mov_write_mdia_tag(pb, track);
713     return updateSize(pb, pos);
714 }
715
716 /* TODO: Not sorted out, but not necessary either */
717 static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
718 {
719     put_be32(pb, 0x15); /* size */
720     put_tag(pb, "iods");
721     put_be32(pb, 0);    /* version & flags */
722     put_be16(pb, 0x1007);
723     put_byte(pb, 0);
724     put_be16(pb, 0x4fff);
725     put_be16(pb, 0xfffe);
726     put_be16(pb, 0x01ff);
727     return 0x15;
728 }
729
730 static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
731 {
732     int maxTrackID = 1, maxTrackLen = 0, i;
733     int64_t maxTrackLenTemp;
734
735     put_be32(pb, 0x6c); /* size (always 0x6c) */
736     put_tag(pb, "mvhd");
737     put_be32(pb, 0); /* version & flags */
738     put_be32(pb, mov->time); /* creation time */
739     put_be32(pb, mov->time); /* modification time */
740     put_be32(pb, mov->timescale); /* timescale */
741     for (i=0; i<MAX_STREAMS; i++) {
742         if(mov->tracks[i].entry > 0) {
743             maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale;
744             if(maxTrackLen < maxTrackLenTemp)
745                 maxTrackLen = maxTrackLenTemp;
746             if(maxTrackID < mov->tracks[i].trackID)
747                 maxTrackID = mov->tracks[i].trackID;
748         }
749     }
750     put_be32(pb, maxTrackLen); /* duration of longest track */
751
752     put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
753     put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
754     put_be16(pb, 0); /* reserved */
755     put_be32(pb, 0); /* reserved */
756     put_be32(pb, 0); /* reserved */
757
758     /* Matrix structure */
759     put_be32(pb, 0x00010000); /* reserved */
760     put_be32(pb, 0x0); /* reserved */
761     put_be32(pb, 0x0); /* reserved */
762     put_be32(pb, 0x0); /* reserved */
763     put_be32(pb, 0x00010000); /* reserved */
764     put_be32(pb, 0x0); /* reserved */
765     put_be32(pb, 0x0); /* reserved */
766     put_be32(pb, 0x0); /* reserved */
767     put_be32(pb, 0x40000000); /* reserved */
768
769     put_be32(pb, 0); /* reserved (preview time) */
770     put_be32(pb, 0); /* reserved (preview duration) */
771     put_be32(pb, 0); /* reserved (poster time) */
772     put_be32(pb, 0); /* reserved (selection time) */
773     put_be32(pb, 0); /* reserved (selection duration) */
774     put_be32(pb, 0); /* reserved (current time) */
775     put_be32(pb, maxTrackID+1); /* Next track id */
776     return 0x6c;
777 }
778
779 static int mov_write_itunes_hdlr_tag(ByteIOContext *pb, MOVContext* mov,
780                                      AVFormatContext *s)
781 {
782     int pos = url_ftell(pb);
783     put_be32(pb, 0); /* size */
784     put_tag(pb, "hdlr");
785     put_be32(pb, 0);
786     put_be32(pb, 0);
787     put_tag(pb, "mdir");
788     put_tag(pb, "appl");
789     put_be32(pb, 0);
790     put_be32(pb, 0);
791     put_be16(pb, 0);
792     return updateSize(pb, pos);
793 }
794
795 /* helper function to write a data tag with the specified string as data */
796 static int mov_write_string_data_tag(ByteIOContext *pb, MOVContext* mov,
797                                      AVFormatContext *s, const char *data)
798 {
799     int pos = url_ftell(pb);
800     put_be32(pb, 0); /* size */
801     put_tag(pb, "data");
802     put_be32(pb, 1);
803     put_be32(pb, 0);
804     put_buffer(pb, data, strlen(data));
805     return updateSize(pb, pos);
806 }
807
808 /* iTunes name of the song/movie */
809 static int mov_write_nam_tag(ByteIOContext *pb, MOVContext* mov,
810                              AVFormatContext *s)
811 {
812     int size = 0;
813     if ( s->title[0] ) {
814         int pos = url_ftell(pb);
815         put_be32(pb, 0); /* size */
816         put_tag(pb, "\251nam");
817         mov_write_string_data_tag(pb, mov, s, s->title);
818         size = updateSize(pb, pos);
819     }
820     return size;
821 }
822
823 /* iTunes name of the artist/performer */
824 static int mov_write_ART_tag(ByteIOContext *pb, MOVContext* mov,
825                              AVFormatContext *s)
826 {
827     int size = 0;
828     if ( s->author[0] ) {
829         int pos = url_ftell(pb);
830         put_be32(pb, 0); /* size */
831         put_tag(pb, "\251ART");
832         // we use the author here as this is the only thing that we have...
833         mov_write_string_data_tag(pb, mov, s, s->author);
834         size = updateSize(pb, pos);
835     }
836     return size;
837 }
838
839 /* iTunes name of the writer */
840 static int mov_write_wrt_tag(ByteIOContext *pb, MOVContext* mov,
841                              AVFormatContext *s)
842 {
843     int size = 0;
844     if ( s->author[0] ) {
845         int pos = url_ftell(pb);
846         put_be32(pb, 0); /* size */
847         put_tag(pb, "\251wrt");
848         mov_write_string_data_tag(pb, mov, s, s->author);
849         size = updateSize(pb, pos);
850     }
851     return size;
852 }
853
854 /* iTunes name of the album */
855 static int mov_write_alb_tag(ByteIOContext *pb, MOVContext* mov,
856                              AVFormatContext *s)
857 {
858     int size = 0;
859     if ( s->album[0] ) {
860         int pos = url_ftell(pb);
861         put_be32(pb, 0); /* size */
862         put_tag(pb, "\251alb");
863         mov_write_string_data_tag(pb, mov, s, s->album);
864         size = updateSize(pb, pos);
865     }
866     return size;
867 }
868
869 /* iTunes year */
870 static int mov_write_day_tag(ByteIOContext *pb, MOVContext* mov,
871                              AVFormatContext *s)
872 {
873     char year[5];
874     int size = 0;
875     if ( s->year ) {
876         int pos = url_ftell(pb);
877         put_be32(pb, 0); /* size */
878         put_tag(pb, "\251day");
879         snprintf(year, 5, "%04d", s->year);
880         mov_write_string_data_tag(pb, mov, s, year);
881         size = updateSize(pb, pos);
882     }
883     return size;
884 }
885
886 /* iTunes tool used to create the file */
887 static int mov_write_too_tag(ByteIOContext *pb, MOVContext* mov,
888                              AVFormatContext *s)
889 {
890     int pos = url_ftell(pb);
891     put_be32(pb, 0); /* size */
892     put_tag(pb, "\251too");
893     mov_write_string_data_tag(pb, mov, s, LIBAVFORMAT_IDENT);
894     return updateSize(pb, pos);
895 }
896
897 /* iTunes comment */
898 static int mov_write_cmt_tag(ByteIOContext *pb, MOVContext* mov,
899                              AVFormatContext *s)
900 {
901     int size = 0;
902     if ( s->comment[0] ) {
903         int pos = url_ftell(pb);
904         put_be32(pb, 0); /* size */
905         put_tag(pb, "\251cmt");
906         mov_write_string_data_tag(pb, mov, s, s->comment);
907         size = updateSize(pb, pos);
908     }
909     return size;
910 }
911
912 /* iTunes custom genre */
913 static int mov_write_gen_tag(ByteIOContext *pb, MOVContext* mov,
914                              AVFormatContext *s)
915 {
916     int size = 0;
917     if ( s->genre[0] ) {
918         int pos = url_ftell(pb);
919         put_be32(pb, 0); /* size */
920         put_tag(pb, "\251gen");
921         mov_write_string_data_tag(pb, mov, s, s->genre);
922         size = updateSize(pb, pos);
923     }
924     return size;
925 }
926
927 /* iTunes track number */
928 static int mov_write_trkn_tag(ByteIOContext *pb, MOVContext* mov,
929                               AVFormatContext *s)
930 {
931     int size = 0;
932     if ( s->track ) {
933         int pos = url_ftell(pb);
934         put_be32(pb, 0); /* size */
935         put_tag(pb, "trkn");
936         {
937             int pos = url_ftell(pb);
938             put_be32(pb, 0); /* size */
939             put_tag(pb, "data");
940             put_be32(pb, 0);        // 8 bytes empty
941             put_be32(pb, 0);
942             put_be16(pb, 0);        // empty
943             put_be16(pb, s->track); // track number
944             put_be16(pb, 0);        // total track number
945             put_be16(pb, 0);        // empty
946             updateSize(pb, pos);
947         }
948         size = updateSize(pb, pos);
949     }
950     return size;
951 }
952
953 /* iTunes meta data list */
954 static int mov_write_ilst_tag(ByteIOContext *pb, MOVContext* mov,
955                               AVFormatContext *s)
956 {
957     int pos = url_ftell(pb);
958     put_be32(pb, 0); /* size */
959     put_tag(pb, "ilst");
960     mov_write_nam_tag(pb, mov, s);
961     mov_write_ART_tag(pb, mov, s);
962     mov_write_wrt_tag(pb, mov, s);
963     mov_write_alb_tag(pb, mov, s);
964     mov_write_day_tag(pb, mov, s);
965     mov_write_too_tag(pb, mov, s);
966     mov_write_cmt_tag(pb, mov, s);
967     mov_write_gen_tag(pb, mov, s);
968     mov_write_trkn_tag(pb, mov, s);
969     return updateSize(pb, pos);
970 }
971
972 /* iTunes meta data tag */
973 static int mov_write_meta_tag(ByteIOContext *pb, MOVContext* mov,
974                               AVFormatContext *s)
975 {
976     int size = 0;
977
978     // only save meta tag if required
979     if ( s->title[0] || s->author[0] || s->album[0] || s->year || 
980          s->comment[0] || s->genre[0] || s->track ) {
981         int pos = url_ftell(pb);
982         put_be32(pb, 0); /* size */
983         put_tag(pb, "meta");
984         put_be32(pb, 0);
985         mov_write_itunes_hdlr_tag(pb, mov, s);
986         mov_write_ilst_tag(pb, mov, s);
987         size = updateSize(pb, pos);
988     }
989     return size;
990 }
991     
992 static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov,
993                               AVFormatContext *s)
994 {
995     int pos = url_ftell(pb);
996     int i;
997
998     put_be32(pb, 0); /* size */
999     put_tag(pb, "udta");
1000
1001     /* iTunes meta data */
1002     mov_write_meta_tag(pb, mov, s);
1003
1004     /* Requirements */
1005     for (i=0; i<MAX_STREAMS; i++) {
1006         if(mov->tracks[i].entry <= 0) continue;
1007         if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC ||
1008             mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) {
1009             int pos = url_ftell(pb);
1010             put_be32(pb, 0); /* size */
1011             put_tag(pb, "\251req");
1012             put_be16(pb, sizeof("QuickTime 6.0 or greater") - 1);
1013             put_be16(pb, 0);
1014             put_buffer(pb, "QuickTime 6.0 or greater",
1015                        sizeof("QuickTime 6.0 or greater") - 1);
1016             updateSize(pb, pos);
1017             break;
1018         }
1019     }
1020
1021     /* Encoder */
1022     if(!(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT))
1023     {
1024         int pos = url_ftell(pb);
1025         put_be32(pb, 0); /* size */
1026         put_tag(pb, "\251enc");
1027         put_be16(pb, sizeof(LIBAVFORMAT_IDENT) - 1); /* string length */
1028         put_be16(pb, 0);
1029         put_buffer(pb, LIBAVFORMAT_IDENT, sizeof(LIBAVFORMAT_IDENT) - 1);
1030         updateSize(pb, pos);
1031     }
1032
1033     if( s->title[0] )
1034     {
1035         int pos = url_ftell(pb);
1036         put_be32(pb, 0); /* size */
1037         put_tag(pb, "\251nam");
1038         put_be16(pb, strlen(s->title)); /* string length */
1039         put_be16(pb, 0);
1040         put_buffer(pb, s->title, strlen(s->title));
1041         updateSize(pb, pos);
1042     }
1043
1044     if( s->author[0] )
1045     {
1046         int pos = url_ftell(pb);
1047         put_be32(pb, 0); /* size */
1048         put_tag(pb, /*"\251aut"*/ "\251day" );
1049         put_be16(pb, strlen(s->author)); /* string length */
1050         put_be16(pb, 0);
1051         put_buffer(pb, s->author, strlen(s->author));
1052         updateSize(pb, pos);
1053     }
1054
1055     if( s->comment[0] )
1056     {
1057         int pos = url_ftell(pb);
1058         put_be32(pb, 0); /* size */
1059         put_tag(pb, "\251des");
1060         put_be16(pb, strlen(s->comment)); /* string length */
1061         put_be16(pb, 0);
1062         put_buffer(pb, s->comment, strlen(s->comment));
1063         updateSize(pb, pos);
1064     }
1065
1066     return updateSize(pb, pos);
1067 }
1068
1069 static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov,
1070                               AVFormatContext *s)
1071 {
1072     int pos, i;
1073     pos = url_ftell(pb);
1074     put_be32(pb, 0); /* size placeholder*/
1075     put_tag(pb, "moov");
1076     mov->timescale = globalTimescale;
1077
1078     for (i=0; i<MAX_STREAMS; i++) {
1079         if(mov->tracks[i].entry <= 0) continue;
1080
1081         if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
1082             mov->tracks[i].timescale = mov->tracks[i].enc->frame_rate;
1083             mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_rate_base;
1084         }
1085         else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
1086             /* If AMR, track timescale = 8000, AMR_WB = 16000 */
1087             if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
1088                 mov->tracks[i].sampleDuration = 160;  // Bytes per chunk
1089                 mov->tracks[i].timescale = 8000;
1090             }
1091             else {
1092                 mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
1093                 mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size;
1094             }
1095         }
1096
1097         mov->tracks[i].trackDuration = 
1098             mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration;
1099         mov->tracks[i].time = mov->time;
1100         mov->tracks[i].trackID = i+1;
1101     }
1102
1103     mov_write_mvhd_tag(pb, mov);
1104     //mov_write_iods_tag(pb, mov);
1105     for (i=0; i<MAX_STREAMS; i++) {
1106         if(mov->tracks[i].entry > 0) {
1107             mov_write_trak_tag(pb, &(mov->tracks[i]));
1108         }
1109     }
1110
1111     mov_write_udta_tag(pb, mov, s);
1112
1113     return updateSize(pb, pos);
1114 }
1115
1116 int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
1117 {
1118     mov->mdat_pos = url_ftell(pb); 
1119     put_be32(pb, 0); /* size placeholder*/
1120     put_tag(pb, "mdat");
1121     return 0;
1122 }
1123
1124 /* TODO: This needs to be more general */
1125 int mov_write_ftyp_tag(ByteIOContext *pb, AVFormatContext *s)
1126 {
1127     MOVContext *mov = s->priv_data;
1128
1129     put_be32(pb, 0x14 ); /* size */
1130     put_tag(pb, "ftyp");
1131
1132     if ( mov->mode == MODE_3GP )
1133         put_tag(pb, "3gp4");
1134     else
1135         put_tag(pb, "isom");
1136
1137     put_be32(pb, 0x200 );
1138
1139     if ( mov->mode == MODE_3GP )
1140         put_tag(pb, "3gp4");
1141     else
1142         put_tag(pb, "mp41");
1143
1144     return 0x14;
1145 }
1146
1147 static int mov_write_header(AVFormatContext *s)
1148 {
1149     ByteIOContext *pb = &s->pb;
1150     MOVContext *mov = s->priv_data;
1151     int i;
1152
1153     for(i=0; i<s->nb_streams; i++){
1154         AVCodecContext *c= &s->streams[i]->codec;
1155
1156         if      (c->codec_type == CODEC_TYPE_VIDEO){
1157             if (!codec_get_tag(codec_movvideo_tags, c->codec_id)){
1158                 if(!codec_get_tag(codec_bmp_tags, c->codec_id))
1159                     return -1;
1160                 else
1161                     av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, the file may be unplayable!\n");
1162             }
1163         }else if(c->codec_type == CODEC_TYPE_AUDIO){
1164             if (!codec_get_tag(codec_movaudio_tags, c->codec_id)){
1165                 if(!codec_get_tag(codec_wav_tags, c->codec_id))
1166                     return -1;
1167                 else
1168                     av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, the file may be unplayable!\n");
1169             }
1170         }
1171     }
1172
1173     /* Default mode == MP4 */
1174     mov->mode = MODE_MP4;
1175
1176     if (s->oformat != NULL) {
1177         if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
1178         else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
1179
1180         if ( mov->mode == MODE_3GP || mov->mode == MODE_MP4 )
1181             mov_write_ftyp_tag(pb,s);
1182     }
1183
1184     for (i=0; i<MAX_STREAMS; i++) {
1185         mov->tracks[i].mode = mov->mode;
1186     }
1187
1188     put_flush_packet(pb);
1189
1190     return 0;
1191 }
1192
1193 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
1194 {
1195     MOVContext *mov = s->priv_data;
1196     ByteIOContext *pb = &s->pb;
1197     AVCodecContext *enc = &s->streams[pkt->stream_index]->codec;
1198     MOVTrack* trk = &mov->tracks[pkt->stream_index];
1199     int cl, id;
1200     unsigned int samplesInChunk = 0;
1201     int size= pkt->size;
1202
1203     if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */
1204     if (!size) return 0; /* Discard 0 sized packets */
1205
1206     if (enc->codec_type == CODEC_TYPE_VIDEO ) {
1207         samplesInChunk = 1;
1208     }
1209     else if (enc->codec_type == CODEC_TYPE_AUDIO ) {
1210         if( enc->codec_id == CODEC_ID_AMR_NB) {
1211             /* We must find out how many AMR blocks there are in one packet */
1212             static uint16_t packed_size[16] =
1213                 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
1214             int len = 0;
1215
1216             while (len < size && samplesInChunk < 100) {
1217                 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
1218                 samplesInChunk++;
1219             }
1220         }
1221         else if(enc->codec_id == CODEC_ID_PCM_ALAW) {
1222             samplesInChunk = size/enc->channels;
1223         }
1224         else if(enc->codec_id == CODEC_ID_PCM_S16BE || enc->codec_id == CODEC_ID_PCM_S16LE) {
1225             samplesInChunk = size/(2*enc->channels);
1226         }           
1227         else {
1228             samplesInChunk = 1;
1229         }
1230     }
1231
1232     if ((enc->codec_id == CODEC_ID_MPEG4 || enc->codec_id == CODEC_ID_AAC)
1233         && trk->vosLen == 0) {
1234 //        assert(enc->extradata_size);
1235
1236         trk->vosLen = enc->extradata_size;
1237         trk->vosData = av_malloc(trk->vosLen);
1238         memcpy(trk->vosData, enc->extradata, trk->vosLen);
1239     }
1240
1241     cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
1242     id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
1243
1244     if (trk->ents_allocated <= trk->entry) {
1245         trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*)); 
1246         if (!trk->cluster)
1247             return -1;
1248         trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
1249         if (!trk->cluster[cl])
1250             return -1;
1251         trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
1252     }
1253     if (mov->mdat_written == 0) {
1254         mov_write_mdat_tag(pb, mov);
1255         mov->mdat_written = 1;
1256         mov->time = s->timestamp;
1257     }
1258
1259     trk->cluster[cl][id].pos = url_ftell(pb);
1260     trk->cluster[cl][id].samplesInChunk = samplesInChunk;
1261     trk->cluster[cl][id].size = size;
1262     trk->cluster[cl][id].entries = samplesInChunk;
1263     if(enc->codec_type == CODEC_TYPE_VIDEO) {
1264         trk->cluster[cl][id].key_frame = !!(pkt->flags & PKT_FLAG_KEY);
1265         if(trk->cluster[cl][id].key_frame)
1266             trk->hasKeyframes = 1;
1267     }
1268     trk->enc = enc;
1269     trk->entry++;
1270     trk->sampleCount += samplesInChunk;
1271     trk->mdat_size += size;
1272
1273     put_buffer(pb, pkt->data, size);
1274
1275     put_flush_packet(pb);
1276     return 0;
1277 }
1278
1279 static int mov_write_trailer(AVFormatContext *s)
1280 {
1281     MOVContext *mov = s->priv_data;
1282     ByteIOContext *pb = &s->pb;
1283     int res = 0;
1284     int i, j;
1285
1286     offset_t moov_pos = url_ftell(pb);
1287
1288     /* Write size of mdat tag */
1289     for (i=0, j=0; i<MAX_STREAMS; i++) {
1290         if(mov->tracks[i].ents_allocated > 0) {
1291             j += mov->tracks[i].mdat_size;
1292         }
1293     }
1294     url_fseek(pb, mov->mdat_pos, SEEK_SET);
1295     put_be32(pb, j+8);
1296     url_fseek(pb, moov_pos, SEEK_SET);
1297
1298     mov_write_moov_tag(pb, mov, s);
1299
1300     for (i=0; i<MAX_STREAMS; i++) {
1301         for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
1302             av_free(mov->tracks[i].cluster[j]);
1303         }
1304         av_free(mov->tracks[i].cluster);
1305         if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData );
1306
1307         mov->tracks[i].cluster = NULL;
1308         mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
1309     }
1310
1311     put_flush_packet(pb);
1312
1313     return res;
1314 }
1315
1316 static AVOutputFormat mov_oformat = {
1317     "mov",
1318     "mov format",
1319     NULL,
1320     "mov",
1321     sizeof(MOVContext),
1322     CODEC_ID_AAC,
1323     CODEC_ID_MPEG4,
1324     mov_write_header,
1325     mov_write_packet,
1326     mov_write_trailer,
1327 };
1328
1329 static AVOutputFormat _3gp_oformat = {
1330     "3gp",
1331     "3gp format",
1332     NULL,
1333     "3gp",
1334     sizeof(MOVContext),
1335     CODEC_ID_AMR_NB,
1336     CODEC_ID_H263,
1337     mov_write_header,
1338     mov_write_packet,
1339     mov_write_trailer,
1340 };
1341
1342 static AVOutputFormat mp4_oformat = {
1343     "mp4",
1344     "mp4 format",
1345     "application/mp4",
1346     "mp4,m4a",
1347     sizeof(MOVContext),
1348     CODEC_ID_AAC,
1349     CODEC_ID_MPEG4,
1350     mov_write_header,
1351     mov_write_packet,
1352     mov_write_trailer,
1353 };
1354
1355 int movenc_init(void)
1356 {
1357     av_register_output_format(&mov_oformat);
1358     av_register_output_format(&_3gp_oformat);
1359     av_register_output_format(&mp4_oformat);
1360     return 0;
1361 }