]> git.sesse.net Git - vlc/commitdiff
sout: allow duplicate outputs to be merged
authorRafaël Carré <rafael.carre@gmail.com>
Sun, 17 Jan 2010 06:37:33 +0000 (07:37 +0100)
committerRafaël Carré <rafael.carre@gmail.com>
Sun, 17 Jan 2010 06:37:33 +0000 (07:37 +0100)
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)

15 files changed:
include/vlc_sout.h
modules/stream_out/autodel.c
modules/stream_out/bridge.c
modules/stream_out/duplicate.c
modules/stream_out/gather.c
modules/stream_out/record.c
modules/stream_out/switcher.c
modules/stream_out/transcode/audio.c
modules/stream_out/transcode/osd.c
modules/stream_out/transcode/spu.c
modules/stream_out/transcode/transcode.c
modules/stream_out/transcode/transcode.h
modules/stream_out/transcode/video.c
src/libvlccore.sym
src/stream_output/stream_output.c

index 2972b060b0ee3a049e9867a539354c098110ba33..03740c076b130faa66a0b08b3967c5a350bbf6ef 100644 (file)
@@ -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 )
 {
index d3143efcd72cd26cad27ba1c29170d66c242f9f7..e9229e5dcfdc0cfa2d303146dd13f30af9b6d0ea 100644 (file)
@@ -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;
         }
     }
index 504956f5c91ee8d02bc8640e356baa53b56b7d9a..ff247468d496b041335cc60511acde9ae1203585 100644 (file)
@@ -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;
index 852327a0817a1dcb6e2af97bf11d5e51af40c440..26cfeffd6e75ff88bc12b53a7d1cb7ad30ca83ad 100644 (file)
@@ -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 );
index 41778d7cb4268fb3b347579296431416e5de17fa..1a266551f9d0ee7796f9027602770b703c41977d 100644 (file)
@@ -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 );
 }
index b953961a33e79a239527131ce49df073745a637a..01fa12269c692a5d8bdb38a0c0195e257074b89f 100644 (file)
@@ -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 )
index 14780596643158d728cbcc994c76523636f2fba7..11a752dca6549d7d714d9c8c53aada26365850a0 100644 (file)
@@ -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;
 }
 
index 5895b6fe4d20c2390c586c7e2d74f0facf623852..1a89b4b47c11accf23a7cf1953aa2456bcfd1db8 100644 (file)
@@ -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 )
index f6cd7f556dabd1e3bc0cf5d1c2708a6284caf020..4424f6ecd75edcc327ccb792c83681c6d2ed792d 100644 (file)
@@ -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;
index 48820eaec328a1ff30112be21aae6ac9162fadda..e493b6ff62a05d747cd054fe7d12e18a18e02454 100644 (file)
@@ -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 )
index 2227f8b394e0f9d390d27ac284d66fb66fb10abc..4d7d3686e99eae760ea2cdc0e69cc46246a0667a 100644 (file)
@@ -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;
 }
index dd7b3bf68c4ca33a810a57c1109629b5865dc35a..72b712068ff9182b3700545ce3f0cb3c2b9adb76 100644 (file)
@@ -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;
index 15fd25d1e34712e8e3ff42f40840041c148be2a1..e77ca96d48774821ebf79a9db125f54bf1d412eb 100644 (file)
@@ -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" );
index 9656d1a85672395910980548197c9352075584fa..f498526b060278718709019ac9b5da1d7dc9f4fc 100644 (file)
@@ -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
index 8fbfbb0aeec3996b065bd46a22da951bc67a1c68..3fec92dfbb47052dac433c12233ae69c138b73fc 100644 (file)
@@ -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;
+    }
 
-        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)