[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