]> git.sesse.net Git - vlc/blob - modules/video_output/opengl.c
* modules/video_output/opengl.c: forward control queries to opengl provider.
[vlc] / modules / video_output / opengl.c
1 /*****************************************************************************
2  * opengl.c: OpenGL video output
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <string.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/vout.h>
34
35 #include <GL/gl.h>
36
37 /* RV16 */
38 #ifndef GL_UNSIGNED_SHORT_5_6_5
39 #define GL_UNSIGNED_SHORT_5_6_5 0x8363
40 #endif
41 //#define VLCGL_RGB_FORMAT GL_RGB
42 //#define VLCGL_RGB_TYPE GL_UNSIGNED_SHORT_5_6_5
43
44 /* RV24 */
45 //#define VLCGL_RGB_FORMAT GL_RGB
46 //#define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
47
48 /* RV32 */
49 #define VLCGL_RGB_FORMAT GL_RGBA
50 #define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
51
52 /*****************************************************************************
53  * Vout interface
54  *****************************************************************************/
55 static int  CreateVout   ( vlc_object_t * );
56 static void DestroyVout  ( vlc_object_t * );
57 static int  Init         ( vout_thread_t * );
58 static void End          ( vout_thread_t * );
59 static int  Manage       ( vout_thread_t * );
60 static void Render       ( vout_thread_t *, picture_t * );
61 static void DisplayVideo ( vout_thread_t *, picture_t * );
62 static int  Control      ( vout_thread_t *, int, va_list );
63
64 static inline int GetAlignedSize( int );
65
66 /*****************************************************************************
67  * Module descriptor
68  *****************************************************************************/
69 vlc_module_begin();
70     set_description( _("OpenGL video output") );
71     set_capability( "video output", 20 );
72     add_shortcut( "opengl" );
73     set_callbacks( CreateVout, DestroyVout );
74 vlc_module_end();
75
76 /*****************************************************************************
77  * vout_sys_t: video output method descriptor
78  *****************************************************************************
79  * This structure is part of the video output thread descriptor.
80  * It describes the OpenGL specific properties of the output thread.
81  *****************************************************************************/
82 struct vout_sys_t
83 {
84     vout_thread_t *p_vout;
85
86     uint8_t     *p_buffer;
87     int         i_index;
88     int         i_tex_width;
89     int         i_tex_height;
90     GLuint      texture;
91
92     int         i_effect; //XXX
93 };
94
95 /*****************************************************************************
96  * CreateVout: This function allocates and initializes the OpenGL vout method.
97  *****************************************************************************/
98 static int CreateVout( vlc_object_t *p_this )
99 {
100     vout_thread_t *p_vout = (vout_thread_t *)p_this;
101     vout_sys_t *p_sys;
102
103     /* Allocate structure */
104     p_vout->p_sys = p_sys = malloc( sizeof( vout_sys_t ) );
105     if( p_sys == NULL )
106     {
107         msg_Err( p_vout, "out of memory" );
108         return VLC_EGENERIC;
109     }
110
111     //XXX set to 0 to disable the cube effect
112     p_sys->i_effect = 1;
113
114     /* A texture must have a size aligned on a power of 2 */
115     p_sys->i_tex_width  = GetAlignedSize( p_vout->render.i_width );
116     p_sys->i_tex_height = GetAlignedSize( p_vout->render.i_height );
117
118     msg_Dbg( p_vout, "Texture size: %dx%d", p_sys->i_tex_width,
119              p_sys->i_tex_height );
120
121     /* Get window */
122     p_sys->p_vout =
123         (vout_thread_t *)vlc_object_create( p_this, VLC_OBJECT_OPENGL );
124     if( p_sys->p_vout == NULL )
125     {
126         msg_Err( p_vout, "out of memory" );
127         return VLC_ENOMEM;
128     }
129     vlc_object_attach( p_sys->p_vout, p_this );
130
131     p_sys->p_vout->i_window_width = p_vout->i_window_width;
132     p_sys->p_vout->i_window_height = p_vout->i_window_height;
133     p_sys->p_vout->b_fullscreen = p_vout->b_fullscreen;
134     p_sys->p_vout->render.i_width = p_vout->render.i_width;
135     p_sys->p_vout->render.i_height = p_vout->render.i_height;
136     p_sys->p_vout->render.i_aspect = p_vout->render.i_aspect;
137
138     p_sys->p_vout->p_module =
139         module_Need( p_sys->p_vout, "opengl provider", NULL, 0 );
140     if( p_sys->p_vout->p_module == NULL )
141     {
142         msg_Err( p_vout, "No OpenGL provider found" );
143         vlc_object_detach( p_sys->p_vout );
144         vlc_object_destroy( p_sys->p_vout );
145         return VLC_ENOOBJ;
146     }
147
148     p_vout->pf_init = Init;
149     p_vout->pf_end = End;
150     p_vout->pf_manage = Manage;
151     p_vout->pf_render = Render;
152     p_vout->pf_display = DisplayVideo;
153     p_vout->pf_control = Control;
154
155     return VLC_SUCCESS;
156 }
157
158 /*****************************************************************************
159  * Init: initialize the OpenGL video thread output method
160  *****************************************************************************/
161 static int Init( vout_thread_t *p_vout )
162 {
163     vout_sys_t *p_sys = p_vout->p_sys;
164     int i_pixel_pitch;
165
166     p_sys->p_vout->pf_init( p_sys->p_vout );
167
168     /* No YUV textures :( */
169
170 #if VLCGL_RGB_FORMAT == GL_RGB
171 #   if VLCGL_RGB_TYPE == GL_UNSIGNED_BYTE
172     p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
173     p_vout->output.i_rmask = 0x000000ff;
174     p_vout->output.i_gmask = 0x0000ff00;
175     p_vout->output.i_bmask = 0x00ff0000;
176     i_pixel_pitch = 3;
177 #   else
178     p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
179     p_vout->output.i_rmask = 0xf800;
180     p_vout->output.i_gmask = 0x07e0;
181     p_vout->output.i_bmask = 0x001f;
182     i_pixel_pitch = 2;
183 #   endif
184 #else
185     p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
186     p_vout->output.i_rmask = 0x000000ff;
187     p_vout->output.i_gmask = 0x0000ff00;
188     p_vout->output.i_bmask = 0x00ff0000;
189     i_pixel_pitch = 4;
190 #endif
191
192     /* Since OpenGL can do rescaling for us, stick to the default
193      * coordinates and aspect. */
194     p_vout->output.i_width  = p_vout->render.i_width;
195     p_vout->output.i_height = p_vout->render.i_height;
196     p_vout->output.i_aspect = p_vout->render.i_aspect;
197
198     /* We know the chroma, allocate a buffer which will be used
199      * directly by the decoder */
200     p_vout->p_picture[0].i_planes = 1;
201     p_sys->p_buffer =
202         malloc( p_sys->i_tex_width * p_sys->i_tex_height * i_pixel_pitch );
203     if( !p_sys->p_buffer )
204     {
205         msg_Err( p_vout, "Out of memory" );
206         return -1;
207     }
208
209     p_vout->p_picture[0].p->p_pixels = p_sys->p_buffer;
210     p_vout->p_picture[0].p->i_lines = p_vout->output.i_height;
211     p_vout->p_picture[0].p->i_pixel_pitch = i_pixel_pitch;
212     p_vout->p_picture[0].p->i_pitch = p_sys->i_tex_width *
213         p_vout->p_picture[0].p->i_pixel_pitch;
214     p_vout->p_picture[0].p->i_visible_pitch = p_vout->output.i_width *
215         p_vout->p_picture[0].p->i_pixel_pitch;
216
217     p_vout->p_picture[0].i_status = DESTROYED_PICTURE;
218     p_vout->p_picture[0].i_type   = DIRECT_PICTURE;
219
220     PP_OUTPUTPICTURE[ 0 ] = &p_vout->p_picture[0];
221     I_OUTPUTPICTURES = 1;
222
223     /* Set the texture parameters */
224     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
225     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
226
227     if( p_sys->i_effect )
228     {
229         glEnable( GL_CULL_FACE);
230         /* glDisable( GL_DEPTH_TEST );
231         glEnable( GL_BLEND );
232         glBlendFunc( GL_SRC_ALPHA, GL_ONE );*/
233
234         /* Set the perpective */
235         glMatrixMode( GL_PROJECTION );
236         glLoadIdentity();
237         glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
238         glMatrixMode( GL_MODELVIEW );
239         glLoadIdentity();
240         glTranslatef( 0.0, 0.0, - 5.0 );
241     }
242
243     return 0;
244 }
245
246 /*****************************************************************************
247  * End: terminate GLX video thread output method
248  *****************************************************************************/
249 static void End( vout_thread_t *p_vout )
250 {
251     glFinish();
252     glFlush();
253 }
254
255 /*****************************************************************************
256  * Destroy: destroy GLX video thread output method
257  *****************************************************************************
258  * Terminate an output method created by CreateVout
259  *****************************************************************************/
260 static void DestroyVout( vlc_object_t *p_this )
261 {
262     vout_thread_t *p_vout = (vout_thread_t *)p_this;
263     vout_sys_t *p_sys = p_vout->p_sys;
264
265     module_Unneed( p_sys->p_vout, p_sys->p_vout->p_module );
266     vlc_object_detach( p_sys->p_vout );
267     vlc_object_destroy( p_sys->p_vout );
268
269     /* Free the texture buffer*/
270     if( p_sys->p_buffer ) free( p_sys->p_buffer );
271
272     free( p_sys );
273 }
274
275 /*****************************************************************************
276  * Manage: handle Sys events
277  *****************************************************************************
278  * This function should be called regularly by video output thread. It returns
279  * a non null value if an error occured.
280  *****************************************************************************/
281 static int Manage( vout_thread_t *p_vout )
282 {
283     vout_sys_t *p_sys = p_vout->p_sys;
284     return p_sys->p_vout->pf_manage( p_sys->p_vout );
285 }
286
287 /*****************************************************************************
288  * Render: render previously calculated output
289  *****************************************************************************/
290 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
291 {
292     vout_sys_t *p_sys = p_vout->p_sys;
293     float f_width = (float)p_vout->output.i_width / p_sys->i_tex_width;
294     float f_height = (float)p_vout->output.i_height / p_sys->i_tex_height;
295
296     glClear( GL_COLOR_BUFFER_BIT );
297
298     glTexImage2D( GL_TEXTURE_2D, 0, 3,
299                   p_sys->i_tex_width, p_sys->i_tex_height , 0,
300                   VLCGL_RGB_FORMAT, VLCGL_RGB_TYPE, p_sys->p_buffer );
301
302     if( !p_sys->i_effect )
303     {
304         glEnable( GL_TEXTURE_2D );
305         glBegin( GL_POLYGON );
306         glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, 1.0 );
307         glTexCoord2f( f_width, 0.0 ); glVertex2f( 1.0, 1.0 );
308         glTexCoord2f( f_width, f_height ); glVertex2f( 1.0, -1.0 );
309         glTexCoord2f( 0.0, f_height ); glVertex2f( -1.0, -1.0 );
310         glEnd();
311     }
312     else
313     {
314         glRotatef( 1.0, 0.3, 0.5, 0.7 );
315
316         glEnable( GL_TEXTURE_2D );
317         glBegin( GL_QUADS );
318
319         /* Front */
320         glTexCoord2f( 0, 0 ); glVertex3f( - 1.0, 1.0, 1.0 );
321         glTexCoord2f( 0, f_height ); glVertex3f( - 1.0, - 1.0, 1.0 );
322         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, 1.0 );
323         glTexCoord2f( f_width, 0 ); glVertex3f( 1.0, 1.0, 1.0 );
324
325         /* Left */
326         glTexCoord2f( 0, 0 ); glVertex3f( - 1.0, 1.0, - 1.0 );
327         glTexCoord2f( 0, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
328         glTexCoord2f( f_width, f_height ); glVertex3f( - 1.0, - 1.0, 1.0 );
329         glTexCoord2f( f_width, 0 ); glVertex3f( - 1.0, 1.0, 1.0 );
330
331         /* Back */
332         glTexCoord2f( 0, 0 ); glVertex3f( 1.0, 1.0, - 1.0 );
333         glTexCoord2f( 0, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
334         glTexCoord2f( f_width, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
335         glTexCoord2f( f_width, 0 ); glVertex3f( - 1.0, 1.0, - 1.0 );
336
337         /* Right */
338         glTexCoord2f( 0, 0 ); glVertex3f( 1.0, 1.0, 1.0 );
339         glTexCoord2f( 0, f_height ); glVertex3f( 1.0, - 1.0, 1.0 );
340         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
341         glTexCoord2f( f_width, 0 ); glVertex3f( 1.0, 1.0, - 1.0 );
342
343         /* Top */
344         glTexCoord2f( 0, 0 ); glVertex3f( - 1.0, 1.0, - 1.0 );
345         glTexCoord2f( 0, f_height ); glVertex3f( - 1.0, 1.0, 1.0 );
346         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, 1.0, 1.0 );
347         glTexCoord2f( f_width, 0 ); glVertex3f( 1.0, 1.0, - 1.0 );
348
349         /* Bottom */
350         glTexCoord2f( 0, 0 ); glVertex3f( - 1.0, - 1.0, 1.0 );
351         glTexCoord2f( 0, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
352         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
353         glTexCoord2f( f_width, 0 ); glVertex3f( 1.0, - 1.0, 1.0 );
354         glEnd();
355     }
356
357     glDisable( GL_TEXTURE_2D);
358 }
359
360 /*****************************************************************************
361  * DisplayVideo: displays previously rendered output
362  *****************************************************************************/
363 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
364 {
365     vout_sys_t *p_sys = p_vout->p_sys;
366     p_sys->p_vout->pf_swap( p_sys->p_vout );
367 }
368
369 int GetAlignedSize( int i_size )
370 {
371     /* Return the nearest power of 2 */
372     int i_result = 1;
373     while( i_result < i_size )
374     {
375         i_result *= 2;
376     }
377     return i_result;
378 }
379
380 /*****************************************************************************
381  * Control: control facility for the vout
382  *****************************************************************************/
383 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
384 {
385     vout_sys_t *p_sys = p_vout->p_sys;
386
387     if( p_sys->p_vout->pf_control )
388         return p_sys->p_vout->pf_control( p_sys->p_vout, i_query, args );
389     else
390         return vout_vaControlDefault( p_vout, i_query, args );
391 }