[vlc-devel] [PATCH 1/2] [RFC] core: add a demux-filter similar to stream-filter for demuxers

Steve Lhomme robux4 at videolabs.io
Fri Apr 22 17:57:20 CEST 2016


it allows filtering the Demux calls to the underlying muxer
it can be chained like stream-filters
internally it's a regular demuxer_t with the p_source demuxer set

the base value of "demux-filter" is set in libvlc, each input_thread_t has
their own copy
---
 NEWS                     |  3 ++
 include/vlc_config_cat.h |  6 ++++
 include/vlc_demux.h      |  9 ++++++
 include/vlc_plugin.h     |  1 +
 src/input/demux.c        | 83 +++++++++++++++++++++++++++++++++++++++++++++---
 src/input/demux.h        |  6 ++--
 src/input/input.c        | 59 +++++++++++++++++++++++++++-------
 src/input/stream_demux.c |  2 +-
 src/input/var.c          |  1 +
 src/libvlc-module.c      |  8 +++++
 src/libvlc.c             |  2 +-
 11 files changed, 161 insertions(+), 19 deletions(-)

diff --git a/NEWS b/NEWS
index dd37984..6767431 100644
--- a/NEWS
+++ b/NEWS
@@ -99,6 +99,9 @@ Stream filter:
  * Added stream prebuffering plugin
  * Removed HTTP Live streaming stream filter
  * Added zlib (a.k.a. deflate) decompression filter
+ 
+Demux filter:
+ * Added a chain of demuxer to wrap the one used for the input used for playback
 
 Audio output:
  * Complete rewrite of the AudioTrack Android module. This is now the default.
diff --git a/include/vlc_config_cat.h b/include/vlc_config_cat.h
index 55d2e46..25edee2 100644
--- a/include/vlc_config_cat.h
+++ b/include/vlc_config_cat.h
@@ -109,6 +109,11 @@
     "Stream filters are special modules that allow advanced operations on " \
     "the input side of VLC. Use with care..." )
 
+#define DEMUX_FILTER_TITLE N_( "Demux filters" )
+#define DEMUX_FILTER_HELP N_( \
+    "Demux filters are special modules that allow advanced operations on " \
+    "the demux side of VLC. Use with care..." )
+
 #define DEMUX_TITLE N_("Demuxers")
 #define DEMUX_HELP N_( "Demuxers are used to separate audio and video streams." )
 
@@ -219,6 +224,7 @@ static const struct config_category_t categories_array[] =
     { SUBCAT_INPUT_ACODEC, ADEC_TITLE, ADEC_HELP },
     { SUBCAT_INPUT_SCODEC, SDEC_TITLE, SDEC_HELP },
     { SUBCAT_INPUT_STREAM_FILTER, STREAM_FILTER_TITLE, STREAM_FILTER_HELP },
+    { SUBCAT_INPUT_DEMUX_FILTER, DEMUX_FILTER_TITLE, DEMUX_FILTER_HELP },
 
     { CAT_SOUT, SOUT_TITLE, SOUT_HELP },
     { SUBCAT_SOUT_GENERAL, SOUT_TITLE, SOUT_GENERAL_HELP },
diff --git a/include/vlc_demux.h b/include/vlc_demux.h
index 45f5416..0dcee90 100644
--- a/include/vlc_demux.h
+++ b/include/vlc_demux.h
@@ -77,6 +77,10 @@ struct demux_t
 
     /* Weak link to parent input */
     input_thread_t *p_input;
+
+    /* for demux-filter */
+    demux_t *p_source;
+    config_chain_t *p_cfg;
 };
 
 /* pf_demux return values */
@@ -396,6 +400,11 @@ VLC_API void demux_PacketizerDestroy( decoder_t *p_packetizer );
     } while(0)
 
 /**
+ * This function will create a packetizer suitable for a demuxer that parses
+ */
+VLC_API demux_t *demux_FilterChainNew( demux_t *p_demux, const char *psz_name );
+
+/**
  * @}
  */
 
diff --git a/include/vlc_plugin.h b/include/vlc_plugin.h
index 42c3288..2e9d4d8 100644
--- a/include/vlc_plugin.h
+++ b/include/vlc_plugin.h
@@ -165,6 +165,7 @@ enum vlc_module_properties
 #define SUBCAT_INPUT_ACODEC 405
 #define SUBCAT_INPUT_SCODEC 406
 #define SUBCAT_INPUT_STREAM_FILTER 407
+#define SUBCAT_INPUT_DEMUX_FILTER 408
 
 #define CAT_SOUT 5
 #define SUBCAT_SOUT_GENERAL 501
