/*****************************************************************************
* vout.m: MacOS X video output module
*****************************************************************************
- * Copyright (C) 2001-2003 VideoLAN
- * $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
+ * Copyright (C) 2001-2007 the VideoLAN team
+ * $Id$
*
* 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>
+ * Benjamin Pracht <bigben 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
* 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
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
-#include <errno.h> /* ENOMEM */
#include <stdlib.h> /* free() */
-#include <string.h> /* strerror() */
+#include <string.h>
+#include <assert.h>
#include <QuickTime/QuickTime.h>
/*****************************************************************************
* VLCView interface
*****************************************************************************/
-@interface VLCQTView : NSQuickDrawView
+@interface VLCQTView : NSQuickDrawView <VLCVoutViewResetting>
{
vout_thread_t * p_vout;
}
++ (void)resetVout: (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;
+ VLCVoutView * o_vout_view;
- vlc_bool_t b_saved_frame;
+ bool b_saved_frame;
+ bool b_cpu_has_simd; /* does CPU supports Altivec, MMX, etc... */
NSRect s_frame;
CodecType i_codec;
MatrixRecordPtr p_matrix;
DecompressorComponent img_dc;
ImageDescriptionHandle h_img_descr;
+
+ /* video geometry in port */
+ int i_origx, i_origy;
+ int i_width, i_height;
+ /* Mozilla plugin-related variables */
+ bool b_embedded;
+ RgnHandle clip_mask;
};
struct picture_sys_t
{
void *p_data;
unsigned int i_size;
+
+ /* When using I420 output */
+ PlanarPixmapInfoYUV420 pixmap_i420;
};
/*****************************************************************************
static int ControlVideo ( vout_thread_t *, int, va_list );
static int CoToggleFullscreen( vout_thread_t *p_vout );
+static int DrawableRedraw( vlc_object_t *p_this, const char *psz_name,
+ vlc_value_t oval, vlc_value_t nval, void *param);
+static void UpdateEmbeddedGeometry( vout_thread_t *p_vout );
static void QTScaleMatrix ( vout_thread_t * );
static int QTCreateSequence ( vout_thread_t * );
static void QTDestroySequence ( vout_thread_t * );
*****************************************************************************
* This function allocates and initializes a MacOS X vout method.
*****************************************************************************/
-int E_(OpenVideoQT) ( vlc_object_t *p_this )
-{
+int 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;
+ vlc_value_t value_drawable;
p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
if( p_vout->p_sys == NULL )
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->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
p_vout->pf_init = InitVideo;
p_vout->pf_end = EndVideo;
p_vout->pf_display = DisplayVideo;
p_vout->pf_control = ControlVideo;
- p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
+ /* Are we embedded? If so, the drawable value will be a pointer to a
+ * CGrafPtr that we're expected to use */
+ var_Get( p_vout->p_libvlc, "drawable", &value_drawable );
+ if( value_drawable.i_int != 0 )
+ p_vout->p_sys->b_embedded = true;
+ else
+ p_vout->p_sys->b_embedded = false;
- 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 );
-
+ p_vout->p_sys->b_cpu_has_simd =
+ vlc_CPU() & (CPU_CAPABILITY_ALTIVEC|CPU_CAPABILITY_MMXEXT);
+ msg_Dbg( p_vout, "we do%s have SIMD enabled CPU", p_vout->p_sys->b_cpu_has_simd ? "" : "n't" );
+
/* Initialize QuickTime */
- p_vout->p_sys->h_img_descr =
+ 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 );
+ msg_Err( p_vout, "QT initialization failed: 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 );
+ /* Damn QT isn't thread safe, so keep a process-wide lock */
+ vlc_mutex_t *p_qtlock = var_AcquireMutex( "quicktime_mutex" );
/* Can we find the right chroma ? */
- err = FindCodec( kComponentVideoUnsigned, bestSpeedCodec,
+ if( p_vout->p_sys->b_cpu_has_simd )
+ {
+ err = FindCodec( kYUVSPixelFormat, bestSpeedCodec,
nil, &p_vout->p_sys->img_dc );
-
- vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
-
+ }
+ else
+ {
+ err = FindCodec( kYUV420CodecType, bestSpeedCodec,
+ nil, &p_vout->p_sys->img_dc );
+ }
+ vlc_mutex_unlock( p_qtlock );
+
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;
+ if( p_vout->p_sys->b_cpu_has_simd )
+ {
+ p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
+ p_vout->p_sys->i_codec = kYUVSPixelFormat;
+ }
+ else
+ {
+ 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" );
+ msg_Err( p_vout, "QT doesn't support any appropriate chroma" );
}
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;
+ 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 )
+ if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
{
- 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];
+ /* Spawn window */
+#define o_qtview p_vout->p_sys->o_qtview
+ o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
+ [o_qtview autorelease];
- while( (o_screen = [o_enumerator nextObject]) != NULL )
+ p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
+ subView: o_qtview frame: nil];
+ if( !p_vout->p_sys->o_vout_view )
{
- 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++;
+ return VLC_EGENERIC;
}
-
- var_AddCallback( p_vout, "video-device", vout_VarCallback,
- NULL );
-
- val2.b_bool = VLC_TRUE;
- var_Set( p_vout, "intf-change", val2 );
+ [o_qtview lockFocus];
+ p_vout->p_sys->p_qdport = [o_qtview qdPort];
+ [o_qtview unlockFocus];
}
-
- /* 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 )
+void CloseVideoQT ( vlc_object_t *p_this )
{
- NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
+ 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];
+ if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
+ [p_vout->p_sys->o_vout_view closeVout];
/* Clean Up Quicktime environment */
ExitMovies();
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 );
+ if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
+ {
+ Rect s_rect;
+ p_vout->p_sys->clip_mask = NULL;
+ GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
+ p_vout->p_sys->i_origx = s_rect.left;
+ p_vout->p_sys->i_origy = s_rect.top;
+ p_vout->p_sys->i_width = s_rect.right - s_rect.left;
+ p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
+ }
+ else
+ {
+ /* As we are embedded (e.g. running as a Mozilla plugin), use the pointer
+ * stored in the "drawable" value as the CGrafPtr for the QuickDraw
+ * graphics port */
+ /* Create the clipping mask */
+ p_vout->p_sys->clip_mask = NewRgn();
+ UpdateEmbeddedGeometry(p_vout);
+ var_AddCallback(p_vout->p_libvlc, "drawableredraw", DrawableRedraw, p_vout);
+ }
+
QTScaleMatrix( p_vout );
if( QTCreateSequence( p_vout ) )
{
- msg_Err( p_vout, "unable to create sequence" );
+ msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
return( 1 );
}
QTDestroySequence( p_vout );
+ if( !p_vout->b_fullscreen && p_vout->p_sys->b_embedded )
+ {
+ var_DelCallback(p_vout->p_libvlc, "drawableredraw", DrawableRedraw, p_vout);
+ DisposeRgn(p_vout->p_sys->clip_mask);
+ }
+
/* Free the direct buffers we allocated */
for( i_index = I_OUTPUTPICTURES; i_index; )
{
{
if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
{
- if( CoToggleFullscreen( p_vout ) )
+ if( CoToggleFullscreen( p_vout ) )
{
return( 1 );
}
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
}
- if( p_vout->i_changes & VOUT_SIZE_CHANGE )
+ if( p_vout->i_changes & VOUT_SIZE_CHANGE )
+ {
+ if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
+ {
+ /* get the geometry from NSQuickDrawView */
+ Rect s_rect;
+ GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
+ p_vout->p_sys->i_origx = s_rect.left;
+ p_vout->p_sys->i_origy = s_rect.top;
+ p_vout->p_sys->i_width = s_rect.right - s_rect.left;
+ p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
+ }
+ else
+ {
+ /* As we're embedded, get the geometry from Mozilla/Safari NPWindow object */
+ UpdateEmbeddedGeometry( p_vout );
+ SetDSequenceMask(p_vout->p_sys->i_seq,
+ p_vout->p_sys->clip_mask);
+ }
+ }
+
+ if( p_vout->i_changes & VOUT_SIZE_CHANGE ||
+ p_vout->i_changes & VOUT_ASPECT_CHANGE )
{
QTScaleMatrix( p_vout );
- SetDSequenceMatrix( p_vout->p_sys->i_seq,
+ SetDSequenceMatrix( p_vout->p_sys->i_seq,
p_vout->p_sys->p_matrix );
-
+ }
+ if( p_vout->i_changes & VOUT_SIZE_CHANGE )
+ {
p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
}
+ if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
+ {
+ p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
+ }
+
+ // can be nil
+ [p_vout->p_sys->o_vout_view manage];
- [p_vout->p_sys->o_window manage];
-
return( 0 );
}
{
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 ) )
+ if( (NULL == p_vout->p_sys->clip_mask) || !EmptyRgn(p_vout->p_sys->clip_mask) )
+ {
+ //CGrafPtr oldPort;
+ //Rect oldBounds;
+
+ /* since there is not way to lock a QuickDraw port for exclusive use
+ there is a potential problem that the frame will be displayed
+ in the wrong place if other embedded plugins redraws as the port
+ origin may be changed */
+ //GetPort(&oldPort);
+ //GetPortBounds(p_vout->p_sys->p_qdport, &oldBounds);
+ SetPort(p_vout->p_sys->p_qdport);
+ SetOrigin(p_vout->p_sys->i_origx, p_vout->p_sys->i_origy);
+ 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 );
+ QDFlushPortBuffer( p_vout->p_sys->p_qdport, p_vout->p_sys->clip_mask );
+ //QDFlushPortBuffer( p_vout->p_sys->p_qdport, NULL );
}
else
{
- QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
+ msg_Warn( p_vout, "QT failed to display the frame sequence: %d", err );
+ }
+ //SetPortBounds(p_vout->p_sys->p_qdport, &oldBounds);
+ //SetPort(oldPort);
}
}
*****************************************************************************/
static int ControlVideo( 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 );
- [p_vout->p_sys->o_window setOnTop: b_arg];
+ b_arg = (bool) va_arg( args, int );
+ [p_vout->p_sys->o_vout_view setOnTop: b_arg];
return VLC_SUCCESS;
case VOUT_CLOSE:
}
/*****************************************************************************
- * CoToggleFullscreen: toggle fullscreen
+ * CoToggleFullscreen: toggle fullscreen
*****************************************************************************
* Returns 0 on success, 1 otherwise
*****************************************************************************/
{
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];
- }
+ if( p_vout->b_fullscreen )
+ [p_vout->p_sys->o_vout_view enterFullscreen];
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];
+ [p_vout->p_sys->o_vout_view leaveFullscreen];
- /* Retrieve the QuickDraw port */
- [o_qtview lockFocus];
- p_vout->p_sys->p_qdport = [o_qtview qdPort];
- [o_qtview unlockFocus];
-#undef o_qtview
+ [o_pool release];
+ return 0;
+}
- SetPort( p_vout->p_sys->p_qdport );
- QTScaleMatrix( p_vout );
+/* If we're embedded, the application is expected to indicate a
+ * window change (move/resize/etc) via the "drawableredraw" value.
+ * If that's the case, set the VOUT_SIZE_CHANGE flag so we do
+ * actually handle the window change. */
- if( QTCreateSequence( p_vout ) )
+static int DrawableRedraw( vlc_object_t *p_this, const char *psz_name,
+ vlc_value_t oval, vlc_value_t nval, void *param)
+{
+ /* ignore changes until we are ready for them */
+ if( (oval.i_int != nval.i_int) && (nval.i_int == 1) )
{
- msg_Err( p_vout, "unable to create sequence" );
- return( 1 );
- }
+ vout_thread_t *p_vout = (vout_thread_t *)param;
+ /* prevent QT from rendering any more video until we have updated
+ the geometry */
+ SetEmptyRgn(p_vout->p_sys->clip_mask);
+ SetDSequenceMask(p_vout->p_sys->i_seq,
+ p_vout->p_sys->clip_mask);
- [o_pool release];
- return 0;
+ p_vout->i_changes |= VOUT_SIZE_CHANGE;
+ }
+ return VLC_SUCCESS;
+}
+
+/* Embedded video get their drawing region from the host application
+ * by the drawable values here. Read those variables, and store them
+ * in the p_vout->p_sys structure so that other functions (such as
+ * DisplayVideo and ManageVideo) can use them later. */
+
+static void UpdateEmbeddedGeometry( vout_thread_t *p_vout )
+{
+ vlc_value_t val;
+ vlc_value_t valt, vall, valb, valr, valx, valy, valw, valh,
+ valportx, valporty;
+
+ var_Get( p_vout->p_libvlc, "drawable", &val );
+ var_Get( p_vout->p_libvlc, "drawablet", &valt );
+ var_Get( p_vout->p_libvlc, "drawablel", &vall );
+ var_Get( p_vout->p_libvlc, "drawableb", &valb );
+ var_Get( p_vout->p_libvlc, "drawabler", &valr );
+ var_Get( p_vout->p_libvlc, "drawablex", &valx );
+ var_Get( p_vout->p_libvlc, "drawabley", &valy );
+ var_Get( p_vout->p_libvlc, "drawablew", &valw );
+ var_Get( p_vout->p_libvlc, "drawableh", &valh );
+ var_Get( p_vout->p_libvlc, "drawableportx", &valportx );
+ var_Get( p_vout->p_libvlc, "drawableporty", &valporty );
+
+ /* portx, porty contains values for SetOrigin() function
+ which isn't used, instead use QT Translate matrix */
+ p_vout->p_sys->i_origx = valportx.i_int;
+ p_vout->p_sys->i_origy = valporty.i_int;
+ p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
+ p_vout->p_sys->i_width = valw.i_int;
+ p_vout->p_sys->i_height = valh.i_int;
+
+ /* update video clipping mask */
+ /*SetRectRgn( p_vout->p_sys->clip_mask , vall.i_int ,
+ valt.i_int, valr.i_int, valb.i_int );*/
+ SetRectRgn( p_vout->p_sys->clip_mask , vall.i_int + valportx.i_int ,
+ valt.i_int + valporty.i_int , valr.i_int + valportx.i_int ,
+ valb.i_int + valporty.i_int );
+
+ /* reset drawableredraw variable indicating we are ready
+ to take changes in video geometry */
+ val.i_int=0;
+ var_Set( p_vout->p_libvlc, "drawableredraw", val );
}
/*****************************************************************************
- * QTScaleMatrix: scale matrix
+ * 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;
+ int i_width = p_vout->p_sys->i_width;
+ int i_height = p_vout->p_sys->i_height;
var_Get( p_vout, "macosx-stretch", &val );
if( val.b_bool )
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 )
+ else if( i_height * p_vout->fmt_in.i_visible_width *
+ p_vout->fmt_in.i_sar_num <
+ i_width * p_vout->fmt_in.i_visible_height *
+ p_vout->fmt_in.i_sar_den )
{
- int i_adj_width = i_height * p_vout->output.i_aspect /
- VOUT_ASPECT_FACTOR;
+ int i_adj_width = i_height * p_vout->fmt_in.i_visible_width *
+ p_vout->fmt_in.i_sar_num /
+ ( p_vout->fmt_in.i_sar_den *
+ p_vout->fmt_in.i_visible_height );
factor_x = FixDiv( Long2Fix( i_adj_width ),
- Long2Fix( p_vout->output.i_width ) );
+ Long2Fix( p_vout->fmt_in.i_visible_width ) );
factor_y = FixDiv( Long2Fix( i_height ),
- Long2Fix( p_vout->output.i_height ) );
+ Long2Fix( p_vout->fmt_in.i_visible_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;
+ int i_adj_height = i_width * p_vout->fmt_in.i_visible_height *
+ p_vout->fmt_in.i_sar_den /
+ ( p_vout->fmt_in.i_sar_num *
+ p_vout->fmt_in.i_visible_width );
factor_x = FixDiv( Long2Fix( i_width ),
- Long2Fix( p_vout->output.i_width ) );
+ Long2Fix( p_vout->fmt_in.i_visible_width ) );
factor_y = FixDiv( Long2Fix( i_adj_height ),
- Long2Fix( p_vout->output.i_height ) );
+ Long2Fix( p_vout->fmt_in.i_visible_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
+ * QTCreateSequence: create a new sequence
*****************************************************************************
* Returns 0 on success, 1 otherwise
*****************************************************************************/
HUnlock( (Handle)p_vout->p_sys->h_img_descr );
- if( ( err = DecompressSequenceBeginS(
+ if( ( err = DecompressSequenceBeginS(
&p_vout->p_sys->i_seq,
p_vout->p_sys->h_img_descr,
NULL,
p_vout->p_sys->p_qdport,
NULL, NULL,
p_vout->p_sys->p_matrix,
- srcCopy, NULL,
+ srcCopy, p_vout->p_sys->clip_mask,
codecFlagUseImageBuffer,
codecLosslessQuality,
bestSpeedCodec ) ) )
{
- msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
+ msg_Err( p_vout, "Failed to initialize QT: DecompressSequenceBeginS failed: %d", err );
return( 1 );
}
}
/*****************************************************************************
- * QTDestroySequence: destroy sequence
+ * QTDestroySequence: destroy sequence
*****************************************************************************/
static void QTDestroySequence( vout_thread_t *p_vout )
{
{
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 );
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_data_orig = p_pic->p_data = malloc( p_pic->p_sys->i_size );
+ /* Memory is always 16-bytes aligned on OSX, so it does not
+ * posix_memalign() */
+ assert( (((uintptr_t)p_pic->p_data) % 16) == 0 );
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_visible_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->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 );
+
+ case VLC_FOURCC('I','4','2','0'):
+ p_pic->p_sys->p_data = (void *)&p_pic->p_sys->pixmap_i420;
+ p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
+
+ /* Allocate the memory buffer */
+ p_pic->p_data_orig = p_pic->p_data = malloc( p_vout->output.i_width
+ * p_vout->output.i_height * 3 / 2 );
+ /* Memory is always 16-bytes aligned on OSX, so it does not
+ * posix_memalign() */
+ assert( (((uintptr_t)p_pic->p_data) % 16) == 0 );
+
+ /* Y buffer */
+ p_pic->Y_PIXELS = p_pic->p_data;
+ p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
+ p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
+ p_pic->p[Y_PLANE].i_pitch = p_vout->output.i_width;
+ p_pic->p[Y_PLANE].i_pixel_pitch = 1;
+ p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width;
+
+ /* U buffer */
+ p_pic->U_PIXELS = p_pic->Y_PIXELS + p_vout->output.i_height * p_vout->output.i_width;
+ p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
+ p_pic->p[U_PLANE].i_pitch = p_vout->output.i_width / 2;
+ p_pic->p[U_PLANE].i_pixel_pitch = 1;
+ p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
+
+ /* V buffer */
+ p_pic->V_PIXELS = p_pic->U_PIXELS + p_vout->output.i_height * p_vout->output.i_width / 4;
+ p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
+ p_pic->p[V_PLANE].i_pitch = p_vout->output.i_width / 2;
+ p_pic->p[V_PLANE].i_pixel_pitch = 1;
+ p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
+
+ /* We allocated 3 planes */
+ p_pic->i_planes = 3;
+
+#define P p_pic->p_sys->pixmap_i420
+ P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
+ - p_pic->p_sys->p_data;
+ P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
+ - p_pic->p_sys->p_data;
+ P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
+ - p_pic->p_sys->p_data;
+
+ P.componentInfoY.rowBytes = p_vout->output.i_width;
+ P.componentInfoCb.rowBytes = p_vout->output.i_width / 2;
+ P.componentInfoCr.rowBytes = p_vout->output.i_width / 2;
+#undef P
+ break;
+
+ default:
+ /* Unknown chroma, tell the guy to get lost */
+ free( p_pic->p_sys );
+ msg_Err( p_vout, "Unknown chroma format 0x%.8x (%4.4s)",
+ p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
+ p_pic->i_planes = 0;
+ return( -1 );
}
return( 0 );
*****************************************************************************/
@implementation VLCQTView
+/* This function will reset the o_vout_view. It's useful to go fullscreen. */
++ (void)resetVout: (vout_thread_t *)p_vout
+{
+ QTDestroySequence( p_vout );
+
+ if( p_vout->b_fullscreen )
+ {
+ if( !p_vout->p_sys->b_embedded )
+ {
+ /* 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 = true;
+ }
+ else
+ {
+ var_DelCallback(p_vout->p_libvlc, "drawableredraw", DrawableRedraw, p_vout);
+ DisposeRgn(p_vout->p_sys->clip_mask);
+ }
+ }
+
+ if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
+ {
+ Rect s_rect;
+ p_vout->p_sys->clip_mask = NULL;
+#define o_qtview p_vout->p_sys->o_qtview
+ o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
+ [o_qtview autorelease];
+
+ if( p_vout->p_sys->b_saved_frame )
+ {
+ p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
+ subView: o_qtview
+ frame: &p_vout->p_sys->s_frame];
+ }
+ else
+ {
+ p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
+ subView: o_qtview frame: nil];
+ }
+
+ /* Retrieve the QuickDraw port */
+ [o_qtview lockFocus];
+ p_vout->p_sys->p_qdport = [o_qtview qdPort];
+ [o_qtview unlockFocus];
+#undef o_qtview
+ GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
+ p_vout->p_sys->i_origx = s_rect.left;
+ p_vout->p_sys->i_origy = s_rect.top;
+ p_vout->p_sys->i_width = s_rect.right - s_rect.left;
+ p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
+ }
+ else
+ {
+ /* Create the clipping mask */
+ p_vout->p_sys->clip_mask = NewRgn();
+ UpdateEmbeddedGeometry(p_vout);
+ var_AddCallback(p_vout->p_libvlc, "drawableredraw", DrawableRedraw, p_vout);
+ }
+ QTScaleMatrix( p_vout );
+
+ if( QTCreateSequence( p_vout ) )
+ {
+ msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
+ return;
+ }
+}
+
- (id) initWithVout:(vout_thread_t *)_p_vout
{
p_vout = _p_vout;