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