* modules/stream_out/autodel.c: New autodel module to work-around a memory
authorChristophe Massiot <massiot@videolan.org>
Thu, 9 Nov 2006 15:13:13 +0000 (15:13 +0000)
committerChristophe Massiot <massiot@videolan.org>
Thu, 9 Nov 2006 15:13:13 +0000 (15:13 +0000)
   leak in the TS mux which is triggered when the input PCR packets
   disappear from the stream without disappearing from the PMT (happens
   on the satellite when the video suddenly gets scrambled). Insert it in
   the sout pipeline : --sout="#autodel:std{...}".

configure.ac
modules/stream_out/Modules.am
modules/stream_out/autodel.c [new file with mode: 0644]

index a57548e..21d69ad 100644 (file)
@@ -1425,7 +1425,7 @@ then
   VLC_ADD_PLUGINS([packetizer_copy])
 
   VLC_ADD_PLUGINS([stream_out_dummy stream_out_standard stream_out_es stream_out_rtp stream_out_description vod_rtsp])
-  VLC_ADD_PLUGINS([stream_out_duplicate stream_out_gather stream_out_display stream_out_transcode stream_out_bridge stream_out_mosaic_bridge])
+  VLC_ADD_PLUGINS([stream_out_duplicate stream_out_gather stream_out_display stream_out_transcode stream_out_bridge stream_out_mosaic_bridge stream_out_autodel])
 #  VLC_ADD_PLUGINS([stream_out_transrate])
   VLC_ADD_PLUGINS([profile_parser])
 
index 69dd910..74e9aef 100644 (file)
@@ -10,3 +10,4 @@ SOURCES_stream_out_rtp = rtp.c
 SOURCES_stream_out_switcher = switcher.c
 SOURCES_stream_out_bridge = bridge.c
 SOURCES_stream_out_mosaic_bridge = mosaic_bridge.c
+SOURCES_stream_out_autodel = autodel.c
diff --git a/modules/stream_out/autodel.c b/modules/stream_out/autodel.c
new file mode 100644 (file)
index 0000000..5e926ef
--- /dev/null
@@ -0,0 +1,190 @@
+/*****************************************************************************
+ * autodel.c: monitor mux inputs and automatically add/delete streams
+ *****************************************************************************
+ * Copyright (C) 2006 the VideoLAN team
+ * $Id: autodel.c 12074 2005-08-08 17:18:08Z dionoea $
+ *
+ * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/sout.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int  Open    ( vlc_object_t * );
+static void Close   ( vlc_object_t * );
+
+#define SOUT_CFG_PREFIX "sout-autodel-"
+
+vlc_module_begin();
+    set_shortname( _("Autodel"));
+    set_description( _("Automatically add/delete input streams"));
+    set_capability( "sout stream", 50 );
+    add_shortcut( "autodel" );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static const char *ppsz_sout_options[] = {
+    NULL
+};
+
+static sout_stream_id_t *Add   ( sout_stream_t *, es_format_t * );
+static int               Del   ( sout_stream_t *, sout_stream_id_t * );
+static int               Send  ( sout_stream_t *, sout_stream_id_t *, block_t * );
+
+struct sout_stream_id_t
+{
+    sout_stream_id_t *id;
+    es_format_t fmt;
+    mtime_t i_last;
+    vlc_bool_t b_error;
+};
+
+struct sout_stream_sys_t
+{
+    sout_stream_t   *p_out;
+    sout_stream_id_t **pp_es;
+    int i_es_num;
+};
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys;
+
+    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 )
+    {
+        msg_Err( p_stream, "cannot create chain" );
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+    p_sys->pp_es = NULL;
+    p_sys->i_es_num = 0;
+
+    sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
+                   p_stream->p_cfg );
+
+    p_stream->pf_add    = Add;
+    p_stream->pf_del    = Del;
+    p_stream->pf_send   = Send;
+
+    p_stream->p_sys     = p_sys;
+
+    /* update p_sout->i_out_pace_nocontrol */
+    p_stream->p_sout->i_out_pace_nocontrol++;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+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 );
+}
+
+static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
+{
+    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;
+    sout_stream_id_t *p_es = malloc( sizeof(sout_stream_id_t) );
+
+    p_es->fmt = *p_fmt;
+    p_es->id = NULL;
+    p_es->i_last = 0;
+    p_es->b_error = VLC_FALSE;
+    TAB_APPEND( p_sys->i_es_num, p_sys->pp_es, p_es );
+
+    return p_es;
+}
+
+static int Del( sout_stream_t *p_stream, sout_stream_id_t *p_es )
+{
+    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;
+    sout_stream_id_t *id = p_es->id;
+
+    TAB_REMOVE( p_sys->i_es_num, p_sys->pp_es, p_es );
+    free( p_es );
+
+    if ( id != NULL )
+        return p_sys->p_out->pf_del( p_sys->p_out, id );
+    else
+        return VLC_SUCCESS;
+}
+
+static int Send( sout_stream_t *p_stream, sout_stream_id_t *p_es,
+                 block_t *p_buffer )
+{
+    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;
+    mtime_t i_current = mdate();
+    int i;
+
+    p_es->i_last = p_buffer->i_dts;
+    if ( p_es->id == NULL && p_es->b_error != VLC_TRUE )
+    {
+        p_es->id = p_sys->p_out->pf_add( p_sys->p_out, &p_es->fmt );
+        if ( p_es->id == NULL )
+        {
+            p_es->b_error = VLC_TRUE;
+            msg_Err( p_stream, "couldn't create chain for id %d",
+                     p_es->fmt.i_id );
+        }
+    }
+
+    if ( p_es->b_error != VLC_TRUE )
+        p_sys->p_out->pf_send( p_sys->p_out, p_es->id, p_buffer );
+    else
+        block_ChainRelease( p_buffer );
+
+    for ( i = 0; i < p_sys->i_es_num; i++ )
+    {
+        if ( p_sys->pp_es[i]->id != NULL
+              && (p_sys->pp_es[i]->fmt.i_cat == VIDEO_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_sys->pp_es[i]->id = NULL;
+        }
+    }
+
+    return VLC_SUCCESS;
+}