X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fstream_out%2Fbridge.c;h=26927316b983f454389fce978fa1c4775edf4c54;hb=98ad3f3cb54dba78cb1b5d2f5d84052b5274c430;hp=8fd0e0697df1a5f4d726054ed16416795ac7a999;hpb=d3fe7f28797d4dba65ffcdd60bf932e758a48a9e;p=vlc diff --git a/modules/stream_out/bridge.c b/modules/stream_out/bridge.c index 8fd0e0697d..26927316b9 100644 --- a/modules/stream_out/bridge.c +++ b/modules/stream_out/bridge.c @@ -1,10 +1,11 @@ /***************************************************************************** * bridge.c: bridge stream output module ***************************************************************************** - * Copyright (C) 2005 the VideoLAN team + * Copyright (C) 2005-2008 the VideoLAN team * $Id$ * * Authors: Christophe Massiot + * Antoine Cellerier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,10 +25,13 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include #include #include @@ -39,6 +43,11 @@ "Integer identifier for this elementary stream. This will be used to " \ "\"find\" this stream later." ) +#define DEST_TEXT N_( "Destination bridge-in name" ) +#define DEST_LONGTEXT N_( \ + "Name of the destination bridge-in. If you do not need more " \ + "than one bridge-in at a time, you can discard this option." ) + #define DELAY_TEXT N_("Delay") #define DELAY_LONGTEXT N_("Pictures coming from the picture video outputs " \ "will be delayed according to this value (in milliseconds, should be "\ @@ -48,6 +57,29 @@ #define ID_OFFSET_LONGTEXT N_("Offset to add to the stream IDs specified in " \ "bridge_out to obtain the stream IDs bridge_in will register.") +#define NAME_TEXT N_( "Name of current instance" ) +#define NAME_LONGTEXT N_( \ + "Name of this bridge-in instance. If you do not need more " \ + "than one bridge-in at a time, you can discard this option." ) + +#define PLACEHOLDER_TEXT N_( "Fallback to placeholder stream when out of data" ) +#define PLACEHOLDER_LONGTEXT N_( \ + "If set to true, the bridge will discard all input elementary streams " \ + "except if it doesn't receive data from another bridge-in. This can " \ + "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_( "Placeholder delay" ) +#define PLACEHOLDER_DELAY_LONGTEXT N_( \ + "Delay (in ms) before the placeholder kicks in." ) + +#define PLACEHOLDER_IFRAME_TEXT N_( "Wait for I frame before toggling placeholder" ) +#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 * ); static int OpenIn ( vlc_object_t * ); @@ -56,45 +88,56 @@ 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( _("Bridge")); - set_description( _("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, - VLC_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, VLC_FALSE ); - add_integer( SOUT_CFG_PREFIX_IN "id-offset", 8192, NULL, ID_OFFSET_TEXT, - ID_OFFSET_LONGTEXT, VLC_FALSE ); - set_callbacks( OpenIn, CloseIn ); - - var_Create( p_module->p_libvlc_global, "bridge-lock", VLC_VAR_MUTEX ); -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 () /***************************************************************************** * Local prototypes *****************************************************************************/ -static const char *ppsz_sout_options_out[] = { - "id", NULL +static const char *const ppsz_sout_options_out[] = { + "id", "in-name", NULL }; -static const char *ppsz_sout_options_in[] = { - "delay", "id-offset", NULL +static const char *const ppsz_sout_options_in[] = { + "delay", "id-offset", "name", + "placeholder", "placeholder-delay", "placeholder-switch-on-iframe", + NULL }; static sout_stream_id_t *AddOut ( sout_stream_t *, es_format_t * ); @@ -110,12 +153,12 @@ typedef struct bridged_es_t es_format_t fmt; block_t *p_block; block_t **pp_last; - vlc_bool_t b_empty; + bool b_empty; /* bridge in part */ sout_stream_id_t *id; mtime_t i_last; - vlc_bool_t b_changed; + bool b_changed; } bridged_es_t; typedef struct bridge_t @@ -124,25 +167,7 @@ typedef struct bridge_t int i_es_num; } bridge_t; -#define GetBridge(a) __GetBridge( VLC_OBJECT(a) ) -static bridge_t *__GetBridge( vlc_object_t *p_object ) -{ - libvlc_global_data_t *p_libvlc_global = p_object->p_libvlc_global; - bridge_t *p_bridge; - vlc_value_t val; - - if( var_Get( p_libvlc_global, "bridge-struct", &val ) != VLC_SUCCESS ) - { - p_bridge = NULL; - } - else - { - p_bridge = val.p_address; - } - - return p_bridge; -} - +static vlc_mutex_t lock = VLC_STATIC_MUTEX; /* * Bridge out @@ -150,10 +175,11 @@ static bridge_t *__GetBridge( vlc_object_t *p_object ) typedef struct out_sout_stream_sys_t { - vlc_mutex_t *p_lock; bridged_es_t *p_es; int i_id; - vlc_bool_t b_inited; + bool b_inited; + + char *psz_name; } out_sout_stream_sys_t; /***************************************************************************** @@ -169,14 +195,22 @@ static int OpenOut( vlc_object_t *p_this ) p_stream->p_cfg ); p_sys = malloc( sizeof( out_sout_stream_sys_t ) ); - p_sys->b_inited = VLC_FALSE; - - var_Get( p_this->p_libvlc_global, "bridge-lock", &val ); - p_sys->p_lock = val.p_address; + if( unlikely( !p_sys ) ) + return VLC_ENOMEM; + p_sys->b_inited = false; var_Get( p_stream, SOUT_CFG_PREFIX_OUT "id", &val ); p_sys->i_id = val.i_int; + var_Get( p_stream, SOUT_CFG_PREFIX_OUT "in-name", &val ); + if( asprintf( &p_sys->psz_name, "bridge-struct-%s", val.psz_string )<0 ) + { + free( val.psz_string ); + free( p_sys ); + return VLC_ENOMEM; + } + free( val.psz_string ); + p_stream->pf_add = AddOut; p_stream->pf_del = DelOut; p_stream->pf_send = SendOut; @@ -198,6 +232,7 @@ static void CloseOut( vlc_object_t * p_this ) p_stream->p_sout->i_out_pace_nocontrol--; + free( p_sys->psz_name ); free( p_sys ); } @@ -210,23 +245,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 = VLC_TRUE; + p_sys->b_inited = true; - vlc_mutex_lock( p_sys->p_lock ); + vlc_mutex_lock( &lock ); - p_bridge = GetBridge( p_stream ); + p_bridge = var_GetAddress( p_stream->p_libvlc, p_sys->psz_name ); if ( p_bridge == NULL ) { - libvlc_global_data_t *p_libvlc_global = p_stream->p_libvlc_global; - vlc_value_t val; + p_bridge = xmalloc( sizeof( bridge_t ) ); - p_bridge = malloc( sizeof( bridge_t ) ); - - var_Create( p_libvlc_global, "bridge-struct", VLC_VAR_ADDRESS ); - val.p_address = p_bridge; - var_Set( p_libvlc_global, "bridge-struct", 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; @@ -240,11 +272,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]; @@ -253,22 +284,23 @@ static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt ) p_es->fmt.i_id = p_sys->i_id; p_es->p_block = NULL; p_es->pp_last = &p_es->p_block; - p_es->b_empty = VLC_FALSE; + p_es->b_empty = false; p_es->id = NULL; - p_es->i_last = 0; - p_es->b_changed = VLC_TRUE; + 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", (char*)&p_es->fmt.i_codec, p_es->fmt.i_id, i ); - vlc_mutex_unlock( p_sys->p_lock ); + vlc_mutex_unlock( &lock ); return (sout_stream_id_t *)p_sys; } static int DelOut( sout_stream_t *p_stream, sout_stream_id_t *id ) { + VLC_UNUSED(id); out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys; bridged_es_t *p_es; @@ -277,18 +309,18 @@ static int DelOut( sout_stream_t *p_stream, sout_stream_id_t *id ) return VLC_SUCCESS; } - vlc_mutex_lock( p_sys->p_lock ); + vlc_mutex_lock( &lock ); p_es = p_sys->p_es; - p_es->b_empty = VLC_TRUE; + p_es->b_empty = true; block_ChainRelease( p_es->p_block ); - p_es->p_block = VLC_FALSE; + p_es->p_block = false; - p_es->b_changed = VLC_TRUE; - vlc_mutex_unlock( p_sys->p_lock ); + p_es->b_changed = true; + vlc_mutex_unlock( &lock ); - p_sys->b_inited = VLC_FALSE; + p_sys->b_inited = false; return VLC_SUCCESS; } @@ -305,7 +337,7 @@ static int SendOut( sout_stream_t *p_stream, sout_stream_id_t *id, return VLC_SUCCESS; } - vlc_mutex_lock( p_sys->p_lock ); + vlc_mutex_lock( &lock ); p_es = p_sys->p_es; *p_es->pp_last = p_buffer; @@ -315,7 +347,7 @@ static int SendOut( sout_stream_t *p_stream, sout_stream_id_t *id, p_buffer = p_buffer->p_next; } - vlc_mutex_unlock( p_sys->p_lock ); + vlc_mutex_unlock( &lock ); return VLC_SUCCESS; } @@ -327,12 +359,23 @@ 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; + + 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; + sout_stream_id_t *id_audio; + mtime_t i_last_audio; } in_sout_stream_sys_t; +enum { placeholder_on, placeholder_off }; + /***************************************************************************** * OpenIn: *****************************************************************************/ @@ -343,9 +386,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 ); @@ -355,15 +399,37 @@ static int OpenIn( vlc_object_t *p_this ) config_ChainParse( p_stream, SOUT_CFG_PREFIX_IN, ppsz_sout_options_in, p_stream->p_cfg ); - var_Get( p_this->p_libvlc_global, "bridge-lock", &val ); - p_sys->p_lock = val.p_address; - var_Get( p_stream, SOUT_CFG_PREFIX_IN "id-offset", &val ); p_sys->i_id_offset = val.i_int; var_Get( p_stream, SOUT_CFG_PREFIX_IN "delay", &val ); p_sys->i_delay = (mtime_t)val.i_int * 1000; + var_Get( p_stream, SOUT_CFG_PREFIX_IN "name", &val ); + if( asprintf( &p_sys->psz_name, "bridge-struct-%s", val.psz_string )<0 ) + { + free( val.psz_string ); + free( p_sys ); + return VLC_ENOMEM; + } + free( val.psz_string ); + + 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 = VLC_TS_INVALID; + p_sys->i_last_audio = VLC_TS_INVALID; + p_sys->id_video = NULL; + p_sys->id_audio = NULL; + p_stream->pf_add = AddIn; p_stream->pf_del = DelIn; p_stream->pf_send = SendIn; @@ -384,24 +450,64 @@ 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 ); free( p_sys ); } +struct sout_stream_id_t +{ + sout_stream_id_t *id; + int i_cat; /* es category. Used for placeholder option */ +}; + static sout_stream_id_t * AddIn( sout_stream_t *p_stream, es_format_t *p_fmt ) { in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys; - return p_sys->p_out->pf_add( p_sys->p_out, p_fmt ); + sout_stream_id_t *id = malloc( sizeof( sout_stream_id_t ) ); + if( !id ) return NULL; + + id->id = p_stream->p_next->pf_add( p_stream->p_next, p_fmt ); + if( !id->id ) + { + free( id ); + return NULL; + } + + if( p_sys->b_placeholder ) + { + id->i_cat = p_fmt->i_cat; + switch( p_fmt->i_cat ) + { + case VIDEO_ES: + if( p_sys->id_video != NULL ) + msg_Err( p_stream, "We already had a video es!" ); + p_sys->id_video = id->id; + break; + case AUDIO_ES: + if( p_sys->id_audio != NULL ) + msg_Err( p_stream, "We already had an audio es!" ); + p_sys->id_audio = id->id; + break; + } + } + + return id; } static int DelIn( sout_stream_t *p_stream, sout_stream_id_t *id ) { in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys; - return p_sys->p_out->pf_del( p_sys->p_out, 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_stream->p_next->pf_del( p_stream->p_next, id->id ); + + free( id ); + return ret; } static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, @@ -409,36 +515,35 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, { in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys; bridge_t *p_bridge; - vlc_bool_t b_no_es = VLC_TRUE; + bool b_no_es = true; int i; + int i_date = mdate(); /* First forward the packet for our own ES */ - p_sys->p_out->pf_send( p_sys->p_out, id, p_buffer ); + if( !p_sys->b_placeholder ) + 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 ); + vlc_mutex_lock( &lock ); - p_bridge = GetBridge( p_stream ); - if ( p_bridge == NULL ) - { - vlc_mutex_unlock( p_sys->p_lock ); - return VLC_SUCCESS; - } + p_bridge = var_GetAddress( p_stream->p_libvlc, p_sys->psz_name ); + if( p_bridge ) + { for ( i = 0; i < p_bridge->i_es_num; i++ ) { if ( !p_bridge->pp_es[i]->b_empty ) - b_no_es = VLC_FALSE; + b_no_es = false; while ( p_bridge->pp_es[i]->p_block != NULL && (p_bridge->pp_es[i]->p_block->i_dts + p_sys->i_delay - < mdate() + < i_date || p_bridge->pp_es[i]->p_block->i_dts + p_sys->i_delay < p_bridge->pp_es[i]->i_last) ) { block_t *p_block = p_bridge->pp_es[i]->p_block; - msg_Dbg( p_stream, "dropping a packet (" I64Fd ")", - mdate() - p_block->i_dts - p_sys->i_delay ); + msg_Dbg( p_stream, "dropping a packet (%"PRId64 ")", + i_date - p_block->i_dts - p_sys->i_delay ); p_bridge->pp_es[i]->p_block = p_bridge->pp_es[i]->p_block->p_next; block_Release( p_block ); @@ -453,7 +558,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 { @@ -465,19 +570,22 @@ 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, p_bridge->pp_es[i]->fmt.i_id, i ); } } - p_bridge->pp_es[i]->b_changed = VLC_FALSE; + p_bridge->pp_es[i]->b_changed = false; if ( p_bridge->pp_es[i]->b_empty ) continue; @@ -485,17 +593,19 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, if ( p_bridge->pp_es[i]->p_block == NULL ) { if ( p_bridge->pp_es[i]->id != NULL - && p_bridge->pp_es[i]->i_last < mdate() ) + && 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 = VLC_TRUE; + p_bridge->pp_es[i]->b_changed = true; p_bridge->pp_es[i]->id = NULL; } 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 ) @@ -505,8 +615,43 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, p_block->i_dts += p_sys->i_delay; p_block = p_block->p_next; } - p_sys->p_out->pf_send( p_sys->p_out, p_bridge->pp_es[i]->id, + sout_stream_id_t *newid = NULL; + if( p_sys->b_placeholder ) + { + switch( p_bridge->pp_es[i]->fmt.i_cat ) + { + 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; + } + } + 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 { @@ -519,15 +664,45 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, if( b_no_es ) { - libvlc_global_data_t *p_libvlc_global = p_stream->p_libvlc_global; 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_global, "bridge-struct" ); + var_Destroy( p_stream->p_libvlc, p_sys->psz_name ); + } + } + + if( p_sys->b_placeholder ) + { + switch( id->i_cat ) + { + case VIDEO_ES: + 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_stream->p_next->pf_send( p_stream->p_next, id->id, p_buffer ); + else + block_Release( p_buffer ); + break; + + default: + block_Release( p_buffer ); /* FIXME: placeholder subs anyone? */ + break; + } } - vlc_mutex_unlock( p_sys->p_lock ); + vlc_mutex_unlock( &lock ); return VLC_SUCCESS; }