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