[vlc-devel] [PATCH 1/2] [RFC] core: add a demux-filter similar to stream-filter for demuxers
Steve Lhomme
robux4 at gmail.com
Sat Apr 23 15:21:24 CEST 2016
On Sat, Apr 23, 2016 at 11:27 AM, Rémi Denis-Courmont <remi at remlab.net> wrote:
> On Friday 22 April 2016 17:57:20 Steve Lhomme wrote:
>> 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
>
>> 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;
>
> union with s.
>
>> + config_chain_t *p_cfg;
>
> This is pointless. A demux can´t spawn a chain.
>
> Also I don´t get how the filter is supposed to pass on ES output requests, and
> direct accesses from access/stream/demux to p_input.
That's "reserved" to the master demuxer. It's at the end of the demuxer chain.
I'm not sure we can restrict what a demuxer filter can/cannot do
directly in the code. But that would be a nice addition.
>> };
>>
>> /* 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 );
>> 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 );
>
> That´s bizarre.
>
>> 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", "" );
>
> I don´t really see the point in a demux filter if it can´t modify anything.
I don't know about other cases where it would make sense but in my
case I hack the GET/SET_TIME/POSITION calls to match/tell the
Chromecast time/position. And because of the communication between the
Chromecast sout and this demuxer that has access to the input, I can
get the title/artwork and send that to the Chromecast to tell what's
playing.
>> 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" */
>
> Hell no.
Should the "sout" AND the "demux-filter" be set/unset by the renderer
API at once then ? That would be fine with me. The only problem is how
can the instances created talk to each other or find each other.
>> + 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)
>
> I don´t see why there should be a flag here.
InputSourceNew() is used by slaves. I don't think a demux-filter
should apply on such input or maybe we need categories of filters.
That seems over-engineered for what we need at the moment.
>> {
>> 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
>> );
>
> --
> Rémi Denis-Courmont
> http://www.remlab.net/
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list