diff --git a/src/input/demux.c b/src/input/demux.c
index 303c0b8..e26f7e5 100644
--- a/src/input/demux.c
+++ b/src/input/demux.c
@@ -84,7 +84,7 @@ demux_t *demux_New( vlc_object_t *p_obj, const char *psz_name,
     return demux_NewAdvanced( p_obj, NULL,
                               (s == NULL) ? psz_name : "",
                               (s != NULL) ? psz_name : "",
-                              psz_location, s, out, false );
+                              psz_location, s, out, false, NULL, NULL );
 }
 
 /*****************************************************************************
@@ -95,7 +95,8 @@ demux_t *demux_New( vlc_object_t *p_obj, const char *psz_name,
 demux_t *demux_NewAdvanced( vlc_object_t *p_obj, input_thread_t *p_parent_input,
                             const char *psz_access, const char *psz_demux,
                             const char *psz_location,
-                            stream_t *s, es_out_t *out, bool b_quick )
+                            stream_t *s, es_out_t *out, bool b_quick,
+                            demux_t *p_wrapped, config_chain_t *p_cfg )
 {
     demux_t *p_demux = vlc_custom_create( p_obj, sizeof( *p_demux ), "demux" );
     if( unlikely(p_demux == NULL) )
@@ -116,6 +117,8 @@ demux_t *demux_NewAdvanced( vlc_object_t *p_obj, input_thread_t *p_parent_input,
     p_demux->psz_demux = strdup( psz_demux );
     p_demux->psz_location = strdup( psz_location );
     p_demux->psz_file = get_path( psz_location ); /* parse URL */
+    p_demux->p_source = p_wrapped;
+    p_demux->p_cfg = p_cfg;
 
     if( unlikely(p_demux->psz_access == NULL
               || p_demux->psz_demux == NULL
@@ -275,7 +278,7 @@ demux_t *input_DemuxNew( vlc_object_t *obj, const char *access_name,
     }
     else /* Try access_demux first */
         demux = demux_NewAdvanced( obj, input, access_name, demux_name, path,
-                                   NULL, out, false );
+                                   NULL, out, false, NULL, NULL );
 
     if( demux == NULL )
     {   /* Then try a real access,stream,demux chain */
@@ -323,7 +326,7 @@ demux_t *input_DemuxNew( vlc_object_t *obj, const char *access_name,
         }
 
         demux = demux_NewAdvanced( obj, input, access_name, demux_name, path,
-                                   stream, out, quick );
+                                   stream, out, quick, NULL, NULL );
         if( demux == NULL )
         {
             msg_Err( obj, "cannot parse %s://%s", access_name, path );
@@ -656,3 +659,75 @@ static bool SkipAPETag( demux_t *p_demux )
     return true;
 }
 
+demux_t *demux_FilterChainNew(demux_t *p_demux, const char *psz_chain)
+{
+    if(!psz_chain || !*psz_chain)
+    {
+        return NULL;
+    }
+
+    char *psz_parser = strdup(psz_chain);
+    if(!psz_parser)
+        return NULL;
+
+    vlc_array_t cfg, name;
+    vlc_array_init(&cfg);
+    vlc_array_init(&name);
+
+    /* parse chain */
+    while(psz_parser)
+    {
+        config_chain_t *p_cfg;
+        char *psz_name;
+        char *psz_rest_chain = config_ChainCreate( &psz_name, &p_cfg, psz_parser );
+        free( psz_parser );
+        psz_parser = psz_rest_chain;
+
+        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--)
+    {
+        const char *p_name = vlc_array_item_at_index(&name, i);
+        demux_t *p_next = demux_NewAdvanced(VLC_OBJECT(p_demux), p_demux->p_input,
+                                            p_demux->psz_access, p_name,
+                                            p_demux->psz_location, p_demux->s,
+                                            p_demux->out, false,
+                                            p_demux, vlc_array_item_at_index(&cfg, i));
+        if(!p_next)
+            goto error;
+
+        vlc_array_append(&module, p_next);
+        p_demux = p_next;
+    }
+
+    vlc_array_clear(&name);
+    vlc_array_clear(&cfg);
+    vlc_array_clear(&module);
+
+    return p_demux;
+ 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--)
+        demux_Delete(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;
+}
diff --git a/src/input/demux.h b/src/input/demux.h
index f841f68..9a5b557 100644
--- a/src/input/demux.h
+++ b/src/input/demux.h
@@ -33,8 +33,10 @@
 /* stream_t *s could be null and then it mean a access+demux in one */
 demux_t *demux_NewAdvanced( vlc_object_t *p_obj, input_thread_t *p_parent_input,
                             const char *psz_access, const char *psz_demux,
-                            const char *psz_path, stream_t *s, es_out_t *out, bool );
-#define demux_NewAdvanced( a, b, c, d, e, f, g, h ) demux_NewAdvanced(VLC_OBJECT(a),b,c,d,e,f,g,h)
+                            const char *psz_path, stream_t *s, es_out_t *out, bool,
+                            demux_t *p_wrapped, config_chain_t *p_cfg );
+#define demux_NewAdvanced( a, b, c, d, e, f, g, h, i, j ) \
+                         demux_NewAdvanced(VLC_OBJECT(a),b,c,d,e,f,g,h,i,j)
 
 demux_t *input_DemuxNew( vlc_object_t *, const char *access, const char *demux,
                          const char *path, es_out_t *out, bool quick,
diff --git a/src/input/input.c b/src/input/input.c
index e8a6f9e..7e9c0bc 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -78,7 +78,8 @@ static void MRLSections( const char *, int *, int *, int *, int *);
 
 static input_source_t *InputSourceNew( input_thread_t *, const char *,
                                        const char *psz_forced_demux,
-                                       bool b_in_can_fail );
+                                       bool b_in_can_fail, bool b_with_filter );
+static void UpdateDemuxer(input_thread_t *, input_source_t *, const char *psz_demux_chain);
 static void InputSourceDestroy( input_source_t * );
 static void InputSourceMeta( input_thread_t *, input_source_t *, vlc_meta_t * );
 #ifdef ENABLE_SOUT
