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

vout_intf.c

00001 /*****************************************************************************
00002  * vout_intf.c : video output interface
00003  *****************************************************************************
00004  * Copyright (C) 2000-2004 the VideoLAN team
00005  * $Id: vout_intf.c 13051 2005-10-31 07:35:39Z md $
00006  *
00007  * Authors: Gildas Bazin <[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>                                                /* free() */
00028 
00029 #include <vlc/vlc.h>
00030 #include <vlc/intf.h>
00031 
00032 #include "vlc_video.h"
00033 #include "video_output.h"
00034 #include "vlc_image.h"
00035 #include "vlc_spu.h"
00036 
00037 /*****************************************************************************
00038  * Local prototypes
00039  *****************************************************************************/
00040 static void InitWindowSize( vout_thread_t *, unsigned *, unsigned * );
00041 
00042 /* Object variables callbacks */
00043 static int ZoomCallback( vlc_object_t *, char const *,
00044                          vlc_value_t, vlc_value_t, void * );
00045 static int CropCallback( vlc_object_t *, char const *,
00046                          vlc_value_t, vlc_value_t, void * );
00047 static int AspectCallback( vlc_object_t *, char const *,
00048                            vlc_value_t, vlc_value_t, void * );
00049 static int OnTopCallback( vlc_object_t *, char const *,
00050                           vlc_value_t, vlc_value_t, void * );
00051 static int FullscreenCallback( vlc_object_t *, char const *,
00052                                vlc_value_t, vlc_value_t, void * );
00053 static int SnapshotCallback( vlc_object_t *, char const *,
00054                              vlc_value_t, vlc_value_t, void * );
00055 
00056 /*****************************************************************************
00057  * vout_RequestWindow: Create/Get a video window if possible.
00058  *****************************************************************************
00059  * This function looks for the main interface and tries to request
00060  * a new video window. If it fails then the vout will still need to create the
00061  * window by itself.
00062  *****************************************************************************/
00063 void *vout_RequestWindow( vout_thread_t *p_vout,
00064                           int *pi_x_hint, int *pi_y_hint,
00065                           unsigned int *pi_width_hint,
00066                           unsigned int *pi_height_hint )
00067 {
00068     intf_thread_t *p_intf = NULL;
00069     vlc_list_t *p_list;
00070     void *p_window;
00071     vlc_value_t val;
00072     int i;
00073 
00074     /* Small kludge */
00075     if( !var_Type( p_vout, "aspect-ratio" ) ) vout_IntfInit( p_vout );
00076 
00077     /* Get requested coordinates */
00078     var_Get( p_vout, "video-x", &val );
00079     *pi_x_hint = val.i_int ;
00080     var_Get( p_vout, "video-y", &val );
00081     *pi_y_hint = val.i_int;
00082 
00083     *pi_width_hint = p_vout->i_window_width;
00084     *pi_height_hint = p_vout->i_window_height;
00085 
00086     /* Check whether someone provided us with a window ID */
00087     var_Get( p_vout->p_vlc, "drawable", &val );
00088     if( val.i_int ) return (void *)val.i_int;
00089 
00090     /* Find if the main interface supports embedding */
00091     p_list = vlc_list_find( p_vout, VLC_OBJECT_INTF, FIND_ANYWHERE );
00092     if( !p_list ) return NULL;
00093 
00094     for( i = 0; i < p_list->i_count; i++ )
00095     {
00096         p_intf = (intf_thread_t *)p_list->p_values[i].p_object;
00097         if( p_intf->b_block && p_intf->pf_request_window ) break;
00098         p_intf = NULL;
00099     }
00100 
00101     if( !p_intf )
00102     {
00103         vlc_list_release( p_list );
00104         return NULL;
00105     }
00106 
00107     vlc_object_yield( p_intf );
00108     vlc_list_release( p_list );
00109 
00110     p_window = p_intf->pf_request_window( p_intf, p_vout, pi_x_hint, pi_y_hint,
00111                                           pi_width_hint, pi_height_hint );
00112 
00113     if( !p_window ) vlc_object_release( p_intf );
00114     else p_vout->p_parent_intf = p_intf;
00115 
00116     return p_window;
00117 }
00118 
00119 void vout_ReleaseWindow( vout_thread_t *p_vout, void *p_window )
00120 {
00121     intf_thread_t *p_intf = p_vout->p_parent_intf;
00122 
00123     if( !p_intf ) return;
00124 
00125     vlc_mutex_lock( &p_intf->object_lock );
00126     if( p_intf->b_dead )
00127     {
00128         vlc_mutex_unlock( &p_intf->object_lock );
00129         return;
00130     }
00131 
00132     if( !p_intf->pf_release_window )
00133     {
00134         msg_Err( p_vout, "no pf_release_window");
00135         vlc_mutex_unlock( &p_intf->object_lock );
00136         vlc_object_release( p_intf );
00137         return;
00138     }
00139 
00140     p_intf->pf_release_window( p_intf, p_window );
00141 
00142     p_vout->p_parent_intf = NULL;
00143     vlc_mutex_unlock( &p_intf->object_lock );
00144     vlc_object_release( p_intf );
00145 }
00146 
00147 int vout_ControlWindow( vout_thread_t *p_vout, void *p_window,
00148                         int i_query, va_list args )
00149 {
00150     intf_thread_t *p_intf = p_vout->p_parent_intf;
00151     int i_ret;
00152 
00153     if( !p_intf ) return VLC_EGENERIC;
00154 
00155     vlc_mutex_lock( &p_intf->object_lock );
00156     if( p_intf->b_dead )
00157     {
00158         vlc_mutex_unlock( &p_intf->object_lock );
00159         return VLC_EGENERIC;
00160     }
00161 
00162     if( !p_intf->pf_control_window )
00163     {
00164         msg_Err( p_vout, "no pf_control_window");
00165         vlc_mutex_unlock( &p_intf->object_lock );
00166         return VLC_EGENERIC;
00167     }
00168 
00169     i_ret = p_intf->pf_control_window( p_intf, p_window, i_query, args );
00170     vlc_mutex_unlock( &p_intf->object_lock );
00171     return i_ret;
00172 }
00173 
00174 /*****************************************************************************
00175  * vout_IntfInit: called during the vout creation to initialise misc things.
00176  *****************************************************************************/
00177 void vout_IntfInit( vout_thread_t *p_vout )
00178 {
00179     vlc_value_t val, text, old_val;
00180     vlc_bool_t b_force_par = VLC_FALSE;
00181 
00182     /* Create a few object variables we'll need later on */
00183     var_Create( p_vout, "snapshot-path", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
00184     var_Create( p_vout, "snapshot-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
00185     var_Create( p_vout, "width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00186     var_Create( p_vout, "height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00187     var_Create( p_vout, "align", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00188     var_Get( p_vout, "align", &val );
00189     p_vout->i_alignment = val.i_int;
00190 
00191     var_Create( p_vout, "video-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00192     var_Create( p_vout, "video-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00193 
00194     /* Zoom object var */
00195     var_Create( p_vout, "zoom", VLC_VAR_FLOAT | VLC_VAR_ISCOMMAND |
00196                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
00197 
00198     text.psz_string = _("Zoom");
00199     var_Change( p_vout, "zoom", VLC_VAR_SETTEXT, &text, NULL );
00200 
00201     var_Get( p_vout, "zoom", &old_val );
00202     if( old_val.f_float == 0.25 ||
00203         old_val.f_float == 0.5 ||
00204         old_val.f_float == 1 ||
00205         old_val.f_float == 2 )
00206     {
00207         var_Change( p_vout, "zoom", VLC_VAR_DELCHOICE, &old_val, NULL );
00208     }
00209 
00210     val.f_float = 0.25; text.psz_string = _("1:4 Quarter");
00211     var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
00212     val.f_float = 0.5; text.psz_string = _("1:2 Half");
00213     var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
00214     val.f_float = 1; text.psz_string = _("1:1 Original");
00215     var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
00216     val.f_float = 2; text.psz_string = _("2:1 Double");
00217     var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
00218 
00219     var_Set( p_vout, "zoom", old_val );
00220 
00221     var_AddCallback( p_vout, "zoom", ZoomCallback, NULL );
00222 
00223     /* Crop object var */
00224     var_Create( p_vout, "crop", VLC_VAR_STRING |
00225                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
00226 
00227     text.psz_string = _("Crop");
00228     var_Change( p_vout, "crop", VLC_VAR_SETTEXT, &text, NULL );
00229 
00230     val.psz_string = "";
00231     var_Change( p_vout, "crop", VLC_VAR_DELCHOICE, &val, 0 );
00232     val.psz_string = ""; text.psz_string = _("Default");
00233     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
00234     val.psz_string = "001:1"; text.psz_string = _("1:1");
00235     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
00236     val.psz_string = "004:3"; text.psz_string = _("4:3");
00237     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
00238     val.psz_string = "16:9"; text.psz_string = _("16:9");
00239     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
00240     val.psz_string = "221:100"; text.psz_string = _("221:100");
00241     var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
00242 
00243     var_AddCallback( p_vout, "crop", CropCallback, NULL );
00244     var_Get( p_vout, "crop", &old_val );
00245     if( old_val.psz_string && *old_val.psz_string )
00246         var_Change( p_vout, "crop", VLC_VAR_TRIGGER_CALLBACKS, 0, 0 );
00247     if( old_val.psz_string ) free( old_val.psz_string );
00248 
00249     /* Monitor pixel aspect-ratio */
00250     var_Create( p_vout, "monitor-par", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
00251     var_Get( p_vout, "monitor-par", &val );
00252     if( val.psz_string && *val.psz_string )
00253     {
00254         char *psz_parser = strchr( val.psz_string, ':' );
00255         unsigned int i_aspect_num = 0, i_aspect_den = 0;
00256         float i_aspect = 0;
00257         if( psz_parser )
00258         {
00259             i_aspect_num = strtol( val.psz_string, 0, 0 );
00260             i_aspect_den = strtol( ++psz_parser, 0, 0 );
00261         }
00262         else
00263         {
00264             i_aspect = atof( val.psz_string );
00265             vlc_ureduce( &i_aspect_num, &i_aspect_den,
00266                          i_aspect *VOUT_ASPECT_FACTOR, VOUT_ASPECT_FACTOR, 0 );
00267         }
00268         if( !i_aspect_num || !i_aspect_den ) i_aspect_num = i_aspect_den = 1;
00269 
00270         p_vout->i_par_num = i_aspect_num;
00271         p_vout->i_par_den = i_aspect_den;
00272 
00273         vlc_ureduce( &p_vout->i_par_num, &p_vout->i_par_den,
00274                      p_vout->i_par_num, p_vout->i_par_den, 0 );
00275 
00276         msg_Dbg( p_vout, "monitor pixel aspect-ratio overriding: %i:%i",
00277                  p_vout->i_par_num, p_vout->i_par_den );
00278         b_force_par = VLC_TRUE;
00279     }
00280     if( val.psz_string ) free( val.psz_string );
00281 
00282     /* Aspect-ratio object var */
00283     var_Create( p_vout, "aspect-ratio", VLC_VAR_STRING |
00284                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
00285 
00286     text.psz_string = _("Aspect-ratio");
00287     var_Change( p_vout, "aspect-ratio", VLC_VAR_SETTEXT, &text, NULL );
00288 
00289     val.psz_string = "";
00290     var_Change( p_vout, "aspect-ratio", VLC_VAR_DELCHOICE, &val, 0 );
00291     val.psz_string = ""; text.psz_string = _("Default");
00292     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
00293     val.psz_string = "001:1"; text.psz_string = _("1:1");
00294     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
00295     val.psz_string = "004:3"; text.psz_string = _("4:3");
00296     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
00297     val.psz_string = "16:9"; text.psz_string = _("16:9");
00298     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
00299     val.psz_string = "221:100"; text.psz_string = _("221:100");
00300     var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
00301 
00302     var_AddCallback( p_vout, "aspect-ratio", AspectCallback, NULL );
00303     var_Get( p_vout, "aspect-ratio", &old_val );
00304     if( (old_val.psz_string && *old_val.psz_string) || b_force_par )
00305         var_Change( p_vout, "aspect-ratio", VLC_VAR_TRIGGER_CALLBACKS, 0, 0 );
00306     if( old_val.psz_string ) free( old_val.psz_string );
00307 
00308     /* Initialize the dimensions of the video window */
00309     InitWindowSize( p_vout, &p_vout->i_window_width,
00310                     &p_vout->i_window_height );
00311 
00312     /* Add a variable to indicate if the window should be on top of others */
00313     var_Create( p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00314     text.psz_string = _("Always on top");
00315     var_Change( p_vout, "video-on-top", VLC_VAR_SETTEXT, &text, NULL );
00316     var_AddCallback( p_vout, "video-on-top", OnTopCallback, NULL );
00317 
00318     /* Add a variable to indicate whether we want window decoration or not */
00319     var_Create( p_vout, "video-deco", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00320 
00321     /* Add a fullscreen variable */
00322     var_Create( p_vout, "fullscreen", VLC_VAR_BOOL );
00323     text.psz_string = _("Fullscreen");
00324     var_Change( p_vout, "fullscreen", VLC_VAR_SETTEXT, &text, NULL );
00325     var_Change( p_vout, "fullscreen", VLC_VAR_INHERITVALUE, &val, NULL );
00326     if( val.b_bool )
00327     {
00328         /* user requested fullscreen */
00329         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
00330     }
00331     var_AddCallback( p_vout, "fullscreen", FullscreenCallback, NULL );
00332 
00333     /* Add a snapshot variable */
00334     var_Create( p_vout, "video-snapshot", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
00335     text.psz_string = _("Snapshot");
00336     var_Change( p_vout, "video-snapshot", VLC_VAR_SETTEXT, &text, NULL );
00337     var_AddCallback( p_vout, "video-snapshot", SnapshotCallback, NULL );
00338 
00339     /* Mouse coordinates */
00340     var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
00341     var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
00342     var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
00343     var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
00344     var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
00345 
00346     var_Create( p_vout, "intf-change", VLC_VAR_BOOL );
00347     val.b_bool = VLC_TRUE;
00348     var_Set( p_vout, "intf-change", val );
00349 }
00350 
00351 /*****************************************************************************
00352  * vout_Snapshot: generates a snapshot.
00353  *****************************************************************************/
00354 int vout_Snapshot( vout_thread_t *p_vout, picture_t *p_pic )
00355 {
00356     image_handler_t *p_image = image_HandlerCreate( p_vout );
00357     video_format_t fmt_in = {0}, fmt_out = {0};
00358     char *psz_filename;
00359     subpicture_t *p_subpic;
00360     picture_t *p_pif;
00361     vlc_value_t val, format;
00362     int i_ret;
00363 
00364     var_Get( p_vout, "snapshot-path", &val );
00365     if( val.psz_string && !*val.psz_string )
00366     {
00367         free( val.psz_string );
00368         val.psz_string = 0;
00369     }
00370 
00371 #if defined(SYS_DARWIN) || defined(SYS_BEOS)
00372     if( !val.psz_string && p_vout->p_vlc->psz_homedir )
00373     {
00374         asprintf( &val.psz_string, "%s/Desktop",
00375                   p_vout->p_vlc->psz_homedir );
00376     }
00377 
00378 #elif defined(WIN32) && !defined(UNDER_CE)
00379     if( !val.psz_string && p_vout->p_vlc->psz_homedir )
00380     {
00381         /* Get the My Pictures folder path */
00382 
00383         char *p_mypicturesdir = NULL;
00384         typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
00385                                                    LPSTR );
00386         #ifndef CSIDL_FLAG_CREATE
00387         #   define CSIDL_FLAG_CREATE 0x8000
00388         #endif
00389         #ifndef CSIDL_MYPICTURES
00390         #   define CSIDL_MYPICTURES 0x27
00391         #endif
00392         #ifndef SHGFP_TYPE_CURRENT
00393         #   define SHGFP_TYPE_CURRENT 0
00394         #endif
00395 
00396         HINSTANCE shfolder_dll;
00397         SHGETFOLDERPATH SHGetFolderPath ;
00398 
00399         /* load the shfolder dll to retrieve SHGetFolderPath */
00400         if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
00401         {
00402             SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
00403                                                       _T("SHGetFolderPathA") );
00404             if( SHGetFolderPath != NULL )
00405             {
00406                 p_mypicturesdir = (char *)malloc( MAX_PATH );
00407                 if( p_mypicturesdir ) 
00408                 {
00409 
00410                     if( S_OK != SHGetFolderPath( NULL,
00411                                         CSIDL_MYPICTURES | CSIDL_FLAG_CREATE,
00412                                         NULL, SHGFP_TYPE_CURRENT,
00413                                         p_mypicturesdir ) )
00414                     {
00415                         free( p_mypicturesdir );
00416                         p_mypicturesdir = NULL;
00417                     }
00418                 }
00419             }
00420             FreeLibrary( shfolder_dll );
00421         }
00422 
00423         if( p_mypicturesdir == NULL )
00424         {
00425             asprintf( &val.psz_string, "%s/" CONFIG_DIR,
00426                       p_vout->p_vlc->psz_homedir );
00427         }
00428         else
00429         {
00430             asprintf( &val.psz_string, p_mypicturesdir );
00431             free( p_mypicturesdir );
00432         }
00433     }
00434 
00435 #else
00436     if( !val.psz_string && p_vout->p_vlc->psz_homedir )
00437     {
00438         asprintf( &val.psz_string, "%s/" CONFIG_DIR,
00439                   p_vout->p_vlc->psz_homedir );
00440     }
00441 #endif
00442 
00443     if( !val.psz_string )
00444     {
00445         msg_Err( p_vout, "no directory specified for snapshots" );
00446         return VLC_EGENERIC;
00447     }
00448     var_Get( p_vout, "snapshot-format", &format );
00449     if( !format.psz_string || !*format.psz_string )
00450     {
00451         if( format.psz_string ) free( format.psz_string );
00452         format.psz_string = strdup( "png" );
00453     }
00454 
00455     asprintf( &psz_filename, "%s/vlcsnap-%u.%s", val.psz_string,
00456               (unsigned int)(p_pic->date / 100000) & 0xFFFFFF,
00457               format.psz_string );
00458     free( val.psz_string );
00459     free( format.psz_string );
00460 
00461     /* Save the snapshot */
00462     fmt_in = p_vout->fmt_in;
00463     fmt_out.i_sar_num = fmt_out.i_sar_den = 1;
00464     i_ret = image_WriteUrl( p_image, p_pic, &fmt_in, &fmt_out, psz_filename );
00465     if( i_ret != VLC_SUCCESS )
00466     {
00467         msg_Err( p_vout, "could not create snapshot %s", psz_filename );
00468         free( psz_filename );
00469         image_HandlerDelete( p_image );
00470         return VLC_EGENERIC;
00471     }
00472 
00473     msg_Dbg( p_vout, "snapshot taken (%s)", psz_filename );
00474     free( psz_filename );
00475 
00476     /* Inject a subpicture with the snapshot */
00477     memset( &fmt_out, 0, sizeof(fmt_out) );
00478     fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
00479     p_pif = image_Convert( p_image, p_pic, &fmt_in, &fmt_out );
00480     image_HandlerDelete( p_image );
00481     if( !p_pif ) return VLC_EGENERIC;
00482 
00483     p_subpic = spu_CreateSubpicture( p_vout->p_spu );
00484     if( p_subpic == NULL )
00485     {
00486          p_pif->pf_release( p_pif );
00487          return VLC_EGENERIC;
00488     }
00489 
00490     p_subpic->i_channel = 0;
00491     p_subpic->i_start = mdate();
00492     p_subpic->i_stop = mdate() + 4000000;
00493     p_subpic->b_ephemer = VLC_TRUE;
00494     p_subpic->b_fade = VLC_TRUE;
00495     p_subpic->i_original_picture_width = p_vout->render.i_width * 4;
00496     p_subpic->i_original_picture_height = p_vout->render.i_height * 4;
00497 
00498     p_subpic->p_region = spu_CreateRegion( p_vout->p_spu, &fmt_out );
00499     vout_CopyPicture( p_image->p_parent, &p_subpic->p_region->picture, p_pif );
00500     p_pif->pf_release( p_pif );
00501 
00502     spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
00503 
00504     return VLC_SUCCESS;
00505 }
00506 
00507 /*****************************************************************************
00508  * vout_ControlDefault: default methods for video output control.
00509  *****************************************************************************/
00510 int vout_vaControlDefault( vout_thread_t *p_vout, int i_query, va_list args )
00511 {
00512     switch( i_query )
00513     {
00514     case VOUT_REPARENT:
00515     case VOUT_CLOSE:
00516         if( p_vout->p_parent_intf )
00517         {
00518             vlc_object_release( p_vout->p_parent_intf );
00519             p_vout->p_parent_intf = NULL;
00520         }
00521         return VLC_SUCCESS;
00522         break;
00523 
00524     case VOUT_SNAPSHOT:
00525         p_vout->b_snapshot = VLC_TRUE;
00526         return VLC_SUCCESS;
00527         break;
00528 
00529     default:
00530         msg_Dbg( p_vout, "control query not supported" );
00531         return VLC_EGENERIC;
00532     }
00533 }
00534 
00535 /*****************************************************************************
00536  * InitWindowSize: find the initial dimensions the video window should have.
00537  *****************************************************************************
00538  * This function will check the "width", "height" and "zoom" config options and
00539  * will calculate the size that the video window should have.
00540  *****************************************************************************/
00541 static void InitWindowSize( vout_thread_t *p_vout, unsigned *pi_width,
00542                             unsigned *pi_height )
00543 {
00544     vlc_value_t val;
00545     int i_width, i_height;
00546     uint64_t ll_zoom;
00547 
00548 #define FP_FACTOR 1000                             /* our fixed point factor */
00549 
00550     var_Get( p_vout, "width", &val );
00551     i_width = val.i_int;
00552     var_Get( p_vout, "height", &val );
00553     i_height = val.i_int;
00554     var_Get( p_vout, "zoom", &val );
00555     ll_zoom = (uint64_t)( FP_FACTOR * val.f_float );
00556 
00557     if( i_width > 0 && i_height > 0)
00558     {
00559         *pi_width = (int)( i_width * ll_zoom / FP_FACTOR );
00560         *pi_height = (int)( i_height * ll_zoom / FP_FACTOR );
00561         goto initwsize_end;
00562     }
00563     else if( i_width > 0 )
00564     {
00565         *pi_width = (int)( i_width * ll_zoom / FP_FACTOR );
00566         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom *
00567             p_vout->fmt_in.i_sar_den * i_width / p_vout->fmt_in.i_sar_num /
00568             FP_FACTOR / p_vout->fmt_in.i_visible_width );
00569         goto initwsize_end;
00570     }
00571     else if( i_height > 0 )
00572     {
00573         *pi_height = (int)( i_height * ll_zoom / FP_FACTOR );
00574         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom *
00575             p_vout->fmt_in.i_sar_num * i_height / p_vout->fmt_in.i_sar_den /
00576             FP_FACTOR / p_vout->fmt_in.i_visible_height );
00577         goto initwsize_end;
00578     }
00579 
00580     if( p_vout->fmt_in.i_sar_num >= p_vout->fmt_in.i_sar_den )
00581     {
00582         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom *
00583             p_vout->fmt_in.i_sar_num / p_vout->fmt_in.i_sar_den / FP_FACTOR );
00584         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom 
00585             / FP_FACTOR );
00586     }
00587     else
00588     {
00589         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom 
00590             / FP_FACTOR );
00591         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom *
00592             p_vout->fmt_in.i_sar_den / p_vout->fmt_in.i_sar_num / FP_FACTOR );
00593     }
00594 
00595 initwsize_end:
00596     msg_Dbg( p_vout, "window size: %dx%d", p_vout->i_window_width, 
00597              p_vout->i_window_height );
00598 
00599 #undef FP_FACTOR
00600 }
00601 
00602 /*****************************************************************************
00603  * Object variables callbacks
00604  *****************************************************************************/
00605 static int ZoomCallback( vlc_object_t *p_this, char const *psz_cmd,
00606                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
00607 {
00608     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00609     InitWindowSize( p_vout, &p_vout->i_window_width,
00610                     &p_vout->i_window_height );
00611     vout_Control( p_vout, VOUT_SET_ZOOM );
00612     return VLC_SUCCESS;
00613 }
00614 
00615 static int CropCallback( vlc_object_t *p_this, char const *psz_cmd,
00616                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
00617 {
00618     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00619     int64_t i_aspect_num, i_aspect_den;
00620     unsigned int i_width, i_height;
00621 
00622     char *psz_end, *psz_parser = strchr( newval.psz_string, ':' );
00623 
00624     /* Restore defaults */
00625     p_vout->fmt_in.i_x_offset = p_vout->fmt_render.i_x_offset;
00626     p_vout->fmt_in.i_visible_width = p_vout->fmt_render.i_visible_width;
00627     p_vout->fmt_in.i_y_offset = p_vout->fmt_render.i_y_offset;
00628     p_vout->fmt_in.i_visible_height = p_vout->fmt_render.i_visible_height;
00629 
00630     if( !psz_parser ) goto crop_end;
00631 
00632     i_aspect_num = strtol( newval.psz_string, &psz_end, 0 );
00633     if( psz_end == newval.psz_string || !i_aspect_num ) goto crop_end;
00634 
00635     i_aspect_den = strtol( ++psz_parser, &psz_end, 0 );
00636     if( psz_end == psz_parser || !i_aspect_den ) goto crop_end;
00637 
00638     i_width = p_vout->fmt_in.i_sar_den * p_vout->fmt_render.i_visible_height *
00639         i_aspect_num / i_aspect_den / p_vout->fmt_in.i_sar_num;
00640     i_height = p_vout->fmt_render.i_visible_width * p_vout->fmt_in.i_sar_num *
00641         i_aspect_den / i_aspect_num / p_vout->fmt_in.i_sar_den;
00642 
00643     if( i_width < p_vout->fmt_render.i_visible_width )
00644     {
00645         p_vout->fmt_in.i_x_offset = p_vout->fmt_render.i_x_offset +
00646             (p_vout->fmt_render.i_visible_width - i_width) / 2;
00647         p_vout->fmt_in.i_visible_width = i_width;
00648     }
00649     else
00650     {
00651         p_vout->fmt_in.i_y_offset = p_vout->fmt_render.i_y_offset +
00652             (p_vout->fmt_render.i_visible_height - i_height) / 2;
00653         p_vout->fmt_in.i_visible_height = i_height;
00654     }
00655 
00656  crop_end:
00657     InitWindowSize( p_vout, &p_vout->i_window_width,
00658                     &p_vout->i_window_height );
00659 
00660     p_vout->i_changes |= VOUT_CROP_CHANGE;
00661 
00662     msg_Dbg( p_vout, "cropping picture %ix%i to %i,%i,%ix%i",
00663              p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
00664              p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
00665              p_vout->fmt_in.i_visible_width,
00666              p_vout->fmt_in.i_visible_height );
00667 
00668     return VLC_SUCCESS;
00669 }
00670 
00671 static int AspectCallback( vlc_object_t *p_this, char const *psz_cmd,
00672                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
00673 {
00674     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00675     unsigned int i_aspect_num, i_aspect_den, i_sar_num, i_sar_den;
00676     vlc_value_t val;
00677 
00678     char *psz_end, *psz_parser = strchr( newval.psz_string, ':' );
00679 
00680     /* Restore defaults */
00681     p_vout->fmt_in.i_sar_num = p_vout->fmt_render.i_sar_num;
00682     p_vout->fmt_in.i_sar_den = p_vout->fmt_render.i_sar_den;
00683     p_vout->fmt_in.i_aspect = p_vout->fmt_render.i_aspect;
00684     p_vout->render.i_aspect = p_vout->fmt_render.i_aspect;
00685 
00686     if( !psz_parser ) goto aspect_end;
00687 
00688     i_aspect_num = strtol( newval.psz_string, &psz_end, 0 );
00689     if( psz_end == newval.psz_string || !i_aspect_num ) goto aspect_end;
00690 
00691     i_aspect_den = strtol( ++psz_parser, &psz_end, 0 );
00692     if( psz_end == psz_parser || !i_aspect_den ) goto aspect_end;
00693 
00694     i_sar_num = i_aspect_num * p_vout->fmt_render.i_visible_height;
00695     i_sar_den = i_aspect_den * p_vout->fmt_render.i_visible_width;
00696     vlc_ureduce( &i_sar_num, &i_sar_den, i_sar_num, i_sar_den, 0 );
00697     p_vout->fmt_in.i_sar_num = i_sar_num;
00698     p_vout->fmt_in.i_sar_den = i_sar_den;
00699     p_vout->fmt_in.i_aspect = i_aspect_num * VOUT_ASPECT_FACTOR / i_aspect_den;
00700     p_vout->render.i_aspect = p_vout->fmt_in.i_aspect;
00701 
00702  aspect_end:
00703     if( p_vout->i_par_num && p_vout->i_par_den )
00704     {
00705         p_vout->fmt_in.i_sar_num *= p_vout->i_par_den;
00706         p_vout->fmt_in.i_sar_den *= p_vout->i_par_num;
00707         p_vout->fmt_in.i_aspect = p_vout->fmt_in.i_aspect *
00708             p_vout->i_par_den / p_vout->i_par_num;
00709         p_vout->render.i_aspect = p_vout->fmt_in.i_aspect;
00710     }
00711 
00712     p_vout->i_changes |= VOUT_ASPECT_CHANGE;
00713 
00714     vlc_ureduce( &i_aspect_num, &i_aspect_den,
00715                  p_vout->fmt_in.i_aspect, VOUT_ASPECT_FACTOR, 0 );
00716     msg_Dbg( p_vout, "new aspect-ratio %i:%i, sample aspect-ratio %i:%i",
00717              i_aspect_num, i_aspect_den,
00718              p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
00719 
00720     var_Get( p_vout, "crop", &val );
00721     return CropCallback( p_this, 0, val, val, 0 );
00722 
00723     return VLC_SUCCESS;
00724 }
00725 
00726 static int OnTopCallback( vlc_object_t *p_this, char const *psz_cmd,
00727                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
00728 {
00729     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00730     playlist_t *p_playlist;
00731     vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, newval.b_bool );
00732 
00733     p_playlist = (playlist_t *)vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
00734                                                  FIND_PARENT );
00735     if( p_playlist )
00736     {
00737         /* Modify playlist as well because the vout might have to be restarted */
00738         var_Create( p_playlist, "video-on-top", VLC_VAR_BOOL );
00739         var_Set( p_playlist, "video-on-top", newval );
00740 
00741         vlc_object_release( p_playlist );
00742     }
00743     return VLC_SUCCESS;
00744 }
00745 
00746 static int FullscreenCallback( vlc_object_t *p_this, char const *psz_cmd,
00747                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00748 {
00749     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00750     playlist_t *p_playlist;
00751     vlc_value_t val;
00752 
00753     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
00754 
00755     p_playlist = (playlist_t *)vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
00756                                                  FIND_PARENT );
00757     if( p_playlist )
00758     {
00759         /* Modify playlist as well because the vout might have to be restarted */
00760         var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL );
00761         var_Set( p_playlist, "fullscreen", newval );
00762 
00763         vlc_object_release( p_playlist );
00764     }
00765 
00766     /* Disable "always on top" in fullscreen mode */
00767     var_Get( p_vout, "video-on-top", &val );
00768     if( newval.b_bool && val.b_bool )
00769     {
00770         val.b_bool = VLC_FALSE;
00771         vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, val.b_bool );
00772     }
00773     else if( !newval.b_bool && val.b_bool )
00774     {
00775         vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, val.b_bool );
00776     }
00777 
00778     val.b_bool = VLC_TRUE;
00779     var_Set( p_vout, "intf-change", val );
00780     return VLC_SUCCESS;
00781 }
00782 
00783 static int SnapshotCallback( vlc_object_t *p_this, char const *psz_cmd,
00784                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00785 {
00786     vout_thread_t *p_vout = (vout_thread_t *)p_this;
00787     vout_Control( p_vout, VOUT_SNAPSHOT );
00788     return VLC_SUCCESS;
00789 }

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