*****************************************************************************/
#include <errno.h> /* ENOMEM */
-#include <vlc/vlc.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
#include <vlc_vout.h>
#import <QuartzCore/QuartzCore.h>
# define GL_CLAMP_TO_EDGE 0x812F
#endif
+@interface VLCVideoView : NSObject
+- (void)addVoutLayer:(CALayer *)layer;
+@end
/*****************************************************************************
* Vout interface
set_shortname( "OpenGLLayer" );
set_category( CAT_VIDEO );
set_subcategory( SUBCAT_VIDEO_VOUT );
- set_description( _("Core Animation OpenGL Layer (Mac OS X)") );
+ set_description( N_("Core Animation OpenGL Layer (Mac OS X)") );
set_capability( "video output", 20 );
add_shortcut( "opengllayer" );
set_callbacks( CreateVout, DestroyVout );
vlc_module_end();
-@interface VLCVideoLayer : CAOpenGLLayer {
+@interface VLCVoutLayer : CAOpenGLLayer {
vout_thread_t * p_vout;
}
+ (id)layerWithVout:(vout_thread_t*)_p_vout;
uint8_t *pp_buffer[2]; /* one last rendered, one to be rendered */
int i_index;
- vlc_bool_t b_frame_available;
+ bool b_frame_available;
+
+ CGLContextObj glContext;
int i_tex_width;
int i_tex_height;
GLuint p_textures[2];
NSAutoreleasePool *autorealease_pool;
- VLCVideoLayer * o_layer;
+ VLCVoutLayer * o_layer;
id o_cocoa_container;
};
msg_Dbg( p_vout, "Texture size: %dx%d", p_sys->i_tex_width,
p_sys->i_tex_height );
-
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = Manage;
return VLC_EGENERIC;
}
}
- p_sys->b_frame_available = VLC_FALSE;
+ p_sys->b_frame_available = false;
p_sys->i_index = 0;
-
+
p_vout->p_picture[0].i_planes = 1;
- p_vout->p_picture[0].p->p_pixels = p_sys->pp_buffer[0];
+ p_vout->p_picture[0].p->p_pixels = p_sys->pp_buffer[p_sys->i_index];
p_vout->p_picture[0].p->i_lines = p_vout->output.i_height;
p_vout->p_picture[0].p->i_visible_lines = p_vout->output.i_height;
p_vout->p_picture[0].p->i_pixel_pitch = i_pixel_pitch;
I_OUTPUTPICTURES = 1;
p_sys->autorealease_pool = [[NSAutoreleasePool alloc] init];
- [VLCVideoLayer performSelectorOnMainThread:@selector(autoinitInVout:)
+ [VLCVoutLayer performSelectorOnMainThread:@selector(autoinitInVout:)
withObject:[NSValue valueWithPointer:p_vout]
waitUntilDone:YES];
{
vout_sys_t *p_sys = p_vout->p_sys;
- p_vout->p_sys->b_frame_available = 0;
+ p_vout->p_sys->b_frame_available = false;
- [p_sys->o_layer performSelectorOnMainThread:@selector(removeFromSuperlayer)
- withObject:nil waitUntilDone:YES];
+ [p_vout->p_sys->o_cocoa_container performSelectorOnMainThread:@selector(removeVoutLayer:) withObject:p_vout->p_sys->o_layer waitUntilDone:YES];
+
+ // Should be done automatically
[p_sys->o_layer release];
[p_sys->autorealease_pool release];
/* Free the texture buffer*/
- glDeleteTextures( 2, p_sys->p_textures );
- if( p_sys->pp_buffer[0] ) free( p_sys->pp_buffer[0] );
- if( p_sys->pp_buffer[1] ) free( p_sys->pp_buffer[1] );
+ free( p_sys->pp_buffer[0] );
+ free( p_sys->pp_buffer[1] );
}
/*****************************************************************************
* a non null value if an error occurred.
*****************************************************************************/
static int Manage( vout_thread_t *p_vout )
-{
+{
+ vout_sys_t *p_sys = p_vout->p_sys;
+
return VLC_SUCCESS;
}
{
vout_sys_t *p_sys = p_vout->p_sys;
- /* Switch buffers */
- int p_new_index;
- @synchronized(p_sys->o_layer)
+ @synchronized( p_sys->o_layer ) /* Make sure the p_sys->glContext isn't edited */
{
- p_new_index = (p_sys->i_index + 1) & 1;
+ if( p_sys->glContext )
+ {
+ CGLLockContext(p_sys->glContext);
+ CGLSetCurrentContext(p_sys->glContext);
+ int i_new_index;
+ i_new_index = ( p_sys->i_index + 1 ) & 1;
+
+
+ /* Update the texture */
+ glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_new_index] );
+ glTexSubImage2D( VLCGL_TARGET, 0, 0, 0,
+ p_vout->fmt_out.i_width,
+ p_vout->fmt_out.i_height,
+ VLCGL_FORMAT, VLCGL_TYPE, p_sys->pp_buffer[i_new_index] );
+
+ /* Bind to the previous texture for drawing */
+ glBindTexture( VLCGL_TARGET, p_sys->p_textures[p_sys->i_index] );
+
+ /* Switch buffers */
+ p_sys->i_index = i_new_index;
+ p_pic->p->p_pixels = p_sys->pp_buffer[p_sys->i_index];
+ CGLUnlockContext(p_sys->glContext);
+
+ p_sys->b_frame_available = true;
+ }
}
/* Give a buffer where the image will be rendered */
- p_pic->p->p_pixels = p_sys->pp_buffer[p_new_index];
-
+ p_pic->p->p_pixels = p_sys->pp_buffer[p_sys->i_index];
}
/*****************************************************************************
static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
{
vout_sys_t *p_sys = p_vout->p_sys;
-
- /* The frame is ready, give its number so the o_layer can display it */
- @synchronized(p_sys->o_layer)
- {
- p_sys->i_index = (p_sys->i_index + 1) & 1; /* Indicate the layer should use that index */
- }
-
- p_sys->b_frame_available = 1;
+
+ [p_sys->o_layer performSelectorOnMainThread:@selector(display)
+ withObject:nil waitUntilDone:YES];
}
/*****************************************************************************
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
-#ifdef __DISABLED_FOR_NOW__
+ /* Note: It seems that we can't bypass those, and even
+ * disabled they are used. They are the cause of the flickering */
+
/* Tell the driver not to make a copy of the texture but to use
our buffer */
glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );
-#endif
/* Use AGP texturing */
- glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
- GL_STORAGE_SHARED_APPLE );
+ glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE );
+
/* Call glTexImage2D only once, and use glTexSubImage2D later */
- glTexImage2D( VLCGL_TARGET, 0, 3, p_sys->i_tex_width,
+ glTexImage2D( VLCGL_TARGET, 0, 4, p_sys->i_tex_width,
p_sys->i_tex_height, 0, VLCGL_FORMAT, VLCGL_TYPE,
p_sys->pp_buffer[i_index] );
}
}
/*****************************************************************************
- * @implementation VLCVideoLayer
+ * @implementation VLCVoutLayer
*/
-@implementation VLCVideoLayer
+@implementation VLCVoutLayer
/*****************************************************************************
* autoinitInVout: Called from the video thread to create a layer.
+ (void)autoinitInVout:(NSValue*)arg
{
vout_thread_t * p_vout = [arg pointerValue];
- p_vout->p_sys->o_layer = [[VLCVideoLayer layerWithVout: p_vout] retain];
- [p_vout->p_sys->o_cocoa_container addVoutSubview:p_vout->p_sys->o_layer];
-}
-
-- (void)setVout:(vout_thread_t*)_p_vout
-{
- p_vout = _p_vout;
+ p_vout->p_sys->o_layer = [[VLCVoutLayer layerWithVout:p_vout] retain];
+ [p_vout->p_sys->o_cocoa_container addVoutLayer:p_vout->p_sys->o_layer];
}
+ (id)layerWithVout:(vout_thread_t*)_p_vout
{
- VLCVideoLayer* me = [super layer];
+ VLCVoutLayer* me = [[[self alloc] init] autorelease];
if( me )
{
- me.asynchronous = YES;
- [me setVout: _p_vout];
+ me->p_vout = _p_vout;
+ me.asynchronous = NO;
+ me.bounds = CGRectMake( 0.0, 0.0,
+ (float)_p_vout->fmt_in.i_visible_width * _p_vout->fmt_in.i_sar_num,
+ (float)_p_vout->fmt_in.i_visible_height * _p_vout->fmt_in.i_sar_den );
}
return me;
}
- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
{
- /* Only draw the frame when if have a frame that was previously rendered */
- return p_vout->p_sys->b_frame_available;
+ /* Only draw the frame if we have a frame that was previously rendered */
+ return p_vout->p_sys->b_frame_available; // Flag is cleared by drawInCGLContext:pixelFormat:forLayerTime:displayTime:
}
- (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
{
- /* Init */
CGLLockContext( glContext );
CGLSetCurrentContext( glContext );
-
+
float f_width, f_height, f_x, f_y;
f_x = (float)p_vout->fmt_out.i_x_offset;
f_height = (float)p_vout->fmt_out.i_y_offset +
(float)p_vout->fmt_out.i_visible_height;
- @synchronized(self)
- {
- glBindTexture( VLCGL_TARGET, p_vout->p_sys->p_textures[p_vout->p_sys->i_index] );
-
- glTexSubImage2D( VLCGL_TARGET, 0, 0, 0,
- p_vout->fmt_out.i_width,
- p_vout->fmt_out.i_height,
- VLCGL_FORMAT, VLCGL_TYPE, p_vout->p_sys->pp_buffer[p_vout->p_sys->i_index] );
-
- }
-
glClear( GL_COLOR_BUFFER_BIT );
glEnable( VLCGL_TARGET );
glTexCoord2f( f_width, f_height ); glVertex2f( 1.0, -1.0 );
glTexCoord2f( f_x, f_height ); glVertex2f( -1.0, -1.0 );
glEnd();
-
+
glDisable( VLCGL_TARGET );
glFlush();
- CGLUnlockContext( glContext );
-}
-- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
-{
- GLuint attribs[] =
- {
- NSOpenGLPFANoRecovery,
- NSOpenGLPFAWindow,
- NSOpenGLPFAAccelerated,
- NSOpenGLPFADoubleBuffer,
- NSOpenGLPFAColorSize, 24,
- NSOpenGLPFAAlphaSize, 8,
- NSOpenGLPFADepthSize, 24,
- NSOpenGLPFAStencilSize, 8,
- NSOpenGLPFAAccumSize, 0,
- 0
- };
-
- NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*) attribs];
-
-
- return [fmt CGLPixelFormatObj];
+ CGLUnlockContext( glContext );
}
- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
CGLContextObj context = [super copyCGLContextForPixelFormat:pixelFormat];
CGLLockContext( context );
+
CGLSetCurrentContext( context );
+
+ /* Swap buffers only during the vertical retrace of the monitor.
+ http://developer.apple.com/documentation/GraphicsImaging/
+ Conceptual/OpenGL/chap5/chapter_5_section_44.html */
+
+ GLint params = 1;
+ CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
+ ¶ms );
+
InitTextures( p_vout );
- glDisable(GL_BLEND);
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- glDisable(GL_CULL_FACE);
+ glDisable( GL_BLEND );
+ glDisable( GL_DEPTH_TEST );
+ glDepthMask( GL_FALSE );
+ glDisable( GL_CULL_FACE) ;
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT );
CGLUnlockContext( context );
+ @synchronized( self )
+ {
+ p_vout->p_sys->glContext = context;
+ }
+
return context;
}
+
+- (void)releaseCGLContext:(CGLContextObj)glContext
+{
+ @synchronized( self )
+ {
+ p_vout->p_sys->glContext = nil;
+ }
+
+ CGLLockContext( glContext );
+ CGLSetCurrentContext( glContext );
+
+ glDeleteTextures( 2, p_vout->p_sys->p_textures );
+
+ CGLUnlockContext( glContext );
+}
@end