]> git.sesse.net Git - vlc/blob - modules/mux/mp4.c
* src/stream_output/stream_output.c, include/stream_output.h: new sout_AccessOutRead...
[vlc] / modules / mux / mp4.c
1 /*****************************************************************************
2  * mp4.c: mp4/mov muxer
3  *****************************************************************************
4  * Copyright (C) 2001, 2002, 2003 VideoLAN
5  * $Id: mp4.c,v 1.10 2004/01/23 17:56:14 gbazin Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/input.h>
34 #include <vlc/sout.h>
35
36 #ifdef HAVE_TIME_H
37 #include <time.h>
38 #endif
39
40 #include "codecs.h"
41
42 /*****************************************************************************
43  * Exported prototypes
44  *****************************************************************************/
45 static int  Open   ( vlc_object_t * );
46 static void Close  ( vlc_object_t * );
47
48 static int Capability(sout_mux_t *, int, void *, void * );
49 static int AddStream( sout_mux_t *, sout_input_t * );
50 static int DelStream( sout_mux_t *, sout_input_t * );
51 static int Mux      ( sout_mux_t * );
52
53 /*****************************************************************************
54  * Module descriptor
55  *****************************************************************************/
56 #define FASTSTART_TEXT N_("Create \"Fast start\" files")
57 #define FASTSTART_LONGTEXT N_( \
58     "When this option is turned on, \"Fast start\" files will be created. " \
59     "(\"Fast start\" files are optimized for download, allowing the user " \
60     "to start previewing the file while it is downloading).")
61
62 vlc_module_begin();
63     set_description( _("MP4/MOV muxer") );
64
65     add_category_hint( "MP4/MOV muxer", NULL, VLC_TRUE );
66         add_bool( "mp4-faststart", 1, NULL, FASTSTART_TEXT, FASTSTART_LONGTEXT, VLC_TRUE );
67
68     set_capability( "sout mux", 5 );
69     add_shortcut( "mp4" );
70     add_shortcut( "mov" );
71     set_callbacks( Open, Close );
72 vlc_module_end();
73
74 /*****************************************************************************
75  * Local prototypes
76  *****************************************************************************/
77 typedef struct
78 {
79     uint64_t i_pos;
80     int      i_size;
81
82     mtime_t  i_pts;
83     mtime_t  i_dts;
84     mtime_t  i_length;
85
86 } mp4_entry_t;
87
88 typedef struct
89 {
90     es_format_t   *p_fmt;
91     int           i_track_id;
92
93     /* index */
94     unsigned int i_entry_count;
95     unsigned int i_entry_max;
96     mp4_entry_t  *entry;
97
98     /* stats */
99     mtime_t      i_duration;
100
101     /* for later stco fix-up (fast start files) */
102     uint64_t i_stco_pos;
103     vlc_bool_t b_stco64;
104
105 } mp4_stream_t;
106
107 struct sout_mux_sys_t
108 {
109     vlc_bool_t b_mov;
110     vlc_bool_t b_64_ext;
111     vlc_bool_t b_fast_start;
112
113     uint64_t i_mdat_pos;
114     uint64_t i_pos;
115
116     mtime_t  i_start_dts;
117
118     int          i_nb_streams;
119     mp4_stream_t **pp_streams;
120 };
121
122 typedef struct bo_t
123 {
124     vlc_bool_t b_grow;
125
126     int        i_buffer_size;
127     int        i_buffer;
128     uint8_t    *p_buffer;
129
130 } bo_t;
131
132 static void bo_init     ( bo_t *, int , uint8_t *, vlc_bool_t  );
133 static void bo_add_8    ( bo_t *, uint8_t );
134 static void bo_add_16be ( bo_t *, uint16_t );
135 static void bo_add_24be ( bo_t *, uint32_t );
136 static void bo_add_32be ( bo_t *, uint32_t );
137 static void bo_add_64be ( bo_t *, uint64_t );
138 static void bo_add_fourcc(bo_t *, char * );
139 static void bo_add_bo   ( bo_t *, bo_t * );
140 static void bo_add_mem  ( bo_t *, int , uint8_t * );
141 static void bo_add_descr( bo_t *, uint8_t , uint32_t );
142
143 static void bo_fix_32be ( bo_t *, int , uint32_t );
144
145 static bo_t *box_new     ( char *fcc );
146 static bo_t *box_full_new( char *fcc, uint8_t v, uint32_t f );
147 static void  box_fix     ( bo_t *box );
148 static void  box_free    ( bo_t *box );
149 static void  box_gather  ( bo_t *box, bo_t *box2 );
150
151 static void box_send( sout_mux_t *p_mux,  bo_t *box );
152
153 static int64_t get_timestamp();
154
155 static sout_buffer_t *bo_to_sout( sout_instance_t *p_sout,  bo_t *box );
156
157 /*****************************************************************************
158  * Open:
159  *****************************************************************************/
160 static int Open( vlc_object_t *p_this )
161 {
162     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
163     sout_mux_sys_t  *p_sys;
164     bo_t            *box;
165
166     p_sys = malloc( sizeof( sout_mux_sys_t ) );
167     p_sys->i_pos        = 0;
168     p_sys->i_nb_streams = 0;
169     p_sys->pp_streams   = NULL;
170     p_sys->i_mdat_pos   = 0;
171     p_sys->b_mov        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" );
172     p_sys->i_start_dts  = 0;
173
174     msg_Dbg( p_mux, "Open" );
175
176     p_mux->pf_capacity  = Capability;
177     p_mux->pf_addstream = AddStream;
178     p_mux->pf_delstream = DelStream;
179     p_mux->pf_mux       = Mux;
180     p_mux->p_sys        = p_sys;
181
182     if( !p_sys->b_mov )
183     {
184         /* Now add ftyp header */
185         box = box_new( "ftyp" );
186         bo_add_fourcc( box, "isom" );
187         bo_add_32be  ( box, 0 );
188         bo_add_fourcc( box, "mp41" );
189         box_fix( box );
190
191         p_sys->i_pos += box->i_buffer;
192         p_sys->i_mdat_pos = p_sys->i_pos;
193
194         box_send( p_mux, box );
195     }
196
197     /* FIXME FIXME
198      * Quicktime actually doesn't like the 64 bits extensions !!! */
199     p_sys->b_64_ext = VLC_FALSE;
200
201     /* Now add mdat header */
202     box = box_new( "mdat" );
203     bo_add_64be  ( box, 0 ); // enough to store an extended size
204
205     p_sys->i_pos += box->i_buffer;
206
207     box_send( p_mux, box );
208
209     return VLC_SUCCESS;
210 }
211
212 static int GetDescrLength( int i_size )
213 {
214     if( i_size < 0x00000080 )
215         return 2 + i_size;
216     else if( i_size < 0x00004000 )
217         return 3 + i_size;
218     else if( i_size < 0x00200000 )
219         return 4 + i_size;
220     else
221         return 5 + i_size;
222 }
223
224 static bo_t *GetESDS( mp4_stream_t *p_stream )
225 {
226     bo_t *esds;
227     int  i_stream_type;
228     int  i_object_type_indication;
229     int  i_decoder_specific_info_size;
230
231     if( p_stream->p_fmt->i_extra > 0 )
232     {
233         i_decoder_specific_info_size =
234             GetDescrLength( p_stream->p_fmt->i_extra );
235     }
236     else
237     {
238         i_decoder_specific_info_size = 0;
239     }
240
241     esds = box_full_new( "esds", 0, 0 );
242
243     /* ES_Descr */
244     bo_add_descr( esds, 0x03, 3 +
245                   GetDescrLength( 13 + i_decoder_specific_info_size ) +
246                   GetDescrLength( 1 ) );
247     bo_add_16be( esds, p_stream->i_track_id );
248     bo_add_8   ( esds, 0x1f );      // flags=0|streamPriority=0x1f
249
250     /* DecoderConfigDescr */
251     bo_add_descr( esds, 0x04, 13 + i_decoder_specific_info_size );
252
253     switch( p_stream->p_fmt->i_codec )
254     {
255         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
256             i_object_type_indication = 0x20;
257             break;
258         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
259             /* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
260             i_object_type_indication = 0x60;
261             break;
262         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
263             /* FIXME for mpeg2-aac == 0x66->0x68 */
264             i_object_type_indication = 0x40;
265             break;
266         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
267             i_object_type_indication =
268                 p_stream->p_fmt->audio.i_rate < 32000 ? 0x69 : 0x6b;
269             break;
270         default:
271             i_object_type_indication = 0x00;
272             break;
273     }
274     i_stream_type = p_stream->p_fmt->i_cat == VIDEO_ES ? 0x04 : 0x05;
275
276     bo_add_8   ( esds, i_object_type_indication );
277     bo_add_8   ( esds, ( i_stream_type << 2 ) | 1 );
278     bo_add_24be( esds, 1024 * 1024 );       // bufferSizeDB
279     bo_add_32be( esds, 0x7fffffff );        // maxBitrate
280     bo_add_32be( esds, 0 );                 // avgBitrate
281
282     if( p_stream->p_fmt->i_extra > 0 )
283     {
284         int i;
285
286         /* DecoderSpecificInfo */
287         bo_add_descr( esds, 0x05, p_stream->p_fmt->i_extra );
288
289         for( i = 0; i < p_stream->p_fmt->i_extra; i++ )
290         {
291             bo_add_8( esds, ((uint8_t*)p_stream->p_fmt->p_extra)[i] );
292         }
293     }
294
295     /* SL_Descr mandatory */
296     bo_add_descr( esds, 0x06, 1 );
297     bo_add_8    ( esds, 0x02 );  // sl_predefined
298
299     box_fix( esds );
300
301     return esds;
302 }
303
304 static bo_t *GetWaveTag( mp4_stream_t *p_stream )
305 {
306     bo_t *wave;
307     bo_t *box;
308
309     wave = box_new( "wave" );
310
311     box = box_new( "frma" );
312     bo_add_fourcc( box, "mp4a" );
313     box_fix( box );
314     box_gather( wave, box );
315
316     box = box_new( "mp4a" );
317     bo_add_32be( box, 0 );
318     box_fix( box );
319     box_gather( wave, box );
320
321     box = GetESDS( p_stream );
322     box_fix( box );
323     box_gather( wave, box );
324
325     box = box_new( "srcq" );
326     bo_add_32be( box, 0x40 );
327     box_fix( box );
328     box_gather( wave, box );
329
330     /* wazza ? */
331     bo_add_32be( wave, 8 ); /* new empty box */
332     bo_add_32be( wave, 0 ); /* box label */
333
334     box_fix( wave );
335
336     return wave;
337 }
338
339 /* TODO: No idea about these values */
340 static bo_t *GetSVQ3Tag( mp4_stream_t *p_stream )
341 {
342     bo_t *smi = box_new( "SMI " );
343
344     bo_add_fourcc( smi, "SEQH" );
345     bo_add_32be( smi, 0x5 );
346     bo_add_32be( smi, 0xe2c0211d );
347     bo_add_8( smi, 0xc0 );
348     box_fix( smi );
349
350     return smi;
351 }
352
353 static bo_t *GetUdtaTag( sout_mux_t *p_mux )
354 {
355     sout_mux_sys_t *p_sys = p_mux->p_sys;
356     bo_t *udta = box_new( "udta" );
357     int i_track;
358
359     /* Requirements */
360     for( i_track = 0; i_track < p_sys->i_nb_streams; i_track++ )
361     {
362         mp4_stream_t *p_stream = p_sys->pp_streams[i_track];
363
364         if( p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','v') ||
365             p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','a') )
366         {
367             bo_t *box = box_new( "\251req" );
368             /* String length */
369             bo_add_16be( box, sizeof("QuickTime 6.0 or greater") - 1);
370             bo_add_16be( box, 0 );
371             bo_add_mem( box, sizeof("QuickTime 6.0 or greater") - 1,
372                         "QuickTime 6.0 or greater" );
373             box_fix( box );
374             box_gather( udta, box );
375             break;
376         }
377     }
378
379     /* Encoder */
380     {
381         bo_t *box = box_new( "\251enc" );
382         /* String length */
383         bo_add_16be( box, sizeof(PACKAGE_STRING " stream output") - 1);
384         bo_add_16be( box, 0 );
385         bo_add_mem( box, sizeof(PACKAGE_STRING " stream output") - 1,
386                     PACKAGE_STRING " stream output" );
387         box_fix( box );
388         box_gather( udta, box );
389     }
390
391     box_fix( udta );
392     return udta;
393 }
394
395 static uint32_t mvhd_matrix[9] =
396     { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
397
398 static bo_t *GetMoovTag( sout_mux_t *p_mux )
399 {
400     sout_mux_sys_t *p_sys = p_mux->p_sys;
401
402     bo_t            *moov, *mvhd;
403     unsigned int    i;
404     int             i_trak, i_index;
405
406     uint32_t        i_movie_timescale = 90000;
407     int64_t         i_movie_duration  = 0;
408
409     moov = box_new( "moov" );
410
411     /* *** add /moov/mvhd *** */
412     if( !p_sys->b_64_ext )
413     {
414         mvhd = box_full_new( "mvhd", 0, 0 );
415         bo_add_32be( mvhd, get_timestamp() );   // creation time
416         bo_add_32be( mvhd, get_timestamp() );   // modification time
417         bo_add_32be( mvhd, i_movie_timescale);  // timescale
418         bo_add_32be( mvhd, i_movie_duration );  // duration
419     }
420     else
421     {
422         mvhd = box_full_new( "mvhd", 1, 0 );
423         bo_add_64be( mvhd, get_timestamp() );   // creation time
424         bo_add_64be( mvhd, get_timestamp() );   // modification time
425         bo_add_32be( mvhd, i_movie_timescale);  // timescale
426         bo_add_64be( mvhd, i_movie_duration );  // duration
427     }
428     bo_add_32be( mvhd, 0x10000 );           // rate
429     bo_add_16be( mvhd, 0x100 );             // volume
430     bo_add_16be( mvhd, 0 );                 // reserved
431     for( i = 0; i < 2; i++ )
432     {
433         bo_add_32be( mvhd, 0 );             // reserved
434     }
435     for( i = 0; i < 9; i++ )
436     {
437         bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
438     }
439     for( i = 0; i < 6; i++ )
440     {
441         bo_add_32be( mvhd, 0 );             // pre-defined
442     }
443
444     /* Find the 1st track id */
445     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
446     {
447         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
448
449         if( p_stream->p_fmt->i_cat == AUDIO_ES ||
450             p_stream->p_fmt->i_cat == VIDEO_ES )
451         {
452             /* Found it */
453             bo_add_32be( mvhd, p_stream->i_track_id ); // next-track-id
454             break;
455         }
456     }
457     if( i_trak == p_sys->i_nb_streams ) /* Just for sanity reasons */
458         bo_add_32be( mvhd, 0xffffffff );
459
460     box_fix( mvhd );
461     box_gather( moov, mvhd );
462
463     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
464     {
465         mp4_stream_t *p_stream;
466         uint32_t     i_timescale;
467         uint32_t     i_chunk_count;
468         unsigned int i_chunk;
469
470         bo_t *trak;
471         bo_t *tkhd;
472         bo_t *mdia;
473         bo_t *mdhd, *hdlr;
474         bo_t *minf;
475         bo_t *dinf;
476         bo_t *dref;
477         bo_t *url;
478         bo_t *stbl;
479         bo_t *stsd;
480         bo_t *stts;
481         bo_t *stco;
482         bo_t *stsc;
483         bo_t *stsz;
484
485         p_stream = p_sys->pp_streams[i_trak];
486
487         if( p_stream->p_fmt->i_cat != AUDIO_ES &&
488             p_stream->p_fmt->i_cat != VIDEO_ES )
489         {
490             msg_Err( p_mux, "FIXME ignoring trak (noaudio&&novideo)" );
491             continue;
492         }
493         if( p_stream->p_fmt->i_cat == AUDIO_ES )
494         {
495             i_timescale = p_stream->p_fmt->audio.i_rate;
496         }
497         else
498         {
499             i_timescale = 1001;
500         }
501
502         /* *** add /moov/trak *** */
503         trak = box_new( "trak" );
504
505         /* *** add /moov/trak/tkhd *** */
506         if( !p_sys->b_64_ext )
507         {
508             if( p_sys->b_mov )
509                 tkhd = box_full_new( "tkhd", 0, 0x0f );
510             else
511                 tkhd = box_full_new( "tkhd", 0, 1 );
512
513             bo_add_32be( tkhd, get_timestamp() );       // creation time
514             bo_add_32be( tkhd, get_timestamp() );       // modification time
515             bo_add_32be( tkhd, p_stream->i_track_id );
516             bo_add_32be( tkhd, 0 );                     // reserved 0
517             bo_add_32be( tkhd, p_stream->i_duration *
518                          (int64_t)i_movie_timescale /
519                          (mtime_t)1000000 );            // duration
520         }
521         else
522         {
523             if( p_sys->b_mov )
524                 tkhd = box_full_new( "tkhd", 1, 0x0f );
525             else
526                 tkhd = box_full_new( "tkhd", 1, 1 );
527
528             bo_add_64be( tkhd, get_timestamp() );       // creation time
529             bo_add_64be( tkhd, get_timestamp() );       // modification time
530             bo_add_32be( tkhd, p_stream->i_track_id );
531             bo_add_32be( tkhd, 0 );                     // reserved 0
532             bo_add_64be( tkhd, p_stream->i_duration *
533                          (int64_t)i_movie_timescale /
534                          (mtime_t)1000000 );            // duration
535         }
536
537         for( i = 0; i < 2; i++ )
538         {
539             bo_add_32be( tkhd, 0 );                 // reserved
540         }
541         bo_add_16be( tkhd, 0 );                     // layer
542         bo_add_16be( tkhd, 0 );                     // pre-defined
543         bo_add_16be( tkhd, p_stream->p_fmt->i_cat == AUDIO_ES ? 0x100 : 0 ); // volume
544         bo_add_16be( tkhd, 0 );                     // reserved
545         for( i = 0; i < 9; i++ )
546         {
547             bo_add_32be( tkhd, mvhd_matrix[i] );    // matrix
548         }
549         if( p_stream->p_fmt->i_cat == AUDIO_ES )
550         {
551             bo_add_32be( tkhd, 0 );                 // width (presentation)
552             bo_add_32be( tkhd, 0 );                 // height(presentation)
553         }
554         else
555         {
556             bo_add_32be( tkhd, p_stream->p_fmt->video.i_width  << 16 );     // width (presentation)
557             bo_add_32be( tkhd, p_stream->p_fmt->video.i_height << 16 );     // height(presentation)
558         }
559         box_fix( tkhd );
560         box_gather( trak, tkhd );
561
562         /* *** add /moov/trak/mdia *** */
563         mdia = box_new( "mdia" );
564
565         /* media header */
566         if( !p_sys->b_64_ext )
567         {
568             mdhd = box_full_new( "mdhd", 0, 0 );
569             bo_add_32be( mdhd, get_timestamp() );   // creation time
570             bo_add_32be( mdhd, get_timestamp() );   // modification time
571             bo_add_32be( mdhd, i_timescale);        // timescale
572             bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
573                                (mtime_t)1000000 );  // duration
574         }
575         else
576         {
577             mdhd = box_full_new( "mdhd", 1, 0 );
578             bo_add_64be( mdhd, get_timestamp() );   // creation time
579             bo_add_64be( mdhd, get_timestamp() );   // modification time
580             bo_add_32be( mdhd, i_timescale);        // timescale
581             bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
582                                (mtime_t)1000000 );  // duration
583         }
584
585         bo_add_16be( mdhd, 0    );              // language   FIXME
586         bo_add_16be( mdhd, 0    );              // predefined
587         box_fix( mdhd );
588         box_gather( mdia, mdhd );
589
590         /* handler reference */
591         hdlr = box_full_new( "hdlr", 0, 0 );
592
593         bo_add_fourcc( hdlr, "mhlr" );         // media handler
594         if( p_stream->p_fmt->i_cat == AUDIO_ES )
595         {
596             bo_add_fourcc( hdlr, "soun" );
597         }
598         else
599         {
600             bo_add_fourcc( hdlr, "vide" );
601         }
602
603         bo_add_32be( hdlr, 0 );         // reserved
604         bo_add_32be( hdlr, 0 );         // reserved
605         bo_add_32be( hdlr, 0 );         // reserved
606
607         if( p_stream->p_fmt->i_cat == AUDIO_ES )
608         {
609             bo_add_8( hdlr, 13 );
610             bo_add_mem( hdlr, 13, "SoundHandler" );
611         }
612         else
613         {
614             bo_add_8( hdlr, 13 );
615             bo_add_mem( hdlr, 13, "VideoHandler" );
616         }
617
618         box_fix( hdlr );
619         box_gather( mdia, hdlr );
620
621         /* minf*/
622         minf = box_new( "minf" );
623
624         /* add smhd|vmhd */
625         if( p_stream->p_fmt->i_cat == AUDIO_ES )
626         {
627             bo_t *smhd;
628
629             smhd = box_full_new( "smhd", 0, 0 );
630             bo_add_16be( smhd, 0 );     // balance
631             bo_add_16be( smhd, 0 );     // reserved
632             box_fix( smhd );
633
634             box_gather( minf, smhd );
635         }
636         else if( p_stream->p_fmt->i_cat == VIDEO_ES )
637         {
638             bo_t *vmhd;
639
640             vmhd = box_full_new( "vmhd", 0, 1 );
641             bo_add_16be( vmhd, 0 );     // graphicsmode
642             for( i = 0; i < 3; i++ )
643             {
644                 bo_add_16be( vmhd, 0 ); // opcolor
645             }
646             box_fix( vmhd );
647
648             box_gather( minf, vmhd );
649         }
650
651         /* dinf */
652         dinf = box_new( "dinf" );
653         dref = box_full_new( "dref", 0, 0 );
654         bo_add_32be( dref, 1 );
655         url = box_full_new( "url ", 0, 0x01 );
656         box_fix( url );
657         box_gather( dref, url );
658         box_fix( dref );
659         box_gather( dinf, dref );
660
661         /* append dinf to mdia */
662         box_fix( dinf );
663         box_gather( minf, dinf );
664
665         /* add stbl */
666         stbl = box_new( "stbl" );
667         stsd = box_full_new( "stsd", 0, 0 );
668         bo_add_32be( stsd, 1 );
669
670         if( p_stream->p_fmt->i_cat == AUDIO_ES )
671         {
672             bo_t *soun;
673             char fcc[4] = "    ";
674             int  i;
675             vlc_bool_t b_mpeg4_hdr;
676
677             switch( p_stream->p_fmt->i_codec )
678             {
679                 case VLC_FOURCC( 'm', 'p', '4', 'a' ):
680                     memcpy( fcc, "mp4a", 4 );
681                     b_mpeg4_hdr = VLC_TRUE;
682                     break;
683
684                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
685                     if( p_sys->b_mov )
686                         memcpy( fcc, ".mp3 ", 4 );
687                     else
688                         memcpy( fcc, "mp4a", 4 );
689                     b_mpeg4_hdr = VLC_FALSE;
690                     break;
691
692                 default:
693                     memcpy( fcc, (char*)&p_stream->p_fmt->i_codec, 4 );
694                     b_mpeg4_hdr = VLC_FALSE;
695                     break;
696             }
697
698             soun = box_new( fcc );
699             for( i = 0; i < 6; i++ )
700             {
701                 bo_add_8( soun, 0 );        // reserved;
702             }
703             bo_add_16be( soun, 1 );         // data-reference-index
704
705             /* SoundDescription */
706             if( p_sys->b_mov &&
707                 p_stream->p_fmt->i_codec == VLC_FOURCC( 'm', 'p', '4', 'a' ) )
708             {
709                 bo_add_16be( soun, 1 );     // version 1;
710             }
711             else
712             {
713                 bo_add_16be( soun, 0 );     // version 0;
714             }
715             bo_add_16be( soun, 0 );         // revision level (0)
716             bo_add_32be( soun, 0 );         // vendor
717             bo_add_16be( soun, p_stream->p_fmt->audio.i_channels );   // channel-count
718             // sample size
719             bo_add_16be( soun, p_stream->p_fmt->audio.i_bitspersample ?
720                          p_stream->p_fmt->audio.i_bitspersample : 16 );
721             bo_add_16be( soun, -2 );        // compression id
722             bo_add_16be( soun, 0 );         // packet size (0)
723             bo_add_16be( soun, p_stream->p_fmt->audio.i_rate ); // sampleratehi
724             bo_add_16be( soun, 0 );                             // sampleratelo
725
726             /* Extended data for SoundDescription V1 */
727             if( p_sys->b_mov &&
728                 p_stream->p_fmt->i_codec == VLC_FOURCC( 'm', 'p', '4', 'a' ) )
729             {
730                 bo_add_32be( soun, p_stream->p_fmt->audio.i_frame_length );    /* samples per packet */
731                 bo_add_32be( soun, 1536 ); /* bytes per packet */
732                 bo_add_32be( soun, 2 );    /* bytes per frame */
733                 /* bytes per sample */
734                 bo_add_32be( soun, 2 /*p_stream->p_fmt->audio.i_bitspersample/8 */);
735             }
736
737             /* add an ES Descriptor */
738             if( b_mpeg4_hdr )
739             {
740                 bo_t *box;
741
742                 if( p_sys->b_mov &&
743                     p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','a') )
744                 {
745                     box = GetWaveTag( p_stream );
746                 }
747                 else
748                 {
749                     box = GetESDS( p_stream );
750                 }
751                 box_fix( box );
752                 box_gather( soun, box );
753             }
754
755             box_fix( soun );
756             box_gather( stsd, soun );
757         }
758         else if( p_stream->p_fmt->i_cat == VIDEO_ES )
759         {
760             bo_t *vide;
761             char fcc[4] = "    ";
762             int  i;
763
764             switch( p_stream->p_fmt->i_codec )
765             {
766                 case VLC_FOURCC( 'm', 'p', '4', 'v' ):
767                 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
768                     memcpy( fcc, "mp4v", 4 );
769                     break;
770
771                 case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
772                     memcpy( fcc, "mjpa", 4 );
773                     break;
774
775                 case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
776                     memcpy( fcc, "SVQ3", 4 );
777                     break;
778
779                 default:
780                     memcpy( fcc, (char*)&p_stream->p_fmt->i_codec, 4 );
781                     break;
782             }
783
784             vide = box_new( fcc );
785             for( i = 0; i < 6; i++ )
786             {
787                 bo_add_8( vide, 0 );        // reserved;
788             }
789             bo_add_16be( vide, 1 );         // data-reference-index
790
791             bo_add_16be( vide, 0 );         // predefined;
792             bo_add_16be( vide, 0 );         // reserved;
793             for( i = 0; i < 3; i++ )
794             {
795                 bo_add_32be( vide, 0 );     // predefined;
796             }
797
798             bo_add_16be( vide, p_stream->p_fmt->video.i_width );  // i_width
799             bo_add_16be( vide, p_stream->p_fmt->video.i_height ); // i_height
800
801             bo_add_32be( vide, 0x00480000 );                // h 72dpi
802             bo_add_32be( vide, 0x00480000 );                // v 72dpi
803
804             bo_add_32be( vide, 0 );         // data size, always 0
805             bo_add_16be( vide, 1 );         // frames count per sample
806
807             // compressor name;
808             for( i = 0; i < 32; i++ )
809             {
810                 bo_add_8( vide, 0 );
811             }
812
813             bo_add_16be( vide, 0x18 );      // depth
814             bo_add_16be( vide, 0xffff );    // predefined
815
816             /* add an ES Descriptor */
817             switch( p_stream->p_fmt->i_codec )
818             {
819             case VLC_FOURCC( 'm', 'p', '4', 'v' ):
820             case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
821                 {
822                     bo_t *esds = GetESDS( p_stream );
823
824                     box_fix( esds );
825                     box_gather( vide, esds );
826                 }
827                 break;
828
829             case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
830                 {
831                     bo_t *esds = GetSVQ3Tag( p_stream );
832
833                     box_fix( esds );
834                     box_gather( vide, esds );
835                 }
836                 break;
837
838             default:
839                 break;
840             }
841
842             box_fix( vide );
843             box_gather( stsd, vide );
844         }
845
846         /* append stsd to stbl */
847         box_fix( stsd );
848         box_gather( stbl, stsd );
849
850         /* we will create chunk table and stsc table
851          * FIXME optim stsc table FIXME */
852         i_chunk_count = 0;
853         for( i = 0; i < p_stream->i_entry_count; )
854         {
855             while( i < p_stream->i_entry_count )
856             {
857                 if( i + 1 < p_stream->i_entry_count &&
858                     p_stream->entry[i].i_pos +
859                     p_stream->entry[i].i_size != p_stream->entry[i + 1].i_pos )
860                 {
861                     i++;
862                     break;
863                 }
864
865                 i++;
866             }
867             i_chunk_count++;
868         }
869
870         /* chunk offset table */
871         p_stream->i_stco_pos = stbl->i_buffer + 16;
872         if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
873         {
874             /* 64 bits version */
875             msg_Dbg( p_mux, "creating %d chunk (co64)", i_chunk_count );
876             p_stream->b_stco64 = VLC_TRUE;
877             stco = box_full_new( "co64", 0, 0 );
878         }
879         else
880         {
881             /* 32 bits version */
882             msg_Dbg( p_mux, "creating %d chunk (stco)", i_chunk_count );
883             p_stream->b_stco64 = VLC_FALSE;
884             stco = box_full_new( "stco", 0, 0 );
885         }
886
887         bo_add_32be( stco, i_chunk_count );
888
889         stsc = box_full_new( "stsc", 0, 0 );
890         bo_add_32be( stsc, i_chunk_count );     // entry-count
891         for( i_chunk = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ )
892         {
893             int i_first;
894
895             if( p_stream->b_stco64 )
896                 bo_add_64be( stco, p_stream->entry[i].i_pos );
897             else
898                 bo_add_32be( stco, p_stream->entry[i].i_pos );
899
900             i_first = i;
901
902             while( i < p_stream->i_entry_count )
903             {
904                 if( i + 1 < p_stream->i_entry_count &&
905                     p_stream->entry[i].i_pos + p_stream->entry[i].i_size
906                     != p_stream->entry[i + 1].i_pos )
907                 {
908                     i++;
909                     break;
910                 }
911
912                 i++;
913             }
914             bo_add_32be( stsc, 1 + i_chunk );   // first-chunk
915             bo_add_32be( stsc, i - i_first ) ;  // samples-per-chunk
916             bo_add_32be( stsc, 1 );             // sample-descr-index
917         }
918
919         /* append stco to stbl */
920         box_fix( stco );
921         box_gather( stbl, stco );
922
923         /* append stsc to stbl */
924         box_fix( stsc );
925         box_gather( stbl, stsc );
926
927         /* add stts */
928         stts = box_full_new( "stts", 0, 0 );
929         bo_add_32be( stts, 0 );     // fixed latter
930         for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
931         {
932             int64_t i_delta;
933             int     i_first;
934
935             i_first = i;
936             i_delta = p_stream->entry[i].i_length;
937
938             while( i < p_stream->i_entry_count )
939             {
940                 if( i + 1 < p_stream->i_entry_count &&
941                     p_stream->entry[i + 1].i_length != i_delta )
942                 {
943                     i++;
944                     break;
945                 }
946
947                 i++;
948             }
949
950             bo_add_32be( stts, i - i_first );           // sample-count
951             bo_add_32be( stts, i_delta * (int64_t)i_timescale /
952                                (int64_t)1000000 );      // sample-delta
953         }
954         bo_fix_32be( stts, 12, i_index );
955
956         /* append stts to stbl */
957         box_fix( stts );
958         box_gather( stbl, stts );
959
960         /* FIXME add ctts ?? FIXME */
961
962         stsz = box_full_new( "stsz", 0, 0 );
963         bo_add_32be( stsz, 0 );                             // sample-size
964         bo_add_32be( stsz, p_stream->i_entry_count );       // sample-count
965         for( i = 0; i < p_stream->i_entry_count; i++ )
966         {
967             bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
968         }
969         /* append stsz to stbl */
970         box_fix( stsz );
971         box_gather( stbl, stsz );
972
973         /* append stbl to minf */
974         box_fix( stbl );
975         p_stream->i_stco_pos += minf->i_buffer;
976         box_gather( minf, stbl );
977
978         /* append minf to mdia */
979         box_fix( minf );
980         p_stream->i_stco_pos += mdia->i_buffer;
981         box_gather( mdia, minf );
982
983         /* append mdia to trak */
984         box_fix( mdia );
985         p_stream->i_stco_pos += trak->i_buffer;
986         box_gather( trak, mdia );
987
988         /* append trak to moov */
989         box_fix( trak );
990         p_stream->i_stco_pos += moov->i_buffer;
991         box_gather( moov, trak );
992     }
993
994     /* Add user data tags */
995     box_gather( moov, GetUdtaTag( p_mux ) );
996
997     box_fix( moov );
998     return moov;
999 }
1000
1001 /*****************************************************************************
1002  * Close:
1003  *****************************************************************************/
1004 static void Close( vlc_object_t * p_this )
1005 {
1006     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
1007     sout_mux_sys_t  *p_sys = p_mux->p_sys;
1008     sout_buffer_t   *p_hdr;
1009     bo_t            bo, *moov;
1010     vlc_value_t     val;
1011
1012     int             i_trak;
1013     uint64_t        i_moov_pos;
1014
1015     uint32_t        i_movie_timescale = 90000;
1016     int64_t         i_movie_duration  = 0;
1017
1018     msg_Dbg( p_mux, "Close" );
1019
1020     /* Create general info */
1021     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1022     {
1023         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1024         i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration );
1025     }
1026     msg_Dbg( p_mux, "movie duration %ds",
1027              (uint32_t)( i_movie_duration / (mtime_t)1000000 ) );
1028
1029     i_movie_duration = i_movie_duration * i_movie_timescale / 1000000;
1030
1031     /* Update mdat size */
1032     bo_init( &bo, 0, NULL, VLC_TRUE );
1033     if( p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32) )
1034     {
1035         /* Extended size */
1036         bo_add_32be  ( &bo, 1 );
1037         bo_add_fourcc( &bo, "mdat" );
1038         bo_add_64be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos );
1039     }
1040     else
1041     {
1042         bo_add_32be  ( &bo, 8 );
1043         bo_add_fourcc( &bo, "wide" );
1044         bo_add_32be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos - 8 );
1045         bo_add_fourcc( &bo, "mdat" );
1046     }
1047     p_hdr = bo_to_sout( p_mux->p_sout, &bo );
1048     free( bo.p_buffer );
1049
1050     sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos );
1051     sout_AccessOutWrite( p_mux->p_access, p_hdr );
1052
1053     /* Create MOOV header */
1054     i_moov_pos = p_sys->i_pos;
1055     moov = GetMoovTag( p_mux );
1056
1057     /* Check we need to create "fast start" files */
1058     var_Create( p_this, "mp4-faststart", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
1059     var_Get( p_this, "mp4-faststart", &val );
1060     p_sys->b_fast_start = val.b_bool;
1061     while( p_sys->b_fast_start )
1062     {
1063         /* Move data to the end of the file so we can fit the moov header
1064          * at the start */
1065         sout_buffer_t *p_buf;
1066         int64_t i_chunk, i_size = p_sys->i_pos - p_sys->i_mdat_pos;
1067         int i_moov_size = moov->i_buffer;
1068
1069         while( i_size > 0 )
1070         {
1071             i_chunk = __MIN( 32768, i_size );
1072             p_buf = sout_BufferNew( p_mux->p_sout, i_chunk );
1073             sout_AccessOutSeek( p_mux->p_access,
1074                                 p_sys->i_mdat_pos + i_size - i_chunk );
1075             if( sout_AccessOutRead( p_mux->p_access, p_buf ) < i_chunk )
1076             {
1077                 msg_Warn( p_this, "read() not supported by acces output, "
1078                           "won't create a fast start file" );
1079                 p_sys->b_fast_start = VLC_FALSE;
1080                 break;
1081             }
1082             sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos + i_size +
1083                                 i_moov_size - i_chunk );
1084             sout_AccessOutWrite( p_mux->p_access, p_buf );
1085             i_size -= i_chunk;
1086         }
1087
1088         if( !p_sys->b_fast_start ) break;
1089
1090         /* Fix-up samples to chunks table in MOOV header */
1091         for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1092         {
1093             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1094             unsigned int i;
1095             int i_chunk;
1096
1097             moov->i_buffer = p_stream->i_stco_pos;
1098             for( i_chunk = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ )
1099             {
1100                 if( p_stream->b_stco64 )
1101                     bo_add_64be( moov, p_stream->entry[i].i_pos + i_moov_size);
1102                 else
1103                     bo_add_32be( moov, p_stream->entry[i].i_pos + i_moov_size);
1104
1105                 while( i < p_stream->i_entry_count )
1106                 {
1107                     if( i + 1 < p_stream->i_entry_count &&
1108                         p_stream->entry[i].i_pos + p_stream->entry[i].i_size
1109                         != p_stream->entry[i + 1].i_pos )
1110                     {
1111                         i++;
1112                         break;
1113                     }
1114
1115                     i++;
1116                 }
1117             }
1118         }
1119
1120         moov->i_buffer = i_moov_size;
1121         i_moov_pos = p_sys->i_mdat_pos;
1122         p_sys->b_fast_start = VLC_FALSE;
1123     }
1124
1125     /* Write MOOV header */
1126     sout_AccessOutSeek( p_mux->p_access, i_moov_pos );
1127     box_send( p_mux, moov );
1128
1129     /* Clean-up */
1130     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1131     {
1132         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1133
1134         if( p_stream->p_fmt->p_extra )
1135         {
1136             free( p_stream->p_fmt->p_extra );
1137         }
1138         free( p_stream->p_fmt );
1139         free( p_stream->entry );
1140         free( p_stream );
1141     }
1142     free( p_sys );
1143 }
1144
1145 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
1146                        void *p_answer )
1147 {
1148    switch( i_query )
1149    {
1150         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
1151             *(vlc_bool_t*)p_answer = VLC_FALSE;
1152             return( SOUT_MUX_CAP_ERR_OK );
1153         default:
1154             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
1155    }
1156 }
1157
1158 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
1159 {
1160     sout_mux_sys_t  *p_sys = p_mux->p_sys;
1161     mp4_stream_t    *p_stream;
1162
1163     switch( p_input->p_fmt->i_codec )
1164     {
1165         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
1166         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
1167         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
1168         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
1169         case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
1170         case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
1171         case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
1172             break;
1173         default:
1174             msg_Err( p_mux, "unsupported codec %4.4s in mp4",
1175                      (char*)&p_input->p_fmt->i_codec );
1176             return VLC_EGENERIC;
1177     }
1178
1179     p_stream                = malloc( sizeof( mp4_stream_t ) );
1180     p_stream->p_fmt         = malloc( sizeof( es_format_t ) );
1181     memcpy( p_stream->p_fmt, p_input->p_fmt, sizeof( es_format_t ) );
1182     if( p_stream->p_fmt->i_extra )
1183     {
1184         p_stream->p_fmt->p_extra =
1185             malloc( p_stream->p_fmt->i_extra );
1186         memcpy( p_stream->p_fmt->p_extra,
1187                 p_input->p_fmt->p_extra,
1188                 p_input->p_fmt->i_extra );
1189     }
1190     p_stream->i_track_id    = p_sys->i_nb_streams + 1;
1191     p_stream->i_entry_count = 0;
1192     p_stream->i_entry_max   = 1000;
1193     p_stream->entry         =
1194         calloc( p_stream->i_entry_max, sizeof( mp4_entry_t ) );
1195     p_stream->i_duration    = 0;
1196
1197     p_input->p_sys          = p_stream;
1198
1199     msg_Dbg( p_mux, "adding input" );
1200
1201     TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, p_stream );
1202     return( VLC_SUCCESS );
1203 }
1204
1205 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
1206 {
1207     msg_Dbg( p_mux, "removing input" );
1208     return( 0 );
1209 }
1210
1211 /****************************************************************************/
1212
1213 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
1214 {
1215     mtime_t i_dts;
1216     int     i_stream;
1217     int     i;
1218
1219     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
1220     {
1221         sout_fifo_t  *p_fifo;
1222
1223         p_fifo = p_mux->pp_inputs[i]->p_fifo;
1224
1225         if( p_fifo->i_depth > 1 )
1226         {
1227             sout_buffer_t *p_buf;
1228
1229             p_buf = sout_FifoShow( p_fifo );
1230             if( i_stream < 0 || p_buf->i_dts < i_dts )
1231             {
1232                 i_dts = p_buf->i_dts;
1233                 i_stream = i;
1234             }
1235         }
1236         else
1237         {
1238             return( -1 ); // wait that all fifo have at least 2 packets
1239         }
1240     }
1241     if( pi_stream )
1242     {
1243         *pi_stream = i_stream;
1244     }
1245     if( pi_dts )
1246     {
1247         *pi_dts = i_dts;
1248     }
1249     return( i_stream );
1250 }
1251
1252 static int Mux( sout_mux_t *p_mux )
1253 {
1254     sout_mux_sys_t  *p_sys = p_mux->p_sys;
1255
1256     for( ;; )
1257     {
1258         sout_input_t    *p_input;
1259         int             i_stream;
1260         mp4_stream_t    *p_stream;
1261         sout_buffer_t   *p_data;
1262         mtime_t         i_dts;
1263
1264         if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
1265         {
1266             return( VLC_SUCCESS );
1267         }
1268
1269         if( !p_sys->i_start_dts )
1270             p_sys->i_start_dts = i_dts;
1271
1272         p_input  = p_mux->pp_inputs[i_stream];
1273         p_stream = (mp4_stream_t*)p_input->p_sys;
1274
1275         p_data  = sout_FifoGet( p_input->p_fifo );
1276         //msg_Dbg( p_mux, "stream=%d size=%6d pos=%8lld", i_stream, p_data->i_size, p_sys->i_pos );
1277
1278         /* add index entry */
1279         p_stream->entry[p_stream->i_entry_count].i_pos   = p_sys->i_pos;
1280         p_stream->entry[p_stream->i_entry_count].i_size  = p_data->i_size;
1281         p_stream->entry[p_stream->i_entry_count].i_pts   = p_data->i_pts;
1282         p_stream->entry[p_stream->i_entry_count].i_dts   = p_data->i_dts;
1283         p_stream->entry[p_stream->i_entry_count].i_length=
1284             __MAX( p_data->i_length, 0 );
1285
1286         if( p_stream->i_entry_count == 0 )
1287         {
1288             /* Here is another bad hack.
1289              * To make sure audio/video are in sync, we report a corrected
1290              * length for the 1st sample. */
1291             p_stream->entry[p_stream->i_entry_count].i_length =
1292                 __MAX( p_data->i_length, 0 ) +
1293                 p_data->i_pts - p_sys->i_start_dts;
1294         }
1295
1296         p_stream->i_entry_count++;
1297         if( p_stream->i_entry_count >= p_stream->i_entry_max )
1298         {
1299             p_stream->i_entry_max += 1000;
1300             p_stream->entry =
1301                 realloc( p_stream->entry,
1302                          p_stream->i_entry_max * sizeof( mp4_entry_t ) );
1303         }
1304
1305         /* update */
1306         p_stream->i_duration += __MAX( p_data->i_length, 0 );
1307         p_sys->i_pos += p_data->i_size;
1308
1309         /* write data */
1310         sout_AccessOutWrite( p_mux->p_access, p_data );
1311     }
1312
1313     return( VLC_SUCCESS );
1314 }
1315
1316
1317 /****************************************************************************/
1318
1319 static void bo_init( bo_t *p_bo, int i_size, uint8_t *p_buffer,
1320                      vlc_bool_t b_grow )
1321 {
1322     if( !p_buffer )
1323     {
1324         p_bo->i_buffer_size = __MAX( i_size, 1024 );
1325         p_bo->p_buffer = malloc( p_bo->i_buffer_size );
1326     }
1327     else
1328     {
1329         p_bo->i_buffer_size = i_size;
1330         p_bo->p_buffer = p_buffer;
1331     }
1332
1333     p_bo->b_grow = b_grow;
1334     p_bo->i_buffer = 0;
1335 }
1336
1337 static void bo_add_8( bo_t *p_bo, uint8_t i )
1338 {
1339     if( p_bo->i_buffer < p_bo->i_buffer_size )
1340     {
1341         p_bo->p_buffer[p_bo->i_buffer] = i;
1342     }
1343     else if( p_bo->b_grow )
1344     {
1345         p_bo->i_buffer_size += 1024;
1346         p_bo->p_buffer = realloc( p_bo->p_buffer, p_bo->i_buffer_size );
1347
1348         p_bo->p_buffer[p_bo->i_buffer] = i;
1349     }
1350
1351     p_bo->i_buffer++;
1352 }
1353
1354 static void bo_add_16be( bo_t *p_bo, uint16_t i )
1355 {
1356     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1357     bo_add_8( p_bo, i &0xff );
1358 }
1359
1360 static void bo_add_24be( bo_t *p_bo, uint32_t i )
1361 {
1362     bo_add_8( p_bo, ( ( i >> 16) &0xff ) );
1363     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1364     bo_add_8( p_bo, (   i &0xff ) );
1365 }
1366 static void bo_add_32be( bo_t *p_bo, uint32_t i )
1367 {
1368     bo_add_16be( p_bo, ( ( i >> 16) &0xffff ) );
1369     bo_add_16be( p_bo, i &0xffff );
1370 }
1371
1372 static void bo_fix_32be ( bo_t *p_bo, int i_pos, uint32_t i)
1373 {
1374     p_bo->p_buffer[i_pos    ] = ( i >> 24 )&0xff;
1375     p_bo->p_buffer[i_pos + 1] = ( i >> 16 )&0xff;
1376     p_bo->p_buffer[i_pos + 2] = ( i >>  8 )&0xff;
1377     p_bo->p_buffer[i_pos + 3] = ( i       )&0xff;
1378 }
1379
1380 static void bo_add_64be( bo_t *p_bo, uint64_t i )
1381 {
1382     bo_add_32be( p_bo, ( ( i >> 32) &0xffffffff ) );
1383     bo_add_32be( p_bo, i &0xffffffff );
1384 }
1385
1386 static void bo_add_fourcc( bo_t *p_bo, char *fcc )
1387 {
1388     bo_add_8( p_bo, fcc[0] );
1389     bo_add_8( p_bo, fcc[1] );
1390     bo_add_8( p_bo, fcc[2] );
1391     bo_add_8( p_bo, fcc[3] );
1392 }
1393
1394 static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem )
1395 {
1396     int i;
1397
1398     for( i = 0; i < i_size; i++ )
1399     {
1400         bo_add_8( p_bo, p_mem[i] );
1401     }
1402 }
1403
1404 static void bo_add_descr( bo_t *p_bo, uint8_t tag, uint32_t i_size )
1405 {
1406     uint32_t i_length;
1407     uint8_t  vals[4];
1408
1409     i_length = i_size;
1410     vals[3] = (unsigned char)(i_length & 0x7f);
1411     i_length >>= 7;
1412     vals[2] = (unsigned char)((i_length & 0x7f) | 0x80); 
1413     i_length >>= 7;
1414     vals[1] = (unsigned char)((i_length & 0x7f) | 0x80); 
1415     i_length >>= 7;
1416     vals[0] = (unsigned char)((i_length & 0x7f) | 0x80);
1417
1418     bo_add_8( p_bo, tag );
1419
1420     if( i_size < 0x00000080 )
1421     {
1422         bo_add_8( p_bo, vals[3] );
1423     }
1424     else if( i_size < 0x00004000 )
1425     {
1426         bo_add_8( p_bo, vals[2] );
1427         bo_add_8( p_bo, vals[3] );
1428     }
1429     else if( i_size < 0x00200000 )
1430     {
1431         bo_add_8( p_bo, vals[1] );
1432         bo_add_8( p_bo, vals[2] );
1433         bo_add_8( p_bo, vals[3] );
1434     }
1435     else if( i_size < 0x10000000 )
1436     {
1437         bo_add_8( p_bo, vals[0] );
1438         bo_add_8( p_bo, vals[1] );
1439         bo_add_8( p_bo, vals[2] );
1440         bo_add_8( p_bo, vals[3] );
1441     }
1442 }
1443
1444 static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
1445 {
1446     int i;
1447
1448     for( i = 0; i < p_bo2->i_buffer; i++ )
1449     {
1450         bo_add_8( p_bo, p_bo2->p_buffer[i] );
1451     }
1452 }
1453
1454 static bo_t * box_new( char *fcc )
1455 {
1456     bo_t *box;
1457
1458     if( ( box = malloc( sizeof( bo_t ) ) ) )
1459     {
1460         bo_init( box, 0, NULL, VLC_TRUE );
1461
1462         bo_add_32be  ( box, 0 );
1463         bo_add_fourcc( box, fcc );
1464     }
1465
1466     return box;
1467 }
1468
1469 static bo_t * box_full_new( char *fcc, uint8_t v, uint32_t f )
1470 {
1471     bo_t *box;
1472
1473     if( ( box = malloc( sizeof( bo_t ) ) ) )
1474     {
1475         bo_init( box, 0, NULL, VLC_TRUE );
1476
1477         bo_add_32be  ( box, 0 );
1478         bo_add_fourcc( box, fcc );
1479         bo_add_8     ( box, v );
1480         bo_add_24be  ( box, f );
1481     }
1482
1483     return box;
1484 }
1485
1486 static void box_fix( bo_t *box )
1487 {
1488     bo_t box_tmp;
1489
1490     memcpy( &box_tmp, box, sizeof( bo_t ) );
1491
1492     box_tmp.i_buffer = 0;
1493     bo_add_32be( &box_tmp, box->i_buffer );
1494 }
1495
1496 static void box_free( bo_t *box )
1497 {
1498     if( box->p_buffer )
1499     {
1500         free( box->p_buffer );
1501     }
1502
1503     free( box );
1504 }
1505
1506 static void box_gather ( bo_t *box, bo_t *box2 )
1507 {
1508     bo_add_bo( box, box2 );
1509     box_free( box2 );
1510 }
1511
1512 static sout_buffer_t * bo_to_sout( sout_instance_t *p_sout,  bo_t *box )
1513 {
1514     sout_buffer_t *p_buf;
1515
1516     p_buf = sout_BufferNew( p_sout, box->i_buffer );
1517     if( box->i_buffer > 0 )
1518     {
1519         memcpy( p_buf->p_buffer, box->p_buffer, box->i_buffer );
1520     }
1521
1522     p_buf->i_size = box->i_buffer;
1523
1524     return p_buf;
1525 }
1526
1527 static void box_send( sout_mux_t *p_mux,  bo_t *box )
1528 {
1529     sout_buffer_t *p_buf;
1530
1531     p_buf = bo_to_sout( p_mux->p_sout, box );
1532     box_free( box );
1533
1534     sout_AccessOutWrite( p_mux->p_access, p_buf );
1535 }
1536
1537 static int64_t get_timestamp()
1538 {
1539     int64_t i_timestamp = 0;
1540
1541 #ifdef HAVE_TIME_H
1542     i_timestamp = time(NULL);
1543     i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
1544     // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
1545 #endif
1546
1547     return i_timestamp;
1548 }