X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Ffilter_chain.c;h=65a822bd7b661fb02d0add8d55643565e8e7f565;hb=5c96f1ca97f41550e06088e008459e525f67f724;hp=0d649f9942e9f8d44c89f553104bd7764a968319;hpb=e259db6fefa6941b1a9cc2c01de8536c53b3ec01;p=vlc diff --git a/src/misc/filter_chain.c b/src/misc/filter_chain.c index 0d649f9942..65a822bd7b 100644 --- a/src/misc/filter_chain.c +++ b/src/misc/filter_chain.c @@ -21,8 +21,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include +#include struct filter_chain_t { @@ -40,6 +45,17 @@ struct filter_chain_t void *p_buffer_allocation_data; /* Data for pf_buffer_allocation_init */ }; +/** + * 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_AppendFromStringInternal( filter_chain_t *, const char * ); +static int filter_chain_DeleteFilterInternal( filter_chain_t *, filter_t * ); + +static int UpdateBufferFunctions( filter_chain_t * ); +static picture_t *VideoBufferNew( filter_t * ); +static void VideoBufferDelete( filter_t *, picture_t * ); + /** * Filter chain initialisation */ @@ -78,7 +94,7 @@ filter_chain_t *__filter_chain_New( vlc_object_t *p_this, void filter_chain_Delete( filter_chain_t *p_chain ) { while( p_chain->filters.i_count ) - filter_chain_DeleteFilter( p_chain, + filter_chain_DeleteFilterInternal( p_chain, (filter_t*)p_chain->filters.pp_elems[0] ); vlc_array_clear( &p_chain->filters ); free( p_chain->psz_capability ); @@ -93,26 +109,34 @@ void filter_chain_Reset( filter_chain_t *p_chain, const es_format_t *p_fmt_in, const es_format_t *p_fmt_out ) { while( p_chain->filters.i_count ) - filter_chain_DeleteFilter( p_chain, + filter_chain_DeleteFilterInternal( p_chain, (filter_t*)p_chain->filters.pp_elems[0] ); - es_format_Clean( &p_chain->fmt_in ); - es_format_Clean( &p_chain->fmt_out ); - es_format_Copy( &p_chain->fmt_in, p_fmt_in ); - es_format_Copy( &p_chain->fmt_out, p_fmt_out ); + if( p_fmt_in ) + { + es_format_Clean( &p_chain->fmt_in ); + es_format_Copy( &p_chain->fmt_in, p_fmt_in ); + } + if( p_fmt_out ) + { + es_format_Clean( &p_chain->fmt_out ); + es_format_Copy( &p_chain->fmt_out, p_fmt_out ); + } } /** * Modifying the filter chain */ -filter_t *filter_chain_AppendFilter( 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 ) +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 ) { + static const char typename[] = "filter"; filter_t *p_filter = - vlc_object_create( p_chain->p_this, VLC_OBJECT_FILTER ); + vlc_custom_create( p_chain->p_this, sizeof(filter_t), + VLC_OBJECT_GENERIC, typename ); if( !p_filter ) return NULL; vlc_object_attach( p_filter, p_chain->p_this ); @@ -134,7 +158,7 @@ filter_t *filter_chain_AppendFilter( filter_chain_t *p_chain, 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, + p_filter->p_module = module_need( p_filter, p_chain->psz_capability, psz_name, psz_name ? true : false ); if( !p_filter->p_module ) @@ -153,14 +177,18 @@ filter_t *filter_chain_AppendFilter( filter_chain_t *p_chain, vlc_array_append( &p_chain->filters, p_filter ); msg_Dbg( p_chain->p_this, "Filter '%s' (%p) appended to chain", - psz_name, p_filter ); + psz_name?:p_filter->psz_object_name, p_filter ); return p_filter; error: - msg_Err( p_chain->p_this, "Failed to create video filter '%s'", - psz_name ); - if( p_filter->p_module ) module_Unneed( p_filter, + 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 ); @@ -169,38 +197,66 @@ filter_t *filter_chain_AppendFilter( filter_chain_t *p_chain, return NULL; } -int filter_chain_AppendFromString( filter_chain_t *p_chain, - const char *psz_string ) +filter_t *filter_chain_AppendFilter( 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 ) +{ + filter_t *p_filter = filter_chain_AppendFilterInternal( p_chain, psz_name, + p_cfg, p_fmt_in, + p_fmt_out ); + if( UpdateBufferFunctions( p_chain ) < 0 ) + msg_Err( p_filter, "Woah! This doesn't look good." ); + return p_filter; +} + +static int filter_chain_AppendFromStringInternal( filter_chain_t *p_chain, + const char *psz_string ) { config_chain_t *p_cfg = NULL; char *psz_name = NULL; + char* psz_new_string; if( !psz_string || !*psz_string ) return 0; - psz_string = config_ChainCreate( &psz_name, &p_cfg, psz_string ); + psz_new_string = config_ChainCreate( &psz_name, &p_cfg, psz_string ); - filter_t *p_filter = filter_chain_AppendFilter( p_chain, psz_name, p_cfg, - NULL, NULL ); + filter_t *p_filter = filter_chain_AppendFilterInternal( p_chain, psz_name, + p_cfg, NULL, NULL ); if( !p_filter ) { msg_Err( p_chain->p_this, "Failed while trying to append '%s' " "to filter chain", psz_name ); free( psz_name ); free( p_cfg ); + free( psz_new_string ); return -1; } free( psz_name ); - int ret = filter_chain_AppendFromString( p_chain, psz_string ); + int ret = filter_chain_AppendFromStringInternal( p_chain, psz_new_string ); + free( psz_new_string ); if( ret < 0 ) { - filter_chain_DeleteFilter( p_chain, p_filter ); + filter_chain_DeleteFilterInternal( p_chain, p_filter ); return ret; } return 1 + ret; } -int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter ) +int filter_chain_AppendFromString( filter_chain_t *p_chain, + const char *psz_string ) +{ + int i_ret = filter_chain_AppendFromStringInternal( p_chain, psz_string ); + if( i_ret < 0 ) return i_ret; + int i_ret2 = UpdateBufferFunctions( p_chain ); + if( i_ret2 < 0 ) return i_ret2; + return i_ret; +} + +static int filter_chain_DeleteFilterInternal( filter_chain_t *p_chain, + filter_t *p_filter ) { int i; /* Find the filter in the chain */ @@ -227,14 +283,20 @@ int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter ) p_chain->pf_buffer_allocation_clear( p_filter ); vlc_object_detach( p_filter ); if( p_filter->p_module ) - module_Unneed( p_filter, p_filter->p_module ); + module_unneed( p_filter, p_filter->p_module ); vlc_object_release( p_filter ); /* FIXME: check fmt_in/fmt_out consitency */ - return VLC_SUCCESS; } +int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter ) +{ + int i_ret = filter_chain_DeleteFilterInternal( p_chain, p_filter ); + if( i_ret < 0 ) return i_ret; + return UpdateBufferFunctions( p_chain ); +} + /** * Reading from the filter chain */ @@ -271,12 +333,27 @@ int filter_chain_GetLength( filter_chain_t *p_chain ) const es_format_t *filter_chain_GetFmtOut( filter_chain_t *p_chain ) { - return &p_chain->fmt_out; + + if( p_chain->b_allow_fmt_out_change ) + return &p_chain->fmt_out; + + /* Unless filter_chain_Reset has been called we are doomed */ + if( p_chain->filters.i_count <= 0 ) + return &p_chain->fmt_out; + + /* */ + filter_t *p_last = (filter_t*)p_chain->filters.pp_elems[p_chain->filters.i_count-1]; + + return &p_last->fmt_out; } /** * Apply the filter chain */ + +/* FIXME This include is needed by the Ugly hack */ +#include + picture_t *filter_chain_VideoFilter( filter_chain_t *p_chain, picture_t *p_pic ) { int i; @@ -284,9 +361,12 @@ picture_t *filter_chain_VideoFilter( filter_chain_t *p_chain, picture_t *p_pic ) for( i = 0; i < p_chain->filters.i_count; i++ ) { filter_t *p_filter = pp_filter[i]; - p_pic = p_filter->pf_video_filter( p_filter, p_pic ); - if( !p_pic ) + picture_t *p_newpic = p_filter->pf_video_filter( p_filter, p_pic ); + + if( !p_newpic ) return NULL; + + p_pic = p_newpic; } return p_pic; } @@ -315,8 +395,74 @@ void filter_chain_SubFilter( filter_chain_t *p_chain, for( i = 0; i < p_chain->filters.i_count; i++ ) { filter_t *p_filter = pp_filter[i]; - subpicture_t *p_subpic = p_filter->pf_sub_filter( p_filter, display_date ); + subpicture_t *p_subpic = p_filter->pf_sub_filter( p_filter, + display_date ); if( p_subpic ) spu_DisplaySubpicture( (spu_t*)p_chain->p_this, p_subpic ); } } + +/** + * Internal chain buffer handling + */ + +/** + * 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" ) ) + { + /** + * 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. + */ + int i; + filter_t **pp_filter = (filter_t **)p_chain->filters.pp_elems; + filter_t *p_filter; + for( i = 0; i < p_chain->filters.i_count - 1; i++ ) + { + p_filter = pp_filter[i]; + if( p_filter->pf_vout_buffer_new != VideoBufferNew ) + { + if( p_chain->pf_buffer_allocation_clear ) + p_chain->pf_buffer_allocation_clear( p_filter ); + p_filter->pf_vout_buffer_new = VideoBufferNew; + p_filter->pf_vout_buffer_del = VideoBufferDelete; + } + } + if( p_chain->filters.i_count >= 1 ) + { + p_filter = pp_filter[i]; + if( p_filter->pf_vout_buffer_new == VideoBufferNew ) + { + p_filter->pf_vout_buffer_new = NULL; + p_filter->pf_vout_buffer_del = NULL; + if( p_chain->pf_buffer_allocation_init( p_filter, + p_chain->p_buffer_allocation_data ) != VLC_SUCCESS ) + return VLC_EGENERIC; + } + } + } + return VLC_SUCCESS; +} + +static picture_t *VideoBufferNew( filter_t *p_filter ) +{ + const video_format_t *p_fmt = &p_filter->fmt_out.video; + + picture_t *p_picture = picture_New( p_fmt->i_chroma, + p_fmt->i_width, p_fmt->i_height, + p_fmt->i_aspect ); + if( !p_picture ) + msg_Err( p_filter, "Failed to allocate picture\n" ); + return p_picture; +} +static void VideoBufferDelete( filter_t *p_filter, picture_t *p_picture ) +{ + picture_Release( p_picture ); +} +