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