X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fstream_out%2Fbridge.c;h=365140bab28223fe78dbe239242b052dff39b3c4;hb=2a98d120084ee14a08b6d3267c8c9eee8ab3648e;hp=70d7647f4a254d294eb0cc030ae3d9e527ab4926;hpb=39dcd7cca3953fd3b04dba2d42457249741ad330;p=vlc diff --git a/modules/stream_out/bridge.c b/modules/stream_out/bridge.c index 70d7647f4a..365140bab2 100644 --- a/modules/stream_out/bridge.c +++ b/modules/stream_out/bridge.c @@ -69,9 +69,16 @@ "be used to configure a place holder stream when the real source " \ "breaks. Source and placeholder streams should have the same format. " ) -#define PLACEHOLDER_DELAY_TEXT N_( "Place holder delay" ) +#define PLACEHOLDER_DELAY_TEXT N_( "Placeholder delay" ) #define PLACEHOLDER_DELAY_LONGTEXT N_( \ - "Delay (in ms) before the place holder kicks in." ) + "Delay (in ms) before the placeholder kicks in." ) + +#define PLACEHOLDER_IFRAME_TEXT N_( "Wait for I frame before toggling placholder" ) +#define PLACEHOLDER_IFRAME_LONGTEXT N_( \ + "If enabled, switching between the placeholder and the normal stream " \ + "will only occur on I frames. This will remove artifacts on stream " \ + "switching at the expense of a slightly longer delay, depending on " \ + "the frequence of I frames in the streams." ) static int OpenOut ( vlc_object_t * ); static void CloseOut( vlc_object_t * ); @@ -81,41 +88,43 @@ static void CloseIn ( vlc_object_t * ); #define SOUT_CFG_PREFIX_OUT "sout-bridge-out-" #define SOUT_CFG_PREFIX_IN "sout-bridge-in-" -vlc_module_begin(); - set_shortname( N_("Bridge")); - set_description( N_("Bridge stream output")); - add_submodule(); - set_section( N_("Bridge out"), NULL ); - set_capability( "sout stream", 50 ); - add_shortcut( "bridge-out" ); +vlc_module_begin () + set_shortname( N_("Bridge")) + set_description( N_("Bridge stream output")) + add_submodule () + set_section( N_("Bridge out"), NULL ) + set_capability( "sout stream", 50 ) + add_shortcut( "bridge-out" ) /* Only usable with VLM. No category so not in gui preferences - set_category( CAT_SOUT ); - set_subcategory( SUBCAT_SOUT_STREAM );*/ - add_integer( SOUT_CFG_PREFIX_OUT "id", 0, NULL, ID_TEXT, ID_LONGTEXT, - false ); - add_string( SOUT_CFG_PREFIX_OUT "in-name", "default", NULL, - DEST_TEXT, DEST_LONGTEXT, false ); - set_callbacks( OpenOut, CloseOut ); - - add_submodule(); - set_section( N_("Bridge in"), NULL ); - set_capability( "sout stream", 50 ); - add_shortcut( "bridge-in" ); - /*set_category( CAT_SOUT ); - set_subcategory( SUBCAT_SOUT_STREAM );*/ - add_integer( SOUT_CFG_PREFIX_IN "delay", 0, NULL, DELAY_TEXT, - DELAY_LONGTEXT, false ); - add_integer( SOUT_CFG_PREFIX_IN "id-offset", 8192, NULL, ID_OFFSET_TEXT, - ID_OFFSET_LONGTEXT, false ); - add_string( SOUT_CFG_PREFIX_IN "name", "default", NULL, - NAME_TEXT, NAME_LONGTEXT, false ); - add_bool( SOUT_CFG_PREFIX_IN "placeholder", false, NULL, - PLACEHOLDER_TEXT, PLACEHOLDER_LONGTEXT, false ); - add_integer( SOUT_CFG_PREFIX_IN "placeholder-delay", 200, NULL, - PLACEHOLDER_DELAY_TEXT, PLACEHOLDER_DELAY_LONGTEXT, false ); - set_callbacks( OpenIn, CloseIn ); - -vlc_module_end(); + set_category( CAT_SOUT ) + set_subcategory( SUBCAT_SOUT_STREAM )*/ + add_integer( SOUT_CFG_PREFIX_OUT "id", 0, ID_TEXT, ID_LONGTEXT, + false ) + add_string( SOUT_CFG_PREFIX_OUT "in-name", "default", + DEST_TEXT, DEST_LONGTEXT, false ) + set_callbacks( OpenOut, CloseOut ) + + add_submodule () + set_section( N_("Bridge in"), NULL ) + set_capability( "sout stream", 50 ) + add_shortcut( "bridge-in" ) + /*set_category( CAT_SOUT ) + set_subcategory( SUBCAT_SOUT_STREAM )*/ + add_integer( SOUT_CFG_PREFIX_IN "delay", 0, DELAY_TEXT, + DELAY_LONGTEXT, false ) + add_integer( SOUT_CFG_PREFIX_IN "id-offset", 8192, ID_OFFSET_TEXT, + ID_OFFSET_LONGTEXT, false ) + add_string( SOUT_CFG_PREFIX_IN "name", "default", + NAME_TEXT, NAME_LONGTEXT, false ) + add_bool( SOUT_CFG_PREFIX_IN "placeholder", false, + PLACEHOLDER_TEXT, PLACEHOLDER_LONGTEXT, false ) + add_integer( SOUT_CFG_PREFIX_IN "placeholder-delay", 200, + PLACEHOLDER_DELAY_TEXT, PLACEHOLDER_DELAY_LONGTEXT, false ) + add_bool( SOUT_CFG_PREFIX_IN "placeholder-switch-on-iframe", true, + PLACEHOLDER_IFRAME_TEXT, PLACEHOLDER_IFRAME_LONGTEXT, false ) + set_callbacks( OpenIn, CloseIn ) + +vlc_module_end () /***************************************************************************** @@ -126,7 +135,9 @@ static const char *const ppsz_sout_options_out[] = { }; static const char *const ppsz_sout_options_in[] = { - "delay", "id-offset", "name", "placeholder", "placeholder-delay", NULL + "delay", "id-offset", "name", + "placeholder", "placeholder-delay", "placeholder-switch-on-iframe", + NULL }; static sout_stream_id_t *AddOut ( sout_stream_t *, es_format_t * ); @@ -156,24 +167,6 @@ typedef struct bridge_t int i_es_num; } bridge_t; -#define GetBridge(a,b) __GetBridge( VLC_OBJECT(a), b ) -static bridge_t *__GetBridge( vlc_object_t *p_object, const char *psz_name ) -{ - bridge_t *p_bridge; - vlc_value_t val; - - if( var_Get( p_object->p_libvlc, psz_name, &val ) ) - { - p_bridge = NULL; - } - else - { - p_bridge = val.p_address; - } - - return p_bridge; -} - /* * Bridge out @@ -202,6 +195,8 @@ static int OpenOut( vlc_object_t *p_this ) p_stream->p_cfg ); p_sys = malloc( sizeof( out_sout_stream_sys_t ) ); + if( unlikely( !p_sys ) ) + return VLC_ENOMEM; p_sys->b_inited = false; var_Create( p_this->p_libvlc, "bridge-lock", VLC_VAR_MUTEX ); @@ -254,23 +249,20 @@ static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt ) if ( p_sys->b_inited ) { + msg_Err( p_stream, "bridge-out can only handle 1 es at a time." ); return NULL; } p_sys->b_inited = true; vlc_mutex_lock( p_sys->p_lock ); - p_bridge = GetBridge( p_stream, p_sys->psz_name ); + p_bridge = var_GetAddress( p_stream->p_libvlc, p_sys->psz_name ); if ( p_bridge == NULL ) { - vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc ); - vlc_value_t val; - - p_bridge = malloc( sizeof( bridge_t ) ); + p_bridge = xmalloc( sizeof( bridge_t ) ); - var_Create( p_libvlc, p_sys->psz_name, VLC_VAR_ADDRESS ); - val.p_address = p_bridge; - var_Set( p_libvlc, p_sys->psz_name, val ); + var_Create( p_stream->p_libvlc, p_sys->psz_name, VLC_VAR_ADDRESS ); + var_SetAddress( p_stream->p_libvlc, p_sys->psz_name, p_bridge ); p_bridge->i_es_num = 0; p_bridge->pp_es = NULL; @@ -284,11 +276,10 @@ static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt ) if ( i == p_bridge->i_es_num ) { - p_bridge->pp_es = realloc( p_bridge->pp_es, - (p_bridge->i_es_num + 1) - * sizeof(bridged_es_t *) ); + p_bridge->pp_es = xrealloc( p_bridge->pp_es, + (p_bridge->i_es_num + 1) * sizeof(bridged_es_t *) ); p_bridge->i_es_num++; - p_bridge->pp_es[i] = malloc( sizeof(bridged_es_t) ); + p_bridge->pp_es[i] = xmalloc( sizeof(bridged_es_t) ); } p_sys->p_es = p_es = p_bridge->pp_es[i]; @@ -300,7 +291,7 @@ static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt ) p_es->b_empty = false; p_es->id = NULL; - p_es->i_last = 0; + p_es->i_last = VLC_TS_INVALID; p_es->b_changed = true; msg_Dbg( p_stream, "bridging out input codec=%4.4s id=%d pos=%d", @@ -372,7 +363,6 @@ static int SendOut( sout_stream_t *p_stream, sout_stream_id_t *id, typedef struct in_sout_stream_sys_t { - sout_stream_t *p_out; vlc_mutex_t *p_lock; int i_id_offset; mtime_t i_delay; @@ -380,6 +370,8 @@ typedef struct in_sout_stream_sys_t char *psz_name; bool b_placeholder; + bool b_switch_on_iframe; + int i_state; mtime_t i_placeholder_delay; sout_stream_id_t *id_video; mtime_t i_last_video; @@ -387,6 +379,8 @@ typedef struct in_sout_stream_sys_t mtime_t i_last_audio; } in_sout_stream_sys_t; +enum { placeholder_on, placeholder_off }; + /***************************************************************************** * OpenIn: *****************************************************************************/ @@ -397,9 +391,10 @@ static int OpenIn( vlc_object_t *p_this ) vlc_value_t val; p_sys = malloc( sizeof( in_sout_stream_sys_t ) ); + if( unlikely( !p_sys ) ) + return VLC_ENOMEM; - p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next ); - if( !p_sys->p_out ) + if( !p_stream->p_next ) { msg_Err( p_stream, "cannot create chain" ); free( p_sys ); @@ -431,11 +426,16 @@ static int OpenIn( vlc_object_t *p_this ) var_Get( p_stream, SOUT_CFG_PREFIX_IN "placeholder", &val ); p_sys->b_placeholder = val.b_bool; + var_Get( p_stream, SOUT_CFG_PREFIX_IN "placeholder-switch-on-iframe", &val); + p_sys->b_switch_on_iframe = val.b_bool; + + p_sys->i_state = placeholder_on; + var_Get( p_stream, SOUT_CFG_PREFIX_IN "placeholder-delay", &val ); p_sys->i_placeholder_delay = (mtime_t)val.i_int * 1000; - p_sys->i_last_video = 0; - p_sys->i_last_audio = 0; + p_sys->i_last_video = VLC_TS_INVALID; + p_sys->i_last_audio = VLC_TS_INVALID; p_sys->id_video = NULL; p_sys->id_audio = NULL; @@ -459,7 +459,6 @@ static void CloseIn( vlc_object_t * p_this ) sout_stream_t *p_stream = (sout_stream_t*)p_this; in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys; - sout_StreamDelete( p_sys->p_out ); p_stream->p_sout->i_out_pace_nocontrol--; free( p_sys->psz_name ); @@ -479,7 +478,7 @@ static sout_stream_id_t * AddIn( sout_stream_t *p_stream, es_format_t *p_fmt ) sout_stream_id_t *id = malloc( sizeof( sout_stream_id_t ) ); if( !id ) return NULL; - id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt ); + id->id = p_stream->p_next->pf_add( p_stream->p_next, p_fmt ); if( !id->id ) { free( id ); @@ -514,7 +513,7 @@ static int DelIn( sout_stream_t *p_stream, sout_stream_id_t *id ) if( id == p_sys->id_video ) p_sys->id_video = NULL; if( id == p_sys->id_audio ) p_sys->id_audio = NULL; - int ret = p_sys->p_out->pf_del( p_sys->p_out, id->id ); + int ret = p_stream->p_next->pf_del( p_stream->p_next, id->id ); free( id ); return ret; @@ -531,12 +530,12 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, /* First forward the packet for our own ES */ if( !p_sys->b_placeholder ) - p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer ); + p_stream->p_next->pf_send( p_stream->p_next, id->id, p_buffer ); /* Then check all bridged streams */ vlc_mutex_lock( p_sys->p_lock ); - p_bridge = GetBridge( p_stream, p_sys->psz_name ); + p_bridge = var_GetAddress( p_stream->p_libvlc, p_sys->psz_name ); if( p_bridge ) { @@ -568,7 +567,7 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, { if ( p_bridge->pp_es[i]->b_empty && p_bridge->pp_es[i]->id != NULL ) { - p_sys->p_out->pf_del( p_sys->p_out, p_bridge->pp_es[i]->id ); + p_stream->p_next->pf_del( p_stream->p_next, p_bridge->pp_es[i]->id ); } else { @@ -580,12 +579,15 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, } p_bridge->pp_es[i]->fmt.i_id += p_sys->i_id_offset; - p_bridge->pp_es[i]->id = p_sys->p_out->pf_add( - p_sys->p_out, &p_bridge->pp_es[i]->fmt ); - if ( p_bridge->pp_es[i]->id == NULL ) + if( !p_sys->b_placeholder ) { - msg_Warn( p_stream, "couldn't create chain for id %d", - p_bridge->pp_es[i]->fmt.i_id ); + p_bridge->pp_es[i]->id = p_stream->p_next->pf_add( + p_stream->p_next, &p_bridge->pp_es[i]->fmt ); + if ( p_bridge->pp_es[i]->id == NULL ) + { + msg_Warn( p_stream, "couldn't create chain for id %d", + p_bridge->pp_es[i]->fmt.i_id ); + } } msg_Dbg( p_stream, "bridging in input codec=%4.4s id=%d pos=%d", (char*)&p_bridge->pp_es[i]->fmt.i_codec, @@ -602,7 +604,9 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, if ( p_bridge->pp_es[i]->id != NULL && p_bridge->pp_es[i]->i_last < i_date ) { - p_sys->p_out->pf_del( p_sys->p_out, p_bridge->pp_es[i]->id ); + if( !p_sys->b_placeholder ) + p_stream->p_next->pf_del( p_stream->p_next, + p_bridge->pp_es[i]->id ); p_bridge->pp_es[i]->fmt.i_id -= p_sys->i_id_offset; p_bridge->pp_es[i]->b_changed = true; p_bridge->pp_es[i]->id = NULL; @@ -610,7 +614,7 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, continue; } - if ( p_bridge->pp_es[i]->id != NULL ) + if ( p_bridge->pp_es[i]->id != NULL || p_sys->b_placeholder) { block_t *p_block = p_bridge->pp_es[i]->p_block; while ( p_block != NULL ) @@ -628,16 +632,35 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, case VIDEO_ES: p_sys->i_last_video = i_date; newid = p_sys->id_video; + if( !newid ) + break; + if( !p_sys->b_switch_on_iframe || + p_sys->i_state == placeholder_off || + ( p_bridge->pp_es[i]->fmt.i_cat == VIDEO_ES && + p_bridge->pp_es[i]->p_block->i_flags & BLOCK_FLAG_TYPE_I ) ) + { + p_stream->p_next->pf_send( p_stream->p_next, + newid, + p_bridge->pp_es[i]->p_block ); + p_sys->i_state = placeholder_off; + } break; case AUDIO_ES: newid = p_sys->id_audio; + if( !newid ) + break; p_sys->i_last_audio = i_date; + default: + p_stream->p_next->pf_send( p_stream->p_next, + newid?newid:p_bridge->pp_es[i]->id, + p_bridge->pp_es[i]->p_block ); break; } } - p_sys->p_out->pf_send( p_sys->p_out, - newid ? newid : p_bridge->pp_es[i]->id, - p_bridge->pp_es[i]->p_block ); + else /* !b_placeholder */ + p_stream->p_next->pf_send( p_stream->p_next, + p_bridge->pp_es[i]->id, + p_bridge->pp_es[i]->p_block ); } else { @@ -650,12 +673,11 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, if( b_no_es ) { - vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc ); for ( i = 0; i < p_bridge->i_es_num; i++ ) free( p_bridge->pp_es[i] ); free( p_bridge->pp_es ); free( p_bridge ); - var_Destroy( p_libvlc, p_sys->psz_name ); + var_Destroy( p_stream->p_libvlc, p_sys->psz_name ); } } @@ -664,15 +686,21 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, switch( id->i_cat ) { case VIDEO_ES: - if( p_sys->i_last_video + p_sys->i_placeholder_delay < i_date ) - p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer ); + if( ( p_sys->i_last_video + p_sys->i_placeholder_delay < i_date + && ( !p_sys->b_switch_on_iframe + || p_buffer->i_flags & BLOCK_FLAG_TYPE_I ) ) + || p_sys->i_state == placeholder_on ) + { + p_stream->p_next->pf_send( p_stream->p_next, id->id, p_buffer ); + p_sys->i_state = placeholder_on; + } else block_Release( p_buffer ); break; case AUDIO_ES: if( p_sys->i_last_audio + p_sys->i_placeholder_delay < i_date ) - p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer ); + p_stream->p_next->pf_send( p_stream->p_next, id->id, p_buffer ); else block_Release( p_buffer ); break;