mirror of
https://github.com/videolan/vlc.git
synced 2025-01-11 18:28:04 +08:00
ALL: OS X OpenGL provider
+ vout.m contains the common code for the QT video output and the GL provider (window creation, events handling) + opengl.c: higher priority on OS X Things are a bit broken atm, any help to debug is welcome ;p
This commit is contained in:
parent
bb7f54bbb1
commit
d4ac5770da
@ -25,6 +25,8 @@ SOURCES_macosx = \
|
||||
output.h \
|
||||
output.m \
|
||||
vout.m \
|
||||
voutqt.m \
|
||||
voutgl.m \
|
||||
vout.h \
|
||||
$(NULL)
|
||||
|
||||
|
@ -291,7 +291,9 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
[o_window toggleFullscreen];
|
||||
vlc_value_t val;
|
||||
var_Get( p_vout, "fullscreen", &val );
|
||||
var_Set( p_vout, "fullscreen", (vlc_value_t)!val.b_bool );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -38,8 +38,11 @@
|
||||
int E_(OpenIntf) ( vlc_object_t * );
|
||||
void E_(CloseIntf) ( vlc_object_t * );
|
||||
|
||||
int E_(OpenVideo) ( vlc_object_t * );
|
||||
void E_(CloseVideo) ( vlc_object_t * );
|
||||
int E_(OpenVideoQT) ( vlc_object_t * );
|
||||
void E_(CloseVideoQT) ( vlc_object_t * );
|
||||
|
||||
int E_(OpenVideoGL) ( vlc_object_t * );
|
||||
void E_(CloseVideoGL) ( vlc_object_t * );
|
||||
|
||||
/*****************************************************************************
|
||||
* Module descriptor
|
||||
@ -59,49 +62,28 @@ void E_(CloseVideo) ( vlc_object_t * );
|
||||
"of the movie when resizing the video, stretch the video " \
|
||||
"to fill the entire window." )
|
||||
|
||||
#define MACOSX_VOUT_TEXT N_("video rendering mode")
|
||||
#define MACOSX_VOUT_LONGTEXT N_("The default method is OpenGL " \
|
||||
"for Quartz Extreme machines and Quartz for the others.")
|
||||
|
||||
#define OPENGL_EFFECT_TEXT N_("OpenGL effect")
|
||||
#define OPENGL_EFFECT_LONGTEXT N_("Use 'None' to display the video " \
|
||||
"without any fantasy, 'Cube' to let the video play on " \
|
||||
"the faces of a rotating cube, 'Transparent cube' do make this " \
|
||||
"cube transparent." )
|
||||
|
||||
#define FILL_TEXT N_("Fill fullscreen")
|
||||
#define FILL_LONGTEXT N_("In fullscreen mode, crop the picture if " \
|
||||
"necessary in order to fill the screen without black " \
|
||||
"borders (OpenGL only)." )
|
||||
|
||||
static char * effect_list[] = { "none", "cube", "transparent-cube" };
|
||||
static char * effect_list_text[] = { N_("None"), N_("Cube"),
|
||||
N_("Transparent cube") };
|
||||
|
||||
static char *ppsz_vout_list[] = { "auto", "quartz", "opengl" };
|
||||
static char *ppsz_vout_list_text[] = { N_("Auto"), "Quartz", "OpenGL" };
|
||||
|
||||
vlc_module_begin();
|
||||
set_description( _("Mac OS X interface, sound and video") );
|
||||
set_capability( "interface", 100 );
|
||||
set_callbacks( E_(OpenIntf), E_(CloseIntf) );
|
||||
add_submodule();
|
||||
set_capability( "video output", 200 );
|
||||
set_callbacks( E_(OpenVideo), E_(CloseVideo) );
|
||||
set_capability( "video output", 100 );
|
||||
set_callbacks( E_(OpenVideoQT), E_(CloseVideoQT) );
|
||||
add_integer( "macosx-vdev", 0, NULL, VDEV_TEXT, VDEV_LONGTEXT,
|
||||
VLC_FALSE );
|
||||
add_bool( "macosx-stretch", 0, NULL, STRETCH_TEXT, STRETCH_LONGTEXT,
|
||||
VLC_FALSE );
|
||||
add_float_with_range( "macosx-opaqueness", 1, 0, 1, NULL,
|
||||
OPAQUENESS_TEXT, OPAQUENESS_LONGTEXT, VLC_TRUE );
|
||||
add_string( "macosx-vout", "auto", NULL, MACOSX_VOUT_TEXT,
|
||||
MACOSX_VOUT_LONGTEXT, VLC_TRUE );
|
||||
change_string_list( ppsz_vout_list, ppsz_vout_list_text, 0 );
|
||||
add_string( "macosx-opengl-effect", "none", NULL,
|
||||
OPENGL_EFFECT_TEXT, OPENGL_EFFECT_LONGTEXT,
|
||||
VLC_TRUE );
|
||||
change_string_list( effect_list, effect_list_text, 0 );
|
||||
add_bool( "macosx-fill", 0, NULL, FILL_TEXT, FILL_LONGTEXT,
|
||||
VLC_TRUE );
|
||||
add_submodule();
|
||||
set_capability( "opengl provider", 100 );
|
||||
set_callbacks( E_(OpenVideoGL), E_(CloseVideoGL) );
|
||||
vlc_module_end();
|
||||
|
||||
|
@ -30,10 +30,18 @@
|
||||
@interface VLCWindow : NSWindow
|
||||
{
|
||||
vout_thread_t * p_vout;
|
||||
|
||||
Ptr p_fullscreen_state;
|
||||
mtime_t i_time_mouse_last_moved;
|
||||
}
|
||||
|
||||
- (void)setVout:(vout_thread_t *)_p_vout;
|
||||
- (vout_thread_t *)getVout;
|
||||
- (id)initWithVout:(vout_thread_t *)_p_vout
|
||||
frame:(NSRect *)s_frame;
|
||||
- (void)close;
|
||||
- (void)setOnTop:(bool)b_on_top;
|
||||
|
||||
- (void)hideMouse:(bool)b_hide;
|
||||
- (void)manage;
|
||||
|
||||
- (void)scaleWindowWithFactor: (float)factor;
|
||||
- (void)toggleFloatOnTop;
|
||||
@ -44,65 +52,3 @@
|
||||
- (BOOL)windowShouldClose:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
/*****************************************************************************
|
||||
* VLCView interface
|
||||
*****************************************************************************/
|
||||
@interface VLCQTView : NSQuickDrawView
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*****************************************************************************
|
||||
* VLCView interface
|
||||
*****************************************************************************/
|
||||
@interface VLCGLView : NSOpenGLView
|
||||
{
|
||||
vout_thread_t * p_vout;
|
||||
int i_effect;
|
||||
unsigned long pi_textures[2];
|
||||
float f_x;
|
||||
float f_y;
|
||||
int initDone;
|
||||
}
|
||||
|
||||
- (id) initWithFrame: (NSRect) frame vout: (vout_thread_t*) p_vout;
|
||||
- (void) initTextures;
|
||||
- (void) reloadTexture: (int) index;
|
||||
- (void) cleanUp;
|
||||
|
||||
@end
|
||||
|
||||
/*****************************************************************************
|
||||
* vout_sys_t: MacOS X video output method descriptor
|
||||
*****************************************************************************/
|
||||
struct vout_sys_t
|
||||
{
|
||||
NSAutoreleasePool *o_pool;
|
||||
NSRect s_rect;
|
||||
VLCWindow * o_window;
|
||||
VLCQTView * o_qtview;
|
||||
|
||||
int i_opengl;
|
||||
int b_pos_saved;
|
||||
|
||||
vlc_bool_t b_mouse_moved;
|
||||
mtime_t i_time_mouse_last_moved;
|
||||
|
||||
#ifdef __QUICKTIME__
|
||||
CodecType i_codec;
|
||||
CGrafPtr p_qdport;
|
||||
ImageSequence i_seq;
|
||||
MatrixRecordPtr p_matrix;
|
||||
DecompressorComponent img_dc;
|
||||
ImageDescriptionHandle h_img_descr;
|
||||
Ptr p_fullscreen_state;
|
||||
#endif
|
||||
|
||||
/* OpenGL */
|
||||
VLCGLView * o_glview;
|
||||
uint8_t * p_data[2];
|
||||
uint8_t * p_data_orig[2];
|
||||
int i_cur_pic;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
336
modules/gui/macosx/voutgl.m
Normal file
336
modules/gui/macosx/voutgl.m
Normal file
@ -0,0 +1,336 @@
|
||||
/*****************************************************************************
|
||||
* vout.m: MacOS X video output module
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2001-2003 VideoLAN
|
||||
* $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
|
||||
*
|
||||
* Authors: Colin Delacroix <colin@zoy.org>
|
||||
* Florian G. Pflug <fgp@phlo.org>
|
||||
* Jon Lech Johansen <jon-vl@nanocrew.net>
|
||||
* Derk-Jan Hartman <hartman at videolan dot org>
|
||||
* Eric Petit <titer@m0k.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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Preamble
|
||||
*****************************************************************************/
|
||||
#include <errno.h> /* ENOMEM */
|
||||
#include <stdlib.h> /* free() */
|
||||
#include <string.h> /* strerror() */
|
||||
|
||||
#include <vlc_keys.h>
|
||||
|
||||
#include "intf.h"
|
||||
#include "vout.h"
|
||||
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
/*****************************************************************************
|
||||
* VLCView interface
|
||||
*****************************************************************************/
|
||||
@interface VLCGLView : NSOpenGLView
|
||||
{
|
||||
vout_thread_t * p_vout;
|
||||
}
|
||||
|
||||
- (id)initWithFrame: (NSRect) frame vout: (vout_thread_t*) p_vout;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
struct vout_sys_t
|
||||
{
|
||||
NSAutoreleasePool *o_pool;
|
||||
VLCWindow * o_window;
|
||||
VLCGLView * o_glview;
|
||||
vlc_bool_t b_saved_frame;
|
||||
NSRect s_frame;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Local prototypes
|
||||
*****************************************************************************/
|
||||
|
||||
static int Init ( vout_thread_t * p_vout );
|
||||
static void End ( vout_thread_t * p_vout );
|
||||
static int Manage ( vout_thread_t * p_vout );
|
||||
static void Swap ( vout_thread_t * p_vout );
|
||||
|
||||
int E_(OpenVideoGL) ( vlc_object_t * p_this )
|
||||
{
|
||||
vout_thread_t * p_vout = (vout_thread_t *) p_this;
|
||||
int i_timeout;
|
||||
vlc_value_t val;
|
||||
|
||||
if( !CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ) )
|
||||
{
|
||||
msg_Warn( p_vout, "no hardware acceleration" );
|
||||
return VLC_EGENERIC;
|
||||
}
|
||||
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 );
|
||||
}
|
||||
|
||||
memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
|
||||
|
||||
/* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
|
||||
for( i_timeout = 20 ; i_timeout-- ; )
|
||||
{
|
||||
if( NSApp == NULL )
|
||||
{
|
||||
msleep( INTF_IDLE_SLEEP );
|
||||
}
|
||||
}
|
||||
|
||||
if( NSApp == NULL )
|
||||
{
|
||||
/* No MacOS X intf, unable to communicate with MT */
|
||||
msg_Err( p_vout, "no MacOS X interface present" );
|
||||
return VLC_EGENERIC;
|
||||
}
|
||||
|
||||
p_vout->pf_init = Init;
|
||||
p_vout->pf_end = End;
|
||||
p_vout->pf_manage = Manage;
|
||||
p_vout->pf_swap = Swap;
|
||||
|
||||
|
||||
p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
var_Create( p_vout, "macosx-vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-opengl-effect", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
|
||||
|
||||
/* Setup the menuitem for the multiple displays. Read the vlc preference (macosx-vdev) for the primary display */
|
||||
NSArray * o_screens = [NSScreen screens];
|
||||
if( [o_screens count] > 0 && var_Type( p_vout, "video-device" ) == 0 )
|
||||
{
|
||||
int i = 1;
|
||||
vlc_value_t val2, text;
|
||||
NSScreen * o_screen;
|
||||
|
||||
var_Get( p_vout, "macosx-vdev", &val );
|
||||
|
||||
var_Create( p_vout, "video-device", VLC_VAR_INTEGER |
|
||||
VLC_VAR_HASCHOICE );
|
||||
text.psz_string = _("Video device");
|
||||
var_Change( p_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
|
||||
|
||||
NSEnumerator * o_enumerator = [o_screens objectEnumerator];
|
||||
|
||||
while( (o_screen = [o_enumerator nextObject]) != NULL )
|
||||
{
|
||||
char psz_temp[255];
|
||||
NSRect s_rect = [o_screen frame];
|
||||
|
||||
snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
|
||||
"%s %d (%dx%d)", _("Screen"), i,
|
||||
(int)s_rect.size.width, (int)s_rect.size.height );
|
||||
|
||||
text.psz_string = psz_temp;
|
||||
val2.i_int = i;
|
||||
var_Change( p_vout, "video-device",
|
||||
VLC_VAR_ADDCHOICE, &val2, &text );
|
||||
|
||||
if( ( i - 1 ) == val.i_int )
|
||||
{
|
||||
var_Set( p_vout, "video-device", val2 );
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
var_AddCallback( p_vout, "video-device", vout_VarCallback,
|
||||
NULL );
|
||||
|
||||
val2.b_bool = VLC_TRUE;
|
||||
var_Set( p_vout, "intf-change", val2 );
|
||||
}
|
||||
|
||||
/* Spawn window */
|
||||
p_vout->p_sys->o_window = [[VLCWindow alloc] initWithVout: p_vout
|
||||
frame: nil];
|
||||
|
||||
/* Add OpenGL view */
|
||||
#define o_glview p_vout->p_sys->o_glview
|
||||
o_glview = [[VLCGLView alloc] initWithFrame:
|
||||
[p_vout->p_sys->o_window frame] vout: p_vout];
|
||||
[p_vout->p_sys->o_window setContentView: o_glview];
|
||||
[o_glview autorelease];
|
||||
#undef o_glview
|
||||
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
|
||||
int E_(CloseVideoGL) ( vlc_object_t * p_this )
|
||||
{
|
||||
vout_thread_t * p_vout = (vout_thread_t *) p_this;
|
||||
NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
[p_vout->p_sys->o_window close];
|
||||
|
||||
[o_pool release];
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
|
||||
static int Init( vout_thread_t * p_vout )
|
||||
{
|
||||
[[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
|
||||
static void End( vout_thread_t * p_vout )
|
||||
{
|
||||
[[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
|
||||
}
|
||||
|
||||
static int Manage( vout_thread_t * p_vout )
|
||||
{
|
||||
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_window contentView] frame].size;
|
||||
p_vout->p_sys->s_frame.origin =
|
||||
[p_vout->p_sys->o_window frame].origin;
|
||||
p_vout->p_sys->b_saved_frame = VLC_TRUE;
|
||||
}
|
||||
[p_vout->p_sys->o_window close];
|
||||
|
||||
p_vout->b_fullscreen = !p_vout->b_fullscreen;
|
||||
|
||||
if( p_vout->p_sys->b_saved_frame )
|
||||
{
|
||||
p_vout->p_sys->o_window = [[VLCWindow alloc]
|
||||
initWithVout: p_vout frame: &p_vout->p_sys->s_frame];
|
||||
}
|
||||
else
|
||||
{
|
||||
p_vout->p_sys->o_window = [[VLCWindow alloc]
|
||||
initWithVout: p_vout frame: nil];
|
||||
}
|
||||
|
||||
#define o_glview p_vout->p_sys->o_glview
|
||||
o_glview = [[VLCGLView alloc] initWithFrame: [p_vout->p_sys->o_window frame] vout: p_vout];
|
||||
[p_vout->p_sys->o_window setContentView: o_glview];
|
||||
[o_glview autorelease];
|
||||
[[o_glview openGLContext] makeCurrentContext];
|
||||
#undef o_glview
|
||||
[o_pool release];
|
||||
|
||||
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
|
||||
}
|
||||
[p_vout->p_sys->o_window manage];
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
|
||||
static void Swap( vout_thread_t * p_vout )
|
||||
{
|
||||
[[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
|
||||
if( [p_vout->p_sys->o_glview lockFocusIfCanDraw] )
|
||||
{
|
||||
glFlush();
|
||||
[p_vout->p_sys->o_glview unlockFocus];
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* VLCGLView implementation
|
||||
*****************************************************************************/
|
||||
@implementation VLCGLView
|
||||
|
||||
- (id) initWithFrame: (NSRect) frame vout: (vout_thread_t*) _p_vout
|
||||
{
|
||||
p_vout = _p_vout;
|
||||
|
||||
NSOpenGLPixelFormatAttribute attribs[] =
|
||||
{
|
||||
NSOpenGLPFAAccelerated,
|
||||
NSOpenGLPFANoRecovery,
|
||||
NSOpenGLPFAColorSize, 24,
|
||||
NSOpenGLPFAAlphaSize, 8,
|
||||
NSOpenGLPFADepthSize, 24,
|
||||
NSOpenGLPFAWindow,
|
||||
0
|
||||
};
|
||||
|
||||
NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
|
||||
initWithAttributes: attribs];
|
||||
|
||||
if( !fmt )
|
||||
{
|
||||
msg_Warn( p_vout, "Cannot create NSOpenGLPixelFormat" );
|
||||
return nil;
|
||||
}
|
||||
|
||||
self = [super initWithFrame:frame pixelFormat: fmt];
|
||||
[fmt release];
|
||||
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
[[self openGLContext] update];
|
||||
|
||||
/* 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 );
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)reshape
|
||||
{
|
||||
int x, y;
|
||||
NSRect bounds = [self bounds];
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
if( bounds.size.height * p_vout->render.i_aspect <
|
||||
bounds.size.width * VOUT_ASPECT_FACTOR )
|
||||
{
|
||||
x = bounds.size.height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
|
||||
y = bounds.size.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = bounds.size.width;
|
||||
y = bounds.size.width * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
|
||||
}
|
||||
glViewport( ( bounds.size.width - x ) / 2,
|
||||
( bounds.size.height - y ) / 2, x, y );
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
}
|
||||
|
||||
- (void) drawRect: (NSRect) rect
|
||||
{
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
glFlush();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
691
modules/gui/macosx/voutqt.m
Normal file
691
modules/gui/macosx/voutqt.m
Normal file
@ -0,0 +1,691 @@
|
||||
/*****************************************************************************
|
||||
* vout.m: MacOS X video output module
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2001-2003 VideoLAN
|
||||
* $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
|
||||
*
|
||||
* Authors: Colin Delacroix <colin@zoy.org>
|
||||
* Florian G. Pflug <fgp@phlo.org>
|
||||
* Jon Lech Johansen <jon-vl@nanocrew.net>
|
||||
* Derk-Jan Hartman <hartman at videolan dot org>
|
||||
* Eric Petit <titer@m0k.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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Preamble
|
||||
*****************************************************************************/
|
||||
#include <errno.h> /* ENOMEM */
|
||||
#include <stdlib.h> /* free() */
|
||||
#include <string.h> /* strerror() */
|
||||
|
||||
#include <QuickTime/QuickTime.h>
|
||||
|
||||
#include <vlc_keys.h>
|
||||
|
||||
#include "intf.h"
|
||||
#include "vout.h"
|
||||
|
||||
#define QT_MAX_DIRECTBUFFERS 10
|
||||
#define VL_MAX_DISPLAYS 16
|
||||
|
||||
/*****************************************************************************
|
||||
* VLCView interface
|
||||
*****************************************************************************/
|
||||
@interface VLCQTView : NSQuickDrawView
|
||||
{
|
||||
vout_thread_t * p_vout;
|
||||
}
|
||||
|
||||
- (id) initWithVout:(vout_thread_t *)p_vout;
|
||||
|
||||
@end
|
||||
|
||||
struct vout_sys_t
|
||||
{
|
||||
NSAutoreleasePool *o_pool;
|
||||
VLCWindow * o_window;
|
||||
VLCQTView * o_qtview;
|
||||
|
||||
vlc_bool_t b_saved_frame;
|
||||
NSRect s_frame;
|
||||
|
||||
CodecType i_codec;
|
||||
CGrafPtr p_qdport;
|
||||
ImageSequence i_seq;
|
||||
MatrixRecordPtr p_matrix;
|
||||
DecompressorComponent img_dc;
|
||||
ImageDescriptionHandle h_img_descr;
|
||||
};
|
||||
|
||||
struct picture_sys_t
|
||||
{
|
||||
void *p_data;
|
||||
unsigned int i_size;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Local prototypes
|
||||
*****************************************************************************/
|
||||
|
||||
static int InitVideo ( vout_thread_t * );
|
||||
static void EndVideo ( vout_thread_t * );
|
||||
static int ManageVideo ( vout_thread_t * );
|
||||
static void DisplayVideo ( vout_thread_t *, picture_t * );
|
||||
static int ControlVideo ( vout_thread_t *, int, va_list );
|
||||
|
||||
static int CoToggleFullscreen( vout_thread_t *p_vout );
|
||||
static void QTScaleMatrix ( vout_thread_t * );
|
||||
static int QTCreateSequence ( vout_thread_t * );
|
||||
static void QTDestroySequence ( vout_thread_t * );
|
||||
static int QTNewPicture ( vout_thread_t *, picture_t * );
|
||||
static void QTFreePicture ( vout_thread_t *, picture_t * );
|
||||
|
||||
/*****************************************************************************
|
||||
* OpenVideo: allocates MacOS X video thread output method
|
||||
*****************************************************************************
|
||||
* This function allocates and initializes a MacOS X vout method.
|
||||
*****************************************************************************/
|
||||
int E_(OpenVideoQT) ( vlc_object_t *p_this )
|
||||
{
|
||||
vout_thread_t * p_vout = (vout_thread_t *)p_this;
|
||||
vlc_value_t val;
|
||||
OSErr err;
|
||||
int i_timeout;
|
||||
|
||||
p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
|
||||
if( p_vout->p_sys == NULL )
|
||||
{
|
||||
msg_Err( p_vout, "out of memory" );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
|
||||
|
||||
/* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
|
||||
for( i_timeout = 20 ; i_timeout-- ; )
|
||||
{
|
||||
if( NSApp == NULL )
|
||||
{
|
||||
msleep( INTF_IDLE_SLEEP );
|
||||
}
|
||||
}
|
||||
|
||||
if( NSApp == NULL )
|
||||
{
|
||||
/* no MacOS X intf, unable to communicate with MT */
|
||||
msg_Err( p_vout, "no MacOS X interface present" );
|
||||
free( p_vout->p_sys );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
p_vout->pf_init = InitVideo;
|
||||
p_vout->pf_end = EndVideo;
|
||||
p_vout->pf_manage = ManageVideo;
|
||||
p_vout->pf_render = NULL;
|
||||
p_vout->pf_display = DisplayVideo;
|
||||
p_vout->pf_control = ControlVideo;
|
||||
|
||||
p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
var_Create( p_vout, "macosx-vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
|
||||
var_Create( p_vout, "macosx-opengl-effect", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
|
||||
|
||||
/* Initialize QuickTime */
|
||||
p_vout->p_sys->h_img_descr =
|
||||
(ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
|
||||
p_vout->p_sys->p_matrix =
|
||||
(MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
|
||||
|
||||
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 VLC_EGENERIC;
|
||||
}
|
||||
|
||||
/* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
|
||||
vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
|
||||
|
||||
/* Can we find the right chroma ? */
|
||||
err = FindCodec( kComponentVideoUnsigned, 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('Y','U','Y','2');
|
||||
p_vout->p_sys->i_codec = kComponentVideoUnsigned;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* Setup the menuitem for the multiple displays. Read the vlc preference (macosx-vdev) for the primary display */
|
||||
NSArray * o_screens = [NSScreen screens];
|
||||
if( [o_screens count] > 0 && var_Type( p_vout, "video-device" ) == 0 )
|
||||
{
|
||||
int i = 1;
|
||||
vlc_value_t val2, text;
|
||||
NSScreen * o_screen;
|
||||
|
||||
var_Get( p_vout, "macosx-vdev", &val );
|
||||
|
||||
var_Create( p_vout, "video-device", VLC_VAR_INTEGER |
|
||||
VLC_VAR_HASCHOICE );
|
||||
text.psz_string = _("Video device");
|
||||
var_Change( p_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
|
||||
|
||||
NSEnumerator * o_enumerator = [o_screens objectEnumerator];
|
||||
|
||||
while( (o_screen = [o_enumerator nextObject]) != NULL )
|
||||
{
|
||||
char psz_temp[255];
|
||||
NSRect s_rect = [o_screen frame];
|
||||
|
||||
snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
|
||||
"%s %d (%dx%d)", _("Screen"), i,
|
||||
(int)s_rect.size.width, (int)s_rect.size.height );
|
||||
|
||||
text.psz_string = psz_temp;
|
||||
val2.i_int = i;
|
||||
var_Change( p_vout, "video-device",
|
||||
VLC_VAR_ADDCHOICE, &val2, &text );
|
||||
|
||||
if( ( i - 1 ) == val.i_int )
|
||||
{
|
||||
var_Set( p_vout, "video-device", val2 );
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
var_AddCallback( p_vout, "video-device", vout_VarCallback,
|
||||
NULL );
|
||||
|
||||
val2.b_bool = VLC_TRUE;
|
||||
var_Set( p_vout, "intf-change", val2 );
|
||||
}
|
||||
|
||||
/* Spawn window */
|
||||
p_vout->p_sys->o_window =
|
||||
[[VLCWindow alloc] initWithVout: p_vout frame: nil];
|
||||
|
||||
#define o_qtview p_vout->p_sys->o_qtview
|
||||
o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
|
||||
[p_vout->p_sys->o_window setContentView: o_qtview];
|
||||
[o_qtview autorelease];
|
||||
|
||||
/* Retrieve the QuickDraw port */
|
||||
[o_qtview lockFocus];
|
||||
p_vout->p_sys->p_qdport = [o_qtview qdPort];
|
||||
[o_qtview unlockFocus];
|
||||
#undef o_qtview
|
||||
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* CloseVideo: destroy video thread output method
|
||||
*****************************************************************************/
|
||||
void E_(CloseVideoQT) ( vlc_object_t *p_this )
|
||||
{
|
||||
NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
|
||||
vout_thread_t * p_vout = (vout_thread_t *)p_this;
|
||||
|
||||
[p_vout->p_sys->o_window close];
|
||||
[p_vout->p_sys->o_window release];
|
||||
|
||||
/* Clean Up Quicktime environment */
|
||||
ExitMovies();
|
||||
free( p_vout->p_sys->p_matrix );
|
||||
DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
|
||||
|
||||
[o_pool release];
|
||||
free( p_vout->p_sys );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* InitVideo: initialize video thread output method
|
||||
*****************************************************************************/
|
||||
static int InitVideo ( vout_thread_t *p_vout )
|
||||
{
|
||||
picture_t *p_pic;
|
||||
int i_index;
|
||||
|
||||
I_OUTPUTPICTURES = 0;
|
||||
|
||||
/* Initialize the output structure; we already found a codec,
|
||||
* and the corresponding chroma we will be using. Since we can
|
||||
* arbitrary scale, stick to the coordinates and aspect. */
|
||||
p_vout->output.i_width = p_vout->render.i_width;
|
||||
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( QTCreateSequence( p_vout ) )
|
||||
{
|
||||
msg_Err( p_vout, "unable to create sequence" );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
/* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
|
||||
while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
|
||||
{
|
||||
p_pic = NULL;
|
||||
|
||||
/* Find an empty picture slot */
|
||||
for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
|
||||
{
|
||||
if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
|
||||
{
|
||||
p_pic = p_vout->p_picture + i_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate the picture */
|
||||
if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p_pic->i_status = DESTROYED_PICTURE;
|
||||
p_pic->i_type = DIRECT_PICTURE;
|
||||
|
||||
PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
|
||||
I_OUTPUTPICTURES++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* EndVideo: terminate video thread output method
|
||||
*****************************************************************************/
|
||||
static void EndVideo( vout_thread_t *p_vout )
|
||||
{
|
||||
int i_index;
|
||||
|
||||
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 ] );
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* ManageVideo: handle events
|
||||
*****************************************************************************
|
||||
* This function should be called regularly by video output thread. It manages
|
||||
* console events. It returns a non null value on error.
|
||||
*****************************************************************************/
|
||||
static int ManageVideo( vout_thread_t *p_vout )
|
||||
{
|
||||
if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
|
||||
{
|
||||
if( CoToggleFullscreen( p_vout ) )
|
||||
{
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
|
||||
}
|
||||
|
||||
if( p_vout->i_changes & VOUT_SIZE_CHANGE )
|
||||
{
|
||||
QTScaleMatrix( p_vout );
|
||||
SetDSequenceMatrix( p_vout->p_sys->i_seq,
|
||||
p_vout->p_sys->p_matrix );
|
||||
|
||||
p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
|
||||
}
|
||||
|
||||
[p_vout->p_sys->o_window manage];
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* vout_Display: displays previously rendered output
|
||||
*****************************************************************************
|
||||
* This function sends the currently rendered image to the display.
|
||||
*****************************************************************************/
|
||||
static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
|
||||
{
|
||||
OSErr err;
|
||||
CodecFlags flags;
|
||||
|
||||
if( ( err = DecompressSequenceFrameWhen(
|
||||
p_vout->p_sys->i_seq,
|
||||
p_pic->p_sys->p_data,
|
||||
p_pic->p_sys->i_size,
|
||||
codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
|
||||
{
|
||||
msg_Warn( p_vout, "DecompressSequenceFrameWhen failed: %d", err );
|
||||
}
|
||||
else
|
||||
{
|
||||
QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* ControlVideo: control facility for the vout
|
||||
*****************************************************************************/
|
||||
static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
|
||||
{
|
||||
vlc_bool_t b_arg;
|
||||
|
||||
switch( i_query )
|
||||
{
|
||||
case VOUT_SET_STAY_ON_TOP:
|
||||
b_arg = va_arg( args, vlc_bool_t );
|
||||
[p_vout->p_sys->o_window setOnTop: b_arg];
|
||||
return VLC_SUCCESS;
|
||||
|
||||
case VOUT_CLOSE:
|
||||
case VOUT_REPARENT:
|
||||
default:
|
||||
return vout_vaControlDefault( p_vout, i_query, args );
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* CoToggleFullscreen: toggle fullscreen
|
||||
*****************************************************************************
|
||||
* Returns 0 on success, 1 otherwise
|
||||
*****************************************************************************/
|
||||
static int CoToggleFullscreen( vout_thread_t *p_vout )
|
||||
{
|
||||
NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
QTDestroySequence( p_vout );
|
||||
|
||||
if( !p_vout->b_fullscreen )
|
||||
{
|
||||
/* Save window size and position */
|
||||
p_vout->p_sys->s_frame.size =
|
||||
[[p_vout->p_sys->o_window contentView] frame].size;
|
||||
p_vout->p_sys->s_frame.origin =
|
||||
[p_vout->p_sys->o_window frame].origin;
|
||||
p_vout->p_sys->b_saved_frame = VLC_TRUE;
|
||||
}
|
||||
[p_vout->p_sys->o_window close];
|
||||
|
||||
p_vout->b_fullscreen = !p_vout->b_fullscreen;
|
||||
|
||||
if( p_vout->p_sys->b_saved_frame )
|
||||
{
|
||||
p_vout->p_sys->o_window = [[VLCWindow alloc]
|
||||
initWithVout: p_vout frame: &p_vout->p_sys->s_frame];
|
||||
}
|
||||
else
|
||||
{
|
||||
p_vout->p_sys->o_window = [[VLCWindow alloc]
|
||||
initWithVout: p_vout frame: nil];
|
||||
}
|
||||
|
||||
#define o_qtview p_vout->p_sys->o_qtview
|
||||
o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
|
||||
[p_vout->p_sys->o_window setContentView: o_qtview];
|
||||
[o_qtview autorelease];
|
||||
|
||||
/* Retrieve the QuickDraw port */
|
||||
[o_qtview lockFocus];
|
||||
p_vout->p_sys->p_qdport = [o_qtview qdPort];
|
||||
[o_qtview unlockFocus];
|
||||
#undef o_qtview
|
||||
|
||||
SetPort( p_vout->p_sys->p_qdport );
|
||||
QTScaleMatrix( p_vout );
|
||||
|
||||
if( QTCreateSequence( p_vout ) )
|
||||
{
|
||||
msg_Err( p_vout, "unable to create sequence" );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
[o_pool release];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* QTScaleMatrix: scale matrix
|
||||
*****************************************************************************/
|
||||
static void QTScaleMatrix( vout_thread_t *p_vout )
|
||||
{
|
||||
Rect s_rect;
|
||||
vlc_value_t val;
|
||||
unsigned int i_width, i_height;
|
||||
Fixed factor_x, factor_y;
|
||||
unsigned int i_offset_x = 0;
|
||||
unsigned int i_offset_y = 0;
|
||||
|
||||
GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
|
||||
|
||||
i_width = s_rect.right - s_rect.left;
|
||||
i_height = s_rect.bottom - s_rect.top;
|
||||
|
||||
var_Get( p_vout, "macosx-stretch", &val );
|
||||
if( val.b_bool )
|
||||
{
|
||||
factor_x = FixDiv( Long2Fix( i_width ),
|
||||
Long2Fix( p_vout->output.i_width ) );
|
||||
factor_y = FixDiv( Long2Fix( i_height ),
|
||||
Long2Fix( p_vout->output.i_height ) );
|
||||
|
||||
}
|
||||
else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
|
||||
{
|
||||
int i_adj_width = i_height * p_vout->output.i_aspect /
|
||||
VOUT_ASPECT_FACTOR;
|
||||
|
||||
factor_x = FixDiv( Long2Fix( i_adj_width ),
|
||||
Long2Fix( p_vout->output.i_width ) );
|
||||
factor_y = FixDiv( Long2Fix( i_height ),
|
||||
Long2Fix( p_vout->output.i_height ) );
|
||||
|
||||
i_offset_x = (i_width - i_adj_width) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
|
||||
p_vout->output.i_aspect;
|
||||
|
||||
factor_x = FixDiv( Long2Fix( i_width ),
|
||||
Long2Fix( p_vout->output.i_width ) );
|
||||
factor_y = FixDiv( Long2Fix( i_adj_height ),
|
||||
Long2Fix( p_vout->output.i_height ) );
|
||||
|
||||
i_offset_y = (i_height - i_adj_height) / 2;
|
||||
}
|
||||
|
||||
SetIdentityMatrix( p_vout->p_sys->p_matrix );
|
||||
|
||||
ScaleMatrix( p_vout->p_sys->p_matrix,
|
||||
factor_x, factor_y,
|
||||
Long2Fix(0), Long2Fix(0) );
|
||||
|
||||
TranslateMatrix( p_vout->p_sys->p_matrix,
|
||||
Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* QTCreateSequence: create a new sequence
|
||||
*****************************************************************************
|
||||
* Returns 0 on success, 1 otherwise
|
||||
*****************************************************************************/
|
||||
static int QTCreateSequence( vout_thread_t *p_vout )
|
||||
{
|
||||
OSErr err;
|
||||
ImageDescriptionPtr p_descr;
|
||||
|
||||
HLock( (Handle)p_vout->p_sys->h_img_descr );
|
||||
p_descr = *p_vout->p_sys->h_img_descr;
|
||||
|
||||
p_descr->idSize = sizeof(ImageDescription);
|
||||
p_descr->cType = p_vout->p_sys->i_codec;
|
||||
p_descr->version = 2;
|
||||
p_descr->revisionLevel = 0;
|
||||
p_descr->vendor = 'mpla';
|
||||
p_descr->width = p_vout->output.i_width;
|
||||
p_descr->height = p_vout->output.i_height;
|
||||
p_descr->hRes = Long2Fix(72);
|
||||
p_descr->vRes = Long2Fix(72);
|
||||
p_descr->spatialQuality = codecLosslessQuality;
|
||||
p_descr->frameCount = 1;
|
||||
p_descr->clutID = -1;
|
||||
p_descr->dataSize = 0;
|
||||
p_descr->depth = 24;
|
||||
|
||||
HUnlock( (Handle)p_vout->p_sys->h_img_descr );
|
||||
|
||||
if( ( err = DecompressSequenceBeginS(
|
||||
&p_vout->p_sys->i_seq,
|
||||
p_vout->p_sys->h_img_descr,
|
||||
NULL,
|
||||
(p_descr->width * p_descr->height * 16) / 8,
|
||||
p_vout->p_sys->p_qdport,
|
||||
NULL, NULL,
|
||||
p_vout->p_sys->p_matrix,
|
||||
srcCopy, NULL,
|
||||
codecFlagUseImageBuffer,
|
||||
codecLosslessQuality,
|
||||
bestSpeedCodec ) ) )
|
||||
{
|
||||
msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* QTDestroySequence: destroy sequence
|
||||
*****************************************************************************/
|
||||
static void QTDestroySequence( vout_thread_t *p_vout )
|
||||
{
|
||||
CDSequenceEnd( p_vout->p_sys->i_seq );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* QTNewPicture: allocate a picture
|
||||
*****************************************************************************
|
||||
* Returns 0 on success, 1 otherwise
|
||||
*****************************************************************************/
|
||||
static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
|
||||
{
|
||||
/* We know the chroma, allocate a buffer which will be used
|
||||
* directly by the decoder */
|
||||
p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
|
||||
|
||||
if( p_pic->p_sys == NULL )
|
||||
{
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
|
||||
p_vout->output.i_width, p_vout->output.i_height,
|
||||
p_vout->output.i_aspect );
|
||||
|
||||
switch( p_vout->output.i_chroma )
|
||||
{
|
||||
case VLC_FOURCC('Y','U','Y','2'):
|
||||
p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
|
||||
|
||||
/* Allocate the memory buffer */
|
||||
p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
|
||||
16, p_pic->p_sys->i_size );
|
||||
|
||||
p_pic->p[0].p_pixels = p_pic->p_data;
|
||||
p_pic->p[0].i_lines = p_vout->output.i_height;
|
||||
p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
|
||||
p_pic->p[0].i_pixel_pitch = 1;
|
||||
p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
|
||||
p_pic->i_planes = 1;
|
||||
|
||||
p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unknown chroma, tell the guy to get lost */
|
||||
free( p_pic->p_sys );
|
||||
msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
|
||||
p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
|
||||
p_pic->i_planes = 0;
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* QTFreePicture: destroy a picture allocated with QTNewPicture
|
||||
*****************************************************************************/
|
||||
static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
|
||||
{
|
||||
switch( p_vout->output.i_chroma )
|
||||
{
|
||||
case VLC_FOURCC('I','4','2','0'):
|
||||
free( p_pic->p_data_orig );
|
||||
break;
|
||||
}
|
||||
|
||||
free( p_pic->p_sys );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* VLCQTView implementation
|
||||
*****************************************************************************/
|
||||
@implementation VLCQTView
|
||||
|
||||
- (id) initWithVout:(vout_thread_t *)_p_vout
|
||||
{
|
||||
p_vout = _p_vout;
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)rect
|
||||
{
|
||||
[[NSColor blackColor] set];
|
||||
NSRectFill( rect );
|
||||
[super drawRect: rect];
|
||||
|
||||
p_vout->i_changes |= VOUT_SIZE_CHANGE;
|
||||
}
|
||||
|
||||
@end
|
@ -87,6 +87,7 @@ static int Control ( vout_thread_t *, int, va_list );
|
||||
|
||||
static inline int GetAlignedSize( int );
|
||||
|
||||
static int InitTextures( vout_thread_t * );
|
||||
static int SendEvents( vlc_object_t *, char const *,
|
||||
vlc_value_t, vlc_value_t, void * );
|
||||
|
||||
@ -99,7 +100,11 @@ static int SendEvents( vlc_object_t *, char const *,
|
||||
|
||||
vlc_module_begin();
|
||||
set_description( _("OpenGL video output") );
|
||||
#ifdef SYS_DARWIN
|
||||
set_capability( "video output", 200 );
|
||||
#else
|
||||
set_capability( "video output", 20 );
|
||||
#endif
|
||||
add_shortcut( "opengl" );
|
||||
set_callbacks( CreateVout, DestroyVout );
|
||||
|
||||
@ -179,7 +184,7 @@ static int CreateVout( vlc_object_t *p_this )
|
||||
module_Need( p_sys->p_vout, "opengl provider", NULL, 0 );
|
||||
if( p_sys->p_vout->p_module == NULL )
|
||||
{
|
||||
msg_Err( p_vout, "No OpenGL provider found" );
|
||||
msg_Warn( p_vout, "No OpenGL provider found" );
|
||||
vlc_object_detach( p_sys->p_vout );
|
||||
vlc_object_destroy( p_sys->p_vout );
|
||||
return VLC_ENOOBJ;
|
||||
@ -192,6 +197,8 @@ static int CreateVout( vlc_object_t *p_this )
|
||||
p_vout->pf_display = DisplayVideo;
|
||||
p_vout->pf_control = Control;
|
||||
|
||||
var_Create( p_sys->p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
|
||||
|
||||
/* Forward events from the opengl provider */
|
||||
var_AddCallback( p_sys->p_vout, "mouse-x", SendEvents, p_vout );
|
||||
var_AddCallback( p_sys->p_vout, "mouse-y", SendEvents, p_vout );
|
||||
@ -207,7 +214,7 @@ static int CreateVout( vlc_object_t *p_this )
|
||||
static int Init( vout_thread_t *p_vout )
|
||||
{
|
||||
vout_sys_t *p_sys = p_vout->p_sys;
|
||||
int i_pixel_pitch, i_index;
|
||||
int i_pixel_pitch;
|
||||
vlc_value_t val;
|
||||
|
||||
p_sys->p_vout->pf_init( p_sys->p_vout );
|
||||
@ -281,45 +288,7 @@ static int Init( vout_thread_t *p_vout )
|
||||
|
||||
I_OUTPUTPICTURES = 1;
|
||||
|
||||
glGenTextures( 2, p_sys->p_textures );
|
||||
|
||||
for( i_index = 0; i_index < 2; i_index++ )
|
||||
{
|
||||
glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_index] );
|
||||
|
||||
/* Set the texture parameters */
|
||||
glTexParameterf( VLCGL_TARGET, GL_TEXTURE_PRIORITY, 1.0 );
|
||||
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP );
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP );
|
||||
|
||||
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
|
||||
#ifdef SYS_DARWIN
|
||||
/* 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 );
|
||||
|
||||
#if 0
|
||||
/* Use VRAM texturing */
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
|
||||
GL_STORAGE_CACHED_APPLE );
|
||||
#else
|
||||
/* Use AGP texturing */
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
|
||||
GL_STORAGE_SHARED_APPLE );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Call glTexImage2D only once, and use glTexSubImage2D later */
|
||||
glTexImage2D( VLCGL_TARGET, 0, 3, p_sys->i_tex_width,
|
||||
p_sys->i_tex_height, 0, VLCGL_FORMAT, VLCGL_TYPE,
|
||||
p_sys->pp_buffer[i_index] );
|
||||
}
|
||||
InitTextures( p_vout );
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
@ -410,7 +379,49 @@ static void DestroyVout( vlc_object_t *p_this )
|
||||
static int Manage( vout_thread_t *p_vout )
|
||||
{
|
||||
vout_sys_t *p_sys = p_vout->p_sys;
|
||||
return p_sys->p_vout->pf_manage( p_sys->p_vout );
|
||||
int i_ret, i_fullscreen_change;
|
||||
|
||||
i_fullscreen_change = ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE );
|
||||
|
||||
p_sys->p_vout->i_changes = p_vout->i_changes;
|
||||
i_ret = p_sys->p_vout->pf_manage( p_sys->p_vout );
|
||||
p_vout->i_changes = p_sys->p_vout->i_changes;
|
||||
|
||||
#ifdef SYS_DARWIN
|
||||
/* On OS X, we create the window and the GL view when entering
|
||||
fullscreen - the textures have to be inited again */
|
||||
if( i_fullscreen_change )
|
||||
{
|
||||
InitTextures( p_vout );
|
||||
|
||||
switch( p_sys->i_effect )
|
||||
{
|
||||
case OPENGL_EFFECT_CUBE:
|
||||
glEnable( GL_CULL_FACE );
|
||||
break;
|
||||
|
||||
case OPENGL_EFFECT_TRANSPARENT_CUBE:
|
||||
glDisable( GL_DEPTH_TEST );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
|
||||
break;
|
||||
}
|
||||
|
||||
if( p_sys->i_effect & ( OPENGL_EFFECT_CUBE |
|
||||
OPENGL_EFFECT_TRANSPARENT_CUBE ) )
|
||||
{
|
||||
/* Set the perpective */
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
glTranslatef( 0.0, 0.0, - 5.0 );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return i_ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -563,6 +574,55 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args )
|
||||
return vout_vaControlDefault( p_vout, i_query, args );
|
||||
}
|
||||
|
||||
static int InitTextures( vout_thread_t *p_vout )
|
||||
{
|
||||
vout_sys_t *p_sys = p_vout->p_sys;
|
||||
int i_index;
|
||||
|
||||
glDeleteTextures( 2, p_sys->p_textures );
|
||||
glGenTextures( 2, p_sys->p_textures );
|
||||
|
||||
for( i_index = 0; i_index < 2; i_index++ )
|
||||
{
|
||||
glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_index] );
|
||||
|
||||
/* Set the texture parameters */
|
||||
glTexParameterf( VLCGL_TARGET, GL_TEXTURE_PRIORITY, 1.0 );
|
||||
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP );
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP );
|
||||
|
||||
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
|
||||
#ifdef SYS_DARWIN
|
||||
/* 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 );
|
||||
|
||||
#if 0
|
||||
/* Use VRAM texturing */
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
|
||||
GL_STORAGE_CACHED_APPLE );
|
||||
#else
|
||||
/* Use AGP texturing */
|
||||
glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
|
||||
GL_STORAGE_SHARED_APPLE );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Call glTexImage2D only once, and use glTexSubImage2D later */
|
||||
glTexImage2D( VLCGL_TARGET, 0, 3, p_sys->i_tex_width,
|
||||
p_sys->i_tex_height, 0, VLCGL_FORMAT, VLCGL_TYPE,
|
||||
p_sys->pp_buffer[i_index] );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* SendEvents: forward mouse and keyboard events to the parent p_vout
|
||||
*****************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user