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