]> git.sesse.net Git - vlc/blob - modules/gui/macosx/voutgl.m
* vout.m : comment the NSLog call in windowContainsEmbedded: this method is called...
[vlc] / modules / gui / macosx / voutgl.m
1 /*****************************************************************************
2  * voutgl.m: MacOS X OpenGL provider
3  *****************************************************************************
4  * Copyright (C) 2001-2004 the VideoLAN team
5  * $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
6  *
7  * Authors: Colin Delacroix <colin@zoy.org>
8  *          Florian G. Pflug <fgp@phlo.org>
9  *          Jon Lech Johansen <jon-vl@nanocrew.net>
10  *          Derk-Jan Hartman <hartman at videolan dot org>
11  *          Eric Petit <titer@m0k.org>
12  *          Benjamin Pracht <bigben at videolan dot org>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27  *****************************************************************************/
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #include <errno.h>                                                 /* ENOMEM */
33 #include <stdlib.h>                                                /* free() */
34 #include <string.h>                                            /* strerror() */
35
36 #include <vlc_keys.h>
37
38 #include "intf.h"
39 #include "vout.h"
40
41 #include <OpenGL/OpenGL.h>
42 #include <OpenGL/gl.h>
43
44 /*****************************************************************************
45  * VLCView interface
46  *****************************************************************************/
47 @interface VLCGLView : NSOpenGLView
48 {
49     vout_thread_t * p_vout;
50 }
51
52 - (id) initWithVout: (vout_thread_t *) p_vout;
53 @end
54
55 struct vout_sys_t
56 {
57     NSAutoreleasePool * o_pool;
58     VLCGLView         * o_glview;
59     VLCVoutView       * o_vout_view;
60     vlc_bool_t          b_saved_frame;
61     NSRect              s_frame;
62     vlc_bool_t          b_got_frame;
63     vlc_mutex_t         lock;
64     vlc_bool_t          b_vout_size_update;
65 };
66
67 /*****************************************************************************
68  * Local prototypes
69  *****************************************************************************/
70
71 static int  Init   ( vout_thread_t * p_vout );
72 static void End    ( vout_thread_t * p_vout );
73 static int  Manage ( vout_thread_t * p_vout );
74 static int  Control( vout_thread_t *, int, va_list );
75 static void Swap   ( vout_thread_t * p_vout );
76 static int  Lock   ( vout_thread_t * p_vout );
77 static void Unlock ( vout_thread_t * p_vout );
78
79 static int AspectCallback( vlc_object_t *, char const *,
80                            vlc_value_t, vlc_value_t, void * );
81
82 int E_(OpenVideoGL)  ( vlc_object_t * p_this )
83 {
84     vout_thread_t * p_vout = (vout_thread_t *) p_this;
85
86     if( !CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ) )
87     {
88         msg_Warn( p_vout, "no OpenGL hardware acceleration found. "
89                           "Video display will be slow" );
90         return( 1 );
91     }
92     msg_Dbg( p_vout, "display is Quartz Extreme accelerated" );
93
94     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
95     if( p_vout->p_sys == NULL )
96     {
97         msg_Err( p_vout, "out of memory" );
98         return( 1 );
99     }
100
101     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
102
103     p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
104     vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
105
106     /* Create the GL view */
107     p_vout->p_sys->o_glview = [[VLCGLView alloc] initWithVout: p_vout];
108     [p_vout->p_sys->o_glview autorelease];
109
110     /* Spawn the window */
111
112     if( !(p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
113                     subView: p_vout->p_sys->o_glview frame: nil]) )
114     {
115         return VLC_EGENERIC;
116     }
117
118     p_vout->p_sys->b_got_frame = VLC_FALSE;
119
120     p_vout->pf_init   = Init;
121     p_vout->pf_end    = End;
122     p_vout->pf_manage = Manage;
123     p_vout->pf_control= Control;
124     p_vout->pf_swap   = Swap;
125     p_vout->pf_lock   = Lock;
126     p_vout->pf_unlock = Unlock;
127
128     return VLC_SUCCESS;
129 }
130
131 void E_(CloseVideoGL) ( vlc_object_t * p_this )
132 {
133     vout_thread_t * p_vout = (vout_thread_t *) p_this;
134     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
135
136     /* Close the window */
137     [p_vout->p_sys->o_vout_view closeVout];
138
139     /* Clean up */
140     vlc_mutex_destroy( &p_vout->p_sys->lock );
141     [o_pool release];
142     free( p_vout->p_sys );
143 }
144
145 static int Init( vout_thread_t * p_vout )
146 {
147     /* The variable is in fact changed on the parent vout */
148     if( !var_Type( p_vout->p_parent, "aspect-ratio" ) )
149     {
150         var_Create( p_vout->p_parent, "aspect-ratio",
151                                 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
152     }
153     var_AddCallback( p_vout->p_parent, "aspect-ratio", AspectCallback, p_vout );
154     [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
155     return VLC_SUCCESS;
156 }
157
158 static void End( vout_thread_t * p_vout )
159 {
160     var_DelCallback( p_vout->p_parent, "aspect-ratio", AspectCallback, p_vout );
161     [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
162 }
163
164 static int Manage( vout_thread_t * p_vout )
165 {
166     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
167     {
168         NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
169
170         if( !p_vout->b_fullscreen )
171         {
172             /* Save window size and position */
173             p_vout->p_sys->s_frame.size =
174                 [p_vout->p_sys->o_vout_view frame].size;
175             p_vout->p_sys->s_frame.origin =
176                 [[p_vout->p_sys->o_vout_view getWindow ]frame].origin;
177             p_vout->p_sys->b_saved_frame = VLC_TRUE;
178         }
179         [p_vout->p_sys->o_vout_view closeVout];
180
181         p_vout->b_fullscreen = !p_vout->b_fullscreen;
182
183 #define o_glview p_vout->p_sys->o_glview
184         o_glview = [[VLCGLView alloc] initWithVout: p_vout];
185         [o_glview autorelease];
186
187         if( p_vout->p_sys->b_saved_frame )
188         {
189             p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
190                         subView: o_glview
191                         frame: &p_vout->p_sys->s_frame];
192         }
193         else
194         {
195             p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
196                         subView: o_glview frame: nil];
197
198         }
199
200         [[o_glview openGLContext] makeCurrentContext];
201 #undef o_glview
202
203         [o_pool release];
204
205         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
206     }
207
208     if( p_vout->p_sys->b_vout_size_update )
209     {
210         NSRect old_bounds = [p_vout->p_sys->o_glview bounds];
211         [p_vout->p_sys->o_glview reshape];
212         if( [p_vout->p_sys->o_glview bounds].size.height !=
213             old_bounds.size.height ||
214             [p_vout->p_sys->o_glview bounds].size.width !=
215             old_bounds.size.width);
216         {
217              p_vout->p_sys->b_vout_size_update = VLC_FALSE;
218         }
219     }
220
221     [p_vout->p_sys->o_vout_view manage];
222     return VLC_SUCCESS;
223 }
224
225 /*****************************************************************************
226  * Control: control facility for the vout
227  *****************************************************************************/
228 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
229 {
230     vlc_bool_t b_arg;
231
232     switch( i_query )
233     {
234         case VOUT_SET_STAY_ON_TOP:
235             b_arg = va_arg( args, vlc_bool_t );
236             [p_vout->p_sys->o_vout_view setOnTop: b_arg];
237             return VLC_SUCCESS;
238
239         case VOUT_CLOSE:
240         case VOUT_REPARENT:
241         default:
242             return vout_vaControlDefault( p_vout, i_query, args );
243     }
244 }
245
246 static void Swap( vout_thread_t * p_vout )
247 {
248     p_vout->p_sys->b_got_frame = VLC_TRUE;
249     [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
250     glFlush();
251 }
252
253 static int Lock( vout_thread_t * p_vout )
254 {
255     vlc_mutex_lock( &p_vout->p_sys->lock );
256     return 0;
257 }
258
259 static void Unlock( vout_thread_t * p_vout )
260 {
261     vlc_mutex_unlock( &p_vout->p_sys->lock );
262 }
263
264 static int AspectCallback( vlc_object_t *p_this, char const *psz_cmd,
265                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
266 {
267     /* Only update the vout size if the aspect ratio has actually been changed*/
268
269     if( strcmp( oldval.psz_string, newval.psz_string ) )
270     {
271         ((vout_thread_t *)p_data)->p_sys->b_vout_size_update = VLC_TRUE;
272     }
273     return VLC_SUCCESS;
274 }
275
276 /*****************************************************************************
277  * VLCGLView implementation
278  *****************************************************************************/
279 @implementation VLCGLView
280
281 - (id) initWithVout: (vout_thread_t *) vout
282 {
283     p_vout = vout;
284
285     NSOpenGLPixelFormatAttribute attribs[] =
286     {
287         NSOpenGLPFAAccelerated,
288         NSOpenGLPFANoRecovery,
289         NSOpenGLPFAColorSize, 24,
290         NSOpenGLPFAAlphaSize, 8,
291         NSOpenGLPFADepthSize, 24,
292         NSOpenGLPFAWindow,
293         0
294     };
295
296     NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
297         initWithAttributes: attribs];
298
299     if( !fmt )
300     {
301         msg_Warn( p_vout, "Could not create OpenGL video output" );
302         return nil;
303     }
304
305     self = [super initWithFrame: NSMakeRect(0,0,10,10) pixelFormat: fmt];
306     [fmt release];
307
308     [[self openGLContext] makeCurrentContext];
309     [[self openGLContext] update];
310
311     /* Swap buffers only during the vertical retrace of the monitor.
312        http://developer.apple.com/documentation/GraphicsImaging/
313        Conceptual/OpenGL/chap5/chapter_5_section_44.html */
314     long params[] = { 1 };
315     CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
316                      params );
317     return self;
318 }
319
320 - (void) reshape
321 {
322     int x, y;
323     vlc_value_t val;
324
325     Lock( p_vout );
326     NSRect bounds = [self bounds];
327
328     [[self openGLContext] makeCurrentContext];
329
330     var_Get( p_vout, "macosx-stretch", &val );
331     if( val.b_bool )
332     {
333         x = bounds.size.width;
334         y = bounds.size.height;
335     }
336     else if( bounds.size.height * p_vout->render.i_aspect *
337              p_vout->fmt_in.i_sar_num <
338              bounds.size.width * VOUT_ASPECT_FACTOR * p_vout->fmt_in.i_sar_den )
339     {
340         x = bounds.size.height * p_vout->render.i_aspect *
341             p_vout->fmt_in.i_sar_num / ( VOUT_ASPECT_FACTOR *
342             p_vout->fmt_in.i_sar_den );
343         y = bounds.size.height;
344     }
345     else
346     {
347         x = bounds.size.width;
348         y = bounds.size.width * p_vout->fmt_in.i_sar_den *
349             VOUT_ASPECT_FACTOR / ( p_vout->fmt_in.i_sar_num *
350             p_vout->render.i_aspect );
351     }
352
353     glViewport( ( bounds.size.width - x ) / 2,
354                 ( bounds.size.height - y ) / 2, x, y );
355
356     if( p_vout->p_sys->b_got_frame )
357     {
358         /* Ask the opengl module to redraw */
359         vout_thread_t * p_parent;
360         p_parent = (vout_thread_t *) p_vout->p_parent;
361         Unlock( p_vout );
362         if( p_parent && p_parent->pf_display )
363         {
364             p_parent->pf_display( p_parent, NULL );
365         }
366     }
367     else
368     {
369         glClear( GL_COLOR_BUFFER_BIT );
370         Unlock( p_vout );
371     }
372     [super reshape];
373 }
374
375 - (void) update
376 {
377     Lock( p_vout );
378     [super update];
379     Unlock( p_vout );
380 }
381
382 - (void) drawRect: (NSRect) rect
383 {
384     Lock( p_vout );
385     [[self openGLContext] makeCurrentContext];
386     glFlush();
387     [super drawRect:rect];
388     Unlock( p_vout );
389 }
390
391 @end
392
393