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