]> git.sesse.net Git - ffmpeg/blob - libavformat/movenc.c
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
[ffmpeg] / libavformat / movenc.c
1 /*
2  * MOV, 3GP, MP4 encoder.
3  * Copyright (c) 2003 Thomas Raivio.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include "avformat.h"
20 #include "avi.h"
21 #include "avio.h"
22 #include <time.h>
23
24 #undef NDEBUG
25 #include <assert.h>
26
27 #define MOV_INDEX_CLUSTER_SIZE 16384
28 #define globalTimescale 1000
29
30 typedef struct MOVIentry {
31     unsigned int flags, pos, len;
32     unsigned int chunkSize;
33     char         key_frame;
34     unsigned int entries;
35 } MOVIentry;
36
37 typedef struct MOVIndex {
38     int         entry;
39     int         samples;
40     int         mdat_size;
41     int         ents_allocated;
42     long        timescale;
43     long        time;
44     long        frameCount;
45     long        trackDuration;
46     long        sampleDelta;
47     int         hasKeyframes;
48     int         trackID;
49     AVCodecContext *enc;
50
51     int         vosLen;
52     uint8_t     *vosData;
53     MOVIentry** cluster;
54 } MOVTrack;
55
56 typedef struct {
57     long    time;
58     int     nb_streams;
59     int     mdat_written;
60     offset_t mdat_pos;
61     offset_t movi_list;
62     long    timescale;
63     MOVTrack tracks[MAX_STREAMS];
64 } MOVContext;
65
66 //FIXME supprt 64bit varaint with wide placeholders
67 static int updateSize (ByteIOContext *pb, int pos)
68 {
69     long curpos = url_ftell(pb);
70     url_fseek(pb, pos, SEEK_SET);
71     put_be32(pb, curpos - pos); /* rewrite size */
72     url_fseek(pb, curpos, SEEK_SET);
73
74     return curpos - pos;
75 }
76
77 static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
78 {
79     int i;
80     int pos = url_ftell(pb);
81     put_be32(pb, 0); /* size */
82     put_tag(pb, "stco");
83     put_be32(pb, 0); /* version & flags */
84     put_be32(pb, track->entry); /* entry count */
85     for (i=0; i<track->entry; i++) {
86         int cl = i / MOV_INDEX_CLUSTER_SIZE;
87         int id = i % MOV_INDEX_CLUSTER_SIZE;
88         put_be32(pb, track->cluster[cl][id].pos);
89     }
90     return updateSize (pb, pos);
91 }
92
93 static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
94 {
95     int equalChunks = 1;
96     int i, tst = -1, oldtst = -1;
97
98     int pos = url_ftell(pb);
99     put_be32(pb, 0); /* size */
100     put_tag(pb, "stsz");
101     put_be32(pb, 0); /* version & flags */
102
103     for (i=0; i<track->entry; i++) {
104         int cl = i / MOV_INDEX_CLUSTER_SIZE;
105         int id = i % MOV_INDEX_CLUSTER_SIZE;
106         tst = track->cluster[cl][id].len;
107           if(oldtst != -1 && tst != oldtst) {
108           equalChunks = 0;
109           break;
110         }
111         oldtst = tst;
112     }
113     if(equalChunks ||
114        track->enc->codec_type == CODEC_TYPE_AUDIO) {
115         //int sSize = track->cluster[0][0].len/track->cluster[0][0].entries;
116         int sSize = track->cluster[0][0].len;
117         put_be32(pb, sSize); // sample size 
118         put_be32(pb, track->samples/track->enc->channels); // sample count 
119     }
120     else {
121         put_be32(pb, 0); // sample size 
122         put_be32(pb, track->entry); // sample count 
123         for (i=0; i<track->entry; i++) {
124             int cl = i / MOV_INDEX_CLUSTER_SIZE;
125             int id = i % MOV_INDEX_CLUSTER_SIZE;
126             put_be32(pb, track->cluster[cl][id].len);
127         }
128     }
129     return updateSize (pb, pos);
130 }
131
132 static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
133 {
134     int index = 0, oldval = -1, i, entryPos, curpos;
135
136     int pos = url_ftell(pb);
137     put_be32(pb, 0); /* size */
138     put_tag(pb, "stsc");
139     put_be32(pb, 0); // version & flags 
140     entryPos = url_ftell(pb);
141     put_be32(pb, track->entry); // entry count 
142     for (i=0; i<track->entry; i++) {
143         int cl = i / MOV_INDEX_CLUSTER_SIZE;
144         int id = i % MOV_INDEX_CLUSTER_SIZE;
145         if(oldval != track->cluster[cl][id].chunkSize) 
146         {
147             put_be32(pb, i+1); // first chunk 
148             put_be32(pb, track->cluster[cl][id].chunkSize);
149             put_be32(pb, 0x1); // sample description index 
150             oldval = track->cluster[cl][id].chunkSize;
151             index++;
152         }
153     }
154     curpos = url_ftell(pb);
155     url_fseek(pb, entryPos, SEEK_SET);
156     put_be32(pb, index); // rewrite size 
157     url_fseek(pb, curpos, SEEK_SET);
158
159     return updateSize (pb, pos);
160 }
161
162 static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
163 {
164     long curpos;
165     int i, index = 0, entryPos;
166     int pos = url_ftell(pb);
167     put_be32(pb, 0); // size 
168     put_tag(pb, "stss");
169     put_be32(pb, 0); // version & flags 
170     entryPos = url_ftell(pb);
171     put_be32(pb, track->entry); // entry count 
172     for (i=0; i<track->entry; i++) {
173         int cl = i / MOV_INDEX_CLUSTER_SIZE;
174         int id = i % MOV_INDEX_CLUSTER_SIZE;
175         if(track->cluster[cl][id].key_frame == 1) {
176             put_be32(pb, i+1);
177             index++;
178         }
179     }
180     curpos = url_ftell(pb);
181     url_fseek(pb, entryPos, SEEK_SET);
182     put_be32(pb, index); // rewrite size 
183     url_fseek(pb, curpos, SEEK_SET);
184     return updateSize (pb, pos);
185 }
186
187 static int mov_write_damr_tag(ByteIOContext *pb)
188 {
189     put_be32(pb, 0x11); /* size */
190     put_tag(pb, "damr");
191     put_tag(pb, "FFMP");
192     put_byte(pb, 0);
193
194     put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */
195     put_be16(pb, 0xa); /* Mode change period (no restriction) */
196     //put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */
197     //put_be16(pb, 1); /* Mode change period (no restriction) */
198     return 0x11;
199 }
200
201 static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
202 {
203     int pos = url_ftell(pb);
204     put_be32(pb, 0); /* size */
205
206     if(track->enc->codec_id == CODEC_ID_PCM_MULAW)
207       put_tag(pb, "ulaw");
208     else if(track->enc->codec_id == CODEC_ID_PCM_ALAW)
209       put_tag(pb, "alaw");
210     else if(track->enc->codec_id == CODEC_ID_ADPCM_IMA_QT)
211       put_tag(pb, "ima4");
212     else if(track->enc->codec_id == CODEC_ID_MACE3)
213       put_tag(pb, "MAC3");
214     else if(track->enc->codec_id == CODEC_ID_MACE6)
215       put_tag(pb, "MAC6");
216     else if(track->enc->codec_id == CODEC_ID_AAC)
217       put_tag(pb, "mp4a");
218     else if(track->enc->codec_id == CODEC_ID_AMR_NB)
219       put_tag(pb, "samr");
220     else
221       put_tag(pb, "    ");
222
223     put_be32(pb, 0); /* Reserved */
224     put_be16(pb, 0); /* Reserved */
225     put_be16(pb, 1); /* Data-reference index, XXX  == 1 */
226     put_be32(pb, 0); /* Reserved */
227     put_be32(pb, 0); /* Reserved */
228
229     put_be16(pb, track->enc->channels); /* Number of channels */
230     /* TODO: Currently hard-coded to 16-bit, there doesn't seem
231                  to be a good way to get number of bits of audio */
232     put_be16(pb, 0x10); /* Reserved */
233     put_be16(pb, 0); /* compression ID (= 0) */
234     put_be16(pb, 0); /* packet size (= 0) */
235     put_be16(pb, track->timescale); /* Time scale */
236     put_be16(pb, 0); /* Reserved */
237
238     if(track->enc->codec_id == CODEC_ID_AMR_NB)
239         mov_write_damr_tag(pb);
240     return updateSize (pb, pos);
241 }
242
243 static int mov_write_d263_tag(ByteIOContext *pb)
244 {
245     put_be32(pb, 0xf); /* size */
246     put_tag(pb, "d263");
247     put_tag(pb, "FFMP");
248     put_be16(pb, 0x0a);
249     put_byte(pb, 0);
250     return 0xf;
251 }
252
253 /* TODO: No idea about these values */
254 static int mov_write_svq3_tag(ByteIOContext *pb)
255 {
256     put_be32(pb, 0x15);
257     put_tag(pb, "SMI ");
258     put_tag(pb, "SEQH");
259     put_be32(pb, 0x5);
260     put_be32(pb, 0xe2c0211d);
261     put_be32(pb, 0xc0000000);
262     put_byte(pb, 0);   
263     return 0x15;
264 }
265
266 static unsigned int esdsLength(unsigned int len)
267 {
268     unsigned int result = 0;
269     unsigned char b = len & 0x7f;
270     result += b;
271     b = (len >> 8) & 0x7f;
272     result += (b + 0x80) << 8;
273     b = (len >> 16) & 0x7f;
274     result += (b + 0x80) << 16;
275     b = (len >> 24) & 0x7f;
276     result += (b + 0x80) << 24;
277     return result;
278 }
279
280 static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
281 {
282     put_be32(pb, track->vosLen+18+14+17);
283     put_tag(pb, "esds");
284     put_be32(pb, 0);              // Version
285
286     put_byte(pb, 0x03);            // tag = ES_DescriptorTag
287     put_be32(pb, esdsLength(track->vosLen+18+14));  // Length
288     put_be16(pb, 0x0001);         // ID (= 1)
289     put_byte(pb, 0x00);            // flags (= no flags)
290
291 // Decoderconfigdescriptor = 4
292     put_byte(pb, 0x04);            // tag = DecoderConfigDescriptor
293     put_be32(pb, esdsLength(track->vosLen+18));  // Length
294     put_byte(pb, 0x20);            // Object type indication (Visual 14496-2)
295     put_byte(pb, 0x11);            // flags (= Visualstream)
296     put_byte(pb, 0x0);             // Buffersize DB (24 bits)
297     put_be16(pb, 0x0dd2);          // Buffersize DB
298
299     // TODO: find real values for these
300     put_be32(pb, 0x0002e918);     // maxbitrate
301     put_be32(pb, 0x00017e6b);     // avg bitrate
302
303 // Decoderspecific info Tag = 5
304     put_byte(pb, 0x05);           // tag = Decoderspecific info
305     put_be32(pb, esdsLength(track->vosLen));   // length
306     put_buffer(pb, track->vosData, track->vosLen);
307     
308     put_byte(pb, 0x06);
309     put_be32(pb, esdsLength(1));  // length
310     put_byte(pb, 0x02);
311     return track->vosLen+18+14+17;
312 }
313
314 static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
315 {
316     int pos = url_ftell(pb);
317     put_be32(pb, 0); /* size */
318     if(track->enc->codec_id == CODEC_ID_SVQ1)
319       put_tag(pb, "SVQ1");
320     else if(track->enc->codec_id == CODEC_ID_SVQ3)
321       put_tag(pb, "SVQ3");
322     else if(track->enc->codec_id == CODEC_ID_MPEG4)
323       put_tag(pb, "mp4v");
324     else if(track->enc->codec_id == CODEC_ID_H263)
325       put_tag(pb, "s263");
326     else
327       put_tag(pb, "    "); /* Unknown tag */
328
329     put_be32(pb, 0); /* Reserved */
330     put_be16(pb, 0); /* Reserved */
331     put_be16(pb, 1); /* Data-reference index */
332
333     put_be32(pb, 0); /* Reserved (= 02000c) */
334     put_be32(pb, 0); /* Reserved ("SVis")*/
335     put_be32(pb, 0); /* Reserved */
336     put_be32(pb, 0); /* Reserved (400)*/
337     put_be16(pb, track->enc->width); /* Video width */
338     put_be16(pb, track->enc->height); /* Video height */
339     put_be32(pb, 0x00480000); /* Reserved */
340     put_be32(pb, 0x00480000); /* Reserved */
341     put_be32(pb, 0); /* Reserved */
342     put_be32(pb, 0); /* Reserved */
343     put_be32(pb, 0); /* Reserved */
344     put_be32(pb, 0); /* Reserved */
345     put_be32(pb, 0); /* Reserved */
346     put_be32(pb, 0); /* Reserved */
347
348     put_be16(pb, 0); /* Reserved */
349     put_be32(pb, 0); /* Reserved */
350     put_be32(pb, 0); /* Reserved */
351     put_be32(pb, 0); /* Reserved */
352     put_be16(pb, 0x18); /* Reserved */
353     put_be16(pb, 0xffff); /* Reserved */
354     if(track->enc->codec_id == CODEC_ID_MPEG4)
355         mov_write_esds_tag(pb, track);
356     else if(track->enc->codec_id == CODEC_ID_H263)
357         mov_write_d263_tag(pb);
358     else if(track->enc->codec_id == CODEC_ID_SVQ3)
359         mov_write_svq3_tag(pb);    
360
361     return updateSize (pb, pos);
362 }
363
364 static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
365 {
366     int pos = url_ftell(pb);
367     put_be32(pb, 0); /* size */
368     put_tag(pb, "stsd");
369     put_be32(pb, 0); /* version & flags */
370     put_be32(pb, 1); /* entry count */
371     if (track->enc->codec_type == CODEC_TYPE_VIDEO)
372         mov_write_video_tag(pb, track);
373     else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
374         mov_write_audio_tag(pb, track);
375     return updateSize(pb, pos);
376 }
377
378 /* TODO?: Currently all samples/frames seem to have same duration */
379 static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
380 {
381     put_be32(pb, 0x18); /* size */
382     put_tag(pb, "stts");
383     put_be32(pb, 0); /* version & flags */
384     put_be32(pb, 1); /* entry count */
385
386     put_be32(pb, track->frameCount); /* sample count */
387     put_be32(pb, track->sampleDelta); /* sample delta */
388     return 0x18;
389 }
390
391 static int mov_write_dref_tag(ByteIOContext *pb)
392 {
393     put_be32(pb, 28); /* size */
394     put_tag(pb, "dref");
395     put_be32(pb, 0); /* version & flags */
396     put_be32(pb, 1); /* entry count */
397
398     put_be32(pb, 0xc); /* size */
399     put_tag(pb, "url ");
400     put_be32(pb, 1); /* version & flags */
401
402     return 28;
403 }
404
405 static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
406 {
407     int pos = url_ftell(pb);
408     put_be32(pb, 0); /* size */
409     put_tag(pb, "stbl");
410     mov_write_stsd_tag(pb, track);
411     mov_write_stts_tag(pb, track);
412     if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
413         track->hasKeyframes)
414         mov_write_stss_tag(pb, track);
415     mov_write_stsc_tag(pb, track);
416     mov_write_stsz_tag(pb, track);
417     mov_write_stco_tag(pb, track);
418     return updateSize(pb, pos);
419 }
420
421 static int mov_write_dinf_tag(ByteIOContext *pb)
422 {
423     int pos = url_ftell(pb);
424     put_be32(pb, 0); /* size */
425     put_tag(pb, "dinf");
426     mov_write_dref_tag(pb);
427     return updateSize(pb, pos);
428 }
429
430 static int mov_write_smhd_tag(ByteIOContext *pb)
431 {
432     put_be32(pb, 16); /* size */
433     put_tag(pb, "smhd");
434     put_be32(pb, 0); /* version & flags */
435     put_be16(pb, 0); /* reserved (balance, normally = 0) */
436     put_be16(pb, 0); /* reserved */
437     return 16;
438 }
439
440 static int mov_write_vmhd_tag(ByteIOContext *pb)
441 {
442     put_be32(pb, 0x14); /* size (always 0x14) */
443     put_tag(pb, "vmhd");
444     put_be32(pb, 0x01); /* version & flags */
445     put_be64(pb, 0); /* reserved (graphics mode = copy) */
446     return 0x14;
447 }
448
449 static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
450 {
451     int pos = url_ftell(pb);
452     put_be32(pb, 0); /* size */
453     put_tag(pb, "minf");
454     if(track->enc->codec_type == CODEC_TYPE_VIDEO)
455         mov_write_vmhd_tag(pb);
456     else
457         mov_write_smhd_tag(pb);
458     mov_write_dinf_tag(pb);
459     mov_write_stbl_tag(pb, track);
460     return updateSize(pb, pos);
461 }
462
463 static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
464 {
465     char *str;
466     int pos = url_ftell(pb);
467     put_be32(pb, 0); /* size */
468     put_tag(pb, "hdlr");
469     put_be32(pb, 0); /* Version & flags */
470     put_be32(pb, 0); /* reserved */
471     if(track->enc->codec_type == CODEC_TYPE_VIDEO)
472         put_tag(pb, "vide"); /* handler type */
473     else
474         put_tag(pb, "soun"); /* handler type */
475     put_be32(pb ,0); /* reserved */
476     put_be32(pb ,0); /* reserved */
477     put_be32(pb ,0); /* reserved */
478     if(track->enc->codec_type == CODEC_TYPE_VIDEO)
479         str = "VideoHandler";
480     else
481         str = "SoundHandler";
482     put_byte(pb, strlen(str)); /* string counter */
483     put_buffer(pb, str, strlen(str));
484     return updateSize(pb, pos);
485 }
486
487 static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
488 {
489     put_be32(pb, 32); /* size */
490     put_tag(pb, "mdhd");
491     put_be32(pb, 0); /* Version & flags */
492     put_be32(pb, track->time); /* creation time */
493     put_be32(pb, track->time); /* modification time */
494     if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
495         int64_t rate = track->enc->frame_rate;
496         put_be32(pb, rate); 
497         put_be32(pb, rate*(int64_t)track->trackDuration/(int64_t)globalTimescale); // duration 
498     }
499     else {
500       put_be32(pb, track->timescale); /* time scale (sample rate for audio) */ 
501       put_be32(pb, track->trackDuration); /* duration */
502     }
503     put_be16(pb, 0); /* language, 0 = english */
504     put_be16(pb, 0); /* reserved (quality) */
505     return 32;
506 }
507
508 static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
509 {
510     int pos = url_ftell(pb);
511     put_be32(pb, 0); /* size */
512     put_tag(pb, "mdia");
513     mov_write_mdhd_tag(pb, track);
514     mov_write_hdlr_tag(pb, track);
515     mov_write_minf_tag(pb, track);
516     return updateSize(pb, pos);
517 }
518
519 static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
520 {
521     int64_t maxTrackLenTemp;
522     put_be32(pb, 0x5c); /* size (always 0x5c) */
523     put_tag(pb, "tkhd");
524     put_be32(pb, 0xf); /* version & flags (track enabled) */
525     put_be32(pb, track->time); /* creation time */
526     put_be32(pb, track->time); /* modification time */
527     put_be32(pb, track->trackID); /* track-id */
528     put_be32(pb, 0); /* reserved */
529     maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale;
530     put_be32(pb, (long)maxTrackLenTemp); /* duration */
531
532     put_be32(pb, 0); /* reserved */
533     put_be32(pb, 0); /* reserved */
534     put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
535     /* Volume, only for audio */
536     if(track->enc->codec_type == CODEC_TYPE_AUDIO)
537         put_be16(pb, 0x0100);
538     else
539         put_be16(pb, 0);
540     put_be16(pb, 0); /* reserved */
541
542     /* Matrix structure */
543     put_be32(pb, 0x00010000); /* reserved */
544     put_be32(pb, 0x0); /* reserved */
545     put_be32(pb, 0x0); /* reserved */
546     put_be32(pb, 0x0); /* reserved */
547     put_be32(pb, 0x00010000); /* reserved */
548     put_be32(pb, 0x0); /* reserved */
549     put_be32(pb, 0x0); /* reserved */
550     put_be32(pb, 0x0); /* reserved */
551     put_be32(pb, 0x40000000); /* reserved */
552
553     /* Track width and height, for visual only */
554     if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
555         put_be32(pb, track->enc->width*0x10000);
556         put_be32(pb, track->enc->height*0x10000);
557     }
558     else {
559         put_be32(pb, 0);
560         put_be32(pb, 0);
561     }
562     return 0x5c;
563 }
564
565 static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
566 {
567     int pos = url_ftell(pb);
568     put_be32(pb, 0); /* size */
569     put_tag(pb, "trak");
570     mov_write_tkhd_tag(pb, track);
571     mov_write_mdia_tag(pb, track);
572     return updateSize(pb, pos);
573 }
574
575 /* TODO: Not sorted out, but not necessary either */
576 static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
577 {
578     put_be32(pb, 0x15); /* size */
579     put_tag(pb, "iods");
580     put_be32(pb, 0);    /* version & flags */
581     put_be16(pb, 0x1007);
582     put_byte(pb, 0);
583     put_be16(pb, 0x4fff);
584     put_be16(pb, 0xfffe);
585     put_be16(pb, 0x01ff);
586     return 0x15;
587 }
588
589 static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
590 {
591     int maxTrackID = 1, maxTrackLen = 0, i;
592     int64_t maxTrackLenTemp;
593
594     put_be32(pb, 0x6c); /* size (always 0x6c) */
595     put_tag(pb, "mvhd");
596     put_be32(pb, 0); /* version & flags */
597     put_be32(pb, mov->time); /* creation time */
598     put_be32(pb, mov->time); /* modification time */
599     put_be32(pb, mov->timescale); /* timescale */
600     for (i=0; i<MAX_STREAMS; i++) {
601         if(mov->tracks[i].entry > 0) {
602             maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale;
603             if(maxTrackLen < maxTrackLenTemp)
604                 maxTrackLen = maxTrackLenTemp;
605             if(maxTrackID < mov->tracks[i].trackID)
606                 maxTrackID = mov->tracks[i].trackID;
607         }
608     }
609     put_be32(pb, maxTrackLen); /* duration of longest track */
610
611     put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
612     put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
613     put_be16(pb, 0); /* reserved */
614     put_be32(pb, 0); /* reserved */
615     put_be32(pb, 0); /* reserved */
616
617     /* Matrix structure */
618     put_be32(pb, 0x00010000); /* reserved */
619     put_be32(pb, 0x0); /* reserved */
620     put_be32(pb, 0x0); /* reserved */
621     put_be32(pb, 0x0); /* reserved */
622     put_be32(pb, 0x00010000); /* reserved */
623     put_be32(pb, 0x0); /* reserved */
624     put_be32(pb, 0x0); /* reserved */
625     put_be32(pb, 0x0); /* reserved */
626     put_be32(pb, 0x40000000); /* reserved */
627
628     put_be32(pb, 0); /* reserved (preview time) */
629     put_be32(pb, 0); /* reserved (preview duration) */
630     put_be32(pb, 0); /* reserved (poster time) */
631     put_be32(pb, 0); /* reserved (selection time) */
632     put_be32(pb, 0); /* reserved (selection duration) */
633     put_be32(pb, 0); /* reserved (current time) */
634     put_be32(pb, maxTrackID+1); /* Next track id */
635     return 0x6c;
636 }
637
638 static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov)
639 {
640     int pos, i;
641     pos = url_ftell(pb);
642     put_be32(pb, 0); /* size placeholder*/
643     put_tag(pb, "moov");
644     mov->timescale = globalTimescale;
645
646     for (i=0; i<MAX_STREAMS; i++) {
647         if(mov->tracks[i].entry > 0) {
648             if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
649                 mov->tracks[i].timescale = globalTimescale;
650                 mov->tracks[i].sampleDelta = mov->tracks[i].enc->frame_rate_base;
651                 mov->tracks[i].frameCount = mov->tracks[i].samples;
652                 mov->tracks[i].trackDuration = (int64_t)((int64_t)mov->tracks[i].entry*
653                     (int64_t)globalTimescale*(int64_t)mov->tracks[i].enc->frame_rate_base)/(int64_t)mov->tracks[i].enc->frame_rate;
654             }
655             else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
656                 long trackDuration = 0;
657                 /* If AMR, track timescale = 8000, AMR_WB = 16000 */
658                 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
659                     int j;
660                     for (j=0; j<mov->tracks[i].samples; j++) {
661                         int cl = j / MOV_INDEX_CLUSTER_SIZE;
662                         int id = j % MOV_INDEX_CLUSTER_SIZE;
663                         trackDuration += mov->tracks[i].cluster[cl][id].entries;
664                     }
665                     mov->tracks[i].sampleDelta = 160;  // Bytes per chunk
666                     mov->tracks[i].frameCount = mov->tracks[i].samples;
667                     mov->tracks[i].trackDuration = 
668                         mov->tracks[i].samples * mov->tracks[i].sampleDelta; //trackDuration
669                     mov->tracks[i].timescale = 8000;
670                 }
671                 else {
672                     int j;
673                     for (j=0; j<=mov->tracks[i].entry; j++) {
674                         int cl = j / MOV_INDEX_CLUSTER_SIZE;
675                         int id = j % MOV_INDEX_CLUSTER_SIZE;
676                         trackDuration += mov->tracks[i].cluster[cl][id].len;
677                     }
678                     mov->tracks[i].frameCount = trackDuration;
679                     mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
680                     mov->tracks[i].sampleDelta = 1;
681                     mov->tracks[i].trackDuration = trackDuration;
682                 }
683             }
684             mov->tracks[i].time = mov->time;
685             mov->tracks[i].trackID = i+1;
686         }
687     }
688
689     mov_write_mvhd_tag(pb, mov);
690     //mov_write_iods_tag(pb, mov);
691     for (i=0; i<MAX_STREAMS; i++) {
692         if(mov->tracks[i].entry > 0) {
693             mov_write_trak_tag(pb, &(mov->tracks[i]));
694         }
695     }
696
697     return updateSize(pb, pos);
698 }
699
700 int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
701 {
702     mov->mdat_pos = url_ftell(pb); 
703     put_be32(pb, 0); /* size placeholder*/
704     put_tag(pb, "mdat");
705     return 0;
706 }
707
708 /* TODO: This needs to be more general */
709 int mov_write_ftyp_tag(ByteIOContext *pb)
710 {
711     put_be32(pb, 0x14 ); /* size */
712     put_tag(pb, "ftyp");
713     put_tag(pb, "3gp4");
714     put_be32(pb, 0x200 );
715     put_tag(pb, "3gp4");
716     return 0x14;
717 }
718
719 static int mov_write_header(AVFormatContext *s)
720 {
721     ByteIOContext *pb = &s->pb;
722
723     if(s->oformat != NULL) {
724     if(!strcmp("3gp", s->oformat->name))
725         mov_write_ftyp_tag(pb);
726     }
727
728     put_flush_packet(pb);
729
730     return 0;
731 }
732
733 static int Timestamp() {
734     time_t ltime;
735     time ( &ltime );
736     return ltime+(24107*86400);
737 }
738
739 static int mov_write_packet(AVFormatContext *s, int stream_index,
740                             const uint8_t *buf, int size, int64_t pts)
741 {
742     MOVContext *mov = s->priv_data;
743     ByteIOContext *pb = &s->pb;
744     AVCodecContext *enc;
745     int cl, id;
746
747     enc = &s->streams[stream_index]->codec;
748     if (!url_is_streamed(&s->pb)) {
749         MOVTrack* trk = &mov->tracks[stream_index];
750         int sampleCount = 0;
751         unsigned int chunkSize = 0;
752
753         if(enc->codec_type == CODEC_TYPE_AUDIO) {
754             /* We must find out how many AMR blocks there are in one packet */
755             if(enc->codec_id == CODEC_ID_AMR_NB) {
756                 static uint16_t packed_size[16] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};             
757                 int len = 0;
758
759                 while(len < size && sampleCount < 100) {
760                     len += packed_size[(buf[len] >> 3) & 0x0F];
761                     sampleCount++;
762                 }
763                 chunkSize = 1;
764             }
765             else {
766                 sampleCount = size;
767                 chunkSize = size/enc->channels;
768             }
769         }
770         else if(enc->codec_type == CODEC_TYPE_VIDEO) {
771             if(enc->codec_id == CODEC_ID_MPEG4 &&
772                trk->vosLen == 0)
773             {
774                 assert(enc->extradata_size);
775
776                 trk->vosLen = enc->extradata_size;
777                 trk->vosData = av_malloc(trk->vosLen);
778                 memcpy(trk->vosData, enc->extradata, trk->vosLen);
779             }
780             chunkSize = 1;
781         }
782
783         cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
784         id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
785
786         if (trk->ents_allocated <= trk->entry) {
787             trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*)); 
788             if (!trk->cluster)
789                 return -1;
790             trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
791             if (!trk->cluster[cl])
792                 return -1;
793             trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
794         }
795         if(mov->mdat_written == 0) {
796             mov_write_mdat_tag(pb, mov);
797             mov->mdat_written = 1;
798             mov->time = Timestamp();
799         }
800         
801         trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list;
802         trk->cluster[cl][id].chunkSize = chunkSize;
803         if(enc->channels > 1)
804           trk->cluster[cl][id].len = size/enc->channels;
805         else
806           trk->cluster[cl][id].len = size;
807         trk->cluster[cl][id].entries = sampleCount;
808         if(enc->codec_type == CODEC_TYPE_VIDEO) {
809             trk->cluster[cl][id].key_frame = enc->coded_frame->key_frame;
810             if(enc->coded_frame->pict_type == FF_I_TYPE)
811             trk->hasKeyframes = 1;
812         }
813         trk->enc = enc;
814         trk->entry++;
815         if(sampleCount == 0)
816             trk->samples++;
817         else
818             trk->samples += sampleCount;
819         trk->mdat_size += size;
820     }
821     put_buffer(pb, buf, size);
822
823     put_flush_packet(pb);
824     return 0;
825 }
826
827 static int mov_write_trailer(AVFormatContext *s)
828 {
829     MOVContext *mov = s->priv_data;
830     ByteIOContext *pb = &s->pb;
831     int res = 0;
832     int i, j;
833     offset_t file_size;
834
835     file_size = url_ftell(pb);
836     j = 0;
837
838     /* Write size of mdat tag */
839     for (i=0; i<MAX_STREAMS; i++) {
840         if(mov->tracks[i].ents_allocated > 0) {
841             j += mov->tracks[i].mdat_size;
842         }
843     }
844     url_fseek(pb, mov->mdat_pos, SEEK_SET);
845     put_be32(pb, j+8);
846     url_fseek(pb, file_size, SEEK_SET);
847
848     mov_write_moov_tag(pb, mov);
849
850     for (i=0; i<MAX_STREAMS; i++) {
851         for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
852             av_free(mov->tracks[i].cluster[j]);
853         }
854         av_free(mov->tracks[i].cluster);
855         mov->tracks[i].cluster = NULL;
856         mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
857     }
858     put_flush_packet(pb);
859
860     return res;
861 }
862
863 static AVOutputFormat mov_oformat = {
864     "mov",
865     "mov format",
866     NULL,
867     "mov",
868     sizeof(MOVContext),
869     CODEC_ID_PCM_ALAW,
870     CODEC_ID_MPEG4,
871     mov_write_header,
872     mov_write_packet,
873     mov_write_trailer,
874 };
875
876 static AVOutputFormat _3gp_oformat = {
877     "3gp",
878     "3gp format",
879     NULL,
880     "3gp",
881     sizeof(MOVContext),
882     CODEC_ID_AMR_NB,
883     CODEC_ID_H263,
884     mov_write_header,
885     mov_write_packet,
886     mov_write_trailer,
887 };
888
889 static AVOutputFormat mp4_oformat = {
890     "mp4",
891     "mp4 format",
892     "application/mp4",
893     "mp4,m4a",
894     sizeof(MOVContext),
895     CODEC_ID_AAC,
896     CODEC_ID_MPEG4,
897     mov_write_header,
898     mov_write_packet,
899     mov_write_trailer,
900 };
901
902 int movenc_init(void)
903 {
904     av_register_output_format(&mov_oformat);
905     av_register_output_format(&_3gp_oformat);
906     av_register_output_format(&mp4_oformat);
907     return 0;
908 }