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