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