]> git.sesse.net Git - vlc/blob - modules/gui/macosx/voutqt.m
* modules/macosx/{vout,voutqt}.m: The Mac OS X Mozilla plugin lives again!
[vlc] / modules / gui / macosx / voutqt.m
1 /*****************************************************************************
2  * vout.m: MacOS X video output module
3  *****************************************************************************
4  * Copyright (C) 2001-2004 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     /* Mozilla plugin-related variables */
75     vlc_bool_t b_embedded;
76     Rect clipping_rect;
77     int portx, porty;
78 };
79
80 struct picture_sys_t
81 {
82     void *p_data;
83     unsigned int i_size;
84     
85     /* When using I420 output */
86     PlanarPixmapInfoYUV420 pixmap_i420;
87 };
88
89 /*****************************************************************************
90  * Local prototypes
91  *****************************************************************************/
92
93 static int  InitVideo           ( vout_thread_t * );
94 static void EndVideo            ( vout_thread_t * );
95 static int  ManageVideo         ( vout_thread_t * );
96 static void DisplayVideo        ( vout_thread_t *, picture_t * );
97 static int  ControlVideo        ( vout_thread_t *, int, va_list );
98
99 static int CoToggleFullscreen( vout_thread_t *p_vout );
100 static void QTScaleMatrix       ( vout_thread_t * );
101 static int  QTCreateSequence    ( vout_thread_t * );
102 static void QTDestroySequence   ( vout_thread_t * );
103 static int  QTNewPicture        ( vout_thread_t *, picture_t * );
104 static void QTFreePicture       ( vout_thread_t *, picture_t * );
105
106 /*****************************************************************************
107  * OpenVideo: allocates MacOS X video thread output method
108  *****************************************************************************
109  * This function allocates and initializes a MacOS X vout method.
110  *****************************************************************************/
111 int E_(OpenVideoQT) ( vlc_object_t *p_this )
112 {
113     vout_thread_t * p_vout = (vout_thread_t *)p_this;
114     OSErr err;
115     vlc_value_t value_drawable;
116
117     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
118     if( p_vout->p_sys == NULL )
119     {
120         msg_Err( p_vout, "out of memory" );
121         return( 1 );
122     }
123
124     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
125
126     p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
127
128     p_vout->pf_init = InitVideo;
129     p_vout->pf_end = EndVideo;
130     p_vout->pf_manage = ManageVideo;
131     p_vout->pf_render = NULL;
132     p_vout->pf_display = DisplayVideo;
133     p_vout->pf_control = ControlVideo;
134
135     /* Are we embedded?  If so, the drawable value will be a pointer to a
136      * CGrafPtr that we're expected to use */
137     var_Get( p_vout->p_vlc, "drawable", &value_drawable );
138     if( value_drawable.i_int != 0 )
139         p_vout->p_sys->b_embedded = VLC_TRUE;
140     else
141         p_vout->p_sys->b_embedded = VLC_FALSE;
142
143     if( p_vout->p_sys->b_embedded )
144     {
145         /* Zero the clipping rectangle */
146         p_vout->p_sys->clipping_rect.left = 0;
147         p_vout->p_sys->clipping_rect.right = 0;
148         p_vout->p_sys->clipping_rect.top = 0;
149         p_vout->p_sys->clipping_rect.bottom = 0;
150     }
151     else
152     {
153         /* Spawn window */
154         p_vout->p_sys->o_window =
155             [[VLCWindow alloc] initWithVout: p_vout frame: nil];
156         if( !p_vout->p_sys->o_window )
157         {
158             return VLC_EGENERIC;
159         }
160     }
161
162     p_vout->p_sys->b_altivec = p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC;
163     msg_Dbg( p_vout, "We do%s have Altivec", p_vout->p_sys->b_altivec ? "" : "n't" );
164     
165     /* Initialize QuickTime */
166     p_vout->p_sys->h_img_descr = 
167         (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
168     p_vout->p_sys->p_matrix =
169         (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
170
171     if( ( err = EnterMovies() ) != noErr )
172     {
173         msg_Err( p_vout, "EnterMovies failed: %d", err );
174         free( p_vout->p_sys->p_matrix );
175         DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
176         free( p_vout->p_sys );
177         return VLC_EGENERIC;
178     }
179
180     /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
181     vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
182
183     /* Can we find the right chroma ? */
184     if( p_vout->p_sys->b_altivec )
185     {
186         err = FindCodec( kYUVSPixelFormat, bestSpeedCodec,
187                         nil, &p_vout->p_sys->img_dc );
188     }
189     else
190     {
191         err = FindCodec( kYUV420CodecType, bestSpeedCodec,
192                         nil, &p_vout->p_sys->img_dc );
193     }
194     vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
195     
196     if( err == noErr && p_vout->p_sys->img_dc != 0 )
197     {
198         if( p_vout->p_sys->b_altivec )
199         {
200             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
201             p_vout->p_sys->i_codec = kYUVSPixelFormat;
202         }
203         else
204         {
205             p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
206             p_vout->p_sys->i_codec = kYUV420CodecType;
207         }
208     }
209     else
210     {
211         msg_Err( p_vout, "failed to find an appropriate codec" );
212     }
213
214     if( p_vout->p_sys->img_dc == 0 )
215     {
216         free( p_vout->p_sys->p_matrix );
217         DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
218         free( p_vout->p_sys );
219         return VLC_EGENERIC;        
220     }
221
222 #define o_qtview p_vout->p_sys->o_qtview
223     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
224     [p_vout->p_sys->o_window setContentView: o_qtview];
225     [o_qtview autorelease];
226
227     /* Retrieve the QuickDraw port */
228     if( p_vout->p_sys->b_embedded )
229     {
230         /* Don't need (nor want) to lock the focus, since otherwise we crash
231          * (presumably because we don't own the window, but I'm not sure
232          * if this is the exact reason)  -andrep */
233         p_vout->p_sys->p_qdport = [o_qtview qdPort];
234     }
235     else
236     {
237         [o_qtview lockFocus];
238         p_vout->p_sys->p_qdport = [o_qtview qdPort];
239         [o_qtview unlockFocus];
240     }
241 #undef o_qtview
242
243     return VLC_SUCCESS;
244 }
245
246 /*****************************************************************************
247  * CloseVideo: destroy video thread output method
248  *****************************************************************************/
249 void E_(CloseVideoQT) ( vlc_object_t *p_this )
250 {
251     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; 
252     vout_thread_t * p_vout = (vout_thread_t *)p_this;
253
254     if( !p_vout->p_sys->b_embedded )
255         [p_vout->p_sys->o_window close];
256
257     /* Clean Up Quicktime environment */
258     ExitMovies();
259     free( p_vout->p_sys->p_matrix );
260     DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
261
262     [o_pool release];
263     free( p_vout->p_sys );
264 }
265
266 /*****************************************************************************
267  * InitVideo: initialize video thread output method
268  *****************************************************************************/
269 static int InitVideo    ( vout_thread_t *p_vout )
270 {
271     picture_t *p_pic;
272     int i_index;
273
274     I_OUTPUTPICTURES = 0;
275
276     /* Initialize the output structure; we already found a codec,
277      * and the corresponding chroma we will be using. Since we can
278      * arbitrary scale, stick to the coordinates and aspect. */
279     p_vout->output.i_width  = p_vout->render.i_width;
280     p_vout->output.i_height = p_vout->render.i_height;
281     p_vout->output.i_aspect = p_vout->render.i_aspect;
282
283     /* If we are embedded (e.g. running as a Mozilla plugin), use the pointer
284      * stored in the "drawable" value as the CGrafPtr for the QuickDraw
285      * graphics port */
286     if( p_vout->p_sys->b_embedded )
287     {
288         vlc_value_t val;
289         var_Get( p_vout->p_vlc, "drawable", &val );
290         p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
291     }
292
293     SetPort( p_vout->p_sys->p_qdport );
294     QTScaleMatrix( p_vout );
295
296     if( QTCreateSequence( p_vout ) )
297     {
298         msg_Err( p_vout, "unable to create sequence" );
299         return( 1 );
300     }
301
302     /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
303     while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
304     {
305         p_pic = NULL;
306
307         /* Find an empty picture slot */
308         for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
309         {
310             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
311             {
312                 p_pic = p_vout->p_picture + i_index;
313                 break;
314             }
315         }
316
317         /* Allocate the picture */
318         if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
319         {
320             break;
321         }
322
323         p_pic->i_status = DESTROYED_PICTURE;
324         p_pic->i_type   = DIRECT_PICTURE;
325
326         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
327         I_OUTPUTPICTURES++;
328     }
329     return 0;
330 }
331
332 /*****************************************************************************
333  * EndVideo: terminate video thread output method
334  *****************************************************************************/
335 static void EndVideo( vout_thread_t *p_vout )
336 {
337     int i_index;
338
339     QTDestroySequence( p_vout );
340
341     /* Free the direct buffers we allocated */
342     for( i_index = I_OUTPUTPICTURES; i_index; )
343     {
344         i_index--;
345         QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
346     }
347 }
348
349 /*****************************************************************************
350  * ManageVideo: handle events
351  *****************************************************************************
352  * This function should be called regularly by video output thread. It manages
353  * console events. It returns a non null value on error.
354  *****************************************************************************/
355 static int ManageVideo( vout_thread_t *p_vout )
356 {
357     vlc_value_t val;
358     var_Get( p_vout->p_vlc, "drawableredraw", &val );
359
360     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
361     {
362         if( CoToggleFullscreen( p_vout ) )  
363         {
364             return( 1 );
365         }
366
367         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
368     }
369
370     if( p_vout->p_sys->b_embedded && val.i_int == 1 )
371     {
372         /* If we're embedded, the application is expected to indicate a
373          * window change (move/resize/etc) via the "drawableredraw" value.
374          * If that's the case, set the VOUT_SIZE_CHANGE flag so we do
375          * actually handle the window change. */
376         val.i_int = 0;
377         var_Set( p_vout->p_vlc, "drawableredraw", val );
378
379         p_vout->i_changes |= VOUT_SIZE_CHANGE;
380     }
381
382     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
383     {
384         QTScaleMatrix( p_vout );
385         SetDSequenceMatrix( p_vout->p_sys->i_seq,
386                             p_vout->p_sys->p_matrix );
387         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
388     }
389
390     [p_vout->p_sys->o_window manage];
391
392     return( 0 );
393 }
394
395 /*****************************************************************************
396  * vout_Display: displays previously rendered output
397  *****************************************************************************
398  * This function sends the currently rendered image to the display.
399  *****************************************************************************/
400 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
401 {
402     OSErr err;
403     CodecFlags flags;
404
405     Rect saved_rect;
406     RgnHandle saved_clip;
407
408     saved_clip = NewRgn();
409
410     if( p_vout->p_sys->b_embedded )
411     {
412         /* In the Mozilla plugin, the browser also draws things in the windows.
413          * So, we have to update the origin and clipping rectangle for each
414          * picture.  FIXME: The vout should probably lock something ... */
415
416         /* Save the origin and clipping rectangle used by the host application
417          * (e.g. Mozilla), so we can restore it later */
418         GetPortBounds( p_vout->p_sys->p_qdport, &saved_rect );
419         GetClip( saved_clip );
420
421         /* The port gets unlocked at the end of this function */
422         LockPortBits( p_vout->p_sys->p_qdport );
423
424         /* Change the origin and clipping to the coordinates that the embedded
425          * window wants to draw at */
426         SetPort( p_vout->p_sys->p_qdport );
427         SetOrigin( p_vout->p_sys->portx , p_vout->p_sys->porty );
428         ClipRect( &p_vout->p_sys->clipping_rect );
429     }
430
431     if( ( err = DecompressSequenceFrameWhen(
432                     p_vout->p_sys->i_seq,
433                     p_pic->p_sys->p_data,
434                     p_pic->p_sys->i_size,
435                     codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
436     {
437         msg_Warn( p_vout, "DecompressSequenceFrameWhen failed: %d", err );
438     }
439     else
440     {
441         if( !p_vout->p_sys->b_embedded )
442             QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
443     }
444
445     if( p_vout->p_sys->b_embedded )
446     {
447         /* Restore the origin and clipping rectangle to the settings used
448          * by the host application */
449         SetOrigin( saved_rect.left, saved_rect.top );
450         SetClip( saved_clip );
451
452         UnlockPortBits( p_vout->p_sys->p_qdport );
453     }
454 }
455
456 /*****************************************************************************
457  * ControlVideo: control facility for the vout
458  *****************************************************************************/
459 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
460 {
461     vlc_bool_t b_arg;
462
463     switch( i_query )
464     {
465         case VOUT_SET_STAY_ON_TOP:
466             b_arg = va_arg( args, vlc_bool_t );
467             [p_vout->p_sys->o_window setOnTop: b_arg];
468             return VLC_SUCCESS;
469
470         case VOUT_CLOSE:
471         case VOUT_REPARENT:
472         default:
473             return vout_vaControlDefault( p_vout, i_query, args );
474     }
475 }
476
477 /*****************************************************************************
478  * CoToggleFullscreen: toggle fullscreen 
479  *****************************************************************************
480  * Returns 0 on success, 1 otherwise
481  *****************************************************************************/
482 static int CoToggleFullscreen( vout_thread_t *p_vout )
483 {
484     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
485
486     QTDestroySequence( p_vout );
487
488     if( !p_vout->b_fullscreen )
489     {
490         /* Save window size and position */
491         p_vout->p_sys->s_frame.size =
492             [[p_vout->p_sys->o_window contentView] frame].size;
493         p_vout->p_sys->s_frame.origin =
494             [p_vout->p_sys->o_window frame].origin;
495         p_vout->p_sys->b_saved_frame = VLC_TRUE;
496     }
497     [p_vout->p_sys->o_window close];
498
499     p_vout->b_fullscreen = !p_vout->b_fullscreen;
500
501     if( p_vout->p_sys->b_saved_frame )
502     {
503         p_vout->p_sys->o_window = [[VLCWindow alloc]
504             initWithVout: p_vout frame: &p_vout->p_sys->s_frame];
505     }
506     else
507     {
508         p_vout->p_sys->o_window = [[VLCWindow alloc]
509             initWithVout: p_vout frame: nil];
510     }
511
512 #define o_qtview p_vout->p_sys->o_qtview
513     o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
514     [p_vout->p_sys->o_window setContentView: o_qtview];
515     [o_qtview autorelease];
516
517     /* Retrieve the QuickDraw port */
518     [o_qtview lockFocus];
519     p_vout->p_sys->p_qdport = [o_qtview qdPort];
520     [o_qtview unlockFocus];
521 #undef o_qtview
522
523     SetPort( p_vout->p_sys->p_qdport );
524     QTScaleMatrix( p_vout );
525
526     if( QTCreateSequence( p_vout ) )
527     {
528         msg_Err( p_vout, "unable to create sequence" );
529         return( 1 ); 
530     } 
531
532     [o_pool release];
533     return 0;
534 }
535
536 /*****************************************************************************
537  * QTScaleMatrix: scale matrix 
538  *****************************************************************************/
539 static void QTScaleMatrix( vout_thread_t *p_vout )
540 {
541     Rect s_rect;
542     vlc_value_t val;
543     unsigned int i_width, i_height;
544     Fixed factor_x, factor_y;
545     unsigned int i_offset_x = 0;
546     unsigned int i_offset_y = 0;
547
548     GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
549
550     i_width = s_rect.right - s_rect.left;
551     i_height = s_rect.bottom - s_rect.top;
552
553     if( p_vout->p_sys->b_embedded )
554     {
555         /* Embedded video get their drawing region from the host application
556          * by the drawable values here.  Read those variables, and store them
557          * in the p_vout->p_sys structure so that other functions (such as
558          * DisplayVideo and ManageVideo) can use them later. */
559         vlc_value_t valt, vall, valb, valr, valx, valy, valw, valh,
560                     valportx, valporty;
561
562         var_Get( p_vout->p_vlc, "drawable", &val );
563         var_Get( p_vout->p_vlc, "drawablet", &valt );
564         var_Get( p_vout->p_vlc, "drawablel", &vall );
565         var_Get( p_vout->p_vlc, "drawableb", &valb );
566         var_Get( p_vout->p_vlc, "drawabler", &valr );
567         var_Get( p_vout->p_vlc, "drawablex", &valx );
568         var_Get( p_vout->p_vlc, "drawabley", &valy );
569         var_Get( p_vout->p_vlc, "drawablew", &valw );
570         var_Get( p_vout->p_vlc, "drawableh", &valh );
571         var_Get( p_vout->p_vlc, "drawableportx", &valportx );
572         var_Get( p_vout->p_vlc, "drawableporty", &valporty );
573
574         p_vout->p_sys->portx = valportx.i_int;
575         p_vout->p_sys->porty = valporty.i_int;
576         p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
577         i_width = valw.i_int;
578         i_height = valh.i_int;
579
580         p_vout->p_sys->clipping_rect.top = 0;
581         p_vout->p_sys->clipping_rect.left = 0;
582         p_vout->p_sys->clipping_rect.bottom = valb.i_int - valt.i_int;
583         p_vout->p_sys->clipping_rect.right = valr.i_int - vall.i_int;
584     }
585
586     var_Get( p_vout, "macosx-stretch", &val );
587     if( val.b_bool )
588     {
589         factor_x = FixDiv( Long2Fix( i_width ),
590                            Long2Fix( p_vout->output.i_width ) );
591         factor_y = FixDiv( Long2Fix( i_height ),
592                            Long2Fix( p_vout->output.i_height ) );
593
594     }
595     else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
596     {
597         int i_adj_width = i_height * p_vout->output.i_aspect /
598                           VOUT_ASPECT_FACTOR;
599
600         factor_x = FixDiv( Long2Fix( i_adj_width ),
601                            Long2Fix( p_vout->output.i_width ) );
602         factor_y = FixDiv( Long2Fix( i_height ),
603                            Long2Fix( p_vout->output.i_height ) );
604
605         i_offset_x = (i_width - i_adj_width) / 2;
606     }
607     else
608     {
609         int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
610                            p_vout->output.i_aspect;
611
612         factor_x = FixDiv( Long2Fix( i_width ),
613                            Long2Fix( p_vout->output.i_width ) );
614         factor_y = FixDiv( Long2Fix( i_adj_height ),
615                            Long2Fix( p_vout->output.i_height ) );
616
617         i_offset_y = (i_height - i_adj_height) / 2;
618     }
619
620     SetIdentityMatrix( p_vout->p_sys->p_matrix );
621
622     ScaleMatrix( p_vout->p_sys->p_matrix,
623                  factor_x, factor_y,
624                  Long2Fix(0), Long2Fix(0) );
625
626     TranslateMatrix( p_vout->p_sys->p_matrix,
627                  Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
628 }
629
630 /*****************************************************************************
631  * QTCreateSequence: create a new sequence 
632  *****************************************************************************
633  * Returns 0 on success, 1 otherwise
634  *****************************************************************************/
635 static int QTCreateSequence( vout_thread_t *p_vout )
636 {
637     OSErr err;
638     ImageDescriptionPtr p_descr;
639
640     HLock( (Handle)p_vout->p_sys->h_img_descr );
641     p_descr = *p_vout->p_sys->h_img_descr;
642
643     p_descr->idSize = sizeof(ImageDescription);
644     p_descr->cType = p_vout->p_sys->i_codec;
645     p_descr->version = 2;
646     p_descr->revisionLevel = 0;
647     p_descr->vendor = 'mpla';
648     p_descr->width = p_vout->output.i_width;
649     p_descr->height = p_vout->output.i_height;
650     p_descr->hRes = Long2Fix(72);
651     p_descr->vRes = Long2Fix(72);
652     p_descr->spatialQuality = codecLosslessQuality;
653     p_descr->frameCount = 1;
654     p_descr->clutID = -1;
655     p_descr->dataSize = 0;
656     p_descr->depth = 24;
657
658     HUnlock( (Handle)p_vout->p_sys->h_img_descr );
659
660     if( ( err = DecompressSequenceBeginS( 
661                               &p_vout->p_sys->i_seq,
662                               p_vout->p_sys->h_img_descr,
663                               NULL,
664                               (p_descr->width * p_descr->height * 16) / 8,
665                               p_vout->p_sys->p_qdport,
666                               NULL, NULL,
667                               p_vout->p_sys->p_matrix,
668                               srcCopy, NULL,
669                               codecFlagUseImageBuffer,
670                               codecLosslessQuality,
671                               bestSpeedCodec ) ) )
672     {
673         msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
674         return( 1 );
675     }
676
677     return( 0 );
678 }
679
680 /*****************************************************************************
681  * QTDestroySequence: destroy sequence 
682  *****************************************************************************/
683 static void QTDestroySequence( vout_thread_t *p_vout )
684 {
685     CDSequenceEnd( p_vout->p_sys->i_seq );
686 }
687
688 /*****************************************************************************
689  * QTNewPicture: allocate a picture
690  *****************************************************************************
691  * Returns 0 on success, 1 otherwise
692  *****************************************************************************/
693 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
694 {
695     /* We know the chroma, allocate a buffer which will be used
696      * directly by the decoder */
697     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
698
699     if( p_pic->p_sys == NULL )
700     {
701         return( -1 );
702     }
703
704     vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
705                       p_vout->output.i_width, p_vout->output.i_height,
706                       p_vout->output.i_aspect );
707
708     switch( p_vout->output.i_chroma )
709     {
710         case VLC_FOURCC('Y','U','Y','2'):
711             p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
712
713             /* Allocate the memory buffer */
714             p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
715                                           16, p_pic->p_sys->i_size );
716
717             p_pic->p[0].p_pixels = p_pic->p_data;
718             p_pic->p[0].i_lines = p_vout->output.i_height;
719             p_pic->p[0].i_visible_lines = p_vout->output.i_height;
720             p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
721             p_pic->p[0].i_pixel_pitch = 1;
722             p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
723             p_pic->i_planes = 1;
724
725             p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
726
727             break;
728             
729         case VLC_FOURCC('I','4','2','0'):
730             p_pic->p_sys->p_data = (void *)&p_pic->p_sys->pixmap_i420;
731             p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
732             
733             /* Allocate the memory buffer */
734             p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
735                                           16, p_vout->output.i_width * p_vout->output.i_height * 3 / 2 );
736
737             /* Y buffer */
738             p_pic->Y_PIXELS = p_pic->p_data; 
739             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
740             p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
741             p_pic->p[Y_PLANE].i_pitch = p_vout->output.i_width;
742             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
743             p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width;
744
745             /* U buffer */
746             p_pic->U_PIXELS = p_pic->Y_PIXELS + p_vout->output.i_height * p_vout->output.i_width;
747             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
748             p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
749             p_pic->p[U_PLANE].i_pitch = p_vout->output.i_width / 2;
750             p_pic->p[U_PLANE].i_pixel_pitch = 1;
751             p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
752
753             /* V buffer */
754             p_pic->V_PIXELS = p_pic->U_PIXELS + p_vout->output.i_height * p_vout->output.i_width / 4;
755             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
756             p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
757             p_pic->p[V_PLANE].i_pitch = p_vout->output.i_width / 2;
758             p_pic->p[V_PLANE].i_pixel_pitch = 1;
759             p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
760
761             /* We allocated 3 planes */
762             p_pic->i_planes = 3;
763
764 #define P p_pic->p_sys->pixmap_i420
765             P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
766                                        - p_pic->p_sys->p_data;
767             P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
768                                         - p_pic->p_sys->p_data;
769             P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
770                                         - p_pic->p_sys->p_data;
771
772             P.componentInfoY.rowBytes = p_vout->output.i_width;
773             P.componentInfoCb.rowBytes = p_vout->output.i_width / 2;
774             P.componentInfoCr.rowBytes = p_vout->output.i_width / 2;
775 #undef P
776             break;
777         
778         default:
779             /* Unknown chroma, tell the guy to get lost */
780             free( p_pic->p_sys );
781             msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
782                      p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
783             p_pic->i_planes = 0;
784             return( -1 );
785     }
786
787     return( 0 );
788 }
789
790 /*****************************************************************************
791  * QTFreePicture: destroy a picture allocated with QTNewPicture
792  *****************************************************************************/
793 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
794 {
795     switch( p_vout->output.i_chroma )
796     {
797         case VLC_FOURCC('I','4','2','0'):
798             free( p_pic->p_data_orig );
799             break;
800     }
801
802     free( p_pic->p_sys );
803 }
804
805 /*****************************************************************************
806  * VLCQTView implementation
807  *****************************************************************************/
808 @implementation VLCQTView
809
810 - (id) initWithVout:(vout_thread_t *)_p_vout
811 {
812     p_vout = _p_vout;
813     return [super init];
814 }
815
816 - (void)drawRect:(NSRect)rect
817 {
818     [[NSColor blackColor] set];
819     NSRectFill( rect );
820     [super drawRect: rect];
821
822     p_vout->i_changes |= VOUT_SIZE_CHANGE;
823 }
824
825 @end