[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