/*****************************************************************************
* voutgl.m: MacOS X OpenGL provider
*****************************************************************************
- * Copyright (C) 2001-2004 the VideoLAN team
- * $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
+ * Copyright (C) 2001-2004, 2007-2009, 2011 the VideoLAN team
+ * $Id$
*
* Authors: Colin Delacroix <colin@zoy.org>
* Florian G. Pflug <fgp@phlo.org>
* Derk-Jan Hartman <hartman at videolan dot org>
* Eric Petit <titer@m0k.org>
* Benjamin Pracht <bigben at videolan dot org>
+ * Damien Fouilleul <damienf at videolan dot org>
+ * Felix Paul Kuehne <fkuehne at videolan dot org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*****************************************************************************
* Preamble
*****************************************************************************/
-#include <errno.h> /* ENOMEM */
#include <stdlib.h> /* free() */
-#include <string.h> /* strerror() */
+#include <string.h>
+#include <vlc_common.h>
#include <vlc_keys.h>
#include "intf.h"
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
+#if 0
+
/*****************************************************************************
- * VLCView interface
+ * VLCGLView interface
*****************************************************************************/
-@interface VLCGLView : NSOpenGLView
+@interface VLCGLView : NSOpenGLView <VLCVoutViewResetting>
{
vout_thread_t * p_vout;
}
++ (void)resetVout: (NSValue *) voutValue;
- (id) initWithVout: (vout_thread_t *) p_vout;
@end
struct vout_sys_t
{
- NSAutoreleasePool * o_pool;
VLCGLView * o_glview;
VLCVoutView * o_vout_view;
- vlc_bool_t b_saved_frame;
+ bool b_saved_frame;
NSRect s_frame;
- vlc_bool_t b_got_frame;
- vlc_mutex_t lock;
- int i_vout_size_update_counter;
- int i_x, i_y;
+ bool b_got_frame;
+
+ bool b_embedded;
};
/*****************************************************************************
static int Lock ( vout_thread_t * p_vout );
static void Unlock ( vout_thread_t * p_vout );
-static int AspectCropCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-
-int E_(OpenVideoGL) ( vlc_object_t * p_this )
+int OpenVideoGL ( vlc_object_t * p_this )
{
vout_thread_t * p_vout = (vout_thread_t *) p_this;
if( !CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ) )
{
msg_Warn( p_vout, "no OpenGL hardware acceleration found. "
- "Video display will be slow" );
- return( 1 );
+ "Video display might be slow" );
}
msg_Dbg( p_vout, "display is Quartz Extreme accelerated" );
p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
if( p_vout->p_sys == NULL )
- {
- msg_Err( p_vout, "out of memory" );
- return( 1 );
- }
+ return VLC_ENOMEM;
memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
- p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
- vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
+ NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
- /* Create the GL view */
- p_vout->p_sys->o_glview = [[VLCGLView alloc] initWithVout: p_vout];
- [p_vout->p_sys->o_glview autorelease];
+ p_vout->p_sys->b_embedded = false;
- /* Spawn the window */
+ [VLCGLView performSelectorOnMainThread:@selector(initVout:) withObject:[NSValue valueWithPointer:p_vout] waitUntilDone:YES];
- if( !(p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
- subView: p_vout->p_sys->o_glview frame: nil]) )
+ [o_pool release];
+
+ /* Check to see if initVout: was successfull */
+ if( !p_vout->p_sys->o_vout_view )
{
+ free( p_vout->p_sys );
return VLC_EGENERIC;
}
- p_vout->p_sys->b_got_frame = VLC_FALSE;
-
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = Manage;
p_vout->pf_swap = Swap;
p_vout->pf_lock = Lock;
p_vout->pf_unlock = Unlock;
+ p_vout->p_sys->b_got_frame = false;
return VLC_SUCCESS;
}
-void E_(CloseVideoGL) ( vlc_object_t * p_this )
+void CloseVideoGL ( vlc_object_t * p_this )
{
vout_thread_t * p_vout = (vout_thread_t *) p_this;
- NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
- /* Close the window */
- [p_vout->p_sys->o_vout_view closeVout];
+ if(VLCIntf && vlc_object_alive (VLCIntf))
+ {
+ NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
+ /* Close the window */
+ [p_vout->p_sys->o_vout_view performSelectorOnMainThread:@selector(closeVout) withObject:NULL waitUntilDone:YES];
+
+ [o_pool release];
+ }
/* Clean up */
- vlc_mutex_destroy( &p_vout->p_sys->lock );
- [o_pool release];
free( p_vout->p_sys );
}
static int Init( vout_thread_t * p_vout )
{
- /* The variable is in fact changed on the parent vout */
- if( !var_Type( p_vout->p_parent, "aspect-ratio" ) )
- {
- var_Create( p_vout->p_parent, "aspect-ratio",
- VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- }
- var_AddCallback( p_vout->p_parent, "aspect-ratio", AspectCropCallback, p_vout );
- if( !var_Type( p_vout->p_parent, "crop" ) )
- {
- var_Create( p_vout->p_parent, "crop",
- VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- }
- var_AddCallback( p_vout->p_parent, "crop", AspectCropCallback, p_vout );
[[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
return VLC_SUCCESS;
}
static void End( vout_thread_t * p_vout )
{
- var_DelCallback( p_vout->p_parent, "aspect-ratio", AspectCropCallback, p_vout );
- var_DelCallback( p_vout->p_parent, "crop", AspectCropCallback, p_vout );
[[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
}
static int Manage( vout_thread_t * p_vout )
{
+ if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
+ {
+ [p_vout->p_sys->o_glview reshape];
+ p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
+ }
+ if( p_vout->i_changes & VOUT_CROP_CHANGE )
+ {
+ [p_vout->p_sys->o_glview reshape];
+ p_vout->i_changes &= ~VOUT_CROP_CHANGE;
+ }
+
if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
{
NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
- if( !p_vout->b_fullscreen )
- {
- /* Save window size and position */
- p_vout->p_sys->s_frame.size =
- [p_vout->p_sys->o_vout_view frame].size;
- p_vout->p_sys->s_frame.origin =
- [[p_vout->p_sys->o_vout_view getWindow ]frame].origin;
- p_vout->p_sys->b_saved_frame = VLC_TRUE;
- }
- [p_vout->p_sys->o_vout_view closeVout];
-
p_vout->b_fullscreen = !p_vout->b_fullscreen;
-#define o_glview p_vout->p_sys->o_glview
- o_glview = [[VLCGLView alloc] initWithVout: p_vout];
- [o_glview autorelease];
-
- if( p_vout->p_sys->b_saved_frame )
- {
- p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
- subView: o_glview
- frame: &p_vout->p_sys->s_frame];
- }
+ if( p_vout->b_fullscreen )
+ [p_vout->p_sys->o_vout_view enterFullscreen];
else
- {
- p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
- subView: o_glview frame: nil];
-
- }
-
- [[o_glview openGLContext] makeCurrentContext];
-#undef o_glview
+ [p_vout->p_sys->o_vout_view leaveFullscreen];
[o_pool release];
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
}
- if( p_vout->p_sys->i_vout_size_update_counter )
- {
- int i_old_x = p_vout->p_sys->i_x, i_old_y = p_vout->p_sys->i_y;
- [p_vout->p_sys->o_glview reshape];
- if( p_vout->p_sys->i_x != i_old_x || p_vout->p_sys->i_y != i_old_y )
- {
- p_vout->p_sys->i_vout_size_update_counter = 0;
- }
- else if( p_vout->p_sys->i_vout_size_update_counter > 0 )
- {
- p_vout->p_sys->i_vout_size_update_counter--;
- }
- }
-
- [p_vout->p_sys->o_vout_view manage];
+ if( p_vout->p_sys->o_vout_view )
+ [p_vout->p_sys->o_vout_view manage];
return VLC_SUCCESS;
}
*****************************************************************************/
static int Control( vout_thread_t *p_vout, int i_query, va_list args )
{
- vlc_bool_t b_arg;
+ bool b_arg;
switch( i_query )
{
case VOUT_SET_STAY_ON_TOP:
- b_arg = va_arg( args, vlc_bool_t );
+ b_arg = (bool) va_arg( args, int );
[p_vout->p_sys->o_vout_view setOnTop: b_arg];
return VLC_SUCCESS;
- case VOUT_CLOSE:
- case VOUT_REPARENT:
default:
- return vout_vaControlDefault( p_vout, i_query, args );
+ return VLC_EGENERIC;
}
}
static void Swap( vout_thread_t * p_vout )
{
- p_vout->p_sys->b_got_frame = VLC_TRUE;
- [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
- glFlush();
+ p_vout->p_sys->b_got_frame = true;
+ [[p_vout->p_sys->o_glview openGLContext] flushBuffer];
}
static int Lock( vout_thread_t * p_vout )
{
- vlc_mutex_lock( &p_vout->p_sys->lock );
- return 0;
+ if( kCGLNoError == CGLLockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]) )
+ {
+ [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
+ return 0;
+ }
+ return 1;
}
static void Unlock( vout_thread_t * p_vout )
{
- vlc_mutex_unlock( &p_vout->p_sys->lock );
-}
-
-static int AspectCropCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- /* Only update the vout size if the aspect ratio has actually been changed*/
- /* We cannot change the size directly in this callback, since fmt_in
- hasn't been updated yet, so do it in Manage */
- if( strcmp( oldval.psz_string, newval.psz_string ) )
- {
- /* khludge ! Here, we are not sure that the vout size will actually
- change (for instance if we go from Predefined to 4:3 on a 4:3
- stream). So, to to trigger reshape endlessly, we decrease that
- counter each time we call reshape. We put it to 0 directly if
- we actually change the vout size. */
- ((vout_thread_t *)p_data)->p_sys->i_vout_size_update_counter = 2;
- }
- return VLC_SUCCESS;
+ CGLUnlockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]);
}
/*****************************************************************************
* VLCGLView implementation
*****************************************************************************/
@implementation VLCGLView
++ (void)initVout:(NSValue *)arg
+{
+ vout_thread_t * p_vout = [arg pointerValue];
+
+ /* Create the GL view */
+ p_vout->p_sys->o_glview = [[VLCGLView alloc] initWithVout: p_vout];
+ [p_vout->p_sys->o_glview autorelease];
+
+ /* Spawn the window */
+ id old_vout = p_vout->p_sys->o_vout_view;
+ p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
+ subView: p_vout->p_sys->o_glview frame: nil] retain];
+ [old_vout release];
+}
+
+/* This function will reset the o_vout_view. It's useful to go fullscreen. */
++ (void)resetVout:(NSValue *) voutValue
+{
+ vout_thread_t * p_vout = [voutValue pointerValue];
+ if( p_vout->b_fullscreen )
+ {
+ /* Save window size and position */
+ p_vout->p_sys->s_frame.size =
+ [p_vout->p_sys->o_vout_view frame].size;
+ p_vout->p_sys->s_frame.origin =
+ [[p_vout->p_sys->o_vout_view voutWindow]frame].origin;
+ p_vout->p_sys->b_saved_frame = true;
+ }
+
+ [p_vout->p_sys->o_vout_view closeVout];
+
+#define o_glview p_vout->p_sys->o_glview
+ o_glview = [[VLCGLView alloc] initWithVout: p_vout];
+ [o_glview autorelease];
+
+ if( p_vout->p_sys->b_saved_frame )
+ {
+ id old_vout = p_vout->p_sys->o_vout_view;
+ p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
+ subView: o_glview
+ frame: &p_vout->p_sys->s_frame] retain];
+ [old_vout release];
+ }
+ else
+ {
+ id old_vout = p_vout->p_sys->o_vout_view;
+ p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
+ subView: o_glview frame: nil] retain];
+ [old_vout release];
+ }
+#undef o_glview
+}
- (id) initWithVout: (vout_thread_t *) vout
{
+ /* Must be called from main thread:
+ * "The NSView class is generally thread-safe, with a few exceptions. You
+ * should create, destroy, resize, move, and perform other operations on NSView
+ * objects only from the main thread of an application. Drawing from secondary
+ * threads is thread-safe as long as you bracket drawing calls with calls to
+ * lockFocusIfCanDraw and unlockFocus." Cocoa Thread Safety */
+
p_vout = vout;
NSOpenGLPixelFormatAttribute attribs[] =
{
+ NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccelerated,
NSOpenGLPFANoRecovery,
NSOpenGLPFAColorSize, 24,
/* Swap buffers only during the vertical retrace of the monitor.
http://developer.apple.com/documentation/GraphicsImaging/
Conceptual/OpenGL/chap5/chapter_5_section_44.html */
- long params[] = { 1 };
- CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
- params );
+ GLint params[] = { 1 };
+ CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, params );
return self;
}
+- (BOOL)mouseDownCanMoveWindow
+{
+ return YES;
+}
+
- (void) reshape
{
int x, y;
- vlc_value_t val;
Lock( p_vout );
NSRect bounds = [self bounds];
- [[self openGLContext] makeCurrentContext];
-
- var_Get( p_vout, "macosx-stretch", &val );
- if( val.b_bool )
+ if( var_GetBool( p_vout, "macosx-stretch" ) )
{
x = bounds.size.width;
y = bounds.size.height;
( p_vout->fmt_in.i_visible_width * p_vout->fmt_in.i_sar_num );
}
- p_vout->p_sys->i_x = x;
- p_vout->p_sys->i_y = y;
-
glViewport( ( bounds.size.width - x ) / 2,
( bounds.size.height - y ) / 2, x, y );
+ [super reshape];
+
if( p_vout->p_sys->b_got_frame )
{
/* Ask the opengl module to redraw */
glClear( GL_COLOR_BUFFER_BIT );
Unlock( p_vout );
}
- [super reshape];
}
- (void) update
- (void) drawRect: (NSRect) rect
{
Lock( p_vout );
- [[self openGLContext] makeCurrentContext];
- glFlush();
+ [[p_vout->p_sys->o_glview openGLContext] flushBuffer];
[super drawRect:rect];
Unlock( p_vout );
}
-@end
+- (void) renewGState
+{
+ NSWindow *window = [self window];
+ if ([window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)])
+ {
+ [window disableScreenUpdatesUntilFlush];
+ }
+ [super renewGState];
+}
+
+@end
+#endif