1 /*****************************************************************************
2 * opengl.c: OpenGL video output
3 *****************************************************************************
4 * Copyright (C) 2004 VideoLAN
7 * Authors: Cyril Deguet <asmax@videolan.org>
8 * Gildas Bazin <gbazin@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <errno.h> /* ENOMEM */
29 #include <stdlib.h> /* malloc(), free() */
36 #include <OpenGL/gl.h>
37 #include <OpenGL/glext.h>
39 /* On OS X, use GL_TEXTURE_RECTANGLE_EXT instead of GL_TEXTURE_2D.
40 This allows sizes which are not powers of 2 */
41 #define VLCGL_TARGET GL_TEXTURE_RECTANGLE_EXT
43 /* OS X OpenGL supports YUV. Hehe. */
44 #define VLCGL_FORMAT GL_YCBCR_422_APPLE
45 #define VLCGL_TYPE GL_UNSIGNED_SHORT_8_8_APPLE
49 #define VLCGL_TARGET GL_TEXTURE_2D
52 #ifndef GL_UNSIGNED_SHORT_5_6_5
53 #define GL_UNSIGNED_SHORT_5_6_5 0x8363
55 //#define VLCGL_RGB_FORMAT GL_RGB
56 //#define VLCGL_RGB_TYPE GL_UNSIGNED_SHORT_5_6_5
59 //#define VLCGL_RGB_FORMAT GL_RGB
60 //#define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
63 #define VLCGL_RGB_FORMAT GL_RGBA
64 #define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
66 /* Use RGB on Win32/GLX */
67 #define VLCGL_FORMAT VLCGL_RGB_FORMAT
68 #define VLCGL_TYPE VLCGL_RGB_TYPE
72 #define OPENGL_EFFECT_NONE 1
73 #define OPENGL_EFFECT_CUBE 2
74 #define OPENGL_EFFECT_TRANSPARENT_CUBE 4
76 /*****************************************************************************
78 *****************************************************************************/
79 static int CreateVout ( vlc_object_t * );
80 static void DestroyVout ( vlc_object_t * );
81 static int Init ( vout_thread_t * );
82 static void End ( vout_thread_t * );
83 static int Manage ( vout_thread_t * );
84 static void Render ( vout_thread_t *, picture_t * );
85 static void DisplayVideo ( vout_thread_t *, picture_t * );
86 static int Control ( vout_thread_t *, int, va_list );
88 static inline int GetAlignedSize( int );
90 static int InitTextures( vout_thread_t * );
91 static int SendEvents( vlc_object_t *, char const *,
92 vlc_value_t, vlc_value_t, void * );
94 /*****************************************************************************
96 *****************************************************************************/
97 #define SPEED_TEXT N_( "OpenGL cube rotation speed" )
98 #define SPEED_LONGTEXT N_( "If the OpenGL cube effect is enabled, this " \
99 "controls its rotation speed." )
101 #define EFFECT_TEXT N_("Select effect")
102 #define EFFECT_LONGTEXT N_( \
103 "Allows you to select different visual effects.")
105 static char *ppsz_effects[] = {
106 "none", "cube", "transparent-cube" };
107 static char *ppsz_effects_text[] = {
108 N_("None"), N_("Cube"), N_("Transparent Cube") };
111 set_description( _("OpenGL video output") );
113 set_capability( "video output", 0 );
115 set_capability( "video output", 20 );
117 add_shortcut( "opengl" );
118 add_float( "opengl-cube-speed", 2.0, NULL, SPEED_TEXT,
119 SPEED_LONGTEXT, VLC_FALSE );
120 set_callbacks( CreateVout, DestroyVout );
121 add_string( "opengl-effect", "none", NULL, EFFECT_TEXT,
122 EFFECT_LONGTEXT, VLC_TRUE );
123 change_string_list( ppsz_effects, ppsz_effects_text, 0 );
126 /*****************************************************************************
127 * vout_sys_t: video output method descriptor
128 *****************************************************************************
129 * This structure is part of the video output thread descriptor.
130 * It describes the OpenGL specific properties of the output thread.
131 *****************************************************************************/
134 vout_thread_t *p_vout;
136 uint8_t *pp_buffer[2];
140 GLuint p_textures[2];
147 /*****************************************************************************
148 * CreateVout: This function allocates and initializes the OpenGL vout method.
149 *****************************************************************************/
150 static int CreateVout( vlc_object_t *p_this )
152 vout_thread_t *p_vout = (vout_thread_t *)p_this;
155 /* Allocate structure */
156 p_vout->p_sys = p_sys = malloc( sizeof( vout_sys_t ) );
159 msg_Err( p_vout, "out of memory" );
163 var_Create( p_vout, "opengl-effect", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
166 p_sys->i_tex_width = p_vout->render.i_width;
167 p_sys->i_tex_height = p_vout->render.i_height;
169 /* A texture must have a size aligned on a power of 2 */
170 p_sys->i_tex_width = GetAlignedSize( p_vout->render.i_width );
171 p_sys->i_tex_height = GetAlignedSize( p_vout->render.i_height );
174 msg_Dbg( p_vout, "Texture size: %dx%d", p_sys->i_tex_width,
175 p_sys->i_tex_height );
179 (vout_thread_t *)vlc_object_create( p_this, VLC_OBJECT_OPENGL );
180 if( p_sys->p_vout == NULL )
182 msg_Err( p_vout, "out of memory" );
185 vlc_object_attach( p_sys->p_vout, p_this );
187 p_sys->p_vout->i_window_width = p_vout->i_window_width;
188 p_sys->p_vout->i_window_height = p_vout->i_window_height;
189 p_sys->p_vout->b_fullscreen = p_vout->b_fullscreen;
190 p_sys->p_vout->render.i_width = p_vout->render.i_width;
191 p_sys->p_vout->render.i_height = p_vout->render.i_height;
192 p_sys->p_vout->render.i_aspect = p_vout->render.i_aspect;
193 p_sys->p_vout->b_scale = p_vout->b_scale;
194 p_sys->p_vout->i_alignment = p_vout->i_alignment;
196 p_sys->p_vout->p_module =
197 module_Need( p_sys->p_vout, "opengl provider", NULL, 0 );
198 if( p_sys->p_vout->p_module == NULL )
200 msg_Warn( p_vout, "No OpenGL provider found" );
201 vlc_object_detach( p_sys->p_vout );
202 vlc_object_destroy( p_sys->p_vout );
206 p_sys->f_speed = var_CreateGetFloat( p_vout, "opengl-cube-speed" );
208 p_vout->pf_init = Init;
209 p_vout->pf_end = End;
210 p_vout->pf_manage = Manage;
211 p_vout->pf_render = Render;
212 p_vout->pf_display = DisplayVideo;
213 p_vout->pf_control = Control;
215 /* Forward events from the opengl provider */
216 var_Create( p_sys->p_vout, "mouse-x", VLC_VAR_INTEGER );
217 var_Create( p_sys->p_vout, "mouse-y", VLC_VAR_INTEGER );
218 var_Create( p_sys->p_vout, "mouse-moved", VLC_VAR_BOOL );
219 var_Create( p_sys->p_vout, "mouse-clicked", VLC_VAR_INTEGER );
220 var_Create( p_sys->p_vout, "video-on-top",
221 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
223 var_AddCallback( p_sys->p_vout, "mouse-x", SendEvents, p_vout );
224 var_AddCallback( p_sys->p_vout, "mouse-y", SendEvents, p_vout );
225 var_AddCallback( p_sys->p_vout, "mouse-moved", SendEvents, p_vout );
226 var_AddCallback( p_sys->p_vout, "mouse-clicked", SendEvents, p_vout );
231 /*****************************************************************************
232 * Init: initialize the OpenGL video thread output method
233 *****************************************************************************/
234 static int Init( vout_thread_t *p_vout )
236 vout_sys_t *p_sys = p_vout->p_sys;
240 p_sys->p_vout->pf_init( p_sys->p_vout );
243 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
244 p_vout->output.i_rmask = 0x00ff0000;
245 p_vout->output.i_gmask = 0x0000ff00;
246 p_vout->output.i_bmask = 0x000000ff;
249 #if VLCGL_RGB_FORMAT == GL_RGB
250 # if VLCGL_RGB_TYPE == GL_UNSIGNED_BYTE
251 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
252 p_vout->output.i_rmask = 0x000000ff;
253 p_vout->output.i_gmask = 0x0000ff00;
254 p_vout->output.i_bmask = 0x00ff0000;
257 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
258 p_vout->output.i_rmask = 0xf800;
259 p_vout->output.i_gmask = 0x07e0;
260 p_vout->output.i_bmask = 0x001f;
264 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
265 p_vout->output.i_rmask = 0x000000ff;
266 p_vout->output.i_gmask = 0x0000ff00;
267 p_vout->output.i_bmask = 0x00ff0000;
272 /* Since OpenGL can do rescaling for us, stick to the default
273 * coordinates and aspect. */
274 p_vout->output.i_width = p_vout->render.i_width;
275 p_vout->output.i_height = p_vout->render.i_height;
276 p_vout->output.i_aspect = p_vout->render.i_aspect;
278 /* We know the chroma, allocate one buffer which will be used
279 * directly by the decoder */
280 p_sys->pp_buffer[0] =
281 malloc( p_sys->i_tex_width * p_sys->i_tex_height * i_pixel_pitch );
282 if( !p_sys->pp_buffer[0] )
284 msg_Err( p_vout, "Out of memory" );
287 p_sys->pp_buffer[1] =
288 malloc( p_sys->i_tex_width * p_sys->i_tex_height * i_pixel_pitch );
289 if( !p_sys->pp_buffer[1] )
291 msg_Err( p_vout, "Out of memory" );
295 p_vout->p_picture[0].i_planes = 1;
296 p_vout->p_picture[0].p->p_pixels = p_sys->pp_buffer[0];
297 p_vout->p_picture[0].p->i_lines = p_vout->output.i_height;
298 p_vout->p_picture[0].p->i_visible_lines = p_vout->output.i_height;
299 p_vout->p_picture[0].p->i_pixel_pitch = i_pixel_pitch;
300 p_vout->p_picture[0].p->i_pitch = p_vout->output.i_width *
301 p_vout->p_picture[0].p->i_pixel_pitch;
302 p_vout->p_picture[0].p->i_visible_pitch = p_vout->output.i_width *
303 p_vout->p_picture[0].p->i_pixel_pitch;
305 p_vout->p_picture[0].i_status = DESTROYED_PICTURE;
306 p_vout->p_picture[0].i_type = DIRECT_PICTURE;
308 PP_OUTPUTPICTURE[ 0 ] = &p_vout->p_picture[0];
310 I_OUTPUTPICTURES = 1;
312 InitTextures( p_vout );
315 glDisable(GL_DEPTH_TEST);
316 glDepthMask(GL_FALSE);
317 glDisable(GL_CULL_FACE);
318 glClear( GL_COLOR_BUFFER_BIT );
320 /* Check if the user asked for useless visual effects */
321 var_Get( p_vout, "opengl-effect", &val );
322 if( !val.psz_string || !strcmp( val.psz_string, "none" ))
324 p_sys->i_effect = OPENGL_EFFECT_NONE;
326 else if( !strcmp( val.psz_string, "cube" ) )
328 p_sys->i_effect = OPENGL_EFFECT_CUBE;
330 glEnable( GL_CULL_FACE);
331 //glEnable( GL_DEPTH_TEST );
333 else if( !strcmp( val.psz_string, "transparent-cube" ) )
335 p_sys->i_effect = OPENGL_EFFECT_TRANSPARENT_CUBE;
337 glDisable( GL_DEPTH_TEST );
338 glEnable( GL_BLEND );
339 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
343 msg_Warn( p_vout, "no valid opengl effect provided, using "
345 p_sys->i_effect = OPENGL_EFFECT_NONE;
347 if( val.psz_string ) free( val.psz_string );
349 if( p_sys->i_effect & ( OPENGL_EFFECT_CUBE |
350 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
352 /* Set the perpective */
353 glMatrixMode( GL_PROJECTION );
355 glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
356 glMatrixMode( GL_MODELVIEW );
358 glTranslatef( 0.0, 0.0, - 5.0 );
364 /*****************************************************************************
365 * End: terminate GLX video thread output method
366 *****************************************************************************/
367 static void End( vout_thread_t *p_vout )
373 /*****************************************************************************
374 * Destroy: destroy GLX video thread output method
375 *****************************************************************************
376 * Terminate an output method created by CreateVout
377 *****************************************************************************/
378 static void DestroyVout( vlc_object_t *p_this )
380 vout_thread_t *p_vout = (vout_thread_t *)p_this;
381 vout_sys_t *p_sys = p_vout->p_sys;
383 module_Unneed( p_sys->p_vout, p_sys->p_vout->p_module );
384 vlc_object_detach( p_sys->p_vout );
385 vlc_object_destroy( p_sys->p_vout );
387 /* Free the texture buffer*/
388 if( p_sys->pp_buffer[0] ) free( p_sys->pp_buffer[0] );
389 if( p_sys->pp_buffer[1] ) free( p_sys->pp_buffer[1] );
394 /*****************************************************************************
395 * Manage: handle Sys events
396 *****************************************************************************
397 * This function should be called regularly by video output thread. It returns
398 * a non null value if an error occurred.
399 *****************************************************************************/
400 static int Manage( vout_thread_t *p_vout )
402 vout_sys_t *p_sys = p_vout->p_sys;
403 int i_ret, i_fullscreen_change;
405 i_fullscreen_change = ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE );
407 p_sys->p_vout->i_changes = p_vout->i_changes;
408 i_ret = p_sys->p_vout->pf_manage( p_sys->p_vout );
409 p_vout->i_changes = p_sys->p_vout->i_changes;
412 /* On OS X, we create the window and the GL view when entering
413 fullscreen - the textures have to be inited again */
414 if( i_fullscreen_change )
416 InitTextures( p_vout );
418 switch( p_sys->i_effect )
420 case OPENGL_EFFECT_CUBE:
421 glEnable( GL_CULL_FACE );
424 case OPENGL_EFFECT_TRANSPARENT_CUBE:
425 glDisable( GL_DEPTH_TEST );
426 glEnable( GL_BLEND );
427 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
431 if( p_sys->i_effect & ( OPENGL_EFFECT_CUBE |
432 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
434 /* Set the perpective */
435 glMatrixMode( GL_PROJECTION );
437 glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
438 glMatrixMode( GL_MODELVIEW );
440 glTranslatef( 0.0, 0.0, - 5.0 );
448 /*****************************************************************************
449 * Render: render previously calculated output
450 *****************************************************************************/
451 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
453 vout_sys_t *p_sys = p_vout->p_sys;
454 float f_width, f_height;
456 /* glTexCoord works differently with GL_TEXTURE_2D and
457 GL_TEXTURE_RECTANGLE_EXT */
459 f_width = (float)p_vout->output.i_width;
460 f_height = (float)p_vout->output.i_height;
462 f_width = (float)p_vout->output.i_width / p_sys->i_tex_width;
463 f_height = (float)p_vout->output.i_height / p_sys->i_tex_height;
466 glClear( GL_COLOR_BUFFER_BIT );
468 /* On Win32/GLX, we do this the usual way:
469 + Fill the buffer with new content,
470 + Reload the texture,
473 On OS X with VRAM or AGP texturing, the order has to be:
474 + Reload the texture,
475 + Fill the buffer with new content,
478 (Thanks to gcc from the Arstechnica forums for the tip)
480 Therefore, we have to use two buffers and textures. On Win32/GLX,
481 we reload the texture to be displayed and use it right away. On
482 OS X, we first render, then reload the texture to be used next
486 glBindTexture( VLCGL_TARGET, p_sys->p_textures[p_sys->i_index] );
489 /* Update the texture */
490 glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
491 p_vout->render.i_width, p_vout->render.i_height,
492 VLCGL_RGB_FORMAT, VLCGL_RGB_TYPE, p_sys->pp_buffer[0] );
495 if( p_sys->i_effect == OPENGL_EFFECT_NONE )
497 glEnable( VLCGL_TARGET );
498 glBegin( GL_POLYGON );
499 glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, 1.0 );
500 glTexCoord2f( f_width, 0.0 ); glVertex2f( 1.0, 1.0 );
501 glTexCoord2f( f_width, f_height ); glVertex2f( 1.0, -1.0 );
502 glTexCoord2f( 0.0, f_height ); glVertex2f( -1.0, -1.0 );
507 glRotatef( 0.5 * p_sys->f_speed , 0.3, 0.5, 0.7 );
509 glEnable( VLCGL_TARGET );
513 glTexCoord2f( 0, 0 ); glVertex3f( - 1.0, 1.0, 1.0 );
514 glTexCoord2f( 0, f_height ); glVertex3f( - 1.0, - 1.0, 1.0 );
515 glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, 1.0 );
516 glTexCoord2f( f_width, 0 ); glVertex3f( 1.0, 1.0, 1.0 );
519 glTexCoord2f( 0, 0 ); glVertex3f( - 1.0, 1.0, - 1.0 );
520 glTexCoord2f( 0, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
521 glTexCoord2f( f_width, f_height ); glVertex3f( - 1.0, - 1.0, 1.0 );
522 glTexCoord2f( f_width, 0 ); glVertex3f( - 1.0, 1.0, 1.0 );
525 glTexCoord2f( 0, 0 ); glVertex3f( 1.0, 1.0, - 1.0 );
526 glTexCoord2f( 0, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
527 glTexCoord2f( f_width, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
528 glTexCoord2f( f_width, 0 ); glVertex3f( - 1.0, 1.0, - 1.0 );
531 glTexCoord2f( 0, 0 ); glVertex3f( 1.0, 1.0, 1.0 );
532 glTexCoord2f( 0, f_height ); glVertex3f( 1.0, - 1.0, 1.0 );
533 glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
534 glTexCoord2f( f_width, 0 ); glVertex3f( 1.0, 1.0, - 1.0 );
537 glTexCoord2f( 0, 0 ); glVertex3f( - 1.0, 1.0, - 1.0 );
538 glTexCoord2f( 0, f_height ); glVertex3f( - 1.0, 1.0, 1.0 );
539 glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, 1.0, 1.0 );
540 glTexCoord2f( f_width, 0 ); glVertex3f( 1.0, 1.0, - 1.0 );
543 glTexCoord2f( 0, 0 ); glVertex3f( - 1.0, - 1.0, 1.0 );
544 glTexCoord2f( 0, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
545 glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
546 glTexCoord2f( f_width, 0 ); glVertex3f( 1.0, - 1.0, 1.0 );
550 glDisable( VLCGL_TARGET );
554 p_sys->i_index = ( p_sys->i_index + 1 ) & 1;
555 p_pic->p->p_pixels = p_sys->pp_buffer[p_sys->i_index];
557 /* Update the texture */
558 glBindTexture( VLCGL_TARGET, p_sys->p_textures[p_sys->i_index] );
559 glTexSubImage2D( VLCGL_TARGET, 0, 0, 0, p_sys->i_tex_width,
560 p_sys->i_tex_height, VLCGL_FORMAT, VLCGL_TYPE,
561 p_sys->pp_buffer[p_sys->i_index] );
565 /*****************************************************************************
566 * DisplayVideo: displays previously rendered output
567 *****************************************************************************/
568 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
570 vout_sys_t *p_sys = p_vout->p_sys;
571 p_sys->p_vout->pf_swap( p_sys->p_vout );
574 int GetAlignedSize( int i_size )
576 /* Return the nearest power of 2 */
578 while( i_result < i_size )
585 /*****************************************************************************
586 * Control: control facility for the vout
587 *****************************************************************************/
588 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
590 vout_sys_t *p_sys = p_vout->p_sys;
592 if( p_sys->p_vout->pf_control )
593 return p_sys->p_vout->pf_control( p_sys->p_vout, i_query, args );
595 return vout_vaControlDefault( p_vout, i_query, args );
598 static int InitTextures( vout_thread_t *p_vout )
600 vout_sys_t *p_sys = p_vout->p_sys;
603 glDeleteTextures( 2, p_sys->p_textures );
604 glGenTextures( 2, p_sys->p_textures );
606 for( i_index = 0; i_index < 2; i_index++ )
608 glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_index] );
610 /* Set the texture parameters */
611 glTexParameterf( VLCGL_TARGET, GL_TEXTURE_PRIORITY, 1.0 );
613 glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
614 glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
616 glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP );
617 glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP );
619 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
622 /* Tell the driver not to make a copy of the texture but to use
624 glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
625 glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );
628 /* Use VRAM texturing */
629 glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
630 GL_STORAGE_CACHED_APPLE );
632 /* Use AGP texturing */
633 glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
634 GL_STORAGE_SHARED_APPLE );
638 /* Call glTexImage2D only once, and use glTexSubImage2D later */
639 glTexImage2D( VLCGL_TARGET, 0, 3, p_sys->i_tex_width,
640 p_sys->i_tex_height, 0, VLCGL_FORMAT, VLCGL_TYPE,
641 p_sys->pp_buffer[i_index] );
647 /*****************************************************************************
648 * SendEvents: forward mouse and keyboard events to the parent p_vout
649 *****************************************************************************/
650 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
651 vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
653 return var_Set( (vlc_object_t *)_p_vout, psz_var, newval );