@@ -1088,7 +1089,7 @@ static void LoadSlaves( input_thread_t *p_input )
             continue;
         msg_Dbg( p_input, "adding slave input '%s'", uri );
 
-        input_source_t *p_slave = InputSourceNew( p_input, uri, NULL, false );
+        input_source_t *p_slave = InputSourceNew( p_input, uri, NULL, false, false );
         if( p_slave )
             TAB_APPEND( p_input->p->i_slave, p_input->p->slave, p_slave );
         free( uri );
@@ -1191,6 +1192,7 @@ static int Init( input_thread_t * p_input )
         msg_Dbg( p_input, "Input is a meta file: disabling unneeded options" );
         var_SetString( p_input, "sout", "" );
         var_SetBool( p_input, "sout-all", false );
+        var_SetString( p_input, "demux-filter", "" );
         var_SetString( p_input, "input-slave", "" );
         var_SetInteger( p_input, "input-repeat", 0 );
         var_SetString( p_input, "sub-file", "" );
@@ -1203,6 +1205,10 @@ static int Init( input_thread_t * p_input )
         goto error;
 #endif
 
+    /* the sout may have modified the "demux-filter" */
+    char *psz_fwd_var = var_GetString( p_input->p_libvlc, "demux-filter" );
+    var_SetString( p_input, "demux-filter", psz_fwd_var );
+
     /* Create es out */
     p_input->p->p_es_out = input_EsOutTimeshiftNew( p_input, p_input->p->p_es_out_display, p_input->p->i_rate );
 
@@ -1212,7 +1218,7 @@ static int Init( input_thread_t * p_input )
 
     /* */
     master = InputSourceNew( p_input, p_input->p->p_item->psz_uri, NULL,
-                             false );
+                             false, true );
     if( master == NULL )
         goto error;
     p_input->p->master = master;
