X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fmacosx%2Fvoutqt.m;h=fcbd6785300d5427a486878d095c4070585c1f43;hb=6ee1e193fd896ab9a4729fde14f009d9ce629815;hp=49ce4ead395dbbe3c826363166d9be2023c2a742;hpb=d4ac5770da4685f9461a6ec0a8c3a9d75b02d180;p=vlc diff --git a/modules/gui/macosx/voutqt.m b/modules/gui/macosx/voutqt.m index 49ce4ead39..fcbd678530 100644 --- a/modules/gui/macosx/voutqt.m +++ b/modules/gui/macosx/voutqt.m @@ -1,20 +1,21 @@ /***************************************************************************** * 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-2004 the VideoLAN team + * $Id$ * * Authors: Colin Delacroix * Florian G. Pflug * Jon Lech Johansen * Derk-Jan Hartman * Eric Petit + * Benjamin Pracht * * 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 @@ -22,7 +23,7 @@ * * 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. *****************************************************************************/ /***************************************************************************** @@ -45,22 +46,23 @@ /***************************************************************************** * VLCView interface *****************************************************************************/ -@interface VLCQTView : NSQuickDrawView +@interface VLCQTView : NSQuickDrawView { 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; + vlc_bool_t b_cpu_has_simd; /* does CPU supports Altivec, MMX, etc... */ NSRect s_frame; CodecType i_codec; @@ -69,12 +71,22 @@ struct vout_sys_t 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 */ + vlc_bool_t b_embedded; + RgnHandle clip_mask; }; struct picture_sys_t { void *p_data; unsigned int i_size; + + /* When using I420 output */ + PlanarPixmapInfoYUV420 pixmap_i420; }; /***************************************************************************** @@ -88,6 +100,9 @@ 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 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 * ); @@ -100,11 +115,10 @@ static void QTFreePicture ( vout_thread_t *, picture_t * ); * 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; + vlc_value_t value_drawable; p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); if( p_vout->p_sys == NULL ) @@ -115,22 +129,7 @@ int E_(OpenVideoQT) ( vlc_object_t *p_this ) 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; @@ -139,47 +138,65 @@ int E_(OpenVideoQT) ( vlc_object_t *p_this ) 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 = VLC_TRUE; + else + p_vout->p_sys->b_embedded = VLC_FALSE; - 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 ); - + 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 lock in the p_libvlc object */ + vlc_mutex_lock( &p_vout->p_libvlc->quicktime_lock ); /* 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_vout->p_libvlc->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; + 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 ) @@ -187,67 +204,26 @@ int E_(OpenVideoQT) ( vlc_object_t *p_this ) 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; @@ -258,11 +234,11 @@ int E_(OpenVideoQT) ( vlc_object_t *p_this ) *****************************************************************************/ void E_(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(); @@ -290,12 +266,32 @@ static int InitVideo ( 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 ); + 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 ); } @@ -338,6 +334,12 @@ static void EndVideo( vout_thread_t *p_vout ) 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; ) { @@ -356,7 +358,7 @@ static int ManageVideo( vout_thread_t *p_vout ) { if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) { - if( CoToggleFullscreen( p_vout ) ) + if( CoToggleFullscreen( p_vout ) ) { return( 1 ); } @@ -364,17 +366,46 @@ static int ManageVideo( vout_thread_t *p_vout ) 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 ); } @@ -387,18 +418,34 @@ 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 ) ) + 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); } } @@ -413,7 +460,7 @@ static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args ) { case VOUT_SET_STAY_ON_TOP: b_arg = va_arg( args, vlc_bool_t ); - [p_vout->p_sys->o_window setOnTop: b_arg]; + [p_vout->p_sys->o_vout_view setOnTop: b_arg]; return VLC_SUCCESS; case VOUT_CLOSE: @@ -424,7 +471,7 @@ static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args ) } /***************************************************************************** - * CoToggleFullscreen: toggle fullscreen + * CoToggleFullscreen: toggle fullscreen ***************************************************************************** * Returns 0 on success, 1 otherwise *****************************************************************************/ @@ -432,72 +479,95 @@ 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]; - } + 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 ) @@ -506,45 +576,52 @@ static void QTScaleMatrix( vout_thread_t *p_vout ) 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 *****************************************************************************/ @@ -573,7 +650,7 @@ static int QTCreateSequence( vout_thread_t *p_vout ) 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, @@ -581,12 +658,12 @@ static int QTCreateSequence( vout_thread_t *p_vout ) 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 ); } @@ -594,7 +671,7 @@ static int QTCreateSequence( vout_thread_t *p_vout ) } /***************************************************************************** - * QTDestroySequence: destroy sequence + * QTDestroySequence: destroy sequence *****************************************************************************/ static void QTDestroySequence( vout_thread_t *p_vout ) { @@ -616,7 +693,7 @@ static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic ) { 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 ); @@ -632,6 +709,7 @@ static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic ) 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; @@ -640,14 +718,63 @@ static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic ) 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 = vlc_memalign( &p_pic->p_data_orig, + 16, p_vout->output.i_width * p_vout->output.i_height * 3 / 2 ); + + /* 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 ); @@ -673,6 +800,76 @@ static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic ) *****************************************************************************/ @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 = VLC_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;