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