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