[vlc-devel] [PATCH] [RFC] add demux filters that are similar in API to regular demuxers

Steve Lhomme robux4 at gmail.com
Mon Jun 6 11:11:13 CEST 2016


On Sun, Jun 5, 2016 at 2:15 PM, Rémi Denis-Courmont <remi at remlab.net> wrote:
> Le 2016-06-05 13:03, Steve Lhomme a écrit :
>>
>> The only difference is that when control/demux callbacks are called, they
>> are
>> given the next demuxers to call in the chain
>>
>> --
>> replaces https://patches.videolan.org/patch/13585/
>> and https://patches.videolan.org/patch/13615/ with legacy patch remaining
>> I do not understand how some demuxers have pf_demux to NULL, so there
>> might be
>> some simplifications possible.
>> ---
>>  NEWS                  |   3 ++
>>  include/vlc_demux.h   |  12 ++++++
>>  src/input/demux.c     | 106
>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>  src/input/demux.h     |   3 ++
>>  src/input/input.c     |   9 +++++
>>  src/input/var.c       |   1 +
>>  src/libvlc-module.c   |   5 +++
>>  src/playlist/engine.c |   1 +
>>  8 files changed, 140 insertions(+)
>>
>> 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_demux.h b/include/vlc_demux.h
>> index 1153e1c..0c4bfeb 100644
>> --- a/include/vlc_demux.h
>> +++ b/include/vlc_demux.h
>> @@ -77,16 +77,25 @@ struct demux_t
>>
>>      /* Weak link to parent input */
>>      input_thread_t *p_input;
>> +
>> +    /* demux_t filter chaining */
>> +    demux_t        *p_next;
>> +    demux_t        *p_prev;
>
>
> Should not be needed.

For now when a demuxer changes the info values, it calls the previous
demux in line to inform it.
I guess with the demux_InfoXXX() calls they can be chained with a
callback so that we always use the top demuxer and the lower demuxer
doesn't need to know what's before.

>> +    int (*pf_filter_demux)  ( demux_t *p_this, demux_t *p_next );
>
>
> Just use pf_demux. You can always access p_demux->p_next in the function.

The problem is that in some parts of the code we check if the demuxer
has a pf_demux function.

http://git.videolan.org/?p=vlc.git;a=blob;f=include/vlc_demux.h;h=f4baeea8a5e97c26d956f4ea34d52051620cf788;hb=HEAD#l301
http://git.videolan.org/?p=vlc.git;a=blob;f=src/input/input.c;h=d4acfda036fb6c1c196439f2feea4d3c9a539739;hb=HEAD#l706
http://git.videolan.org/?p=vlc.git;a=blob;f=src/input/input.c;h=d4acfda036fb6c1c196439f2feea4d3c9a539739;hb=HEAD#l2355

I do not understand how a demuxer or an access demuxer can not have
this callback. So for now I copy the pf_demux from the lower demuxer
in the demux filters so it's also seen at the top of the demuxer
chain.

>>  };
>>
>>  static inline void demux_InfoAddFlags( demux_t *p_demux, int flags )
>>  {
>>      p_demux->info.i_update |= flags;
>> +    if ( p_demux->p_prev )
>> +        demux_InfoAddFlags( p_demux->p_prev, flags );
>>  }
>
>
> This can cause reentrancy issues.

I'll try to chain the calls and get rid of p_prev.

