X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=modules%2Fvideo_filter%2Fchain.c;h=6642dd0539ca21dbe41d6218853380328f34d0ce;hb=80676aa4a6833ce7ec4196d6492ea01fd74422b4;hp=359bcb382b018fa1d66a1e26e2713ed6815f5ea9;hpb=6ef09b541a286e0ee1e2e3a313bc22dd6f60da2f;p=vlc diff --git a/modules/video_filter/chain.c b/modules/video_filter/chain.c index 359bcb382b..6642dd0539 100644 --- a/modules/video_filter/chain.c +++ b/modules/video_filter/chain.c @@ -34,59 +34,45 @@ #include /***************************************************************************** - * Local and extern prototypes. + * Module descriptor *****************************************************************************/ -static int Activate ( vlc_object_t * ); -static void Destroy ( vlc_object_t * ); -static picture_t *Chain( filter_t *, picture_t * ); -static int AllocInit( filter_t *p_filter, void *p_data ); +static int Activate ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +vlc_module_begin () + set_description( N_("Video filtering using a chain of video filter modules") ) + set_capability( "video filter2", 1 ) + set_callbacks( Activate, Destroy ) +vlc_module_end () /***************************************************************************** - * Module descriptor + * Local prototypes. *****************************************************************************/ -vlc_module_begin(); - set_description( N_("Video filtering using a chain of video filter modules") ); - set_capability( "video filter2", 1 ); - set_callbacks( Activate, Destroy ); -vlc_module_end(); +static picture_t *Chain ( filter_t *, picture_t * ); +static int BufferAllocationInit ( filter_t *, void * ); -#define MAX_FILTERS 4 +static int BuildChromaResize( filter_t * ); +static int BuildChromaChain( filter_t *p_filter ); -struct filter_sys_t -{ - filter_chain_t *p_chain; -}; +static int CreateChain( filter_chain_t *p_chain, es_format_t *p_fmt_mid, config_chain_t * ); +static void EsFormatMergeSize( es_format_t *p_dst, + const es_format_t *p_base, + const es_format_t *p_size ); static const vlc_fourcc_t pi_allowed_chromas[] = { - VLC_FOURCC('I','4','2','0'), - VLC_FOURCC('I','4','2','2'), - VLC_FOURCC('R','V','3','2'), - VLC_FOURCC('R','V','2','4'), + VLC_CODEC_I420, + VLC_CODEC_I422, + VLC_CODEC_RGB32, + VLC_CODEC_RGB24, 0 }; -static int CreateChain( filter_chain_t *p_chain, es_format_t *p_fmt_mid ) +struct filter_sys_t { - filter_t *p_filter1; - if( !( p_filter1 = - filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, p_fmt_mid )) ) - return VLC_EGENERIC; - if( !filter_chain_AppendFilter( p_chain, NULL, NULL, p_fmt_mid, NULL ) ) - { - filter_chain_DeleteFilter( p_chain, p_filter1 ); - return VLC_EGENERIC; - } - return VLC_SUCCESS; -} + filter_chain_t *p_chain; +}; -static int AllocInit( filter_t *p_filter, void *p_data ) -{ - /* Not sure about all of this ... it should work */ - p_filter->pf_vout_buffer_new = ((filter_t*)p_data)->pf_vout_buffer_new; - p_filter->pf_vout_buffer_del = ((filter_t*)p_data)->pf_vout_buffer_del; - p_filter->p_owner = ((filter_t*)p_data)->p_owner; - return VLC_SUCCESS; -} +#define CHAIN_LEVEL_MAX 1 /***************************************************************************** * Activate: allocate a chroma function @@ -96,86 +82,43 @@ static int AllocInit( filter_t *p_filter, void *p_data ) static int Activate( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; - static int hack = 0; /* FIXME */ - es_format_t fmt_mid; + filter_sys_t *p_sys; + int i_ret; - if( p_filter->fmt_in.video.i_chroma == p_filter->fmt_out.video.i_chroma ) + const bool b_chroma = p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma; + const bool b_resize = p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width || + p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height; + if( !b_chroma && !b_resize ) return VLC_EGENERIC; - hack++; - if( hack >= MAX_FILTERS ) - { - msg_Err( p_this, "Preventing chain filter reccursion (already %d long)", - hack ); - return VLC_EGENERIC; - } - - filter_sys_t *p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) ); + p_sys = p_filter->p_sys = calloc( 1, sizeof( *p_sys ) ); if( !p_sys ) - { - hack--; return VLC_ENOMEM; - } - memset( p_sys, 0, sizeof( filter_sys_t ) ); - p_filter->p_sys = p_sys; - p_sys->p_chain = filter_chain_New( p_filter, "video filter2", false, AllocInit, NULL, p_filter ); + p_sys->p_chain = filter_chain_New( p_filter, "video filter2", false, BufferAllocationInit, NULL, p_filter ); if( !p_sys->p_chain ) { free( p_sys ); return VLC_EGENERIC; } - filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &p_filter->fmt_out ); - - if( p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width || - p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height || - p_filter->fmt_in.video.i_visible_width != p_filter->fmt_out.video.i_visible_width || - p_filter->fmt_in.video.i_visible_height != p_filter->fmt_out.video.i_visible_height ) - { - /* Lets try resizing and then doing the chroma conversion */ - es_format_Copy( &fmt_mid, &p_filter->fmt_out ); - fmt_mid.video.i_chroma = p_filter->fmt_out.video.i_chroma; - if( CreateChain( p_sys->p_chain, &fmt_mid ) == VLC_SUCCESS ) - { - es_format_Clean( &fmt_mid ); - p_filter->pf_video_filter = Chain; - return VLC_SUCCESS; - } - /* Lets try it the other way arround (chroma and then resize) */ - es_format_Clean( &fmt_mid ); - es_format_Copy( &fmt_mid, &p_filter->fmt_in ); - fmt_mid.video.i_chroma = p_filter->fmt_out.video.i_chroma; - if( CreateChain( p_sys->p_chain, &fmt_mid ) == VLC_SUCCESS ) - { - es_format_Clean( &fmt_mid ); - p_filter->pf_video_filter = Chain; - return VLC_SUCCESS; - } - } + if( b_chroma && b_resize ) + i_ret = BuildChromaResize( p_filter ); + else if( b_chroma ) + i_ret = BuildChromaChain( p_filter ); else + i_ret = VLC_EGENERIC; + + if( i_ret ) { - /* Lets try doing a chroma chain */ - int i; - es_format_Copy( &fmt_mid, &p_filter->fmt_in ); - for( i = 0; pi_allowed_chromas[i]; i++ ) - { - fmt_mid.video.i_chroma = pi_allowed_chromas[i]; - if( CreateChain( p_sys->p_chain, &fmt_mid ) == VLC_SUCCESS ) - { - es_format_Clean( &fmt_mid ); - p_filter->pf_video_filter = Chain; - return VLC_SUCCESS; - } - } + /* Hum ... looks like this really isn't going to work. Too bad. */ + filter_chain_Delete( p_sys->p_chain ); + free( p_sys ); + return VLC_EGENERIC; } - - /* Hum ... looks like this really isn't going to work. Too bad. */ - es_format_Clean( &fmt_mid ); - filter_chain_Delete( p_sys->p_chain ); - free( p_sys ); - hack--; - return VLC_EGENERIC; + /* */ + p_filter->pf_video_filter = Chain; + return VLC_SUCCESS; } static void Destroy( vlc_object_t *p_this ) @@ -192,3 +135,157 @@ static picture_t *Chain( filter_t *p_filter, picture_t *p_pic ) { return filter_chain_VideoFilter( p_filter->p_sys->p_chain, p_pic ); } + +/***************************************************************************** + * Builders + *****************************************************************************/ +static int BuildChromaResize( filter_t *p_filter ) +{ + filter_sys_t *p_sys = p_filter->p_sys; + es_format_t fmt_mid; + int i_ret; + + /* Lets try resizing and then doing the chroma conversion */ + filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &p_filter->fmt_out ); + + msg_Dbg( p_filter, "Trying to build resize+chroma" ); + EsFormatMergeSize( &fmt_mid, &p_filter->fmt_in, &p_filter->fmt_out ); + i_ret = CreateChain( p_sys->p_chain, &fmt_mid, NULL ); + es_format_Clean( &fmt_mid ); + if( i_ret == VLC_SUCCESS ) + return VLC_SUCCESS; + + /* Lets try it the other way arround (chroma and then resize) */ + filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &p_filter->fmt_out ); + + msg_Dbg( p_filter, "Trying to build chroma+resize" ); + EsFormatMergeSize( &fmt_mid, &p_filter->fmt_out, &p_filter->fmt_in ); + i_ret = CreateChain( p_sys->p_chain, &fmt_mid, NULL ); + es_format_Clean( &fmt_mid ); + if( i_ret == VLC_SUCCESS ) + return VLC_SUCCESS; + + return VLC_EGENERIC; +} + +static int BuildChromaChain( filter_t *p_filter ) +{ + filter_sys_t *p_sys = p_filter->p_sys; + es_format_t fmt_mid; + + /* We have to protect ourself against a too high recursion */ + const char *psz_option = MODULE_STRING"-level"; + int i_level = 0; + for( const config_chain_t *c = p_filter->p_cfg; c != NULL; c = c->p_next) + { + if( c->psz_name && c->psz_value && !strcmp(c->psz_name, psz_option) ) + { + i_level = atoi(c->psz_value); + if( i_level < 0 || i_level > CHAIN_LEVEL_MAX ) + { + msg_Err( p_filter, "Too high level of recursion (%d)", i_level ); + return VLC_EGENERIC; + } + break; + } + } + + /* */ + int i_ret = VLC_EGENERIC; + + /* */ + config_chain_t cfg_level; + memset(&cfg_level, 0, sizeof(cfg_level)); + cfg_level.psz_name = strdup(psz_option); + if( asprintf( &cfg_level.psz_value, "%d", i_level + 1) < 0 ) + cfg_level.psz_value = NULL; + if( !cfg_level.psz_name || !cfg_level.psz_value ) + goto exit; + + /* Now try chroma format list */ + for( int i = 0; pi_allowed_chromas[i]; i++ ) + { + const vlc_fourcc_t i_chroma = pi_allowed_chromas[i]; + if( i_chroma == p_filter->fmt_in.i_codec || + i_chroma == p_filter->fmt_out.i_codec ) + continue; + + msg_Dbg( p_filter, "Trying to use chroma %4.4s as middle man", + (char*)&i_chroma ); + + es_format_Copy( &fmt_mid, &p_filter->fmt_in ); + fmt_mid.i_codec = + fmt_mid.video.i_chroma = i_chroma; + fmt_mid.video.i_rmask = 0; + fmt_mid.video.i_gmask = 0; + fmt_mid.video.i_bmask = 0; + video_format_FixRgb(&fmt_mid.video); + + filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &p_filter->fmt_out ); + + i_ret = CreateChain( p_sys->p_chain, &fmt_mid, &cfg_level ); + es_format_Clean( &fmt_mid ); + + if( i_ret == VLC_SUCCESS ) + break; + } + +exit: + free( cfg_level.psz_name ); + free( cfg_level.psz_value ); + return i_ret; +} + +/***************************************************************************** + * Buffer management + *****************************************************************************/ +static picture_t *BufferNew( filter_t *p_filter ) +{ + filter_t *p_parent = (filter_t*)p_filter->p_owner; + + return filter_NewPicture( p_parent ); +} +static void BufferDel( filter_t *p_filter, picture_t *p_pic ) +{ + filter_t *p_parent = (filter_t*)p_filter->p_owner; + + return filter_DeletePicture( p_parent, p_pic ); +} +static int BufferAllocationInit ( filter_t *p_filter, void *p_data ) +{ + p_filter->pf_video_buffer_new = BufferNew; + p_filter->pf_video_buffer_del = BufferDel; + p_filter->p_owner = p_data; + return VLC_SUCCESS; +} + +/***************************************************************************** + * + *****************************************************************************/ +static int CreateChain( filter_chain_t *p_chain, es_format_t *p_fmt_mid, config_chain_t *p_cfg ) +{ + filter_t *p_filter1; + if( !( p_filter1 = + filter_chain_AppendFilter( p_chain, NULL, p_cfg, NULL, p_fmt_mid )) ) + return VLC_EGENERIC; + if( !filter_chain_AppendFilter( p_chain, NULL, p_cfg, p_fmt_mid, NULL ) ) + { + filter_chain_DeleteFilter( p_chain, p_filter1 ); + return VLC_EGENERIC; + } + return VLC_SUCCESS; +} + +static void EsFormatMergeSize( es_format_t *p_dst, + const es_format_t *p_base, + const es_format_t *p_size ) +{ + es_format_Copy( p_dst, p_base ); + + p_dst->video.i_width = p_size->video.i_width; + p_dst->video.i_height = p_size->video.i_height; + + p_dst->video.i_visible_width = p_size->video.i_visible_width; + p_dst->video.i_visible_height = p_size->video.i_visible_height; +} +