]> git.sesse.net Git - vlc/blob - plugins/filter/distort.c
bbefa08b570550cb158ccf9aa4326bb0d19fb65a
[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.4 2002/01/02 14:37:42 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_Probe     ( probedata_t *p_data );
90 static int  vout_Create    ( struct vout_thread_s * );
91 static int  vout_Init      ( struct vout_thread_s * );
92 static void vout_End       ( struct vout_thread_s * );
93 static void vout_Destroy   ( struct vout_thread_s * );
94 static int  vout_Manage    ( struct vout_thread_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->pf_probe = vout_Probe;
109     p_function_list->functions.vout.pf_create     = vout_Create;
110     p_function_list->functions.vout.pf_init       = vout_Init;
111     p_function_list->functions.vout.pf_end        = vout_End;
112     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
113     p_function_list->functions.vout.pf_manage     = vout_Manage;
114     p_function_list->functions.vout.pf_display    = vout_Display;
115     p_function_list->functions.vout.pf_setpalette = NULL;
116 }
117
118 /*****************************************************************************
119  * intf_Probe: return a score
120  *****************************************************************************/
121 static int vout_Probe( probedata_t *p_data )
122 {
123     return( 0 );
124 }
125
126 /*****************************************************************************
127  * vout_Create: allocates Distort video thread output method
128  *****************************************************************************
129  * This function allocates and initializes a Distort vout method.
130  *****************************************************************************/
131 static int vout_Create( vout_thread_t *p_vout )
132 {
133     char *psz_method;
134
135     /* Allocate structure */
136     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
137     if( p_vout->p_sys == NULL )
138     {
139         intf_ErrMsg("error: %s", strerror(ENOMEM) );
140         return( 1 );
141     }
142
143     /* Look what method was requested */
144     psz_method = main_GetPszVariable( VOUT_FILTER_VAR, "" );
145
146     while( *psz_method && *psz_method != ':' )
147     {
148         psz_method++;
149     }
150
151     if( !strcmp( psz_method, ":wave" ) )
152     {
153         p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
154     }
155     else if( !strcmp( psz_method, ":ripple" ) )
156     {
157         p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE;
158     }
159     else
160     {
161         intf_ErrMsg( "filter error: no valid distort mode provided, "
162                      "using distort:wave" );
163         p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
164     }
165
166     return( 0 );
167 }
168
169 /*****************************************************************************
170  * vout_Init: initialize Distort video thread output method
171  *****************************************************************************/
172 static int vout_Init( vout_thread_t *p_vout )
173 {
174     int i_index;
175     char *psz_filter;
176     picture_t *p_pic;
177
178     I_OUTPUTPICTURES = 0;
179
180     /* Initialize the output structure */
181     switch( p_vout->render.i_chroma )
182     {
183         case FOURCC_I420:
184         case FOURCC_IYUV:
185         case FOURCC_YV12:
186         case FOURCC_I422:
187         case FOURCC_I444:
188             p_vout->output.i_chroma = p_vout->render.i_chroma;
189             p_vout->output.i_width  = p_vout->render.i_width;
190             p_vout->output.i_height = p_vout->render.i_height;
191             p_vout->output.i_aspect = p_vout->render.i_aspect;
192             break;
193
194         default:
195             return( 0 ); /* unknown chroma */
196             break;
197     }
198
199     /* Try to open the real video output */
200     psz_filter = main_GetPszVariable( VOUT_FILTER_VAR, "" );
201     main_PutPszVariable( VOUT_FILTER_VAR, "" );
202
203     intf_WarnMsg( 1, "filter: spawning the real video output" );
204
205     p_vout->p_sys->p_vout =
206         vout_CreateThread( NULL,
207                            p_vout->render.i_width, p_vout->render.i_height,
208                            p_vout->render.i_chroma, p_vout->render.i_aspect );
209
210     /* Everything failed */
211     if( p_vout->p_sys->p_vout == NULL )
212     {
213         intf_ErrMsg( "filter error: can't open vout, aborting" );
214
215         return( 0 );
216     }
217  
218     main_PutPszVariable( VOUT_FILTER_VAR, psz_filter );
219
220     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
221
222     p_vout->p_sys->f_angle = 0.0;
223     p_vout->p_sys->last_date = 0;
224
225     return( 0 );
226 }
227
228 /*****************************************************************************
229  * vout_End: terminate Distort video thread output method
230  *****************************************************************************/
231 static void vout_End( vout_thread_t *p_vout )
232 {
233     int i_index;
234
235     /* Free the fake output buffers we allocated */
236     for( i_index = I_OUTPUTPICTURES ; i_index ; )
237     {
238         i_index--;
239         free( PP_OUTPUTPICTURE[ i_index ]->planes[ 0 ].p_data );
240     }
241 }
242
243 /*****************************************************************************
244  * vout_Destroy: destroy Distort video thread output method
245  *****************************************************************************
246  * Terminate an output method created by DistortCreateOutputMethod
247  *****************************************************************************/
248 static void vout_Destroy( vout_thread_t *p_vout )
249 {
250     vout_DestroyThread( p_vout->p_sys->p_vout, NULL );
251
252     free( p_vout->p_sys );
253 }
254
255 /*****************************************************************************
256  * vout_Manage: handle Distort events
257  *****************************************************************************
258  * This function should be called regularly by video output thread. It manages
259  * console events. It returns a non null value on error.
260  *****************************************************************************/
261 static int vout_Manage( vout_thread_t *p_vout )
262 {
263     return( 0 );
264 }
265
266 /*****************************************************************************
267  * vout_Display: displays previously rendered output
268  *****************************************************************************
269  * This function send the currently rendered image to Distort image, waits
270  * until it is displayed and switch the two rendering buffers, preparing next
271  * frame.
272  *****************************************************************************/
273 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
274 {
275     picture_t *p_outpic;
276
277     /* This is a new frame. Get a structure from the video_output. */
278     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
279               == NULL )
280     {
281         if( p_vout->b_die || p_vout->b_error )
282         {
283             return;
284         }
285         msleep( VOUT_OUTMEM_SLEEP );
286     }
287
288     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, mdate() + 50000 );
289
290     switch( p_vout->p_sys->i_mode )
291     {
292         case DISTORT_MODE_WAVE:
293             DistortWave( p_vout, p_pic, p_outpic );
294             break;
295
296         case DISTORT_MODE_RIPPLE:
297             DistortRipple( p_vout, p_pic, p_outpic );
298             break;
299
300         default:
301             break;
302     }
303
304     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
305 }
306
307
308 /*****************************************************************************
309  * DistortWave: draw a wave effect on the picture
310  *****************************************************************************/
311 static void DistortWave( vout_thread_t *p_vout, picture_t *p_inpic,
312                                                 picture_t *p_outpic )
313 {
314     int i_index;
315     double f_angle;
316     mtime_t new_date = mdate();
317
318     p_vout->p_sys->f_angle += (new_date - p_vout->p_sys->last_date) / 200000.0;
319     p_vout->p_sys->last_date = new_date;
320     f_angle = p_vout->p_sys->f_angle;
321
322     for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
323     {
324         int i_line, i_num_lines, i_offset;
325         u8 black_pixel;
326         pixel_data_t *p_in, *p_out;
327
328         p_in = p_inpic->planes[ i_index ].p_data;
329         p_out = p_outpic->planes[ i_index ].p_data;
330
331         i_num_lines = p_inpic->planes[ i_index ].i_bytes
332                           / p_inpic->planes[ i_index ].i_line_bytes;
333
334         black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
335
336         /* Ok, we do 3 times the sin() calculation for each line. So what ? */
337         for( i_line = 0 ; i_line < i_num_lines ; i_line++ )
338         {
339             /* Calculate today's offset, don't go above 1/20th of the screen */
340             i_offset = (double)(p_inpic->planes[ i_index ].i_line_bytes)
341                          * sin( f_angle + 10.0 * (double)i_line
342                                                / (double)i_num_lines )
343                          / 20.0;
344
345             if( i_offset )
346             {
347                 if( i_offset < 0 )
348                 {
349                     FAST_MEMCPY( p_out, p_in - i_offset,
350                          p_inpic->planes[ i_index ].i_line_bytes + i_offset );
351                     p_in += p_inpic->planes[ i_index ].i_line_bytes;
352                     p_out += p_outpic->planes[ i_index ].i_line_bytes;
353                     memset( p_out + i_offset, black_pixel, -i_offset );
354                 }
355                 else
356                 {
357                     FAST_MEMCPY( p_out + i_offset, p_in,
358                          p_inpic->planes[ i_index ].i_line_bytes - i_offset );
359                     memset( p_out, black_pixel, i_offset );
360                     p_in += p_inpic->planes[ i_index ].i_line_bytes;
361                     p_out += p_outpic->planes[ i_index ].i_line_bytes;
362                 }
363             }
364             else
365             {
366                 FAST_MEMCPY( p_out, p_in,
367                              p_inpic->planes[ i_index ].i_line_bytes );
368                 p_in += p_inpic->planes[ i_index ].i_line_bytes;
369                 p_out += p_outpic->planes[ i_index ].i_line_bytes;
370             }
371
372         }
373     }
374 }
375
376 /*****************************************************************************
377  * DistortRipple: draw a ripple effect at the bottom of the picture
378  *****************************************************************************/
379 static void DistortRipple( vout_thread_t *p_vout, picture_t *p_inpic,
380                                                   picture_t *p_outpic )
381 {
382     int i_index;
383     double f_angle;
384     mtime_t new_date = mdate();
385
386     p_vout->p_sys->f_angle -= (p_vout->p_sys->last_date - new_date) / 100000.0;
387     p_vout->p_sys->last_date = new_date;
388     f_angle = p_vout->p_sys->f_angle;
389
390     for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
391     {
392         int i_line, i_first_line, i_num_lines, i_offset;
393         u8 black_pixel;
394         pixel_data_t *p_in, *p_out;
395
396         black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
397
398         i_num_lines = p_inpic->planes[ i_index ].i_bytes
399                           / p_inpic->planes[ i_index ].i_line_bytes;
400
401         i_first_line = i_num_lines * 4 / 5;
402
403         p_in = p_inpic->planes[ i_index ].p_data;
404         p_out = p_outpic->planes[ i_index ].p_data;
405
406         FAST_MEMCPY( p_out, p_in,
407                      i_first_line * p_inpic->planes[ i_index ].i_line_bytes );
408
409         p_in += i_first_line * p_inpic->planes[ i_index ].i_line_bytes;
410         p_out += i_first_line * p_outpic->planes[ i_index ].i_line_bytes;
411
412         /* Ok, we do 3 times the sin() calculation for each line. So what ? */
413         for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ )
414         {
415             /* Calculate today's offset, don't go above 1/20th of the screen */
416             i_offset = (double)(p_inpic->planes[ i_index ].i_line_bytes)
417                          * sin( f_angle + 2.0 * (double)i_line
418                                               / (double)( 1 + i_line
419                                                             - i_first_line) )
420                          * (double)(i_line - i_first_line)
421                          / (double)i_num_lines
422                          / 8.0;
423
424             if( i_offset )
425             {
426                 if( i_offset < 0 )
427                 {
428                     FAST_MEMCPY( p_out, p_in - i_offset,
429                          p_inpic->planes[ i_index ].i_line_bytes + i_offset );
430                     p_in -= p_inpic->planes[ i_index ].i_line_bytes;
431                     p_out += p_outpic->planes[ i_index ].i_line_bytes;
432                     memset( p_out + i_offset, black_pixel, -i_offset );
433                 }
434                 else
435                 {
436                     FAST_MEMCPY( p_out + i_offset, p_in,
437                          p_inpic->planes[ i_index ].i_line_bytes - i_offset );
438                     memset( p_out, black_pixel, i_offset );
439                     p_in -= p_inpic->planes[ i_index ].i_line_bytes;
440                     p_out += p_outpic->planes[ i_index ].i_line_bytes;
441                 }
442             }
443             else
444             {
445                 FAST_MEMCPY( p_out, p_in,
446                              p_inpic->planes[ i_index ].i_line_bytes );
447                 p_in -= p_inpic->planes[ i_index ].i_line_bytes;
448                 p_out += p_outpic->planes[ i_index ].i_line_bytes;
449             }
450
451         }
452     }
453 }
454