Commit cdde0c12 authored by Eric Petit's avatar Eric Petit
Browse files

All: attempt for an OpenGL video output for OS X. Enable --macosx-opengl

 to give it a try (QT is the default method).
  + Known issues: no fullscreen yet, memory leaks, ugly code, ...
  + Known goodies: it's a few % faster than QT here (playing a DVD). If
      experienced OpenGL and Altivec programmers could have a look and
      give some advice, I guess the performance increase might become
      noticeable.
parent f67ec257
dnl Autoconf settings for vlc
dnl $Id: configure.ac,v 1.160 2004/01/26 16:54:56 titer Exp $
dnl $Id: configure.ac,v 1.161 2004/01/26 18:30:37 titer Exp $
AC_INIT(vlc,0.7.1-cvs)
......@@ -3103,11 +3103,11 @@ AC_ARG_ENABLE(macosx,
[if test "${enable_macosx}" = "yes"
then
AX_ADD_BUILTINS([macosx])
AX_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC])
AX_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL])
fi],
[AC_CHECK_HEADERS(Cocoa/Cocoa.h,
AX_ADD_BUILTINS([macosx])
AX_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC])
AX_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL])
)])
dnl
......
......@@ -2,7 +2,7 @@
* macosx.m: MacOS X module for vlc
*****************************************************************************
* Copyright (C) 2001-2003 VideoLAN
* $Id: macosx.m,v 1.18 2004/01/25 18:53:07 gbazin Exp $
* $Id: macosx.m,v 1.19 2004/01/26 18:30:37 titer Exp $
*
* Authors: Colin Delacroix <colin@zoy.org>
* Eugenio Jarosiewicz <ej0@cise.ufl.edu>
......@@ -53,6 +53,10 @@ void E_(CloseVideo) ( vlc_object_t * );
#define OPAQUENESS_LONGTEXT N_( \
"Set the transparency of the video output. 1 is non-transparent (default) " \
"0 is fully transparent.")
#define OPENGL_TEXT N_("Use OpenGL")
#define OPENGL_LONGTEXT N_( \
"Use OpenGL instead of QuickTime to render the video on the screen." )
vlc_module_begin();
set_description( _("MacOS X interface, sound and video") );
......@@ -61,8 +65,11 @@ vlc_module_begin();
add_submodule();
set_capability( "video output", 200 );
set_callbacks( E_(OpenVideo), E_(CloseVideo) );
add_integer( "macosx-vdev", 0, NULL, VDEV_TEXT, VDEV_LONGTEXT, VLC_FALSE );
add_float_with_range( "macosx-opaqueness", 1, 0, 1, NULL, OPAQUENESS_TEXT,
OPAQUENESS_LONGTEXT, VLC_TRUE );
add_integer( "macosx-vdev", 0, NULL, VDEV_TEXT, VDEV_LONGTEXT,
VLC_FALSE );
add_float_with_range( "macosx-opaqueness", 1, 0, 1, NULL,
OPAQUENESS_TEXT, OPAQUENESS_LONGTEXT, VLC_TRUE );
add_bool( "macosx-opengl", 0, NULL, OPENGL_TEXT,
OPENGL_LONGTEXT, VLC_TRUE );
vlc_module_end();
......@@ -2,7 +2,7 @@
* vout.h: MacOS X interface module
*****************************************************************************
* Copyright (C) 2001-2003 VideoLAN
* $Id: vout.h,v 1.17 2004/01/25 17:01:57 murray Exp $
* $Id: vout.h,v 1.18 2004/01/26 18:30:37 titer Exp $
*
* Authors: Colin Delacroix <colin@zoy.org>
* Florian G. Pflug <fgp@phlo.org>
......@@ -47,12 +47,26 @@
/*****************************************************************************
* VLCView interface
*****************************************************************************/
@interface VLCView : NSQuickDrawView
@interface VLCQTView : NSQuickDrawView
{
}
@end
/*****************************************************************************
* VLCView interface
*****************************************************************************/
@interface VLCGLView : NSOpenGLView
{
@public
int i_init_done;
int i_textures_loaded;
int i_index;
unsigned long pi_textures[3];
}
@end
/*****************************************************************************
* VLCVout interface
*****************************************************************************/
......@@ -70,9 +84,12 @@
*****************************************************************************/
struct vout_sys_t
{
int i_opengl;
NSRect s_rect;
int b_pos_saved;
VLCWindow * o_window;
VLCGLView * o_glview;
vlc_bool_t b_mouse_moved;
mtime_t i_time_mouse_last_moved;
......
......@@ -2,7 +2,7 @@
* vout.m: MacOS X video output module
*****************************************************************************
* Copyright (C) 2001-2003 VideoLAN
* $Id: vout.m,v 1.69 2004/01/25 17:01:57 murray Exp $
* $Id: vout.m,v 1.70 2004/01/26 18:30:37 titer Exp $
*
* Authors: Colin Delacroix <colin@zoy.org>
* Florian G. Pflug <fgp@phlo.org>
......@@ -33,6 +33,9 @@
#include <QuickTime/QuickTime.h>
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <vlc_keys.h>
#include "intf.h"
......@@ -129,11 +132,6 @@ int E_(OpenVideo) ( vlc_object_t *p_this )
}
}
p_vout->p_sys->h_img_descr =
(ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
p_vout->p_sys->p_matrix = (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
p_vout->p_sys->p_fullscreen_state = NULL;
p_vout->p_sys->b_mouse_moved = VLC_TRUE;
p_vout->p_sys->i_time_mouse_last_moved = mdate();
......@@ -141,38 +139,51 @@ int E_(OpenVideo) ( vlc_object_t *p_this )
p_vout->p_sys->s_rect.size.width = p_vout->i_window_width;
p_vout->p_sys->s_rect.size.height = p_vout->i_window_height;
if( ( err = EnterMovies() ) != noErr )
/* Check if we should use QuickTime or OpenGL */
p_vout->p_sys->i_opengl = config_GetInt( p_vout, "macosx-opengl" );
if( !p_vout->p_sys->i_opengl )
{
msg_Err( p_vout, "EnterMovies failed: %d", err );
free( p_vout->p_sys->p_matrix );
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
free( p_vout->p_sys );
return( 1 );
}
/* Initialize QuickTime */
p_vout->p_sys->h_img_descr =
(ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
p_vout->p_sys->p_matrix =
(MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
p_vout->p_sys->p_fullscreen_state = NULL;
/* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
if( ( err = EnterMovies() ) != noErr )
{
msg_Err( p_vout, "EnterMovies failed: %d", err );
free( p_vout->p_sys->p_matrix );
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
free( p_vout->p_sys );
return( 1 );
}
err = FindCodec( kYUV420CodecType, bestSpeedCodec,
nil, &p_vout->p_sys->img_dc );
vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
if( err == noErr && p_vout->p_sys->img_dc != 0 )
{
p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
p_vout->p_sys->i_codec = kYUV420CodecType;
}
else
{
msg_Err( p_vout, "failed to find an appropriate codec" );
}
/* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
if( p_vout->p_sys->img_dc == 0 )
{
free( p_vout->p_sys->p_matrix );
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
free( p_vout->p_sys );
return VLC_EGENERIC;
err = FindCodec( kYUV420CodecType, bestSpeedCodec,
nil, &p_vout->p_sys->img_dc );
vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
if( err == noErr && p_vout->p_sys->img_dc != 0 )
{
p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
p_vout->p_sys->i_codec = kYUV420CodecType;
}
else
{
msg_Err( p_vout, "failed to find an appropriate codec" );
}
if( p_vout->p_sys->img_dc == 0 )
{
free( p_vout->p_sys->p_matrix );
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
free( p_vout->p_sys );
return VLC_EGENERIC;
}
}
NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
......@@ -224,8 +235,11 @@ int E_(OpenVideo) ( vlc_object_t *p_this )
if( CoCreateWindow( p_vout ) )
{
msg_Err( p_vout, "unable to create window" );
free( p_vout->p_sys->p_matrix );
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
if( !p_vout->p_sys->i_opengl )
{
free( p_vout->p_sys->p_matrix );
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
}
free( p_vout->p_sys );
return( 1 );
}
......@@ -256,17 +270,28 @@ static int vout_Init( vout_thread_t *p_vout )
p_vout->output.i_height = p_vout->render.i_height;
p_vout->output.i_aspect = p_vout->render.i_aspect;
SetPort( p_vout->p_sys->p_qdport );
QTScaleMatrix( p_vout );
if( !p_vout->p_sys->i_opengl )
{
SetPort( p_vout->p_sys->p_qdport );
QTScaleMatrix( p_vout );
if( QTCreateSequence( p_vout ) )
if( QTCreateSequence( p_vout ) )
{
msg_Err( p_vout, "unable to create sequence" );
return( 1 );
}
}
else
{
msg_Err( p_vout, "unable to create sequence" );
return( 1 );
p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
p_vout->output.i_rmask = 0xFF0000;
p_vout->output.i_gmask = 0x00FF00;
p_vout->output.i_bmask = 0x0000FF;
}
/* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
while( I_OUTPUTPICTURES <
( p_vout->p_sys->i_opengl ? 3 : QT_MAX_DIRECTBUFFERS ) )
{
p_pic = NULL;
......@@ -281,11 +306,25 @@ static int vout_Init( vout_thread_t *p_vout )
}
/* Allocate the picture */
if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
if( p_pic == NULL )
{
break;
}
if( !p_vout->p_sys->i_opengl )
{
if( QTNewPicture( p_vout, p_pic ) )
{
break;
}
}
else
{
vout_AllocatePicture( p_vout, p_pic, p_vout->output.i_chroma,
p_vout->output.i_width, p_vout->output.i_height,
p_vout->output.i_aspect );
}
p_pic->i_status = DESTROYED_PICTURE;
p_pic->i_type = DIRECT_PICTURE;
......@@ -294,6 +333,12 @@ static int vout_Init( vout_thread_t *p_vout )
I_OUTPUTPICTURES++;
}
if( p_vout->p_sys->i_opengl )
{
p_vout->p_sys->o_glview->i_index = -1;
p_vout->p_sys->o_glview->i_init_done = 1;
}
return( 0 );
}
......@@ -304,13 +349,23 @@ static void vout_End( vout_thread_t *p_vout )
{
int i_index;
QTDestroySequence( p_vout );
if( !p_vout->p_sys->i_opengl )
{
QTDestroySequence( p_vout );
}
/* Free the direct buffers we allocated */
for( i_index = I_OUTPUTPICTURES; i_index; )
{
i_index--;
QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
if( !p_vout->p_sys->i_opengl )
{
QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
}
else
{
free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
}
}
}
......@@ -326,13 +381,16 @@ void E_(CloseVideo) ( vlc_object_t *p_this )
msg_Err( p_vout, "unable to destroy window" );
}
if ( p_vout->p_sys->p_fullscreen_state != NULL )
EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
if( !p_vout->p_sys->i_opengl )
{
if ( p_vout->p_sys->p_fullscreen_state != NULL )
EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
ExitMovies();
ExitMovies();
free( p_vout->p_sys->p_matrix );
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
free( p_vout->p_sys->p_matrix );
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
}
free( p_vout->p_sys );
}
......@@ -357,9 +415,12 @@ static int vout_Manage( vout_thread_t *p_vout )
if( p_vout->i_changes & VOUT_SIZE_CHANGE )
{
QTScaleMatrix( p_vout );
SetDSequenceMatrix( p_vout->p_sys->i_seq,
p_vout->p_sys->p_matrix );
if( !p_vout->p_sys->i_opengl )
{
QTScaleMatrix( p_vout );
SetDSequenceMatrix( p_vout->p_sys->i_seq,
p_vout->p_sys->p_matrix );
}
p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
}
......@@ -392,20 +453,31 @@ static int vout_Manage( vout_thread_t *p_vout )
*****************************************************************************/
static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
{
OSErr err;
CodecFlags flags;
if( ( err = DecompressSequenceFrameS(
p_vout->p_sys->i_seq,
p_pic->p_sys->p_info,
p_pic->p_sys->i_size,
codecFlagUseImageBuffer, &flags, nil ) != noErr ) )
if( !p_vout->p_sys->i_opengl )
{
msg_Warn( p_vout, "DecompressSequenceFrameS failed: %d", err );
OSErr err;
CodecFlags flags;
if( ( err = DecompressSequenceFrameS(
p_vout->p_sys->i_seq,
p_pic->p_sys->p_info,
p_pic->p_sys->i_size,
codecFlagUseImageBuffer, &flags, nil ) != noErr ) )
{
msg_Warn( p_vout, "DecompressSequenceFrameS failed: %d", err );
}
else
{
QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
}
}
else
{
QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
p_vout->p_sys->o_glview->i_index++;
p_vout->p_sys->o_glview->i_index %= 3;
[p_vout->p_sys->o_glview setNeedsDisplay: YES];
p_pic->p->p_pixels =
PP_OUTPUTPICTURE[(p_vout->p_sys->o_glview->i_index+1)%3]->p_data;
}
}
......@@ -484,6 +556,12 @@ static int CoDestroyWindow( vout_thread_t *p_vout )
*****************************************************************************/
static int CoToggleFullscreen( vout_thread_t *p_vout )
{
if( p_vout->p_sys->i_opengl )
{
/* TODO */
return 0;
}
QTDestroySequence( p_vout );
if( CoDestroyWindow( p_vout ) )
......@@ -530,7 +608,7 @@ static void VLCHideMouse ( vout_thread_t *p_vout, BOOL b_hide )
if ( b_hide && b_inside )
{
/* only hide if mouse over VLCView */
/* only hide if mouse over VLCQTView */
[NSCursor setHiddenUntilMouseMoves: YES];
}
else if ( !b_hide )
......@@ -936,9 +1014,9 @@ static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
@end
/*****************************************************************************
* VLCView implementation
* VLCQTView implementation
*****************************************************************************/
@implementation VLCView
@implementation VLCQTView
- (void)drawRect:(NSRect)rect
{
......@@ -1180,6 +1258,141 @@ static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
@end
/*****************************************************************************
* VLCGLView implementation
*****************************************************************************/
@implementation VLCGLView
- (id) initWithFrame: (NSRect) frame
{
NSOpenGLPixelFormatAttribute attribs[] =
{
NSOpenGLPFAAccelerated,
NSOpenGLPFANoRecovery,
NSOpenGLPFADoubleBuffer,
0
};
NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
initWithAttributes: attribs];
self = [super initWithFrame:frame pixelFormat: fmt];
[[self openGLContext] makeCurrentContext];
[[self openGLContext] update];
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
glColor4f( 1.0, 1.0, 1.0, 1.0 );
glClearColor( 0.5, 0.5, 0.5, 0.5 );
i_init_done = 0;
i_textures_loaded = 0;
return self;
}
- (void) reshape
{
NSRect bounds;
[[self openGLContext] update];
bounds = [self bounds];
glViewport( 0, 0, (GLsizei) bounds.size.width,
(GLsizei) bounds.size.height );
}
- (void)drawRect:(NSRect)rect
{
vout_thread_t * p_vout;
id o_window = [self window];
p_vout = (vout_thread_t *)[o_window getVout];
/* Make this current context */
[[self openGLContext] makeCurrentContext];
if( !i_init_done )
{
/* Nothing to display, blank the view */
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
return;
}
if( !i_textures_loaded )
{
int i;
glGenTextures( 3, pi_textures );
for( i = 0; i < 3; i++ )
{
/* Create the texture */
glDisable( GL_TEXTURE_2D );
glEnable( GL_TEXTURE_RECTANGLE_EXT );
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, pi_textures[i]);
/* Map our buffer to the texture */
glTexImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGB8,
p_vout->output.i_width, p_vout->output.i_height, 0,
GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
PP_OUTPUTPICTURE[i]->p_data );
}
}
glDisable( GL_TEXTURE_2D );
glEnable( GL_TEXTURE_RECTANGLE_EXT );
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, pi_textures[i_index] );
/* Turn on AGP transferts */
glTexParameterf( GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_PRIORITY, 0.0 );
/* Use AGP texturing */
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE );
/* Tell the driver not to make a copy of the texture but to use out
buffer */
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
/* Linear interpolation */
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
GL_TEXTURE_MAG_FILTER, GL_LINEAR );
/* I have no idea what this exactly does, but it seems to be
necessary for scaling */
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
/* Draw a quad with our texture on it */
glBegin( GL_QUADS );
/* Top left */
glTexCoord2f( 0.0f, 0.0f );
glVertex2f( -1.0f, 1.0f );
/* Bottom left */
glTexCoord2f( 0.0f, (float) p_vout->output.i_height );
glVertex2f( -1.0f, -1.0f );
/* Bottom right */
glTexCoord2f( (float) p_vout->output.i_width,
(float) p_vout->output.i_height );
glVertex2f( 1.0f, -1.0f );
/* Top right */
glTexCoord2f( (float) p_vout->output.i_width, 0.0f );
glVertex2f( 1.0f, 1.0f );
glEnd();
/* Wait for the job to be done */
[[self openGLContext] flushBuffer];
}
@end
/*****************************************************************************
* VLCVout implementation
*****************************************************************************/
......@@ -1188,7 +1401,7 @@ static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
- (void)createWindow:(NSValue *)o_value
{
vlc_value_t val;
VLCView * o_view;
VLCQTView * o_view;
NSScreen * o_screen;
vout_thread_t * p_vout;
vlc_bool_t b_main_screen;
......@@ -1223,6 +1436,12 @@ static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
}
}
if( p_vout->p_sys->i_opengl )
{
/* XXX Fix fullscreen mode */
p_vout->b_fullscreen = 0;
}
if( p_vout->b_fullscreen )
{
NSRect screen_rect = [o_screen frame];
......@@ -1249,9 +1468,12 @@ static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
NSClosableWindowMask |
NSResizableWindowMask;
if ( p_vout->p_sys->p_fullscreen_state != NULL )
EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
p_vout->p_sys->p_fullscreen_state = NULL;
if( !p_vout->p_sys->i_opengl )
{
if ( p_vout->p_sys->p_fullscreen_state != NULL )
EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
p_vout->p_sys->p_fullscreen_state = NULL;
}