@@ -1924,7 +1930,7 @@ static bool Control( input_thread_t *p_input,
             {
                 const char *uri = val.psz_string;
                 input_source_t *slave = InputSourceNew( p_input, uri, NULL,
-                                                        false );
+                                                        false, false );
                 if( slave == NULL )
                 {
                     msg_Warn( p_input, "failed to add %s as slave", uri );
@@ -2145,7 +2151,8 @@ static void UpdateTitleListfromDemux( input_thread_t *p_input )
 static input_source_t *InputSourceNew( input_thread_t *p_input,
                                        const char *psz_mrl,
                                        const char *psz_forced_demux,
-                                       bool b_in_can_fail )
+                                       bool b_in_can_fail,
+                                       bool b_with_filter)
 {
     input_source_t *in = vlc_custom_create( p_input, sizeof( *in ),
                                             "input source" );
@@ -2244,6 +2251,31 @@ static input_source_t *InputSourceNew( input_thread_t *p_input,
         return NULL;
     }
 
+    char *psz_demux_chain = NULL;
+    if (b_with_filter)
+        psz_demux_chain = var_InheritString(p_input, "demux-filter");
+    UpdateDemuxer( p_input, in, psz_demux_chain );
+    if (psz_demux_chain)
+        free(psz_demux_chain);
+
+    if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
+        in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
+
+    return in;
+}
+
+static void UpdateDemuxer(input_thread_t *p_input, input_source_t *in, const char *psz_var_demux_filters)
+{
+    /* add the chain of demux filters */
+    if (psz_var_demux_filters != NULL && psz_var_demux_filters[0])
+    {
+        demux_t *p_filtered_demux = demux_FilterChainNew(in->p_demux, psz_var_demux_filters);
+        if (p_filtered_demux == NULL)
+            msg_Dbg(p_input, "Failed to create demux filter %s", psz_var_demux_filters);
+        else
+            in->p_demux = p_filtered_demux;
+    }
+
     /* Get infos from (access_)demux */
     bool b_can_seek;
     if( demux_Control( in->p_demux, DEMUX_CAN_SEEK, &b_can_seek ) )
@@ -2331,11 +2363,6 @@ static input_source_t *InputSourceNew( input_thread_t *p_input,
 
     if( demux_Control( in->p_demux, DEMUX_GET_FPS, &in->f_fps ) )
         in->f_fps = 0.f;
-
-    if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
-        in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
-
-    return in;
 }
 
 /*****************************************************************************
@@ -2346,7 +2373,17 @@ static void InputSourceDestroy( input_source_t *in )
     int i;
 
     if( in->p_demux )
+    {
+        while (in->p_demux->p_source )
+        {
+            demux_t *p_old = in->p_demux;
+            in->p_demux = p_old->p_source;
+            in->p_demux->s = p_old->s;
+            p_old->s = NULL;
+            demux_Delete( p_old );
+        }
         demux_Delete( in->p_demux );
+    }
 
     if( in->i_title > 0 )
     {
@@ -2831,7 +2868,7 @@ static void input_SubtitleAdd( input_thread_t *p_input,
     var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
 
     input_source_t *sub = InputSourceNew( p_input, url, "subtitle",
-                                          (i_flags & SUB_CANFAIL) );
+                                          (i_flags & SUB_CANFAIL), false );
     if( sub == NULL )
         return;
 
diff --git a/src/input/stream_demux.c b/src/input/stream_demux.c
index 76ca3e3..b06d250 100644
--- a/src/input/stream_demux.c
+++ b/src/input/stream_demux.c
@@ -249,7 +249,7 @@ static void* DStreamThread( void *obj )
 
     /* Create the demuxer */
     p_demux = demux_NewAdvanced( s, s->p_input, "", p_sys->psz_name, "",
-                                 s, p_sys->out, false );
+                                 s, p_sys->out, false, NULL, NULL );
     if( p_demux == NULL )
         return NULL;
 
diff --git a/src/input/var.c b/src/input/var.c
index 0cc1217..080f358 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -505,6 +505,7 @@ void input_ConfigVarInit ( input_thread_t *p_input )
     /* */
     var_Create( p_input, "access", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
     var_Create( p_input, "demux", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+    var_Create( p_input, "demux-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
     var_Create( p_input, "stream-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
 
     /* Meta */
diff --git a/src/libvlc-module.c b/src/libvlc-module.c
index 5c6a6e0..ebd89ba 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -988,6 +988,10 @@ static const char *const ppsz_prefres[] = {
 #define STREAM_FILTER_LONGTEXT N_( \
     "Stream filters are used to modify the stream that is being read. " )
 
+#define DEMUX_FILTER_TEXT N_("Demux filter module")
+#define DEMUX_FILTER_LONGTEXT N_( \
+    "Demux filters are used to modify/control the stream that is being read. " )
+
 #define DEMUX_TEXT N_("Demux module")
 #define DEMUX_LONGTEXT N_( \
     "Demultiplexers are used to separate the \"elementary\" streams " \
@@ -1881,6 +1885,10 @@ vlc_module_begin ()
     add_module_list( "stream-filter", "stream_filter", NULL,
                      STREAM_FILTER_TEXT, STREAM_FILTER_LONGTEXT, false )
 
+    set_subcategory( SUBCAT_INPUT_DEMUX_FILTER )
+    add_module_list( "demux-filter", "demux_filter", NULL,
+                     DEMUX_FILTER_TEXT, DEMUX_FILTER_LONGTEXT, false )
+
 
 /* Stream output options */
     set_category( CAT_SOUT )
diff --git a/src/libvlc.c b/src/libvlc.c
index 30bb985..d06f6dd 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -411,7 +411,7 @@ dbus_out:
 
     /* dynamic variables that may have already been set in the command-line */
     var_Create( p_libvlc, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-
+    var_Create( p_libvlc, "demux-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
 
     /* System specific configuration */
     system_Configure( p_libvlc, i_argc - vlc_optind, ppsz_argv + vlc_optind );
-- 
2.7.0



More information about the vlc-devel mailing list