developing split filter

This forum is about all development around libVLC.
shrieky
New Cone
New Cone
Posts: 4
Joined: 26 Feb 2009 07:58

developing split filter

Postby shrieky » 24 Jun 2009 17:37

Dear all ,

I am trying to develop a split filter which creates a checker pattern over the video. I have taken help from the filters already developed. When I switch on the split framing filter no video is seen. Any help in this regard would be appreciated.

One needs to un-select the overlay video outout in Tools-->Preferences-->video-->Overlay video output (check box).

Code :

/*****************************************************************************
* splitfilter.c : splitfilter image module for vlc
*****************************************************************************
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_vout.h>
#include <math.h>
#include "filter_common.h"

/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Create(vlc_object_t *);
static void Destroy(vlc_object_t *);

static int Init(vout_thread_t *);
static void End(vout_thread_t *);
static int InterlaceBackGroundSurface(vout_thread_t *, picture_t *, picture_t * );
static int CheckerBackGroundSurface( vout_thread_t *, picture_t *, picture_t * );
static void Render(vout_thread_t *, picture_t *);
static int SendEvents(vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void *);


static const char *const pattern_list[] = {
"None","Checker", "Interlace" };
static const char *const pattern_list_text[] = {
N_("None"), N_("Checker"), N_("Interlace")};

#define CFG_PREFIX "splitframing-"
#define i_piccount 10
vlc_module_begin();
set_description(N_("Split Framing video filter"));
set_shortname(N_("Split Framing"));
set_capability("video filter", 0);
set_category(CAT_VIDEO);
set_subcategory(SUBCAT_VIDEO_VFILTER);
#define INTERLACE_TEXT N_("Interlace mode")
#define INTERLACE_LONGTEXT N_("Interlace for playback.")

#define CHECKER_TEXT N_("Checker mode")
#define CHECKER_LONGTEXT N_("Checker playback.")
set_section( N_("Splitframing Settings"),NULL);
add_string( CFG_PREFIX "pattern", "Checker", NULL, CHECKER_TEXT,
CHECKER_LONGTEXT, false );

change_string_list( pattern_list, pattern_list_text, 0 );
#define ALPHA_TEXT N_("alpha-value")
#define ALPHA_LONGTEXT N_("Select the alpha value ")
add_float_with_range( CFG_PREFIX "alpha-value", 1, 0, 1,
NULL, ALPHA_TEXT, ALPHA_LONGTEXT, true );

#define FRAME_TEXT N_("Sub - Frame")
#define FRAME_LONGTEXT N_("Sub Frames")
add_integer_with_range( CFG_PREFIX "frame_k", 1, 1, i_piccount,
NULL, FRAME_TEXT, FRAME_LONGTEXT, true );

#define R_TEXT N_("R value")
#define R_LONGTEXT N_("R value")
add_integer_with_range(CFG_PREFIX "rvalue", 150, 0, 255, NULL, R_TEXT, R_LONGTEXT, true);

#define G_TEXT N_("G value")
#define G_LONGTEXT N_("G value")
add_integer_with_range(CFG_PREFIX "gvalue", 150, 0, 255, NULL, G_TEXT, G_LONGTEXT, true);

#define B_TEXT N_("B value")
#define B_LONGTEXT N_("B value")
add_integer_with_range(CFG_PREFIX "bvalue", 150, 0, 255, NULL, B_TEXT, B_LONGTEXT, true);


set_section( N_("Checker Pattern Settings"),NULL);
#define ROW_TEXT N_("Number of Rows")
#define ROW_LONGTEXT N_("Number of row segments")
add_integer_with_range( CFG_PREFIX "rows", 4, 1, 16,
NULL, ROW_TEXT, ROW_LONGTEXT, true );
#define COL_TEXT N_("Number of Columns")
#define COL_LONGTEXT N_("Number of column segments")
add_integer_with_range( CFG_PREFIX "cols", 4, 1, 16,
NULL, COL_TEXT, COL_LONGTEXT, true );

set_section( N_("Interlace Pattern Settings"),NULL);
#define GAUGE_TEXT N_("Gauge of line")
#define GAUGE_LONGTEXT N_("Gauge of line")
add_integer_with_range( CFG_PREFIX "gauge", 1, 1, 100,
NULL, GAUGE_TEXT, GAUGE_LONGTEXT, true );

add_shortcut("Split Framing");
set_callbacks(Create, Destroy);
vlc_module_end();

static const char *const ppsz_filter_options[] = {
"pattern", "frame_k","rows", "cols", "alpha-value", "gauge","rvalue","gvalue","bvalue",
NULL
};

/*****************************************************************************
* filter_sys_t
*****************************************************************************/
struct vout_sys_t {
vout_thread_t *p_vout;
int i_rows; /* The number of segments along the lines */
int i_cols; /* The number of segments along the pitch*/
float f_alpha; /* The α value to be used in the α-blending */
int i_gauge;
int i_framek;
bool b_toggle;
mtime_t last_date;
uint8_t i_yuvcolor[3];
uint8_t i_rgbcolor[3];

int (*fn_pBg)(vout_thread_t *, picture_t *, picture_t *);
};

