[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:27:10 CEST 2016
On Mon, Jun 6, 2016 at 11:24 AM, Steve Lhomme <robux4 at gmail.com> wrote:
> On Mon, Jun 6, 2016 at 11:11 AM, Steve Lhomme <robux4 at gmail.com> wrote:
>> 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.
>
> It seems only dvdnav and dvdread are in this case.
Not even, they use the DEMUX_INIT_COMMON macro like many other
demuxers. So either it's a test for a state during initialization (odd
as we shouldn't use an object until Open() is done) or it's
dead/legacy code.
Anyone understand why these 3 lines ?
>>>> };
>>>>
>>>> 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