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