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