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