[vlc-devel] [PATCH 01/10] [RFC] core: add demux-filter objects to intercept & filter demuxer calls
Steve Lhomme
robux4 at videolabs.io
Tue May 31 13:55:38 CEST 2016
This can be used to tweak the results of some Control() calls or delay the
actual Demux() call.
A demuxer filter should call demux_FilterDemuxNext() to call the demux
operation to the next demuxer in line and demux_vaFilterControlNext() to pass
the control calls to the next demuxer in line.
--
replaces https://patches.videolan.org/patch/13521/
--
replaces https://patches.videolan.org/patch/13244/ by making the demux_filter_t
a demux_t with many fields unused
removed the config parameters from the demux-filter API from
https://patches.videolan.org/patch/13144/
---
NEWS | 3 ++
include/vlc_common.h | 1 +
include/vlc_demux.h | 35 ++++++++++++++-
src/input/demux.c | 107 +++++++++++++++++++++++++++++++++++++++++++++
src/input/input.c | 65 +++++++++++++++------------
src/input/input_internal.h | 2 +-
src/input/var.c | 1 +
src/libvlc-module.c | 5 +++
src/playlist/engine.c | 1 +
9 files changed, 190 insertions(+), 30 deletions(-)
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_common.h b/include/vlc_common.h
index f05d9c6..9494649 100644
--- a/include/vlc_common.h
+++ b/include/vlc_common.h
@@ -226,6 +226,7 @@ typedef struct access_sys_t access_sys_t;
typedef struct stream_t stream_t;
typedef struct stream_sys_t stream_sys_t;
typedef struct demux_t demux_t;
+typedef struct demux_t demux_filter_t;
typedef struct demux_sys_t demux_sys_t;
typedef struct es_out_t es_out_t;
typedef struct es_out_id_t es_out_id_t;
diff --git a/include/vlc_demux.h b/include/vlc_demux.h
index f4baeea..1de5acc 100644
--- a/include/vlc_demux.h
+++ b/include/vlc_demux.h
@@ -77,6 +77,7 @@ struct demux_t
/* Weak link to parent input */
input_thread_t *p_input;
+ demux_filter_t *p_next;
};
/* pf_demux return values */
@@ -296,6 +297,13 @@ VLC_API void demux_Delete( demux_t * );
VLC_API int demux_vaControlHelper( stream_t *, int64_t i_start, int64_t i_end,
int64_t i_bitrate, int i_align, int i_query, va_list args );
+VLC_USED static inline demux_t *demux_FilterDemuxer( demux_filter_t *p_filter )
+{
+ while ( p_filter->p_next )
+ p_filter = p_filter->p_next;
+ return (demux_t *) p_filter;
+}
+
VLC_USED static inline int demux_Demux( demux_t *p_demux )
{
if( !p_demux->pf_demux )
@@ -304,6 +312,15 @@ VLC_USED static inline int demux_Demux( demux_t *p_demux )
return p_demux->pf_demux( p_demux );
}
+VLC_USED static inline int demux_FilterDemuxNext( demux_filter_t *p_demux_filter )
+{
+ p_demux_filter = p_demux_filter->p_next;
+ if ( p_demux_filter->p_next != NULL )
+ return p_demux_filter->pf_demux( p_demux_filter );
+ /* last in the chain is the real demuxer */
+ return demux_Demux( p_demux_filter );
+}
+
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, ... )
@@ -312,11 +329,24 @@ static inline int demux_Control( demux_t *p_demux, int i_query, ... )
int i_result;
va_start( args, i_query );
- i_result = demux_vaControl( p_demux, i_query, args );
+ if ( p_demux->p_next != NULL )
+ i_result = p_demux->pf_control( p_demux, i_query, args );
+ else
+ /* last in the chain is the real demuxer */
+ i_result = demux_vaControl( (demux_t*) p_demux, i_query, args );
va_end( args );
return i_result;
}
+VLC_USED static inline int demux_vaFilterControlNext( demux_filter_t *p_demux_filter, int i_query, va_list args )
+{
+ p_demux_filter = p_demux_filter->p_next;
+ if ( p_demux_filter->p_next != NULL )
+ return p_demux_filter->pf_control( p_demux_filter, i_query, args );
+ /* last in the chain is the real demuxer */
+ return demux_vaControl( (demux_t*) p_demux_filter, i_query, args );
+}
+
/*************************************************************************
* Miscellaneous helpers for demuxers
*************************************************************************/
@@ -397,6 +427,9 @@ 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_filter_t *p_demux, const char *psz_name );
+void demux_FilterDelete( demux_filter_t * );
+
/**
* @}
*/
diff --git a/src/input/demux.c b/src/input/demux.c
index 303c0b8..10baebd 100644
--- a/src/input/demux.c
+++ b/src/input/demux.c
@@ -134,6 +134,7 @@ 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->p_sys = NULL;
+ p_demux->p_next = NULL;
p_demux->info.i_update = 0;
p_demux->info.i_title = 0;
p_demux->info.i_seekpoint = 0;
@@ -354,6 +355,20 @@ void demux_Delete( demux_t *p_demux )
stream_Delete( s );
}
+void demux_FilterDelete( demux_filter_t *p_demux )
+{
+ demux_filter_t *p_next = p_demux->p_next;
+
+ if ( p_next == NULL )
+ demux_Delete( (demux_t *) p_demux );
+ else
+ {
+ module_unneed( p_demux, p_demux->p_module );
+ vlc_object_release( p_demux );
+ demux_FilterDelete( p_next );
+ }
+}
+
#define static_control_match(foo) \
static_assert((unsigned) DEMUX_##foo == STREAM_##foo, "Mismatch")
@@ -656,3 +671,95 @@ static bool SkipAPETag( demux_t *p_demux )
return true;
}
+static demux_filter_t *demux_FilterNew( demux_filter_t *p_wrapped, const char *p_name )
+{
+ demux_filter_t *p_demux = vlc_custom_create( VLC_OBJECT( p_wrapped ),
+ sizeof( demux_filter_t ), "demux_filter" );
+ if( unlikely(p_demux == NULL) )
+ return NULL;
+
+ p_demux->pf_demux = NULL;
+ p_demux->pf_control = NULL;
+ p_demux->p_sys = NULL;
+ p_demux->s = NULL;
+ p_demux->psz_access = NULL;
+ p_demux->psz_demux = NULL;
+ p_demux->psz_location = NULL;
+ p_demux->psz_file = NULL;
+ p_demux->p_input = NULL;
+ p_demux->out = NULL;
+ p_demux->p_next = (demux_filter_t *) p_wrapped;
+ p_demux->p_module =
+ module_need( p_demux, "demux_filter", p_name, p_name != NULL );
+
+ if( p_demux->p_module == NULL )
+ goto error;
+
+ return p_demux;
+error:
+ vlc_object_release( p_demux );
+ return NULL;
+}
+
+demux_filter_t *demux_FilterChainNew( demux_filter_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 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_filter_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 d1b9b3e..6c0a8a8 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -555,12 +555,13 @@ static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed )
if( i_ret == VLC_DEMUXER_SUCCESS )
{
- if( p_input->p->master->p_demux->info.i_update )
+ demux_t *p_demux = demux_FilterDemuxer( p_input->p->master->p_demux );
+ if( p_demux->info.i_update )
{
- if( p_input->p->master->p_demux->info.i_update & INPUT_UPDATE_TITLE_LIST )
+ if( p_demux->info.i_update & INPUT_UPDATE_TITLE_LIST )
{
UpdateTitleListfromDemux( p_input );
- p_input->p->master->p_demux->info.i_update &= ~INPUT_UPDATE_TITLE_LIST;
+ p_demux->info.i_update &= ~INPUT_UPDATE_TITLE_LIST;
}
if( p_input->p->master->b_title_demux )
{
@@ -697,7 +698,8 @@ static void MainLoop( input_thread_t *p_input, bool b_interactive )
MainLoopDemux( p_input, &b_force_update );
- if( p_input->p->master->p_demux->pf_demux != NULL )
+ demux_t *p_demux = demux_FilterDemuxer( p_input->p->master->p_demux );
+ if( p_demux->pf_demux != NULL )
i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
if( b_force_update )
i_intf_update = 0;
@@ -1615,9 +1617,7 @@ static void ControlPause( input_thread_t *p_input, mtime_t i_control_date )
if( p_input->p->b_can_pause )
{
- demux_t *p_demux = p_input->p->master->p_demux;
-
- if( demux_Control( p_demux, DEMUX_SET_PAUSE_STATE, true ) )
+ if( demux_Control( p_input->p->master->p_demux, DEMUX_SET_PAUSE_STATE, true ) )
{
msg_Warn( p_input, "cannot set pause state" );
return;
@@ -1640,9 +1640,7 @@ static void ControlUnpause( input_thread_t *p_input, mtime_t i_control_date )
{
if( p_input->p->b_can_pause )
{
- demux_t *p_demux = p_input->p->master->p_demux;
-
- if( demux_Control( p_demux, DEMUX_SET_PAUSE_STATE, false ) )
+ if( demux_Control( p_input->p->master->p_demux, DEMUX_SET_PAUSE_STATE, false ) )
{
msg_Err( p_input, "cannot resume" );
input_ChangeState( p_input, ERROR_S );
@@ -1815,7 +1813,7 @@ static bool Control( input_thread_t *p_input,
if( i_rate != p_input->p->i_rate &&
!p_input->p->b_can_pace_control && p_input->p->b_can_rate_control )
{
- demux_t *p_demux = p_input->p->master->p_demux;
+ demux_t *p_demux = demux_FilterDemuxer( p_input->p->master->p_demux );
int i_ret = VLC_EGENERIC;
if( p_demux->s == NULL )
@@ -1894,7 +1892,8 @@ static bool Control( input_thread_t *p_input,
if( p_input->p->master->i_title <= 0 )
break;
- int i_title = p_input->p->master->p_demux->info.i_title;
+ demux_t *p_demux = demux_FilterDemuxer( p_input->p->master->p_demux );
+ int i_title = p_demux->info.i_title;
if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
i_title--;
else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
@@ -1922,7 +1921,7 @@ static bool Control( input_thread_t *p_input,
if( p_input->p->master->i_title <= 0 )
break;
- demux_t *p_demux = p_input->p->master->p_demux;
+ demux_t *p_demux = demux_FilterDemuxer( p_input->p->master->p_demux );
int i_title = p_demux->info.i_title;
int i_seekpoint = p_demux->info.i_seekpoint;
@@ -2122,7 +2121,7 @@ static int UpdateTitleSeekpoint( input_thread_t *p_input,
*****************************************************************************/
static int UpdateTitleSeekpointFromDemux( input_thread_t *p_input )
{
- demux_t *p_demux = p_input->p->master->p_demux;
+ demux_t *p_demux = demux_FilterDemuxer( p_input->p->master->p_demux );
/* TODO event-like */
if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
@@ -2146,18 +2145,18 @@ static int UpdateTitleSeekpointFromDemux( input_thread_t *p_input )
static void UpdateGenericFromDemux( input_thread_t *p_input )
{
- demux_t *p_demux = p_input->p->master->p_demux;
+ demux_t *p_demux = demux_FilterDemuxer( p_input->p->master->p_demux );
if( p_demux->info.i_update & INPUT_UPDATE_META )
{
- InputUpdateMeta( p_input, p_demux );
+ InputUpdateMeta( p_input, p_input->p->master->p_demux );
p_demux->info.i_update &= ~INPUT_UPDATE_META;
}
{
double quality;
double strength;
- if( !demux_Control( p_demux, DEMUX_GET_SIGNAL, &quality, &strength ) )
+ if( !demux_Control( p_input->p->master->p_demux, DEMUX_GET_SIGNAL, &quality, &strength ) )
input_SendEventSignal( p_input, quality, strength );
}
}
@@ -2292,6 +2291,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_filter_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 ) )
@@ -2302,9 +2310,10 @@ static input_source_t *InputSourceNew( input_thread_t *p_input,
&in->b_can_pace_control ) )
in->b_can_pace_control = false;
- assert( in->p_demux->pf_demux != NULL || !in->b_can_pace_control );
+ demux_t *p_demux = demux_FilterDemuxer( in->p_demux );
+ assert( p_demux->pf_demux != NULL || !in->b_can_pace_control );
- if( in->p_demux->s != NULL )
+ if( p_demux->s != NULL )
{
if( !in->b_can_pace_control )
{
@@ -2366,7 +2375,7 @@ static input_source_t *InputSourceNew( input_thread_t *p_input,
{
vlc_mutex_lock( &p_input->p->p_item->lock );
AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, &p_input->p->attachment_demux,
- i_attachment, attachment, in->p_demux );
+ i_attachment, attachment, p_demux);
vlc_mutex_unlock( &p_input->p->p_item->lock );
}
@@ -2394,7 +2403,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 )
{
@@ -2410,9 +2419,9 @@ static void InputSourceDestroy( input_source_t *in )
* InputSourceMeta:
*****************************************************************************/
static void InputSourceMeta( input_thread_t *p_input,
- input_source_t *p_source, vlc_meta_t *p_meta )
+ input_source_t *p_next, vlc_meta_t *p_meta )
{
- demux_t *p_demux = p_source->p_demux;
+ demux_filter_t *p_demux = p_next->p_demux;
/* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED
* is a bad idea */
@@ -2433,7 +2442,7 @@ static void InputSourceMeta( input_thread_t *p_input,
return;
demux_meta_t *p_demux_meta =
- vlc_custom_create( p_source, sizeof( *p_demux_meta ), "demux meta" );
+ vlc_custom_create( p_next, sizeof( *p_demux_meta ), "demux meta" );
if( unlikely(p_demux_meta == NULL) )
return;
p_demux_meta->p_item = p_input->p->p_item;
@@ -2451,7 +2460,7 @@ static void InputSourceMeta( input_thread_t *p_input,
{
vlc_mutex_lock( &p_input->p->p_item->lock );
AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, &p_input->p->attachment_demux,
- p_demux_meta->i_attachments, p_demux_meta->attachments, p_demux);
+ p_demux_meta->i_attachments, p_demux_meta->attachments, demux_FilterDemuxer( p_demux ));
vlc_mutex_unlock( &p_input->p->p_item->lock );
}
module_unneed( p_demux, p_id3 );
@@ -2602,7 +2611,7 @@ static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_atta
* InputUpdateMeta: merge p_item meta data with p_meta taking care of
* arturl and locking issue.
*****************************************************************************/
-static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux )
+static void InputUpdateMeta( input_thread_t *p_input, demux_filter_t *p_demux )
{
vlc_meta_t *p_meta = vlc_meta_New();
if( unlikely(p_meta == NULL) )
@@ -2624,7 +2633,7 @@ static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux )
int j = 0;
for( int i = 0; i < p_input->p->i_attachment; i++ )
{
- if( p_input->p->attachment_demux[i] == p_demux )
+ if( p_input->p->attachment_demux[i] == demux_FilterDemuxer( p_demux ) )
vlc_input_attachment_Delete( p_input->p->attachment[i] );
else
{
@@ -2636,7 +2645,7 @@ static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux )
p_input->p->i_attachment = j;
}
AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, &p_input->p->attachment_demux,
- i_attachment, attachment, p_demux );
+ i_attachment, attachment, demux_FilterDemuxer( p_demux ) );
vlc_mutex_unlock( &p_input->p->p_item->lock );
}
diff --git a/src/input/input_internal.h b/src/input/input_internal.h
index 9ee10e9..f5227d7 100644
--- a/src/input/input_internal.h
+++ b/src/input/input_internal.h
@@ -42,7 +42,7 @@ typedef struct
{
VLC_COMMON_MEMBERS
- demux_t *p_demux; /**< Demux plugin instance */
+ demux_filter_t *p_demux; /**< Demux plugin instance */
/* Title infos for that input */
bool b_title_demux; /* Titles/Seekpoints provided by demux */
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.windows.1
More information about the vlc-devel
mailing list