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

transform.c

00001 /*****************************************************************************
00002  * transform.c : transform image module for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2000-2004 the VideoLAN team
00005  * $Id: transform.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 <vlc/vlc.h>
00031 #include <vlc/vout.h>
00032 
00033 #include "filter_common.h"
00034 
00035 #define TRANSFORM_MODE_HFLIP   1
00036 #define TRANSFORM_MODE_VFLIP   2
00037 #define TRANSFORM_MODE_90      3
00038 #define TRANSFORM_MODE_180     4
00039 #define TRANSFORM_MODE_270     5
00040 
00041 /*****************************************************************************
00042  * Local prototypes
00043  *****************************************************************************/
00044 static int  Create    ( vlc_object_t * );
00045 static void Destroy   ( vlc_object_t * );
00046 
00047 static int  Init      ( vout_thread_t * );
00048 static void End       ( vout_thread_t * );
00049 static void Render    ( vout_thread_t *, picture_t * );
00050 
00051 static int  SendEvents( vlc_object_t *, char const *,
00052                         vlc_value_t, vlc_value_t, void * );
00053 
00054 /*****************************************************************************
00055  * Module descriptor
00056  *****************************************************************************/
00057 #define TYPE_TEXT N_("Transform type")
00058 #define TYPE_LONGTEXT N_("One of '90', '180', '270', 'hflip' and 'vflip'")
00059 
00060 static char *type_list[] = { "90", "180", "270", "hflip", "vflip" };
00061 static char *type_list_text[] = { N_("Rotate by 90 degrees"),
00062   N_("Rotate by 180 degrees"), N_("Rotate by 270 degrees"),
00063   N_("Flip horizontally"), N_("Flip vertically") };
00064 
00065 vlc_module_begin();
00066     set_description( _("Video transformation filter") );
00067     set_shortname( N_("Transformation"));
00068     set_capability( "video filter", 0 );
00069     set_category( CAT_VIDEO );
00070     set_subcategory( SUBCAT_VIDEO_VFILTER );
00071 
00072     add_string( "transform-type", "90", NULL,
00073                           TYPE_TEXT, TYPE_LONGTEXT, VLC_FALSE);
00074         change_string_list( type_list, type_list_text, 0);
00075 
00076     add_shortcut( "transform" );
00077     set_callbacks( Create, Destroy );
00078 vlc_module_end();
00079 
00080 /*****************************************************************************
00081  * vout_sys_t: Transform video output method descriptor
00082  *****************************************************************************
00083  * This structure is part of the video output thread descriptor.
00084  * It describes the Transform specific properties of an output thread.
00085  *****************************************************************************/
00086 struct vout_sys_t
00087 {
00088     int i_mode;
00089     vlc_bool_t b_rotation;
00090     vout_thread_t *p_vout;
00091 };
00092 
00093 /*****************************************************************************
00094  * Control: control facility for the vout (forwards to child vout)
00095  *****************************************************************************/
00096 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
00097 {
00098     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
00099 }
00100 
00101 /*****************************************************************************
00102  * Create: allocates Transform video thread output method
00103  *****************************************************************************
00104  * This function allocates and initializes a Transform vout method.
00105  *****************************************************************************/
00106 static int Create( vlc_object_t *p_this )
00107 {
00108     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00109     char *psz_method;
00110 
00111     /* Allocate structure */
00112     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00113     if( p_vout->p_sys == NULL )
00114     {
00115         msg_Err( p_vout, "out of memory" );
00116         return VLC_ENOMEM;
00117     }
00118 
00119     p_vout->pf_init = Init;
00120     p_vout->pf_end = End;
00121     p_vout->pf_manage = NULL;
00122     p_vout->pf_render = Render;
00123     p_vout->pf_display = NULL;
00124     p_vout->pf_control = Control;
00125 
00126     /* Look what method was requested */
00127     psz_method = config_GetPsz( p_vout, "transform-type" );
00128 
00129     if( psz_method == NULL )
00130     {
00131         msg_Err( p_vout, "configuration variable %s empty", "transform-type" );
00132         msg_Err( p_vout, "no valid transform mode provided, using '90'" );
00133         p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
00134         p_vout->p_sys->b_rotation = 1;
00135     }
00136     else
00137     {
00138         if( !strcmp( psz_method, "hflip" ) )
00139         {
00140             p_vout->p_sys->i_mode = TRANSFORM_MODE_HFLIP;
00141             p_vout->p_sys->b_rotation = 0;
00142         }
00143         else if( !strcmp( psz_method, "vflip" ) )
00144         {
00145             p_vout->p_sys->i_mode = TRANSFORM_MODE_VFLIP;
00146             p_vout->p_sys->b_rotation = 0;
00147         }
00148         else if( !strcmp( psz_method, "90" ) )
00149         {
00150             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
00151             p_vout->p_sys->b_rotation = 1;
00152         }
00153         else if( !strcmp( psz_method, "180" ) )
00154         {
00155             p_vout->p_sys->i_mode = TRANSFORM_MODE_180;
00156             p_vout->p_sys->b_rotation = 0;
00157         }
00158         else if( !strcmp( psz_method, "270" ) )
00159         {
00160             p_vout->p_sys->i_mode = TRANSFORM_MODE_270;
00161             p_vout->p_sys->b_rotation = 1;
00162         }
00163         else
00164         {
00165             msg_Err( p_vout, "no valid transform mode provided, using '90'" );
00166             p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
00167             p_vout->p_sys->b_rotation = 1;
00168         }
00169 
00170         free( psz_method );
00171     }
00172 
00173     return VLC_SUCCESS;
00174 }
00175 
00176 /*****************************************************************************
00177  * Init: initialize Transform video thread output method
00178  *****************************************************************************/
00179 static int Init( vout_thread_t *p_vout )
00180 {
00181     int i_index;
00182     picture_t *p_pic;
00183     video_format_t fmt = {0};
00184 
00185     I_OUTPUTPICTURES = 0;
00186 
00187     /* Initialize the output structure */
00188     p_vout->output.i_chroma = p_vout->render.i_chroma;
00189     p_vout->output.i_width  = p_vout->render.i_width;
00190     p_vout->output.i_height = p_vout->render.i_height;
00191     p_vout->output.i_aspect = p_vout->render.i_aspect;
00192     p_vout->fmt_out = p_vout->fmt_in;
00193     fmt = p_vout->fmt_out;
00194 
00195     /* Try to open the real video output */
00196     msg_Dbg( p_vout, "spawning the real video output" );
00197 
00198     if( p_vout->p_sys->b_rotation )
00199     {
00200         fmt.i_width = p_vout->fmt_out.i_height;
00201         fmt.i_visible_width = p_vout->fmt_out.i_visible_height;
00202         fmt.i_x_offset = p_vout->fmt_out.i_y_offset;
00203 
00204         fmt.i_height = p_vout->fmt_out.i_width;
00205         fmt.i_visible_height = p_vout->fmt_out.i_visible_width;
00206         fmt.i_y_offset = p_vout->fmt_out.i_x_offset;
00207 
00208         fmt.i_aspect = VOUT_ASPECT_FACTOR *
00209             (uint64_t)VOUT_ASPECT_FACTOR / fmt.i_aspect;
00210 
00211         fmt.i_sar_num = p_vout->fmt_out.i_sar_den;
00212         fmt.i_sar_den = p_vout->fmt_out.i_sar_num;
00213 
00214         p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
00215     }
00216     else
00217     {
00218         p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
00219     }
00220 
00221     /* Everything failed */
00222     if( p_vout->p_sys->p_vout == NULL )
00223     {
00224         msg_Err( p_vout, "cannot open vout, aborting" );
00225         return VLC_EGENERIC;
00226     }
00227 
00228     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
00229 
00230     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00231 
00232     ADD_PARENT_CALLBACKS( SendEventsToChild );
00233 
00234     return VLC_SUCCESS;
00235 }
00236 
00237 /*****************************************************************************
00238  * End: terminate Transform video thread output method
00239  *****************************************************************************/
00240 static void End( vout_thread_t *p_vout )
00241 {
00242     int i_index;
00243 
00244     /* Free the fake output buffers we allocated */
00245     for( i_index = I_OUTPUTPICTURES ; i_index ; )
00246     {
00247         i_index--;
00248         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
00249     }
00250 }
00251 
00252 /*****************************************************************************
00253  * Destroy: destroy Transform video thread output method
00254  *****************************************************************************
00255  * Terminate an output method created by TransformCreateOutputMethod
00256  *****************************************************************************/
00257 static void Destroy( vlc_object_t *p_this )
00258 {
00259     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00260 
00261     if( p_vout->p_sys->p_vout )
00262     {
00263         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00264         vlc_object_detach( p_vout->p_sys->p_vout );
00265         vout_Destroy( p_vout->p_sys->p_vout );
00266     }
00267 
00268     DEL_PARENT_CALLBACKS( SendEventsToChild );
00269 
00270     free( p_vout->p_sys );
00271 }
00272 
00273 /*****************************************************************************
00274  * Render: displays previously rendered output
00275  *****************************************************************************
00276  * This function send the currently rendered image to Transform image, waits
00277  * until it is displayed and switch the two rendering buffers, preparing next
00278  * frame.
00279  *****************************************************************************/
00280 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
00281 {
00282     picture_t *p_outpic;
00283     int i_index;
00284 
00285     /* This is a new frame. Get a structure from the video_output. */
00286     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
00287               == NULL )
00288     {
00289         if( p_vout->b_die || p_vout->b_error )
00290         {
00291             return;
00292         }
00293         msleep( VOUT_OUTMEM_SLEEP );
00294     }
00295 
00296     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
00297     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
00298 
00299     switch( p_vout->p_sys->i_mode )
00300     {
00301         case TRANSFORM_MODE_90:
00302             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00303             {
00304                 int i_pitch = p_pic->p[i_index].i_pitch;
00305 
00306                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00307 
00308                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00309                 uint8_t *p_out_end = p_out +
00310                     p_outpic->p[i_index].i_visible_lines *
00311                     p_outpic->p[i_index].i_pitch;
00312 
00313                 for( ; p_out < p_out_end ; )
00314                 {
00315                     uint8_t *p_line_end;
00316 
00317                     p_out_end -= p_outpic->p[i_index].i_pitch
00318                                   - p_outpic->p[i_index].i_visible_pitch;
00319                     p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
00320                         i_pitch;
00321 
00322                     for( ; p_in < p_line_end ; )
00323                     {
00324                         p_line_end -= i_pitch;
00325                         *(--p_out_end) = *p_line_end;
00326                     }
00327 
00328                     p_in++;
00329                 }
00330             }
00331             break;
00332 
00333         case TRANSFORM_MODE_180:
00334             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00335             {
00336                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00337                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
00338                                             * p_pic->p[i_index].i_pitch;
00339 
00340                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00341 
00342                 for( ; p_in < p_in_end ; )
00343                 {
00344                     uint8_t *p_line_start = p_in_end
00345                                              - p_pic->p[i_index].i_pitch;
00346                     p_in_end -= p_pic->p[i_index].i_pitch
00347                                  - p_pic->p[i_index].i_visible_pitch;
00348 
00349                     for( ; p_line_start < p_in_end ; )
00350                     {
00351                         *p_out++ = *(--p_in_end);
00352                     }
00353 
00354                     p_out += p_outpic->p[i_index].i_pitch
00355                               - p_outpic->p[i_index].i_visible_pitch;
00356                 }
00357             }
00358             break;
00359 
00360         case TRANSFORM_MODE_270:
00361             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00362             {
00363                 int i_pitch = p_pic->p[i_index].i_pitch;
00364 
00365                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00366 
00367                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00368                 uint8_t *p_out_end = p_out +
00369                     p_outpic->p[i_index].i_visible_lines *
00370                     p_outpic->p[i_index].i_pitch;
00371 
00372                 for( ; p_out < p_out_end ; )
00373                 {
00374                     uint8_t *p_in_end;
00375 
00376                     p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
00377                         i_pitch;
00378 
00379                     for( ; p_in < p_in_end ; )
00380                     {
00381                         p_in_end -= i_pitch;
00382                         *p_out++ = *p_in_end;
00383                     }
00384 
00385                     p_out += p_outpic->p[i_index].i_pitch
00386                               - p_outpic->p[i_index].i_visible_pitch;
00387                     p_in++;
00388                 }
00389             }
00390             break;
00391 
00392         case TRANSFORM_MODE_HFLIP:
00393             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00394             {
00395                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00396                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
00397                                             * p_pic->p[i_index].i_pitch;
00398 
00399                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00400 
00401                 for( ; p_in < p_in_end ; )
00402                 {
00403                     p_in_end -= p_pic->p[i_index].i_pitch;
00404                     p_vout->p_vlc->pf_memcpy( p_out, p_in_end,
00405                                            p_pic->p[i_index].i_visible_pitch );
00406                     p_out += p_pic->p[i_index].i_pitch;
00407                 }
00408             }
00409             break;
00410 
00411         case TRANSFORM_MODE_VFLIP:
00412             for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00413             {
00414                 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00415                 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
00416                                             * p_pic->p[i_index].i_pitch;
00417 
00418                 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00419 
00420                 for( ; p_in < p_in_end ; )
00421                 {
00422                     uint8_t *p_line_end = p_in
00423                                            + p_pic->p[i_index].i_visible_pitch;
00424 
00425                     for( ; p_in < p_line_end ; )
00426                     {
00427                         *p_out++ = *(--p_line_end);
00428                     }
00429 
00430                     p_in += p_pic->p[i_index].i_pitch;
00431                 }
00432             }
00433             break;
00434 
00435         default:
00436             break;
00437     }
00438 
00439     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
00440 
00441     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
00442 }
00443 
00444 /*****************************************************************************
00445  * SendEvents: forward mouse and keyboard events to the parent p_vout
00446  *****************************************************************************/
00447 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
00448                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
00449 {
00450     vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
00451     vlc_value_t sentval = newval;
00452 
00453     /* Translate the mouse coordinates */
00454     if( !strcmp( psz_var, "mouse-x" ) )
00455     {
00456         switch( p_vout->p_sys->i_mode )
00457         {
00458         case TRANSFORM_MODE_270:
00459             sentval.i_int = p_vout->p_sys->p_vout->output.i_width
00460                              - sentval.i_int;
00461         case TRANSFORM_MODE_90:
00462             var_Set( p_vout, "mouse-y", sentval );
00463             return VLC_SUCCESS;
00464 
00465         case TRANSFORM_MODE_180:
00466         case TRANSFORM_MODE_HFLIP:
00467             sentval.i_int = p_vout->p_sys->p_vout->output.i_width
00468                              - sentval.i_int;
00469             break;
00470 
00471         case TRANSFORM_MODE_VFLIP:
00472         default:
00473             break;
00474         }
00475     }
00476     else if( !strcmp( psz_var, "mouse-y" ) )
00477     {
00478         switch( p_vout->p_sys->i_mode )
00479         {
00480         case TRANSFORM_MODE_90:
00481             sentval.i_int = p_vout->p_sys->p_vout->output.i_height
00482                              - sentval.i_int;
00483         case TRANSFORM_MODE_270:
00484             var_Set( p_vout, "mouse-x", sentval );
00485             return VLC_SUCCESS;
00486 
00487         case TRANSFORM_MODE_180:
00488         case TRANSFORM_MODE_VFLIP:
00489             sentval.i_int = p_vout->p_sys->p_vout->output.i_height
00490                              - sentval.i_int;
00491             break;
00492 
00493         case TRANSFORM_MODE_HFLIP:
00494         default:
00495             break;
00496         }
00497     }
00498 
00499     var_Set( p_vout, psz_var, sentval );
00500 
00501     return VLC_SUCCESS;
00502 }
00503 
00504 /*****************************************************************************
00505  * SendEventsToChild: forward events to the child/children vout
00506  *****************************************************************************/
00507 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
00508                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00509 {
00510     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00511     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
00512     return VLC_SUCCESS;
00513 }

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