[vlc-devel] [PATCH 2/2] [RFC] add demux filters that are similar in API to regular demuxers

Steve Lhomme robux4 at videolabs.io
Sat Jun 4 19:00:26 CEST 2016


The only difference is that when control/demux callbacks are called, they are
given the next demuxers to call in the chain
---
 NEWS                  |   3 ++
 include/vlc_demux.h   |  12 ++++++
 src/input/demux.c     | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/input/input.c     |  11 ++++-
 src/input/var.c       |   1 +
 src/libvlc-module.c   |   5 +++
 src/playlist/engine.c |   1 +
 7 files changed, 145 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index fd5e690..b6eeb06 100644
--- a/NEWS
+++ b/NEWS
@@ -101,6 +101,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 demuxer filter chain to filter or intercept control commands and demuxing
 
 Audio output:
  * Complete rewrite of the AudioTrack Android module. This is now the default.
diff --git a/include/vlc_demux.h b/include/vlc_demux.h
index 1153e1c..cb17cc9 100644
--- a/include/vlc_demux.h
+++ b/include/vlc_demux.h
@@ -77,16 +77,25 @@ struct demux_t
 
     /* Weak link to parent input */
     input_thread_t *p_input;
+
+    /* demux_t filter chaining */
+    demux_t        *p_prev;
+    int (*pf_filter_demux)  ( demux_t *p_this, demux_t *p_next );
+    int (*pf_filter_control)( demux_t *p_this, demux_t *p_next, int i_query, va_list args );
 };
 
 static inline void demux_InfoAddFlags( demux_t *p_demux, int flags )
 {
     p_demux->info.i_update |= flags;
+    if ( p_demux->p_prev )
+        demux_InfoAddFlags( p_demux->p_prev, flags );
 }
 
 static inline void demux_InfoDelFlags( demux_t *p_demux, int flags )
 {
     p_demux->info.i_update &= ~flags;
+    if ( p_demux->p_prev )
+        demux_InfoDelFlags( p_demux->p_prev, flags );
 }
 
 
@@ -422,6 +431,9 @@ VLC_API void demux_PacketizerDestroy( decoder_t *p_packetizer );
     if( !p_demux->p_sys ) return VLC_ENOMEM;\
     } while(0)
 
+demux_t *demux_FilterChainNew( demux_t *p_demux, const char *psz_name );
+void demux_FilterDelete( demux_t * );
+
 /**
  * @}
  */
diff --git a/src/input/demux.c b/src/input/demux.c
index 303c0b8..31393ae 100644
--- a/src/input/demux.c
+++ b/src/input/demux.c
@@ -133,6 +133,9 @@ demux_t *demux_NewAdvanced( vlc_object_t *p_obj, input_thread_t *p_parent_input,
 
     p_demux->pf_demux   = NULL;
     p_demux->pf_control = NULL;
+    p_demux->pf_filter_demux   = NULL;
+    p_demux->pf_filter_control = NULL;
+    p_demux->p_prev     = NULL;
     p_demux->p_sys      = NULL;
     p_demux->info.i_update = 0;
     p_demux->info.i_title  = 0;
@@ -354,6 +357,20 @@ void demux_Delete( demux_t *p_demux )
         stream_Delete( s );
 }
 
+void demux_FilterDelete( demux_t *p_demux )
+{
+    demux_t *p_prev = p_demux->p_prev;
+    if ( p_demux->p_module )
+    {
+        module_unneed( p_demux, p_demux->p_module );
+        vlc_object_release( p_demux );
+        demux_Delete( p_demux );
+    }
+
+    if ( p_prev != NULL )
+        demux_FilterDelete( p_demux );
+}
+
 #define static_control_match(foo) \
     static_assert((unsigned) DEMUX_##foo == STREAM_##foo, "Mismatch")
 
@@ -656,3 +673,99 @@ static bool SkipAPETag( demux_t *p_demux )
     return true;
 }
 
