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