Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

voutqt.m

00001 /*****************************************************************************
00002  * vout.m: MacOS X video output module
00003  *****************************************************************************
00004  * Copyright (C) 2001-2004 the VideoLAN team
00005  * $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
00006  *
00007  * Authors: Colin Delacroix <[email protected]>
00008  *          Florian G. Pflug <[email protected]>
00009  *          Jon Lech Johansen <[email protected]>
00010  *          Derk-Jan Hartman <hartman at videolan dot org>
00011  *          Eric Petit <[email protected]>
00012  *
00013  * This program is free software; you can redistribute it and/or modify
00014  * it under the terms of the GNU General Public License as published by
00015  * the Free Software Foundation; either version 2 of the License, or
00016  * (at your option) any later version.
00017  * 
00018  * This program is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00026  *****************************************************************************/
00027 
00028 /*****************************************************************************
00029  * Preamble
00030  *****************************************************************************/
00031 #include <errno.h>                                                 /* ENOMEM */
00032 #include <stdlib.h>                                                /* free() */
00033 #include <string.h>                                            /* strerror() */
00034 
00035 #include <QuickTime/QuickTime.h>
00036 
00037 #include <vlc_keys.h>
00038 
00039 #include "intf.h"
00040 #include "vout.h"
00041 
00042 #define QT_MAX_DIRECTBUFFERS 10
00043 #define VL_MAX_DISPLAYS 16
00044 
00045 /*****************************************************************************
00046  * VLCView interface
00047  *****************************************************************************/
00048 @interface VLCQTView : NSQuickDrawView
00049 {
00050     vout_thread_t * p_vout;
00051 }
00052 
00053 - (id) initWithVout:(vout_thread_t *)p_vout;
00054 
00055 @end
00056 
00057 struct vout_sys_t
00058 {
00059     NSAutoreleasePool *o_pool;
00060     VLCWindow * o_window;
00061     VLCQTView * o_qtview;
00062 
00063     vlc_bool_t  b_saved_frame;
00064     vlc_bool_t  b_altivec;
00065     NSRect      s_frame;
00066 
00067     CodecType i_codec;
00068     CGrafPtr p_qdport;
00069     ImageSequence i_seq;
00070     MatrixRecordPtr p_matrix;
00071     DecompressorComponent img_dc;
00072     ImageDescriptionHandle h_img_descr;
00073 
00074     /* Mozilla plugin-related variables */
00075     vlc_bool_t b_embedded;
00076     Rect clipping_rect;
00077     int portx, porty;
00078 };
00079 
00080 struct picture_sys_t
00081 {
00082     void *p_data;
00083     unsigned int i_size;
00084     
00085     /* When using I420 output */
00086     PlanarPixmapInfoYUV420 pixmap_i420;
00087 };
00088 
00089 /*****************************************************************************
00090  * Local prototypes
00091  *****************************************************************************/
00092 
00093 static int  InitVideo           ( vout_thread_t * );
00094 static void EndVideo            ( vout_thread_t * );
00095 static int  ManageVideo         ( vout_thread_t * );
00096 static void DisplayVideo        ( vout_thread_t *, picture_t * );
00097 static int  ControlVideo        ( vout_thread_t *, int, va_list );
00098 
00099 static int CoToggleFullscreen( vout_thread_t *p_vout );
00100 static void QTScaleMatrix       ( vout_thread_t * );
00101 static int  QTCreateSequence    ( vout_thread_t * );
00102 static void QTDestroySequence   ( vout_thread_t * );
00103 static int  QTNewPicture        ( vout_thread_t *, picture_t * );
00104 static void QTFreePicture       ( vout_thread_t *, picture_t * );
00105 
00106 /*****************************************************************************
00107  * OpenVideo: allocates MacOS X video thread output method
00108  *****************************************************************************
00109  * This function allocates and initializes a MacOS X vout method.
00110  *****************************************************************************/
00111 int E_(OpenVideoQT) ( vlc_object_t *p_this )
00112 {
00113     vout_thread_t * p_vout = (vout_thread_t *)p_this;
00114     OSErr err;
00115     vlc_value_t value_drawable;
00116 
00117     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00118     if( p_vout->p_sys == NULL )
00119     {
00120         msg_Err( p_vout, "out of memory" );
00121         return( 1 );
00122     }
00123 
00124     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
00125 
00126     p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
00127 
00128     p_vout->pf_init = InitVideo;
00129     p_vout->pf_end = EndVideo;
00130     p_vout->pf_manage = ManageVideo;
00131     p_vout->pf_render = NULL;
00132     p_vout->pf_display = DisplayVideo;
00133     p_vout->pf_control = ControlVideo;
00134 
00135     /* Are we embedded?  If so, the drawable value will be a pointer to a
00136      * CGrafPtr that we're expected to use */
00137     var_Get( p_vout->p_vlc, "drawable", &value_drawable );
00138     if( value_drawable.i_int != 0 )
00139         p_vout->p_sys->b_embedded = VLC_TRUE;
00140     else
00141         p_vout->p_sys->b_embedded = VLC_FALSE;
00142 
00143     p_vout->p_sys->b_altivec = p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC;
00144     msg_Dbg( p_vout, "We do%s have Altivec", p_vout->p_sys->b_altivec ? "" : "n't" );
00145     
00146     /* Initialize QuickTime */
00147     p_vout->p_sys->h_img_descr = 
00148         (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
00149     p_vout->p_sys->p_matrix =
00150         (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
00151 
00152     if( ( err = EnterMovies() ) != noErr )
00153     {
00154         msg_Err( p_vout, "EnterMovies failed: %d", err );
00155         free( p_vout->p_sys->p_matrix );
00156         DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
00157         free( p_vout->p_sys );
00158         return VLC_EGENERIC;
00159     }
00160 
00161     /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
00162     vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
00163 
00164     /* Can we find the right chroma ? */
00165     if( p_vout->p_sys->b_altivec )
00166     {
00167         err = FindCodec( kYUVSPixelFormat, bestSpeedCodec,
00168                         nil, &p_vout->p_sys->img_dc );
00169     }
00170     else
00171     {
00172         err = FindCodec( kYUV420CodecType, bestSpeedCodec,
00173                         nil, &p_vout->p_sys->img_dc );
00174     }
00175     vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
00176     
00177     if( err == noErr && p_vout->p_sys->img_dc != 0 )
00178     {
00179         if( p_vout->p_sys->b_altivec )
00180         {
00181             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
00182             p_vout->p_sys->i_codec = kYUVSPixelFormat;
00183         }
00184         else
00185         {
00186             p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
00187             p_vout->p_sys->i_codec = kYUV420CodecType;
00188         }
00189     }
00190     else
00191     {
00192         msg_Err( p_vout, "failed to find an appropriate codec" );
00193     }
00194 
00195     if( p_vout->p_sys->img_dc == 0 )
00196     {
00197         free( p_vout->p_sys->p_matrix );
00198         DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
00199         free( p_vout->p_sys );
00200         return VLC_EGENERIC;        
00201     }
00202 
00203 #define o_qtview p_vout->p_sys->o_qtview
00204     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
00205     [o_qtview autorelease];
00206 
00207     if( p_vout->p_sys->b_embedded )
00208     {
00209         /* Zero the clipping rectangle */
00210         p_vout->p_sys->clipping_rect.left = 0;
00211         p_vout->p_sys->clipping_rect.right = 0;
00212         p_vout->p_sys->clipping_rect.top = 0;
00213         p_vout->p_sys->clipping_rect.bottom = 0;
00214     }
00215     else
00216     {
00217         /* Spawn window */
00218         p_vout->p_sys->o_window = [[VLCWindow alloc]
00219             initWithVout: p_vout view: o_qtview frame: nil];
00220         if( !p_vout->p_sys->o_window )
00221         {
00222             return VLC_EGENERIC;
00223         }
00224     }
00225 
00226     /* Retrieve the QuickDraw port */
00227     if( p_vout->p_sys->b_embedded )
00228     {
00229         /* Don't need (nor want) to lock the focus, since otherwise we crash
00230          * (presumably because we don't own the window, but I'm not sure
00231          * if this is the exact reason)  -andrep */
00232         p_vout->p_sys->p_qdport = [o_qtview qdPort];
00233     }
00234     else
00235     {
00236         [o_qtview lockFocus];
00237         p_vout->p_sys->p_qdport = [o_qtview qdPort];
00238         [o_qtview unlockFocus];
00239     }
00240 #undef o_qtview
00241 
00242     return VLC_SUCCESS;
00243 }
00244 
00245 /*****************************************************************************
00246  * CloseVideo: destroy video thread output method
00247  *****************************************************************************/
00248 void E_(CloseVideoQT) ( vlc_object_t *p_this )
00249 {
00250     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; 
00251     vout_thread_t * p_vout = (vout_thread_t *)p_this;
00252 
00253     if( !p_vout->p_sys->b_embedded )
00254         [p_vout->p_sys->o_window close];
00255 
00256     /* Clean Up Quicktime environment */
00257     ExitMovies();
00258     free( p_vout->p_sys->p_matrix );
00259     DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
00260 
00261     [o_pool release];
00262     free( p_vout->p_sys );
00263 }
00264 
00265 /*****************************************************************************
00266  * InitVideo: initialize video thread output method
00267  *****************************************************************************/
00268 static int InitVideo    ( vout_thread_t *p_vout )
00269 {
00270     picture_t *p_pic;
00271     int i_index;
00272 
00273     I_OUTPUTPICTURES = 0;
00274 
00275     /* Initialize the output structure; we already found a codec,
00276      * and the corresponding chroma we will be using. Since we can
00277      * arbitrary scale, stick to the coordinates and aspect. */
00278     p_vout->output.i_width  = p_vout->render.i_width;
00279     p_vout->output.i_height = p_vout->render.i_height;
00280     p_vout->output.i_aspect = p_vout->render.i_aspect;
00281 
00282     /* If we are embedded (e.g. running as a Mozilla plugin), use the pointer
00283      * stored in the "drawable" value as the CGrafPtr for the QuickDraw
00284      * graphics port */
00285     if( p_vout->p_sys->b_embedded )
00286     {
00287         vlc_value_t val;
00288         var_Get( p_vout->p_vlc, "drawable", &val );
00289         p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
00290     }
00291 
00292     SetPort( p_vout->p_sys->p_qdport );
00293     QTScaleMatrix( p_vout );
00294 
00295     if( QTCreateSequence( p_vout ) )
00296     {
00297         msg_Err( p_vout, "unable to create sequence" );
00298         return( 1 );
00299     }
00300 
00301     /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
00302     while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
00303     {
00304         p_pic = NULL;
00305 
00306         /* Find an empty picture slot */
00307         for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
00308         {
00309             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
00310             {
00311                 p_pic = p_vout->p_picture + i_index;
00312                 break;
00313             }
00314         }
00315 
00316         /* Allocate the picture */
00317         if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
00318         {
00319             break;
00320         }
00321 
00322         p_pic->i_status = DESTROYED_PICTURE;
00323         p_pic->i_type   = DIRECT_PICTURE;
00324 
00325         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
00326         I_OUTPUTPICTURES++;
00327     }
00328     return 0;
00329 }
00330 
00331 /*****************************************************************************
00332  * EndVideo: terminate video thread output method
00333  *****************************************************************************/
00334 static void EndVideo( vout_thread_t *p_vout )
00335 {
00336     int i_index;
00337 
00338     QTDestroySequence( p_vout );
00339 
00340     /* Free the direct buffers we allocated */
00341     for( i_index = I_OUTPUTPICTURES; i_index; )
00342     {
00343         i_index--;
00344         QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
00345     }
00346 }
00347 
00348 /*****************************************************************************
00349  * ManageVideo: handle events
00350  *****************************************************************************
00351  * This function should be called regularly by video output thread. It manages
00352  * console events. It returns a non null value on error.
00353  *****************************************************************************/
00354 static int ManageVideo( vout_thread_t *p_vout )
00355 {
00356     vlc_value_t val;
00357     var_Get( p_vout->p_vlc, "drawableredraw", &val );
00358 
00359     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
00360     {
00361         if( CoToggleFullscreen( p_vout ) )  
00362         {
00363             return( 1 );
00364         }
00365 
00366         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
00367     }
00368 
00369     if( p_vout->p_sys->b_embedded && val.i_int == 1 )
00370     {
00371         /* If we're embedded, the application is expected to indicate a
00372          * window change (move/resize/etc) via the "drawableredraw" value.
00373          * If that's the case, set the VOUT_SIZE_CHANGE flag so we do
00374          * actually handle the window change. */
00375         val.i_int = 0;
00376         var_Set( p_vout->p_vlc, "drawableredraw", val );
00377 
00378         p_vout->i_changes |= VOUT_SIZE_CHANGE;
00379     }
00380 
00381     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
00382     {
00383         QTScaleMatrix( p_vout );
00384         SetDSequenceMatrix( p_vout->p_sys->i_seq,
00385                             p_vout->p_sys->p_matrix );
00386         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
00387     }
00388 
00389     [p_vout->p_sys->o_window manage];
00390 
00391     return( 0 );
00392 }
00393 
00394 /*****************************************************************************
00395  * vout_Display: displays previously rendered output
00396  *****************************************************************************
00397  * This function sends the currently rendered image to the display.
00398  *****************************************************************************/
00399 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
00400 {
00401     OSErr err;
00402     CodecFlags flags;
00403 
00404     Rect saved_rect;
00405     RgnHandle saved_clip;
00406 
00407     saved_clip = NewRgn();
00408 
00409     if( p_vout->p_sys->b_embedded )
00410     {
00411         /* In the Mozilla plugin, the browser also draws things in the windows.
00412          * So, we have to update the origin and clipping rectangle for each
00413          * picture.  FIXME: The vout should probably lock something ... */
00414 
00415         /* Save the origin and clipping rectangle used by the host application
00416          * (e.g. Mozilla), so we can restore it later */
00417         GetPortBounds( p_vout->p_sys->p_qdport, &saved_rect );
00418         GetClip( saved_clip );
00419 
00420         /* The port gets unlocked at the end of this function */
00421         LockPortBits( p_vout->p_sys->p_qdport );
00422 
00423         /* Change the origin and clipping to the coordinates that the embedded
00424          * window wants to draw at */
00425         SetPort( p_vout->p_sys->p_qdport );
00426         SetOrigin( p_vout->p_sys->portx , p_vout->p_sys->porty );
00427         ClipRect( &p_vout->p_sys->clipping_rect );
00428     }
00429 
00430     if( ( err = DecompressSequenceFrameWhen(
00431                     p_vout->p_sys->i_seq,
00432                     p_pic->p_sys->p_data,
00433                     p_pic->p_sys->i_size,
00434                     codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
00435     {
00436         msg_Warn( p_vout, "DecompressSequenceFrameWhen failed: %d", err );
00437     }
00438     else
00439     {
00440         if( !p_vout->p_sys->b_embedded )
00441             QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
00442     }
00443 
00444     if( p_vout->p_sys->b_embedded )
00445     {
00446         /* Restore the origin and clipping rectangle to the settings used
00447          * by the host application */
00448         SetOrigin( saved_rect.left, saved_rect.top );
00449         SetClip( saved_clip );
00450 
00451         UnlockPortBits( p_vout->p_sys->p_qdport );
00452     }
00453 }
00454 
00455 /*****************************************************************************
00456  * ControlVideo: control facility for the vout
00457  *****************************************************************************/
00458 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
00459 {
00460     vlc_bool_t b_arg;
00461 
00462     switch( i_query )
00463     {
00464         case VOUT_SET_STAY_ON_TOP:
00465             b_arg = va_arg( args, vlc_bool_t );
00466             [p_vout->p_sys->o_window setOnTop: b_arg];
00467             return VLC_SUCCESS;
00468 
00469         case VOUT_CLOSE:
00470         case VOUT_REPARENT:
00471         default:
00472             return vout_vaControlDefault( p_vout, i_query, args );
00473     }
00474 }
00475 
00476 /*****************************************************************************
00477  * CoToggleFullscreen: toggle fullscreen 
00478  *****************************************************************************
00479  * Returns 0 on success, 1 otherwise
00480  *****************************************************************************/
00481 static int CoToggleFullscreen( vout_thread_t *p_vout )
00482 {
00483     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
00484 
00485     QTDestroySequence( p_vout );
00486 
00487     if( !p_vout->b_fullscreen )
00488     {
00489         /* Save window size and position */
00490         p_vout->p_sys->s_frame.size =
00491             [[p_vout->p_sys->o_window contentView] frame].size;
00492         p_vout->p_sys->s_frame.origin =
00493             [p_vout->p_sys->o_window frame].origin;
00494         p_vout->p_sys->b_saved_frame = VLC_TRUE;
00495     }
00496     [p_vout->p_sys->o_window close];
00497 
00498     p_vout->b_fullscreen = !p_vout->b_fullscreen;
00499 
00500 #define o_qtview p_vout->p_sys->o_qtview
00501     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
00502     [o_qtview autorelease];
00503     
00504     if( p_vout->p_sys->b_saved_frame )
00505     {
00506         p_vout->p_sys->o_window = [[VLCWindow alloc]
00507             initWithVout: p_vout view: o_qtview
00508             frame: &p_vout->p_sys->s_frame];
00509     }
00510     else
00511     {
00512         p_vout->p_sys->o_window = [[VLCWindow alloc]
00513             initWithVout: p_vout view: o_qtview frame: nil];
00514     }
00515 
00516     /* Retrieve the QuickDraw port */
00517     [o_qtview lockFocus];
00518     p_vout->p_sys->p_qdport = [o_qtview qdPort];
00519     [o_qtview unlockFocus];
00520 #undef o_qtview
00521 
00522     SetPort( p_vout->p_sys->p_qdport );
00523     QTScaleMatrix( p_vout );
00524 
00525     if( QTCreateSequence( p_vout ) )
00526     {
00527         msg_Err( p_vout, "unable to create sequence" );
00528         return( 1 ); 
00529     } 
00530 
00531     [o_pool release];
00532     return 0;
00533 }
00534 
00535 /*****************************************************************************
00536  * QTScaleMatrix: scale matrix 
00537  *****************************************************************************/
00538 static void QTScaleMatrix( vout_thread_t *p_vout )
00539 {
00540     Rect s_rect;
00541     vlc_value_t val;
00542     unsigned int i_width, i_height;
00543     Fixed factor_x, factor_y;
00544     unsigned int i_offset_x = 0;
00545     unsigned int i_offset_y = 0;
00546 
00547     GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
00548 
00549     i_width = s_rect.right - s_rect.left;
00550     i_height = s_rect.bottom - s_rect.top;
00551 
00552     if( p_vout->p_sys->b_embedded )
00553     {
00554         /* Embedded video get their drawing region from the host application
00555          * by the drawable values here.  Read those variables, and store them
00556          * in the p_vout->p_sys structure so that other functions (such as
00557          * DisplayVideo and ManageVideo) can use them later. */
00558         vlc_value_t valt, vall, valb, valr, valx, valy, valw, valh,
00559                     valportx, valporty;
00560 
00561         var_Get( p_vout->p_vlc, "drawable", &val );
00562         var_Get( p_vout->p_vlc, "drawablet", &valt );
00563         var_Get( p_vout->p_vlc, "drawablel", &vall );
00564         var_Get( p_vout->p_vlc, "drawableb", &valb );
00565         var_Get( p_vout->p_vlc, "drawabler", &valr );
00566         var_Get( p_vout->p_vlc, "drawablex", &valx );
00567         var_Get( p_vout->p_vlc, "drawabley", &valy );
00568         var_Get( p_vout->p_vlc, "drawablew", &valw );
00569         var_Get( p_vout->p_vlc, "drawableh", &valh );
00570         var_Get( p_vout->p_vlc, "drawableportx", &valportx );
00571         var_Get( p_vout->p_vlc, "drawableporty", &valporty );
00572 
00573         p_vout->p_sys->portx = valportx.i_int;
00574         p_vout->p_sys->porty = valporty.i_int;
00575         p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
00576         i_width = valw.i_int;
00577         i_height = valh.i_int;
00578 
00579         p_vout->p_sys->clipping_rect.top = 0;
00580         p_vout->p_sys->clipping_rect.left = 0;
00581         p_vout->p_sys->clipping_rect.bottom = valb.i_int - valt.i_int;
00582         p_vout->p_sys->clipping_rect.right = valr.i_int - vall.i_int;
00583     }
00584 
00585     var_Get( p_vout, "macosx-stretch", &val );
00586     if( val.b_bool )
00587     {
00588         factor_x = FixDiv( Long2Fix( i_width ),
00589                            Long2Fix( p_vout->output.i_width ) );
00590         factor_y = FixDiv( Long2Fix( i_height ),
00591                            Long2Fix( p_vout->output.i_height ) );
00592 
00593     }
00594     else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
00595     {
00596         int i_adj_width = i_height * p_vout->output.i_aspect /
00597                           VOUT_ASPECT_FACTOR;
00598 
00599         factor_x = FixDiv( Long2Fix( i_adj_width ),
00600                            Long2Fix( p_vout->output.i_width ) );
00601         factor_y = FixDiv( Long2Fix( i_height ),
00602                            Long2Fix( p_vout->output.i_height ) );
00603 
00604         i_offset_x = (i_width - i_adj_width) / 2;
00605     }
00606     else
00607     {
00608         int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
00609                            p_vout->output.i_aspect;
00610 
00611         factor_x = FixDiv( Long2Fix( i_width ),
00612                            Long2Fix( p_vout->output.i_width ) );
00613         factor_y = FixDiv( Long2Fix( i_adj_height ),
00614                            Long2Fix( p_vout->output.i_height ) );
00615 
00616         i_offset_y = (i_height - i_adj_height) / 2;
00617     }
00618 
00619     SetIdentityMatrix( p_vout->p_sys->p_matrix );
00620 
00621     ScaleMatrix( p_vout->p_sys->p_matrix,
00622                  factor_x, factor_y,
00623                  Long2Fix(0), Long2Fix(0) );
00624 
00625     TranslateMatrix( p_vout->p_sys->p_matrix,
00626                  Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
00627 }
00628 
00629 /*****************************************************************************
00630  * QTCreateSequence: create a new sequence 
00631  *****************************************************************************
00632  * Returns 0 on success, 1 otherwise
00633  *****************************************************************************/
00634 static int QTCreateSequence( vout_thread_t *p_vout )
00635 {
00636     OSErr err;
00637     ImageDescriptionPtr p_descr;
00638 
00639     HLock( (Handle)p_vout->p_sys->h_img_descr );
00640     p_descr = *p_vout->p_sys->h_img_descr;
00641 
00642     p_descr->idSize = sizeof(ImageDescription);
00643     p_descr->cType = p_vout->p_sys->i_codec;
00644     p_descr->version = 2;
00645     p_descr->revisionLevel = 0;
00646     p_descr->vendor = 'mpla';
00647     p_descr->width = p_vout->output.i_width;
00648     p_descr->height = p_vout->output.i_height;
00649     p_descr->hRes = Long2Fix(72);
00650     p_descr->vRes = Long2Fix(72);
00651     p_descr->spatialQuality = codecLosslessQuality;
00652     p_descr->frameCount = 1;
00653     p_descr->clutID = -1;
00654     p_descr->dataSize = 0;
00655     p_descr->depth = 24;
00656 
00657     HUnlock( (Handle)p_vout->p_sys->h_img_descr );
00658 
00659     if( ( err = DecompressSequenceBeginS( 
00660                               &p_vout->p_sys->i_seq,
00661                               p_vout->p_sys->h_img_descr,
00662                               NULL,
00663                               (p_descr->width * p_descr->height * 16) / 8,
00664                               p_vout->p_sys->p_qdport,
00665                               NULL, NULL,
00666                               p_vout->p_sys->p_matrix,
00667                               srcCopy, NULL,
00668                               codecFlagUseImageBuffer,
00669                               codecLosslessQuality,
00670                               bestSpeedCodec ) ) )
00671     {
00672         msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
00673         return( 1 );
00674     }
00675 
00676     return( 0 );
00677 }
00678 
00679 /*****************************************************************************
00680  * QTDestroySequence: destroy sequence 
00681  *****************************************************************************/
00682 static void QTDestroySequence( vout_thread_t *p_vout )
00683 {
00684     CDSequenceEnd( p_vout->p_sys->i_seq );
00685 }
00686 
00687 /*****************************************************************************
00688  * QTNewPicture: allocate a picture
00689  *****************************************************************************
00690  * Returns 0 on success, 1 otherwise
00691  *****************************************************************************/
00692 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
00693 {
00694     /* We know the chroma, allocate a buffer which will be used
00695      * directly by the decoder */
00696     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
00697 
00698     if( p_pic->p_sys == NULL )
00699     {
00700         return( -1 );
00701     }
00702 
00703     vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
00704                       p_vout->output.i_width, p_vout->output.i_height,
00705                       p_vout->output.i_aspect );
00706 
00707     switch( p_vout->output.i_chroma )
00708     {
00709         case VLC_FOURCC('Y','U','Y','2'):
00710             p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
00711 
00712             /* Allocate the memory buffer */
00713             p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
00714                                           16, p_pic->p_sys->i_size );
00715 
00716             p_pic->p[0].p_pixels = p_pic->p_data;
00717             p_pic->p[0].i_lines = p_vout->output.i_height;
00718             p_pic->p[0].i_visible_lines = p_vout->output.i_height;
00719             p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
00720             p_pic->p[0].i_pixel_pitch = 1;
00721             p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
00722             p_pic->i_planes = 1;
00723 
00724             p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
00725 
00726             break;
00727             
00728         case VLC_FOURCC('I','4','2','0'):
00729             p_pic->p_sys->p_data = (void *)&p_pic->p_sys->pixmap_i420;
00730             p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
00731             
00732             /* Allocate the memory buffer */
00733             p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
00734                                           16, p_vout->output.i_width * p_vout->output.i_height * 3 / 2 );
00735 
00736             /* Y buffer */
00737             p_pic->Y_PIXELS = p_pic->p_data; 
00738             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
00739             p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
00740             p_pic->p[Y_PLANE].i_pitch = p_vout->output.i_width;
00741             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
00742             p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width;
00743 
00744             /* U buffer */
00745             p_pic->U_PIXELS = p_pic->Y_PIXELS + p_vout->output.i_height * p_vout->output.i_width;
00746             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
00747             p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
00748             p_pic->p[U_PLANE].i_pitch = p_vout->output.i_width / 2;
00749             p_pic->p[U_PLANE].i_pixel_pitch = 1;
00750             p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
00751 
00752             /* V buffer */
00753             p_pic->V_PIXELS = p_pic->U_PIXELS + p_vout->output.i_height * p_vout->output.i_width / 4;
00754             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
00755             p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
00756             p_pic->p[V_PLANE].i_pitch = p_vout->output.i_width / 2;
00757             p_pic->p[V_PLANE].i_pixel_pitch = 1;
00758             p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
00759 
00760             /* We allocated 3 planes */
00761             p_pic->i_planes = 3;
00762 
00763 #define P p_pic->p_sys->pixmap_i420
00764             P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
00765                                        - p_pic->p_sys->p_data;
00766             P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
00767                                         - p_pic->p_sys->p_data;
00768             P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
00769                                         - p_pic->p_sys->p_data;
00770 
00771             P.componentInfoY.rowBytes = p_vout->output.i_width;
00772             P.componentInfoCb.rowBytes = p_vout->output.i_width / 2;
00773             P.componentInfoCr.rowBytes = p_vout->output.i_width / 2;
00774 #undef P
00775             break;
00776         
00777         default:
00778             /* Unknown chroma, tell the guy to get lost */
00779             free( p_pic->p_sys );
00780             msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
00781                      p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
00782             p_pic->i_planes = 0;
00783             return( -1 );
00784     }
00785 
00786     return( 0 );
00787 }
00788 
00789 /*****************************************************************************
00790  * QTFreePicture: destroy a picture allocated with QTNewPicture
00791  *****************************************************************************/
00792 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
00793 {
00794     switch( p_vout->output.i_chroma )
00795     {
00796         case VLC_FOURCC('I','4','2','0'):
00797             free( p_pic->p_data_orig );
00798             break;
00799     }
00800 
00801     free( p_pic->p_sys );
00802 }
00803 
00804 /*****************************************************************************
00805  * VLCQTView implementation
00806  *****************************************************************************/
00807 @implementation VLCQTView
00808 
00809 - (id) initWithVout:(vout_thread_t *)_p_vout
00810 {
00811     p_vout = _p_vout;
00812     return [super init];
00813 }
00814 
00815 - (void)drawRect:(NSRect)rect
00816 {
00817     [[NSColor blackColor] set];
00818     NSRectFill( rect );
00819     [super drawRect: rect];
00820 
00821     p_vout->i_changes |= VOUT_SIZE_CHANGE;
00822 }
00823 
00824 @end

Generated on Tue Dec 20 10:14:38 2005 for vlc-0.8.4a by  doxygen 1.4.2