Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

mp4.c

00001 /*****************************************************************************
00002  * mp4.c: mp4/mov muxer
00003  *****************************************************************************
00004  * Copyright (C) 2001, 2002, 2003 the VideoLAN team
00005  * $Id: mp4.c 12698 2005-09-28 18:56:36Z dionoea $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *          Gildas Bazin <gbazin at videolan dot org>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <stdlib.h>
00029 #include <string.h>
00030 
00031 #include <vlc/vlc.h>
00032 #include <vlc/input.h>
00033 #include <vlc/sout.h>
00034 
00035 #ifdef HAVE_TIME_H
00036 #include <time.h>
00037 #endif
00038 
00039 #include "iso_lang.h"
00040 #include "vlc_meta.h"
00041 
00042 /*****************************************************************************
00043  * Module descriptor
00044  *****************************************************************************/
00045 #define FASTSTART_TEXT N_("Create \"Fast start\" files")
00046 #define FASTSTART_LONGTEXT N_( \
00047     "When this option is turned on, \"Fast start\" files will be created. " \
00048     "(\"Fast start\" files are optimized for download, allowing the user " \
00049     "to start previewing the file while it is downloading).")
00050 static int  Open   ( vlc_object_t * );
00051 static void Close  ( vlc_object_t * );
00052 
00053 #define SOUT_CFG_PREFIX "sout-mp4-"
00054 
00055 vlc_module_begin();
00056     set_description( _("MP4/MOV muxer") );
00057     set_category( CAT_SOUT );
00058     set_subcategory( SUBCAT_SOUT_MUX );
00059     set_shortname( "MP4" );
00060 
00061     add_bool( SOUT_CFG_PREFIX "faststart", 1, NULL, FASTSTART_TEXT, FASTSTART_LONGTEXT,
00062               VLC_TRUE );
00063     set_capability( "sout mux", 5 );
00064     add_shortcut( "mp4" );
00065     add_shortcut( "mov" );
00066     add_shortcut( "3gp" );
00067     set_callbacks( Open, Close );
00068 vlc_module_end();
00069 
00070 /*****************************************************************************
00071  * Exported prototypes
00072  *****************************************************************************/
00073 static const char *ppsz_sout_options[] = {
00074     "faststart", NULL
00075 };
00076 
00077 static int Control( sout_mux_t *, int, va_list );
00078 static int AddStream( sout_mux_t *, sout_input_t * );
00079 static int DelStream( sout_mux_t *, sout_input_t * );
00080 static int Mux      ( sout_mux_t * );
00081 
00082 /*****************************************************************************
00083  * Local prototypes
00084  *****************************************************************************/
00085 typedef struct
00086 {
00087     uint64_t i_pos;
00088     int      i_size;
00089 
00090     mtime_t  i_pts_dts;
00091     mtime_t  i_length;
00092     unsigned int i_flags;
00093 
00094 } mp4_entry_t;
00095 
00096 typedef struct
00097 {
00098     es_format_t   fmt;
00099     int           i_track_id;
00100 
00101     /* index */
00102     unsigned int i_entry_count;
00103     unsigned int i_entry_max;
00104     mp4_entry_t  *entry;
00105     int64_t      i_length_neg;
00106 
00107     /* stats */
00108     int64_t      i_dts_start;
00109     int64_t      i_duration;
00110 
00111     /* for later stco fix-up (fast start files) */
00112     uint64_t i_stco_pos;
00113     vlc_bool_t b_stco64;
00114 
00115     /* for h264 */
00116     struct
00117     {
00118         int     i_profile;
00119         int     i_level;
00120 
00121         int     i_sps;
00122         uint8_t *sps;
00123         int     i_pps;
00124         uint8_t *pps;
00125     } avc;
00126 
00127     /* for spu */
00128     int64_t i_last_dts;
00129 
00130 } mp4_stream_t;
00131 
00132 struct sout_mux_sys_t
00133 {
00134     vlc_bool_t b_mov;
00135     vlc_bool_t b_3gp;
00136     vlc_bool_t b_64_ext;
00137     vlc_bool_t b_fast_start;
00138 
00139     uint64_t i_mdat_pos;
00140     uint64_t i_pos;
00141 
00142     int64_t  i_dts_start;
00143 
00144     int          i_nb_streams;
00145     mp4_stream_t **pp_streams;
00146 };
00147 
00148 typedef struct bo_t
00149 {
00150     vlc_bool_t b_grow;
00151 
00152     int        i_buffer_size;
00153     int        i_buffer;
00154     uint8_t    *p_buffer;
00155 
00156 } bo_t;
00157 
00158 static void bo_init     ( bo_t *, int , uint8_t *, vlc_bool_t  );
00159 static void bo_add_8    ( bo_t *, uint8_t );
00160 static void bo_add_16be ( bo_t *, uint16_t );
00161 static void bo_add_24be ( bo_t *, uint32_t );
00162 static void bo_add_32be ( bo_t *, uint32_t );
00163 static void bo_add_64be ( bo_t *, uint64_t );
00164 static void bo_add_fourcc(bo_t *, char * );
00165 static void bo_add_bo   ( bo_t *, bo_t * );
00166 static void bo_add_mem  ( bo_t *, int , uint8_t * );
00167 static void bo_add_descr( bo_t *, uint8_t , uint32_t );
00168 
00169 static void bo_fix_32be ( bo_t *, int , uint32_t );
00170 
00171 static bo_t *box_new     ( char *fcc );
00172 static bo_t *box_full_new( char *fcc, uint8_t v, uint32_t f );
00173 static void  box_fix     ( bo_t *box );
00174 static void  box_free    ( bo_t *box );
00175 static void  box_gather  ( bo_t *box, bo_t *box2 );
00176 
00177 static void box_send( sout_mux_t *p_mux,  bo_t *box );
00178 
00179 static block_t *bo_to_sout( sout_instance_t *p_sout,  bo_t *box );
00180 
00181 static bo_t *GetMoovBox( sout_mux_t *p_mux );
00182 
00183 static block_t *ConvertSUBT( sout_mux_t *, mp4_stream_t *, block_t *);
00184 static void ConvertAVC1( sout_mux_t *, mp4_stream_t *, block_t * );
00185 
00186 /*****************************************************************************
00187  * Open:
00188  *****************************************************************************/
00189 static int Open( vlc_object_t *p_this )
00190 {
00191     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
00192     sout_mux_sys_t  *p_sys;
00193     bo_t            *box;
00194 
00195     msg_Dbg( p_mux, "Mp4 muxer opend" );
00196     sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
00197 
00198     p_mux->pf_control   = Control;
00199     p_mux->pf_addstream = AddStream;
00200     p_mux->pf_delstream = DelStream;
00201     p_mux->pf_mux       = Mux;
00202     p_mux->p_sys        = p_sys = malloc( sizeof( sout_mux_sys_t ) );
00203     p_sys->i_pos        = 0;
00204     p_sys->i_nb_streams = 0;
00205     p_sys->pp_streams   = NULL;
00206     p_sys->i_mdat_pos   = 0;
00207     p_sys->b_mov        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "mov" );
00208     p_sys->b_3gp        = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "3gp" );
00209     p_sys->i_dts_start  = 0;
00210 
00211 
00212     if( !p_sys->b_mov )
00213     {
00214         /* Now add ftyp header */
00215         box = box_new( "ftyp" );
00216         if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
00217         else bo_add_fourcc( box, "isom" );
00218         bo_add_32be  ( box, 0 );
00219         if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
00220         else bo_add_fourcc( box, "mp41" );
00221         box_fix( box );
00222 
00223         p_sys->i_pos += box->i_buffer;
00224         p_sys->i_mdat_pos = p_sys->i_pos;
00225 
00226         box_send( p_mux, box );
00227     }
00228 
00229     /* FIXME FIXME
00230      * Quicktime actually doesn't like the 64 bits extensions !!! */
00231     p_sys->b_64_ext = VLC_FALSE;
00232 
00233     /* Now add mdat header */
00234     box = box_new( "mdat" );
00235     bo_add_64be  ( box, 0 ); // enough to store an extended size
00236 
00237     p_sys->i_pos += box->i_buffer;
00238 
00239     box_send( p_mux, box );
00240 
00241     return VLC_SUCCESS;
00242 }
00243 
00244 /*****************************************************************************
00245  * Close:
00246  *****************************************************************************/
00247 static void Close( vlc_object_t * p_this )
00248 {
00249     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
00250     sout_mux_sys_t  *p_sys = p_mux->p_sys;
00251     block_t   *p_hdr;
00252     bo_t            bo, *moov;
00253     vlc_value_t     val;
00254 
00255     int             i_trak;
00256     uint64_t        i_moov_pos;
00257 
00258     msg_Dbg( p_mux, "Close" );
00259 
00260     /* Update mdat size */
00261     bo_init( &bo, 0, NULL, VLC_TRUE );
00262     if( p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32) )
00263     {
00264         /* Extended size */
00265         bo_add_32be  ( &bo, 1 );
00266         bo_add_fourcc( &bo, "mdat" );
00267         bo_add_64be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos );
00268     }
00269     else
00270     {
00271         bo_add_32be  ( &bo, 8 );
00272         bo_add_fourcc( &bo, "wide" );
00273         bo_add_32be  ( &bo, p_sys->i_pos - p_sys->i_mdat_pos - 8 );
00274         bo_add_fourcc( &bo, "mdat" );
00275     }
00276     p_hdr = bo_to_sout( p_mux->p_sout, &bo );
00277     free( bo.p_buffer );
00278 
00279     sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos );
00280     sout_AccessOutWrite( p_mux->p_access, p_hdr );
00281 
00282     /* Create MOOV header */
00283     i_moov_pos = p_sys->i_pos;
00284     moov = GetMoovBox( p_mux );
00285 
00286     /* Check we need to create "fast start" files */
00287     var_Get( p_this, SOUT_CFG_PREFIX "faststart", &val );
00288     p_sys->b_fast_start = val.b_bool;
00289     while( p_sys->b_fast_start )
00290     {
00291         /* Move data to the end of the file so we can fit the moov header
00292          * at the start */
00293         block_t *p_buf;
00294         int64_t i_chunk, i_size = p_sys->i_pos - p_sys->i_mdat_pos;
00295         int i_moov_size = moov->i_buffer;
00296 
00297         while( i_size > 0 )
00298         {
00299             i_chunk = __MIN( 32768, i_size );
00300             p_buf = block_New( p_mux, i_chunk );
00301             sout_AccessOutSeek( p_mux->p_access,
00302                                 p_sys->i_mdat_pos + i_size - i_chunk );
00303             if( sout_AccessOutRead( p_mux->p_access, p_buf ) < i_chunk )
00304             {
00305                 msg_Warn( p_this, "read() not supported by acces output, "
00306                           "won't create a fast start file" );
00307                 p_sys->b_fast_start = VLC_FALSE;
00308                 block_Release( p_buf );
00309                 break;
00310             }
00311             sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos + i_size +
00312                                 i_moov_size - i_chunk );
00313             sout_AccessOutWrite( p_mux->p_access, p_buf );
00314             i_size -= i_chunk;
00315         }
00316 
00317         if( !p_sys->b_fast_start ) break;
00318 
00319         /* Fix-up samples to chunks table in MOOV header */
00320         for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
00321         {
00322             mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
00323             unsigned int i;
00324             int i_chunk;
00325 
00326             moov->i_buffer = p_stream->i_stco_pos;
00327             for( i_chunk = 0, i = 0; i < p_stream->i_entry_count; i_chunk++ )
00328             {
00329                 if( p_stream->b_stco64 )
00330                     bo_add_64be( moov, p_stream->entry[i].i_pos + i_moov_size);
00331                 else
00332                     bo_add_32be( moov, p_stream->entry[i].i_pos + i_moov_size);
00333 
00334                 while( i < p_stream->i_entry_count )
00335                 {
00336                     if( i + 1 < p_stream->i_entry_count &&
00337                         p_stream->entry[i].i_pos + p_stream->entry[i].i_size
00338                         != p_stream->entry[i + 1].i_pos )
00339                     {
00340                         i++;
00341                         break;
00342                     }
00343 
00344                     i++;
00345                 }
00346             }
00347         }
00348 
00349         moov->i_buffer = i_moov_size;
00350         i_moov_pos = p_sys->i_mdat_pos;
00351         p_sys->b_fast_start = VLC_FALSE;
00352     }
00353 
00354     /* Write MOOV header */
00355     sout_AccessOutSeek( p_mux->p_access, i_moov_pos );
00356     box_send( p_mux, moov );
00357 
00358     /* Clean-up */
00359     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
00360     {
00361         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
00362 
00363         es_format_Clean( &p_stream->fmt );
00364         if( p_stream->avc.i_sps ) free( p_stream->avc.sps );
00365         if( p_stream->avc.i_pps ) free( p_stream->avc.pps );
00366         free( p_stream->entry );
00367         free( p_stream );
00368     }
00369     if( p_sys->i_nb_streams ) free( p_sys->pp_streams );
00370     free( p_sys );
00371 }
00372 
00373 /*****************************************************************************
00374  * Control:
00375  *****************************************************************************/
00376 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
00377 {
00378     vlc_bool_t *pb_bool;
00379 
00380    switch( i_query )
00381    {
00382        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
00383            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00384            *pb_bool = VLC_FALSE;
00385            return VLC_SUCCESS;
00386 
00387        case MUX_GET_ADD_STREAM_WAIT:
00388            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00389            *pb_bool = VLC_TRUE;
00390            return VLC_SUCCESS;
00391 
00392        case MUX_GET_MIME:   /* Not needed, as not streamable */
00393         default:
00394             return VLC_EGENERIC;
00395    }
00396 }
00397 
00398 /*****************************************************************************
00399  * AddStream:
00400  *****************************************************************************/
00401 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
00402 {
00403     sout_mux_sys_t  *p_sys = p_mux->p_sys;
00404     mp4_stream_t    *p_stream;
00405 
00406     switch( p_input->p_fmt->i_codec )
00407     {
00408         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
00409         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
00410         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
00411         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
00412         case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
00413         case VLC_FOURCC( 'm', 'j', 'p', 'b' ):
00414         case VLC_FOURCC( 'S', 'V', 'Q', '1' ):
00415         case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
00416         case VLC_FOURCC( 'H', '2', '6', '3' ):
00417         case VLC_FOURCC( 'h', '2', '6', '4' ):
00418         case VLC_FOURCC( 's', 'a', 'm', 'r' ):
00419         case VLC_FOURCC( 's', 'a', 'w', 'b' ):
00420             break;
00421         case VLC_FOURCC( 's', 'u', 'b', 't' ):
00422             msg_Warn( p_mux, "subtitle track added like in .mov (even when creating .mp4)" );
00423             break;
00424         default:
00425             msg_Err( p_mux, "unsupported codec %4.4s in mp4",
00426                      (char*)&p_input->p_fmt->i_codec );
00427             return VLC_EGENERIC;
00428     }
00429 
00430     p_stream                = malloc( sizeof( mp4_stream_t ) );
00431     es_format_Copy( &p_stream->fmt, p_input->p_fmt );
00432     p_stream->i_track_id    = p_sys->i_nb_streams + 1;
00433     p_stream->i_length_neg  = 0;
00434     p_stream->i_entry_count = 0;
00435     p_stream->i_entry_max   = 1000;
00436     p_stream->entry         =
00437         calloc( p_stream->i_entry_max, sizeof( mp4_entry_t ) );
00438     p_stream->i_dts_start   = 0;
00439     p_stream->i_duration    = 0;
00440     p_stream->avc.i_profile = 77;
00441     p_stream->avc.i_level   = 51;
00442     p_stream->avc.i_sps     = 0;
00443     p_stream->avc.sps       = NULL;
00444     p_stream->avc.i_pps     = 0;
00445     p_stream->avc.pps       = NULL;
00446 
00447     p_input->p_sys          = p_stream;
00448 
00449     msg_Dbg( p_mux, "adding input" );
00450 
00451     TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, p_stream );
00452     return VLC_SUCCESS;
00453 }
00454 
00455 /*****************************************************************************
00456  * DelStream:
00457  *****************************************************************************/
00458 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
00459 {
00460     msg_Dbg( p_mux, "removing input" );
00461     return VLC_SUCCESS;
00462 }
00463 
00464 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
00465 {
00466     mtime_t i_dts;
00467     int     i_stream;
00468     int     i;
00469 
00470     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
00471     {
00472         block_fifo_t   *p_fifo = p_mux->pp_inputs[i]->p_fifo;
00473         block_t *p_buf;
00474 
00475         if( p_fifo->i_depth <= 1 )
00476         {
00477             if( p_mux->pp_inputs[i]->p_fmt->i_cat != SPU_ES )
00478             {
00479                 return -1; // wait that all fifo have at least 2 packets
00480             }
00481             /* For SPU, we wait only 1 packet */
00482             continue;
00483         }
00484 
00485         p_buf = block_FifoShow( p_fifo );
00486         if( i_stream < 0 || p_buf->i_dts < i_dts )
00487         {
00488             i_dts = p_buf->i_dts;
00489             i_stream = i;
00490         }
00491     }
00492     if( pi_stream )
00493     {
00494         *pi_stream = i_stream;
00495     }
00496     if( pi_dts )
00497     {
00498         *pi_dts = i_dts;
00499     }
00500     return i_stream;
00501 }
00502 
00503 /*****************************************************************************
00504  * Mux:
00505  *****************************************************************************/
00506 static int Mux( sout_mux_t *p_mux )
00507 {
00508     sout_mux_sys_t *p_sys = p_mux->p_sys;
00509 
00510     for( ;; )
00511     {
00512         sout_input_t    *p_input;
00513         int             i_stream;
00514         mp4_stream_t    *p_stream;
00515         block_t         *p_data;
00516         mtime_t         i_dts;
00517 
00518         if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
00519         {
00520             return( VLC_SUCCESS );
00521         }
00522 
00523         p_input  = p_mux->pp_inputs[i_stream];
00524         p_stream = (mp4_stream_t*)p_input->p_sys;
00525 
00526         p_data  = block_FifoGet( p_input->p_fifo );
00527         if( p_stream->fmt.i_codec == VLC_FOURCC( 'h', '2', '6', '4' ) )
00528         {
00529             ConvertAVC1( p_mux, p_stream, p_data );
00530         }
00531         else if( p_stream->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) )
00532         {
00533             p_data = ConvertSUBT( p_mux, p_stream, p_data );
00534         }
00535 
00536         if( p_stream->fmt.i_cat != SPU_ES )
00537         {
00538             /* Fix length of the sample */
00539             if( p_input->p_fifo->i_depth > 0 )
00540             {
00541                 block_t *p_next = block_FifoShow( p_input->p_fifo );
00542                 int64_t       i_diff  = p_next->i_dts - p_data->i_dts;
00543 
00544                 if( i_diff < I64C(1000000 ) )   /* protection */
00545                 {
00546                     p_data->i_length = i_diff;
00547                 }
00548             }
00549             if( p_data->i_length <= 0 )
00550             {
00551                 msg_Warn( p_mux, "i_length <= 0" );
00552                 p_stream->i_length_neg += p_data->i_length - 1;
00553                 p_data->i_length = 1;
00554             }
00555             else if( p_stream->i_length_neg < 0 )
00556             {
00557                 int64_t i_recover = __MIN( p_data->i_length / 4, - p_stream->i_length_neg );
00558 
00559                 p_data->i_length -= i_recover;
00560                 p_stream->i_length_neg += i_recover;
00561             }
00562         }
00563 
00564         /* Save starting time */
00565         if( p_stream->i_entry_count == 0 )
00566         {
00567             p_stream->i_dts_start = p_data->i_dts;
00568 
00569             /* Update global dts_start */
00570             if( p_sys->i_dts_start <= 0 ||
00571                 p_stream->i_dts_start < p_sys->i_dts_start )
00572             {
00573                 p_sys->i_dts_start = p_stream->i_dts_start;
00574             }
00575         }
00576 
00577         if( p_stream->fmt.i_cat == SPU_ES && p_stream->i_entry_count > 0 )
00578         {
00579             int64_t i_length = p_data->i_dts - p_stream->i_last_dts;
00580 
00581             if( i_length <= 0 )
00582             {
00583                 /* FIXME handle this broken case */
00584                 i_length = 1;
00585             }
00586 
00587             /* Fix last entry */
00588             if( p_stream->entry[p_stream->i_entry_count-1].i_length <= 0 )
00589             {
00590                 p_stream->entry[p_stream->i_entry_count-1].i_length = i_length;
00591             }
00592         }
00593 
00594 
00595         /* add index entry */
00596         p_stream->entry[p_stream->i_entry_count].i_pos    = p_sys->i_pos;
00597         p_stream->entry[p_stream->i_entry_count].i_size   = p_data->i_buffer;
00598         p_stream->entry[p_stream->i_entry_count].i_pts_dts=
00599             __MAX( p_data->i_pts - p_data->i_dts, 0 );
00600         p_stream->entry[p_stream->i_entry_count].i_length = p_data->i_length;
00601         p_stream->entry[p_stream->i_entry_count].i_flags  = p_data->i_flags;
00602 
00603         p_stream->i_entry_count++;
00604         /* XXX: -1 to always have 2 entry for easy adding of empty SPU */
00605         if( p_stream->i_entry_count >= p_stream->i_entry_max - 1 )
00606         {
00607             p_stream->i_entry_max += 1000;
00608             p_stream->entry =
00609                 realloc( p_stream->entry,
00610                          p_stream->i_entry_max * sizeof( mp4_entry_t ) );
00611         }
00612 
00613         /* update */
00614         p_stream->i_duration += p_data->i_length;
00615         p_sys->i_pos += p_data->i_buffer;
00616 
00617         /* Save the DTS */
00618         p_stream->i_last_dts = p_data->i_dts;
00619 
00620         /* write data */
00621         sout_AccessOutWrite( p_mux->p_access, p_data );
00622 
00623         if( p_stream->fmt.i_cat == SPU_ES )
00624         {
00625             int64_t i_length = p_stream->entry[p_stream->i_entry_count-1].i_length;
00626 
00627             if( i_length != 0 )
00628             {
00629                 /* TODO */
00630                 msg_Dbg( p_mux, "writing a empty subs" ) ;
00631 
00632                 /* Append a idx entry */
00633                 p_stream->entry[p_stream->i_entry_count].i_pos    = p_sys->i_pos;
00634                 p_stream->entry[p_stream->i_entry_count].i_size   = 3;
00635                 p_stream->entry[p_stream->i_entry_count].i_pts_dts= 0;
00636                 p_stream->entry[p_stream->i_entry_count].i_length = 0;
00637                 p_stream->entry[p_stream->i_entry_count].i_flags  = 0;
00638 
00639                 /* XXX: No need to grow the entry here */
00640                 p_stream->i_entry_count++;
00641 
00642                 /* Fix last dts */
00643                 p_stream->i_last_dts += i_length;
00644 
00645                 /* Write a " " */
00646                 p_data = block_New( p_mux, 3 );
00647                 p_data->p_buffer[0] = 0;
00648                 p_data->p_buffer[1] = 1;
00649                 p_data->p_buffer[2] = ' ';
00650 
00651                 p_sys->i_pos += p_data->i_buffer;
00652 
00653                 sout_AccessOutWrite( p_mux->p_access, p_data );
00654             }
00655 
00656             /* Fix duration */
00657             p_stream->i_duration = p_stream->i_last_dts - p_stream->i_dts_start;
00658         }
00659     }
00660 
00661     return( VLC_SUCCESS );
00662 }
00663 
00664 /*****************************************************************************
00665  *
00666  *****************************************************************************/
00667 static block_t *ConvertSUBT( sout_mux_t *p_mux, mp4_stream_t *tk, block_t *p_block )
00668 {
00669     p_block = block_Realloc( p_block, 2, p_block->i_buffer );
00670 
00671     /* No trailling '\0' */
00672     if( p_block->i_buffer > 2 && p_block->p_buffer[p_block->i_buffer-1] == '\0' )
00673         p_block->i_buffer--;
00674 
00675     p_block->p_buffer[0] = ( (p_block->i_buffer - 2) >> 8 )&0xff;
00676     p_block->p_buffer[1] = ( (p_block->i_buffer - 2)      )&0xff;
00677 
00678     return p_block;
00679 }
00680 
00681 static void ConvertAVC1( sout_mux_t *p_mux, mp4_stream_t *tk, block_t *p_block )
00682 {
00683     uint8_t *last = p_block->p_buffer;  /* Assume it starts with 0x00000001 */
00684     uint8_t *dat  = &p_block->p_buffer[4];
00685     uint8_t *end = &p_block->p_buffer[p_block->i_buffer];
00686 
00687 
00688     /* Replace the 4 bytes start code with 4 bytes size,
00689      * FIXME are all startcode 4 bytes ? (I don't think :( */
00690     while( dat < end )
00691     {
00692         int i_size;
00693 
00694         while( dat < end - 4 )
00695         {
00696             if( dat[0] == 0x00 && dat[1] == 0x00  &&
00697                 dat[2] == 0x00 && dat[3] == 0x01 )
00698             {
00699                 break;
00700             }
00701             dat++;
00702         }
00703         if( dat >= end - 4 )
00704         {
00705             dat = end;
00706         }
00707 
00708         /* Fix size */
00709         i_size = dat - &last[4];
00710         last[0] = ( i_size >> 24 )&0xff;
00711         last[1] = ( i_size >> 16 )&0xff;
00712         last[2] = ( i_size >>  8 )&0xff;
00713         last[3] = ( i_size       )&0xff;
00714 
00715         if( (last[4]&0x1f) == 7 && tk->avc.i_sps <= 0 )  /* SPS */
00716         {
00717             tk->avc.i_sps = i_size;
00718             tk->avc.sps = malloc( i_size );
00719             memcpy( tk->avc.sps, &last[4], i_size );
00720 
00721             tk->avc.i_profile = tk->avc.sps[1];
00722             tk->avc.i_level   = tk->avc.sps[3];
00723         }
00724         else if( (last[4]&0x1f) == 8 && tk->avc.i_pps <= 0 )   /* PPS */
00725         {
00726             tk->avc.i_pps = i_size;
00727             tk->avc.pps = malloc( i_size );
00728             memcpy( tk->avc.pps, &last[4], i_size );
00729         }
00730 
00731         last = dat;
00732 
00733         dat += 4;
00734     }
00735 }
00736 
00737 
00738 static int GetDescrLength( int i_size )
00739 {
00740     if( i_size < 0x00000080 )
00741         return 2 + i_size;
00742     else if( i_size < 0x00004000 )
00743         return 3 + i_size;
00744     else if( i_size < 0x00200000 )
00745         return 4 + i_size;
00746     else
00747         return 5 + i_size;
00748 }
00749 
00750 static bo_t *GetESDS( mp4_stream_t *p_stream )
00751 {
00752     bo_t *esds;
00753     int  i_stream_type;
00754     int  i_object_type_indication;
00755     int  i_decoder_specific_info_size;
00756     unsigned int i;
00757     int64_t i_bitrate_avg = 0;
00758     int64_t i_bitrate_max = 0;
00759 
00760     /* Compute avg/max bitrate */
00761     for( i = 0; i < p_stream->i_entry_count; i++ )
00762     {
00763         i_bitrate_avg += p_stream->entry[i].i_size;
00764         if( p_stream->entry[i].i_length > 0)
00765         {
00766             int64_t i_bitrate = I64C(8000000) * p_stream->entry[i].i_size / p_stream->entry[i].i_length;
00767             if( i_bitrate > i_bitrate_max )
00768                 i_bitrate_max = i_bitrate;
00769         }
00770     }
00771 
00772     if( p_stream->i_duration > 0 )
00773         i_bitrate_avg = I64C(8000000) * i_bitrate_avg / p_stream->i_duration;
00774     else
00775         i_bitrate_avg = 0;
00776     if( i_bitrate_max <= 1 )
00777         i_bitrate_max = 0x7fffffff;
00778 
00779     /* */
00780     if( p_stream->fmt.i_extra > 0 )
00781     {
00782         i_decoder_specific_info_size =
00783             GetDescrLength( p_stream->fmt.i_extra );
00784     }
00785     else
00786     {
00787         i_decoder_specific_info_size = 0;
00788     }
00789 
00790     esds = box_full_new( "esds", 0, 0 );
00791 
00792     /* ES_Descr */
00793     bo_add_descr( esds, 0x03, 3 +
00794                   GetDescrLength( 13 + i_decoder_specific_info_size ) +
00795                   GetDescrLength( 1 ) );
00796     bo_add_16be( esds, p_stream->i_track_id );
00797     bo_add_8   ( esds, 0x1f );      // flags=0|streamPriority=0x1f
00798 
00799     /* DecoderConfigDescr */
00800     bo_add_descr( esds, 0x04, 13 + i_decoder_specific_info_size );
00801 
00802     switch( p_stream->fmt.i_codec )
00803     {
00804         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
00805             i_object_type_indication = 0x20;
00806             break;
00807         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
00808             /* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
00809             i_object_type_indication = 0x60;
00810             break;
00811         case VLC_FOURCC( 'm', 'p', '4', 'a' ):
00812             /* FIXME for mpeg2-aac == 0x66->0x68 */
00813             i_object_type_indication = 0x40;
00814             break;
00815         case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
00816             i_object_type_indication =
00817                 p_stream->fmt.audio.i_rate < 32000 ? 0x69 : 0x6b;
00818             break;
00819         default:
00820             i_object_type_indication = 0x00;
00821             break;
00822     }
00823     i_stream_type = p_stream->fmt.i_cat == VIDEO_ES ? 0x04 : 0x05;
00824 
00825     bo_add_8   ( esds, i_object_type_indication );
00826     bo_add_8   ( esds, ( i_stream_type << 2 ) | 1 );
00827     bo_add_24be( esds, 1024 * 1024 );       // bufferSizeDB
00828     bo_add_32be( esds, i_bitrate_max );     // maxBitrate
00829     bo_add_32be( esds, i_bitrate_avg );     // avgBitrate
00830 
00831     if( p_stream->fmt.i_extra > 0 )
00832     {
00833         int i;
00834 
00835         /* DecoderSpecificInfo */
00836         bo_add_descr( esds, 0x05, p_stream->fmt.i_extra );
00837 
00838         for( i = 0; i < p_stream->fmt.i_extra; i++ )
00839         {
00840             bo_add_8( esds, ((uint8_t*)p_stream->fmt.p_extra)[i] );
00841         }
00842     }
00843 
00844     /* SL_Descr mandatory */
00845     bo_add_descr( esds, 0x06, 1 );
00846     bo_add_8    ( esds, 0x02 );  // sl_predefined
00847 
00848     box_fix( esds );
00849 
00850     return esds;
00851 }
00852 
00853 static bo_t *GetWaveTag( mp4_stream_t *p_stream )
00854 {
00855     bo_t *wave;
00856     bo_t *box;
00857 
00858     wave = box_new( "wave" );
00859 
00860     box = box_new( "frma" );
00861     bo_add_fourcc( box, "mp4a" );
00862     box_fix( box );
00863     box_gather( wave, box );
00864 
00865     box = box_new( "mp4a" );
00866     bo_add_32be( box, 0 );
00867     box_fix( box );
00868     box_gather( wave, box );
00869 
00870     box = GetESDS( p_stream );
00871     box_fix( box );
00872     box_gather( wave, box );
00873 
00874     box = box_new( "srcq" );
00875     bo_add_32be( box, 0x40 );
00876     box_fix( box );
00877     box_gather( wave, box );
00878 
00879     /* wazza ? */
00880     bo_add_32be( wave, 8 ); /* new empty box */
00881     bo_add_32be( wave, 0 ); /* box label */
00882 
00883     box_fix( wave );
00884 
00885     return wave;
00886 }
00887 
00888 static bo_t *GetDamrTag( mp4_stream_t *p_stream )
00889 {
00890     bo_t *damr;
00891 
00892     damr = box_new( "damr" );
00893 
00894     bo_add_fourcc( damr, "REFC" );
00895     bo_add_8( damr, 0 );
00896 
00897     if( p_stream->fmt.i_codec == VLC_FOURCC( 's', 'a', 'm', 'r' ) )
00898         bo_add_16be( damr, 0x81ff ); /* Mode set (all modes for AMR_NB) */
00899     else
00900         bo_add_16be( damr, 0x83ff ); /* Mode set (all modes for AMR_WB) */
00901     bo_add_16be( damr, 0x1 ); /* Mode change period (no restriction) */
00902 
00903     box_fix( damr );
00904 
00905     return damr;
00906 }
00907 
00908 static bo_t *GetD263Tag( mp4_stream_t *p_stream )
00909 {
00910     bo_t *d263;
00911 
00912     d263 = box_new( "d263" );
00913 
00914     bo_add_fourcc( d263, "VLC " );
00915     bo_add_16be( d263, 0xa );
00916     bo_add_8( d263, 0 );
00917 
00918     box_fix( d263 );
00919 
00920     return d263;
00921 }
00922 
00923 static bo_t *GetAvcCTag( mp4_stream_t *p_stream )
00924 {
00925     bo_t *avcC;
00926 
00927     /* FIXME use better value */
00928     avcC = box_new( "avcC" );
00929     bo_add_8( avcC, 1 );      /* configuration version */
00930     bo_add_8( avcC, p_stream->avc.i_profile );
00931     bo_add_8( avcC, p_stream->avc.i_profile );     /* profile compatible ??? */
00932     bo_add_8( avcC, p_stream->avc.i_level );       /* level, 5.1 */
00933     bo_add_8( avcC, 0xff );   /* 0b11111100 | lengthsize = 0x11 */
00934 
00935     bo_add_8( avcC, 0xe0 | (p_stream->avc.i_sps > 0 ? 1 : 0) );   /* 0b11100000 | sps_count */
00936     if( p_stream->avc.i_sps > 0 )
00937     {
00938         bo_add_16be( avcC, p_stream->avc.i_sps );
00939         bo_add_mem( avcC, p_stream->avc.i_sps, p_stream->avc.sps );
00940     }
00941 
00942     bo_add_8( avcC, (p_stream->avc.i_pps > 0 ? 1 : 0) );   /* pps_count */
00943     if( p_stream->avc.i_pps > 0 )
00944     {
00945         bo_add_16be( avcC, p_stream->avc.i_pps );
00946         bo_add_mem( avcC, p_stream->avc.i_pps, p_stream->avc.pps );
00947     }
00948     box_fix( avcC );
00949 
00950     return avcC;
00951 }
00952 
00953 /* TODO: No idea about these values */
00954 static bo_t *GetSVQ3Tag( mp4_stream_t *p_stream )
00955 {
00956     bo_t *smi = box_new( "SMI " );
00957 
00958     if( p_stream->fmt.i_extra > 0x4e )
00959     {
00960         uint8_t *p_end = &((uint8_t*)p_stream->fmt.p_extra)[p_stream->fmt.i_extra];
00961         uint8_t *p     = &((uint8_t*)p_stream->fmt.p_extra)[0x46];
00962 
00963         while( p + 8 < p_end )
00964         {
00965             int i_size = GetDWBE( p );
00966             if( i_size <= 1 )
00967             {
00968                 /* FIXME handle 1 as long size */
00969                 break;
00970             }
00971             if( !strncmp( (const char *)&p[4], "SMI ", 4 ) )
00972             {
00973                 bo_add_mem( smi, p_end - p - 8, &p[8] );
00974                 return smi;
00975             }
00976             p += i_size;
00977         }
00978     }
00979 
00980     /* Create a dummy one in fallback */
00981     bo_add_fourcc( smi, "SEQH" );
00982     bo_add_32be( smi, 0x5 );
00983     bo_add_32be( smi, 0xe2c0211d );
00984     bo_add_8( smi, 0xc0 );
00985     box_fix( smi );
00986 
00987     return smi;
00988 }
00989 
00990 static bo_t *GetUdtaTag( sout_mux_t *p_mux )
00991 {
00992     sout_mux_sys_t *p_sys = p_mux->p_sys;
00993     bo_t *udta = box_new( "udta" );
00994     vlc_meta_t *p_meta = p_mux->p_sout->p_meta;
00995     int i_track;
00996 
00997     /* Requirements */
00998     for( i_track = 0; i_track < p_sys->i_nb_streams; i_track++ )
00999     {
01000         mp4_stream_t *p_stream = p_sys->pp_streams[i_track];
01001 
01002         if( p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','v') ||
01003             p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
01004         {
01005             bo_t *box = box_new( "\251req" );
01006             /* String length */
01007             bo_add_16be( box, sizeof("QuickTime 6.0 or greater") - 1);
01008             bo_add_16be( box, 0 );
01009             bo_add_mem( box, sizeof("QuickTime 6.0 or greater") - 1,
01010                         (uint8_t *)"QuickTime 6.0 or greater" );
01011             box_fix( box );
01012             box_gather( udta, box );
01013             break;
01014         }
01015     }
01016 
01017     /* Encoder */
01018     {
01019         bo_t *box = box_new( "\251enc" );
01020         /* String length */
01021         bo_add_16be( box, sizeof(PACKAGE_STRING " stream output") - 1);
01022         bo_add_16be( box, 0 );
01023         bo_add_mem( box, sizeof(PACKAGE_STRING " stream output") - 1,
01024                     (uint8_t*)PACKAGE_STRING " stream output" );
01025         box_fix( box );
01026         box_gather( udta, box );
01027     }
01028 
01029     /* Misc atoms */
01030     if( p_meta )
01031     {
01032         int i;
01033         for( i = 0; i < p_meta->i_meta; i++ )
01034         {
01035             bo_t *box = NULL;
01036 
01037             if( !strcmp( p_meta->name[i], VLC_META_TITLE ) )
01038                 box = box_new( "\251nam" );
01039             else if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
01040                 box = box_new( "\251aut" );
01041             else if( !strcmp( p_meta->name[i], VLC_META_ARTIST ) )
01042                 box = box_new( "\251ART" );
01043             else if( !strcmp( p_meta->name[i], VLC_META_GENRE ) )
01044                 box = box_new( "\251gen" );
01045             else if( !strcmp( p_meta->name[i], VLC_META_COPYRIGHT ) )
01046                 box = box_new( "\251cpy" );
01047             else if( !strcmp( p_meta->name[i], VLC_META_DESCRIPTION ) )
01048                 box = box_new( "\251des" );
01049             else if( !strcmp( p_meta->name[i], VLC_META_DATE ) )
01050                 box = box_new( "\251day" );
01051             else if( !strcmp( p_meta->name[i], VLC_META_URL ) )
01052                 box = box_new( "\251url" );
01053 
01054             if( box )
01055             {
01056                 bo_add_16be( box, strlen( p_meta->value[i] ) );
01057                 bo_add_16be( box, 0 );
01058                 bo_add_mem( box, strlen( p_meta->value[i] ),
01059                             (uint8_t*)(p_meta->value[i]) );
01060                 box_fix( box );
01061                 box_gather( udta, box );
01062             }
01063         }
01064     }
01065 
01066     box_fix( udta );
01067     return udta;
01068 }
01069 
01070 static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
01071 {
01072     sout_mux_sys_t *p_sys = p_mux->p_sys;
01073     vlc_bool_t b_descr = VLC_FALSE;
01074     bo_t *soun;
01075     char fcc[4] = "    ";
01076     int  i;
01077 
01078     switch( p_stream->fmt.i_codec )
01079     {
01080     case VLC_FOURCC('m','p','4','a'):
01081         memcpy( fcc, "mp4a", 4 );
01082         b_descr = VLC_TRUE;
01083         break;
01084 
01085     case VLC_FOURCC('s','a','m','r'):
01086     case VLC_FOURCC('s','a','w','b'):
01087         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
01088         b_descr = VLC_TRUE;
01089         break;
01090 
01091     case VLC_FOURCC('m','p','g','a'):
01092         if( p_sys->b_mov )
01093             memcpy( fcc, ".mp3", 4 );
01094         else
01095         {
01096             memcpy( fcc, "mp4a", 4 );
01097             b_descr = VLC_TRUE;
01098         }
01099         break;
01100 
01101     default:
01102         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
01103         break;
01104     }
01105 
01106     soun = box_new( fcc );
01107     for( i = 0; i < 6; i++ )
01108     {
01109         bo_add_8( soun, 0 );        // reserved;
01110     }
01111     bo_add_16be( soun, 1 );         // data-reference-index
01112 
01113     /* SoundDescription */
01114     if( p_sys->b_mov &&
01115         p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
01116     {
01117         bo_add_16be( soun, 1 );     // version 1;
01118     }
01119     else
01120     {
01121         bo_add_16be( soun, 0 );     // version 0;
01122     }
01123     bo_add_16be( soun, 0 );         // revision level (0)
01124     bo_add_32be( soun, 0 );         // vendor
01125     // channel-count
01126     bo_add_16be( soun, p_stream->fmt.audio.i_channels );
01127     // sample size
01128     bo_add_16be( soun, p_stream->fmt.audio.i_bitspersample ?
01129                  p_stream->fmt.audio.i_bitspersample : 16 );
01130     bo_add_16be( soun, -2 );        // compression id
01131     bo_add_16be( soun, 0 );         // packet size (0)
01132     bo_add_16be( soun, p_stream->fmt.audio.i_rate ); // sampleratehi
01133     bo_add_16be( soun, 0 );                             // sampleratelo
01134 
01135     /* Extended data for SoundDescription V1 */
01136     if( p_sys->b_mov &&
01137         p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
01138     {
01139         /* samples per packet */
01140         bo_add_32be( soun, p_stream->fmt.audio.i_frame_length );
01141         bo_add_32be( soun, 1536 ); /* bytes per packet */
01142         bo_add_32be( soun, 2 );    /* bytes per frame */
01143         /* bytes per sample */
01144         bo_add_32be( soun, 2 /*p_stream->fmt.audio.i_bitspersample/8 */);
01145     }
01146 
01147     /* Add an ES Descriptor */
01148     if( b_descr )
01149     {
01150         bo_t *box;
01151 
01152         if( p_sys->b_mov &&
01153             p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
01154         {
01155             box = GetWaveTag( p_stream );
01156         }
01157         else if( p_stream->fmt.i_codec == VLC_FOURCC('s','a','m','r') )
01158         {
01159             box = GetDamrTag( p_stream );
01160         }
01161         else
01162         {
01163             box = GetESDS( p_stream );
01164         }
01165         box_fix( box );
01166         box_gather( soun, box );
01167     }
01168 
01169     box_fix( soun );
01170 
01171     return soun;
01172 }
01173 
01174 static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
01175 {
01176 
01177     bo_t *vide;
01178     char fcc[4] = "    ";
01179     int  i;
01180 
01181     switch( p_stream->fmt.i_codec )
01182     {
01183     case VLC_FOURCC('m','p','4','v'):
01184     case VLC_FOURCC('m','p','g','v'):
01185         memcpy( fcc, "mp4v", 4 );
01186         break;
01187 
01188     case VLC_FOURCC('M','J','P','G'):
01189         memcpy( fcc, "mjpa", 4 );
01190         break;
01191 
01192     case VLC_FOURCC('S','V','Q','1'):
01193         memcpy( fcc, "SVQ1", 4 );
01194         break;
01195 
01196     case VLC_FOURCC('S','V','Q','3'):
01197         memcpy( fcc, "SVQ3", 4 );
01198         break;
01199 
01200     case VLC_FOURCC('H','2','6','3'):
01201         memcpy( fcc, "s263", 4 );
01202         break;
01203 
01204     case VLC_FOURCC('h','2','6','4'):
01205         memcpy( fcc, "avc1", 4 );
01206         break;
01207 
01208     default:
01209         memcpy( fcc, (char*)&p_stream->fmt.i_codec, 4 );
01210         break;
01211     }
01212 
01213     vide = box_new( fcc );
01214     for( i = 0; i < 6; i++ )
01215     {
01216         bo_add_8( vide, 0 );        // reserved;
01217     }
01218     bo_add_16be( vide, 1 );         // data-reference-index
01219 
01220     bo_add_16be( vide, 0 );         // predefined;
01221     bo_add_16be( vide, 0 );         // reserved;
01222     for( i = 0; i < 3; i++ )
01223     {
01224         bo_add_32be( vide, 0 );     // predefined;
01225     }
01226 
01227     bo_add_16be( vide, p_stream->fmt.video.i_width );  // i_width
01228     bo_add_16be( vide, p_stream->fmt.video.i_height ); // i_height
01229 
01230     bo_add_32be( vide, 0x00480000 );                // h 72dpi
01231     bo_add_32be( vide, 0x00480000 );                // v 72dpi
01232 
01233     bo_add_32be( vide, 0 );         // data size, always 0
01234     bo_add_16be( vide, 1 );         // frames count per sample
01235 
01236     // compressor name;
01237     for( i = 0; i < 32; i++ )
01238     {
01239         bo_add_8( vide, 0 );
01240     }
01241 
01242     bo_add_16be( vide, 0x18 );      // depth
01243     bo_add_16be( vide, 0xffff );    // predefined
01244 
01245     /* add an ES Descriptor */
01246     switch( p_stream->fmt.i_codec )
01247     {
01248     case VLC_FOURCC('m','p','4','v'):
01249     case VLC_FOURCC('m','p','g','v'):
01250         {
01251             bo_t *esds = GetESDS( p_stream );
01252 
01253             box_fix( esds );
01254             box_gather( vide, esds );
01255         }
01256         break;
01257 
01258     case VLC_FOURCC('H','2','6','3'):
01259         {
01260             bo_t *d263 = GetD263Tag( p_stream );
01261 
01262             box_fix( d263 );
01263             box_gather( vide, d263 );
01264         }
01265         break;
01266 
01267     case VLC_FOURCC('S','V','Q','3'):
01268         {
01269             bo_t *esds = GetSVQ3Tag( p_stream );
01270 
01271             box_fix( esds );
01272             box_gather( vide, esds );
01273         }
01274         break;
01275 
01276     case VLC_FOURCC('h','2','6','4'):
01277         box_gather( vide, GetAvcCTag( p_stream ) );
01278         break;
01279 
01280     default:
01281         break;
01282     }
01283 
01284     box_fix( vide );
01285 
01286     return vide;
01287 }
01288 
01289 static bo_t *GetTextBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
01290 {
01291 
01292     bo_t *text = box_new( "text" );
01293     int  i;
01294 
01295     for( i = 0; i < 6; i++ )
01296     {
01297         bo_add_8( text, 0 );        // reserved;
01298     }
01299     bo_add_16be( text, 1 );         // data-reference-index
01300 
01301     bo_add_32be( text, 0 );         // display flags
01302     bo_add_32be( text, 0 );         // justification
01303     for( i = 0; i < 3; i++ )
01304     {
01305         bo_add_16be( text, 0 );     // back ground color
01306     }
01307 
01308     bo_add_16be( text, 0 );         // box text
01309     bo_add_16be( text, 0 );         // box text
01310     bo_add_16be( text, 0 );         // box text
01311     bo_add_16be( text, 0 );         // box text
01312 
01313     bo_add_64be( text, 0 );         // reserved
01314     for( i = 0; i < 3; i++ )
01315     {
01316         bo_add_16be( text, 0xff );  // foreground color
01317     }
01318 
01319     bo_add_8 ( text, 9 );
01320     bo_add_mem( text, 9, (uint8_t*)"Helvetica" );
01321 
01322     box_fix( text );
01323 
01324     return text;
01325 }
01326 
01327 static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
01328 {
01329     sout_mux_sys_t *p_sys = p_mux->p_sys;
01330     unsigned int i_chunk, i_stsc_last_val, i_stsc_entries, i, i_index;
01331     bo_t *stbl, *stsd, *stts, *stco, *stsc, *stsz, *stss;
01332     uint32_t i_timescale;
01333     int64_t i_dts, i_dts_q;
01334 
01335     stbl = box_new( "stbl" );
01336 
01337     /* sample description */
01338     stsd = box_full_new( "stsd", 0, 0 );
01339     bo_add_32be( stsd, 1 );
01340     if( p_stream->fmt.i_cat == AUDIO_ES )
01341     {
01342         bo_t *soun = GetSounBox( p_mux, p_stream );
01343         box_gather( stsd, soun );
01344     }
01345     else if( p_stream->fmt.i_cat == VIDEO_ES )
01346     {
01347         bo_t *vide = GetVideBox( p_mux, p_stream );
01348         box_gather( stsd, vide );
01349     }
01350     else if( p_stream->fmt.i_cat == SPU_ES )
01351     {
01352         box_gather( stsd, GetTextBox( p_mux, p_stream ) );
01353     }
01354     box_fix( stsd );
01355 
01356     /* chunk offset table */
01357     if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
01358     {
01359         /* 64 bits version */
01360         p_stream->b_stco64 = VLC_TRUE;
01361         stco = box_full_new( "co64", 0, 0 );
01362     }
01363     else
01364     {
01365         /* 32 bits version */
01366         p_stream->b_stco64 = VLC_FALSE;
01367         stco = box_full_new( "stco", 0, 0 );
01368     }
01369     bo_add_32be( stco, 0 );     // entry-count (fixed latter)
01370 
01371     /* sample to chunk table */
01372     stsc = box_full_new( "stsc", 0, 0 );
01373     bo_add_32be( stsc, 0 );     // entry-count (fixed latter)
01374 
01375     for( i_chunk = 0, i_stsc_last_val = 0, i_stsc_entries = 0, i = 0;
01376          i < p_stream->i_entry_count; i_chunk++ )
01377     {
01378         int i_first = i;
01379 
01380         if( p_stream->b_stco64 )
01381             bo_add_64be( stco, p_stream->entry[i].i_pos );
01382         else
01383             bo_add_32be( stco, p_stream->entry[i].i_pos );
01384 
01385         while( i < p_stream->i_entry_count )
01386         {
01387             if( i + 1 < p_stream->i_entry_count &&
01388                 p_stream->entry[i].i_pos + p_stream->entry[i].i_size
01389                 != p_stream->entry[i + 1].i_pos )
01390             {
01391                 i++;
01392                 break;
01393             }
01394 
01395             i++;
01396         }
01397 
01398         /* Add entry to the stsc table */
01399         if( i_stsc_last_val != i - i_first )
01400         {
01401             bo_add_32be( stsc, 1 + i_chunk );   // first-chunk
01402             bo_add_32be( stsc, i - i_first ) ;  // samples-per-chunk
01403             bo_add_32be( stsc, 1 );             // sample-descr-index
01404             i_stsc_last_val = i - i_first;
01405             i_stsc_entries++;
01406         }
01407     }
01408 
01409     /* Fix stco entry count */
01410     bo_fix_32be( stco, 12, i_chunk );
01411     msg_Dbg( p_mux, "created %d chunks (stco)", i_chunk );
01412     box_fix( stco );
01413 
01414     /* Fix stsc entry count */
01415     bo_fix_32be( stsc, 12, i_stsc_entries  );
01416     box_fix( stsc );
01417 
01418     /* add stts */
01419     stts = box_full_new( "stts", 0, 0 );
01420     bo_add_32be( stts, 0 );     // entry-count (fixed latter)
01421 
01422     if( p_stream->fmt.i_cat == AUDIO_ES )
01423         i_timescale = p_stream->fmt.audio.i_rate;
01424     else
01425         i_timescale = 1001;
01426 
01427     /* first, create quantified length */
01428     for( i = 0, i_dts = 0, i_dts_q = 0; i < p_stream->i_entry_count; i++ )
01429     {
01430         int64_t i_dts_deq = i_dts_q * I64C(1000000) / (int64_t)i_timescale;
01431         int64_t i_delta = p_stream->entry[i].i_length + i_dts - i_dts_deq;
01432 
01433         i_dts += p_stream->entry[i].i_length;
01434 
01435         p_stream->entry[i].i_length =
01436             i_delta * (int64_t)i_timescale / I64C(1000000);
01437 
01438         i_dts_q += p_stream->entry[i].i_length;
01439     }
01440     /* then write encoded table */
01441     for( i = 0, i_index = 0; i < p_stream->i_entry_count; i_index++)
01442     {
01443         int     i_first = i;
01444         int64_t i_delta = p_stream->entry[i].i_length;
01445 
01446         while( i < p_stream->i_entry_count )
01447         {
01448             i++;
01449             if( i >= p_stream->i_entry_count ||
01450                 p_stream->entry[i].i_length != i_delta )
01451             {
01452                 break;
01453             }
01454         }
01455 
01456         bo_add_32be( stts, i - i_first ); // sample-count
01457         bo_add_32be( stts, i_delta );     // sample-delta
01458     }
01459     bo_fix_32be( stts, 12, i_index );
01460     box_fix( stts );
01461 
01462     /* FIXME add ctts ?? FIXME */
01463 
01464     stsz = box_full_new( "stsz", 0, 0 );
01465     bo_add_32be( stsz, 0 );                             // sample-size
01466     bo_add_32be( stsz, p_stream->i_entry_count );       // sample-count
01467     for( i = 0; i < p_stream->i_entry_count; i++ )
01468     {
01469         bo_add_32be( stsz, p_stream->entry[i].i_size ); // sample-size
01470     }
01471     box_fix( stsz );
01472 
01473     /* create stss table */
01474     stss = NULL;
01475     for( i = 0, i_index = 0; i < p_stream->i_entry_count; i++ )
01476     {
01477         if( p_stream->entry[i].i_flags & BLOCK_FLAG_TYPE_I )
01478         {
01479             if( stss == NULL )
01480             {
01481                 stss = box_full_new( "stss", 0, 0 );
01482                 bo_add_32be( stss, 0 ); /* fixed later */
01483             }
01484             bo_add_32be( stss, 1 + i );
01485             i_index++;
01486         }
01487     }
01488     if( stss )
01489     {
01490         bo_fix_32be( stss, 12, i_index );
01491         box_fix( stss );
01492     }
01493 
01494     /* Now gather all boxes into stbl */
01495     box_gather( stbl, stsd );
01496     box_gather( stbl, stts );
01497     if( stss )
01498     {
01499         box_gather( stbl, stss );
01500     }
01501     box_gather( stbl, stsc );
01502     box_gather( stbl, stsz );
01503     p_stream->i_stco_pos = stbl->i_buffer + 16;
01504     box_gather( stbl, stco );
01505 
01506     /* finish stbl */
01507     box_fix( stbl );
01508 
01509     return stbl;
01510 }
01511 
01512 static int64_t get_timestamp();
01513 
01514 static uint32_t mvhd_matrix[9] =
01515     { 0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000 };
01516 
01517 static bo_t *GetMoovBox( sout_mux_t *p_mux )
01518 {
01519     sout_mux_sys_t *p_sys = p_mux->p_sys;
01520 
01521     bo_t            *moov, *mvhd;
01522     int             i_trak, i;
01523 
01524     uint32_t        i_movie_timescale = 90000;
01525     int64_t         i_movie_duration  = 0;
01526 
01527     moov = box_new( "moov" );
01528 
01529     /* Create general info */
01530     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
01531     {
01532         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
01533         i_movie_duration = __MAX( i_movie_duration, p_stream->i_duration );
01534     }
01535     msg_Dbg( p_mux, "movie duration %ds",
01536              (uint32_t)( i_movie_duration / (mtime_t)1000000 ) );
01537 
01538     i_movie_duration = i_movie_duration * i_movie_timescale / 1000000;
01539 
01540     /* *** add /moov/mvhd *** */
01541     if( !p_sys->b_64_ext )
01542     {
01543         mvhd = box_full_new( "mvhd", 0, 0 );
01544         bo_add_32be( mvhd, get_timestamp() );   // creation time
01545         bo_add_32be( mvhd, get_timestamp() );   // modification time
01546         bo_add_32be( mvhd, i_movie_timescale);  // timescale
01547         bo_add_32be( mvhd, i_movie_duration );  // duration
01548     }
01549     else
01550     {
01551         mvhd = box_full_new( "mvhd", 1, 0 );
01552         bo_add_64be( mvhd, get_timestamp() );   // creation time
01553         bo_add_64be( mvhd, get_timestamp() );   // modification time
01554         bo_add_32be( mvhd, i_movie_timescale);  // timescale
01555         bo_add_64be( mvhd, i_movie_duration );  // duration
01556     }
01557     bo_add_32be( mvhd, 0x10000 );           // rate
01558     bo_add_16be( mvhd, 0x100 );             // volume
01559     bo_add_16be( mvhd, 0 );                 // reserved
01560     for( i = 0; i < 2; i++ )
01561     {
01562         bo_add_32be( mvhd, 0 );             // reserved
01563     }
01564     for( i = 0; i < 9; i++ )
01565     {
01566         bo_add_32be( mvhd, mvhd_matrix[i] );// matrix
01567     }
01568     for( i = 0; i < 6; i++ )
01569     {
01570         bo_add_32be( mvhd, 0 );             // pre-defined
01571     }
01572 
01573     /* Next available track id */
01574     bo_add_32be( mvhd, p_sys->i_nb_streams + 1 ); // next-track-id
01575 
01576     box_fix( mvhd );
01577     box_gather( moov, mvhd );
01578 
01579     for( i_trak = 0; i_trak < p_sys->i_nb_streams; i_trak++ )
01580     {
01581         mp4_stream_t *p_stream;
01582         uint32_t     i_timescale;
01583 
01584         bo_t *trak, *tkhd, *edts, *elst, *mdia, *mdhd, *hdlr;
01585         bo_t *minf, *dinf, *dref, *url, *stbl;
01586 
01587         p_stream = p_sys->pp_streams[i_trak];
01588 
01589         if( p_stream->fmt.i_cat == AUDIO_ES )
01590             i_timescale = p_stream->fmt.audio.i_rate;
01591         else
01592             i_timescale = 1001;
01593 
01594         /* *** add /moov/trak *** */
01595         trak = box_new( "trak" );
01596 
01597         /* *** add /moov/trak/tkhd *** */
01598         if( !p_sys->b_64_ext )
01599         {
01600             if( p_sys->b_mov )
01601                 tkhd = box_full_new( "tkhd", 0, 0x0f );
01602             else
01603                 tkhd = box_full_new( "tkhd", 0, 1 );
01604 
01605             bo_add_32be( tkhd, get_timestamp() );       // creation time
01606             bo_add_32be( tkhd, get_timestamp() );       // modification time
01607             bo_add_32be( tkhd, p_stream->i_track_id );
01608             bo_add_32be( tkhd, 0 );                     // reserved 0
01609             bo_add_32be( tkhd, p_stream->i_duration *
01610                          (int64_t)i_movie_timescale /
01611                          (mtime_t)1000000 );            // duration
01612         }
01613         else
01614         {
01615             if( p_sys->b_mov )
01616                 tkhd = box_full_new( "tkhd", 1, 0x0f );
01617             else
01618                 tkhd = box_full_new( "tkhd", 1, 1 );
01619 
01620             bo_add_64be( tkhd, get_timestamp() );       // creation time
01621             bo_add_64be( tkhd, get_timestamp() );       // modification time
01622             bo_add_32be( tkhd, p_stream->i_track_id );
01623             bo_add_32be( tkhd, 0 );                     // reserved 0
01624             bo_add_64be( tkhd, p_stream->i_duration *
01625                          (int64_t)i_movie_timescale /
01626                          (mtime_t)1000000 );            // duration
01627         }
01628 
01629         for( i = 0; i < 2; i++ )
01630         {
01631             bo_add_32be( tkhd, 0 );                 // reserved
01632         }
01633         bo_add_16be( tkhd, 0 );                     // layer
01634         bo_add_16be( tkhd, 0 );                     // pre-defined
01635         // volume
01636         bo_add_16be( tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0 );
01637         bo_add_16be( tkhd, 0 );                     // reserved
01638         for( i = 0; i < 9; i++ )
01639         {
01640             bo_add_32be( tkhd, mvhd_matrix[i] );    // matrix
01641         }
01642         if( p_stream->fmt.i_cat == AUDIO_ES )
01643         {
01644             bo_add_32be( tkhd, 0 );                 // width (presentation)
01645             bo_add_32be( tkhd, 0 );                 // height(presentation)
01646         }
01647         else if( p_stream->fmt.i_cat == VIDEO_ES )
01648         {
01649             int i_width = p_stream->fmt.video.i_width << 16;
01650             if( p_stream->fmt.video.i_aspect > 0 )
01651             {
01652                 i_width = (int64_t)p_stream->fmt.video.i_aspect *
01653                           ((int64_t)p_stream->fmt.video.i_height << 16) /
01654                           VOUT_ASPECT_FACTOR;
01655             }
01656             // width (presentation)
01657             bo_add_32be( tkhd, i_width );
01658             // height(presentation)
01659             bo_add_32be( tkhd, p_stream->fmt.video.i_height << 16 );
01660         }
01661         else
01662         {
01663             int i_width = 320 << 16;
01664             int i_height = 200;
01665             int i;
01666             for( i = 0; i < p_sys->i_nb_streams; i++ )
01667             {
01668                 mp4_stream_t *tk = p_sys->pp_streams[i];
01669                 if( tk->fmt.i_cat == VIDEO_ES )
01670                 {
01671                     if( p_stream->fmt.video.i_aspect )
01672                         i_width = (int64_t)p_stream->fmt.video.i_aspect *
01673                                    ((int64_t)p_stream->fmt.video.i_height<<16) / VOUT_ASPECT_FACTOR;
01674                     else
01675                         i_width = p_stream->fmt.video.i_width << 16;
01676                     i_height = p_stream->fmt.video.i_height;
01677                     break;
01678                 }
01679             }
01680             bo_add_32be( tkhd, i_width );     // width (presentation)
01681             bo_add_32be( tkhd, i_height << 16 );    // height(presentation)
01682         }
01683 
01684         box_fix( tkhd );
01685         box_gather( trak, tkhd );
01686 
01687         /* *** add /moov/trak/edts and elst */
01688         edts = box_new( "edts" );
01689         elst = box_full_new( "elst", p_sys->b_64_ext ? 1 : 0, 0 );
01690         if( p_stream->i_dts_start > p_sys->i_dts_start )
01691         {
01692             bo_add_32be( elst, 2 );
01693 
01694             if( p_sys->b_64_ext )
01695             {
01696                 bo_add_64be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
01697                              i_movie_timescale / I64C(1000000) );
01698                 bo_add_64be( elst, -1 );
01699             }
01700             else
01701             {
01702                 bo_add_32be( elst, (p_stream->i_dts_start-p_sys->i_dts_start) *
01703                              i_movie_timescale / I64C(1000000) );
01704                 bo_add_32be( elst, -1 );
01705             }
01706             bo_add_16be( elst, 1 );
01707             bo_add_16be( elst, 0 );
01708         }
01709         else
01710         {
01711             bo_add_32be( elst, 1 );
01712         }
01713         if( p_sys->b_64_ext )
01714         {
01715             bo_add_64be( elst, p_stream->i_duration *
01716                          i_movie_timescale / I64C(1000000) );
01717             bo_add_64be( elst, 0 );
01718         }
01719         else
01720         {
01721             bo_add_32be( elst, p_stream->i_duration *
01722                          i_movie_timescale / I64C(1000000) );
01723             bo_add_32be( elst, 0 );
01724         }
01725         bo_add_16be( elst, 1 );
01726         bo_add_16be( elst, 0 );
01727 
01728         box_fix( elst );
01729         box_gather( edts, elst );
01730         box_fix( edts );
01731         box_gather( trak, edts );
01732 
01733         /* *** add /moov/trak/mdia *** */
01734         mdia = box_new( "mdia" );
01735 
01736         /* media header */
01737         if( !p_sys->b_64_ext )
01738         {
01739             mdhd = box_full_new( "mdhd", 0, 0 );
01740             bo_add_32be( mdhd, get_timestamp() );   // creation time
01741             bo_add_32be( mdhd, get_timestamp() );   // modification time
01742             bo_add_32be( mdhd, i_timescale);        // timescale
01743             bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
01744                                (mtime_t)1000000 );  // duration
01745         }
01746         else
01747         {
01748             mdhd = box_full_new( "mdhd", 1, 0 );
01749             bo_add_64be( mdhd, get_timestamp() );   // creation time
01750             bo_add_64be( mdhd, get_timestamp() );   // modification time
01751             bo_add_32be( mdhd, i_timescale);        // timescale
01752             bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
01753                                (mtime_t)1000000 );  // duration
01754         }
01755 
01756         if( p_stream->fmt.psz_language )
01757         {
01758             char *psz = p_stream->fmt.psz_language;
01759             const iso639_lang_t *pl = NULL;
01760             uint16_t lang = 0x0;
01761 
01762             if( strlen( psz ) == 2 )
01763             {
01764                 pl = GetLang_1( psz );
01765             }
01766             else if( strlen( psz ) == 3 )
01767             {
01768                 pl = GetLang_2B( psz );
01769                 if( !strcmp( pl->psz_iso639_1, "??" ) )
01770                 {
01771                     pl = GetLang_2T( psz );
01772                 }
01773             }
01774             if( pl && strcmp( pl->psz_iso639_1, "??" ) )
01775             {
01776                 lang = ( ( pl->psz_iso639_2T[0] - 0x60 ) << 10 ) |
01777                        ( ( pl->psz_iso639_2T[1] - 0x60 ) <<  5 ) |
01778                        ( ( pl->psz_iso639_2T[2] - 0x60 ) );
01779             }
01780             bo_add_16be( mdhd, lang );          // language
01781         }
01782         else
01783         {
01784             bo_add_16be( mdhd, 0    );          // language
01785         }
01786         bo_add_16be( mdhd, 0    );              // predefined
01787         box_fix( mdhd );
01788         box_gather( mdia, mdhd );
01789 
01790         /* handler reference */
01791         hdlr = box_full_new( "hdlr", 0, 0 );
01792 
01793         if( p_sys->b_mov )
01794             bo_add_fourcc( hdlr, "mhlr" );         // media handler
01795         else
01796             bo_add_32be( hdlr, 0 );
01797 
01798         if( p_stream->fmt.i_cat == AUDIO_ES )
01799             bo_add_fourcc( hdlr, "soun" );
01800         else if( p_stream->fmt.i_cat == VIDEO_ES )
01801             bo_add_fourcc( hdlr, "vide" );
01802         else if( p_stream->fmt.i_cat == SPU_ES )
01803             bo_add_fourcc( hdlr, "text" );
01804 
01805         bo_add_32be( hdlr, 0 );         // reserved
01806         bo_add_32be( hdlr, 0 );         // reserved
01807         bo_add_32be( hdlr, 0 );         // reserved
01808 
01809         if( p_sys->b_mov )
01810             bo_add_8( hdlr, 12 );   /* Pascal string for .mov */
01811 
01812         if( p_stream->fmt.i_cat == AUDIO_ES )
01813             bo_add_mem( hdlr, 12, (uint8_t*)"SoundHandler" );
01814         else if( p_stream->fmt.i_cat == VIDEO_ES )
01815             bo_add_mem( hdlr, 12, (uint8_t*)"VideoHandler" );
01816         else
01817             bo_add_mem( hdlr, 12, (uint8_t*)"Text Handler" );
01818 
01819         if( !p_sys->b_mov )
01820             bo_add_8( hdlr, 0 );   /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
01821 
01822         box_fix( hdlr );
01823         box_gather( mdia, hdlr );
01824 
01825         /* minf*/
01826         minf = box_new( "minf" );
01827 
01828         /* add smhd|vmhd */
01829         if( p_stream->fmt.i_cat == AUDIO_ES )
01830         {
01831             bo_t *smhd;
01832 
01833             smhd = box_full_new( "smhd", 0, 0 );
01834             bo_add_16be( smhd, 0 );     // balance
01835             bo_add_16be( smhd, 0 );     // reserved
01836             box_fix( smhd );
01837 
01838             box_gather( minf, smhd );
01839         }
01840         else if( p_stream->fmt.i_cat == VIDEO_ES )
01841         {
01842             bo_t *vmhd;
01843 
01844             vmhd = box_full_new( "vmhd", 0, 1 );
01845             bo_add_16be( vmhd, 0 );     // graphicsmode
01846             for( i = 0; i < 3; i++ )
01847             {
01848                 bo_add_16be( vmhd, 0 ); // opcolor
01849             }
01850             box_fix( vmhd );
01851 
01852             box_gather( minf, vmhd );
01853         }
01854         else if( p_stream->fmt.i_cat == SPU_ES )
01855         {
01856             bo_t *gmhd = box_new( "gmhd" );
01857             bo_t *gmin = box_full_new( "gmin", 0, 1 );
01858 
01859             bo_add_16be( gmin, 0 );     // graphicsmode
01860             for( i = 0; i < 3; i++ )
01861             {
01862                 bo_add_16be( gmin, 0 ); // opcolor
01863             }
01864             bo_add_16be( gmin, 0 );     // balance
01865             bo_add_16be( gmin, 0 );     // reserved
01866             box_fix( gmin );
01867 
01868             box_gather( gmhd, gmin );
01869             box_fix( gmhd );
01870 
01871             box_gather( minf, gmhd );
01872         }
01873 
01874         /* dinf */
01875         dinf = box_new( "dinf" );
01876         dref = box_full_new( "dref", 0, 0 );
01877         bo_add_32be( dref, 1 );
01878         url = box_full_new( "url ", 0, 0x01 );
01879         box_fix( url );
01880         box_gather( dref, url );
01881         box_fix( dref );
01882         box_gather( dinf, dref );
01883 
01884         /* append dinf to mdia */
01885         box_fix( dinf );
01886         box_gather( minf, dinf );
01887 
01888         /* add stbl */
01889         stbl = GetStblBox( p_mux, p_stream );
01890 
01891         /* append stbl to minf */
01892         p_stream->i_stco_pos += minf->i_buffer;
01893         box_gather( minf, stbl );
01894 
01895         /* append minf to mdia */
01896         box_fix( minf );
01897         p_stream->i_stco_pos += mdia->i_buffer;
01898         box_gather( mdia, minf );
01899 
01900         /* append mdia to trak */
01901         box_fix( mdia );
01902         p_stream->i_stco_pos += trak->i_buffer;
01903         box_gather( trak, mdia );
01904 
01905         /* append trak to moov */
01906         box_fix( trak );
01907         p_stream->i_stco_pos += moov->i_buffer;
01908         box_gather( moov, trak );
01909     }
01910 
01911     /* Add user data tags */
01912     box_gather( moov, GetUdtaTag( p_mux ) );
01913 
01914     box_fix( moov );
01915     return moov;
01916 }
01917 
01918 /****************************************************************************/
01919 
01920 static void bo_init( bo_t *p_bo, int i_size, uint8_t *p_buffer,
01921                      vlc_bool_t b_grow )
01922 {
01923     if( !p_buffer )
01924     {
01925         p_bo->i_buffer_size = __MAX( i_size, 1024 );
01926         p_bo->p_buffer = malloc( p_bo->i_buffer_size );
01927     }
01928     else
01929     {
01930         p_bo->i_buffer_size = i_size;
01931         p_bo->p_buffer = p_buffer;
01932     }
01933 
01934     p_bo->b_grow = b_grow;
01935     p_bo->i_buffer = 0;
01936 }
01937 
01938 static void bo_add_8( bo_t *p_bo, uint8_t i )
01939 {
01940     if( p_bo->i_buffer < p_bo->i_buffer_size )
01941     {
01942         p_bo->p_buffer[p_bo->i_buffer] = i;
01943     }
01944     else if( p_bo->b_grow )
01945     {
01946         p_bo->i_buffer_size += 1024;
01947         p_bo->p_buffer = realloc( p_bo->p_buffer, p_bo->i_buffer_size );
01948 
01949         p_bo->p_buffer[p_bo->i_buffer] = i;
01950     }
01951 
01952     p_bo->i_buffer++;
01953 }
01954 
01955 static void bo_add_16be( bo_t *p_bo, uint16_t i )
01956 {
01957     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
01958     bo_add_8( p_bo, i &0xff );
01959 }
01960 
01961 static void bo_add_24be( bo_t *p_bo, uint32_t i )
01962 {
01963     bo_add_8( p_bo, ( ( i >> 16) &0xff ) );
01964     bo_add_8( p_bo, ( ( i >> 8) &0xff ) );
01965     bo_add_8( p_bo, (   i &0xff ) );
01966 }
01967 static void bo_add_32be( bo_t *p_bo, uint32_t i )
01968 {
01969     bo_add_16be( p_bo, ( ( i >> 16) &0xffff ) );
01970     bo_add_16be( p_bo, i &0xffff );
01971 }
01972 
01973 static void bo_fix_32be ( bo_t *p_bo, int i_pos, uint32_t i)
01974 {
01975     p_bo->p_buffer[i_pos    ] = ( i >> 24 )&0xff;
01976     p_bo->p_buffer[i_pos + 1] = ( i >> 16 )&0xff;
01977     p_bo->p_buffer[i_pos + 2] = ( i >>  8 )&0xff;
01978     p_bo->p_buffer[i_pos + 3] = ( i       )&0xff;
01979 }
01980 
01981 static void bo_add_64be( bo_t *p_bo, uint64_t i )
01982 {
01983     bo_add_32be( p_bo, ( ( i >> 32) &0xffffffff ) );
01984     bo_add_32be( p_bo, i &0xffffffff );
01985 }
01986 
01987 static void bo_add_fourcc( bo_t *p_bo, char *fcc )
01988 {
01989     bo_add_8( p_bo, fcc[0] );
01990     bo_add_8( p_bo, fcc[1] );
01991     bo_add_8( p_bo, fcc[2] );
01992     bo_add_8( p_bo, fcc[3] );
01993 }
01994 
01995 static void bo_add_mem( bo_t *p_bo, int i_size, uint8_t *p_mem )
01996 {
01997     int i;
01998 
01999     for( i = 0; i < i_size; i++ )
02000     {
02001         bo_add_8( p_bo, p_mem[i] );
02002     }
02003 }
02004 
02005 static void bo_add_descr( bo_t *p_bo, uint8_t tag, uint32_t i_size )
02006 {
02007     uint32_t i_length;
02008     uint8_t  vals[4];
02009 
02010     i_length = i_size;
02011     vals[3] = (unsigned char)(i_length & 0x7f);
02012     i_length >>= 7;
02013     vals[2] = (unsigned char)((i_length & 0x7f) | 0x80); 
02014     i_length >>= 7;
02015     vals[1] = (unsigned char)((i_length & 0x7f) | 0x80); 
02016     i_length >>= 7;
02017     vals[0] = (unsigned char)((i_length & 0x7f) | 0x80);
02018 
02019     bo_add_8( p_bo, tag );
02020 
02021     if( i_size < 0x00000080 )
02022     {
02023         bo_add_8( p_bo, vals[3] );
02024     }
02025     else if( i_size < 0x00004000 )
02026     {
02027         bo_add_8( p_bo, vals[2] );
02028         bo_add_8( p_bo, vals[3] );
02029     }
02030     else if( i_size < 0x00200000 )
02031     {
02032         bo_add_8( p_bo, vals[1] );
02033         bo_add_8( p_bo, vals[2] );
02034         bo_add_8( p_bo, vals[3] );
02035     }
02036     else if( i_size < 0x10000000 )
02037     {
02038         bo_add_8( p_bo, vals[0] );
02039         bo_add_8( p_bo, vals[1] );
02040         bo_add_8( p_bo, vals[2] );
02041         bo_add_8( p_bo, vals[3] );
02042     }
02043 }
02044 
02045 static void bo_add_bo( bo_t *p_bo, bo_t *p_bo2 )
02046 {
02047     int i;
02048 
02049     for( i = 0; i < p_bo2->i_buffer; i++ )
02050     {
02051         bo_add_8( p_bo, p_bo2->p_buffer[i] );
02052     }
02053 }
02054 
02055 static bo_t * box_new( char *fcc )
02056 {
02057     bo_t *box;
02058 
02059     if( ( box = malloc( sizeof( bo_t ) ) ) )
02060     {
02061         bo_init( box, 0, NULL, VLC_TRUE );
02062 
02063         bo_add_32be  ( box, 0 );
02064         bo_add_fourcc( box, fcc );
02065     }
02066 
02067     return box;
02068 }
02069 
02070 static bo_t * box_full_new( char *fcc, uint8_t v, uint32_t f )
02071 {
02072     bo_t *box;
02073 
02074     if( ( box = malloc( sizeof( bo_t ) ) ) )
02075     {
02076         bo_init( box, 0, NULL, VLC_TRUE );
02077 
02078         bo_add_32be  ( box, 0 );
02079         bo_add_fourcc( box, fcc );
02080         bo_add_8     ( box, v );
02081         bo_add_24be  ( box, f );
02082     }
02083 
02084     return box;
02085 }
02086 
02087 static void box_fix( bo_t *box )
02088 {
02089     bo_t box_tmp;
02090 
02091     memcpy( &box_tmp, box, sizeof( bo_t ) );
02092 
02093     box_tmp.i_buffer = 0;
02094     bo_add_32be( &box_tmp, box->i_buffer );
02095 }
02096 
02097 static void box_free( bo_t *box )
02098 {
02099     if( box->p_buffer )
02100     {
02101         free( box->p_buffer );
02102     }
02103 
02104     free( box );
02105 }
02106 
02107 static void box_gather ( bo_t *box, bo_t *box2 )
02108 {
02109     bo_add_bo( box, box2 );
02110     box_free( box2 );
02111 }
02112 
02113 static block_t * bo_to_sout( sout_instance_t *p_sout,  bo_t *box )
02114 {
02115     block_t *p_buf;
02116 
02117     p_buf = block_New( p_sout, box->i_buffer );
02118     if( box->i_buffer > 0 )
02119     {
02120         memcpy( p_buf->p_buffer, box->p_buffer, box->i_buffer );
02121     }
02122 
02123     return p_buf;
02124 }
02125 
02126 static void box_send( sout_mux_t *p_mux,  bo_t *box )
02127 {
02128     block_t *p_buf;
02129 
02130     p_buf = bo_to_sout( p_mux->p_sout, box );
02131     box_free( box );
02132 
02133     sout_AccessOutWrite( p_mux->p_access, p_buf );
02134 }
02135 
02136 static int64_t get_timestamp()
02137 {
02138     int64_t i_timestamp = 0;
02139 
02140 #ifdef HAVE_TIME_H
02141     i_timestamp = time(NULL);
02142     i_timestamp += 2082844800; // MOV/MP4 start date is 1/1/1904
02143     // 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
02144 #endif
02145 
02146     return i_timestamp;
02147 }

Generated on Tue Dec 20 10:14:34 2005 for vlc-0.8.4a by  doxygen 1.4.2