]> git.sesse.net Git - vlc/blob - modules/mux/mp4.c
Remove some whitespace
[vlc] / modules / mux / mp4.c
1 /*****************************************************************************
2  * mp4.c: mp4/mov muxer
3  *****************************************************************************
4  * Copyright (C) 2001, 2002, 2003, 2006 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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     "Create \"Fast Start\" files. " \
48     "\"Fast Start\" files are optimized for downloads and allow the user " \
49     "to start previewing the file while it is downloading.")
50
51 static int  Open   ( vlc_object_t * );
52 static void Close  ( vlc_object_t * );
53
54 #define SOUT_CFG_PREFIX "sout-mp4-"
55
56 vlc_module_begin();
57     set_description( _("MP4/MOV muxer") );
58     set_category( CAT_SOUT );
59     set_subcategory( SUBCAT_SOUT_MUX );
60     set_shortname( "MP4" );
61
62     add_bool( SOUT_CFG_PREFIX "faststart", 1, NULL,
63               FASTSTART_TEXT, FASTSTART_LONGTEXT,
64               VLC_TRUE );
65     set_capability( "sout mux", 5 );
66     add_shortcut( "mp4" );
67     add_shortcut( "mov" );
68     add_shortcut( "3gp" );
69     set_callbacks( Open, Close );
70 vlc_module_end();
71
72 /*****************************************************************************
73  * Exported prototypes
74  *****************************************************************************/
75 static const char *ppsz_sout_options[] = {
76     "faststart", NULL
77 };
78
79 static int Control( sout_mux_t *, int, va_list );
80 static int AddStream( sout_mux_t *, sout_input_t * );
81 static int DelStream( sout_mux_t *, sout_input_t * );
82 static int Mux      ( sout_mux_t * );
83
84 /*****************************************************************************
85  * Local prototypes
86  *****************************************************************************/
87 typedef struct
88 {
89     uint64_t i_pos;
90     int      i_size;
91
92     mtime_t  i_pts_dts;
93     mtime_t  i_length;
94     unsigned int i_flags;
95
96 } mp4_entry_t;
97
98 typedef struct
99 {
100     es_format_t   fmt;
101     int           i_track_id;
102
103     /* index */
104     unsigned int i_entry_count;
105     unsigned int i_entry_max;
106     mp4_entry_t  *entry;
107     int64_t      i_length_neg;
108
109     /* stats */
110     int64_t      i_dts_start;
111     int64_t      i_duration;
112
113     /* for later stco fix-up (fast start files) */
114     uint64_t i_stco_pos;
115     vlc_bool_t b_stco64;
116
117     /* for h264 */
118     struct
119     {
120         int     i_profile;
121         int     i_level;
122
123         int     i_sps;
124         uint8_t *sps;
125         int     i_pps;
126         uint8_t *pps;
127     } avc;
128
129     /* for spu */
130     int64_t i_last_dts;
131
132 } mp4_stream_t;
133
134 struct sout_mux_sys_t
135 {
136     vlc_bool_t b_mov;
137     vlc_bool_t b_3gp;
138     vlc_bool_t b_64_ext;
139     vlc_bool_t b_fast_start;
140
141     uint64_t i_mdat_pos;
142     uint64_t i_pos;
143
144     int64_t  i_dts_start;
145
146     int          i_nb_streams;
147     mp4_stream_t **pp_streams;
148 };
149
150 typedef struct bo_t
151 {
152     vlc_bool_t b_grow;
153
154     int        i_buffer_size;
155     int        i_buffer;
156     uint8_t    *p_buffer;
157
158 } bo_t;
159
160 static void bo_init     ( bo_t *, int , uint8_t *, vlc_bool_t  );
161 static void bo_add_8    ( bo_t *, uint8_t );
162 static void bo_add_16be ( bo_t *, uint16_t );
163 static void bo_add_24be ( bo_t *, uint32_t );
164 static void bo_add_32be ( bo_t *, uint32_t );
165 static void bo_add_64be ( bo_t *, uint64_t );
166 static void bo_add_fourcc(bo_t *, char * );
167 static void bo_add_bo   ( bo_t *, bo_t * );
168 static void bo_add_mem  ( bo_t *, int , uint8_t * );
169 static void bo_add_descr( bo_t *, uint8_t , uint32_t );
170
171 static void bo_fix_32be ( bo_t *, int , uint32_t );
172
173 static bo_t *box_new     ( char *fcc );
174 static bo_t *box_full_new( char *fcc, uint8_t v, uint32_t f );
175 static void  box_fix     ( bo_t *box );
176 static void  box_free    ( bo_t *box );
177 static void  box_gather  ( bo_t *box, bo_t *box2 );
178
179 static void box_send( sout_mux_t *p_mux,  bo_t *box );
180
181 static block_t *bo_to_sout( sout_instance_t *p_sout,  bo_t *box );
182
183 static bo_t *GetMoovBox( sout_mux_t *p_mux );
184
185 static block_t *ConvertSUBT( sout_mux_t *, mp4_stream_t *, block_t *);
186 static void ConvertAVC1( sout_mux_t *, mp4_stream_t *, block_t * );
187
188 /*****************************************************************************
189  * Open:
190  *****************************************************************************/
191 static int Open( vlc_object_t *p_this )
192 {
193     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
194     sout_mux_sys_t  *p_sys;
195     bo_t            *box;
196
197     msg_Dbg( p_mux, "Mp4 muxer opend" );
198     sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
199
200     p_mux->pf_control   = Control;
201     p_mux->pf_addstream = AddStream;
202     p_mux->pf_delstream = DelStream;
203     p_mux->pf_mux       = Mux;
204     p_mux->p_sys        = p_sys = malloc( sizeof( sout_mux_sys_t ) );
205     p_sys->i_pos        = 0;
206     p_sys->i_nb_streams = 0;
207     p_sys->pp_streams   = NULL;
208     p_sys->i_mdat_pos   = 0;
209     p_sys->b_mov        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" );
210     p_sys->b_3gp        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "3gp" );
211     p_sys->i_dts_start  = 0;
212
213
214     if( !p_sys->b_mov )
215     {
216         /* Now add ftyp header */
217         box = box_new( "ftyp" );
218         if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
219         else bo_add_fourcc( box, "isom" );
220         bo_add_32be  ( box, 0 );
221         if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
222         else bo_add_fourcc( box, "mp41" );
223         box_fix( box );
224
225         p_sys->i_pos += box->i_buffer;
226         p_sys->i_mdat_pos = p_sys->i_pos;
227
228         box_send( p_mux, box );
229     }
230
231     /* FIXME FIXME
232      * Quicktime actually doesn't like the 64 bits extensions !!! */
233     p_sys->b_64_ext = VLC_FALSE;
234
235     /* Now add mdat header */
236     box = box_new( "mdat" );
237     bo_add_64be  ( box, 0 ); // enough to store an extended size
238
239     p_sys->i_pos += box->i_buffer;
240
241     box_send( p_mux, box );
242
243     return VLC_SUCCESS;
244 }
245
246 /*****************************************************************************
247  * Close:
248  *****************************************************************************/
249 static void Close( vlc_object_t * p_this )
250 {
251     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
252     sout_mux_sys_t  *p_sys = p_mux->p_sys;
253     block_t   *p_hdr;
254     bo_t            bo, *moov;
255     vlc_value_t     val;
256
257     int             i_trak;
258     uint64_t        i_moov_pos;
259
260     msg_Dbg( p_mux, "Close" );
261
262     /* Update mdat size */
263     bo_init( &bo, 0, NULL, VLC_TRUE );
264     if( p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32) )
265     {
266         /* Extended size */
267         bo_add_32be  ( &bo, 1 );
268         bo_add_fourcc( &bo, "mdat" );
269         bo_add_64be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos );
270     }
271     else
272     {
273         bo_add_32be  ( &bo, 8 );
274         bo_add_fourcc( &bo, "wide" );
275         bo_add_32be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos - 8 );
276         bo_add_fourcc( &bo, "mdat" );
277     }
278     p_hdr = bo_to_sout( p_mux->p_sout, &bo );
279     free( bo.p_buffer );
280
281     sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos );
282     sout_AccessOutWrite( p_mux->p_access, p_hdr );
283
284     /* Create MOOV header */
285     i_moov_pos = p_sys->i_pos;
286     moov = GetMoovBox( p_mux );
287
288     /* Check we need to create "fast start" files */
289     var_Get( p_this, SOUT_CFG_PREFIX "faststart", &val );
290     p_sys->b_fast_start = val.b_bool;
291     while( p_sys->b_fast_start )
292     {
293         /* Move data to the end of the file so we can fit the moov header
294          * at the start */
295         block_t *p_buf;
296         int64_t i_chunk, i_size = p_sys->i_pos - p_sys->i_mdat_pos;
297         int i_moov_size = moov->i_buffer;
298
299         while( i_size > 0 )
300         {
301             i_chunk = __MIN( 32768, i_size );
302             p_buf = block_New( p_mux, i_chunk );
303             sout_AccessOutSeek( p_mux->p_access,
304                                 p_sys->i_mdat_pos + i_size - i_chunk );
305             if( sout_AccessOutRead( p_mux->p_access, p_buf ) < i_chunk )
306             {
307                 msg_Warn( p_this, "read() not supported by access output, "
308                           "won't create a fast start file" );
309                 p_sys->b_fast_start = VLC_FALSE;
310                 block_Release( p_buf );
311                 break;
312             }
313             sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos + i_size +
314                                 i_moov_size - i_chunk );
315             sout_AccessOutWrite( p_mux->p_access, p_buf );
316             i_size -= i_chunk;
317         }
318
319         if( !p_sys->b_fast_start ) break;
320
321         /* Fix-up samples to chunks table in MOOV header */
322         for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
323         {
324             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
325             unsigned int i;
326             int i_chunk;
327
328             moov->i_buffer = p_stream->i_stco_pos;
329             for( i_chunk = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ )
330             {
331                 if( p_stream->b_stco64 )
332                     bo_add_64be( moov, p_stream->entry[i].i_pos + i_moov_size);
333                 else
334                     bo_add_32be( moov, p_stream->entry[i].i_pos + i_moov_size);
335
336                 while( i < p_stream->i_entry_count )
337                 {
338                     if( i + 1 < p_stream->i_entry_count &&
339                         p_stream->entry[i].i_pos + p_stream->entry[i].i_size
340                         != p_stream->entry[i + 1].i_pos )
341                     {
342                         i++;
343                         break;
344                     }
345
346                     i++;
347                 }
348             }
349         }
350
351         moov->i_buffer = i_moov_size;
352         i_moov_pos = p_sys->i_mdat_pos;
353         p_sys->b_fast_start = VLC_FALSE;
354     }
355
356     /* Write MOOV header */
357     sout_AccessOutSeek( p_mux->p_access, i_moov_pos );
358     box_send( p_mux, moov );
359
360     /* Clean-up */
361     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
362     {
363         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
364
365         es_format_Clean( &p_stream->fmt );
366         if( p_stream->avc.i_sps ) free( p_stream->avc.sps );
367         if( p_stream->avc.i_pps ) free( p_stream->avc.pps );
368         free( p_stream->entry );
369         free( p_stream );
370     }
371     if( p_sys->i_nb_streams ) free( p_sys->pp_streams );
372     free( p_sys );
373 }
374
375 /*****************************************************************************
376  * Control:
377  *****************************************************************************/
378 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
379 {
380     vlc_bool_t *pb_bool;
381
382    switch( i_query )
383    {
384        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
385            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
386            *pb_bool = VLC_FALSE;
387            return VLC_SUCCESS;
388
389        case MUX_GET_ADD_STREAM_WAIT:
390            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
391            *pb_bool = VLC_TRUE;
392            return VLC_SUCCESS;
393
394        case MUX_GET_MIME:   /* Not needed, as not streamable */
395         default:
396             return VLC_EGENERIC;
397    }
398 }
399
400 /*****************************************************************************
401  * AddStream:
402  *****************************************************************************/
403 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
404 {
405     sout_mux_sys_t  *p_sys = p_mux->p_sys;
406     mp4_stream_t    *p_stream;
407
408     switch( p_input->p_fmt->i_codec )
409     {
410         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
411         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
412         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
413         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
414         case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
415         case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
416         case VLC_FOURCC( 'S', 'V', 'Q', '1' ):
417         case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
418         case VLC_FOURCC( 'H', '2', '6', '3' ):
419         case VLC_FOURCC( 'h', '2', '6', '4' ):
420         case VLC_FOURCC( 's', 'a', 'm', 'r' ):
421         case VLC_FOURCC( 's', 'a', 'w', 'b' ):
422             break;
423         case VLC_FOURCC( 's', 'u', 'b', 't' ):
424             msg_Warn( p_mux, "subtitle track added like in .mov (even when creating .mp4)" );
425             break;
426         default:
427             msg_Err( p_mux, "unsupported codec %4.4s in mp4",
428                      (char*)&p_input->p_fmt->i_codec );
429             return VLC_EGENERIC;
430     }
431
432     p_stream                = malloc( sizeof( mp4_stream_t ) );
433     es_format_Copy( &p_stream->fmt, p_input->p_fmt );
434     p_stream->i_track_id    = p_sys->i_nb_streams + 1;
435     p_stream->i_length_neg  = 0;
436     p_stream->i_entry_count = 0;
437     p_stream->i_entry_max   = 1000;
438     p_stream->entry         =
439         calloc( p_stream->i_entry_max, sizeof( mp4_entry_t ) );
440     p_stream->i_dts_start   = 0;
441     p_stream->i_duration    = 0;
442     p_stream->avc.i_profile = 77;
443     p_stream->avc.i_level   = 51;
444     p_stream->avc.i_sps     = 0;
445     p_stream->avc.sps       = NULL;
446     p_stream->avc.i_pps     = 0;
447     p_stream->avc.pps       = NULL;
448
449     p_input->p_sys          = p_stream;
450
451     msg_Dbg( p_mux, "adding input" );
452
453     TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, p_stream );
454     return VLC_SUCCESS;
455 }
456
457 /*****************************************************************************
458  * DelStream:
459  *****************************************************************************/
460 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
461 {
462     msg_Dbg( p_mux, "removing input" );
463     return VLC_SUCCESS;
464 }
465
466 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
467 {
468     mtime_t i_dts;
469     int     i_stream;
470     int     i;
471
472     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
473     {
474         block_fifo_t   *p_fifo = p_mux->pp_inputs[i]->p_fifo;
475         block_t *p_buf;
476
477         if( p_fifo->i_depth <= 1 )
478         {
479             if( p_mux->pp_inputs[i]->p_fmt->i_cat != SPU_ES )
480             {
481                 return -1; // wait that all fifo have at least 2 packets
482             }
483             /* For SPU, we wait only 1 packet */
484             continue;
485         }
486
487         p_buf = block_FifoShow( p_fifo );
488         if( i_stream < 0 || p_buf->i_dts < i_dts )
489         {
490             i_dts = p_buf->i_dts;
491             i_stream = i;
492         }
493     }
494     if( pi_stream )
495     {
496         *pi_stream = i_stream;
497     }
498     if( pi_dts )
499     {
500         *pi_dts = i_dts;
501     }
502     return i_stream;
503 }
504
505 /*****************************************************************************
506  * Mux:
507  *****************************************************************************/
508 static int Mux( sout_mux_t *p_mux )
509 {
510     sout_mux_sys_t *p_sys = p_mux->p_sys;
511
512     for( ;; )
513     {
514         sout_input_t    *p_input;
515         int             i_stream;
516         mp4_stream_t    *p_stream;
517         block_t         *p_data;
518         mtime_t         i_dts;
519
520         if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
521         {
522             return( VLC_SUCCESS );
523         }
524
525         p_input  = p_mux->pp_inputs[i_stream];
526         p_stream = (mp4_stream_t*)p_input->p_sys;
527
528         p_data  = block_FifoGet( p_input->p_fifo );
529         if( p_stream->fmt.i_codec == VLC_FOURCC( 'h', '2', '6', '4' ) )
530         {
531             ConvertAVC1( p_mux, p_stream, p_data );
532         }
533         else if( p_stream->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) )
534         {
535             p_data = ConvertSUBT( p_mux, p_stream, p_data );
536         }
537
538         if( p_stream->fmt.i_cat != SPU_ES )
539         {
540             /* Fix length of the sample */
541             if( p_input->p_fifo->i_depth > 0 )
542             {
543                 block_t *p_next = block_FifoShow( p_input->p_fifo );
544                 int64_t       i_diff  = p_next->i_dts - p_data->i_dts;
545
546                 if( i_diff < I64C(1000000 ) )   /* protection */
547                 {
548                     p_data->i_length = i_diff;
549                 }
550             }
551             if( p_data->i_length <= 0 )
552             {
553                 msg_Warn( p_mux, "i_length <= 0" );
554                 p_stream->i_length_neg += p_data->i_length - 1;
555                 p_data->i_length = 1;
556             }
557             else if( p_stream->i_length_neg < 0 )
558             {
559                 int64_t i_recover = __MIN( p_data->i_length / 4, - p_stream->i_length_neg );
560
561                 p_data->i_length -= i_recover;
562                 p_stream->i_length_neg += i_recover;
563             }
564         }
565
566         /* Save starting time */
567         if( p_stream->i_entry_count == 0 )
568         {
569             p_stream->i_dts_start = p_data->i_dts;
570
571             /* Update global dts_start */
572             if( p_sys->i_dts_start <= 0 ||
573                 p_stream->i_dts_start < p_sys->i_dts_start )
574             {
575                 p_sys->i_dts_start = p_stream->i_dts_start;
576             }
577         }
578
579         if( p_stream->fmt.i_cat == SPU_ES && p_stream->i_entry_count > 0 )
580         {
581             int64_t i_length = p_data->i_dts - p_stream->i_last_dts;
582
583             if( i_length <= 0 )
584             {
585                 /* FIXME handle this broken case */
586                 i_length = 1;
587             }
588
589             /* Fix last entry */
590             if( p_stream->entry[p_stream->i_entry_count-1].i_length <= 0 )
591             {
592                 p_stream->entry[p_stream->i_entry_count-1].i_length = i_length;
593             }
594         }
595
596
597         /* add index entry */
598         p_stream->entry[p_stream->i_entry_count].i_pos    = p_sys->i_pos;
599         p_stream->entry[p_stream->i_entry_count].i_size   = p_data->i_buffer;
600         p_stream->entry[p_stream->i_entry_count].i_pts_dts=
601             __MAX( p_data->i_pts - p_data->i_dts, 0 );
602         p_stream->entry[p_stream->i_entry_count].i_length = p_data->i_length;
603         p_stream->entry[p_stream->i_entry_count].i_flags  = p_data->i_flags;
604
605         p_stream->i_entry_count++;
606         /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
607         if( p_stream->i_entry_count >= p_stream->i_entry_max - 1 )
608         {
609             p_stream->i_entry_max += 1000;
610             p_stream->entry =
611                 realloc( p_stream->entry,
612                          p_stream->i_entry_max * sizeof( mp4_entry_t ) );
613         }
614
615         /* update */
616         p_stream->i_duration += p_data->i_length;
617         p_sys->i_pos += p_data->i_buffer;
618
619         /* Save the DTS */
620         p_stream->i_last_dts = p_data->i_dts;
621
622         /* write data */
623         sout_AccessOutWrite( p_mux->p_access, p_data );
624
625         if( p_stream->fmt.i_cat == SPU_ES )
626         {
627             int64_t i_length = p_stream->entry[p_stream->i_entry_count-1].i_length;
628
629             if( i_length != 0 )
630             {
631                 /* TODO */
632                 msg_Dbg( p_mux, "writing an empty sub" ) ;
633
634                 /* Append a idx entry */
635                 p_stream->entry[p_stream->i_entry_count].i_pos    = p_sys->i_pos;
636                 p_stream->entry[p_stream->i_entry_count].i_size   = 3;
637                 p_stream->entry[p_stream->i_entry_count].i_pts_dts= 0;
638                 p_stream->entry[p_stream->i_entry_count].i_length = 0;
639                 p_stream->entry[p_stream->i_entry_count].i_flags  = 0;
640
641                 /* XXX: No need to grow the entry here */
642                 p_stream->i_entry_count++;
643
644                 /* Fix last dts */
645                 p_stream->i_last_dts += i_length;
646
647                 /* Write a " " */
648                 p_data = block_New( p_mux, 3 );
649                 p_data->p_buffer[0] = 0;
650                 p_data->p_buffer[1] = 1;
651                 p_data->p_buffer[2] = ' ';
652
653                 p_sys->i_pos += p_data->i_buffer;
654
655                 sout_AccessOutWrite( p_mux->p_access, p_data );
656             }
657
658             /* Fix duration */
659             p_stream->i_duration = p_stream->i_last_dts - p_stream->i_dts_start;
660         }
661     }
662
663     return( VLC_SUCCESS );
664 }
665
666 /*****************************************************************************
667  *
668  *****************************************************************************/
669 static block_t *ConvertSUBT( sout_mux_t *p_mux, mp4_stream_t *tk, block_t *p_block )
670 {
671     p_block = block_Realloc( p_block, 2, p_block->i_buffer );
672
673     /* No trailling '\0' */
674     if( p_block->i_buffer > 2 && p_block->p_buffer[p_block->i_buffer-1] == '\0' )
675         p_block->i_buffer--;
676
677     p_block->p_buffer[0] = ( (p_block->i_buffer - 2) >> 8 )&0xff;
678     p_block->p_buffer[1] = ( (p_block->i_buffer - 2)      )&0xff;
679
680     return p_block;
681 }
682
683 static void ConvertAVC1( sout_mux_t *p_mux, mp4_stream_t *tk, block_t *p_block )
684 {
685     uint8_t *last = p_block->p_buffer;  /* Assume it starts with 0x00000001 */
686     uint8_t *dat  = &p_block->p_buffer[4];
687     uint8_t *end = &p_block->p_buffer[p_block->i_buffer];
688
689
690     /* Replace the 4 bytes start code with 4 bytes size,
691      * FIXME are all startcodes 4 bytes ? (I don't think :( */
692     while( dat < end )
693     {
694         int i_size;
695
696         while( dat < end - 4 )
697         {
698             if( dat[0] == 0x00 && dat[1] == 0x00  &&
699                 dat[2] == 0x00 && dat[3] == 0x01 )
700             {
701                 break;
702             }
703             dat++;
704         }
705         if( dat >= end - 4 )
706         {
707             dat = end;
708         }
709
710         /* Fix size */
711         i_size = dat - &last[4];
712         last[0] = ( i_size >> 24 )&0xff;
713         last[1] = ( i_size >> 16 )&0xff;
714         last[2] = ( i_size >>  8 )&0xff;
715         last[3] = ( i_size       )&0xff;
716
717         if( (last[4]&0x1f) == 7 && tk->avc.i_sps <= 0 )  /* SPS */
718         {
719             tk->avc.i_sps = i_size;
720             tk->avc.sps = malloc( i_size );
721             memcpy( tk->avc.sps, &last[4], i_size );
722
723             tk->avc.i_profile = tk->avc.sps[1];
724             tk->avc.i_level   = tk->avc.sps[3];
725         }
726         else if( (last[4]&0x1f) == 8 && tk->avc.i_pps <= 0 )   /* PPS */
727         {
728             tk->avc.i_pps = i_size;
729             tk->avc.pps = malloc( i_size );
730             memcpy( tk->avc.pps, &last[4], i_size );
731         }
732
733         last = dat;
734
735         dat += 4;
736     }
737 }
738
739 static int GetDescrLength( int i_size )
740 {
741     if( i_size < 0x00000080 )
742         return 2 + i_size;
743     else if( i_size < 0x00004000 )
744         return 3 + i_size;
745     else if( i_size < 0x00200000 )
746         return 4 + i_size;
747     else
748         return 5 + i_size;
749 }
750
751 static bo_t *GetESDS( mp4_stream_t *p_stream )
752 {
753     bo_t *esds;
754     int  i_stream_type;
755     int  i_object_type_indication;
756     int  i_decoder_specific_info_size;
757     unsigned int i;
758     int64_t i_bitrate_avg = 0;
759     int64_t i_bitrate_max = 0;
760
761     /* Compute avg/max bitrate */
762     for( i = 0; i < p_stream->i_entry_count; i++ )
763     {
764         i_bitrate_avg += p_stream->entry[i].i_size;
765         if( p_stream->entry[i].i_length > 0)
766         {
767             int64_t i_bitrate = I64C(8000000) * p_stream->entry[i].i_size / p_stream->entry[i].i_length;
768             if( i_bitrate > i_bitrate_max )
769                 i_bitrate_max = i_bitrate;
770         }
771     }
772
773     if( p_stream->i_duration > 0 )
774         i_bitrate_avg = I64C(8000000) * i_bitrate_avg / p_stream->i_duration;
775     else
776         i_bitrate_avg = 0;
777     if( i_bitrate_max <= 1 )
778         i_bitrate_max = 0x7fffffff;
779
780     /* */
781     if( p_stream->fmt.i_extra > 0 )
782     {
783         i_decoder_specific_info_size =
784             GetDescrLength( p_stream->fmt.i_extra );
785     }
786     else
787     {
788         i_decoder_specific_info_size = 0;
789     }
790
791     esds = box_full_new( "esds", 0, 0 );
792
793     /* ES_Descr */
794     bo_add_descr( esds, 0x03, 3 +
795                   GetDescrLength( 13 + i_decoder_specific_info_size ) +
796                   GetDescrLength( 1 ) );
797     bo_add_16be( esds, p_stream->i_track_id );
798     bo_add_8   ( esds, 0x1f );      // flags=0|streamPriority=0x1f
799
800     /* DecoderConfigDescr */
801     bo_add_descr( esds, 0x04, 13 + i_decoder_specific_info_size );
802
803     switch( p_stream->fmt.i_codec )
804     {
805         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
806             i_object_type_indication = 0x20;
807             break;
808         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
809             /* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
810             i_object_type_indication = 0x60;
811             break;
812         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
813             /* FIXME for mpeg2-aac == 0x66->0x68 */
814             i_object_type_indication = 0x40;
815             break;
816         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
817             i_object_type_indication =
818                 p_stream->fmt.audio.i_rate < 32000 ? 0x69 : 0x6b;
819             break;
820         default:
821             i_object_type_indication = 0x00;
822             break;
823     }
824     i_stream_type = p_stream->fmt.i_cat == VIDEO_ES ? 0x04 : 0x05;
825
826     bo_add_8   ( esds, i_object_type_indication );
827     bo_add_8   ( esds, ( i_stream_type << 2 ) | 1 );
828     bo_add_24be( esds, 1024 * 1024 );       // bufferSizeDB
829     bo_add_32be( esds, i_bitrate_max );     // maxBitrate
830     bo_add_32be( esds, i_bitrate_avg );     // avgBitrate
831
832     if( p_stream->fmt.i_extra > 0 )
833     {
834         int i;
835
836         /* DecoderSpecificInfo */
837         bo_add_descr( esds, 0x05, p_stream->fmt.i_extra );
838
839         for( i = 0; i < p_stream->fmt.i_extra; i++ )
840         {
841             bo_add_8( esds, ((uint8_t*)p_stream->fmt.p_extra)[i] );
842         }
843     }
844
845     /* SL_Descr mandatory */
846     bo_add_descr( esds, 0x06, 1 );
847     bo_add_8    ( esds, 0x02 );  // sl_predefined
848
849     box_fix( esds );
850
851     return esds;
852 }
853
854 static bo_t *GetWaveTag( mp4_stream_t *p_stream )
855 {
856     bo_t *wave;
857     bo_t *box;
858
859     wave = box_new( "wave" );
860
861     box = box_new( "frma" );
862     bo_add_fourcc( box, "mp4a" );
863     box_fix( box );
864     box_gather( wave, box );
865
866     box = box_new( "mp4a" );
867     bo_add_32be( box, 0 );
868     box_fix( box );
869     box_gather( wave, box );
870
871     box = GetESDS( p_stream );
872     box_fix( box );
873     box_gather( wave, box );
874
875     box = box_new( "srcq" );
876     bo_add_32be( box, 0x40 );
877     box_fix( box );
878     box_gather( wave, box );
879
880     /* wazza ? */
881     bo_add_32be( wave, 8 ); /* new empty box */
882     bo_add_32be( wave, 0 ); /* box label */
883
884     box_fix( wave );
885
886     return wave;
887 }
888
889 static bo_t *GetDamrTag( mp4_stream_t *p_stream )
890 {
891     bo_t *damr;
892
893     damr = box_new( "damr" );
894
895     bo_add_fourcc( damr, "REFC" );
896     bo_add_8( damr, 0 );
897
898     if( p_stream->fmt.i_codec == VLC_FOURCC( 's', 'a', 'm', 'r' ) )
899         bo_add_16be( damr, 0x81ff ); /* Mode set (all modes for AMR_NB) */
900     else
901         bo_add_16be( damr, 0x83ff ); /* Mode set (all modes for AMR_WB) */
902     bo_add_16be( damr, 0x1 ); /* Mode change period (no restriction) */
903
904     box_fix( damr );
905
906     return damr;
907 }
908
909 static bo_t *GetD263Tag( mp4_stream_t *p_stream )
910 {
911     bo_t *d263;
912
913     d263 = box_new( "d263" );
914
915     bo_add_fourcc( d263, "VLC " );
916     bo_add_16be( d263, 0xa );
917     bo_add_8( d263, 0 );
918
919     box_fix( d263 );
920
921     return d263;
922 }
923
924 static bo_t *GetAvcCTag( mp4_stream_t *p_stream )
925 {
926     bo_t *avcC;
927
928     /* FIXME use better value */
929     avcC = box_new( "avcC" );
930     bo_add_8( avcC, 1 );      /* configuration version */
931     bo_add_8( avcC, p_stream->avc.i_profile );
932     bo_add_8( avcC, p_stream->avc.i_profile );     /* profile compatible ??? */
933     bo_add_8( avcC, p_stream->avc.i_level );       /* level, 5.1 */
934     bo_add_8( avcC, 0xff );   /* 0b11111100 | lengthsize = 0x11 */
935
936     bo_add_8( avcC, 0xe0 | (p_stream->avc.i_sps > 0 ? 1 : 0) );   /* 0b11100000 | sps_count */
937     if( p_stream->avc.i_sps > 0 )
938     {
939         bo_add_16be( avcC, p_stream->avc.i_sps );
940         bo_add_mem( avcC, p_stream->avc.i_sps, p_stream->avc.sps );
941     }
942
943     bo_add_8( avcC, (p_stream->avc.i_pps > 0 ? 1 : 0) );   /* pps_count */
944     if( p_stream->avc.i_pps > 0 )
945     {
946         bo_add_16be( avcC, p_stream->avc.i_pps );
947         bo_add_mem( avcC, p_stream->avc.i_pps, p_stream->avc.pps );
948     }
949     box_fix( avcC );
950
951     return avcC;
952 }
953
954 /* TODO: No idea about these values */
955 static bo_t *GetSVQ3Tag( mp4_stream_t *p_stream )
956 {
957     bo_t *smi = box_new( "SMI " );
958
959     if( p_stream->fmt.i_extra > 0x4e )
960     {
961         uint8_t *p_end = &((uint8_t*)p_stream->fmt.p_extra)[p_stream->fmt.i_extra];
962         uint8_t *p     = &((uint8_t*)p_stream->fmt.p_extra)[0x46];
963
964         while( p + 8 < p_end )
965         {
966             int i_size = GetDWBE( p );
967             if( i_size <= 1 )
968             {
969                 /* FIXME handle 1 as long size */
970                 break;
971             }
972             if( !strncmp( (const char *)&p[4], "SMI ", 4 ) )
973             {
974                 bo_add_mem( smi, p_end - p - 8, &p[8] );
975                 return smi;
976             }
977             p += i_size;
978         }
979     }
980
981     /* Create a dummy one in fallback */
982     bo_add_fourcc( smi, "SEQH" );
983     bo_add_32be( smi, 0x5 );
984     bo_add_32be( smi, 0xe2c0211d );
985     bo_add_8( smi, 0xc0 );
986     box_fix( smi );
987
988     return smi;
989 }
990
991 static bo_t *GetUdtaTag( sout_mux_t *p_mux )
992 {
993     sout_mux_sys_t *p_sys = p_mux->p_sys;
994     bo_t *udta = box_new( "udta" );
995     vlc_meta_t *p_meta = p_mux->p_sout->p_meta;
996     int i_track;
997
998     /* Requirements */
999     for( i_track = 0; i_track < p_sys->i_nb_streams; i_track++ )
1000     {
1001         mp4_stream_t *p_stream = p_sys->pp_streams[i_track];
1002
1003         if( p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','v') ||
1004             p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
1005         {
1006             bo_t *box = box_new( "\251req" );
1007             /* String length */
1008             bo_add_16be( box, sizeof("QuickTime 6.0 or greater") - 1);
1009             bo_add_16be( box, 0 );
1010             bo_add_mem( box, sizeof("QuickTime 6.0 or greater") - 1,
1011                         (uint8_t *)"QuickTime 6.0 or greater" );
1012             box_fix( box );
1013             box_gather( udta, box );
1014             break;
1015         }
1016     }
1017
1018     /* Encoder */
1019     {
1020         bo_t *box = box_new( "\251enc" );
1021         /* String length */
1022         bo_add_16be( box, sizeof(PACKAGE_STRING " stream output") - 1);
1023         bo_add_16be( box, 0 );
1024         bo_add_mem( box, sizeof(PACKAGE_STRING " stream output") - 1,
1025                     (uint8_t*)PACKAGE_STRING " stream output" );
1026         box_fix( box );
1027         box_gather( udta, box );
1028     }
1029
1030     /* Misc atoms */
1031     if( p_meta )
1032     {
1033 #define ADD_META_BOX( type, box_string ) { \
1034         bo_t *box = NULL;  \
1035         if( p_meta->psz_##type ) box = box_new( "\251" box_string ); \
1036         if( box ) \
1037         { \
1038             bo_add_16be( box, strlen( p_meta->psz_##type ) ); \
1039             bo_add_16be( box, 0 ); \
1040             bo_add_mem( box, strlen( p_meta->psz_##type ), \
1041                         (uint8_t*)(p_meta->psz_##type ) ); \
1042             box_fix( box ); \
1043             box_gather( udta, box ); \
1044         } }
1045
1046         ADD_META_BOX( title, "nam" );
1047         ADD_META_BOX( author, "aut" );
1048         ADD_META_BOX( artist, "ART" );
1049         ADD_META_BOX( genre, "gen" );
1050         ADD_META_BOX( copyright, "cpy" );
1051         ADD_META_BOX( description, "des" );
1052         ADD_META_BOX( date, "day" );
1053         ADD_META_BOX( url, "url" );
1054 #undef ADD_META_BOX
1055     }
1056
1057     box_fix( udta );
1058     return udta;
1059 }
1060
1061 static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
1062 {
1063     sout_mux_sys_t *p_sys = p_mux->p_sys;
1064     vlc_bool_t b_descr = VLC_FALSE;
1065     bo_t *soun;
1066     char fcc[4] = "    ";
1067     int  i;
1068
1069     switch( p_stream->fmt.i_codec )
1070     {
1071     case VLC_FOURCC('m','p','4','a'):
1072         memcpy( fcc, "mp4a", 4 );
1073         b_descr = VLC_TRUE;
1074         break;
1075
1076     case VLC_FOURCC('s','a','m','r'):
1077     case VLC_FOURCC('s','a','w','b'):
1078         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1079         b_descr = VLC_TRUE;
1080         break;
1081
1082     case VLC_FOURCC('m','p','g','a'):
1083         if( p_sys->b_mov )
1084             memcpy( fcc, ".mp3", 4 );
1085         else
1086         {
1087             memcpy( fcc, "mp4a", 4 );
1088             b_descr = VLC_TRUE;
1089         }
1090         break;
1091
1092     default:
1093         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1094         break;
1095     }
1096
1097     soun = box_new( fcc );
1098     for( i = 0; i < 6; i++ )
1099     {
1100         bo_add_8( soun, 0 );        // reserved;
1101     }
1102     bo_add_16be( soun, 1 );         // data-reference-index
1103
1104     /* SoundDescription */
1105     if( p_sys->b_mov &&
1106         p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
1107     {
1108         bo_add_16be( soun, 1 );     // version 1;
1109     }
1110     else
1111     {
1112         bo_add_16be( soun, 0 );     // version 0;
1113     }
1114     bo_add_16be( soun, 0 );         // revision level (0)
1115     bo_add_32be( soun, 0 );         // vendor
1116     // channel-count
1117     bo_add_16be( soun, p_stream->fmt.audio.i_channels );
1118     // sample size
1119     bo_add_16be( soun, p_stream->fmt.audio.i_bitspersample ?
1120                  p_stream->fmt.audio.i_bitspersample : 16 );
1121     bo_add_16be( soun, -2 );        // compression id
1122     bo_add_16be( soun, 0 );         // packet size (0)
1123     bo_add_16be( soun, p_stream->fmt.audio.i_rate ); // sampleratehi
1124     bo_add_16be( soun, 0 );                             // sampleratelo
1125
1126     /* Extended data for SoundDescription V1 */
1127     if( p_sys->b_mov &&
1128         p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
1129     {
1130         /* samples per packet */
1131         bo_add_32be( soun, p_stream->fmt.audio.i_frame_length );
1132         bo_add_32be( soun, 1536 ); /* bytes per packet */
1133         bo_add_32be( soun, 2 );    /* bytes per frame */
1134         /* bytes per sample */
1135         bo_add_32be( soun, 2 /*p_stream->fmt.audio.i_bitspersample/8 */);
1136     }
1137
1138     /* Add an ES Descriptor */
1139     if( b_descr )
1140     {
1141         bo_t *box;
1142
1143         if( p_sys->b_mov &&
1144             p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
1145         {
1146             box = GetWaveTag( p_stream );
1147         }
1148         else if( p_stream->fmt.i_codec == VLC_FOURCC('s','a','m','r') )
1149         {
1150             box = GetDamrTag( p_stream );
1151         }
1152         else
1153         {
1154             box = GetESDS( p_stream );
1155         }
1156         box_fix( box );
1157         box_gather( soun, box );
1158     }
1159
1160     box_fix( soun );
1161
1162     return soun;
1163 }
1164
1165 static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
1166 {
1167
1168     bo_t *vide;
1169     char fcc[4] = "    ";
1170     int  i;
1171
1172     switch( p_stream->fmt.i_codec )
1173     {
1174     case VLC_FOURCC('m','p','4','v'):
1175     case VLC_FOURCC('m','p','g','v'):
1176         memcpy( fcc, "mp4v", 4 );
1177         break;
1178
1179     case VLC_FOURCC('M','J','P','G'):
1180         memcpy( fcc, "mjpa", 4 );
1181         break;
1182
1183     case VLC_FOURCC('S','V','Q','1'):
1184         memcpy( fcc, "SVQ1", 4 );
1185         break;
1186
1187     case VLC_FOURCC('S','V','Q','3'):
1188         memcpy( fcc, "SVQ3", 4 );
1189         break;
1190
1191     case VLC_FOURCC('H','2','6','3'):
1192         memcpy( fcc, "s263", 4 );
1193         break;
1194
1195     case VLC_FOURCC('h','2','6','4'):
1196         memcpy( fcc, "avc1", 4 );
1197         break;
1198
1199     default:
1200         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1201         break;
1202     }
1203
1204     vide = box_new( fcc );
1205     for( i = 0; i < 6; i++ )
1206     {
1207         bo_add_8( vide, 0 );        // reserved;
1208     }
1209     bo_add_16be( vide, 1 );         // data-reference-index
1210
1211     bo_add_16be( vide, 0 );         // predefined;
1212     bo_add_16be( vide, 0 );         // reserved;
1213     for( i = 0; i < 3; i++ )
1214     {
1215         bo_add_32be( vide, 0 );     // predefined;
1216     }
1217
1218     bo_add_16be( vide, p_stream->fmt.video.i_width );  // i_width
1219     bo_add_16be( vide, p_stream->fmt.video.i_height ); // i_height
1220
1221     bo_add_32be( vide, 0x00480000 );                // h 72dpi
1222     bo_add_32be( vide, 0x00480000 );                // v 72dpi
1223
1224     bo_add_32be( vide, 0 );         // data size, always 0
1225     bo_add_16be( vide, 1 );         // frames count per sample
1226
1227     // compressor name;
1228     for( i = 0; i < 32; i++ )
1229     {
1230         bo_add_8( vide, 0 );
1231     }
1232
1233     bo_add_16be( vide, 0x18 );      // depth
1234     bo_add_16be( vide, 0xffff );    // predefined
1235
1236     /* add an ES Descriptor */
1237     switch( p_stream->fmt.i_codec )
1238     {
1239     case VLC_FOURCC('m','p','4','v'):
1240     case VLC_FOURCC('m','p','g','v'):
1241         {
1242             bo_t *esds = GetESDS( p_stream );
1243
1244             box_fix( esds );
1245             box_gather( vide, esds );
1246         }
1247         break;
1248
1249     case VLC_FOURCC('H','2','6','3'):
1250         {
1251             bo_t *d263 = GetD263Tag( p_stream );
1252
1253             box_fix( d263 );
1254             box_gather( vide, d263 );
1255         }
1256         break;
1257
1258     case VLC_FOURCC('S','V','Q','3'):
1259         {
1260             bo_t *esds = GetSVQ3Tag( p_stream );
1261
1262             box_fix( esds );
1263             box_gather( vide, esds );
1264         }
1265         break;
1266
1267     case VLC_FOURCC('h','2','6','4'):
1268         box_gather( vide, GetAvcCTag( p_stream ) );
1269         break;
1270
1271     default:
1272         break;
1273     }
1274
1275     box_fix( vide );
1276
1277     return vide;
1278 }
1279
1280 static bo_t *GetTextBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
1281 {
1282
1283     bo_t *text = box_new( "text" );
1284     int  i;
1285
1286     for( i = 0; i < 6; i++ )
1287     {
1288         bo_add_8( text, 0 );        // reserved;
1289     }
1290     bo_add_16be( text, 1 );         // data-reference-index
1291
1292     bo_add_32be( text, 0 );         // display flags
1293     bo_add_32be( text, 0 );         // justification
1294     for( i = 0; i < 3; i++ )
1295     {
1296         bo_add_16be( text, 0 );     // back ground color
1297     }
1298
1299     bo_add_16be( text, 0 );         // box text
1300     bo_add_16be( text, 0 );         // box text
1301     bo_add_16be( text, 0 );         // box text
1302     bo_add_16be( text, 0 );         // box text
1303
1304     bo_add_64be( text, 0 );         // reserved
1305     for( i = 0; i < 3; i++ )
1306     {
1307         bo_add_16be( text, 0xff );  // foreground color
1308     }
1309
1310     bo_add_8 ( text, 9 );
1311     bo_add_mem( text, 9, (uint8_t*)"Helvetica" );
1312
1313     box_fix( text );
1314
1315     return text;
1316 }
1317
1318 static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
1319 {
1320     sout_mux_sys_t *p_sys = p_mux->p_sys;
1321     unsigned int i_chunk, i_stsc_last_val, i_stsc_entries, i, i_index;
1322     bo_t *stbl, *stsd, *stts, *stco, *stsc, *stsz, *stss;
1323     uint32_t i_timescale;
1324     int64_t i_dts, i_dts_q;
1325
1326     stbl = box_new( "stbl" );
1327
1328     /* sample description */
1329     stsd = box_full_new( "stsd", 0, 0 );
1330     bo_add_32be( stsd, 1 );
1331     if( p_stream->fmt.i_cat == AUDIO_ES )
1332     {
1333         bo_t *soun = GetSounBox( p_mux, p_stream );
1334         box_gather( stsd, soun );
1335     }
1336     else if( p_stream->fmt.i_cat == VIDEO_ES )
1337     {
1338         bo_t *vide = GetVideBox( p_mux, p_stream );
1339         box_gather( stsd, vide );
1340     }
1341     else if( p_stream->fmt.i_cat == SPU_ES )
1342     {
1343         box_gather( stsd, GetTextBox( p_mux, p_stream ) );
1344     }
1345     box_fix( stsd );
1346
1347     /* chunk offset table */
1348     if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
1349     {
1350         /* 64 bits version */
1351         p_stream->b_stco64 = VLC_TRUE;
1352         stco = box_full_new( "co64", 0, 0 );
1353     }
1354     else
1355     {
1356         /* 32 bits version */
1357         p_stream->b_stco64 = VLC_FALSE;
1358         stco = box_full_new( "stco", 0, 0 );
1359     }
1360     bo_add_32be( stco, 0 );     // entry-count (fixed latter)
1361
1362     /* sample to chunk table */
1363     stsc = box_full_new( "stsc", 0, 0 );
1364     bo_add_32be( stsc, 0 );     // entry-count (fixed latter)
1365
1366     for( i_chunk = 0, i_stsc_last_val = 0, i_stsc_entries = 0, i = 0;
1367          i < p_stream->i_entry_count; i_chunk++ )
1368     {
1369         int i_first = i;
1370
1371         if( p_stream->b_stco64 )
1372             bo_add_64be( stco, p_stream->entry[i].i_pos );
1373         else
1374             bo_add_32be( stco, p_stream->entry[i].i_pos );
1375
1376         while( i < p_stream->i_entry_count )
1377         {
1378             if( i + 1 < p_stream->i_entry_count &&
1379                 p_stream->entry[i].i_pos + p_stream->entry[i].i_size
1380                 != p_stream->entry[i + 1].i_pos )
1381             {
1382                 i++;
1383                 break;
1384             }
1385
1386             i++;
1387         }
1388
1389         /* Add entry to the stsc table */
1390         if( i_stsc_last_val != i - i_first )
1391         {
1392             bo_add_32be( stsc, 1 + i_chunk );   // first-chunk
1393             bo_add_32be( stsc, i - i_first ) ;  // samples-per-chunk
1394             bo_add_32be( stsc, 1 );             // sample-descr-index
1395             i_stsc_last_val = i - i_first;
1396             i_stsc_entries++;
1397         }
1398     }
1399
1400     /* Fix stco entry count */
1401     bo_fix_32be( stco, 12, i_chunk );
1402     msg_Dbg( p_mux, "created %d chunks (stco)", i_chunk );
1403     box_fix( stco );
1404
1405     /* Fix stsc entry count */
1406     bo_fix_32be( stsc, 12, i_stsc_entries  );
1407     box_fix( stsc );
1408
1409     /* add stts */
1410     stts = box_full_new( "stts", 0, 0 );
1411     bo_add_32be( stts, 0 );     // entry-count (fixed latter)
1412
1413     if( p_stream->fmt.i_cat == AUDIO_ES )
1414         i_timescale = p_stream->fmt.audio.i_rate;
1415     else
1416         i_timescale = 1001;
1417
1418     /* first, create quantified length */
1419     for( i = 0, i_dts = 0, i_dts_q = 0; i < p_stream->i_entry_count; i++ )
1420     {
1421         int64_t i_dts_deq = i_dts_q * I64C(1000000) / (int64_t)i_timescale;
1422         int64_t i_delta = p_stream->entry[i].i_length + i_dts - i_dts_deq;
1423
1424         i_dts += p_stream->entry[i].i_length;
1425
1426         p_stream->entry[i].i_length =
1427             i_delta * (int64_t)i_timescale / I64C(1000000);
1428
1429         i_dts_q += p_stream->entry[i].i_length;
1430     }
1431     /* then write encoded table */
1432     for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
1433     {
1434         int     i_first = i;
1435         int64_t i_delta = p_stream->entry[i].i_length;
1436
1437         while( i < p_stream->i_entry_count )
1438         {
1439             i++;
1440             if( i >= p_stream->i_entry_count ||
1441                 p_stream->entry[i].i_length != i_delta )
1442             {
1443                 break;
1444             }
1445         }
1446
1447         bo_add_32be( stts, i - i_first ); // sample-count
1448         bo_add_32be( stts, i_delta );     // sample-delta
1449     }
1450     bo_fix_32be( stts, 12, i_index );
1451     box_fix( stts );
1452
1453     /* FIXME add ctts ?? FIXME */
1454
1455     stsz = box_full_new( "stsz", 0, 0 );
1456     bo_add_32be( stsz, 0 );                             // sample-size
1457     bo_add_32be( stsz, p_stream->i_entry_count );       // sample-count
1458     for( i = 0; i < p_stream->i_entry_count; i++ )
1459     {
1460         bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
1461     }
1462     box_fix( stsz );
1463
1464     /* create stss table */
1465     stss = NULL;
1466     for( i = 0, i_index = 0; i < p_stream->i_entry_count; i++ )
1467     {
1468         if( p_stream->entry[i].i_flags & BLOCK_FLAG_TYPE_I )
1469         {
1470             if( stss == NULL )
1471             {
1472                 stss = box_full_new( "stss", 0, 0 );
1473                 bo_add_32be( stss, 0 ); /* fixed later */
1474             }
1475             bo_add_32be( stss, 1 + i );
1476             i_index++;
1477         }
1478     }
1479     if( stss )
1480     {
1481         bo_fix_32be( stss, 12, i_index );
1482         box_fix( stss );
1483     }
1484
1485     /* Now gather all boxes into stbl */
1486     box_gather( stbl, stsd );
1487     box_gather( stbl, stts );
1488     if( stss )
1489     {
1490         box_gather( stbl, stss );
1491     }
1492     box_gather( stbl, stsc );
1493     box_gather( stbl, stsz );
1494     p_stream->i_stco_pos = stbl->i_buffer + 16;
1495     box_gather( stbl, stco );
1496
1497     /* finish stbl */
1498     box_fix( stbl );
1499
1500     return stbl;
1501 }
1502
1503 static int64_t get_timestamp();
1504
1505 static uint32_t mvhd_matrix[9] =
1506     { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
1507
1508 static bo_t *GetMoovBox( sout_mux_t *p_mux )
1509 {
1510     sout_mux_sys_t *p_sys = p_mux->p_sys;
1511
1512     bo_t            *moov, *mvhd;
1513     int             i_trak, i;
1514
1515     uint32_t        i_movie_timescale = 90000;
1516     int64_t         i_movie_duration  = 0;
1517
1518     moov = box_new( "moov" );
1519
1520     /* Create general info */
1521     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1522     {
1523         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1524         i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration );
1525     }
1526     msg_Dbg( p_mux, "movie duration %ds",
1527              (uint32_t)( i_movie_duration / (mtime_t)1000000 ) );
1528
1529     i_movie_duration = i_movie_duration * i_movie_timescale / 1000000;
1530
1531     /* *** add /moov/mvhd *** */
1532     if( !p_sys->b_64_ext )
1533     {
1534         mvhd = box_full_new( "mvhd", 0, 0 );
1535         bo_add_32be( mvhd, get_timestamp() );   // creation time
1536         bo_add_32be( mvhd, get_timestamp() );   // modification time
1537         bo_add_32be( mvhd, i_movie_timescale);  // timescale
1538         bo_add_32be( mvhd, i_movie_duration );  // duration
1539     }
1540     else
1541     {
1542         mvhd = box_full_new( "mvhd", 1, 0 );
1543         bo_add_64be( mvhd, get_timestamp() );   // creation time
1544         bo_add_64be( mvhd, get_timestamp() );   // modification time
1545         bo_add_32be( mvhd, i_movie_timescale);  // timescale
1546         bo_add_64be( mvhd, i_movie_duration );  // duration
1547     }
1548     bo_add_32be( mvhd, 0x10000 );           // rate
1549     bo_add_16be( mvhd, 0x100 );             // volume
1550     bo_add_16be( mvhd, 0 );                 // reserved
1551     for( i = 0; i < 2; i++ )
1552     {
1553         bo_add_32be( mvhd, 0 );             // reserved
1554     }
1555     for( i = 0; i < 9; i++ )
1556     {
1557         bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
1558     }
1559     for( i = 0; i < 6; i++ )
1560     {
1561         bo_add_32be( mvhd, 0 );             // pre-defined
1562     }
1563
1564     /* Next available track id */
1565     bo_add_32be( mvhd, p_sys->i_nb_streams + 1 ); // next-track-id
1566
1567     box_fix( mvhd );
1568     box_gather( moov, mvhd );
1569
1570     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1571     {
1572         mp4_stream_t *p_stream;
1573         uint32_t     i_timescale;
1574
1575         bo_t *trak, *tkhd, *edts, *elst, *mdia, *mdhd, *hdlr;
1576         bo_t *minf, *dinf, *dref, *url, *stbl;
1577
1578         p_stream = p_sys->pp_streams[i_trak];
1579
1580         if( p_stream->fmt.i_cat == AUDIO_ES )
1581             i_timescale = p_stream->fmt.audio.i_rate;
1582         else
1583             i_timescale = 1001;
1584
1585         /* *** add /moov/trak *** */
1586         trak = box_new( "trak" );
1587
1588         /* *** add /moov/trak/tkhd *** */
1589         if( !p_sys->b_64_ext )
1590         {
1591             if( p_sys->b_mov )
1592                 tkhd = box_full_new( "tkhd", 0, 0x0f );
1593             else
1594                 tkhd = box_full_new( "tkhd", 0, 1 );
1595
1596             bo_add_32be( tkhd, get_timestamp() );       // creation time
1597             bo_add_32be( tkhd, get_timestamp() );       // modification time
1598             bo_add_32be( tkhd, p_stream->i_track_id );
1599             bo_add_32be( tkhd, 0 );                     // reserved 0
1600             bo_add_32be( tkhd, p_stream->i_duration *
1601                          (int64_t)i_movie_timescale /
1602                          (mtime_t)1000000 );            // duration
1603         }
1604         else
1605         {
1606             if( p_sys->b_mov )
1607                 tkhd = box_full_new( "tkhd", 1, 0x0f );
1608             else
1609                 tkhd = box_full_new( "tkhd", 1, 1 );
1610
1611             bo_add_64be( tkhd, get_timestamp() );       // creation time
1612             bo_add_64be( tkhd, get_timestamp() );       // modification time
1613             bo_add_32be( tkhd, p_stream->i_track_id );
1614             bo_add_32be( tkhd, 0 );                     // reserved 0
1615             bo_add_64be( tkhd, p_stream->i_duration *
1616                          (int64_t)i_movie_timescale /
1617                          (mtime_t)1000000 );            // duration
1618         }
1619
1620         for( i = 0; i < 2; i++ )
1621         {
1622             bo_add_32be( tkhd, 0 );                 // reserved
1623         }
1624         bo_add_16be( tkhd, 0 );                     // layer
1625         bo_add_16be( tkhd, 0 );                     // pre-defined
1626         // volume
1627         bo_add_16be( tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0 );
1628         bo_add_16be( tkhd, 0 );                     // reserved
1629         for( i = 0; i < 9; i++ )
1630         {
1631             bo_add_32be( tkhd, mvhd_matrix[i] );    // matrix
1632         }
1633         if( p_stream->fmt.i_cat == AUDIO_ES )
1634         {
1635             bo_add_32be( tkhd, 0 );                 // width (presentation)
1636             bo_add_32be( tkhd, 0 );                 // height(presentation)
1637         }
1638         else if( p_stream->fmt.i_cat == VIDEO_ES )
1639         {
1640             int i_width = p_stream->fmt.video.i_width << 16;
1641             if( p_stream->fmt.video.i_aspect > 0 )
1642             {
1643                 i_width = (int64_t)p_stream->fmt.video.i_aspect *
1644                           ((int64_t)p_stream->fmt.video.i_height << 16) /
1645                           VOUT_ASPECT_FACTOR;
1646             }
1647             // width (presentation)
1648             bo_add_32be( tkhd, i_width );
1649             // height(presentation)
1650             bo_add_32be( tkhd, p_stream->fmt.video.i_height << 16 );
1651         }
1652         else
1653         {
1654             int i_width = 320 << 16;
1655             int i_height = 200;
1656             int i;
1657             for( i = 0; i < p_sys->i_nb_streams; i++ )
1658             {
1659                 mp4_stream_t *tk = p_sys->pp_streams[i];
1660                 if( tk->fmt.i_cat == VIDEO_ES )
1661                 {
1662                     if( p_stream->fmt.video.i_aspect )
1663                         i_width = (int64_t)p_stream->fmt.video.i_aspect *
1664                                    ((int64_t)p_stream->fmt.video.i_height<<16) / VOUT_ASPECT_FACTOR;
1665                     else
1666                         i_width = p_stream->fmt.video.i_width << 16;
1667                     i_height = p_stream->fmt.video.i_height;
1668                     break;
1669                 }
1670             }
1671             bo_add_32be( tkhd, i_width );     // width (presentation)
1672             bo_add_32be( tkhd, i_height << 16 );    // height(presentation)
1673         }
1674
1675         box_fix( tkhd );
1676         box_gather( trak, tkhd );
1677
1678         /* *** add /moov/trak/edts and elst */
1679         edts = box_new( "edts" );
1680         elst = box_full_new( "elst", p_sys->b_64_ext ? 1 : 0, 0 );
1681         if( p_stream->i_dts_start > p_sys->i_dts_start )
1682         {
1683             bo_add_32be( elst, 2 );
1684
1685             if( p_sys->b_64_ext )
1686             {
1687                 bo_add_64be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
1688                              i_movie_timescale / I64C(1000000) );
1689                 bo_add_64be( elst, -1 );
1690             }
1691             else
1692             {
1693                 bo_add_32be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
1694                              i_movie_timescale / I64C(1000000) );
1695                 bo_add_32be( elst, -1 );
1696             }
1697             bo_add_16be( elst, 1 );
1698             bo_add_16be( elst, 0 );
1699         }
1700         else
1701         {
1702             bo_add_32be( elst, 1 );
1703         }
1704         if( p_sys->b_64_ext )
1705         {
1706             bo_add_64be( elst, p_stream->i_duration *
1707                          i_movie_timescale / I64C(1000000) );
1708             bo_add_64be( elst, 0 );
1709         }
1710         else
1711         {
1712             bo_add_32be( elst, p_stream->i_duration *
1713                          i_movie_timescale / I64C(1000000) );
1714             bo_add_32be( elst, 0 );
1715         }
1716         bo_add_16be( elst, 1 );
1717         bo_add_16be( elst, 0 );
1718
1719         box_fix( elst );
1720         box_gather( edts, elst );
1721         box_fix( edts );
1722         box_gather( trak, edts );
1723
1724         /* *** add /moov/trak/mdia *** */
1725         mdia = box_new( "mdia" );
1726
1727         /* media header */
1728         if( !p_sys->b_64_ext )
1729         {
1730             mdhd = box_full_new( "mdhd", 0, 0 );
1731             bo_add_32be( mdhd, get_timestamp() );   // creation time
1732             bo_add_32be( mdhd, get_timestamp() );   // modification time
1733             bo_add_32be( mdhd, i_timescale);        // timescale
1734             bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
1735                                (mtime_t)1000000 );  // duration
1736         }
1737         else
1738         {
1739             mdhd = box_full_new( "mdhd", 1, 0 );
1740             bo_add_64be( mdhd, get_timestamp() );   // creation time
1741             bo_add_64be( mdhd, get_timestamp() );   // modification time
1742             bo_add_32be( mdhd, i_timescale);        // timescale
1743             bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
1744                                (mtime_t)1000000 );  // duration
1745         }
1746
1747         if( p_stream->fmt.psz_language )
1748         {
1749             char *psz = p_stream->fmt.psz_language;
1750             const iso639_lang_t *pl = NULL;
1751             uint16_t lang = 0x0;
1752
1753             if( strlen( psz ) == 2 )
1754             {
1755                 pl = GetLang_1( psz );
1756             }
1757             else if( strlen( psz ) == 3 )
1758             {
1759                 pl = GetLang_2B( psz );
1760                 if( !strcmp( pl->psz_iso639_1, "??" ) )
1761                 {
1762                     pl = GetLang_2T( psz );
1763                 }
1764             }
1765             if( pl && strcmp( pl->psz_iso639_1, "??" ) )
1766             {
1767                 lang = ( ( pl->psz_iso639_2T[0] - 0x60 ) << 10 ) |
1768                        ( ( pl->psz_iso639_2T[1] - 0x60 ) <<  5 ) |
1769                        ( ( pl->psz_iso639_2T[2] - 0x60 ) );
1770             }
1771             bo_add_16be( mdhd, lang );          // language
1772         }
1773         else
1774         {
1775             bo_add_16be( mdhd, 0    );          // language
1776         }
1777         bo_add_16be( mdhd, 0    );              // predefined
1778         box_fix( mdhd );
1779         box_gather( mdia, mdhd );
1780
1781         /* handler reference */
1782         hdlr = box_full_new( "hdlr", 0, 0 );
1783
1784         if( p_sys->b_mov )
1785             bo_add_fourcc( hdlr, "mhlr" );         // media handler
1786         else
1787             bo_add_32be( hdlr, 0 );
1788
1789         if( p_stream->fmt.i_cat == AUDIO_ES )
1790             bo_add_fourcc( hdlr, "soun" );
1791         else if( p_stream->fmt.i_cat == VIDEO_ES )
1792             bo_add_fourcc( hdlr, "vide" );
1793         else if( p_stream->fmt.i_cat == SPU_ES )
1794             bo_add_fourcc( hdlr, "text" );
1795
1796         bo_add_32be( hdlr, 0 );         // reserved
1797         bo_add_32be( hdlr, 0 );         // reserved
1798         bo_add_32be( hdlr, 0 );         // reserved
1799
1800         if( p_sys->b_mov )
1801             bo_add_8( hdlr, 12 );   /* Pascal string for .mov */
1802
1803         if( p_stream->fmt.i_cat == AUDIO_ES )
1804             bo_add_mem( hdlr, 12, (uint8_t*)"SoundHandler" );
1805         else if( p_stream->fmt.i_cat == VIDEO_ES )
1806             bo_add_mem( hdlr, 12, (uint8_t*)"VideoHandler" );
1807         else
1808             bo_add_mem( hdlr, 12, (uint8_t*)"Text Handler" );
1809
1810         if( !p_sys->b_mov )
1811             bo_add_8( hdlr, 0 );   /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
1812
1813         box_fix( hdlr );
1814         box_gather( mdia, hdlr );
1815
1816         /* minf*/
1817         minf = box_new( "minf" );
1818
1819         /* add smhd|vmhd */
1820         if( p_stream->fmt.i_cat == AUDIO_ES )
1821         {
1822             bo_t *smhd;
1823
1824             smhd = box_full_new( "smhd", 0, 0 );
1825             bo_add_16be( smhd, 0 );     // balance
1826             bo_add_16be( smhd, 0 );     // reserved
1827             box_fix( smhd );
1828
1829             box_gather( minf, smhd );
1830         }
1831         else if( p_stream->fmt.i_cat == VIDEO_ES )
1832         {
1833             bo_t *vmhd;
1834
1835             vmhd = box_full_new( "vmhd", 0, 1 );
1836             bo_add_16be( vmhd, 0 );     // graphicsmode
1837             for( i = 0; i < 3; i++ )
1838             {
1839                 bo_add_16be( vmhd, 0 ); // opcolor
1840             }
1841             box_fix( vmhd );
1842
1843             box_gather( minf, vmhd );
1844         }
1845         else if( p_stream->fmt.i_cat == SPU_ES )
1846         {
1847             bo_t *gmhd = box_new( "gmhd" );
1848             bo_t *gmin = box_full_new( "gmin", 0, 1 );
1849
1850             bo_add_16be( gmin, 0 );     // graphicsmode
1851             for( i = 0; i < 3; i++ )
1852             {
1853                 bo_add_16be( gmin, 0 ); // opcolor
1854             }
1855             bo_add_16be( gmin, 0 );     // balance
1856             bo_add_16be( gmin, 0 );     // reserved
1857             box_fix( gmin );
1858
1859             box_gather( gmhd, gmin );
1860             box_fix( gmhd );
1861
1862             box_gather( minf, gmhd );
1863         }
1864
1865         /* dinf */
1866         dinf = box_new( "dinf" );
1867         dref = box_full_new( "dref", 0, 0 );
1868         bo_add_32be( dref, 1 );
1869         url = box_full_new( "url ", 0, 0x01 );
1870         box_fix( url );
1871         box_gather( dref, url );
1872         box_fix( dref );
1873         box_gather( dinf, dref );
1874
1875         /* append dinf to mdia */
1876         box_fix( dinf );
1877         box_gather( minf, dinf );
1878
1879         /* add stbl */
1880         stbl = GetStblBox( p_mux, p_stream );
1881
1882         /* append stbl to minf */
1883         p_stream->i_stco_pos += minf->i_buffer;
1884         box_gather( minf, stbl );
1885
1886         /* append minf to mdia */
1887         box_fix( minf );
1888         p_stream->i_stco_pos += mdia->i_buffer;
1889         box_gather( mdia, minf );
1890
1891         /* append mdia to trak */
1892         box_fix( mdia );
1893         p_stream->i_stco_pos += trak->i_buffer;
1894         box_gather( trak, mdia );
1895
1896         /* append trak to moov */
1897         box_fix( trak );
1898         p_stream->i_stco_pos += moov->i_buffer;
1899         box_gather( moov, trak );
1900     }
1901
1902     /* Add user data tags */
1903     box_gather( moov, GetUdtaTag( p_mux ) );
1904
1905     box_fix( moov );
1906     return moov;
1907 }
1908
1909 /****************************************************************************/
1910
1911 static void bo_init( bo_t *p_bo, int i_size, uint8_t *p_buffer,
1912                      vlc_bool_t b_grow )
1913 {
1914     if( !p_buffer )
1915     {
1916         p_bo->i_buffer_size = __MAX( i_size, 1024 );
1917         p_bo->p_buffer = malloc( p_bo->i_buffer_size );
1918     }
1919     else
1920     {
1921         p_bo->i_buffer_size = i_size;
1922         p_bo->p_buffer = p_buffer;
1923     }
1924
1925     p_bo->b_grow = b_grow;
1926     p_bo->i_buffer = 0;
1927 }
1928
1929 static void bo_add_8( bo_t *p_bo, uint8_t i )
1930 {
1931     if( p_bo->i_buffer < p_bo->i_buffer_size )
1932     {
1933         p_bo->p_buffer[p_bo->i_buffer] = i;
1934     }
1935     else if( p_bo->b_grow )
1936     {
1937         p_bo->i_buffer_size += 1024;
1938         p_bo->p_buffer = realloc( p_bo->p_buffer, p_bo->i_buffer_size );
1939
1940         p_bo->p_buffer[p_bo->i_buffer] = i;
1941     }
1942
1943     p_bo->i_buffer++;
1944 }
1945
1946 static void bo_add_16be( bo_t *p_bo, uint16_t i )
1947 {
1948     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1949     bo_add_8( p_bo, i &0xff );
1950 }
1951
1952 static void bo_add_24be( bo_t *p_bo, uint32_t i )
1953 {
1954     bo_add_8( p_bo, ( ( i >> 16) &0xff ) );
1955     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1956     bo_add_8( p_bo, (   i &0xff ) );
1957 }
1958 static void bo_add_32be( bo_t *p_bo, uint32_t i )
1959 {
1960     bo_add_16be( p_bo, ( ( i >> 16) &0xffff ) );
1961     bo_add_16be( p_bo, i &0xffff );
1962 }
1963
1964 static void bo_fix_32be ( bo_t *p_bo, int i_pos, uint32_t i)
1965 {
1966     p_bo->p_buffer[i_pos    ] = ( i >> 24 )&0xff;
1967     p_bo->p_buffer[i_pos + 1] = ( i >> 16 )&0xff;
1968     p_bo->p_buffer[i_pos + 2] = ( i >>  8 )&0xff;
1969     p_bo->p_buffer[i_pos + 3] = ( i       )&0xff;
1970 }
1971
1972 static void bo_add_64be( bo_t *p_bo, uint64_t i )
1973 {
1974     bo_add_32be( p_bo, ( ( i >> 32) &0xffffffff ) );
1975     bo_add_32be( p_bo, i &0xffffffff );
1976 }
1977
1978 static void bo_add_fourcc( bo_t *p_bo, char *fcc )
1979 {
1980     bo_add_8( p_bo, fcc[0] );
1981     bo_add_8( p_bo, fcc[1] );
1982     bo_add_8( p_bo, fcc[2] );
1983     bo_add_8( p_bo, fcc[3] );
1984 }
1985
1986 static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem )
1987 {
1988     int i;
1989
1990     for( i = 0; i < i_size; i++ )
1991     {
1992         bo_add_8( p_bo, p_mem[i] );
1993     }
1994 }
1995
1996 static void bo_add_descr( bo_t *p_bo, uint8_t tag, uint32_t i_size )
1997 {
1998     uint32_t i_length;
1999     uint8_t  vals[4];
2000
2001     i_length = i_size;
2002     vals[3] = (unsigned char)(i_length & 0x7f);
2003     i_length >>= 7;
2004     vals[2] = (unsigned char)((i_length & 0x7f) | 0x80); 
2005     i_length >>= 7;
2006     vals[1] = (unsigned char)((i_length & 0x7f) | 0x80); 
2007     i_length >>= 7;
2008     vals[0] = (unsigned char)((i_length & 0x7f) | 0x80);
2009
2010     bo_add_8( p_bo, tag );
2011
2012     if( i_size < 0x00000080 )
2013     {
2014         bo_add_8( p_bo, vals[3] );
2015     }
2016     else if( i_size < 0x00004000 )
2017     {
2018         bo_add_8( p_bo, vals[2] );
2019         bo_add_8( p_bo, vals[3] );
2020     }
2021     else if( i_size < 0x00200000 )
2022     {
2023         bo_add_8( p_bo, vals[1] );
2024         bo_add_8( p_bo, vals[2] );
2025         bo_add_8( p_bo, vals[3] );
2026     }
2027     else if( i_size < 0x10000000 )
2028     {
2029         bo_add_8( p_bo, vals[0] );
2030         bo_add_8( p_bo, vals[1] );
2031         bo_add_8( p_bo, vals[2] );
2032         bo_add_8( p_bo, vals[3] );
2033     }
2034 }
2035
2036 static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
2037 {
2038     int i;
2039
2040     for( i = 0; i < p_bo2->i_buffer; i++ )
2041     {
2042         bo_add_8( p_bo, p_bo2->p_buffer[i] );
2043     }
2044 }
2045
2046 static bo_t * box_new( char *fcc )
2047 {
2048     bo_t *box;
2049
2050     if( ( box = malloc( sizeof( bo_t ) ) ) )
2051     {
2052         bo_init( box, 0, NULL, VLC_TRUE );
2053
2054         bo_add_32be  ( box, 0 );
2055         bo_add_fourcc( box, fcc );
2056     }
2057
2058     return box;
2059 }
2060
2061 static bo_t * box_full_new( char *fcc, uint8_t v, uint32_t f )
2062 {
2063     bo_t *box;
2064
2065     if( ( box = malloc( sizeof( bo_t ) ) ) )
2066     {
2067         bo_init( box, 0, NULL, VLC_TRUE );
2068
2069         bo_add_32be  ( box, 0 );
2070         bo_add_fourcc( box, fcc );
2071         bo_add_8     ( box, v );
2072         bo_add_24be  ( box, f );
2073     }
2074
2075     return box;
2076 }
2077
2078 static void box_fix( bo_t *box )
2079 {
2080     bo_t box_tmp;
2081
2082     memcpy( &box_tmp, box, sizeof( bo_t ) );
2083
2084     box_tmp.i_buffer = 0;
2085     bo_add_32be( &box_tmp, box->i_buffer );
2086 }
2087
2088 static void box_free( bo_t *box )
2089 {
2090     if( box->p_buffer )
2091     {
2092         free( box->p_buffer );
2093     }
2094
2095     free( box );
2096 }
2097
2098 static void box_gather ( bo_t *box, bo_t *box2 )
2099 {
2100     bo_add_bo( box, box2 );
2101     box_free( box2 );
2102 }
2103
2104 static block_t * bo_to_sout( sout_instance_t *p_sout,  bo_t *box )
2105 {
2106     block_t *p_buf;
2107
2108     p_buf = block_New( p_sout, box->i_buffer );
2109     if( box->i_buffer > 0 )
2110     {
2111         memcpy( p_buf->p_buffer, box->p_buffer, box->i_buffer );
2112     }
2113
2114     return p_buf;
2115 }
2116
2117 static void box_send( sout_mux_t *p_mux,  bo_t *box )
2118 {
2119     block_t *p_buf;
2120
2121     p_buf = bo_to_sout( p_mux->p_sout, box );
2122     box_free( box );
2123
2124     sout_AccessOutWrite( p_mux->p_access, p_buf );
2125 }
2126
2127 static int64_t get_timestamp()
2128 {
2129     int64_t i_timestamp = 0;
2130
2131 #ifdef HAVE_TIME_H
2132     i_timestamp = time(NULL);
2133     i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
2134     // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
2135 #endif
2136
2137     return i_timestamp;
2138 }