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