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
00029 #include <stdlib.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032
00033 #include <vlc/vlc.h>
00034 #include <vlc/sout.h>
00035
00036 #include "vlc_meta.h"
00037
00038 #undef DEBUG_BUFFER
00039
00040
00041
00042 static void sout_CfgDestroy( sout_cfg_t * );
00043
00044 #define sout_stream_url_to_chain( p, s ) \
00045 _sout_stream_url_to_chain( VLC_OBJECT(p), s )
00046 static char *_sout_stream_url_to_chain( vlc_object_t *, char * );
00047
00048
00049
00050
00051
00052
00053 typedef struct
00054 {
00055 char *psz_access;
00056 char *psz_way;
00057 char *psz_name;
00058 } mrl_t;
00059
00060
00061 static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl );
00062
00063 static void mrl_Clean( mrl_t *p_mrl );
00064
00065 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
00066
00067
00068
00069
00070 sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
00071 {
00072 sout_instance_t *p_sout;
00073 vlc_value_t keep;
00074
00075 if( var_Get( p_parent, "sout-keep", &keep ) < 0 )
00076 {
00077 msg_Warn( p_parent, "cannot get sout-keep value" );
00078 keep.b_bool = VLC_FALSE;
00079 }
00080 if( keep.b_bool )
00081 {
00082 if( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
00083 FIND_ANYWHERE ) ) != NULL )
00084 {
00085 if( !strcmp( p_sout->psz_sout, psz_dest ) )
00086 {
00087 msg_Dbg( p_parent, "sout keep : reusing sout" );
00088 msg_Dbg( p_parent, "sout keep : you probably want to use "
00089 "gather stream_out" );
00090 vlc_object_detach( p_sout );
00091 vlc_object_attach( p_sout, p_parent );
00092 vlc_object_release( p_sout );
00093 return p_sout;
00094 }
00095 else
00096 {
00097 msg_Dbg( p_parent, "sout keep : destroying unusable sout" );
00098 vlc_object_release( p_sout );
00099 sout_DeleteInstance( p_sout );
00100 }
00101 }
00102 }
00103 else if( !keep.b_bool )
00104 {
00105 while( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
00106 FIND_PARENT ) ) != NULL )
00107 {
00108 msg_Dbg( p_parent, "sout keep : destroying old sout" );
00109 vlc_object_release( p_sout );
00110 sout_DeleteInstance( p_sout );
00111 }
00112 }
00113
00114
00115 p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
00116 if( p_sout == NULL )
00117 {
00118 msg_Err( p_parent, "out of memory" );
00119 return NULL;
00120 }
00121
00122
00123 p_sout->psz_sout = strdup( psz_dest );
00124 p_sout->p_meta = NULL;
00125 p_sout->i_out_pace_nocontrol = 0;
00126 p_sout->p_sys = NULL;
00127
00128 vlc_mutex_init( p_sout, &p_sout->lock );
00129 if( psz_dest && psz_dest[0] == '#' )
00130 {
00131 p_sout->psz_chain = strdup( &psz_dest[1] );
00132 }
00133 else
00134 {
00135 p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
00136 msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
00137 }
00138 p_sout->p_stream = NULL;
00139
00140
00141 vlc_object_attach( p_sout, p_parent );
00142
00143 p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
00144
00145 if( p_sout->p_stream == NULL )
00146 {
00147 msg_Err( p_sout, "stream chained failed for `%s'", p_sout->psz_chain );
00148
00149 FREE( p_sout->psz_sout );
00150 FREE( p_sout->psz_chain );
00151
00152 vlc_object_detach( p_sout );
00153 vlc_object_destroy( p_sout );
00154 return NULL;
00155 }
00156
00157 return p_sout;
00158 }
00159
00160
00161
00162 void sout_DeleteInstance( sout_instance_t * p_sout )
00163 {
00164
00165 vlc_object_detach( p_sout );
00166
00167
00168 sout_StreamDelete( p_sout->p_stream );
00169
00170
00171 FREE( p_sout->psz_sout );
00172 FREE( p_sout->psz_chain );
00173
00174
00175 if( p_sout->p_meta )
00176 {
00177 vlc_meta_Delete( p_sout->p_meta );
00178 }
00179
00180 vlc_mutex_destroy( &p_sout->lock );
00181
00182
00183 vlc_object_destroy( p_sout );
00184 }
00185
00186
00187
00188
00189 sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
00190 es_format_t *p_fmt )
00191 {
00192 sout_packetizer_input_t *p_input;
00193
00194 msg_Dbg( p_sout, "adding a new input" );
00195
00196
00197 p_input = malloc( sizeof( sout_packetizer_input_t ) );
00198 p_input->p_sout = p_sout;
00199 p_input->p_fmt = p_fmt;
00200
00201 if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
00202 {
00203 vlc_object_release( p_sout );
00204 return p_input;
00205 }
00206
00207
00208 vlc_mutex_lock( &p_sout->lock );
00209 p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
00210 vlc_mutex_unlock( &p_sout->lock );
00211
00212 if( p_input->id == NULL )
00213 {
00214 free( p_input );
00215 return NULL;
00216 }
00217
00218 return( p_input );
00219 }
00220
00221
00222
00223
00224 int sout_InputDelete( sout_packetizer_input_t *p_input )
00225 {
00226 sout_instance_t *p_sout = p_input->p_sout;
00227
00228 msg_Dbg( p_sout, "removing an input" );
00229
00230 if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
00231 {
00232 vlc_mutex_lock( &p_sout->lock );
00233 p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
00234 vlc_mutex_unlock( &p_sout->lock );
00235 }
00236
00237 free( p_input );
00238
00239 return( VLC_SUCCESS);
00240 }
00241
00242
00243
00244
00245 int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
00246 block_t *p_buffer )
00247 {
00248 sout_instance_t *p_sout = p_input->p_sout;
00249 int i_ret;
00250
00251 if( p_input->p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
00252 {
00253 block_Release( p_buffer );
00254 return VLC_SUCCESS;
00255 }
00256 if( p_buffer->i_dts <= 0 )
00257 {
00258 msg_Warn( p_sout, "trying to send non-dated packet to stream output!");
00259 block_Release( p_buffer );
00260 return VLC_SUCCESS;
00261 }
00262
00263 vlc_mutex_lock( &p_sout->lock );
00264 i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
00265 p_input->id, p_buffer );
00266 vlc_mutex_unlock( &p_sout->lock );
00267
00268 return i_ret;
00269 }
00270
00271
00272
00273
00274 sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
00275 char *psz_access, char *psz_name )
00276 {
00277 sout_access_out_t *p_access;
00278 char *psz_next;
00279
00280 if( !( p_access = vlc_object_create( p_sout,
00281 sizeof( sout_access_out_t ) ) ) )
00282 {
00283 msg_Err( p_sout, "out of memory" );
00284 return NULL;
00285 }
00286
00287 psz_next = sout_CfgCreate( &p_access->psz_access, &p_access->p_cfg,
00288 psz_access );
00289 if( psz_next )
00290 {
00291 free( psz_next );
00292 }
00293 p_access->psz_name = strdup( psz_name ? psz_name : "" );
00294 p_access->p_sout = p_sout;
00295 p_access->p_sys = NULL;
00296 p_access->pf_seek = NULL;
00297 p_access->pf_read = NULL;
00298 p_access->pf_write = NULL;
00299 p_access->p_module = NULL;
00300 vlc_object_attach( p_access, p_sout );
00301
00302 p_access->p_module =
00303 module_Need( p_access, "sout access", p_access->psz_access, VLC_TRUE );
00304
00305 if( !p_access->p_module )
00306 {
00307 free( p_access->psz_access );
00308 free( p_access->psz_name );
00309 vlc_object_detach( p_access );
00310 vlc_object_destroy( p_access );
00311 return( NULL );
00312 }
00313
00314 return p_access;
00315 }
00316
00317
00318
00319 void sout_AccessOutDelete( sout_access_out_t *p_access )
00320 {
00321 vlc_object_detach( p_access );
00322 if( p_access->p_module )
00323 {
00324 module_Unneed( p_access, p_access->p_module );
00325 }
00326 free( p_access->psz_access );
00327
00328 sout_CfgDestroy( p_access->p_cfg );
00329
00330 free( p_access->psz_name );
00331
00332 vlc_object_destroy( p_access );
00333 }
00334
00335
00336
00337
00338 int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
00339 {
00340 return p_access->pf_seek( p_access, i_pos );
00341 }
00342
00343
00344
00345
00346 int sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
00347 {
00348 return( p_access->pf_read ?
00349 p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
00350 }
00351
00352
00353
00354
00355 int sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
00356 {
00357 return p_access->pf_write( p_access, p_buffer );
00358 }
00359
00360
00361
00362
00363 sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
00364 sout_access_out_t *p_access )
00365 {
00366 sout_mux_t *p_mux;
00367 char *psz_next;
00368
00369 p_mux = vlc_object_create( p_sout, sizeof( sout_mux_t ) );
00370 if( p_mux == NULL )
00371 {
00372 msg_Err( p_sout, "out of memory" );
00373 return NULL;
00374 }
00375
00376 p_mux->p_sout = p_sout;
00377 psz_next = sout_CfgCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
00378 if( psz_next ) free( psz_next );
00379
00380 p_mux->p_access = p_access;
00381 p_mux->pf_control = NULL;
00382 p_mux->pf_addstream = NULL;
00383 p_mux->pf_delstream = NULL;
00384 p_mux->pf_mux = NULL;
00385 p_mux->i_nb_inputs = 0;
00386 p_mux->pp_inputs = NULL;
00387
00388 p_mux->p_sys = NULL;
00389 p_mux->p_module = NULL;
00390
00391 p_mux->b_add_stream_any_time = VLC_FALSE;
00392 p_mux->b_waiting_stream = VLC_TRUE;
00393 p_mux->i_add_stream_start = -1;
00394
00395 vlc_object_attach( p_mux, p_sout );
00396
00397 p_mux->p_module =
00398 module_Need( p_mux, "sout mux", p_mux->psz_mux, VLC_TRUE );
00399
00400 if( p_mux->p_module == NULL )
00401 {
00402 FREE( p_mux->psz_mux );
00403
00404 vlc_object_detach( p_mux );
00405 vlc_object_destroy( p_mux );
00406 return NULL;
00407 }
00408
00409
00410 if( p_mux->pf_control )
00411 {
00412 int b_answer = VLC_FALSE;
00413
00414 if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
00415 &b_answer ) )
00416 {
00417 b_answer = VLC_FALSE;
00418 }
00419
00420 if( b_answer )
00421 {
00422 msg_Dbg( p_sout, "muxer support adding stream at any time" );
00423 p_mux->b_add_stream_any_time = VLC_TRUE;
00424 p_mux->b_waiting_stream = VLC_FALSE;
00425
00426
00427
00428 if( !p_sout->i_out_pace_nocontrol )
00429 {
00430 b_answer = VLC_TRUE;
00431 }
00432 else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
00433 &b_answer ) )
00434 {
00435 b_answer = VLC_FALSE;
00436 }
00437
00438 if( b_answer )
00439 {
00440 msg_Dbg( p_sout, "muxer prefers waiting for all ES before "
00441 "starting muxing" );
00442 p_mux->b_waiting_stream = VLC_TRUE;
00443 }
00444 }
00445 }
00446
00447 return p_mux;
00448 }
00449
00450
00451
00452
00453 void sout_MuxDelete( sout_mux_t *p_mux )
00454 {
00455 vlc_object_detach( p_mux );
00456 if( p_mux->p_module )
00457 {
00458 module_Unneed( p_mux, p_mux->p_module );
00459 }
00460 free( p_mux->psz_mux );
00461
00462 sout_CfgDestroy( p_mux->p_cfg );
00463
00464 vlc_object_destroy( p_mux );
00465 }
00466
00467
00468
00469
00470 sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
00471 {
00472 sout_input_t *p_input;
00473
00474 if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
00475 {
00476 msg_Err( p_mux, "cannot add a new stream (unsuported while muxing "
00477 "for this format)" );
00478 return NULL;
00479 }
00480
00481 msg_Dbg( p_mux, "adding a new input" );
00482
00483
00484 p_input = malloc( sizeof( sout_input_t ) );
00485 p_input->p_sout = p_mux->p_sout;
00486 p_input->p_fmt = p_fmt;
00487 p_input->p_fifo = block_FifoNew( p_mux->p_sout );
00488 p_input->p_sys = NULL;
00489
00490 TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
00491 if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
00492 {
00493 msg_Err( p_mux, "cannot add this stream" );
00494 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
00495 block_FifoRelease( p_input->p_fifo );
00496 free( p_input );
00497 return NULL;
00498 }
00499
00500 return p_input;
00501 }
00502
00503
00504
00505
00506 void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
00507 {
00508 int i_index;
00509
00510 if( p_mux->b_waiting_stream && p_input->p_fifo->i_depth > 0 )
00511 {
00512
00513
00514 p_mux->b_waiting_stream = VLC_FALSE;
00515 p_mux->pf_mux( p_mux );
00516 }
00517
00518 TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
00519 if( i_index >= 0 )
00520 {
00521 if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
00522 {
00523 msg_Err( p_mux, "cannot del this stream from mux" );
00524 }
00525
00526
00527 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
00528
00529 if( p_mux->i_nb_inputs == 0 )
00530 {
00531 msg_Warn( p_mux, "no more input stream for this mux" );
00532 }
00533
00534 block_FifoRelease( p_input->p_fifo );
00535 free( p_input );
00536 }
00537 }
00538
00539
00540
00541
00542 void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
00543 block_t *p_buffer )
00544 {
00545 block_FifoPut( p_input->p_fifo, p_buffer );
00546
00547 if( p_mux->p_sout->i_out_pace_nocontrol )
00548 {
00549 mtime_t current_date = mdate();
00550 if ( current_date > p_buffer->i_dts )
00551 msg_Warn( p_mux, "late buffer for mux input ("I64Fd")",
00552 current_date - p_buffer->i_dts );
00553 }
00554
00555 if( p_mux->b_waiting_stream )
00556 {
00557 if( p_mux->i_add_stream_start < 0 )
00558 {
00559 p_mux->i_add_stream_start = p_buffer->i_dts;
00560 }
00561
00562 if( p_mux->i_add_stream_start >= 0 &&
00563 p_mux->i_add_stream_start + I64C(1500000) < p_buffer->i_dts )
00564 {
00565
00566
00567 p_mux->b_waiting_stream = VLC_FALSE;
00568 }
00569 else
00570 {
00571 return;
00572 }
00573 }
00574 p_mux->pf_mux( p_mux );
00575 }
00576
00577
00578
00579
00580 static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
00581 {
00582 char * psz_dup = strdup( psz_mrl );
00583 char * psz_parser = psz_dup;
00584 char * psz_access = "";
00585 char * psz_way = "";
00586 char * psz_name = "";
00587
00588
00589 while( *psz_parser && *psz_parser != ':' )
00590 {
00591 if( *psz_parser == '{' )
00592 {
00593 while( *psz_parser && *psz_parser != '}' )
00594 {
00595 psz_parser++;
00596 }
00597 if( *psz_parser )
00598 {
00599 psz_parser++;
00600 }
00601 }
00602 else
00603 {
00604 psz_parser++;
00605 }
00606 }
00607 #if defined( WIN32 ) || defined( UNDER_CE )
00608 if( psz_parser - psz_dup == 1 )
00609 {
00610
00611
00612 psz_parser = "";
00613 }
00614 #endif
00615
00616 if( !*psz_parser )
00617 {
00618 psz_access = psz_way = "";
00619 psz_name = psz_dup;
00620 }
00621 else
00622 {
00623 *psz_parser++ = '\0';
00624
00625
00626 if( psz_parser[0] == '/' && psz_parser[1] == '/' )
00627 {
00628 psz_parser += 2 ;
00629 }
00630
00631 psz_name = psz_parser ;
00632
00633
00634 psz_parser = psz_dup;
00635
00636 if( !*psz_parser )
00637 {
00638
00639 psz_access = "";
00640 }
00641 else if( *psz_parser == '/' )
00642 {
00643
00644 psz_access = "";
00645 psz_parser++;
00646 }
00647 else
00648 {
00649 psz_access = psz_parser;
00650
00651 while( *psz_parser && *psz_parser != '/' )
00652 {
00653 if( *psz_parser == '{' )
00654 {
00655 while( *psz_parser && *psz_parser != '}' )
00656 {
00657 psz_parser++;
00658 }
00659 if( *psz_parser )
00660 {
00661 psz_parser++;
00662 }
00663 }
00664 else
00665 {
00666 psz_parser++;
00667 }
00668 }
00669
00670 if( *psz_parser == '/' )
00671 {
00672 *psz_parser++ = '\0';
00673 }
00674 }
00675
00676 if( !*psz_parser )
00677 {
00678
00679 psz_way = "";
00680 }
00681 else
00682 {
00683 psz_way = psz_parser;
00684 }
00685 }
00686
00687 p_mrl->psz_access = strdup( psz_access );
00688 p_mrl->psz_way = strdup( psz_way );
00689 p_mrl->psz_name = strdup( psz_name );
00690
00691 free( psz_dup );
00692 return( VLC_SUCCESS );
00693 }
00694
00695
00696
00697 static void mrl_Clean( mrl_t *p_mrl )
00698 {
00699 FREE( p_mrl->psz_access );
00700 FREE( p_mrl->psz_way );
00701 FREE( p_mrl->psz_name );
00702 }
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
00724 #define SKIPTRAILINGSPACE( p, e ) \
00725 { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
00726
00727
00728 static char *_get_chain_end( char *str )
00729 {
00730 char c, *p = str;
00731
00732 SKIPSPACE( p );
00733
00734 for( ;; )
00735 {
00736 if( !*p || *p == ',' || *p == '}' ) return p;
00737
00738 if( *p != '{' && *p != '"' && *p != '\'' )
00739 {
00740 p++;
00741 continue;
00742 }
00743
00744 if( *p == '{' ) c = '}';
00745 else c = *p;
00746 p++;
00747
00748 for( ;; )
00749 {
00750 if( !*p ) return p;
00751
00752 if( *p == c ) return ++p;
00753 else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
00754 else p++;
00755 }
00756 }
00757 }
00758
00759 char *sout_CfgCreate( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
00760 {
00761 sout_cfg_t *p_cfg = NULL;
00762 char *p = psz_chain;
00763
00764 *ppsz_name = NULL;
00765 *pp_cfg = NULL;
00766
00767 if( !p ) return NULL;
00768
00769 SKIPSPACE( p );
00770
00771 while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) p++;
00772
00773 if( p == psz_chain ) return NULL;
00774
00775 *ppsz_name = strndup( psz_chain, p - psz_chain );
00776
00777 SKIPSPACE( p );
00778
00779 if( *p == '{' )
00780 {
00781 char *psz_name;
00782
00783 p++;
00784
00785 for( ;; )
00786 {
00787 sout_cfg_t cfg;
00788
00789 SKIPSPACE( p );
00790
00791 psz_name = p;
00792
00793 while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' &&
00794 *p != ' ' && *p != '\t' ) p++;
00795
00796
00797 if( p == psz_name )
00798 {
00799 fprintf( stderr, "invalid options (empty)" );
00800 break;
00801 }
00802
00803 cfg.psz_name = strndup( psz_name, p - psz_name );
00804
00805 SKIPSPACE( p );
00806
00807 if( *p == '=' || *p == '{' )
00808 {
00809 char *end;
00810 vlc_bool_t b_keep_brackets = (*p == '{');
00811
00812 if( *p == '=' ) p++;
00813
00814 end = _get_chain_end( p );
00815 if( end <= p )
00816 {
00817 cfg.psz_value = NULL;
00818 }
00819 else
00820 {
00821
00822
00823
00824 SKIPSPACE( p );
00825 }
00826
00827 if( end <= p )
00828 {
00829 cfg.psz_value = NULL;
00830 }
00831 else
00832 {
00833 if( *p == '\'' || *p == '"' ||
00834 ( !b_keep_brackets && *p == '{' ) )
00835 {
00836 p++;
00837
00838 if( *(end-1) != '\'' && *(end-1) == '"' )
00839 SKIPTRAILINGSPACE( p, end );
00840
00841 if( end - 1 <= p ) cfg.psz_value = NULL;
00842 else cfg.psz_value = strndup( p, end -1 - p );
00843 }
00844 else
00845 {
00846 SKIPTRAILINGSPACE( p, end );
00847 if( end <= p ) cfg.psz_value = NULL;
00848 else cfg.psz_value = strndup( p, end - p );
00849 }
00850 }
00851
00852 p = end;
00853 SKIPSPACE( p );
00854 }
00855 else
00856 {
00857 cfg.psz_value = NULL;
00858 }
00859
00860 cfg.p_next = NULL;
00861 if( p_cfg )
00862 {
00863 p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
00864 memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
00865
00866 p_cfg = p_cfg->p_next;
00867 }
00868 else
00869 {
00870 p_cfg = malloc( sizeof( sout_cfg_t ) );
00871 memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
00872
00873 *pp_cfg = p_cfg;
00874 }
00875
00876 if( *p == ',' ) p++;
00877
00878 if( *p == '}' )
00879 {
00880 p++;
00881 break;
00882 }
00883 }
00884 }
00885
00886 if( *p == ':' ) return( strdup( p + 1 ) );
00887
00888 return NULL;
00889 }
00890
00891 static void sout_CfgDestroy( sout_cfg_t *p_cfg )
00892 {
00893 while( p_cfg != NULL )
00894 {
00895 sout_cfg_t *p_next;
00896
00897 p_next = p_cfg->p_next;
00898
00899 FREE( p_cfg->psz_name );
00900 FREE( p_cfg->psz_value );
00901 free( p_cfg );
00902
00903 p_cfg = p_next;
00904 }
00905 }
00906
00907 void __sout_CfgParse( vlc_object_t *p_this, char *psz_prefix,
00908 const char **ppsz_options, sout_cfg_t *cfg )
00909 {
00910 char *psz_name;
00911 int i_type;
00912 int i;
00913
00914
00915 for( i = 0; ppsz_options[i] != NULL; i++ )
00916 {
00917 asprintf( &psz_name, "%s%s", psz_prefix,
00918 *ppsz_options[i] == '*' ? &ppsz_options[i][1] : ppsz_options[i] );
00919
00920 i_type = config_GetType( p_this, psz_name );
00921
00922 var_Create( p_this, psz_name, i_type | VLC_VAR_DOINHERIT );
00923 free( psz_name );
00924 }
00925
00926
00927 if( psz_prefix == NULL ) psz_prefix = "";
00928
00929 while( cfg )
00930 {
00931 vlc_value_t val;
00932 vlc_bool_t b_yes = VLC_TRUE;
00933 vlc_bool_t b_once = VLC_FALSE;
00934
00935 if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
00936 {
00937 cfg = cfg->p_next;
00938 continue;
00939 }
00940 for( i = 0; ppsz_options[i] != NULL; i++ )
00941 {
00942 if( !strcmp( ppsz_options[i], cfg->psz_name ) )
00943 {
00944 break;
00945 }
00946 if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
00947 !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
00948 ( !strncmp( cfg->psz_name, "no", 2 ) &&
00949 !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
00950 {
00951 b_yes = VLC_FALSE;
00952 break;
00953 }
00954
00955 if( *ppsz_options[i] == '*' &&
00956 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
00957 {
00958 b_once = VLC_TRUE;
00959 break;
00960 }
00961
00962 }
00963 if( ppsz_options[i] == NULL )
00964 {
00965 msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
00966 cfg = cfg->p_next;
00967 continue;
00968 }
00969
00970
00971 asprintf( &psz_name, "%s%s", psz_prefix, b_once ? &ppsz_options[i][1] : ppsz_options[i] );
00972
00973
00974 i_type = config_GetType( p_this, psz_name );
00975 if( !i_type )
00976 {
00977 msg_Warn( p_this, "unknown option %s (value=%s)",
00978 cfg->psz_name, cfg->psz_value );
00979 goto next;
00980 }
00981 if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
00982 {
00983 msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
00984 goto next;
00985 }
00986 if( i_type != VLC_VAR_STRING && b_once )
00987 {
00988 msg_Warn( p_this, "*option_name need to be a string option" );
00989 goto next;
00990 }
00991
00992 switch( i_type )
00993 {
00994 case VLC_VAR_BOOL:
00995 val.b_bool = b_yes;
00996 break;
00997 case VLC_VAR_INTEGER:
00998 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
00999 NULL, 0 );
01000 break;
01001 case VLC_VAR_FLOAT:
01002 val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" );
01003 break;
01004 case VLC_VAR_STRING:
01005 case VLC_VAR_MODULE:
01006 val.psz_string = cfg->psz_value;
01007 break;
01008 default:
01009 msg_Warn( p_this, "unhandled config var type" );
01010 memset( &val, 0, sizeof( vlc_value_t ) );
01011 break;
01012 }
01013 if( b_once )
01014 {
01015 vlc_value_t val2;
01016
01017 var_Get( p_this, psz_name, &val2 );
01018 if( *val2.psz_string )
01019 {
01020 free( val2.psz_string );
01021 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
01022 goto next;
01023 }
01024 free( val2.psz_string );
01025 }
01026 var_Set( p_this, psz_name, val );
01027 msg_Dbg( p_this, "set sout option: %s to %s", psz_name, cfg->psz_value );
01028
01029 next:
01030 free( psz_name );
01031 cfg = cfg->p_next;
01032 }
01033 }
01034
01035
01036
01037
01038
01039 sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
01040 {
01041 sout_stream_t *p_stream;
01042
01043 if( !psz_chain )
01044 {
01045 msg_Err( p_sout, "invalid chain" );
01046 return NULL;
01047 }
01048
01049 p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
01050
01051 if( !p_stream )
01052 {
01053 msg_Err( p_sout, "out of memory" );
01054 return NULL;
01055 }
01056
01057 p_stream->p_sout = p_sout;
01058 p_stream->p_sys = NULL;
01059
01060 p_stream->psz_next =
01061 sout_CfgCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
01062
01063 msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
01064
01065 vlc_object_attach( p_stream, p_sout );
01066
01067 p_stream->p_module =
01068 module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
01069
01070 if( !p_stream->p_module )
01071 {
01072 sout_StreamDelete( p_stream );
01073 return NULL;
01074 }
01075
01076 return p_stream;
01077 }
01078
01079 void sout_StreamDelete( sout_stream_t *p_stream )
01080 {
01081 msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
01082
01083 vlc_object_detach( p_stream );
01084 if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
01085
01086 FREE( p_stream->psz_name );
01087 FREE( p_stream->psz_next );
01088
01089 sout_CfgDestroy( p_stream->p_cfg );
01090
01091 msg_Dbg( p_stream, "destroying chain done" );
01092 vlc_object_destroy( p_stream );
01093 }
01094
01095 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
01096 {
01097 mrl_t mrl;
01098 char *psz_chain, *p;
01099
01100 mrl_Parse( &mrl, psz_url );
01101 p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
01102 strlen( mrl.psz_access ) +
01103 strlen( mrl.psz_name ) );
01104
01105
01106 if( config_GetInt( p_this, "sout-display" ) )
01107 {
01108 p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
01109 "access=\"%s\",url=\"%s\"}}",
01110 mrl.psz_way, mrl.psz_access, mrl.psz_name );
01111 }
01112 else
01113 {
01114 p += sprintf( p, "std{mux=\"%s\",access=\"%s\",url=\"%s\"}",
01115 mrl.psz_way, mrl.psz_access, mrl.psz_name );
01116 }
01117
01118 mrl_Clean( &mrl );
01119 return( psz_chain );
01120 }