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