1 /*****************************************************************************
2 * VLCOpenGLVoutView.m: MacOS X OpenGL provider
3 *****************************************************************************
4 * Copyright (C) 2001-2009 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 * Pierre d'Herbemont <pdherbemont 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 *****************************************************************************/
36 #include "VLCOpenGLVoutView.h"
37 #include "VLCMinimalVoutWindow.h"
39 #include <OpenGL/OpenGL.h>
40 #include <OpenGL/gl.h>
42 /*****************************************************************************
44 *****************************************************************************/
45 int cocoaglvoutviewInit( vout_thread_t * p_vout )
47 vlc_value_t value_drawable;
48 id <VLCOpenGLVoutEmbedding> o_cocoaglview_container;
50 msg_Dbg( p_vout, "Mac OS X Vout is opening" );
52 var_Create( p_vout, "drawable-nsobject", VLC_VAR_DOINHERIT );
53 var_Get( p_vout, "drawable-nsobject", &value_drawable );
55 p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
57 /* This will be released in cocoaglvoutviewEnd(), on
58 * main thread, after we are done using it. */
59 o_cocoaglview_container = [(id) value_drawable.p_address retain];
60 if (!o_cocoaglview_container)
62 msg_Warn( p_vout, "No drawable!, spawing a window" );
65 p_vout->p_sys->b_embedded = false;
68 /* Create the GL view */
69 struct args { vout_thread_t * p_vout; id <VLCOpenGLVoutEmbedding> container; } args = { p_vout, o_cocoaglview_container };
71 [VLCOpenGLVoutView performSelectorOnMainThread:@selector(autoinitOpenGLVoutViewIntVoutWithContainer:)
72 withObject:[NSData dataWithBytes: &args length: sizeof(struct args)] waitUntilDone:YES];
74 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
78 /*****************************************************************************
80 *****************************************************************************/
81 void cocoaglvoutviewEnd( vout_thread_t * p_vout )
83 id <VLCOpenGLVoutEmbedding> o_cocoaglview_container;
85 if (!p_vout->p_sys->o_glview)
88 msg_Dbg( p_vout, "Mac OS X Vout is closing" );
89 var_Destroy( p_vout, "drawable-nsobject" );
91 o_cocoaglview_container = [p_vout->p_sys->o_glview container];
93 /* Make sure our view won't request the vout now */
94 [p_vout->p_sys->o_glview detachFromVout];
95 msg_Dbg( p_vout, "Mac OS X Vout is closing" );
97 if( [(id)o_cocoaglview_container respondsToSelector:@selector(removeVoutSubview:)] )
98 [o_cocoaglview_container performSelectorOnMainThread:@selector(removeVoutSubview:) withObject:p_vout->p_sys->o_glview waitUntilDone:NO];
100 /* Let the view go and release it, _without_blocking_ */
101 [p_vout->p_sys->o_glview performSelectorOnMainThread:@selector(removeFromSuperviewAndRelease) withObject:nil waitUntilDone:NO];
102 p_vout->p_sys->o_glview = nil;
104 /* Release the container now that we don't use it */
105 [o_cocoaglview_container performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
107 [p_vout->p_sys->o_pool release];
108 p_vout->p_sys->o_pool = nil;
112 /*****************************************************************************
113 * cocoaglvoutviewManage
114 *****************************************************************************/
115 int cocoaglvoutviewManage( vout_thread_t * p_vout )
117 if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
119 [p_vout->p_sys->o_glview reshape];
120 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
122 if( p_vout->i_changes & VOUT_CROP_CHANGE )
124 [p_vout->p_sys->o_glview reshape];
125 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
128 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
130 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
132 p_vout->b_fullscreen = !p_vout->b_fullscreen;
134 if( p_vout->b_fullscreen )
135 [[p_vout->p_sys->o_glview container] enterFullscreen];
137 [[p_vout->p_sys->o_glview container] leaveFullscreen];
141 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
144 //[[p_vout->p_sys->o_glview container] manage];
148 /*****************************************************************************
149 * cocoaglvoutviewControl: control facility for the vout
150 *****************************************************************************/
151 int cocoaglvoutviewControl( vout_thread_t *p_vout, int i_query, va_list args )
157 case VOUT_SET_STAY_ON_TOP:
158 b_arg = (bool) va_arg( args, int );
159 [[p_vout->p_sys->o_glview container] setOnTop: b_arg];
167 /*****************************************************************************
168 * cocoaglvoutviewSwap
169 *****************************************************************************/
170 void cocoaglvoutviewSwap( vout_thread_t * p_vout )
172 p_vout->p_sys->b_got_frame = true;
173 [[p_vout->p_sys->o_glview openGLContext] flushBuffer];
176 /*****************************************************************************
177 * cocoaglvoutviewLock
178 *****************************************************************************/
179 int cocoaglvoutviewLock( vout_thread_t * p_vout )
181 if( kCGLNoError == CGLLockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]) )
183 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
189 /*****************************************************************************
190 * cocoaglvoutviewUnlock
191 *****************************************************************************/
192 void cocoaglvoutviewUnlock( vout_thread_t * p_vout )
194 CGLUnlockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]);
197 /*****************************************************************************
198 * VLCOpenGLVoutView implementation
199 *****************************************************************************/
200 @implementation VLCOpenGLVoutView
202 /* Init a new gl view and register it to both the framework and the
203 * vout_thread_t. Must be called from main thread. */
204 + (void) autoinitOpenGLVoutViewIntVoutWithContainer: (NSData *) argsAsData
206 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
207 struct args { vout_thread_t * p_vout; id <VLCOpenGLVoutEmbedding> container; } *
208 args = (struct args *)[argsAsData bytes];
209 VLCOpenGLVoutView * oglview;
211 if( !args->container )
213 args->container = [[VLCMinimalVoutWindow alloc] initWithContentRect: NSMakeRect( 0, 0, args->p_vout->i_window_width, args->p_vout->i_window_height )];
214 [(VLCMinimalVoutWindow *)args->container makeKeyAndOrderFront: nil];
216 oglview = [[VLCOpenGLVoutView alloc] initWithVout: args->p_vout container: args->container];
218 args->p_vout->p_sys->o_glview = oglview;
219 [args->container addVoutSubview: oglview];
226 [objectLock dealloc];
230 - (void)removeFromSuperviewAndRelease
232 [self removeFromSuperview];
236 - (id) initWithVout: (vout_thread_t *) vout container: (id <VLCOpenGLVoutEmbedding>) aContainer
238 NSOpenGLPixelFormatAttribute attribs[] =
240 NSOpenGLPFADoubleBuffer,
241 NSOpenGLPFAAccelerated,
242 NSOpenGLPFANoRecovery,
243 NSOpenGLPFAColorSize, 24,
244 NSOpenGLPFAAlphaSize, 8,
245 NSOpenGLPFADepthSize, 24,
250 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
251 initWithAttributes: attribs];
255 msg_Warn( p_vout, "could not create OpenGL video output" );
259 if( self = [super initWithFrame: NSMakeRect(0,0,10,10) pixelFormat: fmt] )
262 container = aContainer;
263 objectLock = [[NSLock alloc] init];
267 [[self openGLContext] makeCurrentContext];
268 [[self openGLContext] update];
270 /* Swap buffers only during the vertical retrace of the monitor.
271 http://developer.apple.com/documentation/GraphicsImaging/
272 Conceptual/OpenGL/chap5/chapter_5_section_44.html */
273 GLint params[] = { 1 };
274 CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
280 - (void) detachFromVout
287 - (id <VLCOpenGLVoutEmbedding>) container
297 vlc_object_release( p_vout );
298 vlc_object_release( p_vout );
315 cocoaglvoutviewLock( p_vout );
316 NSRect bounds = [self bounds];
318 if( [[self container] stretchesVideo] )
320 x = bounds.size.width;
321 y = bounds.size.height;
323 else if( bounds.size.height * p_vout->fmt_in.i_visible_width *
324 p_vout->fmt_in.i_sar_num <
325 bounds.size.width * p_vout->fmt_in.i_visible_height *
326 p_vout->fmt_in.i_sar_den )
328 x = ( bounds.size.height * p_vout->fmt_in.i_visible_width *
329 p_vout->fmt_in.i_sar_num ) /
330 ( p_vout->fmt_in.i_visible_height * p_vout->fmt_in.i_sar_den);
332 y = bounds.size.height;
336 x = bounds.size.width;
337 y = ( bounds.size.width * p_vout->fmt_in.i_visible_height *
338 p_vout->fmt_in.i_sar_den) /
339 ( p_vout->fmt_in.i_visible_width * p_vout->fmt_in.i_sar_num );
342 glViewport( ( bounds.size.width - x ) / 2,
343 ( bounds.size.height - y ) / 2, x, y );
345 if( p_vout->p_sys->b_got_frame )
347 /* Ask the opengl module to redraw */
348 vout_thread_t * p_parent;
349 p_parent = (vout_thread_t *) p_vout->p_parent;
350 cocoaglvoutviewUnlock( p_vout );
351 if( p_parent && p_parent->pf_display )
353 p_parent->pf_display( p_parent, NULL );
358 glClear( GL_COLOR_BUFFER_BIT );
359 cocoaglvoutviewUnlock( p_vout );
369 if( kCGLNoError != CGLLockContext([[self openGLContext] CGLContextObj]) )
372 CGLUnlockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]);
375 - (void) drawRect: (NSRect) rect
379 if( kCGLNoError != CGLLockContext([[self openGLContext] CGLContextObj]) )
381 [[self openGLContext] flushBuffer];
382 [super drawRect:rect];
383 CGLUnlockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]);
386 - (BOOL)mouseDownCanMoveWindow