Commit d6e6460d authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

filter_chain: introduce dedicated filter_chain_NewVideo() for video filters

Also remove the filter chain buffer functions update hack, keep constant
callbacks for video filters in the filter chain, remove now useless
parameters from filter_chain_New(), and inline
filter_chain_AppendFilterInternal().
parent 6650b321
...@@ -297,13 +297,25 @@ typedef struct filter_chain_t filter_chain_t; ...@@ -297,13 +297,25 @@ typedef struct filter_chain_t filter_chain_t;
* \param p_object pointer to a vlc object * \param p_object pointer to a vlc object
* \param psz_capability vlc capability of filters in filter chain * \param psz_capability vlc capability of filters in filter chain
* \param b_allow_format_fmt_change allow changing of fmt * \param b_allow_format_fmt_change allow changing of fmt
* \param pf_buffer_allocation_init callback function to initialize buffer allocations
* \param pf_buffer_allocation_clear callback function to clear buffer allocation initialization
* \param p_buffer_allocation_data pointer to private allocation data
* \return pointer to a filter chain * \return pointer to a filter chain
*/ */
VLC_API filter_chain_t * filter_chain_New( vlc_object_t *, const char *, bool, int (*)( filter_t *, void * ), void (*)( filter_t * ), void * ) VLC_USED; VLC_API filter_chain_t * filter_chain_New( vlc_object_t *, const char *, bool )
#define filter_chain_New( a, b, c, d, e, f ) filter_chain_New( VLC_OBJECT( a ), b, c, d, e, f ) VLC_USED;
#define filter_chain_New( a, b, c ) filter_chain_New( VLC_OBJECT( a ), b, c )
/**
* Creates a new video filter chain.
*
* \param obj pointer to parent VLC object
* \param change whether to allow changing the output format
* \param owner owner video buffer callbacks
* \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 )
VLC_USED;
#define filter_chain_NewVideo( a, b, c ) \
filter_chain_NewVideo( VLC_OBJECT( a ), b, c )
/** /**
* Delete filter chain will delete all filters in the chain and free all * Delete filter chain will delete all filters in the chain and free all
......
...@@ -274,14 +274,6 @@ static void Close( vlc_object_t * p_this ) ...@@ -274,14 +274,6 @@ static void Close( vlc_object_t * p_this )
free( p_sys ); free( p_sys );
} }
static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data )
{
p_filter->owner.sys = p_data;
p_filter->owner.video.buffer_new = video_new_buffer_filter;
p_filter->owner.video.buffer_del = video_del_buffer_filter;
return VLC_SUCCESS;
}
static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt ) static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
{ {
sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_sys_t *p_sys = p_stream->p_sys;
...@@ -400,9 +392,15 @@ static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt ) ...@@ -400,9 +392,15 @@ static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
msg_Dbg( p_stream, "psz_chain: %s", psz_chain ); msg_Dbg( p_stream, "psz_chain: %s", psz_chain );
if( psz_chain ) if( psz_chain )
{ {
p_sys->p_vf2 = filter_chain_New( p_stream, "video filter2", false, filter_owner_t owner = {
video_filter_buffer_allocation_init, .sys = p_sys->p_decoder->p_owner,
NULL, p_sys->p_decoder->p_owner ); .video = {
.buffer_new = video_new_buffer_filter,
.buffer_del = video_del_buffer_filter,
},
};
p_sys->p_vf2 = filter_chain_NewVideo( p_stream, false, &owner );
es_format_t fmt; es_format_t fmt;
es_format_Copy( &fmt, &p_sys->p_decoder->fmt_out ); es_format_Copy( &fmt, &p_sys->p_decoder->fmt_out );
if( p_sys->i_chroma ) if( p_sys->i_chroma )
......
...@@ -77,21 +77,13 @@ static picture_t *transcode_video_filter_buffer_new( filter_t *p_filter ) ...@@ -77,21 +77,13 @@ static picture_t *transcode_video_filter_buffer_new( filter_t *p_filter )
p_filter->fmt_out.video.i_chroma = p_filter->fmt_out.i_codec; p_filter->fmt_out.video.i_chroma = p_filter->fmt_out.i_codec;
return picture_NewFromFormat( &p_filter->fmt_out.video ); return picture_NewFromFormat( &p_filter->fmt_out.video );
} }
static void transcode_video_filter_buffer_del( filter_t *p_filter, picture_t *p_pic ) static void transcode_video_filter_buffer_del( filter_t *p_filter, picture_t *p_pic )
{ {
VLC_UNUSED(p_filter); VLC_UNUSED(p_filter);
picture_Release( p_pic ); picture_Release( p_pic );
} }
static int transcode_video_filter_allocation_init( filter_t *p_filter,
void *p_data )
{
VLC_UNUSED(p_data);
p_filter->owner.video.buffer_new = transcode_video_filter_buffer_new;
p_filter->owner.video.buffer_del = transcode_video_filter_buffer_del;
return VLC_SUCCESS;
}
static void* EncoderThread( void *obj ) static void* EncoderThread( void *obj )
{ {
sout_stream_sys_t *p_sys = (sout_stream_sys_t*)obj; sout_stream_sys_t *p_sys = (sout_stream_sys_t*)obj;
...@@ -293,13 +285,17 @@ int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id ) ...@@ -293,13 +285,17 @@ int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
static void transcode_video_filter_init( sout_stream_t *p_stream, static void transcode_video_filter_init( sout_stream_t *p_stream,
sout_stream_id_sys_t *id ) sout_stream_id_sys_t *id )
{ {
filter_owner_t owner = {
.sys = p_stream->p_sys,
.video = {
.buffer_new = transcode_video_filter_buffer_new,
.buffer_del = transcode_video_filter_buffer_del,
},
};
es_format_t *p_fmt_out = &id->p_decoder->fmt_out; es_format_t *p_fmt_out = &id->p_decoder->fmt_out;
id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec;
id->p_f_chain = filter_chain_New( p_stream, "video filter2", id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec;
false, id->p_f_chain = filter_chain_New( p_stream, false, &owner );
transcode_video_filter_allocation_init,
NULL, p_stream->p_sys );
filter_chain_Reset( id->p_f_chain, p_fmt_out, p_fmt_out ); filter_chain_Reset( id->p_f_chain, p_fmt_out, p_fmt_out );
/* Deinterlace */ /* Deinterlace */
...@@ -322,10 +318,7 @@ static void transcode_video_filter_init( sout_stream_t *p_stream, ...@@ -322,10 +318,7 @@ static void transcode_video_filter_init( sout_stream_t *p_stream,
if( p_stream->p_sys->psz_vf2 ) if( p_stream->p_sys->psz_vf2 )
{ {
id->p_uf_chain = filter_chain_New( p_stream, "video filter2", id->p_uf_chain = filter_chain_New( p_stream, true, &owner );
true,
transcode_video_filter_allocation_init,
NULL, p_stream->p_sys );
filter_chain_Reset( id->p_uf_chain, p_fmt_out, filter_chain_Reset( id->p_uf_chain, p_fmt_out,
&id->p_encoder->fmt_in ); &id->p_encoder->fmt_in );
if( p_fmt_out->video.i_chroma != id->p_encoder->fmt_in.video.i_chroma ) if( p_fmt_out->video.i_chroma != id->p_encoder->fmt_in.video.i_chroma )
......
...@@ -49,7 +49,6 @@ vlc_module_end () ...@@ -49,7 +49,6 @@ vlc_module_end ()
* Local prototypes. * Local prototypes.
*****************************************************************************/ *****************************************************************************/
static picture_t *Chain ( filter_t *, picture_t * ); static picture_t *Chain ( filter_t *, picture_t * );
static int BufferAllocationInit ( filter_t *, void * );
static int BuildTransformChain( filter_t *p_filter ); static int BuildTransformChain( filter_t *p_filter );
static int BuildChromaResize( filter_t * ); static int BuildChromaResize( filter_t * );
...@@ -74,6 +73,23 @@ struct filter_sys_t ...@@ -74,6 +73,23 @@ struct filter_sys_t
filter_chain_t *p_chain; filter_chain_t *p_chain;
}; };
/*****************************************************************************
* Buffer management
*****************************************************************************/
static picture_t *BufferNew( filter_t *p_filter )
{
filter_t *p_parent = p_filter->owner.sys;
return filter_NewPicture( p_parent );
}
static void BufferDel( filter_t *p_filter, picture_t *p_pic )
{
filter_t *p_parent = p_filter->owner.sys;
filter_DeletePicture( p_parent, p_pic );
}
#define CHAIN_LEVEL_MAX 1 #define CHAIN_LEVEL_MAX 1
/***************************************************************************** /*****************************************************************************
...@@ -99,7 +115,15 @@ static int Activate( vlc_object_t *p_this ) ...@@ -99,7 +115,15 @@ static int Activate( vlc_object_t *p_this )
if( !p_sys ) if( !p_sys )
return VLC_ENOMEM; return VLC_ENOMEM;
p_sys->p_chain = filter_chain_New( p_filter, "video filter2", false, BufferAllocationInit, NULL, p_filter ); filter_owner_t owner = {
.sys = p_filter,
.video = {
.buffer_new = BufferNew,
.buffer_del = BufferDel,
},
};
p_sys->p_chain = filter_chain_NewVideo( p_filter, false, &owner );
if( !p_sys->p_chain ) if( !p_sys->p_chain )
{ {
free( p_sys ); free( p_sys );
...@@ -261,31 +285,6 @@ exit: ...@@ -261,31 +285,6 @@ exit:
return i_ret; return i_ret;
} }
/*****************************************************************************
* Buffer management
*****************************************************************************/
static picture_t *BufferNew( filter_t *p_filter )
{
filter_t *p_parent = p_filter->owner.sys;
return filter_NewPicture( p_parent );
}
static void BufferDel( filter_t *p_filter, picture_t *p_pic )
{
filter_t *p_parent = p_filter->owner.sys;
filter_DeletePicture( p_parent, p_pic );
}
static int BufferAllocationInit ( filter_t *p_filter, void *p_data )
{
p_filter->owner.sys = p_data;
p_filter->owner.video.buffer_new = BufferNew;
p_filter->owner.video.buffer_del = BufferDel;
return VLC_SUCCESS;
}
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
static int Activate( vlc_object_t * ); static int Activate( vlc_object_t * );
static void Destroy( vlc_object_t * ); static void Destroy( vlc_object_t * );
static picture_t *Filter( filter_t *, picture_t * ); static picture_t *Filter( filter_t *, picture_t * );
static int alloc_init( filter_t *, void * );
/* This module effectively implements a form of picture-in-picture. /* This module effectively implements a form of picture-in-picture.
* - The outer picture is called the canvas. * - The outer picture is called the canvas.
...@@ -132,6 +131,16 @@ struct filter_sys_t ...@@ -132,6 +131,16 @@ struct filter_sys_t
filter_chain_t *p_chain; filter_chain_t *p_chain;
}; };
static picture_t *video_new( filter_t *p_filter )
{
return filter_NewPicture( p_filter->owner.sys );
}
static void video_del( filter_t *p_filter, picture_t *p_pic )
{
return filter_DeletePicture( p_filter->owner.sys, p_pic );
}
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
...@@ -226,8 +235,15 @@ static int Activate( vlc_object_t *p_this ) ...@@ -226,8 +235,15 @@ static int Activate( vlc_object_t *p_this )
return VLC_ENOMEM; return VLC_ENOMEM;
p_filter->p_sys = p_sys; p_filter->p_sys = p_sys;
p_sys->p_chain = filter_chain_New( p_filter, "video filter2", true, filter_owner_t owner = {
alloc_init, NULL, p_filter ); .sys = p_filter,
.video = {
.buffer_new = video_new,
.buffer_del = video_del,
},
};
p_sys->p_chain = filter_chain_NewVideo( p_filter, true, &owner );
if( !p_sys->p_chain ) if( !p_sys->p_chain )
{ {
msg_Err( p_filter, "Could not allocate filter chain" ); msg_Err( p_filter, "Could not allocate filter chain" );
...@@ -364,24 +380,3 @@ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) ...@@ -364,24 +380,3 @@ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{ {
return filter_chain_VideoFilter( p_filter->p_sys->p_chain, p_pic ); return filter_chain_VideoFilter( p_filter->p_sys->p_chain, p_pic );
} }
/*****************************************************************************
*
*****************************************************************************/
static picture_t *video_new( filter_t *p_filter )
{
return filter_NewPicture( p_filter->owner.sys );
}
static void video_del( filter_t *p_filter, picture_t *p_pic )
{
return filter_DeletePicture( p_filter->owner.sys, p_pic );
}
static int alloc_init( filter_t *p_filter, void *p_data )
{
p_filter->owner.sys = p_data;
p_filter->owner.video.buffer_new = video_new;
p_filter->owner.video.buffer_del = video_del;
return VLC_SUCCESS;
}
...@@ -127,6 +127,7 @@ filter_chain_GetLength ...@@ -127,6 +127,7 @@ filter_chain_GetLength
filter_chain_MouseFilter filter_chain_MouseFilter
filter_chain_MouseEvent filter_chain_MouseEvent
filter_chain_New filter_chain_New
filter_chain_NewVideo
filter_chain_Reset filter_chain_Reset
filter_chain_SubFilter filter_chain_SubFilter
filter_chain_VideoFilter filter_chain_VideoFilter
......
...@@ -31,14 +31,6 @@ ...@@ -31,14 +31,6 @@
#include <libvlc.h> #include <libvlc.h>
#include <assert.h> #include <assert.h>
typedef struct
{
int (*pf_init)( filter_t *, void *p_data ); /* Callback called once filter allocation has succeeded to initialize the filter's buffer allocation callbacks. This function is responsible for setting p_owner if needed. */
void (* pf_clean)( filter_t * ); /* Callback called on filter removal from chain to clean up buffer allocation callbacks data (ie p_owner) */
void *p_data; /* Data for pf_buffer_allocation_init */
} filter_chain_allocator_t;
typedef struct chained_filter_t typedef struct chained_filter_t
{ {
/* Public part of the filter structure */ /* Public part of the filter structure */
...@@ -55,26 +47,11 @@ static inline chained_filter_t *chained (filter_t *filter) ...@@ -55,26 +47,11 @@ static inline chained_filter_t *chained (filter_t *filter)
return (chained_filter_t *)filter; return (chained_filter_t *)filter;
} }
static int AllocatorInit( const filter_chain_allocator_t *,
chained_filter_t * );
static void AllocatorClean( const filter_chain_allocator_t *,
chained_filter_t * );
static bool IsInternalVideoAllocator( chained_filter_t * );
static int InternalVideoInit( filter_t *, void * );
static const filter_chain_allocator_t internal_video_allocator = {
.pf_init = InternalVideoInit,
.pf_clean = NULL,
.p_data = NULL,
};
/* */ /* */
struct filter_chain_t struct filter_chain_t
{ {
vlc_object_t *p_this; /**< Owner object */ filter_owner_t callbacks; /**< Inner callbacks */
filter_chain_allocator_t allocator; /**< Owner allocation callbacks */ filter_owner_t owner; /**< Owner (downstream) callbacks */
chained_filter_t *first, *last; /**< List of filters */ chained_filter_t *first, *last; /**< List of filters */
...@@ -88,49 +65,96 @@ struct filter_chain_t ...@@ -88,49 +65,96 @@ struct filter_chain_t
/** /**
* Local prototypes * Local prototypes
*/ */
static filter_t *filter_chain_AppendFilterInternal( filter_chain_t *,
const char *, config_chain_t *,
const es_format_t *, const es_format_t * );
static int filter_chain_DeleteFilterInternal( filter_chain_t *, filter_t * ); static int filter_chain_DeleteFilterInternal( filter_chain_t *, filter_t * );
static int UpdateBufferFunctions( filter_chain_t * );
static void FilterDeletePictures( filter_t *, picture_t * ); static void FilterDeletePictures( filter_t *, picture_t * );
static filter_chain_t *filter_chain_NewInner( const filter_owner_t *callbacks,
const char *cap, bool fmt_out_change, const filter_owner_t *owner )
{
assert( callbacks != NULL && callbacks->sys != NULL );
assert( cap != NULL );
filter_chain_t *chain = malloc( sizeof(*chain) + strlen( cap ) );
if( unlikely(chain == NULL) )
return NULL;
chain->callbacks = *callbacks;
if( owner != NULL )
chain->owner = *owner;
chain->first = NULL;
chain->last = NULL;
es_format_Init( &chain->fmt_in, UNKNOWN_ES, 0 );
es_format_Init( &chain->fmt_out, UNKNOWN_ES, 0 );
chain->length = 0;
chain->b_allow_fmt_out_change = fmt_out_change;
strcpy( chain->psz_capability, cap );
return chain;
}
#undef filter_chain_New #undef filter_chain_New
/** /**
* Filter chain initialisation * Filter chain initialisation
*/ */
filter_chain_t *filter_chain_New( vlc_object_t *p_this, filter_chain_t *filter_chain_New( vlc_object_t *obj, const char *cap,
const char *psz_capability, bool fmt_out_change )
bool b_allow_fmt_out_change,
int (*pf_buffer_allocation_init)( filter_t *, void * ),
void (*pf_buffer_allocation_clean)( filter_t * ),
void *p_buffer_allocation_data )
{ {
assert( p_this ); filter_owner_t callbacks = {
assert( psz_capability ); .sys = obj,
};
size_t size = sizeof(filter_chain_t) + strlen(psz_capability); return filter_chain_NewInner( &callbacks, cap, fmt_out_change, NULL );
filter_chain_t *p_chain = malloc( size ); }
if( !p_chain )
return NULL; /** Chained filter picture allocator function */
static picture_t *filter_chain_VideoBufferNew( filter_t *filter )
{
if( chained(filter)->next != NULL )
{
picture_t *pic = picture_NewFromFormat( &filter->fmt_out.video );
if( pic == NULL )
msg_Err( filter, "Failed to allocate picture" );
return pic;
}
else
{
filter_chain_t *chain = filter->owner.sys;
p_chain->p_this = p_this; /* XXX ugly */
p_chain->last = p_chain->first = NULL; filter->owner.sys = chain->owner.sys;
p_chain->length = 0; picture_t *pic = chain->owner.video.buffer_new( filter );
strcpy( p_chain->psz_capability, psz_capability ); filter->owner.sys = chain;
return pic;
}
}
es_format_Init( &p_chain->fmt_in, UNKNOWN_ES, 0 ); static void filter_chain_VideoBufferDelete( filter_t *filter, picture_t *pic )
es_format_Init( &p_chain->fmt_out, UNKNOWN_ES, 0 ); {
p_chain->b_allow_fmt_out_change = b_allow_fmt_out_change; if( chained(filter)->next != NULL )
picture_Release( pic );
else
{
filter_chain_t *chain = filter->owner.sys;
p_chain->allocator.pf_init = pf_buffer_allocation_init; chain->owner.video.buffer_del( filter, pic );
p_chain->allocator.pf_clean = pf_buffer_allocation_clean; }
p_chain->allocator.p_data = p_buffer_allocation_data; }
return p_chain; #undef filter_chain_NewVideo
filter_chain_t *filter_chain_NewVideo( vlc_object_t *obj, bool allow_change,
const filter_owner_t *restrict owner )
{
filter_owner_t callbacks = {
.sys = obj,
.video = {
.buffer_new = filter_chain_VideoBufferNew,
.buffer_del = filter_chain_VideoBufferDelete,
},
};
return filter_chain_NewInner( &callbacks, "video filter2", allow_change,
owner );
} }
/** /**
...@@ -138,7 +162,8 @@ filter_chain_t *filter_chain_New( vlc_object_t *p_this, ...@@ -138,7 +162,8 @@ filter_chain_t *filter_chain_New( vlc_object_t *p_this,
*/ */
void filter_chain_Delete( filter_chain_t *p_chain ) void filter_chain_Delete( filter_chain_t *p_chain )
{ {
filter_chain_Reset( p_chain, NULL, NULL ); while( p_chain->first != NULL )
filter_chain_DeleteFilterInternal( p_chain, &p_chain->first->filter );
es_format_Clean( &p_chain->fmt_in ); es_format_Clean( &p_chain->fmt_in );
es_format_Clean( &p_chain->fmt_out ); es_format_Clean( &p_chain->fmt_out );
...@@ -166,22 +191,87 @@ void filter_chain_Reset( filter_chain_t *p_chain, const es_format_t *p_fmt_in, ...@@ -166,22 +191,87 @@ void filter_chain_Reset( filter_chain_t *p_chain, const es_format_t *p_fmt_in,
} }
} }
filter_t *filter_chain_AppendFilter( filter_chain_t *p_chain, filter_t *filter_chain_AppendFilter( filter_chain_t *chain, const char *name,
const char *psz_name, config_chain_t *cfg,
config_chain_t *p_cfg, const es_format_t *fmt_in,
const es_format_t *p_fmt_in, const es_format_t *fmt_out )
const es_format_t *p_fmt_out )
{ {
filter_t *p_filter = filter_chain_AppendFilterInternal( p_chain, psz_name, vlc_object_t *parent = chain->callbacks.sys;
p_cfg, p_fmt_in, chained_filter_t *chained =
p_fmt_out ); vlc_custom_create( parent, sizeof(*chained), "filter" );
if( UpdateBufferFunctions( p_chain ) < 0 ) if( unlikely(chained == NULL) )
msg_Err( p_filter, "Woah! This doesn't look good." ); return NULL;
return p_filter;
filter_t *filter = &chained->filter;
if( fmt_in == NULL )
{
if( chain->last != NULL )
fmt_in = &chain->last->filter.fmt_out;
else
fmt_in = &chain->fmt_in;
}
if( fmt_out == NULL )
fmt_out = &chain->fmt_out;
es_format_Copy( &filter->fmt_in, fmt_in );
es_format_Copy( &filter->fmt_out, fmt_out );
filter->b_allow_fmt_out_change = chain->b_allow_fmt_out_change;
filter->p_cfg = cfg;
filter->owner = chain->callbacks;
filter->owner.sys = chain;
filter->p_module = module_need( filter, chain->psz_capability, name,
name != NULL );
if( filter->p_module == NULL )
goto error;
if( filter->b_allow_fmt_out_change )
{
es_format_Clean( &chain->fmt_out );
es_format_Copy( &chain->fmt_out, &filter->fmt_out );
}
if( chain->last == NULL )
{
assert( chain->first == NULL );
chain->first = chained;
}
else
chain->last->next = chained;
chained->prev = chain->last;
chain->last = chained;
chained->next = NULL;
chain->length++;
vlc_mouse_t *mouse = malloc( sizeof(*mouse) );
if( likely(mouse != NULL) )
vlc_mouse_Init( mouse );
chained->mouse = mouse;
chained->pending = NULL;
msg_Dbg( parent, "Filter '%s' (%p) appended to chain",
(name != NULL) ? name : module_get_name(filter->p_module, false),
filter );
return filter;
error:
if( name != NULL )
msg_Err( parent, "Failed to create %s '%s'", chain->psz_capability,
name );
else
msg_Err( parent, "Failed to create %s", chain->psz_capability );
es_format_Clean( &filter->fmt_out );
es_format_Clean( &filter->fmt_in );
vlc_object_release( filter );
return NULL;
} }
int filter_chain_AppendFromString( filter_chain_t *chain, const char *str ) int filter_chain_AppendFromString( filter_chain_t *chain, const char *str )
{ {
vlc_object_t *obj = chain->callbacks.sys;
char *buf = NULL; char *buf = NULL;
int ret = 0; int ret = 0;
...@@ -196,12 +286,11 @@ int filter_chain_AppendFromString( filter_chain_t *chain, const char *str ) ...@@ -196,12 +286,11 @@ int filter_chain_AppendFromString( filter_chain_t *chain, const char *str )
free( buf ); free( buf );
buf = next; buf = next;
filter_t *filter = filter_chain_AppendFilterInternal( chain, name, cfg, filter_t *filter = filter_chain_AppendFilter( chain, name, cfg,
NULL, NULL ); NULL, NULL );
if( filter == NULL ) if( filter == NULL )
{ {
msg_Err( chain->p_this, "Failed while trying to append '%s' " msg_Err( obj, "Failed to append '%s' to chain", name );
"to filter chain", name );
free( name ); free( name );
free( cfg ); free( cfg );
goto error; goto error;
...@@ -211,8 +300,6 @@ int filter_chain_AppendFromString( filter_chain_t *chain, const char *str ) ...@@ -211,8 +300,6 @@ int filter_chain_AppendFromString( filter_chain_t *chain, const char *str )
ret++; ret++;
} }
if( UpdateBufferFunctions( chain ) )
assert( 0 ); /* should never happen, vf2 alloc cannot fail */
free( buf ); free( buf );
return ret; return ret;
...@@ -231,9 +318,7 @@ int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter ) ...@@ -231,9 +318,7 @@ int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter )
const int i_ret = filter_chain_DeleteFilterInternal( p_chain, p_filter ); const int i_ret = filter_chain_DeleteFilterInternal( p_chain, p_filter );
if( i_ret < 0 ) if( i_ret < 0 )
return i_ret; return i_ret;
return VLC_SUCCESS;
/* FIXME That one seems bad if a error is returned */
return UpdateBufferFunctions( p_chain );
} }
int filter_chain_ForEach( filter_chain_t *chain, int filter_chain_ForEach( filter_chain_t *chain,
...@@ -407,93 +492,10 @@ int filter_chain_MouseEvent( filter_chain_t *p_chain, ...@@ -407,93 +492,10 @@ int filter_chain_MouseEvent( filter_chain_t *p_chain,
} }
/* Helpers */ /* Helpers */
static filter_t *filter_chain_AppendFilterInternal( filter_chain_t *p_chain,
const char *psz_name,
config_chain_t *p_cfg,
const es_format_t *p_fmt_in,
const es_format_t *p_fmt_out )
{
chained_filter_t *p_chained =
vlc_custom_create( p_chain->p_this, sizeof(*p_chained), "filter" );
filter_t *p_filter = &p_chained->filter;
if( !p_filter )
return NULL;
if( !p_fmt_in )
{
if( p_chain->last != NULL )
p_fmt_in = &p_chain->last->filter.fmt_out;
else
p_fmt_in = &p_chain->fmt_in;
}
if( !p_fmt_out )
{
p_fmt_out = &p_chain->fmt_out;
}
es_format_Copy( &p_filter->fmt_in, p_fmt_in );
es_format_Copy( &p_filter->fmt_out, p_fmt_out );
p_filter->p_cfg = p_cfg;
p_filter->b_allow_fmt_out_change = p_chain->b_allow_fmt_out_change;
p_filter->p_module = module_need( p_filter, p_chain->psz_capability,
psz_name, psz_name != NULL );
if( !p_filter->p_module )
goto error;
if( p_filter->b_allow_fmt_out_change )
{
es_format_Clean( &p_chain->fmt_out );
es_format_Copy( &p_chain->fmt_out, &p_filter->fmt_out );
}
if( AllocatorInit( &p_chain->allocator, p_chained ) )
goto error;
if( p_chain->last == NULL )
{
assert( p_chain->first == NULL );
p_chain->first = p_chained;
}
else
p_chain->last->next = p_chained;
p_chained->prev = p_chain->last;
p_chain->last = p_chained;
p_chained->next = NULL;
p_chain->length++;
vlc_mouse_t *p_mouse = malloc( sizeof(*p_mouse) );
if( p_mouse )
vlc_mouse_Init( p_mouse );
p_chained->mouse = p_mouse;
p_chained->pending = NULL;
msg_Dbg( p_chain->p_this, "Filter '%s' (%p) appended to chain",
psz_name ? psz_name : module_get_name(p_filter->p_module, false),
p_filter );
return p_filter;
error:
if( psz_name )
msg_Err( p_chain->p_this, "Failed to create %s '%s'",
p_chain->psz_capability, psz_name );
else
msg_Err( p_chain->p_this, "Failed to create %s",
p_chain->psz_capability );
if( p_filter->p_module )
module_unneed( p_filter, p_filter->p_module );
es_format_Clean( &p_filter->fmt_in );
es_format_Clean( &p_filter->fmt_out );
vlc_object_release( p_filter );
return NULL;
}
static int filter_chain_DeleteFilterInternal( filter_chain_t *p_chain, static int filter_chain_DeleteFilterInternal( filter_chain_t *p_chain,
filter_t *p_filter ) filter_t *p_filter )
{ {
vlc_object_t *obj = p_chain->callbacks.sys;
chained_filter_t *p_chained = chained( p_filter ); chained_filter_t *p_chained = chained( p_filter );
/* Remove it from the chain */ /* Remove it from the chain */
...@@ -514,16 +516,10 @@ static int filter_chain_DeleteFilterInternal( filter_chain_t *p_chain, ...@@ -514,16 +516,10 @@ static int filter_chain_DeleteFilterInternal( filter_chain_t *p_chain,
} }
p_chain->length--; p_chain->length--;
msg_Dbg( p_chain->p_this, "Filter %p removed from chain", p_filter ); msg_Dbg( obj, "Filter %p removed from chain", p_filter );
FilterDeletePictures( &p_chained->filter, p_chained->pending ); FilterDeletePictures( &p_chained->filter, p_chained->pending );
/* Destroy the filter object */
if( IsInternalVideoAllocator( p_chained ) )
AllocatorClean( &internal_video_allocator, p_chained );
else
AllocatorClean( &p_chain->allocator, p_chained );
if( p_filter->p_module ) if( p_filter->p_module )
module_unneed( p_filter, p_filter->p_module ); module_unneed( p_filter, p_filter->p_module );
free( p_chained->mouse ); free( p_chained->mouse );
...@@ -543,100 +539,3 @@ static void FilterDeletePictures( filter_t *filter, picture_t *picture ) ...@@ -543,100 +539,3 @@ static void FilterDeletePictures( filter_t *filter, picture_t *picture )
picture = next; picture = next;
} }
} }
/**
* Internal chain buffer handling
*/
static int UpdateVideoBufferFunctions( filter_chain_t *p_chain )
{
/**
* Last filter uses the filter chain's parent buffer allocation
* functions. All the other filters use internal functions.
* This makes it possible to have format changes between each
* filter without having to worry about the parent's picture
* heap format.
*/
/* FIXME: we should only update the last and penultimate filters */
chained_filter_t *f;
for( f = p_chain->first; f != p_chain->last; f = f->next )
{
if( !IsInternalVideoAllocator( f ) )
{
AllocatorClean( &p_chain->allocator, f );
AllocatorInit( &internal_video_allocator, f );
}
}
if( f != NULL )
{
if( IsInternalVideoAllocator( f ) )
{
AllocatorClean( &internal_video_allocator, f );
if( AllocatorInit( &p_chain->allocator, f ) )
return VLC_EGENERIC;
}
}
return VLC_SUCCESS;
}
/**
* This function should be called after every filter chain change
*/
static int UpdateBufferFunctions( filter_chain_t *p_chain )
{
if( !strcmp( p_chain->psz_capability, "video filter2" ) )
return UpdateVideoBufferFunctions( p_chain );
return VLC_SUCCESS;
}
/* Internal video allocator functions */
static picture_t *VideoBufferNew( filter_t *p_filter )
{
const video_format_t *p_fmt = &p_filter->fmt_out.video;
picture_t *p_picture = picture_NewFromFormat( p_fmt );
if( !p_picture )
msg_Err( p_filter, "Failed to allocate picture" );
return p_picture;
}
static void VideoBufferDelete( filter_t *p_filter, picture_t *p_picture )
{
VLC_UNUSED( p_filter );
picture_Release( p_picture );
}
static int InternalVideoInit( filter_t *p_filter, void *p_data )
{
VLC_UNUSED(p_data);
p_filter->owner.video.buffer_new = VideoBufferNew;
p_filter->owner.video.buffer_del = VideoBufferDelete;
return VLC_SUCCESS;
}
static bool IsInternalVideoAllocator( chained_filter_t *p_filter )
{
return p_filter->filter.owner.video.buffer_new == VideoBufferNew;
}
/* */
static int AllocatorInit( const filter_chain_allocator_t *p_alloc,
chained_filter_t *p_filter )
{
if( p_alloc->pf_init )
return p_alloc->pf_init( &p_filter->filter, p_alloc->p_data );
return VLC_SUCCESS;
}
static void AllocatorClean( const filter_chain_allocator_t *p_alloc,
chained_filter_t *p_filter )
{
if( p_alloc->pf_clean )
p_alloc->pf_clean( &p_filter->filter );
}
...@@ -65,20 +65,13 @@ static picture_t *VideoBufferNew(filter_t *filter) ...@@ -65,20 +65,13 @@ static picture_t *VideoBufferNew(filter_t *filter)
return NULL; return NULL;
return picture_pool_Get(pool); return picture_pool_Get(pool);
} }
static void VideoBufferDelete(filter_t *filter, picture_t *picture) static void VideoBufferDelete(filter_t *filter, picture_t *picture)
{ {
VLC_UNUSED(filter); VLC_UNUSED(filter);
picture_Release(picture); picture_Release(picture);
} }
static int FilterAllocationInit(filter_t *filter, void *vd)
{
filter->owner.sys = vd;
filter->owner.video.buffer_new = VideoBufferNew;
filter->owner.video.buffer_del = VideoBufferDelete;
return VLC_SUCCESS;
}
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
...@@ -458,8 +451,15 @@ static void VoutDisplayCreateRender(vout_display_t *vd) ...@@ -458,8 +451,15 @@ static void VoutDisplayCreateRender(vout_display_t *vd)
msg_Dbg(vd, "A filter to adapt decoder to display is needed"); msg_Dbg(vd, "A filter to adapt decoder to display is needed");
osys->filters = filter_chain_New(vd, "video filter2", false, filter_owner_t owner = {
FilterAllocationInit, NULL, vd); .sys = vd,
.video = {
.buffer_new = VideoBufferNew,
.buffer_del = VideoBufferDelete,
},
};
osys->filters = filter_chain_NewVideo(vd, false, &owner);
assert(osys->filters); /* TODO critical */ assert(osys->filters); /* TODO critical */
/* */ /* */
......
...@@ -696,22 +696,6 @@ static void VoutVideoFilterDelPicture(filter_t *filter, picture_t *picture) ...@@ -696,22 +696,6 @@ static void VoutVideoFilterDelPicture(filter_t *filter, picture_t *picture)
picture_Release(picture); picture_Release(picture);
} }
static int VoutVideoFilterStaticAllocationSetup(filter_t *filter, void *data)
{
filter->owner.sys = data; /* vout */
filter->owner.video.buffer_new = VoutVideoFilterStaticNewPicture;
filter->owner.video.buffer_del = VoutVideoFilterDelPicture;
return VLC_SUCCESS;
}
static int VoutVideoFilterInteractiveAllocationSetup(filter_t *filter, void *data)
{
filter->owner.sys = data; /* vout */
filter->owner.video.buffer_new = VoutVideoFilterInteractiveNewPicture;
filter->owner.video.buffer_del = VoutVideoFilterDelPicture;
return VLC_SUCCESS;
}
static void ThreadFilterFlush(vout_thread_t *vout, bool is_locked) static void ThreadFilterFlush(vout_thread_t *vout, bool is_locked)
{ {
if (vout->p->displayed.current) if (vout->p->displayed.current)
...@@ -1330,12 +1314,20 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state) ...@@ -1330,12 +1314,20 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state)
vout->p->filter.configuration = NULL; vout->p->filter.configuration = NULL;
video_format_Copy(&vout->p->filter.format, &vout->p->original); video_format_Copy(&vout->p->filter.format, &vout->p->original);
filter_owner_t owner = {
.sys = vout,
.video = {
.buffer_new = VoutVideoFilterStaticNewPicture,
.buffer_del = VoutVideoFilterDelPicture,
},
};
vout->p->filter.chain_static = vout->p->filter.chain_static =
filter_chain_New( vout, "video filter2", true, filter_chain_NewVideo( vout, true, &owner );
VoutVideoFilterStaticAllocationSetup, NULL, vout);
owner.video.buffer_new = VoutVideoFilterInteractiveNewPicture;
vout->p->filter.chain_interactive = vout->p->filter.chain_interactive =
filter_chain_New( vout, "video filter2", true, filter_chain_NewVideo( vout, true, &owner );
VoutVideoFilterInteractiveAllocationSetup, NULL, vout);
vout_display_state_t state_default; vout_display_state_t state_default;
if (!state) { if (!state) {
......
...@@ -1227,10 +1227,8 @@ spu_t *spu_Create(vlc_object_t *object) ...@@ -1227,10 +1227,8 @@ spu_t *spu_Create(vlc_object_t *object)
sys->filter_chain_update = NULL; sys->filter_chain_update = NULL;
vlc_mutex_init(&sys->source_chain_lock); vlc_mutex_init(&sys->source_chain_lock);
vlc_mutex_init(&sys->filter_chain_lock); vlc_mutex_init(&sys->filter_chain_lock);
sys->source_chain = filter_chain_New(spu, "sub source", false, sys->source_chain = filter_chain_New(spu, "sub source", false);
NULL, NULL, NULL); sys->filter_chain = filter_chain_New(spu, "sub filter", false);
sys->filter_chain = filter_chain_New(spu, "sub filter", false,
NULL, NULL, NULL);
/* Load text and scale module */ /* Load text and scale module */
sys->text = SpuRenderCreateAndLoadText(spu); sys->text = SpuRenderCreateAndLoadText(spu);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment