[vlc-devel] [PATCH 03/14] filters: separate the filter owners by type
Steve Lhomme
robux4 at ycbcr.xyz
Fri Jul 26 08:28:13 CEST 2019
On 2019-07-25 18:59, Rémi Denis-Courmont wrote:
> Le torstaina 25. heinäkuuta 2019, 13.34.02 EEST Steve Lhomme a écrit :
>> video, spu and audio have different owners with different callbacks.
>> ---
>> include/vlc_filter.h | 34 +++++++++++++++++++---------
>> modules/hw/d3d11/d3d11_surface.c | 6 ++---
>> modules/hw/d3d9/dxa9.c | 6 ++---
>> modules/stream_out/mosaic_bridge.c | 4 ++--
>> modules/stream_out/sdi/SDIStream.cpp | 2 +-
>> modules/stream_out/transcode/video.c | 2 +-
>> modules/video_chroma/chain.c | 4 ++--
>> modules/video_filter/canvas.c | 4 ++--
>> modules/video_filter/edgedetection.c | 4 ++--
>> src/audio_output/filters.c | 4 ++--
>> src/misc/filter_chain.c | 24 ++++++++++----------
>> src/misc/image.c | 2 +-
>> src/video_output/display.c | 4 ++--
>> src/video_output/video_output.c | 8 +++----
>> src/video_output/vout_subpictures.c | 16 ++++++-------
>> 15 files changed, 68 insertions(+), 56 deletions(-)
>>
>> diff --git a/include/vlc_filter.h b/include/vlc_filter.h
>> index 0c756ce10e..95b9db1ce0 100644
>> --- a/include/vlc_filter.h
>> +++ b/include/vlc_filter.h
>> @@ -46,15 +46,22 @@ struct filter_subpicture_callbacks
>> subpicture_t *(*buffer_new)(filter_t *);
>> };
>>
>> -typedef struct filter_owner_t
>> +typedef struct video_filter_owner_t
>> {
>> - union
>> - {
>> - const struct filter_video_callbacks *video;
>> - const struct filter_subpicture_callbacks *sub;
>> - };
>> + const struct filter_video_callbacks *video;
>> + void *sys;
>> +} video_filter_owner_t;
>> +
>> +typedef struct spu_filter_owner_t
>> +{
>> + const struct filter_subpicture_callbacks *sub;
>
> I don't really care about the nesting order of struct vs union. Until/unless
> you split filter_t completely, it won't make much difference.
I thought about it. That's something we should consider but I'm not
entirely sure of the side effects.
At least the whole union now made me thing you could create a filter
that outputs audio from video or vice versa. This is not handled.
> However:
> 1) The name becomes rather weird/unusual.
> 2) The anonymous union becomes pointless. You could just call it owner to the
> same effect.
I think we should first settle what's an "owner". There are 2
conflicting use of this name in the code. I'd rather not add to the
confusion.
> So you'd rather get filter->owner.sub.ops->func
>
>
>> void *sys;
>> -} filter_owner_t;
>> +} spu_filter_owner_t;
>> +
>> +typedef struct audio_filter_owner_t
>> +{
>> + void *sys;
>> +} audio_filter_owner_t;
>>
>> struct vlc_mouse_t;
>>
>> @@ -146,7 +153,12 @@ struct filter_t
>> int (*pf_get_attachments)( filter_t *, input_attachment_t ***, int * );
>>
>> /** Private structure for the owner of the filter */
>> - filter_owner_t owner;
>> + union
>> + {
>> + video_filter_owner_t video_owner;
>> + spu_filter_owner_t spu_owner;
>> + audio_filter_owner_t audio_owner;
>> + };
>> };
>>
>> /**
>> @@ -160,7 +172,7 @@ struct filter_t
>> */
>> static inline picture_t *filter_NewPicture( filter_t *p_filter )
>> {
>> - picture_t *pic = p_filter->owner.video->buffer_new( p_filter );
>> + picture_t *pic = p_filter->video_owner.video->buffer_new( p_filter );
>> if( pic == NULL )
>> msg_Warn( p_filter, "can't get output picture" );
>> return pic;
>> @@ -206,7 +218,7 @@ static inline block_t *filter_DrainAudio( filter_t
>> *p_filter ) */
>> static inline subpicture_t *filter_NewSubpicture( filter_t *p_filter )
>> {
>> - subpicture_t *subpic = p_filter->owner.sub->buffer_new( p_filter );
>> + subpicture_t *subpic = p_filter->spu_owner.sub->buffer_new( p_filter );
>> if( subpic == NULL )
>> msg_Warn( p_filter, "can't get output subpicture" );
>> return subpic;
>> @@ -324,7 +336,7 @@ VLC_USED;
>> * \return new filter chain, or NULL on error
>> */
>> VLC_API filter_chain_t * filter_chain_NewVideo( vlc_object_t *obj, bool
>> change, - const
>> filter_owner_t *owner ) +
>> const video_filter_owner_t *owner ) VLC_USED;
>> #define filter_chain_NewVideo( a, b, c ) \
>> filter_chain_NewVideo( VLC_OBJECT( a ), b, c )
>> diff --git a/modules/hw/d3d11/d3d11_surface.c
>> b/modules/hw/d3d11/d3d11_surface.c index a1d9cbc10f..18382f0959 100644
>> --- a/modules/hw/d3d11/d3d11_surface.c
>> +++ b/modules/hw/d3d11/d3d11_surface.c
>> @@ -517,7 +517,7 @@ static void DeleteFilter( filter_t * p_filter )
>>
>> static picture_t *NewBuffer(filter_t *p_filter)
>> {
>> - filter_t *p_parent = p_filter->owner.sys;
>> + filter_t *p_parent = p_filter->video_owner.sys;
>> filter_sys_t *p_sys = p_parent->p_sys;
>> return p_sys->staging_pic;
>> }
>> @@ -533,8 +533,8 @@ static filter_t *CreateCPUtoGPUFilter( vlc_object_t
>> *p_this, const es_format_t *
>>
>> static const struct filter_video_callbacks cbs = { NewBuffer };
>> p_filter->b_allow_fmt_out_change = false;
>> - p_filter->owner.video = &cbs;
>> - p_filter->owner.sys = p_this;
>> + p_filter->video_owner.video = &cbs;
>> + p_filter->video_owner.sys = p_this;
>>
>> es_format_InitFromVideo( &p_filter->fmt_in, &p_fmt_in->video );
>> es_format_InitFromVideo( &p_filter->fmt_out, &p_fmt_in->video );
>> diff --git a/modules/hw/d3d9/dxa9.c b/modules/hw/d3d9/dxa9.c
>> index d1a34645e2..94302d7d07 100644
>> --- a/modules/hw/d3d9/dxa9.c
>> +++ b/modules/hw/d3d9/dxa9.c
>> @@ -192,7 +192,7 @@ static void DeleteFilter( filter_t * p_filter )
>>
>> static picture_t *NewBuffer(filter_t *p_filter)
>> {
>> - filter_t *p_parent = p_filter->owner.sys;
>> + filter_t *p_parent = p_filter->video_owner.sys;
>> filter_sys_t *p_sys = p_parent->p_sys;
>> return p_sys->staging;
>> }
>> @@ -208,8 +208,8 @@ static filter_t *CreateFilter( vlc_object_t *p_this,
>> const es_format_t *p_fmt_in
>>
>> static const struct filter_video_callbacks cbs = { NewBuffer };
>> p_filter->b_allow_fmt_out_change = false;
>> - p_filter->owner.video = &cbs;
>> - p_filter->owner.sys = p_this;
>> + p_filter->video_owner.video = &cbs;
>> + p_filter->video_owner.sys = p_this;
>>
>> es_format_InitFromVideo( &p_filter->fmt_in, &p_fmt_in->video );
>> es_format_InitFromVideo( &p_filter->fmt_out, &p_fmt_in->video );
>> diff --git a/modules/stream_out/mosaic_bridge.c
>> b/modules/stream_out/mosaic_bridge.c index 4f9210ed61..88e3f2182f 100644
>> --- a/modules/stream_out/mosaic_bridge.c
>> +++ b/modules/stream_out/mosaic_bridge.c
>> @@ -389,7 +389,7 @@ static void *Add( sout_stream_t *p_stream, const
>> es_format_t *p_fmt ) msg_Dbg( p_stream, "psz_chain: %s", psz_chain );
>> if( psz_chain )
>> {
>> - filter_owner_t owner = {
>> + video_filter_owner_t owner = {
>> .video = &cbs,
>> .sys = p_owner,
>> };
>> @@ -579,7 +579,7 @@ inline static int video_update_format_decoder( decoder_t
>> *p_dec )
>>
>> inline static picture_t *video_new_buffer_filter( filter_t *p_filter )
>> {
>> - struct decoder_owner *p_owner = p_filter->owner.sys;
>> + struct decoder_owner *p_owner = p_filter->video_owner.sys;
>> video_update_format( &p_owner->video, &p_filter->fmt_out );
>> return picture_NewFromFormat( &p_filter->fmt_out.video );
>> }
>> diff --git a/modules/stream_out/sdi/SDIStream.cpp
>> b/modules/stream_out/sdi/SDIStream.cpp index 25c5aa8d0e..3401f8e6bb 100644
>> --- a/modules/stream_out/sdi/SDIStream.cpp
>> +++ b/modules/stream_out/sdi/SDIStream.cpp
>> @@ -508,7 +508,7 @@ static const struct filter_video_callbacks
>> transcode_filter_video_cbs = filter_chain_t *
>> VideoDecodedStream::VideoFilterCreate(const es_format_t *p_srcfmt) {
>> filter_chain_t *p_chain;
>> - filter_owner_t owner;
>> + video_filter_owner_t owner;
>> memset(&owner, 0, sizeof(owner));
>> owner.video = &transcode_filter_video_cbs;
>>
>> diff --git a/modules/stream_out/transcode/video.c
>> b/modules/stream_out/transcode/video.c index 4cb139c9b5..cd747ab073 100644
>> --- a/modules/stream_out/transcode/video.c
>> +++ b/modules/stream_out/transcode/video.c
>> @@ -227,7 +227,7 @@ static void transcode_video_filter_init( sout_stream_t
>> *p_stream, const es_format_t *p_dst = transcode_encoder_format_in(
>> id->encoder );
>>
>> /* Build chain */
>> - filter_owner_t owner = {
>> + video_filter_owner_t owner = {
>> .video = &transcode_filter_video_cbs,
>> .sys = id,
>> };
>> diff --git a/modules/video_chroma/chain.c b/modules/video_chroma/chain.c
>> index 4be4bc8e1e..ec6ea9c104 100644
>> --- a/modules/video_chroma/chain.c
>> +++ b/modules/video_chroma/chain.c
>> @@ -132,7 +132,7 @@ static int RestartFilterCallback( vlc_object_t *obj,
>> char const *psz_name,
>> ***************************************************************************
>> **/ static picture_t *BufferChainNew( filter_t *p_filter )
>> {
>> - filter_t *p_chain_parent = p_filter->owner.sys;
>> + filter_t *p_chain_parent = p_filter->video_owner.sys;
>> // the last filter of the internal chain gets its pictures from the
>> original // filter source
>> return filter_NewPicture( p_chain_parent );
>> @@ -159,7 +159,7 @@ static int Activate( filter_t *p_filter, int
>> (*pf_build)(filter_t *) ) if( !p_sys )
>> return VLC_ENOMEM;
>>
>> - filter_owner_t owner = {
>> + video_filter_owner_t owner = {
>> .video = &filter_video_chain_cbs,
>> .sys = p_filter,
>> };
>> diff --git a/modules/video_filter/canvas.c b/modules/video_filter/canvas.c
>> index 3e834c017c..fff622beeb 100644
>> --- a/modules/video_filter/canvas.c
>> +++ b/modules/video_filter/canvas.c
>> @@ -133,7 +133,7 @@ typedef struct
>>
>> static picture_t *video_chain_new( filter_t *p_filter )
>> {
>> - filter_t *p_chain_parent = p_filter->owner.sys;
>> + filter_t *p_chain_parent = p_filter->video_owner.sys;
>> // the last filter of the internal chain gets its pictures from the
>> original // filter source
>> return filter_NewPicture( p_chain_parent );
>> @@ -238,7 +238,7 @@ static int Activate( vlc_object_t *p_this )
>> return VLC_ENOMEM;
>> p_filter->p_sys = p_sys;
>>
>> - filter_owner_t owner = {
>> + video_filter_owner_t owner = {
>> .video = &canvas_cbs,
>> .sys = p_filter,
>> };
>> diff --git a/modules/video_filter/edgedetection.c
>> b/modules/video_filter/edgedetection.c index e9ed9c7380..d7ce05a830 100644
>> --- a/modules/video_filter/edgedetection.c
>> +++ b/modules/video_filter/edgedetection.c
>> @@ -93,7 +93,7 @@ static int Open( vlc_object_t *p_this )
>> {
>> int i_ret;
>> filter_t *p_filter = (filter_t *)p_this;
>> - filter_owner_t owner = {
>> + video_filter_owner_t owner = {
>> .video = &filter_video_edge_cbs,
>> .sys = p_filter,
>> };
>> @@ -142,7 +142,7 @@ static void Close( vlc_object_t *p_this )
>>
>> ***************************************************************************
>> ***/ static picture_t *new_frame( filter_t *p_filter )
>> {
>> - filter_t *p_this = p_filter->owner.sys;
>> + filter_t *p_this = p_filter->video_owner.sys;
>> // the last filter of the internal chain gets its pictures from the
>> original // filter source
>> return filter_NewPicture( p_this );
>> diff --git a/src/audio_output/filters.c b/src/audio_output/filters.c
>> index 6a37c8e8ab..56ed8d2c95 100644
>> --- a/src/audio_output/filters.c
>> +++ b/src/audio_output/filters.c
>> @@ -50,7 +50,7 @@ static filter_t *CreateFilter(vlc_object_t *obj,
>> vlc_clock_t *clock, if (unlikely(filter == NULL))
>> return NULL;
>>
>> - filter->owner.sys = clock;
>> + filter->audio_owner.sys = clock;
>> filter->p_cfg = cfg;
>> filter->fmt_in.audio = *infmt;
>> filter->fmt_in.i_codec = infmt->i_format;
>> @@ -390,7 +390,7 @@ vout_thread_t *aout_filter_GetVout(filter_t *filter,
>> const video_format_t *fmt)
>>
>> video_format_t adj_fmt = *fmt;
>> vout_configuration_t cfg = {
>> - .vout = vout, .clock = filter->owner.sys, .fmt = &adj_fmt,
>> .dpb_size = 1, + .vout = vout, .clock = filter->audio_owner.sys,
>> .fmt = &adj_fmt, .dpb_size = 1, };
>>
>> video_format_AdjustColorSpace(&adj_fmt);
>> diff --git a/src/misc/filter_chain.c b/src/misc/filter_chain.c
>> index c5029affc0..ac7a809466 100644
>> --- a/src/misc/filter_chain.c
>> +++ b/src/misc/filter_chain.c
>> @@ -52,7 +52,7 @@ static inline chained_filter_t *chained(filter_t *filter)
>> struct filter_chain_t
>> {
>> vlc_object_t *obj;
>> - filter_owner_t owner; /**< Owner (downstream) callbacks */
>> + video_filter_owner_t parent_video_owner; /**< Owner (downstream)
>> callbacks */
>>
>> chained_filter_t *first, *last; /**< List of filters */
>>
>> @@ -70,7 +70,7 @@ static void FilterDeletePictures( picture_t * );
>>
>> static filter_chain_t *filter_chain_NewInner( vlc_object_t *obj,
>> const char *cap, const char *conv_cap, bool fmt_out_change,
>> - const filter_owner_t *owner, enum es_format_category_e cat )
>> + const video_filter_owner_t *owner, enum es_format_category_e cat )
>> {
>> assert( obj != NULL );
>> assert( cap != NULL );
>> @@ -81,9 +81,9 @@ static filter_chain_t *filter_chain_NewInner( vlc_object_t
>> *obj,
>>
>> chain->obj = obj;
>> if( owner != NULL )
>> - chain->owner = *owner;
>> + chain->parent_video_owner = *owner;
>> else
>> - memset(&chain->owner, 0, sizeof(chain->owner));
>> + chain->parent_video_owner = (video_filter_owner_t){};
>> chain->first = NULL;
>> chain->last = NULL;
>> es_format_Init( &chain->fmt_in, cat, 0 );
>> @@ -115,12 +115,12 @@ static picture_t *filter_chain_VideoBufferNew(
>> filter_t *filter ) }
>> else
>> {
>> - filter_chain_t *chain = filter->owner.sys;
>> + filter_chain_t *chain = filter->video_owner.sys;
>>
>> /* XXX ugly */
>> - filter->owner.sys = chain->owner.sys;
>> - picture_t *pic = chain->owner.video->buffer_new( filter );
>> - filter->owner.sys = chain;
>> + filter->video_owner.sys = chain->parent_video_owner.sys;
>> + picture_t *pic = chain->parent_video_owner.video->buffer_new(
>> filter ); + filter->video_owner.sys = chain;
>> return pic;
>> }
>> }
>> @@ -132,7 +132,7 @@ static const struct filter_video_callbacks
>> filter_chain_video_cbs =
>>
>> #undef filter_chain_NewVideo
>> filter_chain_t *filter_chain_NewVideo( vlc_object_t *obj, bool
>> allow_change, - const filter_owner_t
>> *restrict owner ) + const
>> video_filter_owner_t *restrict owner ) {
>> return filter_chain_NewInner( obj, "video filter",
>> "video converter", allow_change, owner,
>> VIDEO_ES ); @@ -202,11 +202,11 @@ static filter_t
>> *filter_chain_AppendInner( filter_chain_t *chain,
>>
>> if (fmt_in->i_cat == VIDEO_ES)
>> {
>> - filter->owner.video = &filter_chain_video_cbs;
>> - filter->owner.sys = chain;
>> + filter->video_owner.video = &filter_chain_video_cbs;
>> + filter->video_owner.sys = chain;
>> }
>> else
>> - filter->owner.sub = NULL;
>> + filter->spu_owner.sub = NULL;
>>
>> assert( capability != NULL );
>> if( name != NULL && filter->b_allow_fmt_out_change )
>> diff --git a/src/misc/image.c b/src/misc/image.c
>> index 9d86cbc536..d1743d2a5b 100644
>> --- a/src/misc/image.c
>> +++ b/src/misc/image.c
>> @@ -795,7 +795,7 @@ static filter_t *CreateConverter( vlc_object_t *p_this,
>> const es_format_t *p_fmt filter_t *p_filter;
>>
>> p_filter = vlc_custom_create( p_this, sizeof(filter_t), "filter" );
>> - p_filter->owner.video = &image_filter_cbs;
>> + p_filter->video_owner.video = &image_filter_cbs;
>>
>> es_format_Copy( &p_filter->fmt_in, p_fmt_in );
>> es_format_Copy( &p_filter->fmt_out, p_fmt_in );
>> diff --git a/src/video_output/display.c b/src/video_output/display.c
>> index 2438e4bb87..82d9a8b2b7 100644
>> --- a/src/video_output/display.c
>> +++ b/src/video_output/display.c
>> @@ -48,7 +48,7 @@
>>
>> ***************************************************************************
>> **/ static picture_t *VideoBufferNew(filter_t *filter)
>> {
>> - vout_display_t *vd = filter->owner.sys;
>> + vout_display_t *vd = filter->video_owner.sys;
>> const video_format_t *fmt = &filter->fmt_out.video;
>>
>> assert(vd->fmt.i_chroma == fmt->i_chroma &&
>> @@ -305,7 +305,7 @@ static const struct filter_video_callbacks
>> vout_display_filter_cbs = { static int
>> VoutDisplayCreateRender(vout_display_t *vd)
>> {
>> vout_display_priv_t *osys = container_of(vd, vout_display_priv_t,
>> display); - filter_owner_t owner = {
>> + video_filter_owner_t owner = {
>> .video = &vout_display_filter_cbs,
>> .sys = vd,
>> };
>> diff --git a/src/video_output/video_output.c
>> b/src/video_output/video_output.c index 619ccbf194..f5c2ad2f02 100644
>> --- a/src/video_output/video_output.c
>> +++ b/src/video_output/video_output.c
>> @@ -691,7 +691,7 @@ static void ThreadDelAllFilterCallbacks(vout_thread_t
>> *vout)
>>
>> static picture_t *VoutVideoFilterInteractiveNewPicture(filter_t *filter)
>> {
>> - vout_thread_t *vout = filter->owner.sys;
>> + vout_thread_t *vout = filter->video_owner.sys;
>>
>> picture_t *picture = picture_pool_Get(vout->p->private_pool);
>> if (picture) {
>> @@ -703,7 +703,7 @@ static picture_t
>> *VoutVideoFilterInteractiveNewPicture(filter_t *filter)
>>
>> static picture_t *VoutVideoFilterStaticNewPicture(filter_t *filter)
>> {
>> - vout_thread_t *vout = filter->owner.sys;
>> + vout_thread_t *vout = filter->video_owner.sys;
>>
>> vlc_mutex_assert(&vout->p->filter.lock);
>> if (filter_chain_IsEmpty(vout->p->filter.chain_interactive))
>> @@ -948,7 +948,7 @@ static picture_t *ConvertRGB32AndBlend(vout_thread_t
>> *vout, picture_t *pic, static const struct filter_video_callbacks cbs = {
>> ConvertRGB32AndBlendBufferNew,
>> };
>> - filter_owner_t owner = {
>> + video_filter_owner_t owner = {
>> .video = &cbs,
>> };
>> filter_chain_t *filterc = filter_chain_NewVideo(vout, false, &owner);
>> @@ -1463,7 +1463,7 @@ static int vout_Start(vout_thread_t *vout, const
>> vout_configuration_t *cfg) static const struct filter_video_callbacks
>> interactive_cbs = { VoutVideoFilterInteractiveNewPicture,
>> };
>> - filter_owner_t owner = {
>> + video_filter_owner_t owner = {
>> .video = &static_cbs,
>> .sys = vout,
>> };
>> diff --git a/src/video_output/vout_subpictures.c
>> b/src/video_output/vout_subpictures.c index 23c811e242..fcc21ce0ca 100644
>> --- a/src/video_output/vout_subpictures.c
>> +++ b/src/video_output/vout_subpictures.c
>> @@ -209,7 +209,7 @@ static int spu_get_attachments(filter_t *filter,
>> input_attachment_t ***attachment_ptr,
>> int *attachment_count)
>> {
>> - spu_t *spu = filter->owner.sys;
>> + spu_t *spu = filter->spu_owner.sys;
>>
>> if (spu->p->input)
>> {
>> @@ -229,7 +229,7 @@ static filter_t *SpuRenderCreateAndLoadText(spu_t *spu)
>> if (!text)
>> return NULL;
>>
>> - text->owner.sys = spu;
>> + text->spu_owner.sys = spu;
>>
>> es_format_Init(&text->fmt_in, VIDEO_ES, 0);
>>
>> @@ -278,7 +278,7 @@ static filter_t
>> *SpuRenderCreateAndLoadScale(vlc_object_t *object,
>> scale->fmt_out.video.i_height =
>> scale->fmt_out.video.i_visible_height = require_resize ? 16 : 32;
>>
>> - scale->owner.video = &spu_scaler_cbs;
>> + scale->video_owner.video = &spu_scaler_cbs;
>>
>> scale->p_module = module_need(scale, "video converter", NULL, false);
>> if (!scale->p_module)
>> @@ -1287,11 +1287,11 @@ static void UpdateSPU(spu_t *spu, const
>> vlc_spu_highlight_t *hl)
>>
>> static subpicture_t *sub_new_buffer(filter_t *filter)
>> {
>> - ssize_t channel = *(ssize_t *)filter->owner.sys;
>> + ssize_t *channel = filter->spu_owner.sys;
>>
>> subpicture_t *subpicture = subpicture_New(NULL);
>> if (subpicture)
>> - subpicture->i_channel = channel;
>> + subpicture->i_channel = *channel;
>> return subpicture;
>> }
>>
>> @@ -1307,15 +1307,15 @@ static int SubSourceInit(filter_t *filter, void
>> *data) return VLC_ENOMEM;
>>
>> *channel = spu_RegisterChannel(spu);
>> - filter->owner.sys = channel;
>> - filter->owner.sub = &sub_cbs;
>> + filter->spu_owner.sys = channel;
>> + filter->spu_owner.sub = &sub_cbs;
>> return VLC_SUCCESS;
>> }
>>
>> static int SubSourceClean(filter_t *filter, void *data)
>> {
>> spu_t *spu = data;
>> - ssize_t *channel = filter->owner.sys;
>> + ssize_t *channel = filter->spu_owner.sys;
>>
>> spu_ClearChannel(spu, *channel);
>> free(channel);
>
>
> --
> レミ・デニ-クールモン
> 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