]> git.sesse.net Git - vlc/blob - modules/mux/mp4.c
* modules/mux/mp4.c: support for mov muxing + cleanup.
[vlc] / modules / mux / mp4.c
1 /*****************************************************************************
2  * mp4.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002, 2003 VideoLAN
5  * $Id: mp4.c,v 1.3 2003/08/01 20:06:43 gbazin Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/sout.h>
34
35 #ifdef HAVE_TIME_H
36 #include <time.h>
37 #endif
38
39 #include "codecs.h"
40
41 /*****************************************************************************
42  * Exported prototypes
43  *****************************************************************************/
44 static int     Open   ( vlc_object_t * );
45 static void    Close  ( vlc_object_t * );
46
47 static int Capability(sout_mux_t *, int, void *, void * );
48 static int AddStream( sout_mux_t *, sout_input_t * );
49 static int DelStream( sout_mux_t *, sout_input_t * );
50 static int Mux      ( sout_mux_t * );
51
52 /*****************************************************************************
53  * Module descriptor
54  *****************************************************************************/
55 vlc_module_begin();
56     set_description( _("MP4/MOV muxer") );
57     set_capability( "sout mux", 5 );
58     add_shortcut( "mp4" );
59     add_shortcut( "mov" );
60     set_callbacks( Open, Close );
61 vlc_module_end();
62
63 typedef struct
64 {
65     uint64_t i_pos;
66     int      i_size;
67
68     mtime_t  i_pts;
69     mtime_t  i_dts;
70     mtime_t  i_length;
71
72 } mp4_entry_t;
73
74 typedef struct
75 {
76     sout_format_t *p_fmt;
77     int           i_track_id;
78
79     /* index */
80     unsigned int i_entry_count;
81     unsigned int i_entry_max;
82     mp4_entry_t  *entry;
83
84     /* stats */
85     mtime_t      i_duration;
86 } mp4_stream_t;
87
88 struct sout_mux_sys_t
89 {
90     vlc_bool_t b_mov;
91
92     uint64_t i_mdat_pos;
93     uint64_t i_pos;
94
95     int          i_nb_streams;
96     mp4_stream_t **pp_streams;
97 };
98
99
100 typedef struct bo_t bo_t;
101 struct bo_t
102 {
103     vlc_bool_t b_grow;
104
105     int        i_buffer_size;
106     int        i_buffer;
107     uint8_t    *p_buffer;
108
109 };
110
111 static void bo_init     ( bo_t *, int , uint8_t *, vlc_bool_t  );
112 static void bo_add_8    ( bo_t *, uint8_t );
113 static void bo_add_16be ( bo_t *, uint16_t );
114 static void bo_add_24be ( bo_t *, uint32_t );
115 static void bo_add_32be ( bo_t *, uint32_t );
116 static void bo_add_64be ( bo_t *, uint64_t );
117 static void bo_add_fourcc(bo_t *, char * );
118 static void bo_add_bo   ( bo_t *, bo_t * );
119 static void bo_add_mem  ( bo_t *, int , uint8_t * );
120
121 static void bo_fix_32be ( bo_t *, int , uint32_t );
122
123 static bo_t *box_new     ( char *fcc );
124 static bo_t *box_full_new( char *fcc, uint8_t v, uint32_t f );
125 static void  box_fix     ( bo_t *box );
126 static void  box_free    ( bo_t *box );
127 static void  box_gather  ( bo_t *box, bo_t *box2 );
128
129 static void box_send( sout_mux_t *p_mux,  bo_t *box );
130
131 static int64_t get_timestamp();
132
133 static sout_buffer_t * bo_to_sout( sout_instance_t *p_sout,  bo_t *box );
134
135 /*****************************************************************************
136  * Open:
137  *****************************************************************************/
138 static int Open( vlc_object_t *p_this )
139 {
140     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
141     sout_mux_sys_t  *p_sys;
142     bo_t            *box;
143
144     p_sys = malloc( sizeof( sout_mux_sys_t ) );
145     p_sys->i_pos        = 0;
146     p_sys->i_nb_streams = 0;
147     p_sys->pp_streams   = NULL;
148     p_sys->i_mdat_pos   = 0;
149     p_sys->b_mov        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" );
150
151     msg_Info( p_mux, "Open" );
152
153     p_mux->pf_capacity  = Capability;
154     p_mux->pf_addstream = AddStream;
155     p_mux->pf_delstream = DelStream;
156     p_mux->pf_mux       = Mux;
157     p_mux->p_sys        = p_sys;
158
159     if( !p_sys->b_mov )
160     {
161         /* Now add ftyp header */
162         box = box_new( "ftyp" );
163         bo_add_fourcc( box, "isom" );
164         bo_add_32be  ( box, 0 );
165         bo_add_fourcc( box, "mp41" );
166         box_fix( box );
167
168         p_sys->i_pos += box->i_buffer;
169         p_sys->i_mdat_pos = p_sys->i_pos;
170
171         box_send( p_mux, box );
172     }
173
174     /* Now add mdat header */
175     box = box_new( "mdat" );
176     bo_add_64be  ( box, 0 ); // enough to store an extended size
177
178     p_sys->i_pos += box->i_buffer;
179
180     box_send( p_mux, box );
181
182     return VLC_SUCCESS;
183 }
184
185 static uint32_t GetDescriptorLength24b( int i_length )
186 {
187     uint32_t    i_l1, i_l2, i_l3;
188
189     i_l1 = i_length&0x7f;
190     i_l2 = ( i_length >> 7 )&0x7f;
191     i_l3 = ( i_length >> 14 )&0x7f;
192
193     return( 0x808000 | ( i_l3 << 16 ) | ( i_l2 << 8 ) | i_l1 );
194 }
195
196 static bo_t *GetESDS( mp4_stream_t *p_stream )
197 {
198     bo_t *esds;
199     int  i_stream_type;
200     int  i_object_type_indication;
201     int  i_decoder_specific_info_size;
202
203     if( p_stream->p_fmt->i_extra_data > 0 )
204     {
205         i_decoder_specific_info_size = p_stream->p_fmt->i_extra_data + 4;
206     }
207     else
208     {
209         i_decoder_specific_info_size = 0;
210     }
211
212     esds = box_full_new( "esds", 0, 0 );
213
214     bo_add_8   ( esds, 0x03 );      // ES_DescrTag
215     bo_add_24be( esds,
216                  GetDescriptorLength24b( 25 + i_decoder_specific_info_size ) );
217     bo_add_16be( esds, p_stream->i_track_id );
218     bo_add_8   ( esds, 0x1f );      // flags=0|streamPriority=0x1f
219
220     bo_add_8   ( esds, 0x04 );      // DecoderConfigDescrTag
221     bo_add_24be( esds,
222                  GetDescriptorLength24b( 13 + i_decoder_specific_info_size ) );
223
224     switch( p_stream->p_fmt->i_fourcc )
225     {
226         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
227             i_object_type_indication = 0x20;
228             break;
229         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
230             /* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
231             i_object_type_indication = 0x60;
232             break;
233         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
234             /* FIXME for mpeg2-aac == 0x66->0x68 */
235             i_object_type_indication = 0x40;
236             break;
237         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
238             i_object_type_indication =
239                 p_stream->p_fmt->i_sample_rate < 32000 ? 0x69 : 0x6b;
240             break;
241         default:
242             i_object_type_indication = 0x00;
243             break;
244     }
245     i_stream_type = p_stream->p_fmt->i_cat == VIDEO_ES ? 0x04 : 0x05;
246
247     bo_add_8   ( esds, i_object_type_indication );
248     bo_add_8   ( esds, ( i_stream_type << 2 ) | 1 );
249     bo_add_24be( esds, 1024 * 1024 );       // bufferSizeDB
250     bo_add_32be( esds, 0x7fffffff );        // maxBitrate
251     bo_add_32be( esds, 0 );                 // avgBitrate
252
253     if( p_stream->p_fmt->i_extra_data > 0 )
254     {
255         int i;
256         bo_add_8   ( esds, 0x05 );  // DecoderSpecificInfo
257         bo_add_24be( esds,
258                      GetDescriptorLength24b( p_stream->p_fmt->i_extra_data ) );
259
260         for( i = 0; i < p_stream->p_fmt->i_extra_data; i++ )
261         {
262             bo_add_8( esds, p_stream->p_fmt->p_extra_data[i] );
263         }
264     }
265
266     /* SL_Descr mandatory */
267     bo_add_8   ( esds, 0x06 );  // SLConfigDescriptorTag
268     bo_add_24be( esds, GetDescriptorLength24b( 1 ) );
269     bo_add_8   ( esds, 0x02 );  // sl_predefined
270
271     box_fix( esds );
272
273     return esds;
274 }
275
276 /*****************************************************************************
277  * Close:
278  *****************************************************************************/
279 static uint32_t mvhd_matrix[9] =
280     { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
281
282 static void Close( vlc_object_t * p_this )
283 {
284     sout_mux_t *p_mux = (sout_mux_t*)p_this;
285     sout_mux_sys_t  *p_sys = p_mux->p_sys;
286     sout_buffer_t   *p_hdr;
287     bo_t            bo;
288     bo_t            *moov, *mvhd;
289     unsigned int    i;
290     int             i_trak, i_index;
291
292     uint32_t        i_movie_timescale = 90000;
293     int64_t         i_movie_duration  = 0;
294     msg_Info( p_mux, "Close" );
295
296     /* create general info */
297     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
298     {
299         mp4_stream_t *p_stream;
300
301         p_stream = p_sys->pp_streams[i_trak];
302
303         i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration );
304     }
305     msg_Dbg( p_mux, "movie duration %ds",
306              (uint32_t)( i_movie_duration / (mtime_t)1000000 ) );
307
308     i_movie_duration = i_movie_duration *
309                        (int64_t)i_movie_timescale / (int64_t)1000000;
310
311     /* *** update mdat size *** */
312     bo_init      ( &bo, 0, NULL, VLC_TRUE );
313     if( p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32) )
314     {
315         /* Extended size */
316         bo_add_32be  ( &bo, 1 );
317         bo_add_fourcc( &bo, "mdat" );
318         bo_add_64be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos );
319     }
320     else
321     {
322         bo_add_32be  ( &bo, 8 );
323         bo_add_fourcc( &bo, "wide" );
324         bo_add_32be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos - 8 );
325         bo_add_fourcc( &bo, "mdat" );
326     }
327
328     p_hdr = bo_to_sout( p_mux->p_sout, &bo );
329     free( bo.p_buffer );
330
331     /* seek to mdat */
332     sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos );
333     sout_AccessOutWrite( p_mux->p_access, p_hdr );
334
335     /* Now create header */
336     sout_AccessOutSeek( p_mux->p_access, p_sys->i_pos );
337
338     moov = box_new( "moov" );
339
340     /* *** add /moov/mvhd *** */
341     if( p_sys->b_mov )
342     {
343         mvhd = box_full_new( "mvhd", 0, 0 );
344         bo_add_32be( mvhd, get_timestamp() );   // creation time
345         bo_add_32be( mvhd, get_timestamp() );   // modification time
346         bo_add_32be( mvhd, i_movie_timescale);  // timescale
347         bo_add_32be( mvhd, i_movie_duration );  // duration
348     }
349     else
350     {
351         mvhd = box_full_new( "mvhd", 1, 0 );
352         bo_add_64be( mvhd, get_timestamp() );   // creation time
353         bo_add_64be( mvhd, get_timestamp() );   // modification time
354         bo_add_32be( mvhd, i_movie_timescale);  // timescale
355         bo_add_64be( mvhd, i_movie_duration );  // duration
356     }
357     bo_add_32be( mvhd, 0x10000 );           // rate
358     bo_add_16be( mvhd, 0x100 );             // volume
359     bo_add_16be( mvhd, 0 );                 // reserved
360     for( i = 0; i < 2; i++ )
361     {
362         bo_add_32be( mvhd, 0 );             // reserved
363     }
364     for( i = 0; i < 9; i++ )
365     {
366         bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
367     }
368     for( i = 0; i < 6; i++ )
369     {
370         bo_add_32be( mvhd, 0 );             // pre-defined
371     }
372
373     /* Find the 1st track id */
374     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
375     {
376         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
377
378         if( p_stream->p_fmt->i_cat == AUDIO_ES ||
379             p_stream->p_fmt->i_cat == VIDEO_ES )
380         {
381             /* Found it */
382             bo_add_32be( mvhd, p_stream->i_track_id ); // next-track-id
383             break;
384         }
385     }
386     if( i_trak == p_sys->i_nb_streams ) /* Just for sanity reasons */
387         bo_add_32be( mvhd, 0xffffffff );
388
389     box_fix( mvhd );
390     box_gather( moov, mvhd );
391
392     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
393     {
394         mp4_stream_t *p_stream;
395         uint32_t     i_timescale;
396         uint32_t     i_chunk_count;
397
398         bo_t *trak;
399         bo_t *tkhd;
400         bo_t *mdia;
401         bo_t *mdhd, *hdlr;
402         bo_t *minf;
403         bo_t *dinf;
404         bo_t *dref;
405         bo_t *url;
406         bo_t *stbl;
407         bo_t *stsd;
408         bo_t *stts;
409         bo_t *stsz;
410
411         p_stream = p_sys->pp_streams[i_trak];
412
413         if( p_stream->p_fmt->i_cat != AUDIO_ES &&
414             p_stream->p_fmt->i_cat != VIDEO_ES )
415         {
416             msg_Err( p_mux, "FIXME ignoring trak (noaudio&&novideo)" );
417             continue;
418         }
419         if( p_stream->p_fmt->i_cat == AUDIO_ES )
420         {
421             i_timescale = p_stream->p_fmt->i_sample_rate;
422         }
423         else
424         {
425             i_timescale = 1001;
426         }
427
428         /* *** add /moov/trak *** */
429         trak = box_new( "trak" );
430
431         /* *** add /moov/trak/tkhd *** */
432         if( p_sys->b_mov )
433         {
434             tkhd = box_full_new( "tkhd", 0, 1 );
435             bo_add_32be( tkhd, get_timestamp() );       // creation time
436             bo_add_32be( tkhd, get_timestamp() );       // modification time
437             bo_add_32be( tkhd, p_stream->i_track_id );
438             bo_add_32be( tkhd, 0 );                     // reserved 0
439             bo_add_32be( tkhd, p_stream->i_duration *
440                          (int64_t)i_movie_timescale /
441                          (mtime_t)1000000 );            // duration
442         }
443         else
444         {
445             tkhd = box_full_new( "tkhd", 1, 1 );
446             bo_add_64be( tkhd, get_timestamp() );       // creation time
447             bo_add_64be( tkhd, get_timestamp() );       // modification time
448             bo_add_32be( tkhd, p_stream->i_track_id );
449             bo_add_32be( tkhd, 0 );                     // reserved 0
450             bo_add_64be( tkhd, p_stream->i_duration *
451                          (int64_t)i_movie_timescale /
452                          (mtime_t)1000000 );            // duration
453         }
454
455         for( i = 0; i < 2; i++ )
456         {
457             bo_add_32be( tkhd, 0 );                 // reserved
458         }
459         bo_add_16be( tkhd, 0 );                     // layer
460         bo_add_16be( tkhd, 0 );                     // pre-defined
461         bo_add_16be( tkhd, p_stream->p_fmt->i_cat == AUDIO_ES ? 0x100 : 0 ); // volume
462         bo_add_16be( tkhd, 0 );                     // reserved
463         for( i = 0; i < 9; i++ )
464         {
465             bo_add_32be( tkhd, mvhd_matrix[i] );    // matrix
466         }
467         if( p_stream->p_fmt->i_cat == AUDIO_ES )
468         {
469             bo_add_32be( tkhd, 0 );                 // width (presentation)
470             bo_add_32be( tkhd, 0 );                 // height(presentation)
471         }
472         else
473         {
474             bo_add_32be( tkhd, p_stream->p_fmt->i_width  << 16 );     // width (presentation)
475             bo_add_32be( tkhd, p_stream->p_fmt->i_height << 16 );     // height(presentation)
476         }
477         box_fix( tkhd );
478         box_gather( trak, tkhd );
479
480         /* *** add /moov/trak/mdia *** */
481         mdia = box_new( "mdia" );
482
483         /* */
484         if( p_sys->b_mov )
485         {
486             mdhd = box_full_new( "mdhd", 0, 0 );
487             bo_add_32be( mdhd, get_timestamp() );   // creation time
488             bo_add_32be( mdhd, get_timestamp() );   // modification time
489             bo_add_32be( mdhd, i_timescale);        // timescale
490             bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
491                                (mtime_t)1000000 );  // duration
492         }
493         else
494         {
495             mdhd = box_full_new( "mdhd", 1, 0 );
496             bo_add_64be( mdhd, get_timestamp() );   // creation time
497             bo_add_64be( mdhd, get_timestamp() );   // modification time
498             bo_add_32be( mdhd, i_timescale);        // timescale
499             bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
500                                (mtime_t)1000000 );  // duration
501         }
502
503         bo_add_16be( mdhd, 0    );              // language   FIXME
504         bo_add_16be( mdhd, 0    );              // predefined
505         box_fix( mdhd );
506         box_gather( mdia, mdhd );
507
508         /* */
509         hdlr = box_full_new( "hdlr", 0, 0 );
510         bo_add_32be( hdlr, 0 );         // predefined
511         if( p_stream->p_fmt->i_cat == AUDIO_ES )
512         {
513             bo_add_fourcc( hdlr, "soun" );
514         }
515         else
516         {
517             bo_add_fourcc( hdlr, "vide" );
518         }
519         for( i = 0; i < 3; i++ )
520         {
521             bo_add_32be( hdlr, 0 );     // reserved
522         }
523         bo_add_mem( hdlr, 2, "?" );
524
525         box_fix( hdlr );
526         box_gather( mdia, hdlr );
527
528         /* minf*/
529         minf = box_new( "minf" );
530
531         /* add smhd|vmhd */
532         if( p_stream->p_fmt->i_cat == AUDIO_ES )
533         {
534             bo_t *smhd;
535
536             smhd = box_full_new( "smhd", 0, 0 );
537             bo_add_16be( smhd, 0 );     // balance
538             bo_add_16be( smhd, 0 );     // reserved
539             box_fix( smhd );
540
541             box_gather( minf, smhd );
542         }
543         else if( p_stream->p_fmt->i_cat == VIDEO_ES )
544         {
545             bo_t *vmhd;
546
547             vmhd = box_full_new( "vmhd", 0, 1 );
548             bo_add_16be( vmhd, 0 );     // graphicsmode
549             for( i = 0; i < 3; i++ )
550             {
551                 bo_add_16be( vmhd, 0 ); // opcolor
552             }
553             box_fix( vmhd );
554
555             box_gather( minf, vmhd );
556         }
557
558         /* dinf */
559         dinf = box_new( "dinf" );
560         dref = box_full_new( "dref", 0, 0 );
561         bo_add_32be( dref, 1 );
562         url = box_full_new( "url ", 0, 0x01 );
563         box_fix( url );
564         box_gather( dref, url );
565         box_fix( dref );
566         box_gather( dinf, dref );
567
568         /* append dinf to mdia */
569         box_fix( dinf );
570         box_gather( minf, dinf );
571
572         /* add stbl */
573         stbl = box_new( "stbl" );
574         stsd = box_full_new( "stsd", 0, 0 );
575         bo_add_32be( stsd, 1 );
576
577         if( p_stream->p_fmt->i_cat == AUDIO_ES )
578         {
579             bo_t *soun;
580             char fcc[4] = "    ";
581             int  i;
582             vlc_bool_t b_mpeg4_hdr;
583
584             switch( p_stream->p_fmt->i_fourcc )
585             {
586                 case VLC_FOURCC( 'm', 'p', '4', 'a' ):
587                     memcpy( fcc, "mp4a", 4 );
588                     b_mpeg4_hdr = VLC_TRUE;
589                     break;
590
591                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
592                     if( p_sys->b_mov )
593                         memcpy( fcc, ".mp3 ", 4 );
594                     else
595                         memcpy( fcc, "mp4a", 4 );
596                     b_mpeg4_hdr = VLC_FALSE;
597                     break;
598
599                 default:
600                     memcpy( fcc, (char*)&p_stream->p_fmt->i_fourcc, 4 );
601                     b_mpeg4_hdr = VLC_FALSE;
602                     break;
603             }
604
605             soun = box_new( fcc );
606             for( i = 0; i < 6; i++ )
607             {
608                 bo_add_8( soun, 0 );        // reserved;
609             }
610             bo_add_16be( soun, 1 );         // data-reference-index
611             bo_add_32be( soun, 0 );         // reserved;
612             bo_add_32be( soun, 0 );         // reserved;
613             bo_add_16be( soun, p_stream->p_fmt->i_channels );   // channel-count
614             bo_add_16be( soun, 16);         // FIXME sample size
615             bo_add_16be( soun, 0 );         // predefined
616             bo_add_16be( soun, 0 );         // reserved
617             bo_add_16be( soun, p_stream->p_fmt->i_sample_rate ); // sampleratehi
618             bo_add_16be( soun, 0 );                              // sampleratelo
619
620             /* add an ES Descriptor */
621             if( b_mpeg4_hdr )
622             {
623                 bo_t *esds;
624
625                 esds = GetESDS( p_stream );
626
627                 box_fix( esds );
628                 box_gather( soun, esds );
629             }
630
631             box_fix( soun );
632             box_gather( stsd, soun );
633         }
634         else if( p_stream->p_fmt->i_cat == VIDEO_ES )
635         {
636             bo_t *vide;
637             char fcc[4] = "    ";
638             int  i;
639             vlc_bool_t b_mpeg4_hdr;
640
641             switch( p_stream->p_fmt->i_fourcc )
642             {
643                 case VLC_FOURCC( 'm', 'p', '4', 'v' ):
644                 case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
645                     memcpy( fcc, "mp4v", 4 );
646                     b_mpeg4_hdr = VLC_TRUE;
647                     break;
648
649                 case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
650                     memcpy( fcc, "mjpa", 4 );
651                     b_mpeg4_hdr = VLC_FALSE;
652                     break;
653
654                 default:
655                     memcpy( fcc, (char*)&p_stream->p_fmt->i_fourcc, 4 );
656                     b_mpeg4_hdr = VLC_FALSE;
657                     break;
658             }
659
660             vide = box_new( fcc );
661             for( i = 0; i < 6; i++ )
662             {
663                 bo_add_8( vide, 0 );        // reserved;
664             }
665             bo_add_16be( vide, 1 );         // data-reference-index
666
667             bo_add_16be( vide, 0 );         // predefined;
668             bo_add_16be( vide, 0 );         // reserved;
669             for( i = 0; i < 3; i++ )
670             {
671                 bo_add_32be( vide, 0 );     // predefined;
672             }
673
674             bo_add_16be( vide, p_stream->p_fmt->i_width );  // i_width
675             bo_add_16be( vide, p_stream->p_fmt->i_height ); // i_height
676
677             bo_add_32be( vide, 0x00480000 );                // h 72dpi
678             bo_add_32be( vide, 0x00480000 );                // v 72dpi
679
680             bo_add_32be( vide, 0 );         // reserved
681             bo_add_16be( vide, 1 );         // predefined
682             for( i = 0; i < 32; i++ )
683             {
684                 bo_add_8( vide, 0 );        // compressor name;
685             }
686             bo_add_16be( vide, 0x18 );      // depth
687             bo_add_16be( vide, 0xffff );    // predefined
688
689             /* add an ES Descriptor */
690             if( b_mpeg4_hdr )
691             {
692                 bo_t *esds;
693
694                 esds = GetESDS( p_stream );
695
696                 box_fix( esds );
697                 box_gather( vide, esds );
698             }
699
700             box_fix( vide );
701             box_gather( stsd, vide );
702         }
703
704         /* append stsd to stbl */
705         box_fix( stsd );
706         box_gather( stbl, stsd );
707
708         /* we will create chunk table and stsc table FIXME optim stsc table FIXME */
709         i_chunk_count = 0;
710         for( i = 0; i < p_stream->i_entry_count; )
711         {
712             while( i < p_stream->i_entry_count )
713             {
714                 if( i + 1 < p_stream->i_entry_count &&
715                     p_stream->entry[i].i_pos +
716                     p_stream->entry[i].i_size != p_stream->entry[i + 1].i_pos )
717                 {
718                     i++;
719                     break;
720                 }
721
722                 i++;
723             }
724             i_chunk_count++;
725         }
726
727 //        if( p_sys->i_pos >= 0xffffffff )
728         {
729             bo_t *co64;
730             bo_t *stsc;
731
732             unsigned int  i_chunk;
733
734             msg_Dbg( p_mux, "creating %d chunk (co64)", i_chunk_count );
735
736             co64 = box_full_new( "co64", 0, 0 );
737             bo_add_32be( co64, i_chunk_count );
738
739             stsc = box_full_new( "stsc", 0, 0 );
740             bo_add_32be( stsc, i_chunk_count );     // entry-count
741             for( i_chunk = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ )
742             {
743                 int i_first;
744                 bo_add_64be( co64, p_stream->entry[i].i_pos );
745
746                 i_first = i;
747
748                 while( i < p_stream->i_entry_count )
749                 {
750                     if( i + 1 < p_stream->i_entry_count && p_stream->entry[i].i_pos + p_stream->entry[i].i_size != p_stream->entry[i + 1].i_pos )
751                     {
752                         i++;
753                         break;
754                     }
755
756                     i++;
757                 }
758                 bo_add_32be( stsc, 1 + i_chunk );   // first-chunk
759                 bo_add_32be( stsc, i - i_first ) ;  // samples-per-chunk
760                 bo_add_32be( stsc, 1 );             // sample-descr-index
761             }
762             /* append co64 to stbl */
763             box_fix( co64 );
764             box_gather( stbl, co64 );
765
766             /* append stsc to stbl */
767             box_fix( stsc );
768             box_gather( stbl, stsc );
769         }
770 //        else
771 //        {
772 //              FIXME implement it
773 //        }
774
775
776         /* add stts */
777         stts = box_full_new( "stts", 0, 0 );
778         bo_add_32be( stts, 0 );     // fixed latter
779         for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
780         {
781             int64_t i_delta;
782             int     i_first;
783
784             i_first = i;
785             i_delta = p_stream->entry[i].i_length;
786
787             while( i < p_stream->i_entry_count )
788             {
789                 if( i + 1 < p_stream->i_entry_count &&
790                     p_stream->entry[i + 1].i_length != i_delta )
791                 {
792                     i++;
793                     break;
794                 }
795
796                 i++;
797             }
798
799             bo_add_32be( stts, i - i_first );           // sample-count
800             bo_add_32be( stts, i_delta * (int64_t)i_timescale /
801                                (int64_t)1000000 );      // sample-delta
802         }
803         bo_fix_32be( stts, 12, i_index );
804
805         /* append stts to stbl */
806         box_fix( stts );
807         box_gather( stbl, stts );
808
809         /* FIXME add ctts ?? FIXME */
810
811         stsz = box_full_new( "stsz", 0, 0 );
812         bo_add_32be( stsz, 0 );                             // sample-size
813         bo_add_32be( stsz, p_stream->i_entry_count );       // sample-count
814         for( i = 0; i < p_stream->i_entry_count; i++ )
815         {
816             bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
817         }
818         /* append stsz to stbl */
819         box_fix( stsz );
820         box_gather( stbl, stsz );
821
822         /* append stbl to minf */
823         box_fix( stbl );
824         box_gather( minf, stbl );
825
826         /* append minf to mdia */
827         box_fix( minf );
828         box_gather( mdia, minf );
829
830         /* append mdia to trak */
831         box_fix( mdia );
832         box_gather( trak, mdia );
833
834         /* append trak to moov */
835         box_fix( trak );
836         box_gather( moov, trak );
837     }
838
839     box_fix( moov );
840     box_send( p_mux, moov );
841
842     /* *** release memory *** */
843     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
844     {
845         mp4_stream_t *p_stream;
846
847         p_stream = p_sys->pp_streams[i_trak];
848
849         if( p_stream->p_fmt->p_extra_data )
850         {
851             free( p_stream->p_fmt->p_extra_data );
852         }
853         free( p_stream->p_fmt );
854         free( p_stream->entry );
855         free( p_stream );
856     }
857     free( p_sys );
858 }
859
860 static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
861                        void *p_answer )
862 {
863    switch( i_query )
864    {
865         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
866             *(vlc_bool_t*)p_answer = VLC_FALSE;
867             return( SOUT_MUX_CAP_ERR_OK );
868         default:
869             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
870    }
871 }
872
873 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
874 {
875     sout_mux_sys_t  *p_sys = p_mux->p_sys;
876     mp4_stream_t    *p_stream;
877
878     switch( p_input->p_fmt->i_fourcc )
879     {
880         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
881         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
882         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
883         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
884         case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
885         case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
886             break;
887         default:
888             msg_Err( p_mux, "unsupported codec %4.4s in mp4",
889                      (char*)&p_input->p_fmt->i_fourcc );
890             return VLC_EGENERIC;
891     }
892
893     p_stream                = malloc( sizeof( mp4_stream_t ) );
894     p_stream->p_fmt         = malloc( sizeof( sout_format_t ) );
895     memcpy( p_stream->p_fmt, p_input->p_fmt, sizeof( sout_format_t ) );
896     if( p_stream->p_fmt->i_extra_data )
897     {
898         p_stream->p_fmt->p_extra_data =
899             malloc( p_stream->p_fmt->i_extra_data );
900         memcpy( p_stream->p_fmt->p_extra_data,
901                 p_input->p_fmt->p_extra_data,
902                 p_input->p_fmt->i_extra_data );
903     }
904     p_stream->i_track_id    = p_sys->i_nb_streams + 1;
905     p_stream->i_entry_count = 0;
906     p_stream->i_entry_max   = 1000;
907     p_stream->entry         =
908         calloc( p_stream->i_entry_max, sizeof( mp4_entry_t ) );
909     p_stream->i_duration    = 0;
910
911     p_input->p_sys          = p_stream;
912
913     msg_Dbg( p_mux, "adding input" );
914
915     TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, p_stream );
916     return( VLC_SUCCESS );
917 }
918
919 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
920 {
921     msg_Dbg( p_mux, "removing input" );
922     return( 0 );
923 }
924
925 /****************************************************************************/
926
927 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
928 {
929     mtime_t i_dts;
930     int     i_stream;
931     int     i;
932
933     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
934     {
935         sout_fifo_t  *p_fifo;
936
937         p_fifo = p_mux->pp_inputs[i]->p_fifo;
938
939         if( p_fifo->i_depth > 1 )
940         {
941             sout_buffer_t *p_buf;
942
943             p_buf = sout_FifoShow( p_fifo );
944             if( i_stream < 0 || p_buf->i_dts < i_dts )
945             {
946                 i_dts = p_buf->i_dts;
947                 i_stream = i;
948             }
949         }
950         else
951         {
952             return( -1 ); // wait that all fifo have at least 2 packets
953         }
954     }
955     if( pi_stream )
956     {
957         *pi_stream = i_stream;
958     }
959     if( pi_dts )
960     {
961         *pi_dts = i_dts;
962     }
963     return( i_stream );
964 }
965
966 static int Mux( sout_mux_t *p_mux )
967 {
968     sout_mux_sys_t  *p_sys = p_mux->p_sys;
969
970     for( ;; )
971     {
972         sout_input_t    *p_input;
973         int             i_stream;
974         mp4_stream_t    *p_stream;
975         sout_buffer_t   *p_data;
976         mtime_t         i_dts;
977
978         if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
979         {
980             return( VLC_SUCCESS );
981         }
982
983
984         p_input  = p_mux->pp_inputs[i_stream];
985         p_stream = (mp4_stream_t*)p_input->p_sys;
986
987         p_data  = sout_FifoGet( p_input->p_fifo );
988         //msg_Dbg( p_mux, "stream=%d size=%6d pos=%8lld", i_stream, p_data->i_size, p_sys->i_pos );
989
990         /* add index entry */
991         p_stream->entry[p_stream->i_entry_count].i_pos   = p_sys->i_pos;
992         p_stream->entry[p_stream->i_entry_count].i_size  = p_data->i_size;
993         p_stream->entry[p_stream->i_entry_count].i_pts   = p_data->i_pts;
994         p_stream->entry[p_stream->i_entry_count].i_dts   = p_data->i_dts;
995         p_stream->entry[p_stream->i_entry_count].i_length=
996             __MAX( p_data->i_length, 0 );
997
998         p_stream->i_entry_count++;
999         if( p_stream->i_entry_count >= p_stream->i_entry_max )
1000         {
1001             p_stream->i_entry_max += 1000;
1002             p_stream->entry =
1003                 realloc( p_stream->entry,
1004                          p_stream->i_entry_max * sizeof( mp4_entry_t ) );
1005         }
1006
1007         /* update */
1008         p_stream->i_duration += __MAX( p_data->i_length, 0 );
1009         p_sys->i_pos += p_data->i_size;
1010
1011         /* write data */
1012         sout_AccessOutWrite( p_mux->p_access, p_data );
1013     }
1014
1015     return( VLC_SUCCESS );
1016 }
1017
1018
1019 /****************************************************************************/
1020
1021 static void bo_init( bo_t *p_bo, int i_size, uint8_t *p_buffer,
1022                      vlc_bool_t b_grow )
1023 {
1024     if( !p_buffer )
1025     {
1026         p_bo->i_buffer_size = __MAX( i_size, 1024 );
1027         p_bo->p_buffer = malloc( p_bo->i_buffer_size );
1028     }
1029     else
1030     {
1031         p_bo->i_buffer_size = i_size;
1032         p_bo->p_buffer = p_buffer;
1033     }
1034
1035     p_bo->b_grow = b_grow;
1036     p_bo->i_buffer = 0;
1037 }
1038
1039 static void bo_add_8( bo_t *p_bo, uint8_t i )
1040 {
1041     if( p_bo->i_buffer < p_bo->i_buffer_size )
1042     {
1043         p_bo->p_buffer[p_bo->i_buffer] = i;
1044     }
1045     else if( p_bo->b_grow )
1046     {
1047         p_bo->i_buffer_size += 1024;
1048         p_bo->p_buffer = realloc( p_bo->p_buffer, p_bo->i_buffer_size );
1049
1050         p_bo->p_buffer[p_bo->i_buffer] = i;
1051     }
1052
1053     p_bo->i_buffer++;
1054 }
1055
1056 static void bo_add_16be( bo_t *p_bo, uint16_t i )
1057 {
1058     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1059     bo_add_8( p_bo, i &0xff );
1060 }
1061
1062 static void bo_add_24be( bo_t *p_bo, uint32_t i )
1063 {
1064     bo_add_8( p_bo, ( ( i >> 16) &0xff ) );
1065     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
1066     bo_add_8( p_bo, (   i &0xff ) );
1067 }
1068 static void bo_add_32be( bo_t *p_bo, uint32_t i )
1069 {
1070     bo_add_16be( p_bo, ( ( i >> 16) &0xffff ) );
1071     bo_add_16be( p_bo, i &0xffff );
1072 }
1073
1074 static void bo_fix_32be ( bo_t *p_bo, int i_pos, uint32_t i)
1075 {
1076     p_bo->p_buffer[i_pos    ] = ( i >> 24 )&0xff;
1077     p_bo->p_buffer[i_pos + 1] = ( i >> 16 )&0xff;
1078     p_bo->p_buffer[i_pos + 2] = ( i >>  8 )&0xff;
1079     p_bo->p_buffer[i_pos + 3] = ( i       )&0xff;
1080 }
1081
1082 static void bo_add_64be( bo_t *p_bo, uint64_t i )
1083 {
1084     bo_add_32be( p_bo, ( ( i >> 32) &0xffffffff ) );
1085     bo_add_32be( p_bo, i &0xffffffff );
1086 }
1087
1088 static void bo_add_fourcc( bo_t *p_bo, char *fcc )
1089 {
1090     bo_add_8( p_bo, fcc[0] );
1091     bo_add_8( p_bo, fcc[1] );
1092     bo_add_8( p_bo, fcc[2] );
1093     bo_add_8( p_bo, fcc[3] );
1094 }
1095
1096 static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem )
1097 {
1098     int i;
1099
1100     for( i = 0; i < i_size; i++ )
1101     {
1102         bo_add_8( p_bo, p_mem[i] );
1103     }
1104 }
1105 static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
1106 {
1107     int i;
1108
1109     for( i = 0; i < p_bo2->i_buffer; i++ )
1110     {
1111         bo_add_8( p_bo, p_bo2->p_buffer[i] );
1112     }
1113 }
1114
1115 static bo_t * box_new( char *fcc )
1116 {
1117     bo_t *box;
1118
1119     if( ( box = malloc( sizeof( bo_t ) ) ) )
1120     {
1121         bo_init( box, 0, NULL, VLC_TRUE );
1122
1123         bo_add_32be  ( box, 0 );
1124         bo_add_fourcc( box, fcc );
1125     }
1126
1127     return box;
1128 }
1129
1130 static bo_t * box_full_new( char *fcc, uint8_t v, uint32_t f )
1131 {
1132     bo_t *box;
1133
1134     if( ( box = malloc( sizeof( bo_t ) ) ) )
1135     {
1136         bo_init( box, 0, NULL, VLC_TRUE );
1137
1138         bo_add_32be  ( box, 0 );
1139         bo_add_fourcc( box, fcc );
1140         bo_add_8     ( box, v );
1141         bo_add_24be  ( box, f );
1142     }
1143
1144     return box;
1145 }
1146
1147 static void box_fix( bo_t *box )
1148 {
1149     bo_t box_tmp;
1150
1151     memcpy( &box_tmp, box, sizeof( bo_t ) );
1152
1153     box_tmp.i_buffer = 0;
1154     bo_add_32be( &box_tmp, box->i_buffer );
1155 }
1156
1157 static void box_free( bo_t *box )
1158 {
1159     if( box->p_buffer )
1160     {
1161         free( box->p_buffer );
1162     }
1163
1164     free( box );
1165 }
1166
1167 static void box_gather ( bo_t *box, bo_t *box2 )
1168 {
1169     bo_add_bo( box, box2 );
1170     box_free( box2 );
1171 }
1172
1173
1174 static sout_buffer_t * bo_to_sout( sout_instance_t *p_sout,  bo_t *box )
1175 {
1176     sout_buffer_t *p_buf;
1177
1178     p_buf = sout_BufferNew( p_sout, box->i_buffer );
1179     if( box->i_buffer > 0 )
1180     {
1181         memcpy( p_buf->p_buffer, box->p_buffer, box->i_buffer );
1182     }
1183
1184     p_buf->i_size = box->i_buffer;
1185
1186     return p_buf;
1187 }
1188
1189 static void box_send( sout_mux_t *p_mux,  bo_t *box )
1190 {
1191     sout_buffer_t *p_buf;
1192
1193     p_buf = bo_to_sout( p_mux->p_sout, box );
1194     box_free( box );
1195
1196     sout_AccessOutWrite( p_mux->p_access, p_buf );
1197 }
1198
1199 static int64_t get_timestamp()
1200 {
1201     int64_t i_timestamp = 0;
1202
1203 #ifdef HAVE_TIME_H
1204     i_timestamp = time(NULL);
1205     i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
1206     // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
1207 #endif
1208
1209     return i_timestamp;
1210 }