Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

distort.c

00001 /*****************************************************************************
00002  * distort.c : Misc video effects plugin for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2000, 2001, 2002, 2003 the VideoLAN team
00005  * $Id: distort.c 12968 2005-10-25 19:24:21Z gbazin $
00006  *
00007  * Authors: Samuel Hocevar <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>                                      /* malloc(), free() */
00028 #include <string.h>
00029 
00030 #include <math.h>                                            /* sin(), cos() */
00031 
00032 #include <vlc/vlc.h>
00033 #include <vlc/vout.h>
00034 
00035 #include "filter_common.h"
00036 
00037 #define DISTORT_MODE_WAVE    1
00038 #define DISTORT_MODE_RIPPLE  2
00039 
00040 /*****************************************************************************
00041  * Local prototypes
00042  *****************************************************************************/
00043 static int  Create    ( vlc_object_t * );
00044 static void Destroy   ( vlc_object_t * );
00045 
00046 static int  Init      ( vout_thread_t * );
00047 static void End       ( vout_thread_t * );
00048 static void Render    ( vout_thread_t *, picture_t * );
00049 
00050 static void DistortWave    ( vout_thread_t *, picture_t *, picture_t * );
00051 static void DistortRipple  ( vout_thread_t *, picture_t *, picture_t * );
00052 
00053 static int  SendEvents   ( vlc_object_t *, char const *,
00054                            vlc_value_t, vlc_value_t, void * );
00055 
00056 /*****************************************************************************
00057  * Module descriptor
00058  *****************************************************************************/
00059 #define MODE_TEXT N_("Distort mode")
00060 #define MODE_LONGTEXT N_("Distort mode, one of \"wave\" and \"ripple\"")
00061 
00062 static char *mode_list[] = { "wave", "ripple" };
00063 static char *mode_list_text[] = { N_("Wave"), N_("Ripple") };
00064 
00065 vlc_module_begin();
00066     set_description( _("Distort video filter") );
00067     set_shortname( N_( "Distortion" ));
00068     set_capability( "video filter", 0 );
00069     set_category( CAT_VIDEO );
00070     set_subcategory( SUBCAT_VIDEO_VFILTER );
00071 
00072     add_string( "distort-mode", "wave", NULL, MODE_TEXT, MODE_LONGTEXT,
00073                 VLC_FALSE );
00074         change_string_list( mode_list, mode_list_text, 0 );
00075 
00076     add_shortcut( "distort" );
00077     set_callbacks( Create, Destroy );
00078 vlc_module_end();
00079 
00080 /*****************************************************************************
00081  * vout_sys_t: Distort video output method descriptor
00082  *****************************************************************************
00083  * This structure is part of the video output thread descriptor.
00084  * It describes the Distort specific properties of an output thread.
00085  *****************************************************************************/
00086 struct vout_sys_t
00087 {
00088     int i_mode;
00089     vout_thread_t *p_vout;
00090 
00091     /* For the wave mode */
00092     double  f_angle;
00093     mtime_t last_date;
00094 };
00095 
00096 /*****************************************************************************
00097  * Control: control facility for the vout (forwards to child vout)
00098  *****************************************************************************/
00099 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
00100 {
00101     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
00102 }
00103 
00104 /*****************************************************************************
00105  * Create: allocates Distort video thread output method
00106  *****************************************************************************
00107  * This function allocates and initializes a Distort vout method.
00108  *****************************************************************************/
00109 static int Create( vlc_object_t *p_this )
00110 {
00111     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00112     char *psz_method, *psz_method_tmp;
00113 
00114     /* Allocate structure */
00115     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00116     if( p_vout->p_sys == NULL )
00117     {
00118         msg_Err( p_vout, "out of memory" );
00119         return VLC_ENOMEM;
00120     }
00121 
00122     p_vout->pf_init = Init;
00123     p_vout->pf_end = End;
00124     p_vout->pf_manage = NULL;
00125     p_vout->pf_render = Render;
00126     p_vout->pf_display = NULL;
00127     p_vout->pf_control = Control;
00128 
00129     p_vout->p_sys->i_mode = 0;
00130 
00131     if( !(psz_method = psz_method_tmp
00132           = config_GetPsz( p_vout, "distort-mode" )) )
00133     {
00134         msg_Err( p_vout, "configuration variable %s empty, using 'wave'",
00135                          "distort-mode" );
00136         p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
00137     }
00138     else
00139     {
00140 
00141         if( !strcmp( psz_method, "wave" ) )
00142         {
00143             p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
00144         }
00145         else if( !strcmp( psz_method, "ripple" ) )
00146         {
00147             p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE;
00148         }
00149         else
00150         {
00151             msg_Err( p_vout, "no valid distort mode provided, "
00152                              "using wave" );
00153             p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
00154         }
00155     }
00156     free( psz_method_tmp );
00157 
00158     return VLC_SUCCESS;
00159 }
00160 
00161 /*****************************************************************************
00162  * Init: initialize Distort video thread output method
00163  *****************************************************************************/
00164 static int Init( vout_thread_t *p_vout )
00165 {
00166     int i_index;
00167     picture_t *p_pic;
00168     video_format_t fmt = {0};
00169 
00170     I_OUTPUTPICTURES = 0;
00171 
00172     /* Initialize the output structure */
00173     p_vout->output.i_chroma = p_vout->render.i_chroma;
00174     p_vout->output.i_width  = p_vout->render.i_width;
00175     p_vout->output.i_height = p_vout->render.i_height;
00176     p_vout->output.i_aspect = p_vout->render.i_aspect;
00177     p_vout->fmt_out = p_vout->fmt_in;
00178     fmt = p_vout->fmt_out;
00179 
00180     /* Try to open the real video output */
00181     msg_Dbg( p_vout, "spawning the real video output" );
00182 
00183     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
00184 
00185     /* Everything failed */
00186     if( p_vout->p_sys->p_vout == NULL )
00187     {
00188         msg_Err( p_vout, "cannot open vout, aborting" );
00189         return VLC_EGENERIC;
00190     }
00191 
00192     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
00193 
00194     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00195 
00196     ADD_PARENT_CALLBACKS( SendEventsToChild );
00197 
00198     p_vout->p_sys->f_angle = 0.0;
00199     p_vout->p_sys->last_date = 0;
00200 
00201     return VLC_SUCCESS;
00202 }
00203 
00204 /*****************************************************************************
00205  * End: terminate Distort video thread output method
00206  *****************************************************************************/
00207 static void End( vout_thread_t *p_vout )
00208 {
00209     int i_index;
00210 
00211     /* Free the fake output buffers we allocated */
00212     for( i_index = I_OUTPUTPICTURES ; i_index ; )
00213     {
00214         i_index--;
00215         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
00216     }
00217 }
00218 
00219 /*****************************************************************************
00220  * Destroy: destroy Distort video thread output method
00221  *****************************************************************************
00222  * Terminate an output method created by DistortCreateOutputMethod
00223  *****************************************************************************/
00224 static void Destroy( vlc_object_t *p_this )
00225 {
00226     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00227 
00228     if( p_vout->p_sys->p_vout )
00229     {
00230         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00231         vlc_object_detach( p_vout->p_sys->p_vout );
00232         vout_Destroy( p_vout->p_sys->p_vout );
00233     }
00234 
00235     DEL_PARENT_CALLBACKS( SendEventsToChild );
00236 
00237     free( p_vout->p_sys );
00238 }
00239 
00240 /*****************************************************************************
00241  * Render: displays previously rendered output
00242  *****************************************************************************
00243  * This function send the currently rendered image to Distort image, waits
00244  * until it is displayed and switch the two rendering buffers, preparing next
00245  * frame.
00246  *****************************************************************************/
00247 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
00248 {
00249     picture_t *p_outpic;
00250 
00251     /* This is a new frame. Get a structure from the video_output. */
00252     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
00253               == NULL )
00254     {
00255         if( p_vout->b_die || p_vout->b_error )
00256         {
00257             return;
00258         }
00259         msleep( VOUT_OUTMEM_SLEEP );
00260     }
00261 
00262     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
00263 
00264     switch( p_vout->p_sys->i_mode )
00265     {
00266         case DISTORT_MODE_WAVE:
00267             DistortWave( p_vout, p_pic, p_outpic );
00268             break;
00269 
00270         case DISTORT_MODE_RIPPLE:
00271             DistortRipple( p_vout, p_pic, p_outpic );
00272             break;
00273 
00274         default:
00275             break;
00276     }
00277 
00278     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
00279 }
00280 
00281 /*****************************************************************************
00282  * DistortWave: draw a wave effect on the picture
00283  *****************************************************************************/
00284 static void DistortWave( vout_thread_t *p_vout, picture_t *p_inpic,
00285                                                 picture_t *p_outpic )
00286 {
00287     int i_index;
00288     double f_angle;
00289     mtime_t new_date = mdate();
00290 
00291     p_vout->p_sys->f_angle += (new_date - p_vout->p_sys->last_date) / 200000.0;
00292     p_vout->p_sys->last_date = new_date;
00293     f_angle = p_vout->p_sys->f_angle;
00294 
00295     for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
00296     {
00297         int i_line, i_num_lines, i_offset;
00298         uint8_t black_pixel;
00299         uint8_t *p_in, *p_out;
00300 
00301         p_in = p_inpic->p[i_index].p_pixels;
00302         p_out = p_outpic->p[i_index].p_pixels;
00303 
00304         i_num_lines = p_inpic->p[i_index].i_visible_lines;
00305 
00306         black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
00307 
00308         /* Ok, we do 3 times the sin() calculation for each line. So what ? */
00309         for( i_line = 0 ; i_line < i_num_lines ; i_line++ )
00310         {
00311             /* Calculate today's offset, don't go above 1/20th of the screen */
00312             i_offset = (int)( (double)(p_inpic->p[i_index].i_visible_pitch)
00313                          * sin( f_angle + 10.0 * (double)i_line
00314                                                / (double)i_num_lines )
00315                          / 20.0 );
00316 
00317             if( i_offset )
00318             {
00319                 if( i_offset < 0 )
00320                 {
00321                     p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset,
00322                              p_inpic->p[i_index].i_visible_pitch + i_offset );
00323                     p_in += p_inpic->p[i_index].i_pitch;
00324                     p_out += p_outpic->p[i_index].i_pitch;
00325                     memset( p_out + i_offset, black_pixel, -i_offset );
00326                 }
00327                 else
00328                 {
00329                     p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in,
00330                              p_inpic->p[i_index].i_visible_pitch - i_offset );
00331                     memset( p_out, black_pixel, i_offset );
00332                     p_in += p_inpic->p[i_index].i_pitch;
00333                     p_out += p_outpic->p[i_index].i_pitch;
00334                 }
00335             }
00336             else
00337             {
00338                 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00339                                           p_inpic->p[i_index].i_visible_pitch );
00340                 p_in += p_inpic->p[i_index].i_pitch;
00341                 p_out += p_outpic->p[i_index].i_pitch;
00342             }
00343 
00344         }
00345     }
00346 }
00347 
00348 /*****************************************************************************
00349  * DistortRipple: draw a ripple effect at the bottom of the picture
00350  *****************************************************************************/
00351 static void DistortRipple( vout_thread_t *p_vout, picture_t *p_inpic,
00352                                                   picture_t *p_outpic )
00353 {
00354     int i_index;
00355     double f_angle;
00356     mtime_t new_date = mdate();
00357 
00358     p_vout->p_sys->f_angle -= (p_vout->p_sys->last_date - new_date) / 100000.0;
00359     p_vout->p_sys->last_date = new_date;
00360     f_angle = p_vout->p_sys->f_angle;
00361 
00362     for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
00363     {
00364         int i_line, i_first_line, i_num_lines, i_offset;
00365         uint8_t black_pixel;
00366         uint8_t *p_in, *p_out;
00367 
00368         black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
00369 
00370         i_num_lines = p_inpic->p[i_index].i_visible_lines;
00371 
00372         i_first_line = i_num_lines * 4 / 5;
00373 
00374         p_in = p_inpic->p[i_index].p_pixels;
00375         p_out = p_outpic->p[i_index].p_pixels;
00376 
00377         for( i_line = 0 ; i_line < i_first_line ; i_line++ )
00378         {
00379             p_vout->p_vlc->pf_memcpy( p_out, p_in,
00380                                       p_inpic->p[i_index].i_visible_pitch );
00381             p_in += p_inpic->p[i_index].i_pitch;
00382             p_out += p_outpic->p[i_index].i_pitch;
00383         }
00384 
00385         /* Ok, we do 3 times the sin() calculation for each line. So what ? */
00386         for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ )
00387         {
00388             /* Calculate today's offset, don't go above 1/20th of the screen */
00389             i_offset = (int)( (double)(p_inpic->p[i_index].i_pitch)
00390                          * sin( f_angle + 2.0 * (double)i_line
00391                                               / (double)( 1 + i_line
00392                                                             - i_first_line) )
00393                          * (double)(i_line - i_first_line)
00394                          / (double)i_num_lines
00395                          / 8.0 );
00396 
00397             if( i_offset )
00398             {
00399                 if( i_offset < 0 )
00400                 {
00401                     p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset,
00402                              p_inpic->p[i_index].i_visible_pitch + i_offset );
00403                     p_in -= p_inpic->p[i_index].i_pitch;
00404                     p_out += p_outpic->p[i_index].i_pitch;
00405                     memset( p_out + i_offset, black_pixel, -i_offset );
00406                 }
00407                 else
00408                 {
00409                     p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in,
00410                              p_inpic->p[i_index].i_visible_pitch - i_offset );
00411                     memset( p_out, black_pixel, i_offset );
00412                     p_in -= p_inpic->p[i_index].i_pitch;
00413                     p_out += p_outpic->p[i_index].i_pitch;
00414                 }
00415             }
00416             else
00417             {
00418                 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00419                                           p_inpic->p[i_index].i_visible_pitch );
00420                 p_in -= p_inpic->p[i_index].i_pitch;
00421                 p_out += p_outpic->p[i_index].i_pitch;
00422             }
00423 
00424         }
00425     }
00426 }
00427 
00428 /*****************************************************************************
00429  * SendEvents: forward mouse and keyboard events to the parent p_vout
00430  *****************************************************************************/
00431 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
00432                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00433 {
00434     var_Set( (vlc_object_t *)p_data, psz_var, newval );
00435 
00436     return VLC_SUCCESS;
00437 }
00438 
00439 /*****************************************************************************
00440  * SendEventsToChild: forward events to the child/children vout
00441  *****************************************************************************/
00442 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
00443                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00444 {
00445     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00446     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
00447     return VLC_SUCCESS;
00448 }

Generated on Tue Dec 20 10:14:52 2005 for vlc-0.8.4a by  doxygen 1.4.2