Commit 1743aae3 authored by Rafaël Carré's avatar Rafaël Carré

sout: allow duplicate outputs to be merged

The stream_out_t chain creation is modified: all modules are created by
the core (or by stream_out_duplicate) instead of being created by the
previous module.

sout_StreamChain{New,Delete} replace sout_Stream{New,Delete} to handle
modules chains instead of individual modules

sout_Stream{New,Delete} are still used by those new functions but made
static inside stream_output.c

Remove now unneeded psz_chain from struct sout_instance_t
Replace pointer to chain of next module by pointer to next module in
struct sout_stream_t

Example use:

vlc --sout-all input.mp4 --sout
"#duplicate{dst=transcode{vcodec=mp2v},select=es=0,dst=transcode,select=es=1}:std{...}"

(dst=transcode without acodec/vcodec is a hack to pass the encoded stream to
stream_out_standard without transcoding)
parent d83a491d
......@@ -45,7 +45,6 @@ struct sout_instance_t
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;
......@@ -208,7 +207,7 @@ struct sout_stream_t
char *psz_name;
config_chain_t *p_cfg;
char *psz_next;
sout_stream_t *p_next;
/* Subpicture unit */
spu_t *p_spu;
......@@ -223,8 +222,9 @@ struct sout_stream_t
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 )
{
......
......@@ -68,7 +68,6 @@ struct sout_stream_id_t
struct sout_stream_sys_t
{
sout_stream_t *p_out;
sout_stream_id_t **pp_es;
int i_es_num;
};
......@@ -83,8 +82,7 @@ static int Open( vlc_object_t *p_this )
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 );
......@@ -113,7 +111,6 @@ static void Close( vlc_object_t * p_this )
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 );
......@@ -142,7 +139,7 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *p_es )
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;
}
......@@ -157,7 +154,7 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *p_es,
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;
......@@ -167,7 +164,7 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *p_es,
}
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 );
......@@ -178,7 +175,7 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *p_es,
|| 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;
}
}
......
......@@ -363,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;
......@@ -395,8 +394,7 @@ static int OpenIn( vlc_object_t *p_this )
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 );
......@@ -461,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 );
......@@ -481,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 );
......@@ -516,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;
......@@ -533,7 +530,7 @@ 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 );
......@@ -570,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
{
......@@ -584,8 +581,8 @@ 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;
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",
......@@ -608,7 +605,7 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id,
&& 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;
......@@ -642,7 +639,7 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id,
( 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;
......@@ -654,14 +651,14 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id,
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 );
}
......@@ -694,7 +691,7 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id,
|| 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
......@@ -703,7 +700,7 @@ static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id,
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;
......
......@@ -64,6 +64,9 @@ struct sout_stream_sys_t
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;
};
......@@ -92,20 +95,24 @@ static int Open( vlc_object_t *p_this )
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 );
}
}
......@@ -164,10 +171,11 @@ static void Close( vlc_object_t * p_this )
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 );
......
......@@ -64,8 +64,6 @@ struct sout_stream_id_t
struct sout_stream_sys_t
{
sout_stream_t *p_out;
int i_id;
sout_stream_id_t **id;
};
......@@ -82,8 +80,7 @@ static int Open( vlc_object_t *p_this )
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;
......@@ -110,13 +107,12 @@ static void Close( vlc_object_t * p_this )
{
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 );
}
......@@ -168,7 +164,7 @@ static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
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 );
......@@ -183,7 +179,7 @@ static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
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 );
......@@ -210,7 +206,5 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *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 );
}
......@@ -170,7 +170,7 @@ static void Close( vlc_object_t * p_this )
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 );
......@@ -327,7 +327,7 @@ static int OutputNew( sout_stream_t *p_stream,
/* 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;
......@@ -460,7 +460,7 @@ static void OutputStart( sout_stream_t *p_stream )
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 )
......
......@@ -143,7 +143,6 @@ static const char *const ppsz_sout_options[] = {
struct sout_stream_sys_t
{
sout_stream_t *p_out;
int i_gop;
int i_qscale;
int i_aspect;
......@@ -191,8 +190,7 @@ static int Open( vlc_object_t *p_this )
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 );
......@@ -306,8 +304,6 @@ static void Close( vlc_object_t * p_this )
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 );
}
......@@ -427,7 +423,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
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;
......@@ -475,7 +471,7 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *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 );
......@@ -498,7 +494,7 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *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 );
......@@ -557,7 +553,7 @@ static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id,
{
/* 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;
}
......@@ -594,7 +590,7 @@ static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id,
}
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;
}
......
......@@ -438,7 +438,7 @@ bool transcode_audio_add( sout_stream_t *p_stream, es_format_t *p_fmt,
}
/* 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 )
......
......@@ -68,7 +68,7 @@ int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *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;
......@@ -77,7 +77,7 @@ int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id )
{
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;
......
......@@ -173,7 +173,7 @@ bool transcode_spu_add( sout_stream_t *p_stream, es_format_t *p_fmt,
}
/* 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 )
......
......@@ -258,8 +258,7 @@ static int Open( vlc_object_t *p_this )
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 );
......@@ -515,8 +514,6 @@ static void Close( vlc_object_t * p_this )
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 );
......@@ -596,7 +593,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
{
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;
......@@ -653,7 +650,7 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *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 )
{
......@@ -683,7 +680,7 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
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;
......@@ -727,6 +724,6 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
}
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;
}
......@@ -19,7 +19,6 @@ struct sout_stream_sys_t
{
VLC_COMMON_MEMBERS
sout_stream_t *p_out;
sout_stream_id_t *id_video;
block_t *p_buffers;
vlc_mutex_t lock_out;
......
......@@ -482,8 +482,7 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
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" );
......
......@@ -367,8 +367,8 @@ sout_MuxGetStream
sout_MuxNew
sout_MuxSendBuffer
sout_SAPMethod
sout_StreamDelete
sout_StreamNew
sout_StreamChainDelete
sout_StreamChainNew
sout_UpdateStatistic
__spu_Create
spu_Destroy
......
......@@ -31,6 +31,8 @@
# include "config.h"
#endif
#include <assert.h>
#include <vlc_common.h>
#include <stdlib.h> /* free() */
......@@ -53,9 +55,7 @@
/*****************************************************************************
* 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
......@@ -82,12 +82,27 @@ sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, const char *psz_des
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;
......@@ -95,38 +110,28 @@ sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, const char *psz_des
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;
}
free( psz_chain );
msg_Err( p_sout, "stream chain failed for `%s'", psz_chain );
FREENULL( p_sout->psz_sout );
FREENULL( p_sout->psz_chain );
vlc_object_detach( p_sout );
vlc_object_release( p_sout );
return NULL;
}
return p_sout;
}
/*****************************************************************************
......@@ -135,11 +140,10 @@ sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, const char *psz_des
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 )
......@@ -789,30 +793,51 @@ static void mrl_Clean( mrl_t *p_mrl )
****************************************************************************
****************************************************************************/
/* 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 );
......@@ -821,9 +846,9 @@ sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
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 );
......@@ -841,23 +866,94 @@ sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
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,
static char *sout_stream_url_to_chain( bool b_sout_display,
const char *psz_url )
{
mrl_t mrl;
......@@ -904,7 +1000,7 @@ rtp:
}
/* 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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment