1 /*****************************************************************************
2 * distort.c : Misc video effects plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: distort.c,v 1.17 2002/07/20 18:01:42 sam Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
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
41 /*****************************************************************************
42 * Capabilities defined in the other files.
43 *****************************************************************************/
44 static void vout_getfunctions( function_list_t * p_function_list );
46 /*****************************************************************************
47 * Build configuration tree.
48 *****************************************************************************/
49 #define MODE_TEXT N_("Distort mode")
50 #define MODE_LONGTEXT N_("one of \"wave\" and \"ripple\"")
52 static char *mode_list[] = { "wave", "ripple", NULL };
55 ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL )
56 ADD_STRING_FROM_LIST( "distort-mode", "wave", mode_list, NULL, MODE_TEXT, MODE_LONGTEXT )
60 SET_DESCRIPTION( _("miscellaneous video effects module") )
61 /* Capability score set to 0 because we don't want to be spawned
62 * as a video output unless explicitly requested to */
63 ADD_CAPABILITY( VOUT_FILTER, 0 )
64 ADD_SHORTCUT( "distort" )
68 vout_getfunctions( &p_module->p_functions->vout );
71 MODULE_DEACTIVATE_START
72 MODULE_DEACTIVATE_STOP
74 /*****************************************************************************
75 * vout_sys_t: Distort video output method descriptor
76 *****************************************************************************
77 * This structure is part of the video output thread descriptor.
78 * It describes the Distort specific properties of an output thread.
79 *****************************************************************************/
83 vout_thread_t *p_vout;
85 /* For the wave mode */
90 /*****************************************************************************
92 *****************************************************************************/
93 static int vout_Create ( vout_thread_t * );
94 static int vout_Init ( vout_thread_t * );
95 static void vout_End ( vout_thread_t * );
96 static void vout_Destroy ( vout_thread_t * );
97 static int vout_Manage ( vout_thread_t * );
98 static void vout_Render ( vout_thread_t *, picture_t * );
99 static void vout_Display ( vout_thread_t *, picture_t * );
101 static void DistortWave ( vout_thread_t *, picture_t *, picture_t * );
102 static void DistortRipple ( vout_thread_t *, picture_t *, picture_t * );
104 /*****************************************************************************
105 * Functions exported as capabilities. They are declared as static so that
106 * we don't pollute the namespace too much.
107 *****************************************************************************/
108 static void vout_getfunctions( function_list_t * p_function_list )
110 p_function_list->functions.vout.pf_create = vout_Create;
111 p_function_list->functions.vout.pf_init = vout_Init;
112 p_function_list->functions.vout.pf_end = vout_End;
113 p_function_list->functions.vout.pf_destroy = vout_Destroy;
114 p_function_list->functions.vout.pf_manage = vout_Manage;
115 p_function_list->functions.vout.pf_render = vout_Render;
116 p_function_list->functions.vout.pf_display = vout_Display;
119 /*****************************************************************************
120 * vout_Create: allocates Distort video thread output method
121 *****************************************************************************
122 * This function allocates and initializes a Distort vout method.
123 *****************************************************************************/
124 static int vout_Create( vout_thread_t *p_vout )
126 char *psz_method, *psz_method_tmp;
128 /* Allocate structure */
129 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
130 if( p_vout->p_sys == NULL )
132 msg_Err( p_vout, "out of memory" );
135 p_vout->p_sys->i_mode = 0;
136 /* Look what method was requested from command line*/
137 if( !(psz_method = psz_method_tmp = config_GetPsz( p_vout, "filter" )) )
139 msg_Err( p_vout, "configuration variable %s empty", "filter" );
142 while( *psz_method && *psz_method != ':' )
147 if( !strcmp( psz_method, ":wave" ) )
149 p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
151 else if( !strcmp( psz_method, ":ripple" ) )
153 p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE;
155 free( psz_method_tmp );
156 if( !p_vout->p_sys->i_mode )
158 /* No method given in commandline. Look what method was
159 requested in configuration system */
160 if( !(psz_method = psz_method_tmp
161 = config_GetPsz( p_vout, "distort_mode" )) )
163 msg_Err( p_vout, "configuration variable %s empty, using 'wave'",
165 p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
169 if( !strcmp( psz_method, "wave" ) )
171 p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
173 else if( !strcmp( psz_method, "ripple" ) )
175 p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE;
180 msg_Err( p_vout, "no valid distort mode provided, "
182 p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
186 free( psz_method_tmp );
191 /*****************************************************************************
192 * vout_Init: initialize Distort video thread output method
193 *****************************************************************************/
194 static int vout_Init( vout_thread_t *p_vout )
199 I_OUTPUTPICTURES = 0;
201 /* Initialize the output structure */
202 p_vout->output.i_chroma = p_vout->render.i_chroma;
203 p_vout->output.i_width = p_vout->render.i_width;
204 p_vout->output.i_height = p_vout->render.i_height;
205 p_vout->output.i_aspect = p_vout->render.i_aspect;
207 /* Try to open the real video output */
208 msg_Dbg( p_vout, "spawning the real video output" );
210 p_vout->p_sys->p_vout =
211 vout_CreateThread( p_vout,
212 p_vout->render.i_width, p_vout->render.i_height,
213 p_vout->render.i_chroma, p_vout->render.i_aspect );
215 /* Everything failed */
216 if( p_vout->p_sys->p_vout == NULL )
218 msg_Err( p_vout, "cannot open vout, aborting" );
223 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
225 p_vout->p_sys->f_angle = 0.0;
226 p_vout->p_sys->last_date = 0;
231 /*****************************************************************************
232 * vout_End: terminate Distort video thread output method
233 *****************************************************************************/
234 static void vout_End( vout_thread_t *p_vout )
238 /* Free the fake output buffers we allocated */
239 for( i_index = I_OUTPUTPICTURES ; i_index ; )
242 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
246 /*****************************************************************************
247 * vout_Destroy: destroy Distort video thread output method
248 *****************************************************************************
249 * Terminate an output method created by DistortCreateOutputMethod
250 *****************************************************************************/
251 static void vout_Destroy( vout_thread_t *p_vout )
253 vout_DestroyThread( p_vout->p_sys->p_vout );
255 free( p_vout->p_sys );
258 /*****************************************************************************
259 * vout_Manage: handle Distort events
260 *****************************************************************************
261 * This function should be called regularly by video output thread. It manages
262 * console events. It returns a non null value on error.
263 *****************************************************************************/
264 static int vout_Manage( vout_thread_t *p_vout )
269 /*****************************************************************************
270 * vout_Render: displays previously rendered output
271 *****************************************************************************
272 * This function send the currently rendered image to Distort image, waits
273 * until it is displayed and switch the two rendering buffers, preparing next
275 *****************************************************************************/
276 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
280 /* This is a new frame. Get a structure from the video_output. */
281 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
284 if( p_vout->b_die || p_vout->b_error )
288 msleep( VOUT_OUTMEM_SLEEP );
291 vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
293 switch( p_vout->p_sys->i_mode )
295 case DISTORT_MODE_WAVE:
296 DistortWave( p_vout, p_pic, p_outpic );
299 case DISTORT_MODE_RIPPLE:
300 DistortRipple( p_vout, p_pic, p_outpic );
307 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
310 /*****************************************************************************
311 * vout_Display: displays previously rendered output
312 *****************************************************************************
313 * This function send the currently rendered image to Invert image, waits
314 * until it is displayed and switch the two rendering buffers, preparing next
316 *****************************************************************************/
317 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
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;
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_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 = (double)(p_inpic->p[i_index].i_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_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_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_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;
409 black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
411 i_num_lines = p_inpic->p[i_index].i_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 p_vout->p_vlc->pf_memcpy( p_out, p_in,
419 i_first_line * p_inpic->p[i_index].i_pitch );
421 p_in += i_first_line * p_inpic->p[i_index].i_pitch;
422 p_out += i_first_line * p_outpic->p[i_index].i_pitch;
424 /* Ok, we do 3 times the sin() calculation for each line. So what ? */
425 for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ )
427 /* Calculate today's offset, don't go above 1/20th of the screen */
428 i_offset = (double)(p_inpic->p[i_index].i_pitch)
429 * sin( f_angle + 2.0 * (double)i_line
430 / (double)( 1 + i_line
432 * (double)(i_line - i_first_line)
433 / (double)i_num_lines
440 p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset,
441 p_inpic->p[i_index].i_pitch + i_offset );
442 p_in -= p_inpic->p[i_index].i_pitch;
443 p_out += p_outpic->p[i_index].i_pitch;
444 memset( p_out + i_offset, black_pixel, -i_offset );
448 p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in,
449 p_inpic->p[i_index].i_pitch - i_offset );
450 memset( p_out, black_pixel, i_offset );
451 p_in -= p_inpic->p[i_index].i_pitch;
452 p_out += p_outpic->p[i_index].i_pitch;
457 p_vout->p_vlc->pf_memcpy( p_out, p_in,
458 p_inpic->p[i_index].i_pitch );
459 p_in -= p_inpic->p[i_index].i_pitch;
460 p_out += p_outpic->p[i_index].i_pitch;