/*****************************************************************************
* Create: allocates Wall video thread output method
*****************************************************************************
* This function allocates and initializes a Wall vout method.
* Conversion formula used for the Y'UV planes
*Basic transform
* Y' = 66 * R + 129 * G + 25 * B
* U = -38 * R - 74 * G + 112 * B
* V = 112 * R - 94 * G - 18 * B
*Scale down to 8 bits
* Y' = (Y' + 128) >> 8
* U = (U + 128) >> 8
* V = (V + 128) >> 8
*Shift values
* Y' += 16
* U += 128
* V += 128
*****************************************************************************/
static void RGBtoYUV(vout_thread_t *p_vout)
{
uint64_t i64_y, i64_u, i64_v;

uint8_t i_r, i_g, i_b;
i_r = p_vout->p_sys->i_rgbcolor[0];
i_g = p_vout->p_sys->i_rgbcolor[1];
i_b = p_vout->p_sys->i_rgbcolor[2];

i64_y = 66 * i_r + 129 * i_g + 25 * i_b;
i64_y = (i64_y + 128) >>8;
p_vout->p_sys->i_yuvcolor[0] = i64_y + 16;

i64_u = -38*i_r - 74* i_g + 112 *i_b;
i64_u = ( i64_u + 128) >> 8;
p_vout->p_sys->i_yuvcolor[1] = i64_u + 128;

i64_v = 112*i_r - 94 *i_g - 18 * i_b;
i64_v = (i64_v + 128)>> 8;
p_vout->p_sys->i_yuvcolor[2] = i64_v + 128;
}


/*****************************************************************************
* Control: control facility for the vout (forwards to child vout)
*****************************************************************************/
static int Control(vout_thread_t *p_vout, int i_query, va_list args) {
return vout_vaControl(p_vout->p_sys->p_vout, i_query, args);

}