>>
>>  static inline void demux_InfoDelFlags( demux_t *p_demux, int flags )
>>  {
>>      p_demux->info.i_update &= ~flags;
>> +    if ( p_demux->p_prev )
>> +        demux_InfoDelFlags( p_demux->p_prev, flags );
>>  }
>>
>>
>> @@ -325,6 +334,9 @@ 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_filter_demux)
>> +        return p_demux->pf_filter_demux( p_demux, p_demux->p_next );
>> +
>
>
> Should not be needed.
>
>
>>      if( !p_demux->pf_demux )
>>          return VLC_DEMUXER_SUCCESS;
>>
>> diff --git a/src/input/demux.c b/src/input/demux.c
>> index 303c0b8..6e59c3b 100644
>> --- a/src/input/demux.c
>> +++ b/src/input/demux.c
>> @@ -133,6 +133,9 @@ 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->pf_filter_demux   = NULL;
>> +    p_demux->p_prev     = NULL;
>> +    p_demux->p_next     = NULL;
>>      p_demux->p_sys      = NULL;
>>      p_demux->info.i_update = 0;
>>      p_demux->info.i_title  = 0;
>> @@ -342,6 +345,13 @@ void demux_Delete( demux_t *p_demux )
>>  {
>>      stream_t *s;
>>
>> +    demux_t *p_next = p_demux->p_next;
>> +    if ( p_next != NULL )
>> +    {
>> +        p_next->s = NULL; /* demux fiters don't own the stream */
>> +        demux_Delete( p_next );
>> +    }
>> +
>>      module_unneed( p_demux, p_demux->p_module );
>>      free( p_demux->psz_file );
>>      free( p_demux->psz_location );
>> @@ -656,3 +666,99 @@ static bool SkipAPETag( demux_t *p_demux )
>>      return true;
>>  }
>>
>> +static demux_t *demux_FilterNew( demux_t *p_wrapped, const char *p_name )
>> +{
>> +    demux_t *p_demux = vlc_custom_create( VLC_OBJECT( p_wrapped ),
>> +                                                 sizeof( demux_t ),
>> "demux_filter" );
>> +    if( unlikely(p_demux == NULL) )
>> +        return NULL;
>> +
>> +    p_demux->pf_demux     = p_wrapped->pf_demux; /* forwarded as
>> it's tested for NULL */
>> +    p_demux->pf_control   = p_wrapped->pf_control;
>> +    p_demux->pf_filter_demux   = NULL;
>> +    p_demux->p_sys        = NULL;
>> +    p_demux->s            = p_wrapped->s;
>> +    p_demux->psz_access   = NULL;
>> +    p_demux->psz_demux    = NULL;
>> +    p_demux->psz_location = NULL;
>> +    p_demux->psz_file     = NULL;
>> +    p_demux->p_input      = p_wrapped->p_input;
>> +    p_demux->out          = NULL;
>> +    p_demux->p_module =
>> +        module_need( p_demux, "demux_filter", p_name, p_name != NULL );
>> +
>> +    if( p_demux->p_module == NULL )
>> +        goto error;
>> +
>> +    assert(p_demux->pf_demux == p_wrapped->pf_demux); /* ensure the
>> NULL test is kept */
>> +    p_wrapped->p_prev = p_demux;
>> +    p_demux->p_next = p_wrapped;
>> +
>> +    return p_demux;
>> +error:
>> +    vlc_object_release( p_demux );
>> +    return NULL;
>> +}
>> +
>> +demux_t *demux_FilterChainNew( demux_t *p_demux, const char *psz_chain )
>> +{
>> +    if( !psz_chain || !*psz_chain )
>> +        return NULL; /* add permanent filters */
>> +
>> +    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_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/demux.h b/src/input/demux.h
>> index f841f68..24be9b2 100644
>> --- a/src/input/demux.h
>> +++ b/src/input/demux.h
>> @@ -39,4 +39,7 @@ demux_t *demux_NewAdvanced( vlc_object_t *p_obj,
>> input_thread_t *p_parent_input,
>>  demux_t *input_DemuxNew( vlc_object_t *, const char *access, const
>> char *demux,
>>                           const char *path, es_out_t *out, bool quick,
>>                           input_thread_t * );
>> +
>> +demux_t *demux_FilterChainNew( demux_t *p_demux, const char *psz_name );
>> +
>>  #endif
>> diff --git a/src/input/input.c b/src/input/input.c
>> index 5af8256..2169ede 100644
>> --- a/src/input/input.c
>> +++ b/src/input/input.c
>> @@ -2334,6 +2334,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_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 ) )
>> 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 );
>
>
> --
> 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