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