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