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 #define ID_TEXT N_("ID")
00037 #define ID_LONGTEXT N_( \
00038 "Specify an identifier integer for this elementary stream" )
00039
00040 #define DELAY_TEXT N_("Delay")
00041 #define DELAY_LONGTEXT N_("Pictures coming from the picture video outputs " \
00042 "will be delayed accordingly (in milliseconds, >= 100 ms). For high " \
00043 "values you will need to raise file-caching and others.")
00044
00045 #define ID_OFFSET_TEXT N_("ID Offset")
00046 #define ID_OFFSET_LONGTEXT N_("Offset to add to the stream IDs specified in " \
00047 "bridge_out to obtain the stream IDs bridge_in will register.")
00048
00049 static int OpenOut ( vlc_object_t * );
00050 static void CloseOut( vlc_object_t * );
00051 static int OpenIn ( vlc_object_t * );
00052 static void CloseIn ( vlc_object_t * );
00053
00054 #define SOUT_CFG_PREFIX_OUT "sout-bridge-out-"
00055 #define SOUT_CFG_PREFIX_IN "sout-bridge-in-"
00056
00057 vlc_module_begin();
00058 set_shortname( _("Bridge"));
00059 set_description( _("Bridge stream output"));
00060 add_submodule();
00061 set_section( N_("Bridge out"), NULL );
00062 set_capability( "sout stream", 50 );
00063 add_shortcut( "bridge-out" );
00064
00065
00066
00067 add_integer( SOUT_CFG_PREFIX_OUT "id", 0, NULL, ID_TEXT, ID_LONGTEXT,
00068 VLC_FALSE );
00069 set_callbacks( OpenOut, CloseOut );
00070
00071 add_submodule();
00072 set_section( N_("Bridge in"), NULL );
00073 set_capability( "sout stream", 50 );
00074 add_shortcut( "bridge-in" );
00075
00076
00077 add_integer( SOUT_CFG_PREFIX_IN "delay", 0, NULL, DELAY_TEXT,
00078 DELAY_LONGTEXT, VLC_FALSE );
00079 add_integer( SOUT_CFG_PREFIX_IN "id-offset", 8192, NULL, ID_OFFSET_TEXT,
00080 ID_OFFSET_LONGTEXT, VLC_FALSE );
00081 set_callbacks( OpenIn, CloseIn );
00082
00083 var_Create( p_module->p_libvlc, "bridge-lock", VLC_VAR_MUTEX );
00084 vlc_module_end();
00085
00086
00087
00088
00089
00090 static const char *ppsz_sout_options_out[] = {
00091 "id", NULL
00092 };
00093
00094 static const char *ppsz_sout_options_in[] = {
00095 "delay", "id-offset", NULL
00096 };
00097
00098 static sout_stream_id_t *AddOut ( sout_stream_t *, es_format_t * );
00099 static int DelOut ( sout_stream_t *, sout_stream_id_t * );
00100 static int SendOut( sout_stream_t *, sout_stream_id_t *, block_t * );
00101
00102 static sout_stream_id_t *AddIn ( sout_stream_t *, es_format_t * );
00103 static int DelIn ( sout_stream_t *, sout_stream_id_t * );
00104 static int SendIn( sout_stream_t *, sout_stream_id_t *, block_t * );
00105
00106 typedef struct bridged_es_t
00107 {
00108 es_format_t fmt;
00109 block_t *p_block;
00110 block_t **pp_last;
00111 vlc_bool_t b_empty;
00112
00113
00114 sout_stream_id_t *id;
00115 mtime_t i_last;
00116 vlc_bool_t b_changed;
00117 } bridged_es_t;
00118
00119 typedef struct bridge_t
00120 {
00121 bridged_es_t **pp_es;
00122 int i_es_num;
00123 } bridge_t;
00124
00125 #define GetBridge(a) __GetBridge( VLC_OBJECT(a) )
00126 static bridge_t *__GetBridge( vlc_object_t *p_object )
00127 {
00128 libvlc_t *p_libvlc = p_object->p_libvlc;
00129 bridge_t *p_bridge;
00130 vlc_value_t val;
00131
00132 if( var_Get( p_libvlc, "bridge-struct", &val ) != VLC_SUCCESS )
00133 {
00134 p_bridge = NULL;
00135 }
00136 else
00137 {
00138 p_bridge = val.p_address;
00139 }
00140
00141 return p_bridge;
00142 }
00143
00144
00145
00146
00147
00148
00149 typedef struct out_sout_stream_sys_t
00150 {
00151 vlc_mutex_t *p_lock;
00152 bridged_es_t *p_es;
00153 int i_id;
00154 vlc_bool_t b_inited;
00155 } out_sout_stream_sys_t;
00156
00157
00158
00159
00160 static int OpenOut( vlc_object_t *p_this )
00161 {
00162 sout_stream_t *p_stream = (sout_stream_t *)p_this;
00163 out_sout_stream_sys_t *p_sys;
00164 vlc_value_t val;
00165
00166 sout_CfgParse( p_stream, SOUT_CFG_PREFIX_OUT, ppsz_sout_options_out,
00167 p_stream->p_cfg );
00168
00169 p_sys = malloc( sizeof( out_sout_stream_sys_t ) );
00170 p_sys->b_inited = VLC_FALSE;
00171
00172 var_Get( p_this->p_libvlc, "bridge-lock", &val );
00173 p_sys->p_lock = val.p_address;
00174
00175 var_Get( p_stream, SOUT_CFG_PREFIX_OUT "id", &val );
00176 p_sys->i_id = val.i_int;
00177
00178 p_stream->pf_add = AddOut;
00179 p_stream->pf_del = DelOut;
00180 p_stream->pf_send = SendOut;
00181
00182 p_stream->p_sys = (sout_stream_sys_t *)p_sys;
00183
00184 p_stream->p_sout->i_out_pace_nocontrol++;
00185
00186 return VLC_SUCCESS;
00187 }
00188
00189
00190
00191
00192 static void CloseOut( vlc_object_t * p_this )
00193 {
00194 sout_stream_t *p_stream = (sout_stream_t*)p_this;
00195 out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
00196
00197 p_stream->p_sout->i_out_pace_nocontrol--;
00198
00199 free( p_sys );
00200 }
00201
00202 static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt )
00203 {
00204 out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
00205 bridge_t *p_bridge;
00206 bridged_es_t *p_es;
00207 int i;
00208
00209 if ( p_sys->b_inited )
00210 {
00211 return NULL;
00212 }
00213 p_sys->b_inited = VLC_TRUE;
00214
00215 vlc_mutex_lock( p_sys->p_lock );
00216
00217 p_bridge = GetBridge( p_stream );
00218 if ( p_bridge == NULL )
00219 {
00220 libvlc_t *p_libvlc = p_stream->p_libvlc;
00221 vlc_value_t val;
00222
00223 p_bridge = malloc( sizeof( bridge_t ) );
00224
00225 var_Create( p_libvlc, "bridge-struct", VLC_VAR_ADDRESS );
00226 val.p_address = p_bridge;
00227 var_Set( p_libvlc, "bridge-struct", val );
00228
00229 p_bridge->i_es_num = 0;
00230 p_bridge->pp_es = NULL;
00231 }
00232
00233 for ( i = 0; i < p_bridge->i_es_num; i++ )
00234 {
00235 if ( p_bridge->pp_es[i]->b_empty && !p_bridge->pp_es[i]->b_changed )
00236 break;
00237 }
00238
00239 if ( i == p_bridge->i_es_num )
00240 {
00241 p_bridge->pp_es = realloc( p_bridge->pp_es,
00242 (p_bridge->i_es_num + 1)
00243 * sizeof(bridged_es_t *) );
00244 p_bridge->i_es_num++;
00245 p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) );
00246 }
00247
00248 p_sys->p_es = p_es = p_bridge->pp_es[i];
00249
00250 p_es->fmt = *p_fmt;
00251 p_es->fmt.i_id = p_sys->i_id;
00252 p_es->p_block = NULL;
00253 p_es->pp_last = &p_es->p_block;
00254 p_es->b_empty = VLC_FALSE;
00255
00256 p_es->id = NULL;
00257 p_es->i_last = 0;
00258 p_es->b_changed = VLC_TRUE;
00259
00260 msg_Dbg( p_stream, "bridging out input codec=%4.4s id=%d pos=%d",
00261 (char*)&p_es->fmt.i_codec, p_es->fmt.i_id, i );
00262
00263 vlc_mutex_unlock( p_sys->p_lock );
00264
00265 return (sout_stream_id_t *)p_sys;
00266 }
00267
00268 static int DelOut( sout_stream_t *p_stream, sout_stream_id_t *id )
00269 {
00270 out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
00271 bridged_es_t *p_es;
00272
00273 if ( !p_sys->b_inited )
00274 {
00275 return VLC_SUCCESS;
00276 }
00277
00278 vlc_mutex_lock( p_sys->p_lock );
00279
00280 p_es = p_sys->p_es;
00281
00282 p_es->b_empty = VLC_TRUE;
00283 block_ChainRelease( p_es->p_block );
00284 p_es->p_block = VLC_FALSE;
00285
00286 p_es->b_changed = VLC_TRUE;
00287 vlc_mutex_unlock( p_sys->p_lock );
00288
00289 p_sys->b_inited = VLC_FALSE;
00290
00291 return VLC_SUCCESS;
00292 }
00293
00294 static int SendOut( sout_stream_t *p_stream, sout_stream_id_t *id,
00295 block_t *p_buffer )
00296 {
00297 out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys;
00298 bridged_es_t *p_es;
00299
00300 if ( (out_sout_stream_sys_t *)id != p_sys )
00301 {
00302 block_ChainRelease( p_buffer );
00303 return VLC_SUCCESS;
00304 }
00305
00306 vlc_mutex_lock( p_sys->p_lock );
00307
00308 p_es = p_sys->p_es;
00309 *p_es->pp_last = p_buffer;
00310 while ( p_buffer != NULL )
00311 {
00312 p_es->pp_last = &p_buffer->p_next;
00313 p_buffer = p_buffer->p_next;
00314 }
00315
00316 vlc_mutex_unlock( p_sys->p_lock );
00317
00318 return VLC_SUCCESS;
00319 }
00320
00321
00322
00323
00324
00325
00326 typedef struct in_sout_stream_sys_t
00327 {
00328 sout_stream_t *p_out;
00329 vlc_mutex_t *p_lock;
00330 int i_id_offset;
00331 mtime_t i_delay;
00332 } in_sout_stream_sys_t;
00333
00334
00335
00336
00337 static int OpenIn( vlc_object_t *p_this )
00338 {
00339 sout_stream_t *p_stream = (sout_stream_t*)p_this;
00340 in_sout_stream_sys_t *p_sys;
00341 vlc_value_t val;
00342
00343 p_sys = malloc( sizeof( in_sout_stream_sys_t ) );
00344
00345 p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
00346 if( !p_sys->p_out )
00347 {
00348 msg_Err( p_stream, "cannot create chain" );
00349 free( p_sys );
00350 return VLC_EGENERIC;
00351 }
00352
00353 sout_CfgParse( p_stream, SOUT_CFG_PREFIX_IN, ppsz_sout_options_in,
00354 p_stream->p_cfg );
00355
00356 var_Get( p_this->p_libvlc, "bridge-lock", &val );
00357 p_sys->p_lock = val.p_address;
00358
00359 var_Get( p_stream, SOUT_CFG_PREFIX_IN "id-offset", &val );
00360 p_sys->i_id_offset = val.i_int;
00361
00362 var_Get( p_stream, SOUT_CFG_PREFIX_IN "delay", &val );
00363 p_sys->i_delay = (mtime_t)val.i_int * 1000;
00364
00365 p_stream->pf_add = AddIn;
00366 p_stream->pf_del = DelIn;
00367 p_stream->pf_send = SendIn;
00368
00369 p_stream->p_sys = (sout_stream_sys_t *)p_sys;
00370
00371
00372 p_stream->p_sout->i_out_pace_nocontrol++;
00373
00374 return VLC_SUCCESS;
00375 }
00376
00377
00378
00379
00380 static void CloseIn( vlc_object_t * p_this )
00381 {
00382 sout_stream_t *p_stream = (sout_stream_t*)p_this;
00383 in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys;
00384
00385 sout_StreamDelete( p_sys->p_out );
00386 p_stream->p_sout->i_out_pace_nocontrol--;
00387
00388 free( p_sys );
00389 }
00390
00391 static sout_stream_id_t * AddIn( sout_stream_t *p_stream, es_format_t *p_fmt )
00392 {
00393 in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys;
00394
00395 return p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
00396 }
00397
00398 static int DelIn( sout_stream_t *p_stream, sout_stream_id_t *id )
00399 {
00400 in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys;
00401
00402 return p_sys->p_out->pf_del( p_sys->p_out, id );
00403 }
00404
00405 static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id,
00406 block_t *p_buffer )
00407 {
00408 in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys;
00409 bridge_t *p_bridge;
00410 vlc_bool_t b_no_es = VLC_TRUE;
00411 int i;
00412
00413
00414 p_sys->p_out->pf_send( p_sys->p_out, id, p_buffer );
00415
00416
00417 vlc_mutex_lock( p_sys->p_lock );
00418
00419 p_bridge = GetBridge( p_stream );
00420 if ( p_bridge == NULL )
00421 {
00422 vlc_mutex_unlock( p_sys->p_lock );
00423 return VLC_SUCCESS;
00424 }
00425
00426 for ( i = 0; i < p_bridge->i_es_num; i++ )
00427 {
00428 if ( !p_bridge->pp_es[i]->b_empty )
00429 b_no_es = VLC_FALSE;
00430
00431 while ( p_bridge->pp_es[i]->p_block != NULL
00432 && (p_bridge->pp_es[i]->p_block->i_dts + p_sys->i_delay
00433 < mdate()
00434 || p_bridge->pp_es[i]->p_block->i_dts + p_sys->i_delay
00435 < p_bridge->pp_es[i]->i_last) )
00436 {
00437 block_t *p_block = p_bridge->pp_es[i]->p_block;
00438 msg_Dbg( p_stream, "dropping a packet (" I64Fd ")",
00439 mdate() - p_block->i_dts - p_sys->i_delay );
00440 p_bridge->pp_es[i]->p_block
00441 = p_bridge->pp_es[i]->p_block->p_next;
00442 block_Release( p_block );
00443 }
00444
00445 if ( p_bridge->pp_es[i]->p_block == NULL )
00446 {
00447 p_bridge->pp_es[i]->pp_last = &p_bridge->pp_es[i]->p_block;
00448 }
00449
00450 if ( p_bridge->pp_es[i]->b_changed )
00451 {
00452 if ( p_bridge->pp_es[i]->b_empty && p_bridge->pp_es[i]->id != NULL )
00453 {
00454 p_sys->p_out->pf_del( p_sys->p_out, p_bridge->pp_es[i]->id );
00455 }
00456 else
00457 {
00458
00459 if ( p_bridge->pp_es[i]->p_block == NULL
00460 || p_bridge->pp_es[i]->p_block->p_next == NULL )
00461 {
00462 continue;
00463 }
00464
00465 p_bridge->pp_es[i]->fmt.i_id += p_sys->i_id_offset;
00466 p_bridge->pp_es[i]->id = p_sys->p_out->pf_add(
00467 p_sys->p_out, &p_bridge->pp_es[i]->fmt );
00468 if ( p_bridge->pp_es[i]->id == NULL )
00469 {
00470 msg_Warn( p_stream, "couldn't create chain for id %d",
00471 p_bridge->pp_es[i]->fmt.i_id );
00472 }
00473 msg_Dbg( p_stream, "bridging in input codec=%4.4s id=%d pos=%d",
00474 (char*)&p_bridge->pp_es[i]->fmt.i_codec,
00475 p_bridge->pp_es[i]->fmt.i_id, i );
00476 }
00477 }
00478 p_bridge->pp_es[i]->b_changed = VLC_FALSE;
00479
00480 if ( p_bridge->pp_es[i]->b_empty )
00481 continue;
00482
00483 if ( p_bridge->pp_es[i]->p_block == NULL )
00484 {
00485 if ( p_bridge->pp_es[i]->id != NULL
00486 && p_bridge->pp_es[i]->i_last < mdate() )
00487 {
00488 p_sys->p_out->pf_del( p_sys->p_out, p_bridge->pp_es[i]->id );
00489 p_bridge->pp_es[i]->fmt.i_id -= p_sys->i_id_offset;
00490 p_bridge->pp_es[i]->b_changed = VLC_TRUE;
00491 p_bridge->pp_es[i]->id = NULL;
00492 }
00493 continue;
00494 }
00495
00496 if ( p_bridge->pp_es[i]->id != NULL )
00497 {
00498 block_t *p_block = p_bridge->pp_es[i]->p_block;
00499 while ( p_block != NULL )
00500 {
00501 p_bridge->pp_es[i]->i_last = p_block->i_dts;
00502 p_block->i_pts += p_sys->i_delay;
00503 p_block->i_dts += p_sys->i_delay;
00504 p_block = p_block->p_next;
00505 }
00506 p_sys->p_out->pf_send( p_sys->p_out, p_bridge->pp_es[i]->id,
00507 p_bridge->pp_es[i]->p_block );
00508 }
00509 else
00510 {
00511 block_ChainRelease( p_bridge->pp_es[i]->p_block );
00512 }
00513
00514 p_bridge->pp_es[i]->p_block = NULL;
00515 p_bridge->pp_es[i]->pp_last = &p_bridge->pp_es[i]->p_block;
00516 }
00517
00518 if( b_no_es )
00519 {
00520 libvlc_t *p_libvlc = p_stream->p_libvlc;
00521 for ( i = 0; i < p_bridge->i_es_num; i++ )
00522 free( p_bridge->pp_es[i] );
00523 free( p_bridge->pp_es );
00524 free( p_bridge );
00525 var_Destroy( p_libvlc, "bridge-struct" );
00526 }
00527
00528 vlc_mutex_unlock( p_sys->p_lock );
00529
00530 return VLC_SUCCESS;
00531 }