]> git.sesse.net Git - vlc/blob - modules/gui/macosx/voutqt.m
macosx/vout*.m: factorized some more code, fixed GL video device selection
[vlc] / modules / gui / macosx / voutqt.m
1 /*****************************************************************************
2  * vout.m: MacOS X video output module
3  *****************************************************************************
4  * Copyright (C) 2001-2003 VideoLAN
5  * $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
6  *
7  * Authors: Colin Delacroix <colin@zoy.org>
8  *          Florian G. Pflug <fgp@phlo.org>
9  *          Jon Lech Johansen <jon-vl@nanocrew.net>
10  *          Derk-Jan Hartman <hartman at videolan dot org>
11  *          Eric Petit <titer@m0k.org>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <errno.h>                                                 /* ENOMEM */
32 #include <stdlib.h>                                                /* free() */
33 #include <string.h>                                            /* strerror() */
34
35 #include <QuickTime/QuickTime.h>
36
37 #include <vlc_keys.h>
38
39 #include "intf.h"
40 #include "vout.h"
41
42 #define QT_MAX_DIRECTBUFFERS 10
43 #define VL_MAX_DISPLAYS 16
44
45 /*****************************************************************************
46  * VLCView interface
47  *****************************************************************************/
48 @interface VLCQTView : NSQuickDrawView
49 {
50     vout_thread_t * p_vout;
51 }
52
53 - (id) initWithVout:(vout_thread_t *)p_vout;
54
55 @end
56
57 struct vout_sys_t
58 {
59     NSAutoreleasePool *o_pool;
60     VLCWindow * o_window;
61     VLCQTView * o_qtview;
62
63     vlc_bool_t  b_saved_frame;
64     vlc_bool_t  b_altivec;
65     NSRect      s_frame;
66
67     CodecType i_codec;
68     CGrafPtr p_qdport;
69     ImageSequence i_seq;
70     MatrixRecordPtr p_matrix;
71     DecompressorComponent img_dc;
72     ImageDescriptionHandle h_img_descr;
73 };
74
75 struct picture_sys_t
76 {
77     void *p_data;
78     unsigned int i_size;
79     
80     /* When using I420 output */
81     PlanarPixmapInfoYUV420 pixmap_i420;
82 };
83
84 /*****************************************************************************
85  * Local prototypes
86  *****************************************************************************/
87
88 static int  InitVideo           ( vout_thread_t * );
89 static void EndVideo            ( vout_thread_t * );
90 static int  ManageVideo         ( vout_thread_t * );
91 static void DisplayVideo        ( vout_thread_t *, picture_t * );
92 static int  ControlVideo        ( vout_thread_t *, int, va_list );
93
94 static int CoToggleFullscreen( vout_thread_t *p_vout );
95 static void QTScaleMatrix       ( vout_thread_t * );
96 static int  QTCreateSequence    ( vout_thread_t * );
97 static void QTDestroySequence   ( vout_thread_t * );
98 static int  QTNewPicture        ( vout_thread_t *, picture_t * );
99 static void QTFreePicture       ( vout_thread_t *, picture_t * );
100
101 /*****************************************************************************
102  * OpenVideo: allocates MacOS X video thread output method
103  *****************************************************************************
104  * This function allocates and initializes a MacOS X vout method.
105  *****************************************************************************/
106 int E_(OpenVideoQT) ( vlc_object_t *p_this )
107 {   
108     vout_thread_t * p_vout = (vout_thread_t *)p_this;
109     OSErr err;
110     int i_timeout;
111
112     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
113     if( p_vout->p_sys == NULL )
114     {
115         msg_Err( p_vout, "out of memory" );
116         return( 1 );
117     }
118
119     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
120
121     /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
122     for( i_timeout = 20 ; i_timeout-- ; )
123     {
124         if( NSApp == NULL )
125         {
126             msleep( INTF_IDLE_SLEEP );
127         }
128     }
129
130     if( NSApp == NULL )
131     {
132         /* no MacOS X intf, unable to communicate with MT */
133         msg_Err( p_vout, "no MacOS X interface present" );
134         free( p_vout->p_sys );
135         return( 1 );
136     }
137
138     p_vout->pf_init = InitVideo;
139     p_vout->pf_end = EndVideo;
140     p_vout->pf_manage = ManageVideo;
141     p_vout->pf_render = NULL;
142     p_vout->pf_display = DisplayVideo;
143     p_vout->pf_control = ControlVideo;
144
145     p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
146
147     p_vout->p_sys->b_altivec = p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC;
148     msg_Dbg( p_vout, "We do%s have Altivec", p_vout->p_sys->b_altivec ? "" : "n't" );
149     
150     /* Initialize QuickTime */
151     p_vout->p_sys->h_img_descr = 
152         (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
153     p_vout->p_sys->p_matrix =
154         (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
155
156     if( ( err = EnterMovies() ) != noErr )
157     {
158         msg_Err( p_vout, "EnterMovies failed: %d", err );
159         free( p_vout->p_sys->p_matrix );
160         DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
161         free( p_vout->p_sys );
162         return VLC_EGENERIC;
163     }
164
165     /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
166     vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
167
168     /* Can we find the right chroma ? */
169     if( p_vout->p_sys->b_altivec )
170     {
171         err = FindCodec( kYUVSPixelFormat, bestSpeedCodec,
172                         nil, &p_vout->p_sys->img_dc );
173     }
174     else
175     {
176         err = FindCodec( kYUV420CodecType, bestSpeedCodec,
177                         nil, &p_vout->p_sys->img_dc );
178     }
179     vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
180     
181     if( err == noErr && p_vout->p_sys->img_dc != 0 )
182     {
183         if( p_vout->p_sys->b_altivec )
184         {
185             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
186             p_vout->p_sys->i_codec = kYUVSPixelFormat;
187         }
188         else
189         {
190             p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
191             p_vout->p_sys->i_codec = kYUV420CodecType;
192         }
193     }
194     else
195     {
196         msg_Err( p_vout, "failed to find an appropriate codec" );
197     }
198
199     if( p_vout->p_sys->img_dc == 0 )
200     {
201         free( p_vout->p_sys->p_matrix );
202         DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
203         free( p_vout->p_sys );
204         return VLC_EGENERIC;        
205     }
206
207     /* Spawn window */
208     p_vout->p_sys->o_window =
209         [[VLCWindow alloc] initWithVout: p_vout frame: nil];
210
211 #define o_qtview p_vout->p_sys->o_qtview
212     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
213     [p_vout->p_sys->o_window setContentView: o_qtview];
214     [o_qtview autorelease];
215
216     /* Retrieve the QuickDraw port */
217     [o_qtview lockFocus];
218     p_vout->p_sys->p_qdport = [o_qtview qdPort];
219     [o_qtview unlockFocus];
220 #undef o_qtview
221
222     return VLC_SUCCESS;
223 }
224
225 /*****************************************************************************
226  * CloseVideo: destroy video thread output method
227  *****************************************************************************/
228 void E_(CloseVideoQT) ( vlc_object_t *p_this )
229 {
230     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; 
231     vout_thread_t * p_vout = (vout_thread_t *)p_this;
232
233     [p_vout->p_sys->o_window close];
234
235     /* Clean Up Quicktime environment */
236     ExitMovies();
237     free( p_vout->p_sys->p_matrix );
238     DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
239
240     [o_pool release];
241     free( p_vout->p_sys );
242 }
243
244 /*****************************************************************************
245  * InitVideo: initialize video thread output method
246  *****************************************************************************/
247 static int InitVideo    ( vout_thread_t *p_vout )
248 {
249     picture_t *p_pic;
250     int i_index;
251
252     I_OUTPUTPICTURES = 0;
253
254     /* Initialize the output structure; we already found a codec,
255      * and the corresponding chroma we will be using. Since we can
256      * arbitrary scale, stick to the coordinates and aspect. */
257     p_vout->output.i_width  = p_vout->render.i_width;
258     p_vout->output.i_height = p_vout->render.i_height;
259     p_vout->output.i_aspect = p_vout->render.i_aspect;
260
261     SetPort( p_vout->p_sys->p_qdport );
262     QTScaleMatrix( p_vout );
263
264     if( QTCreateSequence( p_vout ) )
265     {
266         msg_Err( p_vout, "unable to create sequence" );
267         return( 1 );
268     }
269
270     /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
271     while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
272     {
273         p_pic = NULL;
274
275         /* Find an empty picture slot */
276         for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
277         {
278             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
279             {
280                 p_pic = p_vout->p_picture + i_index;
281                 break;
282             }
283         }
284
285         /* Allocate the picture */
286         if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
287         {
288             break;
289         }
290
291         p_pic->i_status = DESTROYED_PICTURE;
292         p_pic->i_type   = DIRECT_PICTURE;
293
294         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
295         I_OUTPUTPICTURES++;
296     }
297     return 0;
298 }
299
300 /*****************************************************************************
301  * EndVideo: terminate video thread output method
302  *****************************************************************************/
303 static void EndVideo( vout_thread_t *p_vout )
304 {
305     int i_index;
306
307     QTDestroySequence( p_vout );
308
309     /* Free the direct buffers we allocated */
310     for( i_index = I_OUTPUTPICTURES; i_index; )
311     {
312         i_index--;
313         QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
314     }
315 }
316
317 /*****************************************************************************
318  * ManageVideo: handle events
319  *****************************************************************************
320  * This function should be called regularly by video output thread. It manages
321  * console events. It returns a non null value on error.
322  *****************************************************************************/
323 static int ManageVideo( vout_thread_t *p_vout )
324 {
325     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
326     {
327         if( CoToggleFullscreen( p_vout ) )  
328         {
329             return( 1 );
330         }
331
332         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
333     }
334
335     if( p_vout->i_changes & VOUT_SIZE_CHANGE ) 
336     {
337         QTScaleMatrix( p_vout );
338         SetDSequenceMatrix( p_vout->p_sys->i_seq, 
339                             p_vout->p_sys->p_matrix );
340  
341         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
342     }
343
344     [p_vout->p_sys->o_window manage];
345     
346     return( 0 );
347 }
348
349 /*****************************************************************************
350  * vout_Display: displays previously rendered output
351  *****************************************************************************
352  * This function sends the currently rendered image to the display.
353  *****************************************************************************/
354 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
355 {
356     OSErr err;
357     CodecFlags flags;
358
359     if( ( err = DecompressSequenceFrameWhen( 
360                     p_vout->p_sys->i_seq,
361                     p_pic->p_sys->p_data,
362                     p_pic->p_sys->i_size,                    
363                     codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
364     {
365         msg_Warn( p_vout, "DecompressSequenceFrameWhen failed: %d", err );
366     }
367     else
368     {
369         QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
370     }
371 }
372
373 /*****************************************************************************
374  * ControlVideo: control facility for the vout
375  *****************************************************************************/
376 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
377 {
378     vlc_bool_t b_arg;
379
380     switch( i_query )
381     {
382         case VOUT_SET_STAY_ON_TOP:
383             b_arg = va_arg( args, vlc_bool_t );
384             [p_vout->p_sys->o_window setOnTop: b_arg];
385             return VLC_SUCCESS;
386
387         case VOUT_CLOSE:
388         case VOUT_REPARENT:
389         default:
390             return vout_vaControlDefault( p_vout, i_query, args );
391     }
392 }
393
394 /*****************************************************************************
395  * CoToggleFullscreen: toggle fullscreen 
396  *****************************************************************************
397  * Returns 0 on success, 1 otherwise
398  *****************************************************************************/
399 static int CoToggleFullscreen( vout_thread_t *p_vout )
400 {
401     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
402
403     QTDestroySequence( p_vout );
404
405     if( !p_vout->b_fullscreen )
406     {
407         /* Save window size and position */
408         p_vout->p_sys->s_frame.size =
409             [[p_vout->p_sys->o_window contentView] frame].size;
410         p_vout->p_sys->s_frame.origin =
411             [p_vout->p_sys->o_window frame].origin;
412         p_vout->p_sys->b_saved_frame = VLC_TRUE;
413     }
414     [p_vout->p_sys->o_window close];
415
416     p_vout->b_fullscreen = !p_vout->b_fullscreen;
417
418     if( p_vout->p_sys->b_saved_frame )
419     {
420         p_vout->p_sys->o_window = [[VLCWindow alloc]
421             initWithVout: p_vout frame: &p_vout->p_sys->s_frame];
422     }
423     else
424     {
425         p_vout->p_sys->o_window = [[VLCWindow alloc]
426             initWithVout: p_vout frame: nil];
427     }
428
429 #define o_qtview p_vout->p_sys->o_qtview
430     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
431     [p_vout->p_sys->o_window setContentView: o_qtview];
432     [o_qtview autorelease];
433
434     /* Retrieve the QuickDraw port */
435     [o_qtview lockFocus];
436     p_vout->p_sys->p_qdport = [o_qtview qdPort];
437     [o_qtview unlockFocus];
438 #undef o_qtview
439
440     SetPort( p_vout->p_sys->p_qdport );
441     QTScaleMatrix( p_vout );
442
443     if( QTCreateSequence( p_vout ) )
444     {
445         msg_Err( p_vout, "unable to create sequence" );
446         return( 1 ); 
447     } 
448
449     [o_pool release];
450     return 0;
451 }
452
453 /*****************************************************************************
454  * QTScaleMatrix: scale matrix 
455  *****************************************************************************/
456 static void QTScaleMatrix( vout_thread_t *p_vout )
457 {
458     Rect s_rect;
459     vlc_value_t val;
460     unsigned int i_width, i_height;
461     Fixed factor_x, factor_y;
462     unsigned int i_offset_x = 0;
463     unsigned int i_offset_y = 0;
464
465     GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
466
467     i_width = s_rect.right - s_rect.left;
468     i_height = s_rect.bottom - s_rect.top;
469
470     var_Get( p_vout, "macosx-stretch", &val );
471     if( val.b_bool )
472     {
473         factor_x = FixDiv( Long2Fix( i_width ),
474                            Long2Fix( p_vout->output.i_width ) );
475         factor_y = FixDiv( Long2Fix( i_height ),
476                            Long2Fix( p_vout->output.i_height ) );
477                            
478     }
479     else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
480     {
481         int i_adj_width = i_height * p_vout->output.i_aspect /
482                           VOUT_ASPECT_FACTOR;
483
484         factor_x = FixDiv( Long2Fix( i_adj_width ),
485                            Long2Fix( p_vout->output.i_width ) );
486         factor_y = FixDiv( Long2Fix( i_height ),
487                            Long2Fix( p_vout->output.i_height ) );
488
489         i_offset_x = (i_width - i_adj_width) / 2;
490     }
491     else
492     {
493         int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
494                            p_vout->output.i_aspect;
495
496         factor_x = FixDiv( Long2Fix( i_width ),
497                            Long2Fix( p_vout->output.i_width ) );
498         factor_y = FixDiv( Long2Fix( i_adj_height ),
499                            Long2Fix( p_vout->output.i_height ) );
500
501         i_offset_y = (i_height - i_adj_height) / 2;
502     }
503     
504     SetIdentityMatrix( p_vout->p_sys->p_matrix );
505
506     ScaleMatrix( p_vout->p_sys->p_matrix,
507                  factor_x, factor_y,
508                  Long2Fix(0), Long2Fix(0) );
509                  
510     TranslateMatrix( p_vout->p_sys->p_matrix,
511                  Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
512 }
513
514 /*****************************************************************************
515  * QTCreateSequence: create a new sequence 
516  *****************************************************************************
517  * Returns 0 on success, 1 otherwise
518  *****************************************************************************/
519 static int QTCreateSequence( vout_thread_t *p_vout )
520 {
521     OSErr err;
522     ImageDescriptionPtr p_descr;
523
524     HLock( (Handle)p_vout->p_sys->h_img_descr );
525     p_descr = *p_vout->p_sys->h_img_descr;
526
527     p_descr->idSize = sizeof(ImageDescription);
528     p_descr->cType = p_vout->p_sys->i_codec;
529     p_descr->version = 2;
530     p_descr->revisionLevel = 0;
531     p_descr->vendor = 'mpla';
532     p_descr->width = p_vout->output.i_width;
533     p_descr->height = p_vout->output.i_height;
534     p_descr->hRes = Long2Fix(72);
535     p_descr->vRes = Long2Fix(72);
536     p_descr->spatialQuality = codecLosslessQuality;
537     p_descr->frameCount = 1;
538     p_descr->clutID = -1;
539     p_descr->dataSize = 0;
540     p_descr->depth = 24;
541
542     HUnlock( (Handle)p_vout->p_sys->h_img_descr );
543
544     if( ( err = DecompressSequenceBeginS( 
545                               &p_vout->p_sys->i_seq,
546                               p_vout->p_sys->h_img_descr,
547                               NULL,
548                               (p_descr->width * p_descr->height * 16) / 8,
549                               p_vout->p_sys->p_qdport,
550                               NULL, NULL,
551                               p_vout->p_sys->p_matrix,
552                               srcCopy, NULL,
553                               codecFlagUseImageBuffer,
554                               codecLosslessQuality,
555                               bestSpeedCodec ) ) )
556     {
557         msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
558         return( 1 );
559     }
560
561     return( 0 );
562 }
563
564 /*****************************************************************************
565  * QTDestroySequence: destroy sequence 
566  *****************************************************************************/
567 static void QTDestroySequence( vout_thread_t *p_vout )
568 {
569     CDSequenceEnd( p_vout->p_sys->i_seq );
570 }
571
572 /*****************************************************************************
573  * QTNewPicture: allocate a picture
574  *****************************************************************************
575  * Returns 0 on success, 1 otherwise
576  *****************************************************************************/
577 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
578 {
579     /* We know the chroma, allocate a buffer which will be used
580      * directly by the decoder */
581     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
582
583     if( p_pic->p_sys == NULL )
584     {
585         return( -1 );
586     }
587
588     vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
589                       p_vout->output.i_width, p_vout->output.i_height,
590                       p_vout->output.i_aspect );
591
592     switch( p_vout->output.i_chroma )
593     {
594         case VLC_FOURCC('Y','U','Y','2'):
595             p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
596
597             /* Allocate the memory buffer */
598             p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
599                                           16, p_pic->p_sys->i_size );
600
601             p_pic->p[0].p_pixels = p_pic->p_data;
602             p_pic->p[0].i_lines = p_vout->output.i_height;
603             p_pic->p[0].i_visible_lines = p_vout->output.i_height;
604             p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
605             p_pic->p[0].i_pixel_pitch = 1;
606             p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
607             p_pic->i_planes = 1;
608
609             p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
610
611             break;
612             
613         case VLC_FOURCC('I','4','2','0'):
614             p_pic->p_sys->p_data = (void *)&p_pic->p_sys->pixmap_i420;
615             p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
616             
617             /* Allocate the memory buffer */
618             p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
619                                           16, p_vout->output.i_width * p_vout->output.i_height * 3 / 2 );
620
621             /* Y buffer */
622             p_pic->Y_PIXELS = p_pic->p_data; 
623             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
624             p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
625             p_pic->p[Y_PLANE].i_pitch = p_vout->output.i_width;
626             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
627             p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width;
628
629             /* U buffer */
630             p_pic->U_PIXELS = p_pic->Y_PIXELS + p_vout->output.i_height * p_vout->output.i_width;
631             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
632             p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
633             p_pic->p[U_PLANE].i_pitch = p_vout->output.i_width / 2;
634             p_pic->p[U_PLANE].i_pixel_pitch = 1;
635             p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
636
637             /* V buffer */
638             p_pic->V_PIXELS = p_pic->U_PIXELS + p_vout->output.i_height * p_vout->output.i_width / 4;
639             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
640             p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
641             p_pic->p[V_PLANE].i_pitch = p_vout->output.i_width / 2;
642             p_pic->p[V_PLANE].i_pixel_pitch = 1;
643             p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
644
645             /* We allocated 3 planes */
646             p_pic->i_planes = 3;
647
648 #define P p_pic->p_sys->pixmap_i420
649             P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
650                                        - p_pic->p_sys->p_data;
651             P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
652                                         - p_pic->p_sys->p_data;
653             P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
654                                         - p_pic->p_sys->p_data;
655
656             P.componentInfoY.rowBytes = p_vout->output.i_width;
657             P.componentInfoCb.rowBytes = p_vout->output.i_width / 2;
658             P.componentInfoCr.rowBytes = p_vout->output.i_width / 2;
659 #undef P
660             break;
661         
662         default:
663             /* Unknown chroma, tell the guy to get lost */
664             free( p_pic->p_sys );
665             msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
666                      p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
667             p_pic->i_planes = 0;
668             return( -1 );
669     }
670
671     return( 0 );
672 }
673
674 /*****************************************************************************
675  * QTFreePicture: destroy a picture allocated with QTNewPicture
676  *****************************************************************************/
677 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
678 {
679     switch( p_vout->output.i_chroma )
680     {
681         case VLC_FOURCC('I','4','2','0'):
682             free( p_pic->p_data_orig );
683             break;
684     }
685
686     free( p_pic->p_sys );
687 }
688
689 /*****************************************************************************
690  * VLCQTView implementation
691  *****************************************************************************/
692 @implementation VLCQTView
693
694 - (id) initWithVout:(vout_thread_t *)_p_vout
695 {
696     p_vout = _p_vout;
697     return [super init];
698 }
699
700 - (void)drawRect:(NSRect)rect
701 {
702     [[NSColor blackColor] set];
703     NSRectFill( rect );
704     [super drawRect: rect];
705
706     p_vout->i_changes |= VOUT_SIZE_CHANGE;
707 }
708
709 @end