1 /*****************************************************************************
2 * voutgl.m: MacOS X OpenGL provider
3 *****************************************************************************
4 * Copyright (C) 2001-2004, 2007-2009, 2011 the VideoLAN team
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 * Damien Fouilleul <damienf at videolan dot org>
14 * Felix Paul Kuehne <fkuehne at videolan dot org>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
29 *****************************************************************************/
31 /*****************************************************************************
33 *****************************************************************************/
34 #include <stdlib.h> /* free() */
37 #include <vlc_common.h>
43 #include <OpenGL/OpenGL.h>
44 #include <OpenGL/gl.h>
46 /*****************************************************************************
48 *****************************************************************************/
49 @interface VLCGLView : NSOpenGLView <VLCVoutViewResetting>
51 vout_thread_t * p_vout;
54 + (void)resetVout: (NSValue *) voutValue;
55 - (id) initWithVout: (vout_thread_t *) p_vout;
61 VLCVoutView * o_vout_view;
69 /*****************************************************************************
71 *****************************************************************************/
73 static int Init ( vout_thread_t * p_vout );
74 static void End ( vout_thread_t * p_vout );
75 static int Manage ( vout_thread_t * p_vout );
76 static int Control( vout_thread_t *, int, va_list );
77 static void Swap ( vout_thread_t * p_vout );
78 static int Lock ( vout_thread_t * p_vout );
79 static void Unlock ( vout_thread_t * p_vout );
81 int OpenVideoGL ( vlc_object_t * p_this )
83 vout_thread_t * p_vout = (vout_thread_t *) p_this;
85 if( !CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ) )
87 msg_Warn( p_vout, "no OpenGL hardware acceleration found. "
88 "Video display might be slow" );
90 msg_Dbg( p_vout, "display is Quartz Extreme accelerated" );
92 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
93 if( p_vout->p_sys == NULL )
96 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
98 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
100 p_vout->p_sys->b_embedded = false;
102 [VLCGLView performSelectorOnMainThread:@selector(initVout:) withObject:[NSValue valueWithPointer:p_vout] waitUntilDone:YES];
106 /* Check to see if initVout: was successfull */
107 if( !p_vout->p_sys->o_vout_view )
109 free( p_vout->p_sys );
113 p_vout->pf_init = Init;
114 p_vout->pf_end = End;
115 p_vout->pf_manage = Manage;
116 p_vout->pf_control= Control;
117 p_vout->pf_swap = Swap;
118 p_vout->pf_lock = Lock;
119 p_vout->pf_unlock = Unlock;
120 p_vout->p_sys->b_got_frame = false;
125 void CloseVideoGL ( vlc_object_t * p_this )
127 vout_thread_t * p_vout = (vout_thread_t *) p_this;
129 if(VLCIntf && vlc_object_alive (VLCIntf))
131 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
133 /* Close the window */
134 [p_vout->p_sys->o_vout_view performSelectorOnMainThread:@selector(closeVout) withObject:NULL waitUntilDone:YES];
139 free( p_vout->p_sys );
142 static int Init( vout_thread_t * p_vout )
144 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
148 static void End( vout_thread_t * p_vout )
150 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
153 static int Manage( vout_thread_t * p_vout )
155 if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
157 [p_vout->p_sys->o_glview reshape];
158 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
160 if( p_vout->i_changes & VOUT_CROP_CHANGE )
162 [p_vout->p_sys->o_glview reshape];
163 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
166 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
168 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
170 p_vout->b_fullscreen = !p_vout->b_fullscreen;
172 if( p_vout->b_fullscreen )
173 [p_vout->p_sys->o_vout_view enterFullscreen];
175 [p_vout->p_sys->o_vout_view leaveFullscreen];
179 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
182 if( p_vout->p_sys->o_vout_view )
183 [p_vout->p_sys->o_vout_view manage];
187 /*****************************************************************************
188 * Control: control facility for the vout
189 *****************************************************************************/
190 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
196 case VOUT_SET_STAY_ON_TOP:
197 b_arg = (bool) va_arg( args, int );
198 [p_vout->p_sys->o_vout_view setOnTop: b_arg];
206 static void Swap( vout_thread_t * p_vout )
208 p_vout->p_sys->b_got_frame = true;
209 [[p_vout->p_sys->o_glview openGLContext] flushBuffer];
212 static int Lock( vout_thread_t * p_vout )
214 if( kCGLNoError == CGLLockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]) )
216 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
222 static void Unlock( vout_thread_t * p_vout )
224 CGLUnlockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]);
227 /*****************************************************************************
228 * VLCGLView implementation
229 *****************************************************************************/
230 @implementation VLCGLView
231 + (void)initVout:(NSValue *)arg
233 vout_thread_t * p_vout = [arg pointerValue];
235 /* Create the GL view */
236 p_vout->p_sys->o_glview = [[VLCGLView alloc] initWithVout: p_vout];
237 [p_vout->p_sys->o_glview autorelease];
239 /* Spawn the window */
240 id old_vout = p_vout->p_sys->o_vout_view;
241 p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
242 subView: p_vout->p_sys->o_glview frame: nil] retain];
246 /* This function will reset the o_vout_view. It's useful to go fullscreen. */
247 + (void)resetVout:(NSValue *) voutValue
249 vout_thread_t * p_vout = [voutValue pointerValue];
250 if( p_vout->b_fullscreen )
252 /* Save window size and position */
253 p_vout->p_sys->s_frame.size =
254 [p_vout->p_sys->o_vout_view frame].size;
255 p_vout->p_sys->s_frame.origin =
256 [[p_vout->p_sys->o_vout_view voutWindow]frame].origin;
257 p_vout->p_sys->b_saved_frame = true;
260 [p_vout->p_sys->o_vout_view closeVout];
262 #define o_glview p_vout->p_sys->o_glview
263 o_glview = [[VLCGLView alloc] initWithVout: p_vout];
264 [o_glview autorelease];
266 if( p_vout->p_sys->b_saved_frame )
268 id old_vout = p_vout->p_sys->o_vout_view;
269 p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
271 frame: &p_vout->p_sys->s_frame] retain];
276 id old_vout = p_vout->p_sys->o_vout_view;
277 p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
278 subView: o_glview frame: nil] retain];
284 - (id) initWithVout: (vout_thread_t *) vout
286 /* Must be called from main thread:
287 * "The NSView class is generally thread-safe, with a few exceptions. You
288 * should create, destroy, resize, move, and perform other operations on NSView
289 * objects only from the main thread of an application. Drawing from secondary
290 * threads is thread-safe as long as you bracket drawing calls with calls to
291 * lockFocusIfCanDraw and unlockFocus." Cocoa Thread Safety */
295 NSOpenGLPixelFormatAttribute attribs[] =
297 NSOpenGLPFADoubleBuffer,
298 NSOpenGLPFAAccelerated,
299 NSOpenGLPFANoRecovery,
300 NSOpenGLPFAColorSize, 24,
301 NSOpenGLPFAAlphaSize, 8,
302 NSOpenGLPFADepthSize, 24,
307 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
308 initWithAttributes: attribs];
312 msg_Warn( p_vout, "could not create OpenGL video output" );
316 self = [super initWithFrame: NSMakeRect(0,0,10,10) pixelFormat: fmt];
319 [[self openGLContext] makeCurrentContext];
320 [[self openGLContext] update];
322 /* Swap buffers only during the vertical retrace of the monitor.
323 http://developer.apple.com/documentation/GraphicsImaging/
324 Conceptual/OpenGL/chap5/chapter_5_section_44.html */
325 GLint params[] = { 1 };
326 CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, params );
330 - (BOOL)mouseDownCanMoveWindow
340 NSRect bounds = [self bounds];
342 if( var_GetBool( p_vout, "macosx-stretch" ) )
344 x = bounds.size.width;
345 y = bounds.size.height;
347 else if( bounds.size.height * p_vout->fmt_in.i_visible_width *
348 p_vout->fmt_in.i_sar_num <
349 bounds.size.width * p_vout->fmt_in.i_visible_height *
350 p_vout->fmt_in.i_sar_den )
352 x = ( bounds.size.height * p_vout->fmt_in.i_visible_width *
353 p_vout->fmt_in.i_sar_num ) /
354 ( p_vout->fmt_in.i_visible_height * p_vout->fmt_in.i_sar_den);
356 y = bounds.size.height;
360 x = bounds.size.width;
361 y = ( bounds.size.width * p_vout->fmt_in.i_visible_height *
362 p_vout->fmt_in.i_sar_den) /
363 ( p_vout->fmt_in.i_visible_width * p_vout->fmt_in.i_sar_num );
366 glViewport( ( bounds.size.width - x ) / 2,
367 ( bounds.size.height - y ) / 2, x, y );
371 if( p_vout->p_sys->b_got_frame )
373 /* Ask the opengl module to redraw */
374 vout_thread_t * p_parent;
375 p_parent = (vout_thread_t *) p_vout->p_parent;
377 if( p_parent && p_parent->pf_display )
379 p_parent->pf_display( p_parent, NULL );
384 glClear( GL_COLOR_BUFFER_BIT );
396 - (void) drawRect: (NSRect) rect
399 [[p_vout->p_sys->o_glview openGLContext] flushBuffer];
400 [super drawRect:rect];
406 NSWindow *window = [self window];
408 if ([window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)])
410 [window disableScreenUpdatesUntilFlush];