Commit 6b7fbfed authored by Antoine Cellerier's avatar Antoine Cellerier

Make "video filter2" filters selectable on the vout level.

Exemple: --video-filter "adjust{hue=180}:wave"
For the moment, the video filter2 filters are applied *before* subpicture filters.
parent 25f65dad
...@@ -55,6 +55,9 @@ typedef struct vout_chroma_t ...@@ -55,6 +55,9 @@ typedef struct vout_chroma_t
} vout_chroma_t; } vout_chroma_t;
/** Maximum numbers of video filters2 that can be attached to a vout */
#define MAX_VFILTERS 10
/** /**
* Video output thread descriptor * Video output thread descriptor
* *
...@@ -150,6 +153,18 @@ struct vout_thread_t ...@@ -150,6 +153,18 @@ struct vout_thread_t
char *psz_filter_chain; char *psz_filter_chain;
vlc_bool_t b_filter_change; vlc_bool_t b_filter_change;
/* Video filter2 chain
* these are handled like in transcode.c
* XXX: we might need to merge the two chains (v1 and v2 filters) */
char *psz_vfilters[MAX_VFILTERS];
sout_cfg_t *p_vfilters_cfg[MAX_VFILTERS];
int i_vfilters_cfg;
filter_t *pp_vfilters[MAX_VFILTERS];
int i_vfilters;
vlc_bool_t b_vfilter_change;
/* Misc */ /* Misc */
vlc_bool_t b_snapshot; /**< take one snapshot on the next loop */ vlc_bool_t b_snapshot; /**< take one snapshot on the next loop */
}; };
......
...@@ -296,12 +296,18 @@ static char *ppsz_align_descriptions[] = ...@@ -296,12 +296,18 @@ static char *ppsz_align_descriptions[] =
"VLC can avoid creating window caption, frames, etc... around the video" \ "VLC can avoid creating window caption, frames, etc... around the video" \
", giving a \"minimal\" window.") ", giving a \"minimal\" window.")
#define FILTER_TEXT N_("Video filter module") #define VOUT_FILTER_TEXT N_("Video output filter module")
#define FILTER_LONGTEXT N_( \ #define VOUT_FILTER_LONGTEXT N_( \
"This adds post-processing filters to enhance the " \ "This adds post-processing filters to enhance the " \
"picture quality, for instance deinterlacing, or to clone or distort " \ "picture quality, for instance deinterlacing, or to clone or distort " \
"the video window.") "the video window.")
#define VIDEO_FILTER_TEXT N_("Video filter module")
#define VIDEO_FILTER_LONGTEXT N_( \
"This adds post-processing filters to enhance the " \
"picture quality, for instance deinterlacing, or distort" \
"the video.")
#define SNAP_PATH_TEXT N_("Video snapshot directory") #define SNAP_PATH_TEXT N_("Video snapshot directory")
#define SNAP_PATH_LONGTEXT N_( \ #define SNAP_PATH_LONGTEXT N_( \
"Directory where the video snapshots will be stored.") "Directory where the video snapshots will be stored.")
...@@ -1286,8 +1292,13 @@ vlc_module_begin(); ...@@ -1286,8 +1292,13 @@ vlc_module_begin();
set_subcategory( SUBCAT_VIDEO_VFILTER ); set_subcategory( SUBCAT_VIDEO_VFILTER );
add_module_list_cat( "vout-filter", SUBCAT_VIDEO_VFILTER, NULL, NULL, add_module_list_cat( "vout-filter", SUBCAT_VIDEO_VFILTER, NULL, NULL,
FILTER_TEXT, FILTER_LONGTEXT, VLC_FALSE ); VOUT_FILTER_TEXT, VOUT_FILTER_LONGTEXT, VLC_FALSE );
add_deprecated( "filter", VLC_FALSE ); /*deprecated since 0.8.2 */ add_deprecated( "filter", VLC_FALSE ); /*deprecated since 0.8.2 */
set_subcategory( SUBCAT_VIDEO_VFILTER2 );
add_module_list_cat( "video-filter", SUBCAT_VIDEO_VFILTER2, NULL, NULL,
VIDEO_FILTER_TEXT, VIDEO_FILTER_LONGTEXT, VLC_FALSE );
#if 0 #if 0
add_string( "pixel-ratio", "1", NULL, PIXEL_RATIO_TEXT, PIXEL_RATIO_TEXT ); add_string( "pixel-ratio", "1", NULL, PIXEL_RATIO_TEXT, PIXEL_RATIO_TEXT );
#endif #endif
......
...@@ -43,6 +43,9 @@ ...@@ -43,6 +43,9 @@
#include <vlc/input.h> /* for input_thread_t and i_pts_delay */ #include <vlc/input.h> /* for input_thread_t and i_pts_delay */
#include "vlc_playlist.h" #include "vlc_playlist.h"
#include "vlc_filter.h"
#include <vlc/sout.h> /* sout_CfgParse */
#if defined( __APPLE__ ) #if defined( __APPLE__ )
#include "darwin_specific.h" #include "darwin_specific.h"
#endif #endif
...@@ -65,10 +68,39 @@ static int DeinterlaceCallback( vlc_object_t *, char const *, ...@@ -65,10 +68,39 @@ static int DeinterlaceCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * ); vlc_value_t, vlc_value_t, void * );
static int FilterCallback( vlc_object_t *, char const *, static int FilterCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * ); vlc_value_t, vlc_value_t, void * );
static int VideoFilter2Callback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
/* From vout_intf.c */ /* From vout_intf.c */
int vout_Snapshot( vout_thread_t *, picture_t * ); int vout_Snapshot( vout_thread_t *, picture_t * );
/* Video filter2 parsing */
static int ParseVideoFilter2Chain( vout_thread_t *, char * );
static void RemoveVideoFilters2( vout_thread_t *p_vout );
/*****************************************************************************
* Video Filter2 functions
*****************************************************************************/
struct filter_owner_sys_t
{
vout_thread_t *p_vout;
};
static picture_t *video_new_buffer_filter( filter_t *p_filter )
{
picture_t *p_picture;
vout_thread_t *p_vout = p_filter->p_owner->p_vout;
p_picture = vout_CreatePicture( p_vout, 0, 0, 0 );
return p_picture;
}
static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
{
vout_DestroyPicture( p_filter->p_owner->p_vout, p_pic );
}
/***************************************************************************** /*****************************************************************************
* vout_Request: find a video output thread, create one, or destroy one. * vout_Request: find a video output thread, create one, or destroy one.
***************************************************************************** *****************************************************************************
...@@ -321,6 +353,13 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) ...@@ -321,6 +353,13 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Get( p_vout, "vout-filter", &val ); var_Get( p_vout, "vout-filter", &val );
p_vout->psz_filter_chain = val.psz_string; p_vout->psz_filter_chain = val.psz_string;
/* Apply video filter2 objects on the first vout */
var_Create( p_vout, "video-filter",
VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Get( p_vout, "video-filter", &val );
ParseVideoFilter2Chain( p_vout, val.psz_string );
free( val.psz_string );
} }
else else
{ {
...@@ -331,8 +370,16 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) ...@@ -331,8 +370,16 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
if( psz_end && *(psz_end+1) ) if( psz_end && *(psz_end+1) )
p_vout->psz_filter_chain = strdup( psz_end+1 ); p_vout->psz_filter_chain = strdup( psz_end+1 );
else p_vout->psz_filter_chain = NULL; else p_vout->psz_filter_chain = NULL;
/* Create a video filter2 var ... but don't inherit values */
var_Create( p_vout, "video-filter", VLC_VAR_STRING );
ParseVideoFilter2Chain( p_vout, NULL );
} }
var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
p_vout->b_vfilter_change = VLC_TRUE;
p_vout->i_vfilters = 0;
/* Choose the video output module */ /* Choose the video output module */
if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain ) if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
{ {
...@@ -900,6 +947,81 @@ static void RunThread( vout_thread_t *p_vout) ...@@ -900,6 +947,81 @@ static void RunThread( vout_thread_t *p_vout)
i_idle_loops++; i_idle_loops++;
} }
/* Video Filter2 stuff */
if( p_vout->b_vfilter_change == VLC_TRUE )
{
int i;
RemoveVideoFilters2( p_vout );
for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
{
filter_t *p_vfilter =
p_vout->pp_vfilters[p_vout->i_vfilters] =
vlc_object_create( p_vout, VLC_OBJECT_FILTER );
vlc_object_attach( p_vfilter, p_vout );
p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
p_vfilter->fmt_in.video = p_vout->fmt_render;
p_vfilter->fmt_out.video = p_vout->fmt_render;
p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
p_vout->psz_vfilters[i], 0 );
if( p_vfilter->p_module )
{
p_vfilter->p_owner =
malloc( sizeof( filter_owner_sys_t ) );
p_vfilter->p_owner->p_vout = p_vout;
p_vout->i_vfilters++;
msg_Dbg( p_vout, "video filter found (%s)",
p_vout->psz_vfilters[i] );
}
else
{
msg_Err( p_vout, "no video filter found (%s)",
p_vout->psz_vfilters[i] );
vlc_object_detach( p_vfilter );
vlc_object_destroy( p_vfilter );
}
}
p_vout->b_vfilter_change = VLC_FALSE;
}
if( p_picture )
{
int i;
for( i = 0; i < p_vout->i_vfilters; i++ )
{
picture_t *p_old = p_picture;
p_picture = p_vout->pp_vfilters[i]->pf_video_filter(
p_vout->pp_vfilters[i], p_picture );
if( !p_picture )
{
break;
}
/* FIXME: this is kind of wrong
* if you have 2 or more vfilters and the 2nd breaks,
* on the next loop the 1st one will be applied again */
/* if p_old and p_picture are the same (ie the filter
* worked on the old picture), then following code is
* still alright since i_status gets changed back to
* the right value */
if( p_old->i_refcount )
{
p_old->i_status = DISPLAYED_PICTURE;
}
else
{
p_old->i_status = DESTROYED_PICTURE;
}
p_picture->i_status = READY_PICTURE;
}
}
if( p_picture && p_vout->b_snapshot ) if( p_picture && p_vout->b_snapshot )
{ {
p_vout->b_snapshot = VLC_FALSE; p_vout->b_snapshot = VLC_FALSE;
...@@ -1130,6 +1252,9 @@ static void EndThread( vout_thread_t *p_vout ) ...@@ -1130,6 +1252,9 @@ static void EndThread( vout_thread_t *p_vout )
spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE ); spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
spu_Destroy( p_vout->p_spu ); spu_Destroy( p_vout->p_spu );
/* Destroy the video filters2 */
RemoveVideoFilters2( p_vout );
/* Destroy translation tables */ /* Destroy translation tables */
p_vout->pf_end( p_vout ); p_vout->pf_end( p_vout );
...@@ -1401,3 +1526,87 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd, ...@@ -1401,3 +1526,87 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/*****************************************************************************
* Video Filter2 stuff
*****************************************************************************/
static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
{
int i;
for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
{
/* FIXME: this should be moved in a separate function */
struct sout_cfg_t *p_cfg =
p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
while( p_cfg )
{
struct sout_cfg_t *p_next = p_cfg->p_next;
free( p_cfg->psz_name );
free( p_cfg->psz_value );
free( p_cfg );
p_cfg = p_next;
}
/* </FIXME> */
free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
}
p_vout->i_vfilters_cfg = 0;
if( psz_vfilters && *psz_vfilters )
{
char *psz_parser = psz_vfilters;
while( psz_parser && *psz_parser )
{
psz_parser = sout_CfgCreate(
&p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
&p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
psz_parser );
msg_Dbg( p_vout, "adding vfilter: %s\n",
p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
p_vout->i_vfilters_cfg++;
if( psz_parser && psz_parser )
{
if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
{
msg_Warn( p_vout,
"maximum number of video filters reached. \"%s\" discarded",
psz_parser );
break;
}
}
}
}
return VLC_SUCCESS;
}
static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
if( !strcmp( oldval.psz_string, newval.psz_string ) )
{
ParseVideoFilter2Chain( p_vout, newval.psz_string );
p_vout->b_vfilter_change = VLC_TRUE;
}
return VLC_SUCCESS;
}
static void RemoveVideoFilters2( vout_thread_t *p_vout )
{
int i;
for( i = 0; i < p_vout->i_vfilters; i++ )
{
vlc_object_detach( p_vout->pp_vfilters[i] );
if( p_vout->pp_vfilters[i]->p_module )
{
module_Unneed( p_vout->pp_vfilters[i],
p_vout->pp_vfilters[i]->p_module );
}
free( p_vout->pp_vfilters[i]->p_owner );
vlc_object_destroy( p_vout->pp_vfilters[i] );
}
p_vout->i_vfilters = 0;
}
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