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 #include <stdlib.h>
00028 #include <string.h>
00029
00030 #include <vlc/vlc.h>
00031 #include <vlc/sout.h>
00032
00033
00034
00035
00036 static int Open ( vlc_object_t * );
00037 static void Close ( vlc_object_t * );
00038
00039 vlc_module_begin();
00040 set_description( _("Duplicate stream output") );
00041 set_capability( "sout stream", 50 );
00042 add_shortcut( "duplicate" );
00043 add_shortcut( "dup" );
00044 set_category( CAT_SOUT );
00045 set_subcategory( SUBCAT_SOUT_STREAM );
00046 set_callbacks( Open, Close );
00047 vlc_module_end();
00048
00049
00050
00051
00052
00053 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
00054 static int Del ( sout_stream_t *, sout_stream_id_t * );
00055 static int Send( sout_stream_t *, sout_stream_id_t *,
00056 block_t* );
00057
00058 struct sout_stream_sys_t
00059 {
00060 int i_nb_streams;
00061 sout_stream_t **pp_streams;
00062
00063 int i_nb_select;
00064 char **ppsz_select;
00065 };
00066
00067 struct sout_stream_id_t
00068 {
00069 int i_nb_ids;
00070 void **pp_ids;
00071 };
00072
00073 static vlc_bool_t ESSelected( es_format_t *fmt, char *psz_select );
00074
00075
00076
00077
00078 static int Open( vlc_object_t *p_this )
00079 {
00080 sout_stream_t *p_stream = (sout_stream_t*)p_this;
00081 sout_stream_sys_t *p_sys;
00082 sout_cfg_t *p_cfg;
00083
00084 msg_Dbg( p_stream, "creating 'duplicate'" );
00085
00086 p_sys = malloc( sizeof( sout_stream_sys_t ) );
00087
00088 p_sys->i_nb_streams = 0;
00089 p_sys->pp_streams = NULL;
00090 p_sys->i_nb_select = 0;
00091 p_sys->ppsz_select = NULL;
00092
00093 for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
00094 {
00095 if( !strncmp( p_cfg->psz_name, "dst", strlen( "dst" ) ) )
00096 {
00097 sout_stream_t *s;
00098
00099 msg_Dbg( p_stream, " * adding `%s'", p_cfg->psz_value );
00100 s = sout_StreamNew( p_stream->p_sout, p_cfg->psz_value );
00101
00102 if( s )
00103 {
00104 TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, s );
00105 TAB_APPEND( p_sys->i_nb_select, p_sys->ppsz_select, NULL );
00106 }
00107 }
00108 else if( !strncmp( p_cfg->psz_name, "select", strlen( "select" ) ) )
00109 {
00110 char *psz = p_cfg->psz_value;
00111 if( p_sys->i_nb_select > 0 && psz && *psz )
00112 {
00113 msg_Dbg( p_stream, " * apply selection %s", psz );
00114 p_sys->ppsz_select[p_sys->i_nb_select - 1] = strdup( psz );
00115 }
00116 }
00117 }
00118
00119 if( p_sys->i_nb_streams == 0 )
00120 {
00121 msg_Err( p_stream, "no destination given" );
00122 free( p_sys );
00123
00124 return VLC_EGENERIC;
00125 }
00126
00127 p_stream->pf_add = Add;
00128 p_stream->pf_del = Del;
00129 p_stream->pf_send = Send;
00130
00131 p_stream->p_sys = p_sys;
00132
00133 return VLC_SUCCESS;
00134 }
00135
00136
00137
00138
00139 static void Close( vlc_object_t * p_this )
00140 {
00141 sout_stream_t *p_stream = (sout_stream_t*)p_this;
00142 sout_stream_sys_t *p_sys = p_stream->p_sys;
00143
00144 int i;
00145
00146 msg_Dbg( p_stream, "closing a duplication" );
00147 for( i = 0; i < p_sys->i_nb_streams; i++ )
00148 {
00149 sout_StreamDelete( p_sys->pp_streams[i] );
00150 if( p_sys->ppsz_select[i] )
00151 {
00152 free( p_sys->ppsz_select[i] );
00153 }
00154 }
00155 if( p_sys->pp_streams )
00156 {
00157 free( p_sys->pp_streams );
00158 }
00159 if( p_sys->ppsz_select )
00160 {
00161 free( p_sys->ppsz_select );
00162 }
00163
00164 free( p_sys );
00165 }
00166
00167
00168
00169
00170 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
00171 {
00172 sout_stream_sys_t *p_sys = p_stream->p_sys;
00173 sout_stream_id_t *id;
00174 int i_stream, i_valid_streams = 0;
00175
00176 id = malloc( sizeof( sout_stream_id_t ) );
00177 id->i_nb_ids = 0;
00178 id->pp_ids = NULL;
00179
00180 msg_Dbg( p_stream, "duplicated a new stream codec=%4.4s (es=%d group=%d)",
00181 (char*)&p_fmt->i_codec, p_fmt->i_id, p_fmt->i_group );
00182
00183 for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
00184 {
00185 void *id_new = NULL;
00186
00187 if( ESSelected( p_fmt, p_sys->ppsz_select[i_stream] ) )
00188 {
00189 sout_stream_t *out = p_sys->pp_streams[i_stream];
00190
00191 id_new = (void*)out->pf_add( out, p_fmt );
00192 if( id_new )
00193 {
00194 msg_Dbg( p_stream, " - added for output %d", i_stream );
00195 i_valid_streams++;
00196 }
00197 else
00198 {
00199 msg_Dbg( p_stream, " - failed for output %d", i_stream );
00200 }
00201 }
00202 else
00203 {
00204 msg_Dbg( p_stream, " - ignored for output %d", i_stream );
00205 }
00206
00207
00208
00209 TAB_APPEND( id->i_nb_ids, id->pp_ids, id_new );
00210 }
00211
00212 if( i_valid_streams <= 0 )
00213 {
00214 Del( p_stream, id );
00215 return NULL;
00216 }
00217
00218 return id;
00219 }
00220
00221
00222
00223
00224 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
00225 {
00226 sout_stream_sys_t *p_sys = p_stream->p_sys;
00227 int i_stream;
00228
00229 for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
00230 {
00231 if( id->pp_ids[i_stream] )
00232 {
00233 sout_stream_t *out = p_sys->pp_streams[i_stream];
00234 out->pf_del( out, id->pp_ids[i_stream] );
00235 }
00236 }
00237
00238 free( id->pp_ids );
00239 free( id );
00240 return VLC_SUCCESS;
00241 }
00242
00243
00244
00245
00246 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
00247 block_t *p_buffer )
00248 {
00249 sout_stream_sys_t *p_sys = p_stream->p_sys;
00250 sout_stream_t *p_dup_stream;
00251 int i_stream;
00252
00253
00254 while( p_buffer )
00255 {
00256 block_t *p_next = p_buffer->p_next;
00257
00258 p_buffer->p_next = NULL;
00259
00260 for( i_stream = 0; i_stream < p_sys->i_nb_streams - 1; i_stream++ )
00261 {
00262 block_t *p_dup;
00263 p_dup_stream = p_sys->pp_streams[i_stream];
00264
00265 if( id->pp_ids[i_stream] )
00266 {
00267 p_dup = block_Duplicate( p_buffer );
00268
00269 p_dup_stream->pf_send( p_dup_stream, id->pp_ids[i_stream],
00270 p_dup );
00271 }
00272 }
00273
00274 if( i_stream < p_sys->i_nb_streams && id->pp_ids[i_stream] )
00275 {
00276 p_dup_stream = p_sys->pp_streams[i_stream];
00277 p_dup_stream->pf_send( p_dup_stream, id->pp_ids[i_stream],
00278 p_buffer );
00279 }
00280 else
00281 {
00282 block_Release( p_buffer );
00283 }
00284
00285 p_buffer = p_next;
00286 }
00287 return VLC_SUCCESS;
00288 }
00289
00290
00291
00292
00293 static vlc_bool_t NumInRange( char *psz_range, int i_num )
00294 {
00295 char *psz = strchr( psz_range, '-' );
00296 char *end;
00297 int i_start, i_stop;
00298
00299 if( psz )
00300 {
00301 i_start = strtol( psz_range, &end, 0 );
00302 if( end == psz_range ) i_start = i_num;
00303
00304 i_stop = strtol( psz, &end, 0 );
00305 if( end == psz_range ) i_stop = i_num;
00306 }
00307 else
00308 {
00309 i_start = i_stop = strtol( psz_range, NULL, 0 );
00310 }
00311
00312 return i_start <= i_num && i_num <= i_stop ? VLC_TRUE : VLC_FALSE;
00313 }
00314
00315 static vlc_bool_t ESSelected( es_format_t *fmt, char *psz_select )
00316 {
00317 char *psz_dup;
00318 char *psz;
00319
00320
00321 int i_cat = -1;
00322 int i_es = -1;
00323 int i_prgm= -1;
00324
00325
00326 if( psz_select == NULL || *psz_select == '\0' )
00327 {
00328 return VLC_TRUE;
00329 }
00330 psz_dup = strdup( psz_select );
00331 psz = psz_dup;
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342 while( psz && *psz )
00343 {
00344 char *p;
00345
00346
00347 while( *psz == ' ' || *psz == '\t' ) psz++;
00348
00349
00350 p = strchr( psz, ',' );
00351 if( p == psz )
00352 {
00353
00354 psz = p + 1;
00355 continue;
00356 }
00357 if( p )
00358 {
00359 *p++ = '\0';
00360 }
00361
00362 if( !strncmp( psz, "no-audio", strlen( "no-audio" ) ) ||
00363 !strncmp( psz, "noaudio", strlen( "noaudio" ) ) )
00364 {
00365 if( i_cat == -1 )
00366 {
00367 i_cat = fmt->i_cat != AUDIO_ES ? 1 : 0;
00368 }
00369 }
00370 else if( !strncmp( psz, "no-video", strlen( "no-video" ) ) ||
00371 !strncmp( psz, "novideo", strlen( "novideo" ) ) )
00372 {
00373 if( i_cat == -1 )
00374 {
00375 i_cat = fmt->i_cat != VIDEO_ES ? 1 : 0;
00376 }
00377 }
00378 else if( !strncmp( psz, "no-spu", strlen( "no-spu" ) ) ||
00379 !strncmp( psz, "nospu", strlen( "nospu" ) ) )
00380 {
00381 if( i_cat == -1 )
00382 {
00383 i_cat = fmt->i_cat != SPU_ES ? 1 : 0;
00384 }
00385 }
00386 else if( !strncmp( psz, "audio", strlen( "audio" ) ) )
00387 {
00388 if( i_cat == -1 )
00389 {
00390 i_cat = fmt->i_cat == AUDIO_ES ? 1 : 0;
00391 }
00392 }
00393 else if( !strncmp( psz, "video", strlen( "video" ) ) )
00394 {
00395 if( i_cat == -1 )
00396 {
00397 i_cat = fmt->i_cat == VIDEO_ES ? 1 : 0;
00398 }
00399 }
00400 else if( !strncmp( psz, "spu", strlen( "spu" ) ) )
00401 {
00402 if( i_cat == -1 )
00403 {
00404 i_cat = fmt->i_cat == SPU_ES ? 1 : 0;
00405 }
00406 }
00407 else if( strchr( psz, '=' ) != NULL )
00408 {
00409 char *psz_arg = strchr( psz, '=' );
00410 *psz_arg++ = '\0';
00411
00412 if( !strcmp( psz, "no-es" ) || !strcmp( psz, "noes" ) )
00413 {
00414 if( i_es == -1 )
00415 {
00416 i_es = NumInRange( psz_arg, fmt->i_id ) ? 0 : -1;
00417 }
00418 }
00419 else if( !strcmp( psz, "es" ) )
00420 {
00421 if( i_es == -1 )
00422 {
00423 i_es = NumInRange( psz_arg, fmt->i_id) ? 1 : -1;
00424 }
00425 }
00426 else if( !strcmp( psz, "no-prgm" ) || !strcmp( psz, "noprgm" ) ||
00427 !strcmp( psz, "no-program" ) || !strcmp( psz, "noprogram" ) )
00428 {
00429 if( fmt->i_group >= 0 && i_prgm == -1 )
00430 {
00431 i_prgm = NumInRange( psz_arg, fmt->i_group ) ? 0 : -1;
00432 }
00433 }
00434 else if( !strcmp( psz, "prgm" ) || !strcmp( psz, "program" ) )
00435 {
00436 if( fmt->i_group >= 0 && i_prgm == -1 )
00437 {
00438 i_prgm = NumInRange( psz_arg, fmt->i_group ) ? 1 : -1;
00439 }
00440 }
00441 }
00442 else
00443 {
00444 fprintf( stderr, "unknown args (%s)\n", psz );
00445 }
00446
00447 psz = p;
00448 }
00449
00450 free( psz_dup );
00451
00452 if( i_cat == 1 || i_es == 1 || i_prgm == 1 )
00453 {
00454 return VLC_TRUE;
00455 }
00456 return VLC_FALSE;
00457 }