static int Create(vlc_object_t *p_this)
{
vout_thread_t *p_vout = (vout_thread_t *) p_this;
char *psz_pattern;
/* Allocate structure */
p_vout->p_sys = malloc(sizeof(vout_sys_t));
if (p_vout->p_sys == NULL)
return VLC_ENOMEM;

p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = NULL;
p_vout->pf_control = Control;
p_vout->pf_render = Render;
p_vout->pf_display = NULL;

config_ChainParse(p_vout, CFG_PREFIX, ppsz_filter_options,
p_vout->p_cfg);

if( !(psz_pattern=
var_CreateGetNonEmptyStringCommand( p_vout, CFG_PREFIX "pattern" )) )
{
msg_Err( p_vout, "configuration variable "
CFG_PREFIX "Pattern empty" );

/*Edited by Srikanth */
p_vout->p_sys->fn_pBg = NULL;
//p_vout->p_sys->fn_pBg = CheckerBackGroundSurface;
/***************************/
}
else
{
if( !strcmp( psz_pattern, "Checker" ) )
{
p_vout->p_sys->fn_pBg = CheckerBackGroundSurface;

}
else if( !strcmp( psz_pattern, "Interlace" ) )
{
p_vout->p_sys->fn_pBg = InterlaceBackGroundSurface;

}
else if( !strcmp( psz_pattern, "None" ) )
{
p_vout->p_sys->fn_pBg = NULL;

}
else
{
msg_Err( p_vout, "no valid gradient mode provided (%s)", psz_pattern );
/*Edited by Srikanth */
p_vout->p_sys->fn_pBg = NULL;
//p_vout->p_sys->fn_pBg = CheckerBackGroundSurface;
}
}
free( psz_pattern );

/* The α value to be used in the α-blending */
/* The number of segments along the lines */
p_vout->p_sys->i_rows = var_CreateGetInteger( p_vout, CFG_PREFIX "rows" );
/* The number of segments along the pitch*/
p_vout->p_sys->i_cols = var_CreateGetInteger( p_vout, CFG_PREFIX "cols" );
p_vout->p_sys->i_gauge = var_CreateGetInteger( p_vout, CFG_PREFIX "gauge" );
p_vout->p_sys->f_alpha = var_CreateGetFloat( p_vout, CFG_PREFIX "alpha-value" );
p_vout->p_sys->i_framek = var_CreateGetInteger( p_vout, CFG_PREFIX "frame_k" );
p_vout->p_sys->i_rgbcolor[0] = var_CreateGetInteger( p_vout, CFG_PREFIX "rvalue");
p_vout->p_sys->i_rgbcolor[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "gvalue");
p_vout->p_sys->i_rgbcolor[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bvalue");

RGBtoYUV( p_vout );


p_vout->p_sys->last_date = 0;
p_vout->p_sys->b_toggle = false;
return VLC_SUCCESS;
}

static int Init(vout_thread_t *p_vout) {
picture_t *p_pic;
int i_index = 0;
video_format_t fmt;

memset(&fmt, 0, sizeof (video_format_t));
I_OUTPUTPICTURES = 0;

/* Initialize the output structure */
p_vout->output.i_chroma = p_vout->render.i_chroma;
p_vout->output.i_width = p_vout->render.i_width;
p_vout->output.i_height = p_vout->render.i_height;
p_vout->output.i_aspect = p_vout->render.i_aspect;


p_vout->fmt_out = p_vout->fmt_in;


/* Try to open the real video output */
msg_Dbg(p_vout, "spawning the real video output");
fmt = p_vout->fmt_out;
p_vout->p_sys->p_vout = vout_Create(p_vout, &fmt);

/* Everything failed */
if (p_vout->p_sys->p_vout == NULL) {
msg_Err(p_vout, "cannot open vouts, aborting");
return VLC_EGENERIC;
}
ADD_CALLBACKS(p_vout->p_sys->p_vout, SendEvents);
ALLOCATE_DIRECTBUFFERS(VOUT_MAX_PICTURES);

ADD_PARENT_CALLBACKS(SendEventsToChild);
return VLC_SUCCESS;
}

/*****************************************************************************
* End: terminate Wall video thread output method
*****************************************************************************/
static void End(vout_thread_t *p_vout) {
int i_index;


/* Free the fake output buffers we allocated */
for (i_index = I_OUTPUTPICTURES; i_index;) {
i_index--;
free(PP_OUTPUTPICTURE[ i_index ]->p_data_orig);
}
DEL_PARENT_CALLBACKS(SendEventsToChild);
DEL_CALLBACKS(p_vout->p_sys->p_vout, SendEvents);
vout_CloseAndRelease(p_vout->p_sys->p_vout);

}

/*****************************************************************************
* Destroy: destroy Wall video thread output method
*****************************************************************************
* Terminate an output method created by WallCreateOutputMethod
*****************************************************************************/
static void Destroy(vlc_object_t *p_this) {
vout_thread_t *p_vout = (vout_thread_t *) p_this;
free(p_vout->p_sys);
}



/*****************************************************************************
* RenderPlanarYUV: displays previously rendered output
*****************************************************************************
* This function send the currently rendered image to Wall image, waits
* until it is displayed and switch the two rendering buffers, preparing next
* frame.
*****************************************************************************/

static void Render(vout_thread_t *p_vout, picture_t *p_pic) {
picture_t * pp_outpic[i_piccount] = {NULL};
int i_pic=0;
vout_sys_t *p_sys = p_vout->p_sys;
int i_outpics = p_sys->i_framek;

for ( int i_pic=0; i_pic<=i_outpics; i_pic++)
{
while ((pp_outpic[i_pic] =
vout_CreatePicture(p_vout->p_sys->p_vout, 0, 0, 0)
) == NULL)
{
if (!vlc_object_alive(p_vout) || p_vout->b_error)
{
vout_DestroyPicture(
p_vout->p_sys->p_vout, pp_outpic[i_pic]);
msg_Err(p_vout, "KRG:: Displaying number %d ERROr", i_pic);
return;
}

msleep(VOUT_OUTMEM_SLEEP);
}
}
pp_outpic[0]->date = p_pic->date;
if (!p_vout->p_sys->last_date)
{
for ( int i=1; i<=i_outpics; i++ )
{
pp_outpic->date = pp_outpic[i-1]->date + 20000/p_sys->i_framek;
}
}
else
{
for ( int i=1; i<=i_outpics; i++ )
{
pp_outpic->date = pp_outpic[i-1]->date +
( pp_outpic[i-1]->date - p_vout->p_sys->last_date )/
(p_sys->i_framek + 1);
}
}
p_vout->p_sys->last_date = p_pic->date;

for (i_pic =0; i_pic<= i_outpics; i_pic++)
{
vout_LinkPicture(p_vout->p_sys->p_vout, pp_outpic[i_pic]);
}

for (i_pic=0; i_pic<= i_outpics; i_pic++)
{
p_vout->p_sys->b_toggle = (p_vout->p_sys->b_toggle == false) ? true : false;
if ( p_vout->p_sys->fn_pBg != NULL )
p_vout->p_sys->fn_pBg(p_vout, pp_outpic[i_pic], p_pic);
else
picture_Copy( pp_outpic[i_pic], p_pic );
vout_UnlinkPicture(p_vout->p_sys->p_vout, pp_outpic[i_pic]);
vout_DisplayPicture(p_vout->p_sys->p_vout, pp_outpic[i_pic]);

}

}

static int SendEvents(vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data) {
VLC_UNUSED(p_this);
VLC_UNUSED(oldval);
var_Set((vlc_object_t *) p_data, psz_var, newval);

return VLC_SUCCESS;
}

/*****************************************************************************
* SendEventsToChild: forward events to the child/children vout
****************************************************************************/
static int SendEventsToChild(vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data) {
VLC_UNUSED(p_data);
VLC_UNUSED(oldval);
vout_thread_t *p_vout = (vout_thread_t *) p_this;
var_Set(p_vout->p_sys->p_vout, psz_var, newval);
return VLC_SUCCESS;
}


static int CheckerBackGroundSurface( vout_thread_t *p_vout,
picture_t *p_outpic ,
picture_t* p_pic)
{
int i_plane;

int i_row=0, i_col=0; /* # of screen lines
and pitch count*/
int i_rowOff=0, i_colOff=0; /* # of subregion lines
and pitch count*/
const int i_lineSegs = p_vout->p_sys->i_rows; /* # of lines for the subregion */
const int i_pitchSegs = p_vout->p_sys->i_cols; /* # of columns for the subregion */

uint8_t i_fragpitch = 0; /* Pitch of the subregion */
uint8_t i_fragline = 0; /* Lines in a subregion*/

bool b_toggle = p_vout->p_sys->b_toggle;
const float f_alpha = p_vout->p_sys->f_alpha;
const float f_alpha_= 1.0 - f_alpha;
/* Loop-0 though all the planes*/

for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
{
uint8_t *p_out, *p_in ; /* Refrence to the p_outpic*/
const int i_pitch = p_outpic->p[i_plane].i_pitch;
const int i_lines = p_outpic->p[i_plane].i_lines;
const int i_visible_pitch = p_outpic->p[i_plane].i_visible_pitch;
const int i_visible_lines = p_outpic->p[i_plane].i_visible_lines;
//msg_Dbg(p_vout,"KRG:::plane=%d, pitch=%d, v_p=%d, line=%d, v_lines=%d time=%llu", i_plane, i_pitch,i_visible_pitch,i_lines,i_visible_lines, p_pic->date);
/* Get the start address of the plane surface*/
p_out = p_outpic->p[i_plane].p_pixels;
p_in = p_pic->p[i_plane].p_pixels;

/* Calculate the subregion dimensions
* in terms of pitch and number of lines */
i_fragline = ( int )( i_visible_lines / i_lineSegs );
i_fragpitch = ( int )( i_visible_pitch / i_pitchSegs );

/* Loop-1 through the line segments of the display*/
for ( i_row = 0; i_row < i_lineSegs; i_row++ )
{
/* Save the offset in temp value. saves some CPU cycles */
const int i_row_pitch_offset = i_row * i_pitch * i_fragline;
/* Loop-2 through the pitch segments of the display */
for ( i_col = 0; i_col < i_pitchSegs; i_col++ )
{
/* Save the offset in temp value. saves some CPU cycles */
const int i_col_pitch_offset = i_col * i_fragpitch +
i_row_pitch_offset;
int i_paintloc = (i_row + i_col) % 2;
bool b_paint = (b_toggle)? i_paintloc?true:false:i_paintloc?false:true;
/* Loop-3 through the row lines of the row segment*/
for ( i_rowOff = 0; i_rowOff < i_fragline; i_rowOff++ )
{
/* Save the offset in temp value. saves some CPU cycles */
const int i_row_offset = i_rowOff * i_pitch +
i_col_pitch_offset;
/* Loop-4 through the pitch of the pitch segment*/
for ( i_colOff = 0; i_colOff < i_fragpitch; i_colOff++ )
{
/* Fill White colour */
p_out[ i_row_offset +
i_colOff ]
= ( b_paint ) ? f_alpha_ * (p_vout->p_sys->i_yuvcolor[i_plane])
+ f_alpha * (p_in [ i_row_offset + i_colOff ]) :
p_in[ i_row_offset + i_colOff ];
}/* End of Loop-4 */
}/* End of Loop-3 */
}/* End of Loop-2 */
}/* End of Loop-1 */
}/* End of Loop-0 */


}

#define PIXEL_DATA(X) (b_paint)?f_alpha_ * (p_vout->p_sys->i_yuvcolor[X]) \
+ f_alpha * (*p_in++):*p_in++


static int InterlaceBackGroundSurface(vout_thread_t *p_vout,
picture_t *p_outpic, picture_t *p_pic)
{
uint8_t *p_in, *p_in_v, *p_in_end, *p_line_end;
uint8_t *p_out, *p_out_v;
bool b_toggle = p_vout->p_sys->b_toggle;
const float f_alpha = p_vout->p_sys->f_alpha;
const float f_alpha_= 1.0 - f_alpha;
int i_loc=0, i_gauge=0;
for (int i_plane=0; i_plane<p_pic->i_planes; i_plane++)
{
p_in = p_pic->p[i_plane].p_pixels;
p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
* p_pic->p[i_plane].i_pitch - 8;

p_out = p_outpic->p[i_plane].p_pixels;

for( ; p_in < p_in_end ; )
{
p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch - 8;
int i_paintloc = ( i_loc ) % 2;
bool b_paint = (b_toggle == true) ? i_paintloc ? true : false : i_paintloc ? false : true;
for( ; p_in < p_line_end ; )
{
/* Do 8 pixels at a time */
*p_out++ = PIXEL_DATA(i_plane); *p_out++ = PIXEL_DATA(i_plane);
*p_out++ = PIXEL_DATA(i_plane); *p_out++ = PIXEL_DATA(i_plane);
*p_out++ = PIXEL_DATA(i_plane); *p_out++ = PIXEL_DATA(i_plane);
*p_out++ = PIXEL_DATA(i_plane); *p_out++ = PIXEL_DATA(i_plane);
}

p_line_end += 8;

for( ; p_in < p_line_end ; )
{
*p_out++ = PIXEL_DATA(i_plane);
}

p_in += p_pic->p[i_plane].i_pitch
- p_pic->p[i_plane].i_visible_pitch;
p_out += p_outpic->p[i_plane].i_pitch
- p_outpic->p[i_plane].i_visible_pitch;
if (++i_gauge >= p_vout->p_sys->i_gauge)
{
i_gauge=0;
i_loc++;
}
}
}
}

Rémi Denis-Courmont
Developer
Developer
Posts: 15279
Joined: 07 Jun 2004 16:01
VLC version: master
Operating System: Linux
Contact:

Re: developing split filter

Postby Rémi Denis-Courmont » 24 Jun 2009 19:46

I cannot promise anything but for development inside rather than around VLC, it is usually best to talk on the vlc-devel ML. Also, it is painful to read unindented code.
Rémi Denis-Courmont
https://www.remlab.net/
Private messages soliciting support will be systematically discarded

shrieky
New Cone
New Cone
Posts: 4
Joined: 26 Feb 2009 07:58

Re: developing split filter

Postby shrieky » 24 Jun 2009 20:59

Dear Rémi Denis-Courmont,

Could you please guide where to post this. And I would not mind uploading the code at some external site if you would like to look into the problem.

Regards,
Shrieky

Rémi Denis-Courmont
Developer
Developer
Posts: 15279
Joined: 07 Jun 2004 16:01
VLC version: master
Operating System: Linux
Contact:

Re: developing split filter

Postby Rémi Denis-Courmont » 25 Jun 2009 16:53

vlc dash devel at videolan dot org
Rémi Denis-Courmont
https://www.remlab.net/
Private messages soliciting support will be systematically discarded


Return to “Development around libVLC”

Who is online

Users browsing this forum: No registered users and 50 guests