[vlc-devel] [PATCH 02/11] [RFC] core: add demux-filter objects to intercept & filter demuxer calls

Steve Lhomme robux4 at videolabs.io
Mon May 2 18:24:01 CEST 2016


This can be used to tweak the results of some Control() calls or delay the
actual Demux() call.
---
 NEWS                 |  3 ++
 include/vlc_common.h |  2 ++
 include/vlc_demux.h  | 47 ++++++++++++++++++++++++-
 src/input/demux.c    | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/input/input.c    | 16 +++++++++
 src/input/var.c      |  1 +
 src/libvlc-module.c  |  5 +++
 src/libvlc.c         |  2 ++
 8 files changed, 171 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index dd37984..9da578c 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 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_common.h b/include/vlc_common.h
index f05d9c6..f61eb4e 100644
--- a/include/vlc_common.h
+++ b/include/vlc_common.h
@@ -227,6 +227,8 @@ typedef struct stream_t     stream_t;
 typedef struct stream_sys_t stream_sys_t;
 typedef struct demux_t  demux_t;
 typedef struct demux_sys_t demux_sys_t;
+typedef struct demux_filter_t  demux_filter_t;
+typedef struct demux_filter_sys_t demux_filter_sys_t;
 typedef struct es_out_t     es_out_t;
 typedef struct es_out_id_t  es_out_id_t;
 typedef struct es_out_sys_t es_out_sys_t;
diff --git a/include/vlc_demux.h b/include/vlc_demux.h
index 45f5416..2d0ecf3 100644
--- a/include/vlc_demux.h
+++ b/include/vlc_demux.h
@@ -74,11 +74,31 @@ struct demux_t
         int          i_seekpoint;   /* idem, start from 0 */
     } info;
     demux_sys_t *p_sys;
+    demux_filter_t *p_filters; /* chained list of demux-filters           */
 
     /* Weak link to parent input */
     input_thread_t *p_input;
 };
 
+struct demux_filter_t
+{
+    VLC_COMMON_MEMBERS
+
+    /* Module properties */
+    module_t    *p_module;
+
+    /* return true if the demux should return the returned code */
+    int (*pf_demux)  ( demux_filter_t * );
+    int (*pf_control)( demux_filter_t *, int i_query, va_list args);
+
+    demux_t            *p_demux;
+    demux_filter_sys_t *p_sys;
+
+    const config_chain_t *p_cfg;
+
+    struct demux_filter_t *p_next;
+};
+
 /* pf_demux return values */
 #define VLC_DEMUXER_EOF       0
 #define VLC_DEMUXER_EGENERIC -1
@@ -296,12 +316,25 @@ VLC_API int demux_vaControlHelper( stream_t *, int64_t i_start, int64_t i_end,
 
 VLC_USED static inline int demux_Demux( demux_t *p_demux )
 {
-    if( !p_demux->pf_demux )
+    if( !p_demux->pf_demux && !p_demux->p_filters )
         return 1;
 
+    if ( p_demux->p_filters != NULL )
+        return p_demux->p_filters->pf_demux( p_demux->p_filters );
+
     return p_demux->pf_demux( p_demux );
 }
 
+VLC_USED static inline int demux_FilterDemux( demux_filter_t *p_demux_filter )
+{
+    if ( p_demux_filter->p_next )
+        return p_demux_filter->p_next->pf_demux( p_demux_filter->p_next );
+
+    if ( p_demux_filter->p_demux )
+        return p_demux_filter->p_demux->pf_demux( p_demux_filter->p_demux );
+    return 1;
+}
+
 VLC_API int demux_vaControl( demux_t *p_demux, int i_query, va_list args );
 
 static inline int demux_Control( demux_t *p_demux, int i_query, ... )
@@ -315,6 +348,16 @@ static inline int demux_Control( demux_t *p_demux, int i_query, ... )
     return i_result;
 }
 
+VLC_USED static inline int demux_FilterControl( demux_filter_t *p_demux_filter, int i_query, va_list args )
+{
+    if ( p_demux_filter->p_next )
+        return p_demux_filter->p_next->pf_control( p_demux_filter->p_next, i_query, args );
+
+    if ( p_demux_filter->p_demux )
+        return p_demux_filter->p_demux->pf_control( p_demux_filter->p_demux, i_query, args );
+    return 1;
+}
+
 /*************************************************************************
  * Miscellaneous helpers for demuxers
  *************************************************************************/
@@ -395,6 +438,8 @@ VLC_API void demux_PacketizerDestroy( decoder_t *p_packetizer );
     if( !p_demux->p_sys ) return VLC_ENOMEM;\
     } while(0)
 
