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