]> git.sesse.net Git - vlc/blob - modules/mux/mp4.c
Use var_InheritString for --decklink-video-connection.
[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", "mov", "3gp" )
68     set_callbacks( Open, Close )
69 vlc_module_end ()
70
71 /*****************************************************************************
72  * Exported prototypes
73  *****************************************************************************/
74 static const char *const ppsz_sout_options[] = {
75     "faststart", NULL
76 };
77
78 static int Control( sout_mux_t *, int, va_list );
79 static int AddStream( sout_mux_t *, sout_input_t * );
80 static int DelStream( sout_mux_t *, sout_input_t * );
81 static int Mux      ( sout_mux_t * );
82
83 /*****************************************************************************
84  * Local prototypes
85  *****************************************************************************/
86 typedef struct
87 {
88     uint64_t i_pos;
89     int      i_size;
90
91     mtime_t  i_pts_dts;
92     mtime_t  i_length;
93     unsigned int i_flags;
94
95 } mp4_entry_t;
96
97 typedef struct
98 {
99     es_format_t   fmt;
100     int           i_track_id;
101
102     /* index */
103     unsigned int i_entry_count;
104     unsigned int i_entry_max;
105     mp4_entry_t  *entry;
106     int64_t      i_length_neg;
107
108     /* stats */
109     int64_t      i_dts_start;
110     int64_t      i_duration;
111
112     /* for later stco fix-up (fast start files) */
113     uint64_t i_stco_pos;
114     bool b_stco64;
115
116     /* for spu */
117     int64_t i_last_dts;
118
119 } mp4_stream_t;
120
121 struct sout_mux_sys_t
122 {
123     bool b_mov;
124     bool b_3gp;
125     bool b_64_ext;
126     bool b_fast_start;
127
128     uint64_t i_mdat_pos;
129     uint64_t i_pos;
130
131     int64_t  i_dts_start;
132
133     int          i_nb_streams;
134     mp4_stream_t **pp_streams;
135 };
136
137 typedef struct bo_t
138 {
139     bool b_grow;
140
141     int        i_buffer_size;
142     int        i_buffer;
143     uint8_t    *p_buffer;
144
145 } bo_t;
146
147 static void bo_init     ( bo_t *, int , uint8_t *, bool  );
148 static void bo_add_8    ( bo_t *, uint8_t );
149 static void bo_add_16be ( bo_t *, uint16_t );
150 static void bo_add_24be ( bo_t *, uint32_t );
151 static void bo_add_32be ( bo_t *, uint32_t );
152 static void bo_add_64be ( bo_t *, uint64_t );
153 static void bo_add_fourcc(bo_t *, const char * );
154 static void bo_add_bo   ( bo_t *, bo_t * );
155 static void bo_add_mem  ( bo_t *, int , uint8_t * );
156 static void bo_add_descr( bo_t *, uint8_t , uint32_t );
157
158 static void bo_fix_32be ( bo_t *, int , uint32_t );
159
160 static bo_t *box_new     ( const char *fcc );
161 static bo_t *box_full_new( const char *fcc, uint8_t v, uint32_t f );
162 static void  box_fix     ( bo_t *box );
163 static void  box_free    ( bo_t *box );
164 static void  box_gather  ( bo_t *box, bo_t *box2 );
165
166 static void box_send( sout_mux_t *p_mux,  bo_t *box );
167
168 static block_t *bo_to_sout( sout_instance_t *p_sout,  bo_t *box );
169
170 static bo_t *GetMoovBox( sout_mux_t *p_mux );
171
172 static block_t *ConvertSUBT( block_t *);
173 static block_t *ConvertAVC1( block_t * );
174
175 /*****************************************************************************
176  * Open:
177  *****************************************************************************/
178 static int Open( vlc_object_t *p_this )
179 {
180     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
181     sout_mux_sys_t  *p_sys;
182     bo_t            *box;
183
184     msg_Dbg( p_mux, "Mp4 muxer opened" );
185     config_ChainParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
186
187     p_mux->pf_control   = Control;
188     p_mux->pf_addstream = AddStream;
189     p_mux->pf_delstream = DelStream;
190     p_mux->pf_mux       = Mux;
191     p_mux->p_sys        = p_sys = malloc( sizeof( sout_mux_sys_t ) );
192     if( !p_sys )
193         return VLC_ENOMEM;
194     p_sys->i_pos        = 0;
195     p_sys->i_nb_streams = 0;
196     p_sys->pp_streams   = NULL;
197     p_sys->i_mdat_pos   = 0;
198     p_sys->b_mov        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" );
199     p_sys->b_3gp        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "3gp" );
200     p_sys->i_dts_start  = 0;
201
202
203     if( !p_sys->b_mov )
204     {
205         /* Now add ftyp header */
206         box = box_new( "ftyp" );
207         if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp6" );
208         else bo_add_fourcc( box, "isom" );
209         bo_add_32be  ( box, 0 );
210         if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
211         else bo_add_fourcc( box, "mp41" );
212         bo_add_fourcc( box, "avc1" );
213         bo_add_fourcc( box, "qt  " );
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_stream->i_last_dts - p_stream->i_dts_start + 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 > 3 )
879         {
880             /* seek startcode */
881             while( p_buffer[0] != 0 || p_buffer[1] != 0 ||
882                    p_buffer[2] != 1 )
883             {
884                  i_buffer--;
885                  p_buffer++;
886             }
887             const int i_nal_type = p_buffer[3]&0x1f;
888             int i_offset    = 1;
889             int i_size      = 0;
890             int i_startcode = 0;
891  
892  
893             for( i_offset = 1; i_offset+2 < i_buffer ; i_offset++)
894             {
895                 if( p_buffer[i_offset] == 0 && p_buffer[i_offset+1] == 0 &&
896                     p_buffer[i_offset+2] == 1 )
897                 {
898                     /* we found another startcode */
899                     i_startcode = i_offset;
900                     while( p_buffer[i_startcode-1] == 0 && i_startcode > 0 )
901                         i_startcode--;
902                     break;
903                 }
904             }
905             i_size = i_startcode ? i_startcode : i_buffer;
906
907             if( i_nal_type == 7 )
908             {
909                 p_sps = &p_buffer[3];
910                 i_sps_size = i_size - 3;
911             }
912             if( i_nal_type == 8 )
913             {
914                 p_pps = &p_buffer[3];
915                 i_pps_size = i_size - 3;
916             }
917             i_buffer -= i_size;
918             p_buffer += i_size;
919         }
920     }
921  
922     /* FIXME use better value */
923     avcC = box_new( "avcC" );
924     bo_add_8( avcC, 1 );      /* configuration version */
925     bo_add_8( avcC, i_sps_size ? p_sps[1] : 77 );
926     bo_add_8( avcC, i_sps_size ? p_sps[2] : 64 );
927     bo_add_8( avcC, i_sps_size ? p_sps[3] : 30 );       /* level, 5.1 */
928     bo_add_8( avcC, 0xff );   /* 0b11111100 | lengthsize = 0x11 */
929
930     bo_add_8( avcC, 0xe0 | (i_sps_size > 0 ? 1 : 0) );   /* 0b11100000 | sps_count */
931     if( i_sps_size > 0 )
932     {
933         bo_add_16be( avcC, i_sps_size );
934         bo_add_mem( avcC, i_sps_size, p_sps );
935     }
936
937     bo_add_8( avcC, (i_pps_size > 0 ? 1 : 0) );   /* pps_count */
938     if( i_pps_size > 0 )
939     {
940         bo_add_16be( avcC, i_pps_size );
941         bo_add_mem( avcC, i_pps_size, p_pps );
942     }
943     box_fix( avcC );
944
945     return avcC;
946 }
947
948 /* TODO: No idea about these values */
949 static bo_t *GetSVQ3Tag( mp4_stream_t *p_stream )
950 {
951     bo_t *smi = box_new( "SMI " );
952
953     if( p_stream->fmt.i_extra > 0x4e )
954     {
955         uint8_t *p_end = &((uint8_t*)p_stream->fmt.p_extra)[p_stream->fmt.i_extra];
956         uint8_t *p     = &((uint8_t*)p_stream->fmt.p_extra)[0x46];
957
958         while( p + 8 < p_end )
959         {
960             int i_size = GetDWBE( p );
961             if( i_size <= 1 )
962             {
963                 /* FIXME handle 1 as long size */
964                 break;
965             }
966             if( !strncmp( (const char *)&p[4], "SMI ", 4 ) )
967             {
968                 bo_add_mem( smi, p_end - p - 8, &p[8] );
969                 return smi;
970             }
971             p += i_size;
972         }
973     }
974
975     /* Create a dummy one in fallback */
976     bo_add_fourcc( smi, "SEQH" );
977     bo_add_32be( smi, 0x5 );
978     bo_add_32be( smi, 0xe2c0211d );
979     bo_add_8( smi, 0xc0 );
980     box_fix( smi );
981
982     return smi;
983 }
984
985 static bo_t *GetUdtaTag( sout_mux_t *p_mux )
986 {
987     sout_mux_sys_t *p_sys = p_mux->p_sys;
988     bo_t *udta = box_new( "udta" );
989     vlc_meta_t *p_meta = p_mux->p_sout->p_meta;
990     int i_track;
991
992     /* Requirements */
993     for( i_track = 0; i_track < p_sys->i_nb_streams; i_track++ )
994     {
995         mp4_stream_t *p_stream = p_sys->pp_streams[i_track];
996
997         if( p_stream->fmt.i_codec == VLC_CODEC_MP4V ||
998             p_stream->fmt.i_codec == VLC_CODEC_MP4A )
999         {
1000             bo_t *box = box_new( "\251req" );
1001             /* String length */
1002             bo_add_16be( box, sizeof("QuickTime 6.0 or greater") - 1);
1003             bo_add_16be( box, 0 );
1004             bo_add_mem( box, sizeof("QuickTime 6.0 or greater") - 1,
1005                         (uint8_t *)"QuickTime 6.0 or greater" );
1006             box_fix( box );
1007             box_gather( udta, box );
1008             break;
1009         }
1010     }
1011
1012     /* Encoder */
1013     {
1014         bo_t *box = box_new( "\251enc" );
1015         /* String length */
1016         bo_add_16be( box, sizeof(PACKAGE_STRING " stream output") - 1);
1017         bo_add_16be( box, 0 );
1018         bo_add_mem( box, sizeof(PACKAGE_STRING " stream output") - 1,
1019                     (uint8_t*)PACKAGE_STRING " stream output" );
1020         box_fix( box );
1021         box_gather( udta, box );
1022     }
1023
1024     /* Misc atoms */
1025     if( p_meta )
1026     {
1027 #define ADD_META_BOX( type, box_string ) { \
1028         bo_t *box = NULL;  \
1029         if( vlc_meta_Get( p_meta, vlc_meta_##type ) ) box = box_new( "\251" box_string ); \
1030         if( box ) \
1031         { \
1032             bo_add_16be( box, strlen( vlc_meta_Get( p_meta, vlc_meta_##type ) )); \
1033             bo_add_16be( box, 0 ); \
1034             bo_add_mem( box, strlen( vlc_meta_Get( p_meta, vlc_meta_##type ) ), \
1035                         (uint8_t*)(vlc_meta_Get( p_meta, vlc_meta_##type ) ) ); \
1036             box_fix( box ); \
1037             box_gather( udta, box ); \
1038         } }
1039
1040         ADD_META_BOX( Title, "nam" );
1041         ADD_META_BOX( Artist, "ART" );
1042         ADD_META_BOX( Genre, "gen" );
1043         ADD_META_BOX( Copyright, "cpy" );
1044         ADD_META_BOX( Description, "des" );
1045         ADD_META_BOX( Date, "day" );
1046         ADD_META_BOX( URL, "url" );
1047 #undef ADD_META_BOX
1048     }
1049
1050     box_fix( udta );
1051     return udta;
1052 }
1053
1054 static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
1055 {
1056     sout_mux_sys_t *p_sys = p_mux->p_sys;
1057     bool b_descr = false;
1058     bo_t *soun;
1059     char fcc[4] = "    ";
1060     int  i;
1061
1062     switch( p_stream->fmt.i_codec )
1063     {
1064     case VLC_CODEC_MP4A:
1065         memcpy( fcc, "mp4a", 4 );
1066         b_descr = true;
1067         break;
1068
1069     case VLC_CODEC_AMR_NB:
1070     case VLC_CODEC_AMR_WB:
1071         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1072         b_descr = true;
1073         break;
1074
1075     case VLC_CODEC_MPGA:
1076         if( p_sys->b_mov )
1077             memcpy( fcc, ".mp3", 4 );
1078         else
1079         {
1080             memcpy( fcc, "mp4a", 4 );
1081             b_descr = true;
1082         }
1083         break;
1084
1085     default:
1086         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1087         break;
1088     }
1089
1090     soun = box_new( fcc );
1091     for( i = 0; i < 6; i++ )
1092     {
1093         bo_add_8( soun, 0 );        // reserved;
1094     }
1095     bo_add_16be( soun, 1 );         // data-reference-index
1096
1097     /* SoundDescription */
1098     if( p_sys->b_mov &&
1099         p_stream->fmt.i_codec == VLC_CODEC_MP4A )
1100     {
1101         bo_add_16be( soun, 1 );     // version 1;
1102     }
1103     else
1104     {
1105         bo_add_16be( soun, 0 );     // version 0;
1106     }
1107     bo_add_16be( soun, 0 );         // revision level (0)
1108     bo_add_32be( soun, 0 );         // vendor
1109     // channel-count
1110     bo_add_16be( soun, p_stream->fmt.audio.i_channels );
1111     // sample size
1112     bo_add_16be( soun, p_stream->fmt.audio.i_bitspersample ?
1113                  p_stream->fmt.audio.i_bitspersample : 16 );
1114     bo_add_16be( soun, -2 );        // compression id
1115     bo_add_16be( soun, 0 );         // packet size (0)
1116     bo_add_16be( soun, p_stream->fmt.audio.i_rate ); // sampleratehi
1117     bo_add_16be( soun, 0 );                             // sampleratelo
1118
1119     /* Extended data for SoundDescription V1 */
1120     if( p_sys->b_mov &&
1121         p_stream->fmt.i_codec == VLC_CODEC_MP4A )
1122     {
1123         /* samples per packet */
1124         bo_add_32be( soun, p_stream->fmt.audio.i_frame_length );
1125         bo_add_32be( soun, 1536 ); /* bytes per packet */
1126         bo_add_32be( soun, 2 );    /* bytes per frame */
1127         /* bytes per sample */
1128         bo_add_32be( soun, 2 /*p_stream->fmt.audio.i_bitspersample/8 */);
1129     }
1130
1131     /* Add an ES Descriptor */
1132     if( b_descr )
1133     {
1134         bo_t *box;
1135
1136         if( p_sys->b_mov &&
1137             p_stream->fmt.i_codec == VLC_CODEC_MP4A )
1138         {
1139             box = GetWaveTag( p_stream );
1140         }
1141         else if( p_stream->fmt.i_codec == VLC_CODEC_AMR_NB )
1142         {
1143             box = GetDamrTag( p_stream );
1144         }
1145         else
1146         {
1147             box = GetESDS( p_stream );
1148         }
1149         box_fix( box );
1150         box_gather( soun, box );
1151     }
1152
1153     box_fix( soun );
1154
1155     return soun;
1156 }
1157
1158 static bo_t *GetVideBox( mp4_stream_t *p_stream )
1159 {
1160
1161     bo_t *vide;
1162     char fcc[4] = "    ";
1163     int  i;
1164
1165     switch( p_stream->fmt.i_codec )
1166     {
1167     case VLC_CODEC_MP4V:
1168     case VLC_CODEC_MPGV:
1169         memcpy( fcc, "mp4v", 4 );
1170         break;
1171
1172     case VLC_CODEC_MJPG:
1173         memcpy( fcc, "mjpa", 4 );
1174         break;
1175
1176     case VLC_CODEC_SVQ1:
1177         memcpy( fcc, "SVQ1", 4 );
1178         break;
1179
1180     case VLC_CODEC_SVQ3:
1181         memcpy( fcc, "SVQ3", 4 );
1182         break;
1183
1184     case VLC_CODEC_H263:
1185         memcpy( fcc, "s263", 4 );
1186         break;
1187
1188     case VLC_CODEC_H264:
1189         memcpy( fcc, "avc1", 4 );
1190         break;
1191
1192     case VLC_CODEC_YV12:
1193         memcpy( fcc, "yv12", 4 );
1194         break;
1195
1196     case VLC_CODEC_YUYV:
1197         memcpy( fcc, "yuy2", 4 );
1198         break;
1199
1200     default:
1201         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
1202         break;
1203     }
1204
1205     vide = box_new( fcc );
1206     for( i = 0; i < 6; i++ )
1207     {
1208         bo_add_8( vide, 0 );        // reserved;
1209     }
1210     bo_add_16be( vide, 1 );         // data-reference-index
1211
1212     bo_add_16be( vide, 0 );         // predefined;
1213     bo_add_16be( vide, 0 );         // reserved;
1214     for( i = 0; i < 3; i++ )
1215     {
1216         bo_add_32be( vide, 0 );     // predefined;
1217     }
1218
1219     bo_add_16be( vide, p_stream->fmt.video.i_width );  // i_width
1220     bo_add_16be( vide, p_stream->fmt.video.i_height ); // i_height
1221
1222     bo_add_32be( vide, 0x00480000 );                // h 72dpi
1223     bo_add_32be( vide, 0x00480000 );                // v 72dpi
1224
1225     bo_add_32be( vide, 0 );         // data size, always 0
1226     bo_add_16be( vide, 1 );         // frames count per sample
1227
1228     // compressor name;
1229     for( i = 0; i < 32; i++ )
1230     {
1231         bo_add_8( vide, 0 );
1232     }
1233
1234     bo_add_16be( vide, 0x18 );      // depth
1235     bo_add_16be( vide, 0xffff );    // predefined
1236
1237     /* add an ES Descriptor */
1238     switch( p_stream->fmt.i_codec )
1239     {
1240     case VLC_CODEC_MP4V:
1241     case VLC_CODEC_MPGV:
1242         {
1243             bo_t *esds = GetESDS( p_stream );
1244
1245             box_fix( esds );
1246             box_gather( vide, esds );
1247         }
1248         break;
1249
1250     case VLC_CODEC_H263:
1251         {
1252             bo_t *d263 = GetD263Tag();
1253
1254             box_fix( d263 );
1255             box_gather( vide, d263 );
1256         }
1257         break;
1258
1259     case VLC_CODEC_SVQ3:
1260         {
1261             bo_t *esds = GetSVQ3Tag( p_stream );
1262
1263             box_fix( esds );
1264             box_gather( vide, esds );
1265         }
1266         break;
1267
1268     case VLC_CODEC_H264:
1269         box_gather( vide, GetAvcCTag( p_stream ) );
1270         break;
1271
1272     default:
1273         break;
1274     }
1275
1276     box_fix( vide );
1277
1278     return vide;
1279 }
1280
1281 static bo_t *GetTextBox( void )
1282 {
1283
1284     bo_t *text = box_new( "text" );
1285     int  i;
1286
1287     for( i = 0; i < 6; i++ )
1288     {
1289         bo_add_8( text, 0 );        // reserved;
1290     }
1291     bo_add_16be( text, 1 );         // data-reference-index
1292
1293     bo_add_32be( text, 0 );         // display flags
1294     bo_add_32be( text, 0 );         // justification
1295     for( i = 0; i < 3; i++ )
1296     {
1297         bo_add_16be( text, 0 );     // back ground color
1298     }
1299
1300     bo_add_16be( text, 0 );         // box text
1301     bo_add_16be( text, 0 );         // box text
1302     bo_add_16be( text, 0 );         // box text
1303     bo_add_16be( text, 0 );         // box text
1304
1305     bo_add_64be( text, 0 );         // reserved
1306     for( i = 0; i < 3; i++ )
1307     {
1308         bo_add_16be( text, 0xff );  // foreground color
1309     }
1310
1311     bo_add_8 ( text, 9 );
1312     bo_add_mem( text, 9, (uint8_t*)"Helvetica" );
1313
1314     box_fix( text );
1315
1316     return text;
1317 }
1318
1319 static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
1320 {
1321     sout_mux_sys_t *p_sys = p_mux->p_sys;
1322     unsigned int i_chunk, i_stsc_last_val, i_stsc_entries, i, i_index;
1323     bo_t *stbl, *stsd, *stts, *stco, *stsc, *stsz, *stss;
1324     uint32_t i_timescale;
1325     int64_t i_dts, i_dts_q;
1326
1327     stbl = box_new( "stbl" );
1328
1329     /* sample description */
1330     stsd = box_full_new( "stsd", 0, 0 );
1331     bo_add_32be( stsd, 1 );
1332     if( p_stream->fmt.i_cat == AUDIO_ES )
1333     {
1334         bo_t *soun = GetSounBox( p_mux, p_stream );
1335         box_gather( stsd, soun );
1336     }
1337     else if( p_stream->fmt.i_cat == VIDEO_ES )
1338     {
1339         bo_t *vide = GetVideBox( p_stream );
1340         box_gather( stsd, vide );
1341     }
1342     else if( p_stream->fmt.i_cat == SPU_ES )
1343     {
1344         box_gather( stsd, GetTextBox() );
1345     }
1346     box_fix( stsd );
1347
1348     /* chunk offset table */
1349     if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
1350     {
1351         /* 64 bits version */
1352         p_stream->b_stco64 = true;
1353         stco = box_full_new( "co64", 0, 0 );
1354     }
1355     else
1356     {
1357         /* 32 bits version */
1358         p_stream->b_stco64 = false;
1359         stco = box_full_new( "stco", 0, 0 );
1360     }
1361     bo_add_32be( stco, 0 );     // entry-count (fixed latter)
1362
1363     /* sample to chunk table */
1364     stsc = box_full_new( "stsc", 0, 0 );
1365     bo_add_32be( stsc, 0 );     // entry-count (fixed latter)
1366
1367     for( i_chunk = 0, i_stsc_last_val = 0, i_stsc_entries = 0, i = 0;
1368          i < p_stream->i_entry_count; i_chunk++ )
1369     {
1370         int i_first = i;
1371
1372         if( p_stream->b_stco64 )
1373             bo_add_64be( stco, p_stream->entry[i].i_pos );
1374         else
1375             bo_add_32be( stco, p_stream->entry[i].i_pos );
1376
1377         while( i < p_stream->i_entry_count )
1378         {
1379             if( i + 1 < p_stream->i_entry_count &&
1380                 p_stream->entry[i].i_pos + p_stream->entry[i].i_size
1381                 != p_stream->entry[i + 1].i_pos )
1382             {
1383                 i++;
1384                 break;
1385             }
1386
1387             i++;
1388         }
1389
1390         /* Add entry to the stsc table */
1391         if( i_stsc_last_val != i - i_first )
1392         {
1393             bo_add_32be( stsc, 1 + i_chunk );   // first-chunk
1394             bo_add_32be( stsc, i - i_first ) ;  // samples-per-chunk
1395             bo_add_32be( stsc, 1 );             // sample-descr-index
1396             i_stsc_last_val = i - i_first;
1397             i_stsc_entries++;
1398         }
1399     }
1400
1401     /* Fix stco entry count */
1402     bo_fix_32be( stco, 12, i_chunk );
1403     msg_Dbg( p_mux, "created %d chunks (stco)", i_chunk );
1404     box_fix( stco );
1405
1406     /* Fix stsc entry count */
1407     bo_fix_32be( stsc, 12, i_stsc_entries  );
1408     box_fix( stsc );
1409
1410     /* add stts */
1411     stts = box_full_new( "stts", 0, 0 );
1412     bo_add_32be( stts, 0 );     // entry-count (fixed latter)
1413
1414     if( p_stream->fmt.i_cat == AUDIO_ES )
1415         i_timescale = p_stream->fmt.audio.i_rate;
1416     else
1417         i_timescale = 1001;
1418
1419     /* first, create quantified length */
1420     for( i = 0, i_dts = 0, i_dts_q = 0; i < p_stream->i_entry_count; i++ )
1421     {
1422         int64_t i_dts_deq = i_dts_q * INT64_C(1000000) / (int64_t)i_timescale;
1423         int64_t i_delta = p_stream->entry[i].i_length + i_dts - i_dts_deq;
1424
1425         i_dts += p_stream->entry[i].i_length;
1426
1427         p_stream->entry[i].i_length =
1428             i_delta * (int64_t)i_timescale / INT64_C(1000000);
1429
1430         i_dts_q += p_stream->entry[i].i_length;
1431     }
1432     /* then write encoded table */
1433     for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
1434     {
1435         int     i_first = i;
1436         int64_t i_delta = p_stream->entry[i].i_length;
1437
1438         while( i < p_stream->i_entry_count )
1439         {
1440             i++;
1441             if( i >= p_stream->i_entry_count ||
1442                 p_stream->entry[i].i_length != i_delta )
1443             {
1444                 break;
1445             }
1446         }
1447
1448         bo_add_32be( stts, i - i_first ); // sample-count
1449         bo_add_32be( stts, i_delta );     // sample-delta
1450     }
1451     bo_fix_32be( stts, 12, i_index );
1452     box_fix( stts );
1453
1454     /* FIXME add ctts ?? FIXME */
1455
1456     stsz = box_full_new( "stsz", 0, 0 );
1457     bo_add_32be( stsz, 0 );                             // sample-size
1458     bo_add_32be( stsz, p_stream->i_entry_count );       // sample-count
1459     for( i = 0; i < p_stream->i_entry_count; i++ )
1460     {
1461         bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
1462     }
1463     box_fix( stsz );
1464
1465     /* create stss table */
1466     stss = NULL;
1467     for( i = 0, i_index = 0; i < p_stream->i_entry_count; i++ )
1468     {
1469         if( p_stream->entry[i].i_flags & BLOCK_FLAG_TYPE_I )
1470         {
1471             if( stss == NULL )
1472             {
1473                 stss = box_full_new( "stss", 0, 0 );
1474                 bo_add_32be( stss, 0 ); /* fixed later */
1475             }
1476             bo_add_32be( stss, 1 + i );
1477             i_index++;
1478         }
1479     }
1480     if( stss )
1481     {
1482         bo_fix_32be( stss, 12, i_index );
1483         box_fix( stss );
1484     }
1485
1486     /* Now gather all boxes into stbl */
1487     box_gather( stbl, stsd );
1488     box_gather( stbl, stts );
1489     if( stss )
1490     {
1491         box_gather( stbl, stss );
1492     }
1493     box_gather( stbl, stsc );
1494     box_gather( stbl, stsz );
1495     p_stream->i_stco_pos = stbl->i_buffer + 16;
1496     box_gather( stbl, stco );
1497
1498     /* finish stbl */
1499     box_fix( stbl );
1500
1501     return stbl;
1502 }
1503
1504 static int64_t get_timestamp(void);
1505
1506 static const uint32_t mvhd_matrix[9] =
1507     { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
1508
1509 static bo_t *GetMoovBox( sout_mux_t *p_mux )
1510 {
1511     sout_mux_sys_t *p_sys = p_mux->p_sys;
1512
1513     bo_t            *moov, *mvhd;
1514     int             i_trak, i;
1515
1516     uint32_t        i_movie_timescale = 90000;
1517     int64_t         i_movie_duration  = 0;
1518     int64_t         i_timestamp = get_timestamp();
1519
1520     moov = box_new( "moov" );
1521
1522     /* Create general info */
1523     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1524     {
1525         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1526         i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration );
1527     }
1528     msg_Dbg( p_mux, "movie duration %ds",
1529              (uint32_t)( i_movie_duration / (mtime_t)1000000 ) );
1530
1531     i_movie_duration = i_movie_duration * i_movie_timescale / 1000000;
1532
1533     /* *** add /moov/mvhd *** */
1534     if( !p_sys->b_64_ext )
1535     {
1536         mvhd = box_full_new( "mvhd", 0, 0 );
1537         bo_add_32be( mvhd, i_timestamp );   // creation time
1538         bo_add_32be( mvhd, i_timestamp );   // modification time
1539         bo_add_32be( mvhd, i_movie_timescale);  // timescale
1540         bo_add_32be( mvhd, i_movie_duration );  // duration
1541     }
1542     else
1543     {
1544         mvhd = box_full_new( "mvhd", 1, 0 );
1545         bo_add_64be( mvhd, i_timestamp );   // creation time
1546         bo_add_64be( mvhd, i_timestamp );   // modification time
1547         bo_add_32be( mvhd, i_movie_timescale);  // timescale
1548         bo_add_64be( mvhd, i_movie_duration );  // duration
1549     }
1550     bo_add_32be( mvhd, 0x10000 );           // rate
1551     bo_add_16be( mvhd, 0x100 );             // volume
1552     bo_add_16be( mvhd, 0 );                 // reserved
1553     for( i = 0; i < 2; i++ )
1554     {
1555         bo_add_32be( mvhd, 0 );             // reserved
1556     }
1557     for( i = 0; i < 9; i++ )
1558     {
1559         bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
1560     }
1561     for( i = 0; i < 6; i++ )
1562     {
1563         bo_add_32be( mvhd, 0 );             // pre-defined
1564     }
1565
1566     /* Next available track id */
1567     bo_add_32be( mvhd, p_sys->i_nb_streams + 1 ); // next-track-id
1568
1569     box_fix( mvhd );
1570     box_gather( moov, mvhd );
1571
1572     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1573     {
1574         mp4_stream_t *p_stream;
1575         uint32_t     i_timescale;
1576
1577         bo_t *trak, *tkhd, *edts, *elst, *mdia, *mdhd, *hdlr;
1578         bo_t *minf, *dinf, *dref, *url, *stbl;
1579
1580         p_stream = p_sys->pp_streams[i_trak];
1581
1582         if( p_stream->fmt.i_cat == AUDIO_ES )
1583             i_timescale = p_stream->fmt.audio.i_rate;
1584         else
1585             i_timescale = 1001;
1586
1587         /* *** add /moov/trak *** */
1588         trak = box_new( "trak" );
1589
1590         /* *** add /moov/trak/tkhd *** */
1591         if( !p_sys->b_64_ext )
1592         {
1593             if( p_sys->b_mov )
1594                 tkhd = box_full_new( "tkhd", 0, 0x0f );
1595             else
1596                 tkhd = box_full_new( "tkhd", 0, 1 );
1597
1598             bo_add_32be( tkhd, i_timestamp );       // creation time
1599             bo_add_32be( tkhd, i_timestamp );       // modification time
1600             bo_add_32be( tkhd, p_stream->i_track_id );
1601             bo_add_32be( tkhd, 0 );                     // reserved 0
1602             bo_add_32be( tkhd, p_stream->i_duration *
1603                          (int64_t)i_movie_timescale /
1604                          (mtime_t)1000000 );            // duration
1605         }
1606         else
1607         {
1608             if( p_sys->b_mov )
1609                 tkhd = box_full_new( "tkhd", 1, 0x0f );
1610             else
1611                 tkhd = box_full_new( "tkhd", 1, 1 );
1612
1613             bo_add_64be( tkhd, i_timestamp );       // creation time
1614             bo_add_64be( tkhd, i_timestamp );       // modification time
1615             bo_add_32be( tkhd, p_stream->i_track_id );
1616             bo_add_32be( tkhd, 0 );                     // reserved 0
1617             bo_add_64be( tkhd, p_stream->i_duration *
1618                          (int64_t)i_movie_timescale /
1619                          (mtime_t)1000000 );            // duration
1620         }
1621
1622         for( i = 0; i < 2; i++ )
1623         {
1624             bo_add_32be( tkhd, 0 );                 // reserved
1625         }
1626         bo_add_16be( tkhd, 0 );                     // layer
1627         bo_add_16be( tkhd, 0 );                     // pre-defined
1628         // volume
1629         bo_add_16be( tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0 );
1630         bo_add_16be( tkhd, 0 );                     // reserved
1631         for( i = 0; i < 9; i++ )
1632         {
1633             bo_add_32be( tkhd, mvhd_matrix[i] );    // matrix
1634         }
1635         if( p_stream->fmt.i_cat == AUDIO_ES )
1636         {
1637             bo_add_32be( tkhd, 0 );                 // width (presentation)
1638             bo_add_32be( tkhd, 0 );                 // height(presentation)
1639         }
1640         else if( p_stream->fmt.i_cat == VIDEO_ES )
1641         {
1642             int i_width = p_stream->fmt.video.i_width << 16;
1643             if( p_stream->fmt.video.i_sar_num > 0 &&
1644                 p_stream->fmt.video.i_sar_den > 0 )
1645             {
1646                 i_width = (int64_t)p_stream->fmt.video.i_sar_num *
1647                           ((int64_t)p_stream->fmt.video.i_width << 16) /
1648                           p_stream->fmt.video.i_sar_den;
1649             }
1650             // width (presentation)
1651             bo_add_32be( tkhd, i_width );
1652             // height(presentation)
1653             bo_add_32be( tkhd, p_stream->fmt.video.i_height << 16 );
1654         }
1655         else
1656         {
1657             int i_width = 320 << 16;
1658             int i_height = 200;
1659             int i;
1660             for( i = 0; i < p_sys->i_nb_streams; i++ )
1661             {
1662                 mp4_stream_t *tk = p_sys->pp_streams[i];
1663                 if( tk->fmt.i_cat == VIDEO_ES )
1664                 {
1665                     if( tk->fmt.video.i_sar_num > 0 &&
1666                         tk->fmt.video.i_sar_den > 0 )
1667                         i_width = (int64_t)tk->fmt.video.i_sar_num *
1668                                   ((int64_t)tk->fmt.video.i_width << 16) /
1669                                   tk->fmt.video.i_sar_den;
1670                     else
1671                         i_width = tk->fmt.video.i_width << 16;
1672                     i_height = tk->fmt.video.i_height;
1673                     break;
1674                 }
1675             }
1676             bo_add_32be( tkhd, i_width );     // width (presentation)
1677             bo_add_32be( tkhd, i_height << 16 );    // height(presentation)
1678         }
1679
1680         box_fix( tkhd );
1681         box_gather( trak, tkhd );
1682
1683         /* *** add /moov/trak/edts and elst */
1684         edts = box_new( "edts" );
1685         elst = box_full_new( "elst", p_sys->b_64_ext ? 1 : 0, 0 );
1686         if( p_stream->i_dts_start > p_sys->i_dts_start )
1687         {
1688             bo_add_32be( elst, 2 );
1689
1690             if( p_sys->b_64_ext )
1691             {
1692                 bo_add_64be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
1693                              i_movie_timescale / INT64_C(1000000) );
1694                 bo_add_64be( elst, -1 );
1695             }
1696             else
1697             {
1698                 bo_add_32be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
1699                              i_movie_timescale / INT64_C(1000000) );
1700                 bo_add_32be( elst, -1 );
1701             }
1702             bo_add_16be( elst, 1 );
1703             bo_add_16be( elst, 0 );
1704         }
1705         else
1706         {
1707             bo_add_32be( elst, 1 );
1708         }
1709         if( p_sys->b_64_ext )
1710         {
1711             bo_add_64be( elst, p_stream->i_duration *
1712                          i_movie_timescale / INT64_C(1000000) );
1713             bo_add_64be( elst, 0 );
1714         }
1715         else
1716         {
1717             bo_add_32be( elst, p_stream->i_duration *
1718                          i_movie_timescale / INT64_C(1000000) );
1719             bo_add_32be( elst, 0 );
1720         }
1721         bo_add_16be( elst, 1 );
1722         bo_add_16be( elst, 0 );
1723
1724         box_fix( elst );
1725         box_gather( edts, elst );
1726         box_fix( edts );
1727         box_gather( trak, edts );
1728
1729         /* *** add /moov/trak/mdia *** */
1730         mdia = box_new( "mdia" );
1731
1732         /* media header */
1733         if( !p_sys->b_64_ext )
1734         {
1735             mdhd = box_full_new( "mdhd", 0, 0 );
1736             bo_add_32be( mdhd, i_timestamp );   // creation time
1737             bo_add_32be( mdhd, i_timestamp );   // modification time
1738             bo_add_32be( mdhd, i_timescale);        // timescale
1739             bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
1740                                (mtime_t)1000000 );  // duration
1741         }
1742         else
1743         {
1744             mdhd = box_full_new( "mdhd", 1, 0 );
1745             bo_add_64be( mdhd, i_timestamp );   // creation time
1746             bo_add_64be( mdhd, i_timestamp );   // modification time
1747             bo_add_32be( mdhd, i_timescale);        // timescale
1748             bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
1749                                (mtime_t)1000000 );  // duration
1750         }
1751
1752         if( p_stream->fmt.psz_language )
1753         {
1754             char *psz = p_stream->fmt.psz_language;
1755             const iso639_lang_t *pl = NULL;
1756             uint16_t lang = 0x0;
1757
1758             if( strlen( psz ) == 2 )
1759             {
1760                 pl = GetLang_1( psz );
1761             }
1762             else if( strlen( psz ) == 3 )
1763             {
1764                 pl = GetLang_2B( psz );
1765                 if( !strcmp( pl->psz_iso639_1, "??" ) )
1766                 {
1767                     pl = GetLang_2T( psz );
1768                 }
1769             }
1770             if( pl && strcmp( pl->psz_iso639_1, "??" ) )
1771             {
1772                 lang = ( ( pl->psz_iso639_2T[0] - 0x60 ) << 10 ) |
1773                        ( ( pl->psz_iso639_2T[1] - 0x60 ) <<  5 ) |
1774                        ( ( pl->psz_iso639_2T[2] - 0x60 ) );
1775             }
1776             bo_add_16be( mdhd, lang );          // language
1777         }
1778         else
1779         {
1780             bo_add_16be( mdhd, 0    );          // language
1781         }
1782         bo_add_16be( mdhd, 0    );              // predefined
1783         box_fix( mdhd );
1784         box_gather( mdia, mdhd );
1785
1786         /* handler reference */
1787         hdlr = box_full_new( "hdlr", 0, 0 );
1788
1789         if( p_sys->b_mov )
1790             bo_add_fourcc( hdlr, "mhlr" );         // media handler
1791         else
1792             bo_add_32be( hdlr, 0 );
1793
1794         if( p_stream->fmt.i_cat == AUDIO_ES )
1795             bo_add_fourcc( hdlr, "soun" );
1796         else if( p_stream->fmt.i_cat == VIDEO_ES )
1797             bo_add_fourcc( hdlr, "vide" );
1798         else if( p_stream->fmt.i_cat == SPU_ES )
1799             bo_add_fourcc( hdlr, "text" );
1800
1801         bo_add_32be( hdlr, 0 );         // reserved
1802         bo_add_32be( hdlr, 0 );         // reserved
1803         bo_add_32be( hdlr, 0 );         // reserved
1804
1805         if( p_sys->b_mov )
1806             bo_add_8( hdlr, 12 );   /* Pascal string for .mov */
1807
1808         if( p_stream->fmt.i_cat == AUDIO_ES )
1809             bo_add_mem( hdlr, 12, (uint8_t*)"SoundHandler" );
1810         else if( p_stream->fmt.i_cat == VIDEO_ES )
1811             bo_add_mem( hdlr, 12, (uint8_t*)"VideoHandler" );
1812         else
1813             bo_add_mem( hdlr, 12, (uint8_t*)"Text Handler" );
1814
1815         if( !p_sys->b_mov )
1816             bo_add_8( hdlr, 0 );   /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
1817
1818         box_fix( hdlr );
1819         box_gather( mdia, hdlr );
1820
1821         /* minf*/
1822         minf = box_new( "minf" );
1823
1824         /* add smhd|vmhd */
1825         if( p_stream->fmt.i_cat == AUDIO_ES )
1826         {
1827             bo_t *smhd;
1828
1829             smhd = box_full_new( "smhd", 0, 0 );
1830             bo_add_16be( smhd, 0 );     // balance
1831             bo_add_16be( smhd, 0 );     // reserved
1832             box_fix( smhd );
1833
1834             box_gather( minf, smhd );
1835         }
1836         else if( p_stream->fmt.i_cat == VIDEO_ES )
1837         {
1838             bo_t *vmhd;
1839
1840             vmhd = box_full_new( "vmhd", 0, 1 );
1841             bo_add_16be( vmhd, 0 );     // graphicsmode
1842             for( i = 0; i < 3; i++ )
1843             {
1844                 bo_add_16be( vmhd, 0 ); // opcolor
1845             }
1846             box_fix( vmhd );
1847
1848             box_gather( minf, vmhd );
1849         }
1850         else if( p_stream->fmt.i_cat == SPU_ES )
1851         {
1852             bo_t *gmhd = box_new( "gmhd" );
1853             bo_t *gmin = box_full_new( "gmin", 0, 1 );
1854
1855             bo_add_16be( gmin, 0 );     // graphicsmode
1856             for( i = 0; i < 3; i++ )
1857             {
1858                 bo_add_16be( gmin, 0 ); // opcolor
1859             }
1860             bo_add_16be( gmin, 0 );     // balance
1861             bo_add_16be( gmin, 0 );     // reserved
1862             box_fix( gmin );
1863
1864             box_gather( gmhd, gmin );
1865             box_fix( gmhd );
1866
1867             box_gather( minf, gmhd );
1868         }
1869
1870         /* dinf */
1871         dinf = box_new( "dinf" );
1872         dref = box_full_new( "dref", 0, 0 );
1873         bo_add_32be( dref, 1 );
1874         url = box_full_new( "url ", 0, 0x01 );
1875         box_fix( url );
1876         box_gather( dref, url );
1877         box_fix( dref );
1878         box_gather( dinf, dref );
1879
1880         /* append dinf to mdia */
1881         box_fix( dinf );
1882         box_gather( minf, dinf );
1883
1884         /* add stbl */
1885         stbl = GetStblBox( p_mux, p_stream );
1886
1887         /* append stbl to minf */
1888         p_stream->i_stco_pos += minf->i_buffer;
1889         box_gather( minf, stbl );
1890
1891         /* append minf to mdia */
1892         box_fix( minf );
1893         p_stream->i_stco_pos += mdia->i_buffer;
1894         box_gather( mdia, minf );
1895
1896         /* append mdia to trak */
1897         box_fix( mdia );
1898         p_stream->i_stco_pos += trak->i_buffer;
1899         box_gather( trak, mdia );
1900
1901         /* append trak to moov */
1902         box_fix( trak );
1903         p_stream->i_stco_pos += moov->i_buffer;
1904         box_gather( moov, trak );
1905     }
1906
1907     /* Add user data tags */
1908     box_gather( moov, GetUdtaTag( p_mux ) );
1909
1910     box_fix( moov );
1911     return moov;
1912 }
1913
1914 /****************************************************************************/
1915
1916 static void bo_init( bo_t *p_bo, int i_size, uint8_t *p_buffer,
1917                      bool b_grow )
1918 {
1919     if( !p_buffer )
1920     {
1921         p_bo->i_buffer_size = __MAX( i_size, 1024 );
1922         p_bo->p_buffer = xmalloc( p_bo->i_buffer_size );
1923     }
1924     else
1925     {
1926         p_bo->i_buffer_size = i_size;
1927         p_bo->p_buffer = p_buffer;
1928     }
1929
1930     p_bo->b_grow = b_grow;
1931     p_bo->i_buffer = 0;
1932 }
1933
1934 static void bo_add_8( bo_t *p_bo, uint8_t i )
1935 {
1936     if( p_bo->i_buffer < p_bo->i_buffer_size )
1937     {
1938         p_bo->p_buffer[p_bo->i_buffer] = i;
1939     }
1940     else if( p_bo->b_grow )
1941     {
1942         p_bo->i_buffer_size += 1024;
1943         p_bo->p_buffer = xrealloc( p_bo->p_buffer, p_bo->i_buffer_size );
1944         p_bo->p_buffer[p_bo->i_buffer] = i;
1945     }
1946
1947     p_bo->i_buffer++;
1948 }
1949
1950 static void bo_add_16be( bo_t *p_bo, uint16_t i )
1951 {
1952     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1953     bo_add_8( p_bo, i &0xff );
1954 }
1955
1956 static void bo_add_24be( bo_t *p_bo, uint32_t i )
1957 {
1958     bo_add_8( p_bo, ( ( i >> 16) &0xff ) );
1959     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1960     bo_add_8( p_bo, (   i &0xff ) );
1961 }
1962 static void bo_add_32be( bo_t *p_bo, uint32_t i )
1963 {
1964     bo_add_16be( p_bo, ( ( i >> 16) &0xffff ) );
1965     bo_add_16be( p_bo, i &0xffff );
1966 }
1967
1968 static void bo_fix_32be ( bo_t *p_bo, int i_pos, uint32_t i)
1969 {
1970     p_bo->p_buffer[i_pos    ] = ( i >> 24 )&0xff;
1971     p_bo->p_buffer[i_pos + 1] = ( i >> 16 )&0xff;
1972     p_bo->p_buffer[i_pos + 2] = ( i >>  8 )&0xff;
1973     p_bo->p_buffer[i_pos + 3] = ( i       )&0xff;
1974 }
1975
1976 static void bo_add_64be( bo_t *p_bo, uint64_t i )
1977 {
1978     bo_add_32be( p_bo, ( ( i >> 32) &0xffffffff ) );
1979     bo_add_32be( p_bo, i &0xffffffff );
1980 }
1981
1982 static void bo_add_fourcc( bo_t *p_bo, const char *fcc )
1983 {
1984     bo_add_8( p_bo, fcc[0] );
1985     bo_add_8( p_bo, fcc[1] );
1986     bo_add_8( p_bo, fcc[2] );
1987     bo_add_8( p_bo, fcc[3] );
1988 }
1989
1990 static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem )
1991 {
1992     int i;
1993
1994     for( i = 0; i < i_size; i++ )
1995     {
1996         bo_add_8( p_bo, p_mem[i] );
1997     }
1998 }
1999
2000 static void bo_add_descr( bo_t *p_bo, uint8_t tag, uint32_t i_size )
2001 {
2002     uint32_t i_length;
2003     uint8_t  vals[4];
2004
2005     i_length = i_size;
2006     vals[3] = (unsigned char)(i_length & 0x7f);
2007     i_length >>= 7;
2008     vals[2] = (unsigned char)((i_length & 0x7f) | 0x80);
2009     i_length >>= 7;
2010     vals[1] = (unsigned char)((i_length & 0x7f) | 0x80);
2011     i_length >>= 7;
2012     vals[0] = (unsigned char)((i_length & 0x7f) | 0x80);
2013
2014     bo_add_8( p_bo, tag );
2015
2016     if( i_size < 0x00000080 )
2017     {
2018         bo_add_8( p_bo, vals[3] );
2019     }
2020     else if( i_size < 0x00004000 )
2021     {
2022         bo_add_8( p_bo, vals[2] );
2023         bo_add_8( p_bo, vals[3] );
2024     }
2025     else if( i_size < 0x00200000 )
2026     {
2027         bo_add_8( p_bo, vals[1] );
2028         bo_add_8( p_bo, vals[2] );
2029         bo_add_8( p_bo, vals[3] );
2030     }
2031     else if( i_size < 0x10000000 )
2032     {
2033         bo_add_8( p_bo, vals[0] );
2034         bo_add_8( p_bo, vals[1] );
2035         bo_add_8( p_bo, vals[2] );
2036         bo_add_8( p_bo, vals[3] );
2037     }
2038 }
2039
2040 static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
2041 {
2042     int i;
2043
2044     for( i = 0; i < p_bo2->i_buffer; i++ )
2045     {
2046         bo_add_8( p_bo, p_bo2->p_buffer[i] );
2047     }
2048 }
2049
2050 static bo_t * box_new( const char *fcc )
2051 {
2052     bo_t *box;
2053
2054     if( ( box = malloc( sizeof( bo_t ) ) ) )
2055     {
2056         bo_init( box, 0, NULL, true );
2057
2058         bo_add_32be  ( box, 0 );
2059         bo_add_fourcc( box, fcc );
2060     }
2061
2062     return box;
2063 }
2064
2065 static bo_t * box_full_new( const char *fcc, uint8_t v, uint32_t f )
2066 {
2067     bo_t *box;
2068
2069     if( ( box = malloc( sizeof( bo_t ) ) ) )
2070     {
2071         bo_init( box, 0, NULL, true );
2072
2073         bo_add_32be  ( box, 0 );
2074         bo_add_fourcc( box, fcc );
2075         bo_add_8     ( box, v );
2076         bo_add_24be  ( box, f );
2077     }
2078
2079     return box;
2080 }
2081
2082 static void box_fix( bo_t *box )
2083 {
2084     bo_t box_tmp;
2085
2086     memcpy( &box_tmp, box, sizeof( bo_t ) );
2087
2088     box_tmp.i_buffer = 0;
2089     bo_add_32be( &box_tmp, box->i_buffer );
2090 }
2091
2092 static void box_free( bo_t *box )
2093 {
2094     free( box->p_buffer );
2095     free( box );
2096 }
2097
2098 static void box_gather ( bo_t *box, bo_t *box2 )
2099 {
2100     bo_add_bo( box, box2 );
2101     box_free( box2 );
2102 }
2103
2104 static block_t * bo_to_sout( sout_instance_t *p_sout,  bo_t *box )
2105 {
2106     (void)p_sout;
2107     block_t *p_buf;
2108
2109     p_buf = block_New( p_sout, box->i_buffer );
2110     if( box->i_buffer > 0 )
2111     {
2112         memcpy( p_buf->p_buffer, box->p_buffer, box->i_buffer );
2113     }
2114
2115     return p_buf;
2116 }
2117
2118 static void box_send( sout_mux_t *p_mux,  bo_t *box )
2119 {
2120     block_t *p_buf;
2121
2122     p_buf = bo_to_sout( p_mux->p_sout, box );
2123     box_free( box );
2124
2125     sout_AccessOutWrite( p_mux->p_access, p_buf );
2126 }
2127
2128 static int64_t get_timestamp(void)
2129 {
2130     int64_t i_timestamp = time(NULL);
2131
2132     i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
2133     // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
2134
2135     return i_timestamp;
2136 }