]> git.sesse.net Git - vlc/blob - modules/gui/macosx/voutqt.m
* ALL: use i_visible_lines in plane_t.
[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     NSRect      s_frame;
65
66     CodecType i_codec;
67     CGrafPtr p_qdport;
68     ImageSequence i_seq;
69     MatrixRecordPtr p_matrix;
70     DecompressorComponent img_dc;
71     ImageDescriptionHandle h_img_descr;
72 };
73
74 struct picture_sys_t
75 {
76     void *p_data;
77     unsigned int i_size;
78 };
79
80 /*****************************************************************************
81  * Local prototypes
82  *****************************************************************************/
83
84 static int  InitVideo           ( vout_thread_t * );
85 static void EndVideo            ( vout_thread_t * );
86 static int  ManageVideo         ( vout_thread_t * );
87 static void DisplayVideo        ( vout_thread_t *, picture_t * );
88 static int  ControlVideo        ( vout_thread_t *, int, va_list );
89
90 static int CoToggleFullscreen( vout_thread_t *p_vout );
91 static void QTScaleMatrix       ( vout_thread_t * );
92 static int  QTCreateSequence    ( vout_thread_t * );
93 static void QTDestroySequence   ( vout_thread_t * );
94 static int  QTNewPicture        ( vout_thread_t *, picture_t * );
95 static void QTFreePicture       ( vout_thread_t *, picture_t * );
96
97 /*****************************************************************************
98  * OpenVideo: allocates MacOS X video thread output method
99  *****************************************************************************
100  * This function allocates and initializes a MacOS X vout method.
101  *****************************************************************************/
102 int E_(OpenVideoQT) ( vlc_object_t *p_this )
103 {   
104     vout_thread_t * p_vout = (vout_thread_t *)p_this;
105     vlc_value_t val;
106     OSErr err;
107     int i_timeout;
108
109     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
110     if( p_vout->p_sys == NULL )
111     {
112         msg_Err( p_vout, "out of memory" );
113         return( 1 );
114     }
115
116     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
117
118     /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
119     for( i_timeout = 20 ; i_timeout-- ; )
120     {
121         if( NSApp == NULL )
122         {
123             msleep( INTF_IDLE_SLEEP );
124         }
125     }
126
127     if( NSApp == NULL )
128     {
129         /* no MacOS X intf, unable to communicate with MT */
130         msg_Err( p_vout, "no MacOS X interface present" );
131         free( p_vout->p_sys );
132         return( 1 );
133     }
134
135     p_vout->pf_init = InitVideo;
136     p_vout->pf_end = EndVideo;
137     p_vout->pf_manage = ManageVideo;
138     p_vout->pf_render = NULL;
139     p_vout->pf_display = DisplayVideo;
140     p_vout->pf_control = ControlVideo;
141
142     p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
143
144     var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
145     var_Create( p_vout, "macosx-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
146     var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
147     var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
148     
149     /* Initialize QuickTime */
150     p_vout->p_sys->h_img_descr = 
151         (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
152     p_vout->p_sys->p_matrix =
153         (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
154
155     if( ( err = EnterMovies() ) != noErr )
156     {
157         msg_Err( p_vout, "EnterMovies failed: %d", err );
158         free( p_vout->p_sys->p_matrix );
159         DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
160         free( p_vout->p_sys );
161         return VLC_EGENERIC;
162     }
163
164     /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
165     vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
166
167     /* Can we find the right chroma ? */
168     err = FindCodec( kComponentVideoUnsigned, bestSpeedCodec,
169                         nil, &p_vout->p_sys->img_dc );
170     
171     vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
172     
173     if( err == noErr && p_vout->p_sys->img_dc != 0 )
174     {
175         p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
176         p_vout->p_sys->i_codec = kComponentVideoUnsigned;
177     }
178     else
179     {
180         msg_Err( p_vout, "failed to find an appropriate codec" );
181     }
182
183     if( p_vout->p_sys->img_dc == 0 )
184     {
185         free( p_vout->p_sys->p_matrix );
186         DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
187         free( p_vout->p_sys );
188         return VLC_EGENERIC;        
189     }
190
191     /* Setup the menuitem for the multiple displays. Read the vlc preference (macosx-vdev) for the primary display */
192     NSArray * o_screens = [NSScreen screens];
193     if( [o_screens count] > 0 && var_Type( p_vout, "video-device" ) == 0 )
194     {
195         int i = 1;
196         vlc_value_t val2, text;
197         NSScreen * o_screen;
198
199         var_Get( p_vout, "macosx-vdev", &val );
200
201         var_Create( p_vout, "video-device", VLC_VAR_INTEGER |
202                                             VLC_VAR_HASCHOICE ); 
203         text.psz_string = _("Video device");
204         var_Change( p_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
205         
206         NSEnumerator * o_enumerator = [o_screens objectEnumerator];
207
208         while( (o_screen = [o_enumerator nextObject]) != NULL )
209         {
210             char psz_temp[255];
211             NSRect s_rect = [o_screen frame];
212
213             snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1, 
214                       "%s %d (%dx%d)", _("Screen"), i,
215                       (int)s_rect.size.width, (int)s_rect.size.height ); 
216
217             text.psz_string = psz_temp;
218             val2.i_int = i;
219             var_Change( p_vout, "video-device",
220                         VLC_VAR_ADDCHOICE, &val2, &text );
221
222             if( ( i - 1 ) == val.i_int )
223             {
224                 var_Set( p_vout, "video-device", val2 );
225             }
226             i++;
227         }
228
229         var_AddCallback( p_vout, "video-device", vout_VarCallback,
230                          NULL );
231
232         val2.b_bool = VLC_TRUE;
233         var_Set( p_vout, "intf-change", val2 );
234     }
235
236     /* Spawn window */
237     p_vout->p_sys->o_window =
238         [[VLCWindow alloc] initWithVout: p_vout frame: nil];
239
240 #define o_qtview p_vout->p_sys->o_qtview
241     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
242     [p_vout->p_sys->o_window setContentView: o_qtview];
243     [o_qtview autorelease];
244
245     /* Retrieve the QuickDraw port */
246     [o_qtview lockFocus];
247     p_vout->p_sys->p_qdport = [o_qtview qdPort];
248     [o_qtview unlockFocus];
249 #undef o_qtview
250
251     return VLC_SUCCESS;
252 }
253
254 /*****************************************************************************
255  * CloseVideo: destroy video thread output method
256  *****************************************************************************/
257 void E_(CloseVideoQT) ( vlc_object_t *p_this )
258 {
259     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; 
260     vout_thread_t * p_vout = (vout_thread_t *)p_this;
261
262     [p_vout->p_sys->o_window close];
263     [p_vout->p_sys->o_window release];
264
265     /* Clean Up Quicktime environment */
266     ExitMovies();
267     free( p_vout->p_sys->p_matrix );
268     DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
269
270     [o_pool release];
271     free( p_vout->p_sys );
272 }
273
274 /*****************************************************************************
275  * InitVideo: initialize video thread output method
276  *****************************************************************************/
277 static int InitVideo    ( vout_thread_t *p_vout )
278 {
279     picture_t *p_pic;
280     int i_index;
281
282     I_OUTPUTPICTURES = 0;
283
284     /* Initialize the output structure; we already found a codec,
285      * and the corresponding chroma we will be using. Since we can
286      * arbitrary scale, stick to the coordinates and aspect. */
287     p_vout->output.i_width  = p_vout->render.i_width;
288     p_vout->output.i_height = p_vout->render.i_height;
289     p_vout->output.i_aspect = p_vout->render.i_aspect;
290
291     SetPort( p_vout->p_sys->p_qdport );
292     QTScaleMatrix( p_vout );
293
294     if( QTCreateSequence( p_vout ) )
295     {
296         msg_Err( p_vout, "unable to create sequence" );
297         return( 1 );
298     }
299
300     /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
301     while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
302     {
303         p_pic = NULL;
304
305         /* Find an empty picture slot */
306         for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
307         {
308             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
309             {
310                 p_pic = p_vout->p_picture + i_index;
311                 break;
312             }
313         }
314
315         /* Allocate the picture */
316         if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
317         {
318             break;
319         }
320
321         p_pic->i_status = DESTROYED_PICTURE;
322         p_pic->i_type   = DIRECT_PICTURE;
323
324         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
325         I_OUTPUTPICTURES++;
326     }
327     return 0;
328 }
329
330 /*****************************************************************************
331  * EndVideo: terminate video thread output method
332  *****************************************************************************/
333 static void EndVideo( vout_thread_t *p_vout )
334 {
335     int i_index;
336
337     QTDestroySequence( p_vout );
338
339     /* Free the direct buffers we allocated */
340     for( i_index = I_OUTPUTPICTURES; i_index; )
341     {
342         i_index--;
343         QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
344     }
345 }
346
347 /*****************************************************************************
348  * ManageVideo: handle events
349  *****************************************************************************
350  * This function should be called regularly by video output thread. It manages
351  * console events. It returns a non null value on error.
352  *****************************************************************************/
353 static int ManageVideo( vout_thread_t *p_vout )
354 {
355     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
356     {
357         if( CoToggleFullscreen( p_vout ) )  
358         {
359             return( 1 );
360         }
361
362         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
363     }
364
365     if( p_vout->i_changes & VOUT_SIZE_CHANGE ) 
366     {
367         QTScaleMatrix( p_vout );
368         SetDSequenceMatrix( p_vout->p_sys->i_seq, 
369                             p_vout->p_sys->p_matrix );
370  
371         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
372     }
373
374     [p_vout->p_sys->o_window manage];
375     
376     return( 0 );
377 }
378
379 /*****************************************************************************
380  * vout_Display: displays previously rendered output
381  *****************************************************************************
382  * This function sends the currently rendered image to the display.
383  *****************************************************************************/
384 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
385 {
386     OSErr err;
387     CodecFlags flags;
388
389     if( ( err = DecompressSequenceFrameWhen( 
390                     p_vout->p_sys->i_seq,
391                     p_pic->p_sys->p_data,
392                     p_pic->p_sys->i_size,                    
393                     codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
394     {
395         msg_Warn( p_vout, "DecompressSequenceFrameWhen failed: %d", err );
396     }
397     else
398     {
399         QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
400     }
401 }
402
403 /*****************************************************************************
404  * ControlVideo: control facility for the vout
405  *****************************************************************************/
406 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
407 {
408     vlc_bool_t b_arg;
409
410     switch( i_query )
411     {
412         case VOUT_SET_STAY_ON_TOP:
413             b_arg = va_arg( args, vlc_bool_t );
414             [p_vout->p_sys->o_window setOnTop: b_arg];
415             return VLC_SUCCESS;
416
417         case VOUT_CLOSE:
418         case VOUT_REPARENT:
419         default:
420             return vout_vaControlDefault( p_vout, i_query, args );
421     }
422 }
423
424 /*****************************************************************************
425  * CoToggleFullscreen: toggle fullscreen 
426  *****************************************************************************
427  * Returns 0 on success, 1 otherwise
428  *****************************************************************************/
429 static int CoToggleFullscreen( vout_thread_t *p_vout )
430 {
431     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
432
433     QTDestroySequence( p_vout );
434
435     if( !p_vout->b_fullscreen )
436     {
437         /* Save window size and position */
438         p_vout->p_sys->s_frame.size =
439             [[p_vout->p_sys->o_window contentView] frame].size;
440         p_vout->p_sys->s_frame.origin =
441             [p_vout->p_sys->o_window frame].origin;
442         p_vout->p_sys->b_saved_frame = VLC_TRUE;
443     }
444     [p_vout->p_sys->o_window close];
445
446     p_vout->b_fullscreen = !p_vout->b_fullscreen;
447
448     if( p_vout->p_sys->b_saved_frame )
449     {
450         p_vout->p_sys->o_window = [[VLCWindow alloc]
451             initWithVout: p_vout frame: &p_vout->p_sys->s_frame];
452     }
453     else
454     {
455         p_vout->p_sys->o_window = [[VLCWindow alloc]
456             initWithVout: p_vout frame: nil];
457     }
458
459 #define o_qtview p_vout->p_sys->o_qtview
460     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
461     [p_vout->p_sys->o_window setContentView: o_qtview];
462     [o_qtview autorelease];
463
464     /* Retrieve the QuickDraw port */
465     [o_qtview lockFocus];
466     p_vout->p_sys->p_qdport = [o_qtview qdPort];
467     [o_qtview unlockFocus];
468 #undef o_qtview
469
470     SetPort( p_vout->p_sys->p_qdport );
471     QTScaleMatrix( p_vout );
472
473     if( QTCreateSequence( p_vout ) )
474     {
475         msg_Err( p_vout, "unable to create sequence" );
476         return( 1 ); 
477     } 
478
479     [o_pool release];
480     return 0;
481 }
482
483 /*****************************************************************************
484  * QTScaleMatrix: scale matrix 
485  *****************************************************************************/
486 static void QTScaleMatrix( vout_thread_t *p_vout )
487 {
488     Rect s_rect;
489     vlc_value_t val;
490     unsigned int i_width, i_height;
491     Fixed factor_x, factor_y;
492     unsigned int i_offset_x = 0;
493     unsigned int i_offset_y = 0;
494
495     GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
496
497     i_width = s_rect.right - s_rect.left;
498     i_height = s_rect.bottom - s_rect.top;
499
500     var_Get( p_vout, "macosx-stretch", &val );
501     if( val.b_bool )
502     {
503         factor_x = FixDiv( Long2Fix( i_width ),
504                            Long2Fix( p_vout->output.i_width ) );
505         factor_y = FixDiv( Long2Fix( i_height ),
506                            Long2Fix( p_vout->output.i_height ) );
507                            
508     }
509     else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
510     {
511         int i_adj_width = i_height * p_vout->output.i_aspect /
512                           VOUT_ASPECT_FACTOR;
513
514         factor_x = FixDiv( Long2Fix( i_adj_width ),
515                            Long2Fix( p_vout->output.i_width ) );
516         factor_y = FixDiv( Long2Fix( i_height ),
517                            Long2Fix( p_vout->output.i_height ) );
518
519         i_offset_x = (i_width - i_adj_width) / 2;
520     }
521     else
522     {
523         int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
524                            p_vout->output.i_aspect;
525
526         factor_x = FixDiv( Long2Fix( i_width ),
527                            Long2Fix( p_vout->output.i_width ) );
528         factor_y = FixDiv( Long2Fix( i_adj_height ),
529                            Long2Fix( p_vout->output.i_height ) );
530
531         i_offset_y = (i_height - i_adj_height) / 2;
532     }
533     
534     SetIdentityMatrix( p_vout->p_sys->p_matrix );
535
536     ScaleMatrix( p_vout->p_sys->p_matrix,
537                  factor_x, factor_y,
538                  Long2Fix(0), Long2Fix(0) );
539                  
540     TranslateMatrix( p_vout->p_sys->p_matrix,
541                  Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
542 }
543
544 /*****************************************************************************
545  * QTCreateSequence: create a new sequence 
546  *****************************************************************************
547  * Returns 0 on success, 1 otherwise
548  *****************************************************************************/
549 static int QTCreateSequence( vout_thread_t *p_vout )
550 {
551     OSErr err;
552     ImageDescriptionPtr p_descr;
553
554     HLock( (Handle)p_vout->p_sys->h_img_descr );
555     p_descr = *p_vout->p_sys->h_img_descr;
556
557     p_descr->idSize = sizeof(ImageDescription);
558     p_descr->cType = p_vout->p_sys->i_codec;
559     p_descr->version = 2;
560     p_descr->revisionLevel = 0;
561     p_descr->vendor = 'mpla';
562     p_descr->width = p_vout->output.i_width;
563     p_descr->height = p_vout->output.i_height;
564     p_descr->hRes = Long2Fix(72);
565     p_descr->vRes = Long2Fix(72);
566     p_descr->spatialQuality = codecLosslessQuality;
567     p_descr->frameCount = 1;
568     p_descr->clutID = -1;
569     p_descr->dataSize = 0;
570     p_descr->depth = 24;
571
572     HUnlock( (Handle)p_vout->p_sys->h_img_descr );
573
574     if( ( err = DecompressSequenceBeginS( 
575                               &p_vout->p_sys->i_seq,
576                               p_vout->p_sys->h_img_descr,
577                               NULL,
578                               (p_descr->width * p_descr->height * 16) / 8,
579                               p_vout->p_sys->p_qdport,
580                               NULL, NULL,
581                               p_vout->p_sys->p_matrix,
582                               srcCopy, NULL,
583                               codecFlagUseImageBuffer,
584                               codecLosslessQuality,
585                               bestSpeedCodec ) ) )
586     {
587         msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
588         return( 1 );
589     }
590
591     return( 0 );
592 }
593
594 /*****************************************************************************
595  * QTDestroySequence: destroy sequence 
596  *****************************************************************************/
597 static void QTDestroySequence( vout_thread_t *p_vout )
598 {
599     CDSequenceEnd( p_vout->p_sys->i_seq );
600 }
601
602 /*****************************************************************************
603  * QTNewPicture: allocate a picture
604  *****************************************************************************
605  * Returns 0 on success, 1 otherwise
606  *****************************************************************************/
607 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
608 {
609     /* We know the chroma, allocate a buffer which will be used
610      * directly by the decoder */
611     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
612
613     if( p_pic->p_sys == NULL )
614     {
615         return( -1 );
616     }
617     
618     vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
619                       p_vout->output.i_width, p_vout->output.i_height,
620                       p_vout->output.i_aspect );
621
622     switch( p_vout->output.i_chroma )
623     {
624         case VLC_FOURCC('Y','U','Y','2'):
625             p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
626
627             /* Allocate the memory buffer */
628             p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
629                                           16, p_pic->p_sys->i_size );
630
631             p_pic->p[0].p_pixels = p_pic->p_data;
632             p_pic->p[0].i_lines = p_vout->output.i_height;
633             p_pic->p[0].i_visible_lines = p_vout->output.i_height;
634             p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
635             p_pic->p[0].i_pixel_pitch = 1;
636             p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
637             p_pic->i_planes = 1;
638
639             p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
640
641             break;
642
643     default:
644         /* Unknown chroma, tell the guy to get lost */
645         free( p_pic->p_sys );
646         msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
647                  p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
648         p_pic->i_planes = 0;
649         return( -1 );
650     }
651
652     return( 0 );
653 }
654
655 /*****************************************************************************
656  * QTFreePicture: destroy a picture allocated with QTNewPicture
657  *****************************************************************************/
658 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
659 {
660     switch( p_vout->output.i_chroma )
661     {
662         case VLC_FOURCC('I','4','2','0'):
663             free( p_pic->p_data_orig );
664             break;
665     }
666
667     free( p_pic->p_sys );
668 }
669
670 /*****************************************************************************
671  * VLCQTView implementation
672  *****************************************************************************/
673 @implementation VLCQTView
674
675 - (id) initWithVout:(vout_thread_t *)_p_vout
676 {
677     p_vout = _p_vout;
678     return [super init];
679 }
680
681 - (void)drawRect:(NSRect)rect
682 {
683     [[NSColor blackColor] set];
684     NSRectFill( rect );
685     [super drawRect: rect];
686
687     p_vout->i_changes |= VOUT_SIZE_CHANGE;
688 }
689
690 @end