]> git.sesse.net Git - vlc/blob - plugins/filter/distort.c
* ALL: got rid of *_Probe functions because most of them were duplicates
[vlc] / plugins / filter / distort.c
1 /*****************************************************************************
2  * distort.c : Misc video effects plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: distort.c,v 1.7 2002/02/15 13:32:53 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
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.
13  * 
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30
31 #include <math.h>                                            /* sin(), cos() */
32
33 #include <videolan/vlc.h>
34
35 #include "video.h"
36 #include "video_output.h"
37
38 #include "filter_common.h"
39
40 #define DISTORT_MODE_WAVE    1
41 #define DISTORT_MODE_RIPPLE  2
42
43 /*****************************************************************************
44  * Capabilities defined in the other files.
45  *****************************************************************************/
46 static void vout_getfunctions( function_list_t * p_function_list );
47
48 /*****************************************************************************
49  * Build configuration tree.
50  *****************************************************************************/
51 MODULE_CONFIG_START
52 MODULE_CONFIG_STOP
53
54 MODULE_INIT_START
55     SET_DESCRIPTION( "miscellaneous video effects module" )
56     /* Capability score set to 0 because we don't want to be spawned
57      * as a video output unless explicitly requested to */
58     ADD_CAPABILITY( VOUT, 0 )
59     ADD_SHORTCUT( "distort" )
60 MODULE_INIT_STOP
61
62 MODULE_ACTIVATE_START
63     vout_getfunctions( &p_module->p_functions->vout );
64 MODULE_ACTIVATE_STOP
65
66 MODULE_DEACTIVATE_START
67 MODULE_DEACTIVATE_STOP
68
69 /*****************************************************************************
70  * vout_sys_t: Distort video output method descriptor
71  *****************************************************************************
72  * This structure is part of the video output thread descriptor.
73  * It describes the Distort specific properties of an output thread.
74  *****************************************************************************/
75 typedef struct vout_sys_s
76 {
77     int i_mode;
78     struct vout_thread_s *p_vout;
79
80     /* For the wave mode */
81     double  f_angle;
82     mtime_t last_date;
83
84 } vout_sys_t;
85
86 /*****************************************************************************
87  * Local prototypes
88  *****************************************************************************/
89 static int  vout_Create    ( struct vout_thread_s * );
90 static int  vout_Init      ( struct vout_thread_s * );
91 static void vout_End       ( struct vout_thread_s * );
92 static void vout_Destroy   ( struct vout_thread_s * );
93 static int  vout_Manage    ( struct vout_thread_s * );
94 static void vout_Render    ( struct vout_thread_s *, struct picture_s * );
95 static void vout_Display   ( struct vout_thread_s *, struct picture_s * );
96
97 static void DistortWave    ( struct vout_thread_s *, struct picture_s *,
98                                                      struct picture_s * );
99 static void DistortRipple  ( struct vout_thread_s *, struct picture_s *,
100                                                      struct picture_s * );
101
102 /*****************************************************************************
103  * Functions exported as capabilities. They are declared as static so that
104  * we don't pollute the namespace too much.
105  *****************************************************************************/
106 static void vout_getfunctions( function_list_t * p_function_list )
107 {
108     p_function_list->functions.vout.pf_create     = vout_Create;
109     p_function_list->functions.vout.pf_init       = vout_Init;
110     p_function_list->functions.vout.pf_end        = vout_End;
111     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
112     p_function_list->functions.vout.pf_manage     = vout_Manage;
113     p_function_list->functions.vout.pf_render     = vout_Render;
114     p_function_list->functions.vout.pf_display    = vout_Display;
115 }
116
117 /*****************************************************************************
118  * vout_Create: allocates Distort video thread output method
119  *****************************************************************************
120  * This function allocates and initializes a Distort vout method.
121  *****************************************************************************/
122 static int vout_Create( vout_thread_t *p_vout )
123 {
124     char *psz_method;
125
126     /* Allocate structure */
127     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
128     if( p_vout->p_sys == NULL )
129     {
130         intf_ErrMsg("error: %s", strerror(ENOMEM) );
131         return( 1 );
132     }
133
134     /* Look what method was requested */
135     psz_method = main_GetPszVariable( VOUT_FILTER_VAR, "" );
136
137     while( *psz_method && *psz_method != ':' )
138     {
139         psz_method++;
140     }
141
142     if( !strcmp( psz_method, ":wave" ) )
143     {
144         p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
145     }
146     else if( !strcmp( psz_method, ":ripple" ) )
147     {
148         p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE;
149     }
150     else
151     {
152         intf_ErrMsg( "filter error: no valid distort mode provided, "
153                      "using distort:wave" );
154         p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
155     }
156
157     return( 0 );
158 }
159
160 /*****************************************************************************
161  * vout_Init: initialize Distort video thread output method
162  *****************************************************************************/
163 static int vout_Init( vout_thread_t *p_vout )
164 {
165     int i_index;
166     char *psz_filter;
167     picture_t *p_pic;
168
169     I_OUTPUTPICTURES = 0;
170
171     /* Initialize the output structure */
172     p_vout->output.i_chroma = p_vout->render.i_chroma;
173     p_vout->output.i_width  = p_vout->render.i_width;
174     p_vout->output.i_height = p_vout->render.i_height;
175     p_vout->output.i_aspect = p_vout->render.i_aspect;
176
177     /* Try to open the real video output */
178     psz_filter = main_GetPszVariable( VOUT_FILTER_VAR, "" );
179     main_PutPszVariable( VOUT_FILTER_VAR, "" );
180
181     intf_WarnMsg( 1, "filter: spawning the real video output" );
182
183     p_vout->p_sys->p_vout =
184         vout_CreateThread( NULL,
185                            p_vout->render.i_width, p_vout->render.i_height,
186                            p_vout->render.i_chroma, p_vout->render.i_aspect );
187
188     /* Everything failed */
189     if( p_vout->p_sys->p_vout == NULL )
190     {
191         intf_ErrMsg( "filter error: can't open vout, aborting" );
192
193         return( 0 );
194     }
195  
196     main_PutPszVariable( VOUT_FILTER_VAR, psz_filter );
197
198     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
199
200     p_vout->p_sys->f_angle = 0.0;
201     p_vout->p_sys->last_date = 0;
202
203     return( 0 );
204 }
205
206 /*****************************************************************************
207  * vout_End: terminate Distort video thread output method
208  *****************************************************************************/
209 static void vout_End( vout_thread_t *p_vout )
210 {
211     int i_index;
212
213     /* Free the fake output buffers we allocated */
214     for( i_index = I_OUTPUTPICTURES ; i_index ; )
215     {
216         i_index--;
217         free( PP_OUTPUTPICTURE[ i_index ]->p_data );
218     }
219 }
220
221 /*****************************************************************************
222  * vout_Destroy: destroy Distort video thread output method
223  *****************************************************************************
224  * Terminate an output method created by DistortCreateOutputMethod
225  *****************************************************************************/
226 static void vout_Destroy( vout_thread_t *p_vout )
227 {
228     vout_DestroyThread( p_vout->p_sys->p_vout, NULL );
229
230     free( p_vout->p_sys );
231 }
232
233 /*****************************************************************************
234  * vout_Manage: handle Distort events
235  *****************************************************************************
236  * This function should be called regularly by video output thread. It manages
237  * console events. It returns a non null value on error.
238  *****************************************************************************/
239 static int vout_Manage( vout_thread_t *p_vout )
240 {
241     return( 0 );
242 }
243
244 /*****************************************************************************
245  * vout_Render: displays previously rendered output
246  *****************************************************************************
247  * This function send the currently rendered image to Distort image, waits
248  * until it is displayed and switch the two rendering buffers, preparing next
249  * frame.
250  *****************************************************************************/
251 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
252 {
253     picture_t *p_outpic;
254
255     /* This is a new frame. Get a structure from the video_output. */
256     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
257               == NULL )
258     {
259         if( p_vout->b_die || p_vout->b_error )
260         {
261             return;
262         }
263         msleep( VOUT_OUTMEM_SLEEP );
264     }
265
266     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
267
268     switch( p_vout->p_sys->i_mode )
269     {
270         case DISTORT_MODE_WAVE:
271             DistortWave( p_vout, p_pic, p_outpic );
272             break;
273
274         case DISTORT_MODE_RIPPLE:
275             DistortRipple( p_vout, p_pic, p_outpic );
276             break;
277
278         default:
279             break;
280     }
281
282     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
283 }
284
285 /*****************************************************************************
286  * vout_Display: displays previously rendered output
287  *****************************************************************************
288  * This function send the currently rendered image to Invert image, waits
289  * until it is displayed and switch the two rendering buffers, preparing next
290  * frame.
291  *****************************************************************************/
292 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
293 {
294     ;
295 }
296
297 /*****************************************************************************
298  * DistortWave: draw a wave effect on the picture
299  *****************************************************************************/
300 static void DistortWave( vout_thread_t *p_vout, picture_t *p_inpic,
301                                                 picture_t *p_outpic )
302 {
303     int i_index;
304     double f_angle;
305     mtime_t new_date = mdate();
306
307     p_vout->p_sys->f_angle += (new_date - p_vout->p_sys->last_date) / 200000.0;
308     p_vout->p_sys->last_date = new_date;
309     f_angle = p_vout->p_sys->f_angle;
310
311     for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
312     {
313         int i_line, i_num_lines, i_offset;
314         u8 black_pixel;
315         u8 *p_in, *p_out;
316
317         p_in = p_inpic->p[i_index].p_pixels;
318         p_out = p_outpic->p[i_index].p_pixels;
319
320         i_num_lines = p_inpic->p[i_index].i_lines;
321
322         black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
323
324         /* Ok, we do 3 times the sin() calculation for each line. So what ? */
325         for( i_line = 0 ; i_line < i_num_lines ; i_line++ )
326         {
327             /* Calculate today's offset, don't go above 1/20th of the screen */
328             i_offset = (double)(p_inpic->p[i_index].i_pitch)
329                          * sin( f_angle + 10.0 * (double)i_line
330                                                / (double)i_num_lines )
331                          / 20.0;
332
333             if( i_offset )
334             {
335                 if( i_offset < 0 )
336                 {
337                     FAST_MEMCPY( p_out, p_in - i_offset,
338                                  p_inpic->p[i_index].i_pitch + i_offset );
339                     p_in += p_inpic->p[i_index].i_pitch;
340                     p_out += p_outpic->p[i_index].i_pitch;
341                     memset( p_out + i_offset, black_pixel, -i_offset );
342                 }
343                 else
344                 {
345                     FAST_MEMCPY( p_out + i_offset, p_in,
346                                  p_inpic->p[i_index].i_pitch - i_offset );
347                     memset( p_out, black_pixel, i_offset );
348                     p_in += p_inpic->p[i_index].i_pitch;
349                     p_out += p_outpic->p[i_index].i_pitch;
350                 }
351             }
352             else
353             {
354                 FAST_MEMCPY( p_out, p_in, p_inpic->p[i_index].i_pitch );
355                 p_in += p_inpic->p[i_index].i_pitch;
356                 p_out += p_outpic->p[i_index].i_pitch;
357             }
358
359         }
360     }
361 }
362
363 /*****************************************************************************
364  * DistortRipple: draw a ripple effect at the bottom of the picture
365  *****************************************************************************/
366 static void DistortRipple( vout_thread_t *p_vout, picture_t *p_inpic,
367                                                   picture_t *p_outpic )
368 {
369     int i_index;
370     double f_angle;
371     mtime_t new_date = mdate();
372
373     p_vout->p_sys->f_angle -= (p_vout->p_sys->last_date - new_date) / 100000.0;
374     p_vout->p_sys->last_date = new_date;
375     f_angle = p_vout->p_sys->f_angle;
376
377     for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
378     {
379         int i_line, i_first_line, i_num_lines, i_offset;
380         u8 black_pixel;
381         u8 *p_in, *p_out;
382
383         black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
384
385         i_num_lines = p_inpic->p[i_index].i_lines;
386
387         i_first_line = i_num_lines * 4 / 5;
388
389         p_in = p_inpic->p[i_index].p_pixels;
390         p_out = p_outpic->p[i_index].p_pixels;
391
392         FAST_MEMCPY( p_out, p_in, i_first_line * p_inpic->p[i_index].i_pitch );
393
394         p_in += i_first_line * p_inpic->p[i_index].i_pitch;
395         p_out += i_first_line * p_outpic->p[i_index].i_pitch;
396
397         /* Ok, we do 3 times the sin() calculation for each line. So what ? */
398         for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ )
399         {
400             /* Calculate today's offset, don't go above 1/20th of the screen */
401             i_offset = (double)(p_inpic->p[i_index].i_pitch)
402                          * sin( f_angle + 2.0 * (double)i_line
403                                               / (double)( 1 + i_line
404                                                             - i_first_line) )
405                          * (double)(i_line - i_first_line)
406                          / (double)i_num_lines
407                          / 8.0;
408
409             if( i_offset )
410             {
411                 if( i_offset < 0 )
412                 {
413                     FAST_MEMCPY( p_out, p_in - i_offset,
414                                  p_inpic->p[i_index].i_pitch + i_offset );
415                     p_in -= p_inpic->p[i_index].i_pitch;
416                     p_out += p_outpic->p[i_index].i_pitch;
417                     memset( p_out + i_offset, black_pixel, -i_offset );
418                 }
419                 else
420                 {
421                     FAST_MEMCPY( p_out + i_offset, p_in,
422                                  p_inpic->p[i_index].i_pitch - i_offset );
423                     memset( p_out, black_pixel, i_offset );
424                     p_in -= p_inpic->p[i_index].i_pitch;
425                     p_out += p_outpic->p[i_index].i_pitch;
426                 }
427             }
428             else
429             {
430                 FAST_MEMCPY( p_out, p_in, p_inpic->p[i_index].i_pitch );
431                 p_in -= p_inpic->p[i_index].i_pitch;
432                 p_out += p_outpic->p[i_index].i_pitch;
433             }
434
435         }
436     }
437 }
438