+static demux_t *demux_FilterNew( demux_t *p_wrapped, const char *p_name )
+{
+    demux_t *p_demux = vlc_custom_create( VLC_OBJECT( p_wrapped ),
+                                                 sizeof( demux_t ), "demux_filter" );
+    if( unlikely(p_demux == NULL) )
+        return NULL;
+
+    p_demux->pf_demux     = p_wrapped->pf_demux;
+    p_demux->pf_control   = p_wrapped->pf_control;
+    p_demux->pf_filter_demux   = NULL;
+    p_demux->pf_filter_control = NULL;
+    p_demux->p_sys        = NULL;
+    p_demux->s            = p_wrapped->s;
+    p_demux->psz_access   = NULL;
+    p_demux->psz_demux    = NULL;
+    p_demux->psz_location = NULL;
+    p_demux->psz_file     = NULL;
+    p_demux->p_input      = p_wrapped->p_input;
+    p_demux->out          = NULL;
+    p_wrapped->p_prev     = p_demux;
+    p_demux->p_module =
+        module_need( p_demux, "demux_filter", p_name, p_name != NULL );
+
+    if( p_demux->p_module == NULL )
+        goto error;
+
+    assert(p_demux->pf_demux == p_wrapped->pf_demux &&  p_demux->pf_control == p_wrapped->pf_control);
+
+    return p_demux;
+error:
+    vlc_object_release( p_demux );
+    return NULL;
+}
+
+demux_t *demux_FilterChainNew( demux_t *p_demux, const char *psz_chain )
+{
+    if( !psz_chain || !*psz_chain )
+        return demux_FilterNew( p_demux, NULL ); /* add permanent filters */
+
+    char *psz_parser = strdup(psz_chain);
+    if(!psz_parser)
+        return NULL;
+
+    vlc_array_t name;
+    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(&name, psz_name);
+        config_ChainDestroy(p_cfg);
+    }
+
+    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_FilterNew( p_demux, p_name );
+        if(!p_next)
+            goto error;
+
+        vlc_array_append(&module, p_next);
+        p_demux = p_next;
+    }
+
+    vlc_array_clear(&name);
+    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));
+    }
+    vlc_array_clear(&name);
+
+    return NULL;
+}
diff --git a/src/input/input.c b/src/input/input.c
index 5af8256..b780d97 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -2334,6 +2334,15 @@ static input_source_t *InputSourceNew( input_thread_t *p_input,
         return NULL;
     }
 
+    char *psz_demux_chain = var_GetNonEmptyString(p_input, "demux-filter");
+    /* add the chain of demux filters */
+    demux_t *p_filtered_demux = demux_FilterChainNew( in->p_demux, psz_demux_chain );
+    if ( p_filtered_demux != NULL )
+        in->p_demux = p_filtered_demux;
+    else if ( psz_demux_chain != NULL )
+        msg_Dbg(p_input, "Failed to create demux filter %s", psz_demux_chain);
+    free( psz_demux_chain );
+
     /* Get infos from (access_)demux */
     bool b_can_seek;
     if( demux_Control( in->p_demux, DEMUX_CAN_SEEK, &b_can_seek ) )
@@ -2436,7 +2445,7 @@ static void InputSourceDestroy( input_source_t *in )
     int i;
 
     if( in->p_demux )
-        demux_Delete( in->p_demux );
+        demux_FilterDelete( in->p_demux );
 
     if( in->i_title > 0 )
     {
diff --git a/src/input/var.c b/src/input/var.c
index 6534603..437c614 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -513,6 +513,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 74fc7e5..5e7be1d 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -980,6 +980,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 " \
@@ -1868,6 +1872,7 @@ vlc_module_begin ()
     add_module_list( "stream-filter", "stream_filter", NULL,
                      STREAM_FILTER_TEXT, STREAM_FILTER_LONGTEXT, false )
 
+    add_string( "demux-filter", NULL, DEMUX_FILTER_TEXT, DEMUX_FILTER_LONGTEXT, true )
 
 /* Stream output options */
     set_category( CAT_SOUT )
diff --git a/src/playlist/engine.c b/src/playlist/engine.c
index 9f3abf0..1ff64c7 100644
--- a/src/playlist/engine.c
+++ b/src/playlist/engine.c
@@ -472,6 +472,7 @@ static void VariablesInit( playlist_t *p_playlist )
 
     /* sout variables */
     var_Create( p_playlist, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+    var_Create( p_playlist, "demux-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
 
     /* */
     var_Create( p_playlist, "album-art", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-- 
2.7.0



More information about the vlc-devel mailing list