1 /*****************************************************************************
2 * opengl.c: OpenGL video output
3 *****************************************************************************
4 * Copyright (C) 2004 the VideoLAN team
7 * Authors: Cyril Deguet <asmax@videolan.org>
8 * Gildas Bazin <gbazin@videolan.org>
9 * Eric Petit <titer@m0k.org>
10 * Cedric Cocquebert <cedric.cocquebert@supelec.fr>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
42 /*****************************************************************************
44 *****************************************************************************/
45 static int CreateVout ( vlc_object_t * );
46 static void DestroyVout ( vlc_object_t * );
47 static int Init ( vout_thread_t * );
48 static void End ( vout_thread_t * );
49 static int Manage ( vout_thread_t * );
50 static void Render ( vout_thread_t *, picture_t * );
51 static void DisplayVideo ( vout_thread_t *, picture_t * );
52 static int Control ( vout_thread_t *, int, va_list );
54 static int SendEvents ( vlc_object_t *, char const *,
55 vlc_value_t, vlc_value_t, void * );
57 #define PROVIDER_TEXT N_("OpenGL Provider")
58 #define PROVIDER_LONGTEXT N_("Allows you to modify what OpenGL provider should be used")
61 set_shortname( "OpenGL" )
62 set_category( CAT_VIDEO )
63 set_subcategory( SUBCAT_VIDEO_VOUT )
64 set_description( N_("OpenGL video output") )
66 set_capability( "video output", 200 )
68 set_capability( "video output", 20 )
70 add_shortcut( "opengl" )
71 /* Allow opengl provider plugin selection */
72 add_module( "opengl-provider", "opengl provider", NULL, NULL,
73 PROVIDER_TEXT, PROVIDER_LONGTEXT, true )
74 set_callbacks( CreateVout, DestroyVout )
77 /*****************************************************************************
78 * vout_sys_t: video output method descriptor
79 *****************************************************************************
80 * This structure is part of the video output thread descriptor.
81 * It describes the OpenGL specific properties of the output thread.
82 *****************************************************************************/
85 vout_thread_t *p_vout;
87 vout_display_opengl_t vgl;
89 picture_pool_t *p_pool;
93 /*****************************************************************************
94 * CreateVout: This function allocates and initializes the OpenGL vout method.
95 *****************************************************************************/
96 static int CreateVout( vlc_object_t *p_this )
98 vout_thread_t *p_vout = (vout_thread_t *)p_this;
102 /* Allocate structure */
103 p_vout->p_sys = p_sys = malloc( sizeof( vout_sys_t ) );
109 (vout_thread_t *)vlc_object_create( p_this, sizeof( vout_thread_t ) );
110 if( p_sys->p_vout == NULL )
115 vlc_object_attach( p_sys->p_vout, p_this );
117 p_sys->p_vout->i_window_width = p_vout->i_window_width;
118 p_sys->p_vout->i_window_height = p_vout->i_window_height;
119 p_sys->p_vout->b_fullscreen = p_vout->b_fullscreen;
120 p_sys->p_vout->render.i_width = p_vout->render.i_width;
121 p_sys->p_vout->render.i_height = p_vout->render.i_height;
122 p_sys->p_vout->render.i_aspect = p_vout->render.i_aspect;
123 p_sys->p_vout->fmt_render = p_vout->fmt_render;
124 p_sys->p_vout->fmt_in = p_vout->fmt_in;
125 p_sys->p_vout->b_autoscale = p_vout->b_autoscale;
126 p_sys->p_vout->i_zoom = p_vout->i_zoom;
127 p_sys->p_vout->i_alignment = p_vout->i_alignment;
128 var_Create( p_sys->p_vout, "video-deco",
129 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
131 /* Forward events from the opengl provider */
132 var_Create( p_sys->p_vout, "mouse-x", VLC_VAR_INTEGER );
133 var_Create( p_sys->p_vout, "mouse-y", VLC_VAR_INTEGER );
134 var_Create( p_sys->p_vout, "mouse-moved", VLC_VAR_BOOL );
135 var_Create( p_sys->p_vout, "mouse-clicked", VLC_VAR_BOOL );
136 var_Create( p_sys->p_vout, "mouse-button-down", VLC_VAR_INTEGER );
137 var_Create( p_sys->p_vout, "video-on-top",
138 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
139 var_Create( p_sys->p_vout, "autoscale",
140 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
141 var_Create( p_sys->p_vout, "scale",
142 VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
144 var_AddCallback( p_sys->p_vout, "mouse-x", SendEvents, p_vout );
145 var_AddCallback( p_sys->p_vout, "mouse-y", SendEvents, p_vout );
146 var_AddCallback( p_sys->p_vout, "mouse-moved", SendEvents, p_vout );
147 var_AddCallback( p_sys->p_vout, "mouse-clicked", SendEvents, p_vout );
148 var_AddCallback( p_sys->p_vout, "mouse-button-down", SendEvents, p_vout );
149 var_AddCallback( p_sys->p_vout, "video-on-top", SendEvents, p_vout );
150 var_AddCallback( p_vout, "autoscale", SendEvents, p_sys->p_vout );
151 var_AddCallback( p_vout, "scale", SendEvents, p_sys->p_vout );
153 psz = var_CreateGetString( p_vout, "opengl-provider" );
154 p_sys->p_vout->p_module =
155 module_need( p_sys->p_vout, "opengl provider", psz, false );
157 if( p_sys->p_vout->p_module == NULL )
159 msg_Warn( p_vout, "No OpenGL provider found" );
160 vlc_object_detach( p_sys->p_vout );
161 /* no need for var_DelCallback here :-) */
162 vlc_object_release( p_sys->p_vout );
167 p_vout->pf_init = Init;
168 p_vout->pf_end = End;
169 p_vout->pf_manage = Manage;
170 p_vout->pf_render = Render;
171 p_vout->pf_display = DisplayVideo;
172 p_vout->pf_control = Control;
177 static int OpenglLock(vout_opengl_t *gl)
179 vout_thread_t *p_vout = gl->sys;
181 if( !p_vout->pf_lock )
183 return p_vout->pf_lock( p_vout );
185 static void OpenglUnlock(vout_opengl_t *gl)
187 vout_thread_t *p_vout = gl->sys;
189 if( p_vout->pf_unlock )
190 p_vout->pf_unlock( p_vout );
192 static void OpenglSwap(vout_opengl_t *gl)
194 vout_thread_t *p_vout = gl->sys;
195 p_vout->pf_swap( p_vout );
198 /*****************************************************************************
199 * Init: initialize the OpenGL video thread output method
200 *****************************************************************************/
201 static int Init( vout_thread_t *p_vout )
203 vout_sys_t *p_sys = p_vout->p_sys;
205 p_sys->p_vout->pf_init( p_sys->p_vout );
207 p_sys->gl.lock = OpenglLock;
208 p_sys->gl.unlock = OpenglUnlock;
209 p_sys->gl.swap = OpenglSwap;
210 p_sys->gl.sys = p_sys->p_vout;
213 video_format_Init( &fmt, 0 );
214 video_format_Setup( &fmt,
215 p_vout->render.i_chroma,
216 p_vout->render.i_width,
217 p_vout->render.i_height,
218 p_vout->render.i_aspect );
221 if( vout_display_opengl_Init( &p_sys->vgl, &fmt, &p_sys->gl ) )
223 I_OUTPUTPICTURES = 0;
226 p_sys->p_pool = vout_display_opengl_GetPool( &p_sys->vgl );
229 vout_display_opengl_Clean( &p_sys->vgl );
230 I_OUTPUTPICTURES = 0;
235 p_vout->output.i_chroma = fmt.i_chroma;
236 p_vout->output.i_rmask = fmt.i_rmask;
237 p_vout->output.i_gmask = fmt.i_gmask;
238 p_vout->output.i_bmask = fmt.i_bmask;
240 /* Since OpenGL can do rescaling for us, stick to the default
241 * coordinates and aspect. */
242 p_vout->output.i_width = p_vout->render.i_width;
243 p_vout->output.i_height = p_vout->render.i_height;
244 p_vout->output.i_aspect = p_vout->render.i_aspect;
246 p_vout->fmt_out = p_vout->fmt_in;
247 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
250 p_sys->p_current = picture_pool_Get( p_sys->p_pool );
251 p_vout->p_picture[0] = *p_sys->p_current;
252 p_vout->p_picture[0].i_status = DESTROYED_PICTURE;
253 p_vout->p_picture[0].i_type = DIRECT_PICTURE;
254 p_vout->p_picture[0].i_refcount = 0;
255 p_vout->p_picture[0].p_sys = NULL;
256 PP_OUTPUTPICTURE[0] = &p_vout->p_picture[0];
258 I_OUTPUTPICTURES = 1;
263 /*****************************************************************************
264 * End: terminate GLX video thread output method
265 *****************************************************************************/
266 static void End( vout_thread_t *p_vout )
268 vout_sys_t *p_sys = p_vout->p_sys;
270 if( I_OUTPUTPICTURES > 0 )
273 if( p_sys->p_current )
274 picture_Release( p_sys->p_current );
275 vout_display_opengl_Clean( &p_sys->vgl );
277 p_vout->p_picture[0].i_status = FREE_PICTURE;
278 I_OUTPUTPICTURES = 0;
281 /* We must release the opengl provider here: opengl requiere init and end
282 to be done in the same thread */
283 module_unneed( p_sys->p_vout, p_sys->p_vout->p_module );
284 vlc_object_release( p_sys->p_vout );
287 /*****************************************************************************
288 * Destroy: destroy GLX video thread output method
289 *****************************************************************************
290 * Terminate an output method created by CreateVout
291 *****************************************************************************/
292 static void DestroyVout( vlc_object_t *p_this )
294 vout_thread_t *p_vout = (vout_thread_t *)p_this;
295 vout_sys_t *p_sys = p_vout->p_sys;
300 /*****************************************************************************
301 * Manage: handle Sys events
302 *****************************************************************************
303 * This function should be called regularly by video output thread. It returns
304 * a non null value if an error occurred.
305 *****************************************************************************/
306 static int Manage( vout_thread_t *p_vout )
308 vout_sys_t *p_sys = p_vout->p_sys;
309 int i_ret, i_fullscreen_change;
311 i_fullscreen_change = ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE );
313 p_vout->fmt_out.i_x_offset = p_sys->p_vout->fmt_in.i_x_offset =
314 p_vout->fmt_in.i_x_offset;
315 p_vout->fmt_out.i_y_offset = p_sys->p_vout->fmt_in.i_y_offset =
316 p_vout->fmt_in.i_y_offset;
317 p_vout->fmt_out.i_visible_width = p_sys->p_vout->fmt_in.i_visible_width =
318 p_vout->fmt_in.i_visible_width;
319 p_vout->fmt_out.i_visible_height = p_sys->p_vout->fmt_in.i_visible_height =
320 p_vout->fmt_in.i_visible_height;
321 p_vout->fmt_out.i_aspect = p_sys->p_vout->fmt_in.i_aspect =
322 p_vout->fmt_in.i_aspect;
323 p_vout->fmt_out.i_sar_num = p_sys->p_vout->fmt_in.i_sar_num =
324 p_vout->fmt_in.i_sar_num;
325 p_vout->fmt_out.i_sar_den = p_sys->p_vout->fmt_in.i_sar_den =
326 p_vout->fmt_in.i_sar_den;
327 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
329 p_sys->p_vout->i_changes = p_vout->i_changes;
330 i_ret = p_sys->p_vout->pf_manage( p_sys->p_vout );
331 p_vout->i_changes = p_sys->p_vout->i_changes;
334 /* On OS X, we create the window and the GL view when entering
335 fullscreen - the textures have to be inited again */
336 if( i_fullscreen_change )
338 /* FIXME should we release p_current ? */
339 vout_display_opengl_ResetTextures( &p_sys->vgl );
343 // to align in real time in OPENGL
344 if (p_sys->p_vout->i_alignment != p_vout->i_alignment)
346 p_vout->i_changes |= VOUT_CROP_CHANGE; //to force change
347 p_sys->p_vout->i_alignment = p_vout->i_alignment;
350 /* forward signal that autoscale toggle has changed */
351 if (p_vout->i_changes & VOUT_SCALE_CHANGE )
353 p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
355 p_sys->p_vout->i_changes |= VOUT_SCALE_CHANGE;
358 /* forward signal that scale has changed */
359 if (p_vout->i_changes & VOUT_ZOOM_CHANGE )
361 p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
363 p_sys->p_vout->i_changes |= VOUT_ZOOM_CHANGE;
370 /*****************************************************************************
371 * Render: render previously calculated output
372 *****************************************************************************/
373 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
375 vout_sys_t *p_sys = p_vout->p_sys;
377 if( p_sys->p_current )
379 assert( p_sys->p_current->p[0].p_pixels == p_pic->p[0].p_pixels );
381 vout_display_opengl_Prepare( &p_sys->vgl, p_sys->p_current );
382 picture_Release( p_sys->p_current );
385 p_sys->p_current = picture_pool_Get( p_sys->p_pool );
386 if( p_sys->p_current )
387 p_pic->p[0].p_pixels = p_sys->p_current->p[0].p_pixels;
392 /*****************************************************************************
393 * DisplayVideo: displays previously rendered output
394 *****************************************************************************/
395 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
397 vout_sys_t *p_sys = p_vout->p_sys;
399 vout_display_opengl_Display( &p_sys->vgl, &p_vout->fmt_out );
403 /*****************************************************************************
404 * Control: control facility for the vout
405 *****************************************************************************/
406 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
408 vout_sys_t *p_sys = p_vout->p_sys;
410 if( p_sys->p_vout->pf_control )
411 return p_sys->p_vout->pf_control( p_sys->p_vout, i_query, args );
415 /*****************************************************************************
416 * SendEvents: forward mouse and keyboard events to the parent p_vout
417 *****************************************************************************/
418 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
419 vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
421 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
422 return var_Set( (vlc_object_t *)_p_vout, psz_var, newval );