VLC_COMMON_MEMBERS
char *psz_sout;
- char *psz_chain;
/* meta data (Read only) XXX it won't be set before the first packet received */
vlc_meta_t *p_meta;
char *psz_name;
config_chain_t *p_cfg;
- char *psz_next;
+ sout_stream_t *p_next;
/* Subpicture unit */
spu_t *p_spu;
sout_stream_sys_t *p_sys;
};
-VLC_EXPORT( sout_stream_t *, sout_StreamNew, ( sout_instance_t *, char *psz_chain ) );
-VLC_EXPORT( void, sout_StreamDelete, ( sout_stream_t * ) );
+VLC_EXPORT( void, sout_StreamChainDelete, (sout_stream_t *p_first, sout_stream_t *p_last ) );
+VLC_EXPORT( sout_stream_t *, sout_StreamChainNew, (sout_instance_t *p_sout,
+ char *psz_chain, sout_stream_t *p_next, sout_stream_t **p_last) );
static inline sout_stream_id_t *sout_StreamIdAdd( sout_stream_t *s, es_format_t *fmt )
{
struct sout_stream_sys_t
{
- sout_stream_t *p_out;
sout_stream_id_t **pp_es;
int i_es_num;
};
p_sys = malloc( sizeof( sout_stream_sys_t ) );
- 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 );
sout_stream_t *p_stream = (sout_stream_t*)p_this;
sout_stream_sys_t *p_sys = (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 );
free( p_es );
if ( id != NULL )
- return p_sys->p_out->pf_del( p_sys->p_out, id );
+ return p_stream->p_next->pf_del( p_stream->p_next, id );
else
return VLC_SUCCESS;
}
p_es->i_last = p_buffer->i_dts;
if ( p_es->id == NULL && p_es->b_error != true )
{
- p_es->id = p_sys->p_out->pf_add( p_sys->p_out, &p_es->fmt );
+ p_es->id = p_stream->p_next->pf_add( p_stream->p_next, &p_es->fmt );
if ( p_es->id == NULL )
{
p_es->b_error = true;
}
if ( p_es->b_error != true )
- p_sys->p_out->pf_send( p_sys->p_out, p_es->id, p_buffer );
+ p_stream->p_next->pf_send( p_stream->p_next, p_es->id, p_buffer );
else
block_ChainRelease( p_buffer );
|| p_sys->pp_es[i]->fmt.i_cat == AUDIO_ES)
&& p_sys->pp_es[i]->i_last < i_current )
{
- p_sys->p_out->pf_del( p_sys->p_out, p_sys->pp_es[i]->id );
+ p_stream->p_next->pf_del( p_stream->p_next, p_sys->pp_es[i]->id );
p_sys->pp_es[i]->id = NULL;
}
}
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;
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 );
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 );
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 );
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;
/* 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 );
{
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
{
p_bridge->pp_es[i]->fmt.i_id += p_sys->i_id_offset;
if( !p_sys->b_placeholder )
{
- p_bridge->pp_es[i]->id = p_sys->p_out->pf_add(
- p_sys->p_out, &p_bridge->pp_es[i]->fmt );
+ 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]->i_last < i_date )
{
if( !p_sys->b_placeholder )
- p_sys->p_out->pf_del( p_sys->p_out,
+ 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]->fmt.i_cat == VIDEO_ES &&
p_bridge->pp_es[i]->p_block->i_flags & BLOCK_FLAG_TYPE_I ) )
{
- p_sys->p_out->pf_send( p_sys->p_out,
+ 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;
p_sys->i_last_audio = i_date;
default:
- p_sys->p_out->pf_send( p_sys->p_out,
+ 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_sys->p_out->pf_send( p_sys->p_out,
+ p_stream->p_next->pf_send( p_stream->p_next,
p_bridge->pp_es[i]->id,
p_bridge->pp_es[i]->p_block );
}
|| p_buffer->i_flags & BLOCK_FLAG_TYPE_I ) )
|| p_sys->i_state == placeholder_on )
{
- 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 );
p_sys->i_state = placeholder_on;
}
else
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;
int i_nb_streams;
sout_stream_t **pp_streams;
+ int i_nb_last_streams;
+ sout_stream_t **pp_last_streams;
+
int i_nb_select;
char **ppsz_select;
};
return VLC_ENOMEM;
TAB_INIT( p_sys->i_nb_streams, p_sys->pp_streams );
+ TAB_INIT( p_sys->i_nb_last_streams, p_sys->pp_last_streams );
TAB_INIT( p_sys->i_nb_select, p_sys->ppsz_select );
for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
{
if( !strncmp( p_cfg->psz_name, "dst", strlen( "dst" ) ) )
{
- sout_stream_t *s;
+ sout_stream_t *s, *p_last;
msg_Dbg( p_stream, " * adding `%s'", p_cfg->psz_value );
- s = sout_StreamNew( p_stream->p_sout, p_cfg->psz_value );
+ s = sout_StreamChainNew( p_stream->p_sout, p_cfg->psz_value,
+ p_stream->p_next, &p_last );
if( s )
{
TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, s );
+ TAB_APPEND( p_sys->i_nb_last_streams, p_sys->pp_last_streams,
+ p_last );
TAB_APPEND( p_sys->i_nb_select, p_sys->ppsz_select, NULL );
}
}
msg_Dbg( p_stream, "closing a duplication" );
for( i = 0; i < p_sys->i_nb_streams; i++ )
{
- sout_StreamDelete( p_sys->pp_streams[i] );
+ sout_StreamChainDelete(p_sys->pp_streams[i], p_sys->pp_last_streams[i]);
free( p_sys->ppsz_select[i] );
}
free( p_sys->pp_streams );
+ free( p_sys->pp_last_streams );
free( p_sys->ppsz_select );
free( p_sys );
struct sout_stream_sys_t
{
- sout_stream_t *p_out;
-
int i_id;
sout_stream_id_t **id;
};
if( p_sys == NULL )
return VLC_EGENERIC;
- p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
- if( p_sys->p_out == NULL )
+ if( !p_stream->p_next )
{
free( p_sys );
return VLC_EGENERIC;
{
sout_stream_id_t *id = p_sys->id[i];
- sout_StreamIdDel( p_sys->p_out, id->id );
+ sout_StreamIdDel( p_stream->p_next, id->id );
es_format_Clean( &id->fmt );
free( id );
}
TAB_CLEAN( p_sys->i_id, p_sys->id );
- sout_StreamDelete( p_sys->p_out );
free( p_sys );
}
if( !id->b_used && id->fmt.i_cat == p_fmt->i_cat )
{
TAB_REMOVE( p_sys->i_id, p_sys->id, id );
- sout_StreamIdDel( p_sys->p_out, id->id );
+ sout_StreamIdDel( p_stream->p_next, id->id );
es_format_Clean( &id->fmt );
free( id );
return NULL;
es_format_Copy( &id->fmt, p_fmt );
id->b_used = true;
- id->id = sout_StreamIdAdd( p_sys->p_out, &id->fmt );
+ id->id = sout_StreamIdAdd( p_stream->p_next, &id->fmt );
if( id->id == NULL )
{
free( id );
static int Send( sout_stream_t *p_stream,
sout_stream_id_t *id, block_t *p_buffer )
{
- sout_stream_sys_t *p_sys = p_stream->p_sys;
-
- return sout_StreamIdSend( p_sys->p_out, id->id, p_buffer );
+ return sout_StreamIdSend( p_stream->p_next, id->id, p_buffer );
}
sout_stream_sys_t *p_sys = p_stream->p_sys;
if( p_sys->p_out )
- sout_StreamDelete( p_sys->p_out );
+ sout_StreamChainDelete( p_sys->p_out, p_sys->p_out );
TAB_CLEAN( p_sys->i_id, p_sys->id );
free( p_sys->psz_prefix );
/* Create the output */
msg_Dbg( p_stream, "Using record output `%s'", psz_output );
- p_sys->p_out = sout_StreamNew( p_stream->p_sout, psz_output );
+ p_sys->p_out = sout_StreamChainNew( p_stream->p_sout, psz_output, NULL, NULL );
if( !p_sys->p_out )
goto error;
id->id = NULL;
}
if( p_sys->p_out )
- sout_StreamDelete( p_sys->p_out );
+ sout_StreamChainDelete( p_sys->p_out, p_sys->p_out );
p_sys->p_out = NULL;
if( i_es > i_best_es )
struct sout_stream_sys_t
{
- sout_stream_t *p_out;
int i_gop;
int i_qscale;
int i_aspect;
if( !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 );
sout_stream_t *p_stream = (sout_stream_t *)p_this;
sout_stream_sys_t *p_sys = p_stream->p_sys;
- sout_StreamDelete( p_sys->p_out );
-
free( p_sys );
}
memcpy( &id->f_src, p_fmt, sizeof( es_format_t ) );
/* open output stream */
- 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 != NULL )
return id;
if ( id->id )
{
- p_sys->p_out->pf_del( p_sys->p_out, id->id );
+ p_stream->p_next->pf_del( p_stream->p_next, id->id );
}
free( id );
if ( !id->b_switcher_video && !id->b_switcher_audio )
{
- return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
+ return p_stream->p_next->pf_send( p_stream->p_next, id->id, p_buffer );
}
block_ChainAppend( &id->p_queued, p_buffer );
{
/* Full forward */
if ( p_blocks != NULL )
- p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks );
+ p_stream->p_next->pf_send( p_stream->p_next, id->id, p_blocks );
return i_dts;
}
}
if ( p_blocks_out != NULL )
- p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks_out );
+ p_stream->p_next->pf_send( p_stream->p_next, id->id, p_blocks_out );
return i_dts;
}
}
/* Open output stream */
- id->id = sout_StreamIdAdd( p_sys->p_out, &id->p_encoder->fmt_out );
+ id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out );
id->b_transcode = true;
if( !id->id )
}
/* open output stream */
- id->id = sout_StreamIdAdd( p_sys->p_out, &id->p_encoder->fmt_out );
+ id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out );
id->b_transcode = true;
if( !id->id ) goto error;
{
msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
(char*)&id->p_decoder->fmt_out.i_codec );
- id->id = sout_StreamIdAdd( p_sys->p_out, &id->p_decoder->fmt_out );
+ id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_decoder->fmt_out );
id->b_transcode = false;
if( !id->id ) goto error;
}
/* open output stream */
- id->id = sout_StreamIdAdd( p_sys->p_out, &id->p_encoder->fmt_out );
+ id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out );
id->b_transcode = true;
if( !id->id )
p_sys = vlc_object_create( p_this, sizeof( sout_stream_sys_t ) );
- 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" );
vlc_object_release( p_sys );
sout_stream_t *p_stream = (sout_stream_t*)p_this;
sout_stream_sys_t *p_sys = p_stream->p_sys;
- sout_StreamDelete( p_sys->p_out );
-
free( p_sys->psz_af );
config_ChainDestroy( p_sys->p_audio_cfg );
{
msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
(char*)&p_fmt->i_codec );
- id->id = sout_StreamIdAdd( p_sys->p_out, p_fmt );
+ id->id = sout_StreamIdAdd( p_stream->p_next, p_fmt );
id->b_transcode = false;
success = id->id;
}
}
- if( id->id ) sout_StreamIdDel( p_sys->p_out, id->id );
+ if( id->id ) sout_StreamIdDel( p_stream->p_next, id->id );
if( id->p_decoder )
{
if( !id->b_transcode )
{
if( id->id )
- return sout_StreamIdSend( p_sys->p_out, id->id, p_buffer );
+ return sout_StreamIdSend( p_stream->p_next, id->id, p_buffer );
block_Release( p_buffer );
return VLC_EGENERIC;
}
if( p_out )
- return sout_StreamIdSend( p_sys->p_out, id->id, p_out );
+ return sout_StreamIdSend( p_stream->p_next, id->id, p_out );
return VLC_SUCCESS;
}
{
VLC_COMMON_MEMBERS
- sout_stream_t *p_out;
sout_stream_id_t *id_video;
block_t *p_buffers;
vlc_mutex_t lock_out;
id->p_encoder->fmt_out.i_codec =
vlc_fourcc_GetCodec( VIDEO_ES, id->p_encoder->fmt_out.i_codec );
- id->id = sout_StreamIdAdd( p_stream->p_sys->p_out,
- &id->p_encoder->fmt_out );
+ id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out );
if( !id->id )
{
msg_Err( p_stream, "cannot add this stream" );
sout_MuxNew
sout_MuxSendBuffer
sout_SAPMethod
-sout_StreamDelete
-sout_StreamNew
+sout_StreamChainDelete
+sout_StreamChainNew
sout_UpdateStatistic
__spu_Create
spu_Destroy
# include "config.h"
#endif
+#include <assert.h>
+
#include <vlc_common.h>
#include <stdlib.h> /* free() */
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-#define sout_stream_url_to_chain( p, s ) \
- _sout_stream_url_to_chain( VLC_OBJECT(p), s )
-static char *_sout_stream_url_to_chain( vlc_object_t *, const char * );
+static char *sout_stream_url_to_chain( bool, const char * );
/*
* Generic MRL parser
static const char typename[] = "stream output";
sout_instance_t *p_sout;
+ char *psz_chain;
+ if( psz_dest && psz_dest[0] == '#' )
+ {
+ psz_chain = strdup( &psz_dest[1] );
+ }
+ else
+ {
+ psz_chain = sout_stream_url_to_chain(
+ config_GetInt(p_parent, "sout-display") > 0, psz_dest );
+ }
+ if(!psz_chain)
+ return NULL;
+
/* *** Allocate descriptor *** */
p_sout = vlc_custom_create( p_parent, sizeof( *p_sout ),
VLC_OBJECT_GENERIC, typename );
if( p_sout == NULL )
return NULL;
+ msg_Dbg( p_sout, "using sout chain=`%s'", psz_chain );
+
/* *** init descriptor *** */
p_sout->psz_sout = strdup( psz_dest );
p_sout->p_meta = NULL;
p_sout->p_sys = NULL;
vlc_mutex_init( &p_sout->lock );
- if( psz_dest && psz_dest[0] == '#' )
- {
- p_sout->psz_chain = strdup( &psz_dest[1] );
- }
- else
- {
- p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
- msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
- }
p_sout->p_stream = NULL;
/* attach it for inherit */
vlc_object_attach( p_sout, p_parent );
- /* */
var_Create( p_sout, "sout-mux-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
- /* */
- p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
- if( p_sout->p_stream == NULL )
+ p_sout->p_stream = sout_StreamChainNew( p_sout, psz_chain, NULL, NULL );
+ if( p_sout->p_stream )
{
- msg_Err( p_sout, "stream chain failed for `%s'", p_sout->psz_chain );
+ free( psz_chain );
+ return p_sout;
+ }
- FREENULL( p_sout->psz_sout );
- FREENULL( p_sout->psz_chain );
+ free( psz_chain );
+ msg_Err( p_sout, "stream chain failed for `%s'", psz_chain );
- vlc_object_detach( p_sout );
- vlc_object_release( p_sout );
- return NULL;
- }
+ FREENULL( p_sout->psz_sout );
- return p_sout;
+ vlc_object_detach( p_sout );
+ vlc_object_release( p_sout );
+ return NULL;
}
/*****************************************************************************
void sout_DeleteInstance( sout_instance_t * p_sout )
{
/* remove the stream out chain */
- sout_StreamDelete( p_sout->p_stream );
+ sout_StreamChainDelete( p_sout->p_stream, NULL );
/* *** free all string *** */
FREENULL( p_sout->psz_sout );
- FREENULL( p_sout->psz_chain );
/* delete meta */
if( p_sout->p_meta )
****************************************************************************
****************************************************************************/
-/* create a complete chain */
-/* chain format:
- module{option=*:option=*}[:module{option=*:...}]
- */
+/* Destroy a "stream_out" module */
+static void sout_StreamDelete( sout_stream_t *p_stream )
+{
+ msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
-/*
- * parse module{options=str, option="str "}:
- * return a pointer on the rest
- * XXX: psz_chain is modified
+ vlc_object_detach( p_stream );
+ if( p_stream->p_module ) module_unneed( p_stream, p_stream->p_module );
+
+ FREENULL( p_stream->psz_name );
+
+ config_ChainDestroy( p_stream->p_cfg );
+
+ msg_Dbg( p_stream, "destroying chain done" );
+ vlc_object_release( p_stream );
+}
+
+/* Destroy a "stream_out" modules chain
+ *
+ * p_first is the first module to be destroyed in the chain
+ * p_last is the last module to be destroyed
+ * if NULL, all modules are destroyed
+ * if not NULL, modules following it must be destroyed separately
*/
+void sout_StreamChainDelete(sout_stream_t *p_first, sout_stream_t *p_last)
+{
+ if(!p_first)
+ return;
+
+ if(p_first != p_last)
+ sout_StreamChainDelete(p_first->p_next, p_last);
+
+ sout_StreamDelete(p_first);
+}
+/* Create a "stream_out" module, which may forward its ES to p_next module */
/*
* XXX name and p_cfg are used (-> do NOT free them)
*/
-sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
+static sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_name,
+ config_chain_t *p_cfg, sout_stream_t *p_next)
{
static const char typename[] = "stream out";
sout_stream_t *p_stream;
- if( !psz_chain )
- {
- msg_Err( p_sout, "invalid chain" );
- return NULL;
- }
+ assert(psz_name);
p_stream = vlc_custom_create( p_sout, sizeof( *p_stream ),
VLC_OBJECT_GENERIC, typename );
p_stream->p_sout = p_sout;
p_stream->p_sys = NULL;
-
- p_stream->psz_next =
- config_ChainCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
+ p_stream->psz_name = psz_name;
+ p_stream->p_cfg = p_cfg;
+ p_stream->p_next = p_next;
msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
return p_stream;
}
-void sout_StreamDelete( sout_stream_t *p_stream )
+/* Creates a complete "stream_out" modules chain
+ *
+ * chain format: module1{option=*:option=*}[:module2{option=*:...}]
+ *
+ * The modules are created starting from the last one and linked together
+ * A pointer to the last module created is stored if pp_last isn't NULL, to
+ * make sure sout_StreamChainDelete doesn't delete modules created in another
+ * place.
+ *
+ * Returns a pointer to the first module.
+ */
+sout_stream_t *sout_StreamChainNew(sout_instance_t *p_sout, char *psz_chain,
+ sout_stream_t *p_next, sout_stream_t **pp_last)
{
- msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
+ if(!psz_chain || !*psz_chain)
+ {
+ if(pp_last) *pp_last = NULL;
+ return p_next;
+ }
- vlc_object_detach( p_stream );
- if( p_stream->p_module ) module_unneed( p_stream, p_stream->p_module );
+ char *psz_parser = strdup(psz_chain);
+ if(!psz_parser)
+ return NULL;
- FREENULL( p_stream->psz_name );
- FREENULL( p_stream->psz_next );
+ vlc_array_t cfg, name;
+ vlc_array_init(&cfg);
+ vlc_array_init(&name);
- config_ChainDestroy( p_stream->p_cfg );
+ /* parse chain */
+ while(psz_parser)
+ {
+ config_chain_t *p_cfg;
+ char *psz_name;
+ psz_chain = config_ChainCreate( &psz_name, &p_cfg, psz_parser );
+ free( psz_parser );
+ psz_parser = psz_chain;
- msg_Dbg( p_stream, "destroying chain done" );
- vlc_object_release( p_stream );
+ vlc_array_append(&cfg, p_cfg);
+ vlc_array_append(&name, psz_name);
+ }
+
+ int i = vlc_array_count(&name);
+ vlc_array_t module;
+ vlc_array_init(&module);
+ while(i--)
+ {
+ p_next = sout_StreamNew( p_sout, vlc_array_item_at_index(&name, i),
+ vlc_array_item_at_index(&cfg, i), p_next);
+
+ if(!p_next)
+ goto error;
+
+ if(i == vlc_array_count(&name) - 1 && pp_last)
+ *pp_last = p_next; /* last module created in the chain */
+
+ vlc_array_append(&module, p_next);
+ }
+
+ vlc_array_clear(&name);
+ vlc_array_clear(&cfg);
+ vlc_array_clear(&module);
+
+ return p_next;
+
+error:
+
+ i++; /* last module couldn't be created */
+
+ /* destroy all modules created, starting with the last one */
+ int modules = vlc_array_count(&module);
+ while(modules--)
+ sout_StreamDelete(vlc_array_item_at_index(&module, modules));
+ vlc_array_clear(&module);
+
+ /* then destroy all names and config which weren't destroyed by
+ * sout_StreamDelete */
+ while(i--)
+ {
+ free(vlc_array_item_at_index(&name, i));
+ config_ChainDestroy(vlc_array_item_at_index(&cfg, i));
+ }
+ vlc_array_clear(&name);
+ vlc_array_clear(&cfg);
+
+ return NULL;
}
-static char *_sout_stream_url_to_chain( vlc_object_t *p_this,
- const char *psz_url )
+static char *sout_stream_url_to_chain( bool b_sout_display,
+ const char *psz_url )
{
mrl_t mrl;
char *psz_chain;
}
/* Duplicate and wrap if sout-display is on */
- if (psz_chain && (config_GetInt( p_this, "sout-display" ) > 0))
+ if (psz_chain && b_sout_display)
{
char *tmp;
if (asprintf (&tmp, "duplicate{dst=display,dst=%s}", tmp) == -1)