+demux_filter_t *demux_FilterChainNew( demux_t *p_demux, const char *psz_name );
+
 /**
  * @}
  */
diff --git a/src/input/demux.c b/src/input/demux.c
index 303c0b8..67a8646 100644
--- a/src/input/demux.c
+++ b/src/input/demux.c
@@ -363,7 +363,10 @@ static int demux_ControlInternal( demux_t *demux, int query, ... )
     va_list ap;
 
     va_start( ap, query );
-    ret = demux->pf_control( demux, query, ap );
+    if ( demux->p_filters )
+        ret = demux->p_filters->pf_control( demux->p_filters, query, ap );
+    else
+        ret = demux->pf_control( demux, query, ap );
     va_end( ap );
     return ret;
 }
@@ -382,7 +385,10 @@ int demux_vaControl( demux_t *demux, int query, va_list args )
                 va_list ap;
 
                 va_copy( ap, args );
-                ret = demux->pf_control( demux, query, args );
+                if ( demux->p_filters )
+                    ret = demux->p_filters->pf_control( demux->p_filters, query, args );
+                else
+                    ret = demux->pf_control( demux, query, args );
                 if( ret != VLC_SUCCESS )
                     ret = stream_vaControl( demux->s, query, ap );
                 va_end( ap );
@@ -416,6 +422,8 @@ int demux_vaControl( demux_t *demux, int query, va_list args )
             }
         }
 
+    if ( demux->p_filters )
+        return demux->p_filters->pf_control( demux->p_filters, query, args );
     return demux->pf_control( demux, query, args );
 }
 
@@ -656,3 +664,89 @@ static bool SkipAPETag( demux_t *p_demux )
     return true;
 }
 
+static demux_filter_t *demux_FilterNew( demux_t *p_demux, const char *p_name,
+                                        const config_chain_t *p_cfg )
+{
+    demux_filter_t *p_filter = vlc_custom_create( VLC_OBJECT(p_demux), sizeof( *p_filter ), "demux_filter" );
+    if( unlikely(p_filter == NULL) )
+        return NULL;
+
+    p_filter->p_demux = p_demux;
+    p_filter->p_cfg = p_cfg;
+    p_filter->p_module = module_need( p_filter, "demux_filter", p_name, true);
+    if( p_filter->p_module == NULL )
+        goto error;
+
+    return p_filter;
+
+error:
+    vlc_object_release( p_filter );
+    return NULL;
+}
+
+demux_filter_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);
+    }
+
+    demux_filter_t *p_prev = NULL;
+    demux_filter_t *p_next = NULL;
+    int i = vlc_array_count(&name);
+    while (i--)
+    {
+        const char *p_name = vlc_array_item_at_index(&name, i);
+        p_next = demux_FilterNew( p_demux, p_name, vlc_array_item_at_index(&cfg, i) );
+        if ( p_next == NULL )
+            goto error;
+
+        p_next->p_next = p_prev;
+        p_prev = p_next;
+    }
+
+    vlc_array_clear(&name);
+    vlc_array_clear(&cfg);
+
+    return p_next;
+ error:
+    i++;    /* last module couldn't be created */
+
+    /* destroy all modules created  */
+    while(p_prev)
+    {
+        p_next = p_prev->p_next;
+        vlc_object_release( p_prev );
+    }
+
+    /* 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/input.c b/src/input/input.c
index 5591a4e..604fc2b 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -2193,6 +2193,14 @@ 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_filter_t *p_filtered_demux = demux_FilterChainNew( in->p_demux, psz_demux_chain );
+    in->p_demux->p_filters = p_filtered_demux;
+    if ( p_filtered_demux == NULL && psz_demux_chain != NULL)
+        msg_Dbg( p_input, "Failed to create demux filter chain %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 ) )
@@ -2295,7 +2303,15 @@ static void InputSourceDestroy( input_source_t *in )
     int i;
 
     if( in->p_demux )
+    {
+        while (in->p_demux->p_filters )
+        {
+            demux_filter_t *p_old = in->p_demux->p_filters;
+            in->p_demux->p_filters = p_old->p_next;
+            vlc_object_release( p_old );
+        }
         demux_Delete( in->p_demux );
+    }
 
     if( in->i_title > 0 )
     {
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 d529c32..4c9c462 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -985,6 +985,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 " \
@@ -1876,6 +1880,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/libvlc.c b/src/libvlc.c
index 4e33a04..ccc62ca 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -409,6 +409,8 @@ dbus_out:
     var_Create( p_libvlc, "app-version", VLC_VAR_STRING );
     var_SetString( p_libvlc, "app-version", PACKAGE_VERSION );
 
+    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