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", 400 )
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-moved", VLC_VAR_COORDS
);
133 var_Create( p_sys
->p_vout
, "mouse-clicked", VLC_VAR_COORDS
);
134 var_Create( p_sys
->p_vout
, "mouse-button-down", VLC_VAR_INTEGER
);
135 var_Create( p_sys
->p_vout
, "video-on-top",
136 VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
137 var_Create( p_sys
->p_vout
, "autoscale",
138 VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
139 var_Create( p_sys
->p_vout
, "scale",
140 VLC_VAR_FLOAT
| VLC_VAR_DOINHERIT
);
142 var_AddCallback( p_sys
->p_vout
, "mouse-moved", SendEvents
, p_vout
);
143 var_AddCallback( p_sys
->p_vout
, "mouse-clicked", SendEvents
, p_vout
);
144 var_AddCallback( p_sys
->p_vout
, "mouse-button-down", SendEvents
, p_vout
);
145 var_AddCallback( p_sys
->p_vout
, "video-on-top", SendEvents
, p_vout
);
146 var_AddCallback( p_vout
, "autoscale", SendEvents
, p_sys
->p_vout
);
147 var_AddCallback( p_vout
, "scale", SendEvents
, p_sys
->p_vout
);
149 psz
= var_CreateGetString( p_vout
, "opengl-provider" );
150 p_sys
->p_vout
->p_module
=
151 module_need( p_sys
->p_vout
, "opengl provider", psz
, false );
153 if( p_sys
->p_vout
->p_module
== NULL
)
155 msg_Warn( p_vout
, "No OpenGL provider found" );
156 /* no need for var_DelCallback here :-) */
157 vlc_object_release( p_sys
->p_vout
);
162 p_vout
->pf_init
= Init
;
163 p_vout
->pf_end
= End
;
164 p_vout
->pf_manage
= Manage
;
165 p_vout
->pf_render
= Render
;
166 p_vout
->pf_display
= DisplayVideo
;
167 p_vout
->pf_control
= Control
;
172 static int OpenglLock(vout_opengl_t
*gl
)
174 vout_thread_t
*p_vout
= gl
->sys
;
176 if( !p_vout
->pf_lock
)
178 return p_vout
->pf_lock( p_vout
);
180 static void OpenglUnlock(vout_opengl_t
*gl
)
182 vout_thread_t
*p_vout
= gl
->sys
;
184 if( p_vout
->pf_unlock
)
185 p_vout
->pf_unlock( p_vout
);
187 static void OpenglSwap(vout_opengl_t
*gl
)
189 vout_thread_t
*p_vout
= gl
->sys
;
190 p_vout
->pf_swap( p_vout
);
193 /*****************************************************************************
194 * Init: initialize the OpenGL video thread output method
195 *****************************************************************************/
196 static int Init( vout_thread_t
*p_vout
)
198 vout_sys_t
*p_sys
= p_vout
->p_sys
;
200 p_sys
->p_vout
->pf_init( p_sys
->p_vout
);
202 p_sys
->gl
.lock
= OpenglLock
;
203 p_sys
->gl
.unlock
= OpenglUnlock
;
204 p_sys
->gl
.swap
= OpenglSwap
;
205 p_sys
->gl
.sys
= p_sys
->p_vout
;
208 video_format_Init( &fmt
, 0 );
209 video_format_Setup( &fmt
,
210 p_vout
->render
.i_chroma
,
211 p_vout
->render
.i_width
,
212 p_vout
->render
.i_height
,
213 p_vout
->render
.i_aspect
* p_vout
->render
.i_height
,
214 VOUT_ASPECT_FACTOR
* p_vout
->render
.i_width
);
217 if( vout_display_opengl_Init( &p_sys
->vgl
, &fmt
, &p_sys
->gl
) )
219 I_OUTPUTPICTURES
= 0;
222 p_sys
->p_pool
= vout_display_opengl_GetPool( &p_sys
->vgl
);
225 vout_display_opengl_Clean( &p_sys
->vgl
);
226 I_OUTPUTPICTURES
= 0;
231 p_vout
->output
.i_chroma
= fmt
.i_chroma
;
232 p_vout
->output
.i_rmask
= fmt
.i_rmask
;
233 p_vout
->output
.i_gmask
= fmt
.i_gmask
;
234 p_vout
->output
.i_bmask
= fmt
.i_bmask
;
236 /* Since OpenGL can do rescaling for us, stick to the default
237 * coordinates and aspect. */
238 p_vout
->output
.i_width
= p_vout
->render
.i_width
;
239 p_vout
->output
.i_height
= p_vout
->render
.i_height
;
240 p_vout
->output
.i_aspect
= p_vout
->render
.i_aspect
;
242 p_vout
->fmt_out
= p_vout
->fmt_in
;
243 p_vout
->fmt_out
.i_chroma
= p_vout
->output
.i_chroma
;
246 p_sys
->p_current
= picture_pool_Get( p_sys
->p_pool
);
247 p_vout
->p_picture
[0] = *p_sys
->p_current
;
248 p_vout
->p_picture
[0].i_status
= DESTROYED_PICTURE
;
249 p_vout
->p_picture
[0].i_type
= DIRECT_PICTURE
;
250 p_vout
->p_picture
[0].i_refcount
= 0;
251 p_vout
->p_picture
[0].p_sys
= NULL
;
252 PP_OUTPUTPICTURE
[0] = &p_vout
->p_picture
[0];
254 I_OUTPUTPICTURES
= 1;
259 /*****************************************************************************
260 * End: terminate GLX video thread output method
261 *****************************************************************************/
262 static void End( vout_thread_t
*p_vout
)
264 vout_sys_t
*p_sys
= p_vout
->p_sys
;
266 if( I_OUTPUTPICTURES
> 0 )
269 if( p_sys
->p_current
)
270 picture_Release( p_sys
->p_current
);
271 vout_display_opengl_Clean( &p_sys
->vgl
);
273 p_vout
->p_picture
[0].i_status
= FREE_PICTURE
;
274 I_OUTPUTPICTURES
= 0;
277 /* We must release the opengl provider here: opengl requiere init and end
278 to be done in the same thread */
279 module_unneed( p_sys
->p_vout
, p_sys
->p_vout
->p_module
);
280 vlc_object_release( p_sys
->p_vout
);
283 /*****************************************************************************
284 * Destroy: destroy GLX video thread output method
285 *****************************************************************************
286 * Terminate an output method created by CreateVout
287 *****************************************************************************/
288 static void DestroyVout( vlc_object_t
*p_this
)
290 vout_thread_t
*p_vout
= (vout_thread_t
*)p_this
;
291 vout_sys_t
*p_sys
= p_vout
->p_sys
;
296 /*****************************************************************************
297 * Manage: handle Sys events
298 *****************************************************************************
299 * This function should be called regularly by video output thread. It returns
300 * a non null value if an error occurred.
301 *****************************************************************************/
302 static int Manage( vout_thread_t
*p_vout
)
304 vout_sys_t
*p_sys
= p_vout
->p_sys
;
305 int i_ret
, i_fullscreen_change
;
307 i_fullscreen_change
= ( p_vout
->i_changes
& VOUT_FULLSCREEN_CHANGE
);
309 p_vout
->fmt_out
.i_x_offset
= p_sys
->p_vout
->fmt_in
.i_x_offset
=
310 p_vout
->fmt_in
.i_x_offset
;
311 p_vout
->fmt_out
.i_y_offset
= p_sys
->p_vout
->fmt_in
.i_y_offset
=
312 p_vout
->fmt_in
.i_y_offset
;
313 p_vout
->fmt_out
.i_visible_width
= p_sys
->p_vout
->fmt_in
.i_visible_width
=
314 p_vout
->fmt_in
.i_visible_width
;
315 p_vout
->fmt_out
.i_visible_height
= p_sys
->p_vout
->fmt_in
.i_visible_height
=
316 p_vout
->fmt_in
.i_visible_height
;
317 p_vout
->fmt_out
.i_sar_num
= p_sys
->p_vout
->fmt_in
.i_sar_num
=
318 p_vout
->fmt_in
.i_sar_num
;
319 p_vout
->fmt_out
.i_sar_den
= p_sys
->p_vout
->fmt_in
.i_sar_den
=
320 p_vout
->fmt_in
.i_sar_den
;
321 p_vout
->output
.i_aspect
= (int64_t)p_vout
->fmt_in
.i_sar_num
* p_vout
->fmt_in
.i_width
* VOUT_ASPECT_FACTOR
/
322 p_vout
->fmt_in
.i_sar_den
/ p_vout
->fmt_in
.i_height
;
324 p_sys
->p_vout
->i_changes
= p_vout
->i_changes
;
325 i_ret
= p_sys
->p_vout
->pf_manage( p_sys
->p_vout
);
326 p_vout
->i_changes
= p_sys
->p_vout
->i_changes
;
329 /* On OS X, we create the window and the GL view when entering
330 fullscreen - the textures have to be inited again */
331 if( i_fullscreen_change
)
333 /* FIXME should we release p_current ? */
334 vout_display_opengl_ResetTextures( &p_sys
->vgl
);
338 // to align in real time in OPENGL
339 if (p_sys
->p_vout
->i_alignment
!= p_vout
->i_alignment
)
341 p_vout
->i_changes
|= VOUT_CROP_CHANGE
; //to force change
342 p_sys
->p_vout
->i_alignment
= p_vout
->i_alignment
;
345 /* forward signal that autoscale toggle has changed */
346 if (p_vout
->i_changes
& VOUT_SCALE_CHANGE
)
348 p_vout
->i_changes
&= ~VOUT_SCALE_CHANGE
;
350 p_sys
->p_vout
->i_changes
|= VOUT_SCALE_CHANGE
;
353 /* forward signal that scale has changed */
354 if (p_vout
->i_changes
& VOUT_ZOOM_CHANGE
)
356 p_vout
->i_changes
&= ~VOUT_ZOOM_CHANGE
;
358 p_sys
->p_vout
->i_changes
|= VOUT_ZOOM_CHANGE
;
365 /*****************************************************************************
366 * Render: render previously calculated output
367 *****************************************************************************/
368 static void Render( vout_thread_t
*p_vout
, picture_t
*p_pic
)
370 vout_sys_t
*p_sys
= p_vout
->p_sys
;
372 picture_t
*p_next
= p_sys
->p_current
;
374 if( VLCGL_TEXTURE_COUNT
> 1 )
376 /* Get the next picture to display */
377 p_next
= picture_pool_Get( p_sys
->p_pool
);
381 if( p_sys
->p_current
)
383 assert( p_sys
->p_current
->p
[0].p_pixels
== p_pic
->p
[0].p_pixels
);
385 /* Make sure we have the prepare after the picture_pool_Get,
386 * because picture_pool_Get() will bind the new picture texture,
387 * and vout_display_opengl_Prepare() bind the current rendered picture
389 * DisplayVideo() will effectively use the last binded texture. */
391 vout_display_opengl_Prepare( &p_sys
->vgl
, p_sys
->p_current
);
394 if( p_sys
->p_current
!= p_next
) {
395 if( p_sys
->p_current
)
396 picture_Release( p_sys
->p_current
);
398 /* Swap the picture texture on opengl vout side. */
399 p_sys
->p_current
= p_next
;
401 /* Now, switch the only picture that is being used
402 * to render in the backend to point to our "next"
404 p_pic
->p
[0].p_pixels
= p_sys
->p_current
->p
[0].p_pixels
;
410 /*****************************************************************************
411 * DisplayVideo: displays previously rendered output
412 *****************************************************************************/
413 static void DisplayVideo( vout_thread_t
*p_vout
, picture_t
*p_pic
)
415 vout_sys_t
*p_sys
= p_vout
->p_sys
;
417 vout_display_opengl_Display( &p_sys
->vgl
, &p_vout
->fmt_out
);
421 /*****************************************************************************
422 * Control: control facility for the vout
423 *****************************************************************************/
424 static int Control( vout_thread_t
*p_vout
, int i_query
, va_list args
)
426 vout_sys_t
*p_sys
= p_vout
->p_sys
;
428 if( p_sys
->p_vout
->pf_control
)
429 return p_sys
->p_vout
->pf_control( p_sys
->p_vout
, i_query
, args
);
433 /*****************************************************************************
434 * SendEvents: forward mouse and keyboard events to the parent p_vout
435 *****************************************************************************/
436 static int SendEvents( vlc_object_t
*p_this
, char const *psz_var
,
437 vlc_value_t oldval
, vlc_value_t newval
, void *_p_vout
)
439 VLC_UNUSED(p_this
); VLC_UNUSED(oldval
);
440 return var_Set( (vlc_object_t
*)_p_vout
, psz_var
, newval
);