]> git.sesse.net Git - vlc/blob - modules/gui/macosx/voutqt.m
* Don't release the VLCWindow on QTClose. The mainthread still needs it.
[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
264     /* Clean Up Quicktime environment */
265     ExitMovies();
266     free( p_vout->p_sys->p_matrix );
267     DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
268
269     [o_pool release];
270     free( p_vout->p_sys );
271 }
272
273 /*****************************************************************************
274  * InitVideo: initialize video thread output method
275  *****************************************************************************/
276 static int InitVideo    ( vout_thread_t *p_vout )
277 {
278     picture_t *p_pic;
279     int i_index;
280
281     I_OUTPUTPICTURES = 0;
282
283     /* Initialize the output structure; we already found a codec,
284      * and the corresponding chroma we will be using. Since we can
285      * arbitrary scale, stick to the coordinates and aspect. */
286     p_vout->output.i_width  = p_vout->render.i_width;
287     p_vout->output.i_height = p_vout->render.i_height;
288     p_vout->output.i_aspect = p_vout->render.i_aspect;
289
290     SetPort( p_vout->p_sys->p_qdport );
291     QTScaleMatrix( p_vout );
292
293     if( QTCreateSequence( p_vout ) )
294     {
295         msg_Err( p_vout, "unable to create sequence" );
296         return( 1 );
297     }
298
299     /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
300     while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
301     {
302         p_pic = NULL;
303
304         /* Find an empty picture slot */
305         for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
306         {
307             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
308             {
309                 p_pic = p_vout->p_picture + i_index;
310                 break;
311             }
312         }
313
314         /* Allocate the picture */
315         if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
316         {
317             break;
318         }
319
320         p_pic->i_status = DESTROYED_PICTURE;
321         p_pic->i_type   = DIRECT_PICTURE;
322
323         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
324         I_OUTPUTPICTURES++;
325     }
326     return 0;
327 }
328
329 /*****************************************************************************
330  * EndVideo: terminate video thread output method
331  *****************************************************************************/
332 static void EndVideo( vout_thread_t *p_vout )
333 {
334     int i_index;
335
336     QTDestroySequence( p_vout );
337
338     /* Free the direct buffers we allocated */
339     for( i_index = I_OUTPUTPICTURES; i_index; )
340     {
341         i_index--;
342         QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
343     }
344 }
345
346 /*****************************************************************************
347  * ManageVideo: handle events
348  *****************************************************************************
349  * This function should be called regularly by video output thread. It manages
350  * console events. It returns a non null value on error.
351  *****************************************************************************/
352 static int ManageVideo( vout_thread_t *p_vout )
353 {
354     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
355     {
356         if( CoToggleFullscreen( p_vout ) )  
357         {
358             return( 1 );
359         }
360
361         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
362     }
363
364     if( p_vout->i_changes & VOUT_SIZE_CHANGE ) 
365     {
366         QTScaleMatrix( p_vout );
367         SetDSequenceMatrix( p_vout->p_sys->i_seq, 
368                             p_vout->p_sys->p_matrix );
369  
370         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
371     }
372
373     [p_vout->p_sys->o_window manage];
374     
375     return( 0 );
376 }
377
378 /*****************************************************************************
379  * vout_Display: displays previously rendered output
380  *****************************************************************************
381  * This function sends the currently rendered image to the display.
382  *****************************************************************************/
383 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
384 {
385     OSErr err;
386     CodecFlags flags;
387
388     if( ( err = DecompressSequenceFrameWhen( 
389                     p_vout->p_sys->i_seq,
390                     p_pic->p_sys->p_data,
391                     p_pic->p_sys->i_size,                    
392                     codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
393     {
394         msg_Warn( p_vout, "DecompressSequenceFrameWhen failed: %d", err );
395     }
396     else
397     {
398         QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
399     }
400 }
401
402 /*****************************************************************************
403  * ControlVideo: control facility for the vout
404  *****************************************************************************/
405 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
406 {
407     vlc_bool_t b_arg;
408
409     switch( i_query )
410     {
411         case VOUT_SET_STAY_ON_TOP:
412             b_arg = va_arg( args, vlc_bool_t );
413             [p_vout->p_sys->o_window setOnTop: b_arg];
414             return VLC_SUCCESS;
415
416         case VOUT_CLOSE:
417         case VOUT_REPARENT:
418         default:
419             return vout_vaControlDefault( p_vout, i_query, args );
420     }
421 }
422
423 /*****************************************************************************
424  * CoToggleFullscreen: toggle fullscreen 
425  *****************************************************************************
426  * Returns 0 on success, 1 otherwise
427  *****************************************************************************/
428 static int CoToggleFullscreen( vout_thread_t *p_vout )
429 {
430     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
431
432     QTDestroySequence( p_vout );
433
434     if( !p_vout->b_fullscreen )
435     {
436         /* Save window size and position */
437         p_vout->p_sys->s_frame.size =
438             [[p_vout->p_sys->o_window contentView] frame].size;
439         p_vout->p_sys->s_frame.origin =
440             [p_vout->p_sys->o_window frame].origin;
441         p_vout->p_sys->b_saved_frame = VLC_TRUE;
442     }
443     [p_vout->p_sys->o_window close];
444
445     p_vout->b_fullscreen = !p_vout->b_fullscreen;
446
447     if( p_vout->p_sys->b_saved_frame )
448     {
449         p_vout->p_sys->o_window = [[VLCWindow alloc]
450             initWithVout: p_vout frame: &p_vout->p_sys->s_frame];
451     }
452     else
453     {
454         p_vout->p_sys->o_window = [[VLCWindow alloc]
455             initWithVout: p_vout frame: nil];
456     }
457
458 #define o_qtview p_vout->p_sys->o_qtview
459     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
460     [p_vout->p_sys->o_window setContentView: o_qtview];
461     [o_qtview autorelease];
462
463     /* Retrieve the QuickDraw port */
464     [o_qtview lockFocus];
465     p_vout->p_sys->p_qdport = [o_qtview qdPort];
466     [o_qtview unlockFocus];
467 #undef o_qtview
468
469     SetPort( p_vout->p_sys->p_qdport );
470     QTScaleMatrix( p_vout );
471
472     if( QTCreateSequence( p_vout ) )
473     {
474         msg_Err( p_vout, "unable to create sequence" );
475         return( 1 ); 
476     } 
477
478     [o_pool release];
479     return 0;
480 }
481
482 /*****************************************************************************
483  * QTScaleMatrix: scale matrix 
484  *****************************************************************************/
485 static void QTScaleMatrix( vout_thread_t *p_vout )
486 {
487     Rect s_rect;
488     vlc_value_t val;
489     unsigned int i_width, i_height;
490     Fixed factor_x, factor_y;
491     unsigned int i_offset_x = 0;
492     unsigned int i_offset_y = 0;
493
494     GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
495
496     i_width = s_rect.right - s_rect.left;
497     i_height = s_rect.bottom - s_rect.top;
498
499     var_Get( p_vout, "macosx-stretch", &val );
500     if( val.b_bool )
501     {
502         factor_x = FixDiv( Long2Fix( i_width ),
503                            Long2Fix( p_vout->output.i_width ) );
504         factor_y = FixDiv( Long2Fix( i_height ),
505                            Long2Fix( p_vout->output.i_height ) );
506                            
507     }
508     else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
509     {
510         int i_adj_width = i_height * p_vout->output.i_aspect /
511                           VOUT_ASPECT_FACTOR;
512
513         factor_x = FixDiv( Long2Fix( i_adj_width ),
514                            Long2Fix( p_vout->output.i_width ) );
515         factor_y = FixDiv( Long2Fix( i_height ),
516                            Long2Fix( p_vout->output.i_height ) );
517
518         i_offset_x = (i_width - i_adj_width) / 2;
519     }
520     else
521     {
522         int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
523                            p_vout->output.i_aspect;
524
525         factor_x = FixDiv( Long2Fix( i_width ),
526                            Long2Fix( p_vout->output.i_width ) );
527         factor_y = FixDiv( Long2Fix( i_adj_height ),
528                            Long2Fix( p_vout->output.i_height ) );
529
530         i_offset_y = (i_height - i_adj_height) / 2;
531     }
532     
533     SetIdentityMatrix( p_vout->p_sys->p_matrix );
534
535     ScaleMatrix( p_vout->p_sys->p_matrix,
536                  factor_x, factor_y,
537                  Long2Fix(0), Long2Fix(0) );
538                  
539     TranslateMatrix( p_vout->p_sys->p_matrix,
540                  Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
541 }
542
543 /*****************************************************************************
544  * QTCreateSequence: create a new sequence 
545  *****************************************************************************
546  * Returns 0 on success, 1 otherwise
547  *****************************************************************************/
548 static int QTCreateSequence( vout_thread_t *p_vout )
549 {
550     OSErr err;
551     ImageDescriptionPtr p_descr;
552
553     HLock( (Handle)p_vout->p_sys->h_img_descr );
554     p_descr = *p_vout->p_sys->h_img_descr;
555
556     p_descr->idSize = sizeof(ImageDescription);
557     p_descr->cType = p_vout->p_sys->i_codec;
558     p_descr->version = 2;
559     p_descr->revisionLevel = 0;
560     p_descr->vendor = 'mpla';
561     p_descr->width = p_vout->output.i_width;
562     p_descr->height = p_vout->output.i_height;
563     p_descr->hRes = Long2Fix(72);
564     p_descr->vRes = Long2Fix(72);
565     p_descr->spatialQuality = codecLosslessQuality;
566     p_descr->frameCount = 1;
567     p_descr->clutID = -1;
568     p_descr->dataSize = 0;
569     p_descr->depth = 24;
570
571     HUnlock( (Handle)p_vout->p_sys->h_img_descr );
572
573     if( ( err = DecompressSequenceBeginS( 
574                               &p_vout->p_sys->i_seq,
575                               p_vout->p_sys->h_img_descr,
576                               NULL,
577                               (p_descr->width * p_descr->height * 16) / 8,
578                               p_vout->p_sys->p_qdport,
579                               NULL, NULL,
580                               p_vout->p_sys->p_matrix,
581                               srcCopy, NULL,
582                               codecFlagUseImageBuffer,
583                               codecLosslessQuality,
584                               bestSpeedCodec ) ) )
585     {
586         msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
587         return( 1 );
588     }
589
590     return( 0 );
591 }
592
593 /*****************************************************************************
594  * QTDestroySequence: destroy sequence 
595  *****************************************************************************/
596 static void QTDestroySequence( vout_thread_t *p_vout )
597 {
598     CDSequenceEnd( p_vout->p_sys->i_seq );
599 }
600
601 /*****************************************************************************
602  * QTNewPicture: allocate a picture
603  *****************************************************************************
604  * Returns 0 on success, 1 otherwise
605  *****************************************************************************/
606 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
607 {
608     /* We know the chroma, allocate a buffer which will be used
609      * directly by the decoder */
610     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
611
612     if( p_pic->p_sys == NULL )
613     {
614         return( -1 );
615     }
616     
617     vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
618                       p_vout->output.i_width, p_vout->output.i_height,
619                       p_vout->output.i_aspect );
620
621     switch( p_vout->output.i_chroma )
622     {
623         case VLC_FOURCC('Y','U','Y','2'):
624             p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
625
626             /* Allocate the memory buffer */
627             p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
628                                           16, p_pic->p_sys->i_size );
629
630             p_pic->p[0].p_pixels = p_pic->p_data;
631             p_pic->p[0].i_lines = p_vout->output.i_height;
632             p_pic->p[0].i_visible_lines = p_vout->output.i_height;
633             p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
634             p_pic->p[0].i_pixel_pitch = 1;
635             p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
636             p_pic->i_planes = 1;
637
638             p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
639
640             break;
641
642     default:
643         /* Unknown chroma, tell the guy to get lost */
644         free( p_pic->p_sys );
645         msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
646                  p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
647         p_pic->i_planes = 0;
648         return( -1 );
649     }
650
651     return( 0 );
652 }
653
654 /*****************************************************************************
655  * QTFreePicture: destroy a picture allocated with QTNewPicture
656  *****************************************************************************/
657 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
658 {
659     switch( p_vout->output.i_chroma )
660     {
661         case VLC_FOURCC('I','4','2','0'):
662             free( p_pic->p_data_orig );
663             break;
664     }
665
666     free( p_pic->p_sys );
667 }
668
669 /*****************************************************************************
670  * VLCQTView implementation
671  *****************************************************************************/
672 @implementation VLCQTView
673
674 - (id) initWithVout:(vout_thread_t *)_p_vout
675 {
676     p_vout = _p_vout;
677     return [super init];
678 }
679
680 - (void)drawRect:(NSRect)rect
681 {
682     [[NSColor blackColor] set];
683     NSRectFill( rect );
684     [super drawRect: rect];
685
686     p_vout->i_changes |= VOUT_SIZE_CHANGE;
687 }
688
689 @end