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