]> git.sesse.net Git - vlc/blob - modules/mux/mp4.c
* mp4.c: for mp3 in mp4a we need an ESDS.
[vlc] / modules / mux / mp4.c
1 /*****************************************************************************
2  * mp4.c: mp4/mov muxer
3  *****************************************************************************
4  * Copyright (C) 2001, 2002, 2003 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/input.h>
34 #include <vlc/sout.h>
35
36 #ifdef HAVE_TIME_H
37 #include <time.h>
38 #endif
39
40 #include "codecs.h"
41
42 /*****************************************************************************
43  * Exported prototypes
44  *****************************************************************************/
45 static int  Open   ( vlc_object_t * );
46 static void Close  ( vlc_object_t * );
47
48 static int Capability(sout_mux_t *, int, void *, void * );
49 static int AddStream( sout_mux_t *, sout_input_t * );
50 static int DelStream( sout_mux_t *, sout_input_t * );
51 static int Mux      ( sout_mux_t * );
52
53 /*****************************************************************************
54  * Module descriptor
55  *****************************************************************************/
56 #define FASTSTART_TEXT N_("Create \"Fast start\" files")
57 #define FASTSTART_LONGTEXT N_( \
58     "When this option is turned on, \"Fast start\" files will be created. " \
59     "(\"Fast start\" files are optimized for download, allowing the user " \
60     "to start previewing the file while it is downloading).")
61
62 vlc_module_begin();
63     set_description( _("MP4/MOV muxer") );
64
65     add_bool( "mp4-faststart", 1, NULL, FASTSTART_TEXT, FASTSTART_LONGTEXT,
66               VLC_TRUE );
67
68     set_capability( "sout mux", 5 );
69     add_shortcut( "mp4" );
70     add_shortcut( "mov" );
71     set_callbacks( Open, Close );
72 vlc_module_end();
73
74 /*****************************************************************************
75  * Local prototypes
76  *****************************************************************************/
77 typedef struct
78 {
79     uint64_t i_pos;
80     int      i_size;
81
82     mtime_t  i_pts;
83     mtime_t  i_dts;
84     mtime_t  i_length;
85
86 } mp4_entry_t;
87
88 typedef struct
89 {
90     es_format_t   *p_fmt;
91     int           i_track_id;
92
93     /* index */
94     unsigned int i_entry_count;
95     unsigned int i_entry_max;
96     mp4_entry_t  *entry;
97
98     /* stats */
99     mtime_t      i_duration;
100
101     /* for later stco fix-up (fast start files) */
102     uint64_t i_stco_pos;
103     vlc_bool_t b_stco64;
104
105 } mp4_stream_t;
106
107 struct sout_mux_sys_t
108 {
109     vlc_bool_t b_mov;
110     vlc_bool_t b_64_ext;
111     vlc_bool_t b_fast_start;
112
113     uint64_t i_mdat_pos;
114     uint64_t i_pos;
115
116     mtime_t  i_start_dts;
117
118     int          i_nb_streams;
119     mp4_stream_t **pp_streams;
120 };
121
122 typedef struct bo_t
123 {
124     vlc_bool_t b_grow;
125
126     int        i_buffer_size;
127     int        i_buffer;
128     uint8_t    *p_buffer;
129
130 } bo_t;
131
132 static void bo_init     ( bo_t *, int , uint8_t *, vlc_bool_t  );
133 static void bo_add_8    ( bo_t *, uint8_t );
134 static void bo_add_16be ( bo_t *, uint16_t );
135 static void bo_add_24be ( bo_t *, uint32_t );
136 static void bo_add_32be ( bo_t *, uint32_t );
137 static void bo_add_64be ( bo_t *, uint64_t );
138 static void bo_add_fourcc(bo_t *, char * );
139 static void bo_add_bo   ( bo_t *, bo_t * );
140 static void bo_add_mem  ( bo_t *, int , uint8_t * );
141 static void bo_add_descr( bo_t *, uint8_t , uint32_t );
142
143 static void bo_fix_32be ( bo_t *, int , uint32_t );
144
145 static bo_t *box_new     ( char *fcc );
146 static bo_t *box_full_new( char *fcc, uint8_t v, uint32_t f );
147 static void  box_fix     ( bo_t *box );
148 static void  box_free    ( bo_t *box );
149 static void  box_gather  ( bo_t *box, bo_t *box2 );
150
151 static void box_send( sout_mux_t *p_mux,  bo_t *box );
152
153 static int64_t get_timestamp();
154
155 static sout_buffer_t *bo_to_sout( sout_instance_t *p_sout,  bo_t *box );
156
157 /*****************************************************************************
158  * Open:
159  *****************************************************************************/
160 static int Open( vlc_object_t *p_this )
161 {
162     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
163     sout_mux_sys_t  *p_sys;
164     bo_t            *box;
165
166     p_sys = malloc( sizeof( sout_mux_sys_t ) );
167     p_sys->i_pos        = 0;
168     p_sys->i_nb_streams = 0;
169     p_sys->pp_streams   = NULL;
170     p_sys->i_mdat_pos   = 0;
171     p_sys->b_mov        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" );
172     p_sys->i_start_dts  = 0;
173
174     msg_Dbg( p_mux, "Open" );
175
176     p_mux->pf_capacity  = Capability;
177     p_mux->pf_addstream = AddStream;
178     p_mux->pf_delstream = DelStream;
179     p_mux->pf_mux       = Mux;
180     p_mux->p_sys        = p_sys;
181
182     if( !p_sys->b_mov )
183     {
184         /* Now add ftyp header */
185         box = box_new( "ftyp" );
186         bo_add_fourcc( box, "isom" );
187         bo_add_32be  ( box, 0 );
188         bo_add_fourcc( box, "mp41" );
189         box_fix( box );
190
191         p_sys->i_pos += box->i_buffer;
192         p_sys->i_mdat_pos = p_sys->i_pos;
193
194         box_send( p_mux, box );
195     }
196
197     /* FIXME FIXME
198      * Quicktime actually doesn't like the 64 bits extensions !!! */
199     p_sys->b_64_ext = VLC_FALSE;
200
201     /* Now add mdat header */
202     box = box_new( "mdat" );
203     bo_add_64be  ( box, 0 ); // enough to store an extended size
204
205     p_sys->i_pos += box->i_buffer;
206
207     box_send( p_mux, box );
208
209     return VLC_SUCCESS;
210 }
211
212 static int GetDescrLength( int i_size )
213 {
214     if( i_size < 0x00000080 )
215         return 2 + i_size;
216     else if( i_size < 0x00004000 )
217         return 3 + i_size;
218     else if( i_size < 0x00200000 )
219         return 4 + i_size;
220     else
221         return 5 + i_size;
222 }
223
224 static bo_t *GetESDS( mp4_stream_t *p_stream )
225 {
226     bo_t *esds;
227     int  i_stream_type;
228     int  i_object_type_indication;
229     int  i_decoder_specific_info_size;
230
231     if( p_stream->p_fmt->i_extra > 0 )
232     {
233         i_decoder_specific_info_size =
234             GetDescrLength( p_stream->p_fmt->i_extra );
235     }
236     else
237     {
238         i_decoder_specific_info_size = 0;
239     }
240
241     esds = box_full_new( "esds", 0, 0 );
242
243     /* ES_Descr */
244     bo_add_descr( esds, 0x03, 3 +
245                   GetDescrLength( 13 + i_decoder_specific_info_size ) +
246                   GetDescrLength( 1 ) );
247     bo_add_16be( esds, p_stream->i_track_id );
248     bo_add_8   ( esds, 0x1f );      // flags=0|streamPriority=0x1f
249
250     /* DecoderConfigDescr */
251     bo_add_descr( esds, 0x04, 13 + i_decoder_specific_info_size );
252
253     switch( p_stream->p_fmt->i_codec )
254     {
255         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
256             i_object_type_indication = 0x20;
257             break;
258         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
259             /* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
260             i_object_type_indication = 0x60;
261             break;
262         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
263             /* FIXME for mpeg2-aac == 0x66->0x68 */
264             i_object_type_indication = 0x40;
265             break;
266         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
267             i_object_type_indication =
268                 p_stream->p_fmt->audio.i_rate < 32000 ? 0x69 : 0x6b;
269             break;
270         default:
271             i_object_type_indication = 0x00;
272             break;
273     }
274     i_stream_type = p_stream->p_fmt->i_cat == VIDEO_ES ? 0x04 : 0x05;
275
276     bo_add_8   ( esds, i_object_type_indication );
277     bo_add_8   ( esds, ( i_stream_type << 2 ) | 1 );
278     bo_add_24be( esds, 1024 * 1024 );       // bufferSizeDB
279     bo_add_32be( esds, 0x7fffffff );        // maxBitrate
280     bo_add_32be( esds, 0 );                 // avgBitrate
281
282     if( p_stream->p_fmt->i_extra > 0 )
283     {
284         int i;
285
286         /* DecoderSpecificInfo */
287         bo_add_descr( esds, 0x05, p_stream->p_fmt->i_extra );
288
289         for( i = 0; i < p_stream->p_fmt->i_extra; i++ )
290         {
291             bo_add_8( esds, ((uint8_t*)p_stream->p_fmt->p_extra)[i] );
292         }
293     }
294
295     /* SL_Descr mandatory */
296     bo_add_descr( esds, 0x06, 1 );
297     bo_add_8    ( esds, 0x02 );  // sl_predefined
298
299     box_fix( esds );
300
301     return esds;
302 }
303
304 static bo_t *GetWaveTag( mp4_stream_t *p_stream )
305 {
306     bo_t *wave;
307     bo_t *box;
308
309     wave = box_new( "wave" );
310
311     box = box_new( "frma" );
312     bo_add_fourcc( box, "mp4a" );
313     box_fix( box );
314     box_gather( wave, box );
315
316     box = box_new( "mp4a" );
317     bo_add_32be( box, 0 );
318     box_fix( box );
319     box_gather( wave, box );
320
321     box = GetESDS( p_stream );
322     box_fix( box );
323     box_gather( wave, box );
324
325     box = box_new( "srcq" );
326     bo_add_32be( box, 0x40 );
327     box_fix( box );
328     box_gather( wave, box );
329
330     /* wazza ? */
331     bo_add_32be( wave, 8 ); /* new empty box */
332     bo_add_32be( wave, 0 ); /* box label */
333
334     box_fix( wave );
335
336     return wave;
337 }
338
339 /* TODO: No idea about these values */
340 static bo_t *GetSVQ3Tag( mp4_stream_t *p_stream )
341 {
342     bo_t *smi = box_new( "SMI " );
343
344     bo_add_fourcc( smi, "SEQH" );
345     bo_add_32be( smi, 0x5 );
346     bo_add_32be( smi, 0xe2c0211d );
347     bo_add_8( smi, 0xc0 );
348     box_fix( smi );
349
350     return smi;
351 }
352
353 static bo_t *GetUdtaTag( sout_mux_t *p_mux )
354 {
355     sout_mux_sys_t *p_sys = p_mux->p_sys;
356     bo_t *udta = box_new( "udta" );
357     int i_track;
358
359     /* Requirements */
360     for( i_track = 0; i_track < p_sys->i_nb_streams; i_track++ )
361     {
362         mp4_stream_t *p_stream = p_sys->pp_streams[i_track];
363
364         if( p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','v') ||
365             p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','a') )
366         {
367             bo_t *box = box_new( "\251req" );
368             /* String length */
369             bo_add_16be( box, sizeof("QuickTime 6.0 or greater") - 1);
370             bo_add_16be( box, 0 );
371             bo_add_mem( box, sizeof("QuickTime 6.0 or greater") - 1,
372                         "QuickTime 6.0 or greater" );
373             box_fix( box );
374             box_gather( udta, box );
375             break;
376         }
377     }
378
379     /* Encoder */
380     {
381         bo_t *box = box_new( "\251enc" );
382         /* String length */
383         bo_add_16be( box, sizeof(PACKAGE_STRING " stream output") - 1);
384         bo_add_16be( box, 0 );
385         bo_add_mem( box, sizeof(PACKAGE_STRING " stream output") - 1,
386                     PACKAGE_STRING " stream output" );
387         box_fix( box );
388         box_gather( udta, box );
389     }
390
391     box_fix( udta );
392     return udta;
393 }
394
395 static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
396 {
397     sout_mux_sys_t *p_sys = p_mux->p_sys;
398     vlc_bool_t b_descr = VLC_FALSE;
399     bo_t *soun;
400     char fcc[4] = "    ";
401     int  i;
402
403     switch( p_stream->p_fmt->i_codec )
404     {
405     case VLC_FOURCC('m','p','4','a'):
406         memcpy( fcc, "mp4a", 4 );
407         b_descr = VLC_TRUE;
408         break;
409
410     case VLC_FOURCC('m','p','g','a'):
411         if( p_sys->b_mov )
412             memcpy( fcc, ".mp3", 4 );
413         else
414         {
415             memcpy( fcc, "mp4a", 4 );
416             b_descr = VLC_TRUE;
417         }
418         break;
419
420     default:
421         memcpy( fcc, (char*)&p_stream->p_fmt->i_codec, 4 );
422         break;
423     }
424
425     soun = box_new( fcc );
426     for( i = 0; i < 6; i++ )
427     {
428         bo_add_8( soun, 0 );        // reserved;
429     }
430     bo_add_16be( soun, 1 );         // data-reference-index
431
432     /* SoundDescription */
433     if( p_sys->b_mov &&
434         p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','a') )
435     {
436         bo_add_16be( soun, 1 );     // version 1;
437     }
438     else
439     {
440         bo_add_16be( soun, 0 );     // version 0;
441     }
442     bo_add_16be( soun, 0 );         // revision level (0)
443     bo_add_32be( soun, 0 );         // vendor
444     // channel-count
445     bo_add_16be( soun, p_stream->p_fmt->audio.i_channels );
446     // sample size
447     bo_add_16be( soun, p_stream->p_fmt->audio.i_bitspersample ?
448                  p_stream->p_fmt->audio.i_bitspersample : 16 );
449     bo_add_16be( soun, -2 );        // compression id
450     bo_add_16be( soun, 0 );         // packet size (0)
451     bo_add_16be( soun, p_stream->p_fmt->audio.i_rate ); // sampleratehi
452     bo_add_16be( soun, 0 );                             // sampleratelo
453
454     /* Extended data for SoundDescription V1 */
455     if( p_sys->b_mov &&
456         p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','a') )
457     {
458         /* samples per packet */
459         bo_add_32be( soun, p_stream->p_fmt->audio.i_frame_length );
460         bo_add_32be( soun, 1536 ); /* bytes per packet */
461         bo_add_32be( soun, 2 );    /* bytes per frame */
462         /* bytes per sample */
463         bo_add_32be( soun, 2 /*p_stream->p_fmt->audio.i_bitspersample/8 */);
464     }
465
466     /* Add an ES Descriptor */
467     if( b_descr )
468     {
469         bo_t *box;
470
471         if( p_sys->b_mov &&
472             p_stream->p_fmt->i_codec == VLC_FOURCC('m','p','4','a') )
473         {
474             box = GetWaveTag( p_stream );
475         }
476         else
477         {
478             box = GetESDS( p_stream );
479         }
480         box_fix( box );
481         box_gather( soun, box );
482     }
483
484     box_fix( soun );
485
486     return soun;
487 }
488
489 static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
490 {
491
492     bo_t *vide;
493     char fcc[4] = "    ";
494     int  i;
495
496     switch( p_stream->p_fmt->i_codec )
497     {
498     case VLC_FOURCC('m','p','4','v'):
499     case VLC_FOURCC('m','p','g','v'):
500         memcpy( fcc, "mp4v", 4 );
501         break;
502
503     case VLC_FOURCC('M','J','P','G'):
504         memcpy( fcc, "mjpa", 4 );
505         break;
506
507     case VLC_FOURCC('S','V','Q','3'):
508         memcpy( fcc, "SVQ3", 4 );
509         break;
510
511     default:
512         memcpy( fcc, (char*)&p_stream->p_fmt->i_codec, 4 );
513         break;
514     }
515
516     vide = box_new( fcc );
517     for( i = 0; i < 6; i++ )
518     {
519         bo_add_8( vide, 0 );        // reserved;
520     }
521     bo_add_16be( vide, 1 );         // data-reference-index
522
523     bo_add_16be( vide, 0 );         // predefined;
524     bo_add_16be( vide, 0 );         // reserved;
525     for( i = 0; i < 3; i++ )
526     {
527         bo_add_32be( vide, 0 );     // predefined;
528     }
529
530     bo_add_16be( vide, p_stream->p_fmt->video.i_width );  // i_width
531     bo_add_16be( vide, p_stream->p_fmt->video.i_height ); // i_height
532
533     bo_add_32be( vide, 0x00480000 );                // h 72dpi
534     bo_add_32be( vide, 0x00480000 );                // v 72dpi
535
536     bo_add_32be( vide, 0 );         // data size, always 0
537     bo_add_16be( vide, 1 );         // frames count per sample
538
539     // compressor name;
540     for( i = 0; i < 32; i++ )
541     {
542         bo_add_8( vide, 0 );
543     }
544
545     bo_add_16be( vide, 0x18 );      // depth
546     bo_add_16be( vide, 0xffff );    // predefined
547
548     /* add an ES Descriptor */
549     switch( p_stream->p_fmt->i_codec )
550     {
551     case VLC_FOURCC('m','p','4','v'):
552     case VLC_FOURCC('m','p','g','v'):
553         {
554             bo_t *esds = GetESDS( p_stream );
555
556             box_fix( esds );
557             box_gather( vide, esds );
558         }
559         break;
560
561     case VLC_FOURCC('S','V','Q','3'):
562         {
563             bo_t *esds = GetSVQ3Tag( p_stream );
564
565             box_fix( esds );
566             box_gather( vide, esds );
567         }
568         break;
569
570     default:
571         break;
572     }
573
574     box_fix( vide );
575
576     return vide;
577 }
578
579 static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
580 {
581     sout_mux_sys_t *p_sys = p_mux->p_sys;
582     unsigned int i_chunk, i_stsc_last_val, i_stsc_entries, i, i_index;
583     bo_t *stbl, *stsd, *stts, *stco, *stsc, *stsz;
584     uint32_t i_timescale;
585
586     stbl = box_new( "stbl" );
587     stsd = box_full_new( "stsd", 0, 0 );
588     bo_add_32be( stsd, 1 );
589
590     if( p_stream->p_fmt->i_cat == AUDIO_ES )
591     {
592         bo_t *soun = GetSounBox( p_mux, p_stream );
593         box_gather( stsd, soun );
594     }
595     else if( p_stream->p_fmt->i_cat == VIDEO_ES )
596     {
597         bo_t *vide = GetVideBox( p_mux, p_stream );
598         box_gather( stsd, vide );
599     }
600
601     /* append stsd to stbl */
602     box_fix( stsd );
603     box_gather( stbl, stsd );
604
605     /* chunk offset table */
606     p_stream->i_stco_pos = stbl->i_buffer + 16;
607     if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
608     {
609         /* 64 bits version */
610         p_stream->b_stco64 = VLC_TRUE;
611         stco = box_full_new( "co64", 0, 0 );
612     }
613     else
614     {
615         /* 32 bits version */
616         p_stream->b_stco64 = VLC_FALSE;
617         stco = box_full_new( "stco", 0, 0 );
618     }
619     bo_add_32be( stco, 0 );     // entry-count (fixed latter)
620
621     /* sample to chunk table */
622     stsc = box_full_new( "stsc", 0, 0 );
623     bo_add_32be( stsc, 0 );     // entry-count (fixed latter)
624
625     for( i_chunk = 0, i_stsc_last_val = 0, i_stsc_entries = 0, i = 0;
626          i < p_stream->i_entry_count; i_chunk++ )
627     {
628         int i_first = i;
629
630         if( p_stream->b_stco64 )
631             bo_add_64be( stco, p_stream->entry[i].i_pos );
632         else
633             bo_add_32be( stco, p_stream->entry[i].i_pos );
634
635         while( i < p_stream->i_entry_count )
636         {
637             if( i + 1 < p_stream->i_entry_count &&
638                 p_stream->entry[i].i_pos + p_stream->entry[i].i_size
639                 != p_stream->entry[i + 1].i_pos )
640             {
641                 i++;
642                 break;
643             }
644
645             i++;
646         }
647
648         /* Add entry to the stsc table */
649         if( i_stsc_last_val != i - i_first )
650         {
651             bo_add_32be( stsc, 1 + i_chunk );   // first-chunk
652             bo_add_32be( stsc, i - i_first ) ;  // samples-per-chunk
653             bo_add_32be( stsc, 1 );             // sample-descr-index
654             i_stsc_last_val = i - i_first;
655             i_stsc_entries++;
656         }
657     }
658
659     /* Fix stco entry count */
660     bo_fix_32be( stco, 12, i_chunk );
661     msg_Dbg( p_mux, "created %d chunks (stco)", i_chunk );
662
663     /* append stco to stbl */
664     box_fix( stco );
665     box_gather( stbl, stco );
666
667     /* Fix stsc entry count */
668     bo_fix_32be( stsc, 12, i_stsc_entries  );
669
670     /* append stsc to stbl */
671     box_fix( stsc );
672     box_gather( stbl, stsc );
673
674     /* add stts */
675     stts = box_full_new( "stts", 0, 0 );
676     bo_add_32be( stts, 0 );     // entry-count (fixed latter)
677
678     if( p_stream->p_fmt->i_cat == AUDIO_ES )
679         i_timescale = p_stream->p_fmt->audio.i_rate;
680     else
681         i_timescale = 1001;
682
683     for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
684     {
685         int64_t i_delta;
686         int     i_first;
687
688         i_first = i;
689         i_delta = p_stream->entry[i].i_length;
690
691         while( i < p_stream->i_entry_count )
692         {
693             if( i + 1 < p_stream->i_entry_count &&
694                 p_stream->entry[i + 1].i_length != i_delta )
695             {
696                 i++;
697                 break;
698             }
699
700             i++;
701         }
702
703         bo_add_32be( stts, i - i_first );           // sample-count
704         bo_add_32be( stts, i_delta * (int64_t)i_timescale /
705                      (int64_t)1000000 );            // sample-delta
706     }
707     bo_fix_32be( stts, 12, i_index );
708
709     /* append stts to stbl */
710     box_fix( stts );
711     box_gather( stbl, stts );
712
713     /* FIXME add ctts ?? FIXME */
714
715     stsz = box_full_new( "stsz", 0, 0 );
716     bo_add_32be( stsz, 0 );                             // sample-size
717     bo_add_32be( stsz, p_stream->i_entry_count );       // sample-count
718     for( i = 0; i < p_stream->i_entry_count; i++ )
719     {
720         bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
721     }
722     /* append stsz to stbl */
723     box_fix( stsz );
724     box_gather( stbl, stsz );
725
726     box_fix( stbl );
727
728     return stbl;
729 }
730
731 static uint32_t mvhd_matrix[9] =
732     { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
733
734 static bo_t *GetMoovBox( sout_mux_t *p_mux )
735 {
736     sout_mux_sys_t *p_sys = p_mux->p_sys;
737
738     bo_t            *moov, *mvhd;
739     int             i_trak, i;
740
741     uint32_t        i_movie_timescale = 90000;
742     int64_t         i_movie_duration  = 0;
743
744     moov = box_new( "moov" );
745
746     /* Create general info */
747     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
748     {
749         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
750         i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration );
751     }
752     msg_Dbg( p_mux, "movie duration %ds",
753              (uint32_t)( i_movie_duration / (mtime_t)1000000 ) );
754
755     i_movie_duration = i_movie_duration * i_movie_timescale / 1000000;
756
757     /* *** add /moov/mvhd *** */
758     if( !p_sys->b_64_ext )
759     {
760         mvhd = box_full_new( "mvhd", 0, 0 );
761         bo_add_32be( mvhd, get_timestamp() );   // creation time
762         bo_add_32be( mvhd, get_timestamp() );   // modification time
763         bo_add_32be( mvhd, i_movie_timescale);  // timescale
764         bo_add_32be( mvhd, i_movie_duration );  // duration
765     }
766     else
767     {
768         mvhd = box_full_new( "mvhd", 1, 0 );
769         bo_add_64be( mvhd, get_timestamp() );   // creation time
770         bo_add_64be( mvhd, get_timestamp() );   // modification time
771         bo_add_32be( mvhd, i_movie_timescale);  // timescale
772         bo_add_64be( mvhd, i_movie_duration );  // duration
773     }
774     bo_add_32be( mvhd, 0x10000 );           // rate
775     bo_add_16be( mvhd, 0x100 );             // volume
776     bo_add_16be( mvhd, 0 );                 // reserved
777     for( i = 0; i < 2; i++ )
778     {
779         bo_add_32be( mvhd, 0 );             // reserved
780     }
781     for( i = 0; i < 9; i++ )
782     {
783         bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
784     }
785     for( i = 0; i < 6; i++ )
786     {
787         bo_add_32be( mvhd, 0 );             // pre-defined
788     }
789
790     /* Next available track id */
791     bo_add_32be( mvhd, p_sys->i_nb_streams + 1 ); // next-track-id
792
793     box_fix( mvhd );
794     box_gather( moov, mvhd );
795
796     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
797     {
798         mp4_stream_t *p_stream;
799         uint32_t     i_timescale;
800
801         bo_t *trak, *tkhd, *mdia, *mdhd, *hdlr;
802         bo_t *minf, *dinf, *dref, *url, *stbl;
803
804         p_stream = p_sys->pp_streams[i_trak];
805
806         if( p_stream->p_fmt->i_cat != AUDIO_ES &&
807             p_stream->p_fmt->i_cat != VIDEO_ES )
808         {
809             msg_Err( p_mux, "FIXME ignoring trak (noaudio&&novideo)" );
810             continue;
811         }
812
813         if( p_stream->p_fmt->i_cat == AUDIO_ES )
814             i_timescale = p_stream->p_fmt->audio.i_rate;
815         else
816             i_timescale = 1001;
817
818         /* *** add /moov/trak *** */
819         trak = box_new( "trak" );
820
821         /* *** add /moov/trak/tkhd *** */
822         if( !p_sys->b_64_ext )
823         {
824             if( p_sys->b_mov )
825                 tkhd = box_full_new( "tkhd", 0, 0x0f );
826             else
827                 tkhd = box_full_new( "tkhd", 0, 1 );
828
829             bo_add_32be( tkhd, get_timestamp() );       // creation time
830             bo_add_32be( tkhd, get_timestamp() );       // modification time
831             bo_add_32be( tkhd, p_stream->i_track_id );
832             bo_add_32be( tkhd, 0 );                     // reserved 0
833             bo_add_32be( tkhd, p_stream->i_duration *
834                          (int64_t)i_movie_timescale /
835                          (mtime_t)1000000 );            // duration
836         }
837         else
838         {
839             if( p_sys->b_mov )
840                 tkhd = box_full_new( "tkhd", 1, 0x0f );
841             else
842                 tkhd = box_full_new( "tkhd", 1, 1 );
843
844             bo_add_64be( tkhd, get_timestamp() );       // creation time
845             bo_add_64be( tkhd, get_timestamp() );       // modification time
846             bo_add_32be( tkhd, p_stream->i_track_id );
847             bo_add_32be( tkhd, 0 );                     // reserved 0
848             bo_add_64be( tkhd, p_stream->i_duration *
849                          (int64_t)i_movie_timescale /
850                          (mtime_t)1000000 );            // duration
851         }
852
853         for( i = 0; i < 2; i++ )
854         {
855             bo_add_32be( tkhd, 0 );                 // reserved
856         }
857         bo_add_16be( tkhd, 0 );                     // layer
858         bo_add_16be( tkhd, 0 );                     // pre-defined
859         // volume
860         bo_add_16be( tkhd, p_stream->p_fmt->i_cat == AUDIO_ES ? 0x100 : 0 );
861         bo_add_16be( tkhd, 0 );                     // reserved
862         for( i = 0; i < 9; i++ )
863         {
864             bo_add_32be( tkhd, mvhd_matrix[i] );    // matrix
865         }
866         if( p_stream->p_fmt->i_cat == AUDIO_ES )
867         {
868             bo_add_32be( tkhd, 0 );                 // width (presentation)
869             bo_add_32be( tkhd, 0 );                 // height(presentation)
870         }
871         else
872         {
873             // width (presentation)
874             bo_add_32be( tkhd, p_stream->p_fmt->video.i_aspect *
875                          p_stream->p_fmt->video.i_height /
876                          VOUT_ASPECT_FACTOR << 16 );
877             // height(presentation)
878             bo_add_32be( tkhd, p_stream->p_fmt->video.i_height << 16 );
879         }
880         box_fix( tkhd );
881         box_gather( trak, tkhd );
882
883         /* *** add /moov/trak/mdia *** */
884         mdia = box_new( "mdia" );
885
886         /* media header */
887         if( !p_sys->b_64_ext )
888         {
889             mdhd = box_full_new( "mdhd", 0, 0 );
890             bo_add_32be( mdhd, get_timestamp() );   // creation time
891             bo_add_32be( mdhd, get_timestamp() );   // modification time
892             bo_add_32be( mdhd, i_timescale);        // timescale
893             bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
894                                (mtime_t)1000000 );  // duration
895         }
896         else
897         {
898             mdhd = box_full_new( "mdhd", 1, 0 );
899             bo_add_64be( mdhd, get_timestamp() );   // creation time
900             bo_add_64be( mdhd, get_timestamp() );   // modification time
901             bo_add_32be( mdhd, i_timescale);        // timescale
902             bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
903                                (mtime_t)1000000 );  // duration
904         }
905
906         bo_add_16be( mdhd, 0    );              // language   FIXME
907         bo_add_16be( mdhd, 0    );              // predefined
908         box_fix( mdhd );
909         box_gather( mdia, mdhd );
910
911         /* handler reference */
912         hdlr = box_full_new( "hdlr", 0, 0 );
913
914         bo_add_fourcc( hdlr, "mhlr" );         // media handler
915         if( p_stream->p_fmt->i_cat == AUDIO_ES )
916         {
917             bo_add_fourcc( hdlr, "soun" );
918         }
919         else
920         {
921             bo_add_fourcc( hdlr, "vide" );
922         }
923
924         bo_add_32be( hdlr, 0 );         // reserved
925         bo_add_32be( hdlr, 0 );         // reserved
926         bo_add_32be( hdlr, 0 );         // reserved
927
928         bo_add_8( hdlr, 12 );
929         if( p_stream->p_fmt->i_cat == AUDIO_ES )
930             bo_add_mem( hdlr, 12, "SoundHandler" );
931         else
932             bo_add_mem( hdlr, 12, "VideoHandler" );
933
934         box_fix( hdlr );
935         box_gather( mdia, hdlr );
936
937         /* minf*/
938         minf = box_new( "minf" );
939
940         /* add smhd|vmhd */
941         if( p_stream->p_fmt->i_cat == AUDIO_ES )
942         {
943             bo_t *smhd;
944
945             smhd = box_full_new( "smhd", 0, 0 );
946             bo_add_16be( smhd, 0 );     // balance
947             bo_add_16be( smhd, 0 );     // reserved
948             box_fix( smhd );
949
950             box_gather( minf, smhd );
951         }
952         else if( p_stream->p_fmt->i_cat == VIDEO_ES )
953         {
954             bo_t *vmhd;
955
956             vmhd = box_full_new( "vmhd", 0, 1 );
957             bo_add_16be( vmhd, 0 );     // graphicsmode
958             for( i = 0; i < 3; i++ )
959             {
960                 bo_add_16be( vmhd, 0 ); // opcolor
961             }
962             box_fix( vmhd );
963
964             box_gather( minf, vmhd );
965         }
966
967         /* dinf */
968         dinf = box_new( "dinf" );
969         dref = box_full_new( "dref", 0, 0 );
970         bo_add_32be( dref, 1 );
971         url = box_full_new( "url ", 0, 0x01 );
972         box_fix( url );
973         box_gather( dref, url );
974         box_fix( dref );
975         box_gather( dinf, dref );
976
977         /* append dinf to mdia */
978         box_fix( dinf );
979         box_gather( minf, dinf );
980
981         /* add stbl */
982         stbl = GetStblBox( p_mux, p_stream );
983
984         /* append stbl to minf */
985         p_stream->i_stco_pos += minf->i_buffer;
986         box_gather( minf, stbl );
987
988         /* append minf to mdia */
989         box_fix( minf );
990         p_stream->i_stco_pos += mdia->i_buffer;
991         box_gather( mdia, minf );
992
993         /* append mdia to trak */
994         box_fix( mdia );
995         p_stream->i_stco_pos += trak->i_buffer;
996         box_gather( trak, mdia );
997
998         /* append trak to moov */
999         box_fix( trak );
1000         p_stream->i_stco_pos += moov->i_buffer;
1001         box_gather( moov, trak );
1002     }
1003
1004     /* Add user data tags */
1005     box_gather( moov, GetUdtaTag( p_mux ) );
1006
1007     box_fix( moov );
1008     return moov;
1009 }
1010
1011 /*****************************************************************************
1012  * Close:
1013  *****************************************************************************/
1014 static void Close( vlc_object_t * p_this )
1015 {
1016     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
1017     sout_mux_sys_t  *p_sys = p_mux->p_sys;
1018     sout_buffer_t   *p_hdr;
1019     bo_t            bo, *moov;
1020     vlc_value_t     val;
1021
1022     int             i_trak;
1023     uint64_t        i_moov_pos;
1024
1025     msg_Dbg( p_mux, "Close" );
1026
1027     /* Update mdat size */
1028     bo_init( &bo, 0, NULL, VLC_TRUE );
1029     if( p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32) )
1030     {
1031         /* Extended size */
1032         bo_add_32be  ( &bo, 1 );
1033         bo_add_fourcc( &bo, "mdat" );
1034         bo_add_64be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos );
1035     }
1036     else
1037     {
1038         bo_add_32be  ( &bo, 8 );
1039         bo_add_fourcc( &bo, "wide" );
1040         bo_add_32be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos - 8 );
1041         bo_add_fourcc( &bo, "mdat" );
1042     }
1043     p_hdr = bo_to_sout( p_mux->p_sout, &bo );
1044     free( bo.p_buffer );
1045
1046     sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos );
1047     sout_AccessOutWrite( p_mux->p_access, p_hdr );
1048
1049     /* Create MOOV header */
1050     i_moov_pos = p_sys->i_pos;
1051     moov = GetMoovBox( p_mux );
1052
1053     /* Check we need to create "fast start" files */
1054     var_Create( p_this, "mp4-faststart", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
1055     var_Get( p_this, "mp4-faststart", &val );
1056     p_sys->b_fast_start = val.b_bool;
1057     while( p_sys->b_fast_start )
1058     {
1059         /* Move data to the end of the file so we can fit the moov header
1060          * at the start */
1061         sout_buffer_t *p_buf;
1062         int64_t i_chunk, i_size = p_sys->i_pos - p_sys->i_mdat_pos;
1063         int i_moov_size = moov->i_buffer;
1064
1065         while( i_size > 0 )
1066         {
1067             i_chunk = __MIN( 32768, i_size );
1068             p_buf = sout_BufferNew( p_mux->p_sout, i_chunk );
1069             sout_AccessOutSeek( p_mux->p_access,
1070                                 p_sys->i_mdat_pos + i_size - i_chunk );
1071             if( sout_AccessOutRead( p_mux->p_access, p_buf ) < i_chunk )
1072             {
1073                 msg_Warn( p_this, "read() not supported by acces output, "
1074                           "won't create a fast start file" );
1075                 p_sys->b_fast_start = VLC_FALSE;
1076                 break;
1077             }
1078             sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos + i_size +
1079                                 i_moov_size - i_chunk );
1080             sout_AccessOutWrite( p_mux->p_access, p_buf );
1081             i_size -= i_chunk;
1082         }
1083
1084         if( !p_sys->b_fast_start ) break;
1085
1086         /* Fix-up samples to chunks table in MOOV header */
1087         for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1088         {
1089             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1090             unsigned int i;
1091             int i_chunk;
1092
1093             moov->i_buffer = p_stream->i_stco_pos;
1094             for( i_chunk = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ )
1095             {
1096                 if( p_stream->b_stco64 )
1097                     bo_add_64be( moov, p_stream->entry[i].i_pos + i_moov_size);
1098                 else
1099                     bo_add_32be( moov, p_stream->entry[i].i_pos + i_moov_size);
1100
1101                 while( i < p_stream->i_entry_count )
1102                 {
1103                     if( i + 1 < p_stream->i_entry_count &&
1104                         p_stream->entry[i].i_pos + p_stream->entry[i].i_size
1105                         != p_stream->entry[i + 1].i_pos )
1106                     {
1107                         i++;
1108                         break;
1109                     }
1110
1111                     i++;
1112                 }
1113             }
1114         }
1115
1116         moov->i_buffer = i_moov_size;
1117         i_moov_pos = p_sys->i_mdat_pos;
1118         p_sys->b_fast_start = VLC_FALSE;
1119     }
1120
1121     /* Write MOOV header */
1122     sout_AccessOutSeek( p_mux->p_access, i_moov_pos );
1123     box_send( p_mux, moov );
1124
1125     /* Clean-up */
1126     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
1127     {
1128         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
1129
1130         if( p_stream->p_fmt->p_extra )
1131         {
1132             free( p_stream->p_fmt->p_extra );
1133         }
1134         free( p_stream->p_fmt );
1135         free( p_stream->entry );
1136         free( p_stream );
1137     }
1138     if( p_sys->i_nb_streams ) free( p_sys->pp_streams );
1139     free( p_sys );
1140 }
1141
1142 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
1143                        void *p_answer )
1144 {
1145    switch( i_query )
1146    {
1147         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
1148             *(vlc_bool_t*)p_answer = VLC_FALSE;
1149             return( SOUT_MUX_CAP_ERR_OK );
1150         default:
1151             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
1152    }
1153 }
1154
1155 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
1156 {
1157     sout_mux_sys_t  *p_sys = p_mux->p_sys;
1158     mp4_stream_t    *p_stream;
1159
1160     switch( p_input->p_fmt->i_codec )
1161     {
1162         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
1163         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
1164         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
1165         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
1166         case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
1167         case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
1168         case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
1169             break;
1170         default:
1171             msg_Err( p_mux, "unsupported codec %4.4s in mp4",
1172                      (char*)&p_input->p_fmt->i_codec );
1173             return VLC_EGENERIC;
1174     }
1175
1176     p_stream                = malloc( sizeof( mp4_stream_t ) );
1177     p_stream->p_fmt         = malloc( sizeof( es_format_t ) );
1178     memcpy( p_stream->p_fmt, p_input->p_fmt, sizeof( es_format_t ) );
1179     if( p_stream->p_fmt->i_extra )
1180     {
1181         p_stream->p_fmt->p_extra =
1182             malloc( p_stream->p_fmt->i_extra );
1183         memcpy( p_stream->p_fmt->p_extra,
1184                 p_input->p_fmt->p_extra,
1185                 p_input->p_fmt->i_extra );
1186     }
1187     p_stream->i_track_id    = p_sys->i_nb_streams + 1;
1188     p_stream->i_entry_count = 0;
1189     p_stream->i_entry_max   = 1000;
1190     p_stream->entry         =
1191         calloc( p_stream->i_entry_max, sizeof( mp4_entry_t ) );
1192     p_stream->i_duration    = 0;
1193
1194     p_input->p_sys          = p_stream;
1195
1196     msg_Dbg( p_mux, "adding input" );
1197
1198     TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, p_stream );
1199     return VLC_SUCCESS;
1200 }
1201
1202 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
1203 {
1204     msg_Dbg( p_mux, "removing input" );
1205     return VLC_SUCCESS;
1206 }
1207
1208 /****************************************************************************/
1209
1210 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
1211 {
1212     mtime_t i_dts;
1213     int     i_stream;
1214     int     i;
1215
1216     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
1217     {
1218         sout_fifo_t  *p_fifo;
1219
1220         p_fifo = p_mux->pp_inputs[i]->p_fifo;
1221
1222         if( p_fifo->i_depth > 1 )
1223         {
1224             sout_buffer_t *p_buf;
1225
1226             p_buf = sout_FifoShow( p_fifo );
1227             if( i_stream < 0 || p_buf->i_dts < i_dts )
1228             {
1229                 i_dts = p_buf->i_dts;
1230                 i_stream = i;
1231             }
1232         }
1233         else
1234         {
1235             return( -1 ); // wait that all fifo have at least 2 packets
1236         }
1237     }
1238     if( pi_stream )
1239     {
1240         *pi_stream = i_stream;
1241     }
1242     if( pi_dts )
1243     {
1244         *pi_dts = i_dts;
1245     }
1246     return( i_stream );
1247 }
1248
1249 static int Mux( sout_mux_t *p_mux )
1250 {
1251     sout_mux_sys_t *p_sys = p_mux->p_sys;
1252
1253     for( ;; )
1254     {
1255         sout_input_t    *p_input;
1256         int             i_stream;
1257         mp4_stream_t    *p_stream;
1258         sout_buffer_t   *p_data;
1259         mtime_t         i_dts;
1260
1261         if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
1262         {
1263             return( VLC_SUCCESS );
1264         }
1265
1266         if( !p_sys->i_start_dts )
1267             p_sys->i_start_dts = i_dts;
1268
1269         p_input  = p_mux->pp_inputs[i_stream];
1270         p_stream = (mp4_stream_t*)p_input->p_sys;
1271
1272         p_data  = sout_FifoGet( p_input->p_fifo );
1273
1274         /* add index entry */
1275         p_stream->entry[p_stream->i_entry_count].i_pos   = p_sys->i_pos;
1276         p_stream->entry[p_stream->i_entry_count].i_size  = p_data->i_size;
1277         p_stream->entry[p_stream->i_entry_count].i_pts   = p_data->i_pts;
1278         p_stream->entry[p_stream->i_entry_count].i_dts   = p_data->i_dts;
1279         p_stream->entry[p_stream->i_entry_count].i_length=
1280             __MAX( p_data->i_length, 0 );
1281
1282         if( p_stream->i_entry_count == 0 )
1283         {
1284             /* Here is another bad hack.
1285              * To make sure audio/video are in sync, we report a corrected
1286              * length for the 1st sample. */
1287             p_stream->entry[p_stream->i_entry_count].i_length =
1288                 __MAX( p_data->i_length, 0 ) +
1289                 p_data->i_pts - p_sys->i_start_dts;
1290         }
1291
1292         p_stream->i_entry_count++;
1293         if( p_stream->i_entry_count >= p_stream->i_entry_max )
1294         {
1295             p_stream->i_entry_max += 1000;
1296             p_stream->entry =
1297                 realloc( p_stream->entry,
1298                          p_stream->i_entry_max * sizeof( mp4_entry_t ) );
1299         }
1300
1301         /* update */
1302         p_stream->i_duration += __MAX( p_data->i_length, 0 );
1303         p_sys->i_pos += p_data->i_size;
1304
1305         /* write data */
1306         sout_AccessOutWrite( p_mux->p_access, p_data );
1307     }
1308
1309     return( VLC_SUCCESS );
1310 }
1311
1312
1313 /****************************************************************************/
1314
1315 static void bo_init( bo_t *p_bo, int i_size, uint8_t *p_buffer,
1316                      vlc_bool_t b_grow )
1317 {
1318     if( !p_buffer )
1319     {
1320         p_bo->i_buffer_size = __MAX( i_size, 1024 );
1321         p_bo->p_buffer = malloc( p_bo->i_buffer_size );
1322     }
1323     else
1324     {
1325         p_bo->i_buffer_size = i_size;
1326         p_bo->p_buffer = p_buffer;
1327     }
1328
1329     p_bo->b_grow = b_grow;
1330     p_bo->i_buffer = 0;
1331 }
1332
1333 static void bo_add_8( bo_t *p_bo, uint8_t i )
1334 {
1335     if( p_bo->i_buffer < p_bo->i_buffer_size )
1336     {
1337         p_bo->p_buffer[p_bo->i_buffer] = i;
1338     }
1339     else if( p_bo->b_grow )
1340     {
1341         p_bo->i_buffer_size += 1024;
1342         p_bo->p_buffer = realloc( p_bo->p_buffer, p_bo->i_buffer_size );
1343
1344         p_bo->p_buffer[p_bo->i_buffer] = i;
1345     }
1346
1347     p_bo->i_buffer++;
1348 }
1349
1350 static void bo_add_16be( bo_t *p_bo, uint16_t i )
1351 {
1352     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1353     bo_add_8( p_bo, i &0xff );
1354 }
1355
1356 static void bo_add_24be( bo_t *p_bo, uint32_t i )
1357 {
1358     bo_add_8( p_bo, ( ( i >> 16) &0xff ) );
1359     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1360     bo_add_8( p_bo, (   i &0xff ) );
1361 }
1362 static void bo_add_32be( bo_t *p_bo, uint32_t i )
1363 {
1364     bo_add_16be( p_bo, ( ( i >> 16) &0xffff ) );
1365     bo_add_16be( p_bo, i &0xffff );
1366 }
1367
1368 static void bo_fix_32be ( bo_t *p_bo, int i_pos, uint32_t i)
1369 {
1370     p_bo->p_buffer[i_pos    ] = ( i >> 24 )&0xff;
1371     p_bo->p_buffer[i_pos + 1] = ( i >> 16 )&0xff;
1372     p_bo->p_buffer[i_pos + 2] = ( i >>  8 )&0xff;
1373     p_bo->p_buffer[i_pos + 3] = ( i       )&0xff;
1374 }
1375
1376 static void bo_add_64be( bo_t *p_bo, uint64_t i )
1377 {
1378     bo_add_32be( p_bo, ( ( i >> 32) &0xffffffff ) );
1379     bo_add_32be( p_bo, i &0xffffffff );
1380 }
1381
1382 static void bo_add_fourcc( bo_t *p_bo, char *fcc )
1383 {
1384     bo_add_8( p_bo, fcc[0] );
1385     bo_add_8( p_bo, fcc[1] );
1386     bo_add_8( p_bo, fcc[2] );
1387     bo_add_8( p_bo, fcc[3] );
1388 }
1389
1390 static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem )
1391 {
1392     int i;
1393
1394     for( i = 0; i < i_size; i++ )
1395     {
1396         bo_add_8( p_bo, p_mem[i] );
1397     }
1398 }
1399
1400 static void bo_add_descr( bo_t *p_bo, uint8_t tag, uint32_t i_size )
1401 {
1402     uint32_t i_length;
1403     uint8_t  vals[4];
1404
1405     i_length = i_size;
1406     vals[3] = (unsigned char)(i_length & 0x7f);
1407     i_length >>= 7;
1408     vals[2] = (unsigned char)((i_length & 0x7f) | 0x80); 
1409     i_length >>= 7;
1410     vals[1] = (unsigned char)((i_length & 0x7f) | 0x80); 
1411     i_length >>= 7;
1412     vals[0] = (unsigned char)((i_length & 0x7f) | 0x80);
1413
1414     bo_add_8( p_bo, tag );
1415
1416     if( i_size < 0x00000080 )
1417     {
1418         bo_add_8( p_bo, vals[3] );
1419     }
1420     else if( i_size < 0x00004000 )
1421     {
1422         bo_add_8( p_bo, vals[2] );
1423         bo_add_8( p_bo, vals[3] );
1424     }
1425     else if( i_size < 0x00200000 )
1426     {
1427         bo_add_8( p_bo, vals[1] );
1428         bo_add_8( p_bo, vals[2] );
1429         bo_add_8( p_bo, vals[3] );
1430     }
1431     else if( i_size < 0x10000000 )
1432     {
1433         bo_add_8( p_bo, vals[0] );
1434         bo_add_8( p_bo, vals[1] );
1435         bo_add_8( p_bo, vals[2] );
1436         bo_add_8( p_bo, vals[3] );
1437     }
1438 }
1439
1440 static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
1441 {
1442     int i;
1443
1444     for( i = 0; i < p_bo2->i_buffer; i++ )
1445     {
1446         bo_add_8( p_bo, p_bo2->p_buffer[i] );
1447     }
1448 }
1449
1450 static bo_t * box_new( char *fcc )
1451 {
1452     bo_t *box;
1453
1454     if( ( box = malloc( sizeof( bo_t ) ) ) )
1455     {
1456         bo_init( box, 0, NULL, VLC_TRUE );
1457
1458         bo_add_32be  ( box, 0 );
1459         bo_add_fourcc( box, fcc );
1460     }
1461
1462     return box;
1463 }
1464
1465 static bo_t * box_full_new( char *fcc, uint8_t v, uint32_t f )
1466 {
1467     bo_t *box;
1468
1469     if( ( box = malloc( sizeof( bo_t ) ) ) )
1470     {
1471         bo_init( box, 0, NULL, VLC_TRUE );
1472
1473         bo_add_32be  ( box, 0 );
1474         bo_add_fourcc( box, fcc );
1475         bo_add_8     ( box, v );
1476         bo_add_24be  ( box, f );
1477     }
1478
1479     return box;
1480 }
1481
1482 static void box_fix( bo_t *box )
1483 {
1484     bo_t box_tmp;
1485
1486     memcpy( &box_tmp, box, sizeof( bo_t ) );
1487
1488     box_tmp.i_buffer = 0;
1489     bo_add_32be( &box_tmp, box->i_buffer );
1490 }
1491
1492 static void box_free( bo_t *box )
1493 {
1494     if( box->p_buffer )
1495     {
1496         free( box->p_buffer );
1497     }
1498
1499     free( box );
1500 }
1501
1502 static void box_gather ( bo_t *box, bo_t *box2 )
1503 {
1504     bo_add_bo( box, box2 );
1505     box_free( box2 );
1506 }
1507
1508 static sout_buffer_t * bo_to_sout( sout_instance_t *p_sout,  bo_t *box )
1509 {
1510     sout_buffer_t *p_buf;
1511
1512     p_buf = sout_BufferNew( p_sout, box->i_buffer );
1513     if( box->i_buffer > 0 )
1514     {
1515         memcpy( p_buf->p_buffer, box->p_buffer, box->i_buffer );
1516     }
1517
1518     p_buf->i_size = box->i_buffer;
1519
1520     return p_buf;
1521 }
1522
1523 static void box_send( sout_mux_t *p_mux,  bo_t *box )
1524 {
1525     sout_buffer_t *p_buf;
1526
1527     p_buf = bo_to_sout( p_mux->p_sout, box );
1528     box_free( box );
1529
1530     sout_AccessOutWrite( p_mux->p_access, p_buf );
1531 }
1532
1533 static int64_t get_timestamp()
1534 {
1535     int64_t i_timestamp = 0;
1536
1537 #ifdef HAVE_TIME_H
1538     i_timestamp = time(NULL);
1539     i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
1540     // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
1541 #endif
1542
1543     return i_timestamp;
1544 }