From: Rafaël Carré Date: Sun, 17 Jan 2010 06:37:33 +0000 (+0100) Subject: sout: allow duplicate outputs to be merged X-Git-Tag: 1.1.0-ff~1163 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=1743aae3ec2b5e8b02c3bad36dcd50914ac09d8a;p=vlc 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) --- diff --git a/include/vlc_sout.h b/include/vlc_sout.h index 2972b060b0..03740c076b 100644 --- a/include/vlc_sout.h +++ b/include/vlc_sout.h @@ -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 ) { diff --git a/modules/stream_out/autodel.c b/modules/stream_out/autodel.c index d3143efcd7..e9229e5dcf 100644 --- a/modules/stream_out/autodel.c +++ b/modules/stream_out/autodel.c @@ -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; } } diff --git a/modules/stream_out/bridge.c b/modules/stream_out/bridge.c index 504956f5c9..ff247468d4 100644 --- a/modules/stream_out/bridge.c +++ b/modules/stream_out/bridge.c @@ -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; diff --git a/modules/stream_out/duplicate.c b/modules/stream_out/duplicate.c index 852327a081..26cfeffd6e 100644 --- a/modules/stream_out/duplicate.c +++ b/modules/stream_out/duplicate.c @@ -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 ); diff --git a/modules/stream_out/gather.c b/modules/stream_out/gather.c index 41778d7cb4..1a266551f9 100644 --- a/modules/stream_out/gather.c +++ b/modules/stream_out/gather.c @@ -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 ); } diff --git a/modules/stream_out/record.c b/modules/stream_out/record.c index b953961a33..01fa12269c 100644 --- a/modules/stream_out/record.c +++ b/modules/stream_out/record.c @@ -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 ) diff --git a/modules/stream_out/switcher.c b/modules/stream_out/switcher.c index 1478059664..11a752dca6 100644 --- a/modules/stream_out/switcher.c +++ b/modules/stream_out/switcher.c @@ -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; } diff --git a/modules/stream_out/transcode/audio.c b/modules/stream_out/transcode/audio.c index 5895b6fe4d..1a89b4b47c 100644 --- a/modules/stream_out/transcode/audio.c +++ b/modules/stream_out/transcode/audio.c @@ -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 ) diff --git a/modules/stream_out/transcode/osd.c b/modules/stream_out/transcode/osd.c index f6cd7f556d..4424f6ecd7 100644 --- a/modules/stream_out/transcode/osd.c +++ b/modules/stream_out/transcode/osd.c @@ -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; diff --git a/modules/stream_out/transcode/spu.c b/modules/stream_out/transcode/spu.c index 48820eaec3..e493b6ff62 100644 --- a/modules/stream_out/transcode/spu.c +++ b/modules/stream_out/transcode/spu.c @@ -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 ) diff --git a/modules/stream_out/transcode/transcode.c b/modules/stream_out/transcode/transcode.c index 2227f8b394..4d7d3686e9 100644 --- a/modules/stream_out/transcode/transcode.c +++ b/modules/stream_out/transcode/transcode.c @@ -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; } diff --git a/modules/stream_out/transcode/transcode.h b/modules/stream_out/transcode/transcode.h index dd7b3bf68c..72b712068f 100644 --- a/modules/stream_out/transcode/transcode.h +++ b/modules/stream_out/transcode/transcode.h @@ -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; diff --git a/modules/stream_out/transcode/video.c b/modules/stream_out/transcode/video.c index 15fd25d1e3..e77ca96d48 100644 --- a/modules/stream_out/transcode/video.c +++ b/modules/stream_out/transcode/video.c @@ -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" ); diff --git a/src/libvlccore.sym b/src/libvlccore.sym index 9656d1a856..f498526b06 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -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 diff --git a/src/stream_output/stream_output.c b/src/stream_output/stream_output.c index 8fbfbb0aee..3fec92dfbb 100644 --- a/src/stream_output/stream_output.c +++ b/src/stream_output/stream_output.c @@ -31,6 +31,8 @@ # include "config.h" #endif +#include + #include #include /* 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; + } - 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; } /***************************************************************************** @@ -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,24 +866,95 @@ 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, - 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; @@ -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)