1 /*****************************************************************************
2 * distort.c : Misc video effects plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 the VideoLAN team
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Antoine Cellerier <dionoea -at- videolan -dot- org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
31 #include <math.h> /* sin(), cos() */
36 #include "filter_common.h"
38 #define DISTORT_MODE_WAVE 1
39 #define DISTORT_MODE_RIPPLE 2
40 #define DISTORT_MODE_GRADIENT 3
41 #define DISTORT_MODE_EDGE 4
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Create ( vlc_object_t * );
47 static void Destroy ( vlc_object_t * );
49 static int Init ( vout_thread_t * );
50 static void End ( vout_thread_t * );
51 static void Render ( vout_thread_t *, picture_t * );
53 static void DistortWave ( vout_thread_t *, picture_t *, picture_t * );
54 static void DistortRipple ( vout_thread_t *, picture_t *, picture_t * );
55 static void DistortGradient( vout_thread_t *, picture_t *, picture_t * );
56 static void DistortEdge ( vout_thread_t *, picture_t *, picture_t * );
58 static int SendEvents ( vlc_object_t *, char const *,
59 vlc_value_t, vlc_value_t, void * );
61 /*****************************************************************************
63 *****************************************************************************/
64 #define MODE_TEXT N_("Distort mode")
65 #define MODE_LONGTEXT N_("Distort mode, one of \"wave\", \"ripple\", \"gradient\" and \"edge\"")
67 #define GRADIENT_TEXT N_("Gradient image type")
68 #define GRADIENT_LONGTEXT N_("Gradient image type (0 or 1)")
70 #define CARTOON_TEXT N_("Apply cartoon effect")
71 #define CARTOON_LONGTEXT N_("Apply cartoon effect. Used by \"gradient\" and \"edge\".")
73 static char *mode_list[] = { "wave", "ripple", "gradient", "edge" };
74 static char *mode_list_text[] = { N_("Wave"), N_("Ripple"), N_("gradient"), N_("Edge") };
77 set_description( _("Distort video filter") );
78 set_shortname( N_( "Distortion" ));
79 set_capability( "video filter", 0 );
80 set_category( CAT_VIDEO );
81 set_subcategory( SUBCAT_VIDEO_VFILTER );
83 add_string( "distort-mode", "wave", NULL, MODE_TEXT, MODE_LONGTEXT,
85 change_string_list( mode_list, mode_list_text, 0 );
87 add_integer_with_range( "distort-gradient-type", 0, 0, 1, NULL,
88 GRADIENT_TEXT, GRADIENT_LONGTEXT, VLC_FALSE );
89 add_bool( "distort-cartoon", 1, NULL,
90 CARTOON_TEXT, CARTOON_LONGTEXT, VLC_FALSE );
92 add_shortcut( "distort" );
93 set_callbacks( Create, Destroy );
96 /*****************************************************************************
97 * vout_sys_t: Distort video output method descriptor
98 *****************************************************************************
99 * This structure is part of the video output thread descriptor.
100 * It describes the Distort specific properties of an output thread.
101 *****************************************************************************/
105 vout_thread_t *p_vout;
107 /* For the wave mode */
111 /* For the gradient mode */
113 vlc_bool_t b_cartoon;
116 /*****************************************************************************
117 * Control: control facility for the vout (forwards to child vout)
118 *****************************************************************************/
119 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
121 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
124 /*****************************************************************************
125 * Create: allocates Distort video thread output method
126 *****************************************************************************
127 * This function allocates and initializes a Distort vout method.
128 *****************************************************************************/
129 static int Create( vlc_object_t *p_this )
131 vout_thread_t *p_vout = (vout_thread_t *)p_this;
132 char *psz_method, *psz_method_tmp;
134 /* Allocate structure */
135 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
136 if( p_vout->p_sys == NULL )
138 msg_Err( p_vout, "out of memory" );
142 p_vout->pf_init = Init;
143 p_vout->pf_end = End;
144 p_vout->pf_manage = NULL;
145 p_vout->pf_render = Render;
146 p_vout->pf_display = NULL;
147 p_vout->pf_control = Control;
149 p_vout->p_sys->i_mode = 0;
151 if( !(psz_method = psz_method_tmp
152 = config_GetPsz( p_vout, "distort-mode" )) )
154 msg_Err( p_vout, "configuration variable %s empty, using 'wave'",
156 p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
161 if( !strcmp( psz_method, "wave" ) )
163 p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
165 else if( !strcmp( psz_method, "ripple" ) )
167 p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE;
169 else if( !strcmp( psz_method, "gradient" ) )
171 p_vout->p_sys->i_mode = DISTORT_MODE_GRADIENT;
173 else if( !strcmp( psz_method, "edge" ) )
175 p_vout->p_sys->i_mode = DISTORT_MODE_EDGE;
179 msg_Err( p_vout, "no valid distort mode provided, "
181 p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
184 free( psz_method_tmp );
186 p_vout->p_sys->i_gradient_type =
187 config_GetInt( p_vout, "distort-gradient-type" );
188 p_vout->p_sys->b_cartoon =
189 config_GetInt( p_vout, "distort-cartoon" );
194 /*****************************************************************************
195 * Init: initialize Distort video thread output method
196 *****************************************************************************/
197 static int Init( vout_thread_t *p_vout )
201 video_format_t fmt = {0};
203 I_OUTPUTPICTURES = 0;
205 /* Initialize the output structure */
206 p_vout->output.i_chroma = p_vout->render.i_chroma;
207 p_vout->output.i_width = p_vout->render.i_width;
208 p_vout->output.i_height = p_vout->render.i_height;
209 p_vout->output.i_aspect = p_vout->render.i_aspect;
210 p_vout->fmt_out = p_vout->fmt_in;
211 fmt = p_vout->fmt_out;
213 /* Try to open the real video output */
214 msg_Dbg( p_vout, "spawning the real video output" );
216 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
218 /* Everything failed */
219 if( p_vout->p_sys->p_vout == NULL )
221 msg_Err( p_vout, "cannot open vout, aborting" );
225 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
227 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
229 ADD_PARENT_CALLBACKS( SendEventsToChild );
231 p_vout->p_sys->f_angle = 0.0;
232 p_vout->p_sys->last_date = 0;
237 /*****************************************************************************
238 * End: terminate Distort video thread output method
239 *****************************************************************************/
240 static void End( vout_thread_t *p_vout )
244 /* Free the fake output buffers we allocated */
245 for( i_index = I_OUTPUTPICTURES ; i_index ; )
248 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
252 /*****************************************************************************
253 * Destroy: destroy Distort video thread output method
254 *****************************************************************************
255 * Terminate an output method created by DistortCreateOutputMethod
256 *****************************************************************************/
257 static void Destroy( vlc_object_t *p_this )
259 vout_thread_t *p_vout = (vout_thread_t *)p_this;
261 if( p_vout->p_sys->p_vout )
263 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
264 vlc_object_detach( p_vout->p_sys->p_vout );
265 vout_Destroy( p_vout->p_sys->p_vout );
268 DEL_PARENT_CALLBACKS( SendEventsToChild );
270 free( p_vout->p_sys );
273 /*****************************************************************************
274 * Render: displays previously rendered output
275 *****************************************************************************
276 * This function send the currently rendered image to Distort image, waits
277 * until it is displayed and switch the two rendering buffers, preparing next
279 *****************************************************************************/
280 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
284 /* This is a new frame. Get a structure from the video_output. */
285 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
288 if( p_vout->b_die || p_vout->b_error )
292 msleep( VOUT_OUTMEM_SLEEP );
295 vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
297 switch( p_vout->p_sys->i_mode )
299 case DISTORT_MODE_WAVE:
300 DistortWave( p_vout, p_pic, p_outpic );
303 case DISTORT_MODE_RIPPLE:
304 DistortRipple( p_vout, p_pic, p_outpic );
307 case DISTORT_MODE_EDGE:
308 DistortEdge( p_vout, p_pic, p_outpic );
311 case DISTORT_MODE_GRADIENT:
312 DistortGradient( p_vout, p_pic, p_outpic );
319 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
322 /*****************************************************************************
323 * DistortWave: draw a wave effect on the picture
324 *****************************************************************************/
325 static void DistortWave( vout_thread_t *p_vout, picture_t *p_inpic,
326 picture_t *p_outpic )
330 mtime_t new_date = mdate();
332 p_vout->p_sys->f_angle += (new_date - p_vout->p_sys->last_date) / 200000.0;
333 p_vout->p_sys->last_date = new_date;
334 f_angle = p_vout->p_sys->f_angle;
336 for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
338 int i_line, i_num_lines, i_offset;
340 uint8_t *p_in, *p_out;
342 p_in = p_inpic->p[i_index].p_pixels;
343 p_out = p_outpic->p[i_index].p_pixels;
345 i_num_lines = p_inpic->p[i_index].i_visible_lines;
347 black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
349 /* Ok, we do 3 times the sin() calculation for each line. So what ? */
350 for( i_line = 0 ; i_line < i_num_lines ; i_line++ )
352 /* Calculate today's offset, don't go above 1/20th of the screen */
353 i_offset = (int)( (double)(p_inpic->p[i_index].i_visible_pitch)
354 * sin( f_angle + 10.0 * (double)i_line
355 / (double)i_num_lines )
362 p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset,
363 p_inpic->p[i_index].i_visible_pitch + i_offset );
364 p_in += p_inpic->p[i_index].i_pitch;
365 p_out += p_outpic->p[i_index].i_pitch;
366 memset( p_out + i_offset, black_pixel, -i_offset );
370 p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in,
371 p_inpic->p[i_index].i_visible_pitch - i_offset );
372 memset( p_out, black_pixel, i_offset );
373 p_in += p_inpic->p[i_index].i_pitch;
374 p_out += p_outpic->p[i_index].i_pitch;
379 p_vout->p_vlc->pf_memcpy( p_out, p_in,
380 p_inpic->p[i_index].i_visible_pitch );
381 p_in += p_inpic->p[i_index].i_pitch;
382 p_out += p_outpic->p[i_index].i_pitch;
389 /*****************************************************************************
390 * DistortRipple: draw a ripple effect at the bottom of the picture
391 *****************************************************************************/
392 static void DistortRipple( vout_thread_t *p_vout, picture_t *p_inpic,
393 picture_t *p_outpic )
397 mtime_t new_date = mdate();
399 p_vout->p_sys->f_angle -= (p_vout->p_sys->last_date - new_date) / 100000.0;
400 p_vout->p_sys->last_date = new_date;
401 f_angle = p_vout->p_sys->f_angle;
403 for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
405 int i_line, i_first_line, i_num_lines, i_offset;
407 uint8_t *p_in, *p_out;
409 black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
411 i_num_lines = p_inpic->p[i_index].i_visible_lines;
413 i_first_line = i_num_lines * 4 / 5;
415 p_in = p_inpic->p[i_index].p_pixels;
416 p_out = p_outpic->p[i_index].p_pixels;
418 for( i_line = 0 ; i_line < i_first_line ; i_line++ )
420 p_vout->p_vlc->pf_memcpy( p_out, p_in,
421 p_inpic->p[i_index].i_visible_pitch );
422 p_in += p_inpic->p[i_index].i_pitch;
423 p_out += p_outpic->p[i_index].i_pitch;
426 /* Ok, we do 3 times the sin() calculation for each line. So what ? */
427 for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ )
429 /* Calculate today's offset, don't go above 1/20th of the screen */
430 i_offset = (int)( (double)(p_inpic->p[i_index].i_pitch)
431 * sin( f_angle + 2.0 * (double)i_line
432 / (double)( 1 + i_line
434 * (double)(i_line - i_first_line)
435 / (double)i_num_lines
442 p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset,
443 p_inpic->p[i_index].i_visible_pitch + i_offset );
444 p_in -= p_inpic->p[i_index].i_pitch;
445 p_out += p_outpic->p[i_index].i_pitch;
446 memset( p_out + i_offset, black_pixel, -i_offset );
450 p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in,
451 p_inpic->p[i_index].i_visible_pitch - i_offset );
452 memset( p_out, black_pixel, i_offset );
453 p_in -= p_inpic->p[i_index].i_pitch;
454 p_out += p_outpic->p[i_index].i_pitch;
459 p_vout->p_vlc->pf_memcpy( p_out, p_in,
460 p_inpic->p[i_index].i_visible_pitch );
461 p_in -= p_inpic->p[i_index].i_pitch;
462 p_out += p_outpic->p[i_index].i_pitch;
469 /*****************************************************************************
470 * DistortGradient: Sobel
471 *****************************************************************************/
472 static void DistortGradient( vout_thread_t *p_vout, picture_t *p_inpic,
473 picture_t *p_outpic )
476 int i_height = p_inpic->format.i_height;
477 int i_width = p_inpic->format.i_width;
479 uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels;
480 uint8_t *p_outpix = p_outpic->p[Y_PLANE].p_pixels;
482 uint32_t p_smooth[ i_height * i_width ];
484 if( p_vout->p_sys->b_cartoon )
486 memcpy( p_outpic->p[U_PLANE].p_pixels, p_inpic->p[U_PLANE].p_pixels,
487 p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
488 memcpy( p_outpic->p[V_PLANE].p_pixels, p_inpic->p[V_PLANE].p_pixels,
489 p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
493 memset( p_outpic->p[U_PLANE].p_pixels, 0x80,
494 p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
495 memset( p_outpic->p[V_PLANE].p_pixels, 0x80,
496 p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
499 /* Gaussian convolution ( sigma == 1.4 )
501 | 2 4 5 4 2 | | 2 4 4 4 2 |
502 | 4 9 12 9 4 | | 4 8 12 8 4 |
503 | 5 12 15 12 5 | ~ | 4 12 16 12 4 |
504 | 4 9 12 9 4 | | 4 8 12 8 4 |
505 | 2 4 5 4 2 | | 2 4 4 4 2 | */
507 for( y = 2; y < i_height - 2; y++ )
509 for( x = 2; x < i_width - 2; x++ )
511 p_smooth[y*i_width+x] = (
513 ( p_inpix[(y-2)*i_width+x-2]<<1 )
514 + ( p_inpix[(y-2)*i_width+x-1]<<2 )
515 + ( p_inpix[(y-2)*i_width+x]<<2 )
516 + ( p_inpix[(y-2)*i_width+x+1]<<2 )
517 + ( p_inpix[(y-2)*i_width+x+2]<<1 )
519 + ( p_inpix[(y-1)*i_width+x-1]<<3 )
520 + ( p_inpix[(y-1)*i_width+x-2]<<2 )
521 + ( p_inpix[(y-1)*i_width+x]*12 )
522 + ( p_inpix[(y-1)*i_width+x+1]<<3 )
523 + ( p_inpix[(y-1)*i_width+x+2]<<2 )
525 + ( p_inpix[y*i_width+x-2]<<2 )
526 + ( p_inpix[y*i_width+x-1]*12 )
527 + ( p_inpix[y*i_width+x]<<4 )
528 + ( p_inpix[y*i_width+x+1]*12 )
529 + ( p_inpix[y*i_width+x+2]<<2 )
531 + ( p_inpix[(y+1)*i_width+x-2]<<2 )
532 + ( p_inpix[(y+1)*i_width+x-1]<<3 )
533 + ( p_inpix[(y+1)*i_width+x]*12 )
534 + ( p_inpix[(y+1)*i_width+x+1]<<3 )
535 + ( p_inpix[(y+1)*i_width+x+2]<<2 )
537 + ( p_inpix[(y+2)*i_width+x-2]<<1 )
538 + ( p_inpix[(y+2)*i_width+x-1]<<2 )
539 + ( p_inpix[(y+2)*i_width+x]<<2 )
540 + ( p_inpix[(y+2)*i_width+x+1]<<2 )
541 + ( p_inpix[(y+2)*i_width+x+2]<<1 )
549 | -2 0 2 | and | 0 0 0 |
550 | -1 0 1 | | -1 -2 -1 | */
552 for( y = 1; y < i_height - 1; y++ )
554 for( x = 1; x < i_width - 1; x++ )
559 ((p_smooth[(y-1)*i_width+x] - p_smooth[(y+1)*i_width+x])<<1)
560 + (p_smooth[(y-1)*i_width+x-1] - p_smooth[(y+1)*i_width+x-1])
561 + (p_smooth[(y-1)*i_width+x+1] - p_smooth[(y+1)*i_width+x+1])
565 ((p_smooth[y*i_width+x-1] - p_smooth[y*i_width+x+1])<<1)
566 + (p_smooth[(y-1)*i_width+x-1] - p_smooth[(y-1)*i_width+x+1])
567 + (p_smooth[(y+1)*i_width+x-1] - p_smooth[(y+1)*i_width+x+1])
570 if( p_vout->p_sys->i_gradient_type )
572 if( p_vout->p_sys->b_cartoon )
576 p_outpix[y*i_width+x] = 0x00;
580 if( p_smooth[y*i_width+x] > 0xa0 )
581 p_outpix[y*i_width+x] =
582 0xff - ((0xff - p_inpix[y*i_width+x] )>>2);
583 else if( p_smooth[y*i_width+x] > 0x70 )
584 p_outpix[y*i_width+x] =
585 0xa0 - ((0xa0 - p_inpix[y*i_width+x] )>>2);
586 else if( p_smooth[y*i_width+x] > 0x28 )
587 p_outpix[y*i_width+x] =
588 0x70 - ((0x70 - p_inpix[y*i_width+x] )>>2);
590 p_outpix[y*i_width+x] =
591 0x28 - ((0x28 - p_inpix[y*i_width+x] )>>2);
597 p_outpix[y*i_width+x] = 255;
599 p_outpix[y*i_width+x] = (uint8_t)a;
605 p_outpix[y*i_width+x] = 0;
607 p_outpix[y*i_width+x] = (uint8_t)(255 - a);
613 /*****************************************************************************
614 * DistortEdge: Canny edge detection algorithm
615 *****************************************************************************
616 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
617 * (well ... my implementation isn't really the canny algorithm ... but some
618 * ideas are the same)
619 *****************************************************************************/
628 static void DistortEdge( vout_thread_t *p_vout, picture_t *p_inpic,
629 picture_t *p_outpic )
633 int i_height = p_inpic->format.i_height;
634 int i_width = p_inpic->format.i_width;
636 uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels;
637 uint8_t *p_outpix = p_outpic->p[Y_PLANE].p_pixels;
639 uint32_t p_smooth[ i_height * i_width ];
640 uint32_t p_grad[ i_height * i_width ];
641 uint8_t p_theta[ i_height * i_width ];
643 if( p_vout->p_sys->b_cartoon )
645 memcpy( p_outpic->p[U_PLANE].p_pixels, p_inpic->p[U_PLANE].p_pixels,
646 p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
647 memcpy( p_outpic->p[V_PLANE].p_pixels, p_inpic->p[V_PLANE].p_pixels,
648 p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
652 memset( p_outpic->p[Y_PLANE].p_pixels, 0xff,
653 p_outpic->p[Y_PLANE].i_lines * p_outpic->p[Y_PLANE].i_pitch );
654 memset( p_outpic->p[U_PLANE].p_pixels, 0x80,
655 p_outpic->p[U_PLANE].i_lines * p_outpic->p[U_PLANE].i_pitch );
656 memset( p_outpic->p[V_PLANE].p_pixels, 0x80,
657 p_outpic->p[V_PLANE].i_lines * p_outpic->p[V_PLANE].i_pitch );
660 /* Gaussian convolution ( sigma == 1.4 )
662 | 2 4 5 4 2 | | 2 4 4 4 2 |
663 | 4 9 12 9 4 | | 4 8 12 8 4 |
664 | 5 12 15 12 5 | ~ | 4 12 16 12 4 |
665 | 4 9 12 9 4 | | 4 8 12 8 4 |
666 | 2 4 5 4 2 | | 2 4 4 4 2 | */
668 for( y = 2; y < i_height - 2; y++ )
670 for( x = 2; x < i_width - 2; x++ )
672 p_smooth[y*i_width+x] = (
674 ( p_inpix[(y-2)*i_width+x-2]<<1 )
675 + ( p_inpix[(y-2)*i_width+x-1]<<2 )
676 + ( p_inpix[(y-2)*i_width+x]<<2 )
677 + ( p_inpix[(y-2)*i_width+x+1]<<2 )
678 + ( p_inpix[(y-2)*i_width+x+2]<<1 )
680 + ( p_inpix[(y-1)*i_width+x-1]<<3 )
681 + ( p_inpix[(y-1)*i_width+x-2]<<2 )
682 + ( p_inpix[(y-1)*i_width+x]*12 )
683 + ( p_inpix[(y-1)*i_width+x+1]<<3 )
684 + ( p_inpix[(y-1)*i_width+x+2]<<2 )
686 + ( p_inpix[y*i_width+x-2]<<2 )
687 + ( p_inpix[y*i_width+x-1]*12 )
688 + ( p_inpix[y*i_width+x]<<4 )
689 + ( p_inpix[y*i_width+x+1]*12 )
690 + ( p_inpix[y*i_width+x+2]<<2 )
692 + ( p_inpix[(y+1)*i_width+x-2]<<2 )
693 + ( p_inpix[(y+1)*i_width+x-1]<<3 )
694 + ( p_inpix[(y+1)*i_width+x]*12 )
695 + ( p_inpix[(y+1)*i_width+x+1]<<3 )
696 + ( p_inpix[(y+1)*i_width+x+2]<<2 )
698 + ( p_inpix[(y+2)*i_width+x-2]<<1 )
699 + ( p_inpix[(y+2)*i_width+x-1]<<2 )
700 + ( p_inpix[(y+2)*i_width+x]<<2 )
701 + ( p_inpix[(y+2)*i_width+x+1]<<2 )
702 + ( p_inpix[(y+2)*i_width+x+2]<<1 )
710 | -2 0 2 | and | 0 0 0 |
711 | -1 0 1 | | -1 -2 -1 | */
713 for( y = 1; y < i_height - 1; y++ )
715 for( x = 1; x < i_width - 1; x++ )
718 ((p_smooth[(y-1)*i_width+x] - p_smooth[(y+1)*i_width+x])<<1)
719 + (p_smooth[(y-1)*i_width+x-1] - p_smooth[(y+1)*i_width+x-1])
720 + (p_smooth[(y-1)*i_width+x+1] - p_smooth[(y+1)*i_width+x+1]);
722 ((p_smooth[y*i_width+x-1] - p_smooth[y*i_width+x+1])<<1)
723 + (p_smooth[(y-1)*i_width+x-1] - p_smooth[(y-1)*i_width+x+1])
724 + (p_smooth[(y+1)*i_width+x-1] - p_smooth[(y+1)*i_width+x+1]);
725 p_grad[y*i_width+x] = abs( gradx ) + abs( grady );
726 /* tan( 22.5 ) = 0,414213562 .. * 128 = 53
727 * tan( 26,565051177 ) = 0.5
728 * tan( 45 + 22.5 ) = 2,414213562 .. * 128 = 309
729 * tan( 63,434948823 ) 2 */
730 if( (grady<<1) > gradx )
731 p_theta[y*i_width+x] = THETA_P;
732 else if( (grady<<1) < -gradx )
733 p_theta[y*i_width+x] = THETA_M;
734 else if( !gradx || abs(grady) > abs(gradx)<<1 )
735 p_theta[y*i_width+x] = THETA_Y;
737 p_theta[y*i_width+x] = THETA_X;
742 for( y = 1; y < i_height - 1; y++ )
744 for( x = 1; x < i_width - 1; x++ )
746 if( p_grad[y*i_width+x] > 40 )
748 switch( p_theta[y*i_width+x] )
751 if( p_grad[y*i_width+x] > p_grad[(y-1)*i_width+x]
752 && p_grad[y*i_width+x] > p_grad[(y+1)*i_width+x] )
754 p_outpix[y*i_width+x] = 0;
755 } else goto colorize;
758 if( p_grad[y*i_width+x] > p_grad[(y-1)*i_width+x-1]
759 && p_grad[y*i_width+x] > p_grad[(y+1)*i_width+x+1] )
761 p_outpix[y*i_width+x] = 0;
762 } else goto colorize;
765 if( p_grad[y*i_width+x] > p_grad[(y-1)*i_width+x+1]
766 && p_grad[y*i_width+x] > p_grad[(y+1)*i_width+x-1] )
768 p_outpix[y*i_width+x] = 0;
769 } else goto colorize;
772 if( p_grad[y*i_width+x] > p_grad[y*i_width+x-1]
773 && p_grad[y*i_width+x] > p_grad[y*i_width+x+1] )
775 p_outpix[y*i_width+x] = 0;
776 } else goto colorize;
783 if( p_vout->p_sys->b_cartoon )
785 if( p_smooth[y*i_width+x] > 0xa0 )
786 p_outpix[y*i_width+x] =
787 0xff - ((0xff - p_inpix[y*i_width+x] )>>2);
788 else if( p_smooth[y*i_width+x] > 0x70 )
789 p_outpix[y*i_width+x] =
790 0xa0 - ((0xa0 - p_inpix[y*i_width+x] )>>2);
791 else if( p_smooth[y*i_width+x] > 0x28 )
792 p_outpix[y*i_width+x] =
793 0x70 - ((0x70 - p_inpix[y*i_width+x] )>>2);
795 p_outpix[y*i_width+x] =
796 0x28 - ((0x28 - p_inpix[y*i_width+x] )>>2);
802 /*****************************************************************************
803 * SendEvents: forward mouse and keyboard events to the parent p_vout
804 *****************************************************************************/
805 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
806 vlc_value_t oldval, vlc_value_t newval, void *p_data )
808 var_Set( (vlc_object_t *)p_data, psz_var, newval );
813 /*****************************************************************************
814 * SendEventsToChild: forward events to the child/children vout
815 *****************************************************************************/
816 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
817 vlc_value_t oldval, vlc_value_t newval, void *p_data )
819 vout_thread_t *p_vout = (vout_thread_t *)p_this;
820 var_Set( p_vout->p_sys->p_vout, psz_var, newval );