00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
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
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
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
00108 int64_t i_dts_start;
00109 int64_t i_duration;
00110
00111
00112 uint64_t i_stco_pos;
00113 vlc_bool_t b_stco64;
00114
00115
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
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
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
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
00230
00231 p_sys->b_64_ext = VLC_FALSE;
00232
00233
00234 box = box_new( "mdat" );
00235 bo_add_64be ( box, 0 );
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
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
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
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
00283 i_moov_pos = p_sys->i_pos;
00284 moov = GetMoovBox( p_mux );
00285
00286
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
00292
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
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
00355 sout_AccessOutSeek( p_mux->p_access, i_moov_pos );
00356 box_send( p_mux, moov );
00357
00358
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
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:
00393 default:
00394 return VLC_EGENERIC;
00395 }
00396 }
00397
00398
00399
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
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;
00480 }
00481
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
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
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 ) )
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
00565 if( p_stream->i_entry_count == 0 )
00566 {
00567 p_stream->i_dts_start = p_data->i_dts;
00568
00569
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
00584 i_length = 1;
00585 }
00586
00587
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
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
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
00614 p_stream->i_duration += p_data->i_length;
00615 p_sys->i_pos += p_data->i_buffer;
00616
00617
00618 p_stream->i_last_dts = p_data->i_dts;
00619
00620
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
00630 msg_Dbg( p_mux, "writing a empty subs" ) ;
00631
00632
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
00640 p_stream->i_entry_count++;
00641
00642
00643 p_stream->i_last_dts += i_length;
00644
00645
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
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
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;
00684 uint8_t *dat = &p_block->p_buffer[4];
00685 uint8_t *end = &p_block->p_buffer[p_block->i_buffer];
00686
00687
00688
00689
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
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 )
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 )
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
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
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 );
00798
00799
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
00809 i_object_type_indication = 0x60;
00810 break;
00811 case VLC_FOURCC( 'm', 'p', '4', 'a' ):
00812
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 );
00828 bo_add_32be( esds, i_bitrate_max );
00829 bo_add_32be( esds, i_bitrate_avg );
00830
00831 if( p_stream->fmt.i_extra > 0 )
00832 {
00833 int i;
00834
00835
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
00845 bo_add_descr( esds, 0x06, 1 );
00846 bo_add_8 ( esds, 0x02 );
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
00880 bo_add_32be( wave, 8 );
00881 bo_add_32be( wave, 0 );
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 );
00899 else
00900 bo_add_16be( damr, 0x83ff );
00901 bo_add_16be( damr, 0x1 );
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
00928 avcC = box_new( "avcC" );
00929 bo_add_8( avcC, 1 );
00930 bo_add_8( avcC, p_stream->avc.i_profile );
00931 bo_add_8( avcC, p_stream->avc.i_profile );
00932 bo_add_8( avcC, p_stream->avc.i_level );
00933 bo_add_8( avcC, 0xff );
00934
00935 bo_add_8( avcC, 0xe0 | (p_stream->avc.i_sps > 0 ? 1 : 0) );
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) );
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
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
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
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
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
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
01018 {
01019 bo_t *box = box_new( "\251enc" );
01020
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
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 );
01110 }
01111 bo_add_16be( soun, 1 );
01112
01113
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 );
01118 }
01119 else
01120 {
01121 bo_add_16be( soun, 0 );
01122 }
01123 bo_add_16be( soun, 0 );
01124 bo_add_32be( soun, 0 );
01125
01126 bo_add_16be( soun, p_stream->fmt.audio.i_channels );
01127
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 );
01131 bo_add_16be( soun, 0 );
01132 bo_add_16be( soun, p_stream->fmt.audio.i_rate );
01133 bo_add_16be( soun, 0 );
01134
01135
01136 if( p_sys->b_mov &&
01137 p_stream->fmt.i_codec == VLC_FOURCC('m','p','4','a') )
01138 {
01139
01140 bo_add_32be( soun, p_stream->fmt.audio.i_frame_length );
01141 bo_add_32be( soun, 1536 );
01142 bo_add_32be( soun, 2 );
01143
01144 bo_add_32be( soun, 2 );
01145 }
01146
01147
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 );
01217 }
01218 bo_add_16be( vide, 1 );
01219
01220 bo_add_16be( vide, 0 );
01221 bo_add_16be( vide, 0 );
01222 for( i = 0; i < 3; i++ )
01223 {
01224 bo_add_32be( vide, 0 );
01225 }
01226
01227 bo_add_16be( vide, p_stream->fmt.video.i_width );
01228 bo_add_16be( vide, p_stream->fmt.video.i_height );
01229
01230 bo_add_32be( vide, 0x00480000 );
01231 bo_add_32be( vide, 0x00480000 );
01232
01233 bo_add_32be( vide, 0 );
01234 bo_add_16be( vide, 1 );
01235
01236
01237 for( i = 0; i < 32; i++ )
01238 {
01239 bo_add_8( vide, 0 );
01240 }
01241
01242 bo_add_16be( vide, 0x18 );
01243 bo_add_16be( vide, 0xffff );
01244
01245
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 );
01298 }
01299 bo_add_16be( text, 1 );
01300
01301 bo_add_32be( text, 0 );
01302 bo_add_32be( text, 0 );
01303 for( i = 0; i < 3; i++ )
01304 {
01305 bo_add_16be( text, 0 );
01306 }
01307
01308 bo_add_16be( text, 0 );
01309 bo_add_16be( text, 0 );
01310 bo_add_16be( text, 0 );
01311 bo_add_16be( text, 0 );
01312
01313 bo_add_64be( text, 0 );
01314 for( i = 0; i < 3; i++ )
01315 {
01316 bo_add_16be( text, 0xff );
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
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
01357 if( p_sys->i_pos >= (((uint64_t)0x1) << 32) )
01358 {
01359
01360 p_stream->b_stco64 = VLC_TRUE;
01361 stco = box_full_new( "co64", 0, 0 );
01362 }
01363 else
01364 {
01365
01366 p_stream->b_stco64 = VLC_FALSE;
01367 stco = box_full_new( "stco", 0, 0 );
01368 }
01369 bo_add_32be( stco, 0 );
01370
01371
01372 stsc = box_full_new( "stsc", 0, 0 );
01373 bo_add_32be( stsc, 0 );
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
01399 if( i_stsc_last_val != i - i_first )
01400 {
01401 bo_add_32be( stsc, 1 + i_chunk );
01402 bo_add_32be( stsc, i - i_first ) ;
01403 bo_add_32be( stsc, 1 );
01404 i_stsc_last_val = i - i_first;
01405 i_stsc_entries++;
01406 }
01407 }
01408
01409
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
01415 bo_fix_32be( stsc, 12, i_stsc_entries );
01416 box_fix( stsc );
01417
01418
01419 stts = box_full_new( "stts", 0, 0 );
01420 bo_add_32be( stts, 0 );
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
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
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 );
01457 bo_add_32be( stts, i_delta );
01458 }
01459 bo_fix_32be( stts, 12, i_index );
01460 box_fix( stts );
01461
01462
01463
01464 stsz = box_full_new( "stsz", 0, 0 );
01465 bo_add_32be( stsz, 0 );
01466 bo_add_32be( stsz, p_stream->i_entry_count );
01467 for( i = 0; i < p_stream->i_entry_count; i++ )
01468 {
01469 bo_add_32be( stsz, p_stream->entry[i].i_size );
01470 }
01471 box_fix( stsz );
01472
01473
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 );
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
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
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
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
01541 if( !p_sys->b_64_ext )
01542 {
01543 mvhd = box_full_new( "mvhd", 0, 0 );
01544 bo_add_32be( mvhd, get_timestamp() );
01545 bo_add_32be( mvhd, get_timestamp() );
01546 bo_add_32be( mvhd, i_movie_timescale);
01547 bo_add_32be( mvhd, i_movie_duration );
01548 }
01549 else
01550 {
01551 mvhd = box_full_new( "mvhd", 1, 0 );
01552 bo_add_64be( mvhd, get_timestamp() );
01553 bo_add_64be( mvhd, get_timestamp() );
01554 bo_add_32be( mvhd, i_movie_timescale);
01555 bo_add_64be( mvhd, i_movie_duration );
01556 }
01557 bo_add_32be( mvhd, 0x10000 );
01558 bo_add_16be( mvhd, 0x100 );
01559 bo_add_16be( mvhd, 0 );
01560 for( i = 0; i < 2; i++ )
01561 {
01562 bo_add_32be( mvhd, 0 );
01563 }
01564 for( i = 0; i < 9; i++ )
01565 {
01566 bo_add_32be( mvhd, mvhd_matrix[i] );
01567 }
01568 for( i = 0; i < 6; i++ )
01569 {
01570 bo_add_32be( mvhd, 0 );
01571 }
01572
01573
01574 bo_add_32be( mvhd, p_sys->i_nb_streams + 1 );
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
01595 trak = box_new( "trak" );
01596
01597
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() );
01606 bo_add_32be( tkhd, get_timestamp() );
01607 bo_add_32be( tkhd, p_stream->i_track_id );
01608 bo_add_32be( tkhd, 0 );
01609 bo_add_32be( tkhd, p_stream->i_duration *
01610 (int64_t)i_movie_timescale /
01611 (mtime_t)1000000 );
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() );
01621 bo_add_64be( tkhd, get_timestamp() );
01622 bo_add_32be( tkhd, p_stream->i_track_id );
01623 bo_add_32be( tkhd, 0 );
01624 bo_add_64be( tkhd, p_stream->i_duration *
01625 (int64_t)i_movie_timescale /
01626 (mtime_t)1000000 );
01627 }
01628
01629 for( i = 0; i < 2; i++ )
01630 {
01631 bo_add_32be( tkhd, 0 );
01632 }
01633 bo_add_16be( tkhd, 0 );
01634 bo_add_16be( tkhd, 0 );
01635
01636 bo_add_16be( tkhd, p_stream->fmt.i_cat == AUDIO_ES ? 0x100 : 0 );
01637 bo_add_16be( tkhd, 0 );
01638 for( i = 0; i < 9; i++ )
01639 {
01640 bo_add_32be( tkhd, mvhd_matrix[i] );
01641 }
01642 if( p_stream->fmt.i_cat == AUDIO_ES )
01643 {
01644 bo_add_32be( tkhd, 0 );
01645 bo_add_32be( tkhd, 0 );
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
01657 bo_add_32be( tkhd, i_width );
01658
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 );
01681 bo_add_32be( tkhd, i_height << 16 );
01682 }
01683
01684 box_fix( tkhd );
01685 box_gather( trak, tkhd );
01686
01687
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
01734 mdia = box_new( "mdia" );
01735
01736
01737 if( !p_sys->b_64_ext )
01738 {
01739 mdhd = box_full_new( "mdhd", 0, 0 );
01740 bo_add_32be( mdhd, get_timestamp() );
01741 bo_add_32be( mdhd, get_timestamp() );
01742 bo_add_32be( mdhd, i_timescale);
01743 bo_add_32be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
01744 (mtime_t)1000000 );
01745 }
01746 else
01747 {
01748 mdhd = box_full_new( "mdhd", 1, 0 );
01749 bo_add_64be( mdhd, get_timestamp() );
01750 bo_add_64be( mdhd, get_timestamp() );
01751 bo_add_32be( mdhd, i_timescale);
01752 bo_add_64be( mdhd, p_stream->i_duration * (int64_t)i_timescale /
01753 (mtime_t)1000000 );
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 );
01781 }
01782 else
01783 {
01784 bo_add_16be( mdhd, 0 );
01785 }
01786 bo_add_16be( mdhd, 0 );
01787 box_fix( mdhd );
01788 box_gather( mdia, mdhd );
01789
01790
01791 hdlr = box_full_new( "hdlr", 0, 0 );
01792
01793 if( p_sys->b_mov )
01794 bo_add_fourcc( hdlr, "mhlr" );
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 );
01806 bo_add_32be( hdlr, 0 );
01807 bo_add_32be( hdlr, 0 );
01808
01809 if( p_sys->b_mov )
01810 bo_add_8( hdlr, 12 );
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 );
01821
01822 box_fix( hdlr );
01823 box_gather( mdia, hdlr );
01824
01825
01826 minf = box_new( "minf" );
01827
01828
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 );
01835 bo_add_16be( smhd, 0 );
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 );
01846 for( i = 0; i < 3; i++ )
01847 {
01848 bo_add_16be( vmhd, 0 );
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 );
01860 for( i = 0; i < 3; i++ )
01861 {
01862 bo_add_16be( gmin, 0 );
01863 }
01864 bo_add_16be( gmin, 0 );
01865 bo_add_16be( gmin, 0 );
01866 box_fix( gmin );
01867
01868 box_gather( gmhd, gmin );
01869 box_fix( gmhd );
01870
01871 box_gather( minf, gmhd );
01872 }
01873
01874
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
01885 box_fix( dinf );
01886 box_gather( minf, dinf );
01887
01888
01889 stbl = GetStblBox( p_mux, p_stream );
01890
01891
01892 p_stream->i_stco_pos += minf->i_buffer;
01893 box_gather( minf, stbl );
01894
01895
01896 box_fix( minf );
01897 p_stream->i_stco_pos += mdia->i_buffer;
01898 box_gather( mdia, minf );
01899
01900
01901 box_fix( mdia );
01902 p_stream->i_stco_pos += trak->i_buffer;
01903 box_gather( trak, mdia );
01904
01905
01906 box_fix( trak );
01907 p_stream->i_stco_pos += moov->i_buffer;
01908 box_gather( moov, trak );
01909 }
01910
01911
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;
02143
02144 #endif
02145
02146 return i_timestamp;
02147 }