1 /*****************************************************************************
2 * vout.m: MacOS X video output module
3 *****************************************************************************
4 * Copyright (C) 2001-2004 the VideoLAN team
5 * $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
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 * Benjamin Pracht <bigben AT videolan DOT org>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
32 #include <errno.h> /* ENOMEM */
33 #include <stdlib.h> /* free() */
34 #include <string.h> /* strerror() */
36 #include <QuickTime/QuickTime.h>
43 #define QT_MAX_DIRECTBUFFERS 10
44 #define VL_MAX_DISPLAYS 16
46 /*****************************************************************************
48 *****************************************************************************/
49 @interface VLCQTView : NSQuickDrawView
51 vout_thread_t * p_vout;
54 - (id) initWithVout:(vout_thread_t *)p_vout;
60 NSAutoreleasePool *o_pool;
62 VLCVoutView * o_vout_view;
64 vlc_bool_t b_saved_frame;
65 vlc_bool_t b_cpu_has_simd; /* does CPU supports Altivec, MMX, etc... */
71 MatrixRecordPtr p_matrix;
72 DecompressorComponent img_dc;
73 ImageDescriptionHandle h_img_descr;
75 /* video geometry in port */
77 int i_width, i_height;
78 /* Mozilla plugin-related variables */
79 vlc_bool_t b_embedded;
88 /* When using I420 output */
89 PlanarPixmapInfoYUV420 pixmap_i420;
92 /*****************************************************************************
94 *****************************************************************************/
96 static int InitVideo ( vout_thread_t * );
97 static void EndVideo ( vout_thread_t * );
98 static int ManageVideo ( vout_thread_t * );
99 static void DisplayVideo ( vout_thread_t *, picture_t * );
100 static int ControlVideo ( vout_thread_t *, int, va_list );
102 static int CoToggleFullscreen( vout_thread_t *p_vout );
103 static int DrawableRedraw( vlc_object_t *p_this, const char *psz_name,
104 vlc_value_t oval, vlc_value_t nval, void *param);
105 static void UpdateEmbeddedGeometry( vout_thread_t *p_vout );
106 static void QTScaleMatrix ( vout_thread_t * );
107 static int QTCreateSequence ( vout_thread_t * );
108 static void QTDestroySequence ( vout_thread_t * );
109 static int QTNewPicture ( vout_thread_t *, picture_t * );
110 static void QTFreePicture ( vout_thread_t *, picture_t * );
112 /*****************************************************************************
113 * OpenVideo: allocates MacOS X video thread output method
114 *****************************************************************************
115 * This function allocates and initializes a MacOS X vout method.
116 *****************************************************************************/
117 int E_(OpenVideoQT) ( vlc_object_t *p_this )
119 vout_thread_t * p_vout = (vout_thread_t *)p_this;
121 vlc_value_t value_drawable;
123 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
124 if( p_vout->p_sys == NULL )
126 msg_Err( p_vout, "out of memory" );
130 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
132 p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
134 p_vout->pf_init = InitVideo;
135 p_vout->pf_end = EndVideo;
136 p_vout->pf_manage = ManageVideo;
137 p_vout->pf_render = NULL;
138 p_vout->pf_display = DisplayVideo;
139 p_vout->pf_control = ControlVideo;
141 /* Are we embedded? If so, the drawable value will be a pointer to a
142 * CGrafPtr that we're expected to use */
143 var_Get( p_vout->p_vlc, "drawable", &value_drawable );
144 if( value_drawable.i_int != 0 )
145 p_vout->p_sys->b_embedded = VLC_TRUE;
147 p_vout->p_sys->b_embedded = VLC_FALSE;
149 p_vout->p_sys->b_cpu_has_simd = (p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC)
150 | (p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT);
151 msg_Dbg( p_vout, "we do%s have SIMD enabled CPU", p_vout->p_sys->b_cpu_has_simd ? "" : "n't" );
153 /* Initialize QuickTime */
154 p_vout->p_sys->h_img_descr =
155 (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
156 p_vout->p_sys->p_matrix =
157 (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
159 if( ( err = EnterMovies() ) != noErr )
161 msg_Err( p_vout, "QT initialization failed: EnterMovies failed: %d", err );
162 free( p_vout->p_sys->p_matrix );
163 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
164 free( p_vout->p_sys );
168 /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
169 vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
171 /* Can we find the right chroma ? */
172 if( p_vout->p_sys->b_cpu_has_simd )
174 err = FindCodec( kYUVSPixelFormat, bestSpeedCodec,
175 nil, &p_vout->p_sys->img_dc );
179 err = FindCodec( kYUV420CodecType, bestSpeedCodec,
180 nil, &p_vout->p_sys->img_dc );
182 vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
184 if( err == noErr && p_vout->p_sys->img_dc != 0 )
186 if( p_vout->p_sys->b_cpu_has_simd )
188 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
189 p_vout->p_sys->i_codec = kYUVSPixelFormat;
193 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
194 p_vout->p_sys->i_codec = kYUV420CodecType;
199 msg_Err( p_vout, "QT doesn't support any appropriate chroma" );
202 if( p_vout->p_sys->img_dc == 0 )
204 free( p_vout->p_sys->p_matrix );
205 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
206 free( p_vout->p_sys );
210 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
213 #define o_qtview p_vout->p_sys->o_qtview
214 o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
215 [o_qtview autorelease];
217 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
218 subView: o_qtview frame: nil];
219 if( !p_vout->p_sys->o_vout_view )
223 [o_qtview lockFocus];
224 p_vout->p_sys->p_qdport = [o_qtview qdPort];
225 [o_qtview unlockFocus];
232 /*****************************************************************************
233 * CloseVideo: destroy video thread output method
234 *****************************************************************************/
235 void E_(CloseVideoQT) ( vlc_object_t *p_this )
237 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
238 vout_thread_t * p_vout = (vout_thread_t *)p_this;
240 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
241 [p_vout->p_sys->o_vout_view closeVout];
243 /* Clean Up Quicktime environment */
245 free( p_vout->p_sys->p_matrix );
246 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
249 free( p_vout->p_sys );
252 /*****************************************************************************
253 * InitVideo: initialize video thread output method
254 *****************************************************************************/
255 static int InitVideo ( vout_thread_t *p_vout )
260 I_OUTPUTPICTURES = 0;
262 /* Initialize the output structure; we already found a codec,
263 * and the corresponding chroma we will be using. Since we can
264 * arbitrary scale, stick to the coordinates and aspect. */
265 p_vout->output.i_width = p_vout->render.i_width;
266 p_vout->output.i_height = p_vout->render.i_height;
267 p_vout->output.i_aspect = p_vout->render.i_aspect;
269 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
272 p_vout->p_sys->clip_mask = NULL;
273 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
274 p_vout->p_sys->i_origx = s_rect.left;
275 p_vout->p_sys->i_origy = s_rect.top;
276 p_vout->p_sys->i_width = s_rect.right - s_rect.left;
277 p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
281 /* As we are embedded (e.g. running as a Mozilla plugin), use the pointer
282 * stored in the "drawable" value as the CGrafPtr for the QuickDraw
284 /* Create the clipping mask */
285 p_vout->p_sys->clip_mask = NewRgn();
286 UpdateEmbeddedGeometry(p_vout);
287 var_AddCallback(p_vout->p_vlc, "drawableredraw", DrawableRedraw, p_vout);
290 QTScaleMatrix( p_vout );
292 if( QTCreateSequence( p_vout ) )
294 msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
298 /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
299 while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
303 /* Find an empty picture slot */
304 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
306 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
308 p_pic = p_vout->p_picture + i_index;
313 /* Allocate the picture */
314 if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
319 p_pic->i_status = DESTROYED_PICTURE;
320 p_pic->i_type = DIRECT_PICTURE;
322 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
328 /*****************************************************************************
329 * EndVideo: terminate video thread output method
330 *****************************************************************************/
331 static void EndVideo( vout_thread_t *p_vout )
335 QTDestroySequence( p_vout );
337 if( !p_vout->b_fullscreen && p_vout->p_sys->b_embedded )
339 var_DelCallback(p_vout->p_vlc, "drawableredraw", DrawableRedraw, p_vout);
340 DisposeRgn(p_vout->p_sys->clip_mask);
343 /* Free the direct buffers we allocated */
344 for( i_index = I_OUTPUTPICTURES; i_index; )
347 QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
351 /*****************************************************************************
352 * ManageVideo: handle events
353 *****************************************************************************
354 * This function should be called regularly by video output thread. It manages
355 * console events. It returns a non null value on error.
356 *****************************************************************************/
357 static int ManageVideo( vout_thread_t *p_vout )
359 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
361 if( CoToggleFullscreen( p_vout ) )
366 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
369 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
371 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
373 /* get the geometry from NSQuickDrawView */
375 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
376 p_vout->p_sys->i_origx = s_rect.left;
377 p_vout->p_sys->i_origy = s_rect.top;
378 p_vout->p_sys->i_width = s_rect.right - s_rect.left;
379 p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
383 /* As we're embedded, get the geometry from Mozilla/Safari NPWindow object */
384 UpdateEmbeddedGeometry( p_vout );
385 SetDSequenceMask(p_vout->p_sys->i_seq,
386 p_vout->p_sys->clip_mask);
390 if( p_vout->i_changes & VOUT_SIZE_CHANGE ||
391 p_vout->i_changes & VOUT_ASPECT_CHANGE )
393 QTScaleMatrix( p_vout );
394 SetDSequenceMatrix( p_vout->p_sys->i_seq,
395 p_vout->p_sys->p_matrix );
397 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
399 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
401 if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
403 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
407 [p_vout->p_sys->o_vout_view manage];
412 /*****************************************************************************
413 * vout_Display: displays previously rendered output
414 *****************************************************************************
415 * This function sends the currently rendered image to the display.
416 *****************************************************************************/
417 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
421 if( (NULL == p_vout->p_sys->clip_mask) || !EmptyRgn(p_vout->p_sys->clip_mask) )
426 /* since there is not way to lock a QuickDraw port for exclusive use
427 there is a potential problem that the frame will be displayed
428 in the wrong place if other embedded plugins redraws as the port
429 origin may be changed */
431 //GetPortBounds(p_vout->p_sys->p_qdport, &oldBounds);
432 SetPort(p_vout->p_sys->p_qdport);
433 SetOrigin(p_vout->p_sys->i_origx, p_vout->p_sys->i_origy);
434 if( ( err = DecompressSequenceFrameWhen(
435 p_vout->p_sys->i_seq,
436 p_pic->p_sys->p_data,
437 p_pic->p_sys->i_size,
438 codecFlagUseImageBuffer, &flags, NULL, NULL ) == noErr ) )
440 QDFlushPortBuffer( p_vout->p_sys->p_qdport, p_vout->p_sys->clip_mask );
441 //QDFlushPortBuffer( p_vout->p_sys->p_qdport, NULL );
445 msg_Warn( p_vout, "QT failed to display the frame sequence: %d", err );
447 //SetPortBounds(p_vout->p_sys->p_qdport, &oldBounds);
452 /*****************************************************************************
453 * ControlVideo: control facility for the vout
454 *****************************************************************************/
455 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
461 case VOUT_SET_STAY_ON_TOP:
462 b_arg = va_arg( args, vlc_bool_t );
463 [p_vout->p_sys->o_vout_view setOnTop: b_arg];
469 return vout_vaControlDefault( p_vout, i_query, args );
473 /*****************************************************************************
474 * CoToggleFullscreen: toggle fullscreen
475 *****************************************************************************
476 * Returns 0 on success, 1 otherwise
477 *****************************************************************************/
478 static int CoToggleFullscreen( vout_thread_t *p_vout )
480 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
482 QTDestroySequence( p_vout );
484 if( !p_vout->b_fullscreen )
486 if( !p_vout->p_sys->b_embedded )
488 /* Save window size and position */
489 p_vout->p_sys->s_frame.size =
490 [p_vout->p_sys->o_vout_view frame].size;
491 p_vout->p_sys->s_frame.origin =
492 [[p_vout->p_sys->o_vout_view getWindow] frame].origin;
493 p_vout->p_sys->b_saved_frame = VLC_TRUE;
497 var_DelCallback(p_vout->p_vlc, "drawableredraw", DrawableRedraw, p_vout);
498 DisposeRgn(p_vout->p_sys->clip_mask);
501 [p_vout->p_sys->o_vout_view closeVout];
503 p_vout->b_fullscreen = !p_vout->b_fullscreen;
505 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
508 p_vout->p_sys->clip_mask = NULL;
509 #define o_qtview p_vout->p_sys->o_qtview
510 o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
511 [o_qtview autorelease];
513 if( p_vout->p_sys->b_saved_frame )
515 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
517 frame: &p_vout->p_sys->s_frame];
521 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
522 subView: o_qtview frame: nil];
525 /* Retrieve the QuickDraw port */
526 [o_qtview lockFocus];
527 p_vout->p_sys->p_qdport = [o_qtview qdPort];
528 [o_qtview unlockFocus];
530 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
531 p_vout->p_sys->i_origx = s_rect.left;
532 p_vout->p_sys->i_origy = s_rect.top;
533 p_vout->p_sys->i_width = s_rect.right - s_rect.left;
534 p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
538 /* Create the clipping mask */
539 p_vout->p_sys->clip_mask = NewRgn();
540 UpdateEmbeddedGeometry(p_vout);
541 var_AddCallback(p_vout->p_vlc, "drawableredraw", DrawableRedraw, p_vout);
543 QTScaleMatrix( p_vout );
545 if( QTCreateSequence( p_vout ) )
547 msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
555 /* If we're embedded, the application is expected to indicate a
556 * window change (move/resize/etc) via the "drawableredraw" value.
557 * If that's the case, set the VOUT_SIZE_CHANGE flag so we do
558 * actually handle the window change. */
560 static int DrawableRedraw( vlc_object_t *p_this, const char *psz_name,
561 vlc_value_t oval, vlc_value_t nval, void *param)
563 /* ignore changes until we are ready for them */
564 if( (oval.i_int != nval.i_int) && (nval.i_int == 1) )
566 vout_thread_t *p_vout = (vout_thread_t *)param;
567 /* prevent QT from rendering any more video until we have updated
569 SetEmptyRgn(p_vout->p_sys->clip_mask);
570 SetDSequenceMask(p_vout->p_sys->i_seq,
571 p_vout->p_sys->clip_mask);
573 p_vout->i_changes |= VOUT_SIZE_CHANGE;
578 /* Embedded video get their drawing region from the host application
579 * by the drawable values here. Read those variables, and store them
580 * in the p_vout->p_sys structure so that other functions (such as
581 * DisplayVideo and ManageVideo) can use them later. */
583 static void UpdateEmbeddedGeometry( vout_thread_t *p_vout )
586 vlc_value_t valt, vall, valb, valr, valx, valy, valw, valh,
589 var_Get( p_vout->p_vlc, "drawable", &val );
590 var_Get( p_vout->p_vlc, "drawablet", &valt );
591 var_Get( p_vout->p_vlc, "drawablel", &vall );
592 var_Get( p_vout->p_vlc, "drawableb", &valb );
593 var_Get( p_vout->p_vlc, "drawabler", &valr );
594 var_Get( p_vout->p_vlc, "drawablex", &valx );
595 var_Get( p_vout->p_vlc, "drawabley", &valy );
596 var_Get( p_vout->p_vlc, "drawablew", &valw );
597 var_Get( p_vout->p_vlc, "drawableh", &valh );
598 var_Get( p_vout->p_vlc, "drawableportx", &valportx );
599 var_Get( p_vout->p_vlc, "drawableporty", &valporty );
601 /* portx, porty contains values for SetOrigin() function
602 which isn't used, instead use QT Translate matrix */
603 p_vout->p_sys->i_origx = valportx.i_int;
604 p_vout->p_sys->i_origy = valporty.i_int;
605 p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
606 p_vout->p_sys->i_width = valw.i_int;
607 p_vout->p_sys->i_height = valh.i_int;
609 /* update video clipping mask */
610 /*SetRectRgn( p_vout->p_sys->clip_mask , vall.i_int ,
611 valt.i_int, valr.i_int, valb.i_int );*/
612 SetRectRgn( p_vout->p_sys->clip_mask , vall.i_int + valportx.i_int ,
613 valt.i_int + valporty.i_int , valr.i_int + valportx.i_int ,
614 valb.i_int + valporty.i_int );
616 /* reset drawableredraw variable indicating we are ready
617 to take changes in video geometry */
619 var_Set( p_vout->p_vlc, "drawableredraw", val );
622 /*****************************************************************************
623 * QTScaleMatrix: scale matrix
624 *****************************************************************************/
625 static void QTScaleMatrix( vout_thread_t *p_vout )
628 Fixed factor_x, factor_y;
629 unsigned int i_offset_x = 0;
630 unsigned int i_offset_y = 0;
631 int i_width = p_vout->p_sys->i_width;
632 int i_height = p_vout->p_sys->i_height;
634 var_Get( p_vout, "macosx-stretch", &val );
637 factor_x = FixDiv( Long2Fix( i_width ),
638 Long2Fix( p_vout->output.i_width ) );
639 factor_y = FixDiv( Long2Fix( i_height ),
640 Long2Fix( p_vout->output.i_height ) );
643 else if( i_height * p_vout->fmt_in.i_visible_width *
644 p_vout->fmt_in.i_sar_num <
645 i_width * p_vout->fmt_in.i_visible_height *
646 p_vout->fmt_in.i_sar_den )
648 int i_adj_width = i_height * p_vout->fmt_in.i_visible_width *
649 p_vout->fmt_in.i_sar_num /
650 ( p_vout->fmt_in.i_sar_den *
651 p_vout->fmt_in.i_visible_height );
653 factor_x = FixDiv( Long2Fix( i_adj_width ),
654 Long2Fix( p_vout->fmt_in.i_visible_width ) );
655 factor_y = FixDiv( Long2Fix( i_height ),
656 Long2Fix( p_vout->fmt_in.i_visible_height ) );
658 i_offset_x = (i_width - i_adj_width) / 2;
662 int i_adj_height = i_width * p_vout->fmt_in.i_visible_height *
663 p_vout->fmt_in.i_sar_den /
664 ( p_vout->fmt_in.i_sar_num *
665 p_vout->fmt_in.i_visible_width );
667 factor_x = FixDiv( Long2Fix( i_width ),
668 Long2Fix( p_vout->fmt_in.i_visible_width ) );
669 factor_y = FixDiv( Long2Fix( i_adj_height ),
670 Long2Fix( p_vout->fmt_in.i_visible_height ) );
672 i_offset_y = (i_height - i_adj_height) / 2;
675 SetIdentityMatrix( p_vout->p_sys->p_matrix );
677 ScaleMatrix( p_vout->p_sys->p_matrix,
679 Long2Fix(0), Long2Fix(0) );
681 TranslateMatrix( p_vout->p_sys->p_matrix,
682 Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
685 /*****************************************************************************
686 * QTCreateSequence: create a new sequence
687 *****************************************************************************
688 * Returns 0 on success, 1 otherwise
689 *****************************************************************************/
690 static int QTCreateSequence( vout_thread_t *p_vout )
693 ImageDescriptionPtr p_descr;
695 HLock( (Handle)p_vout->p_sys->h_img_descr );
696 p_descr = *p_vout->p_sys->h_img_descr;
698 p_descr->idSize = sizeof(ImageDescription);
699 p_descr->cType = p_vout->p_sys->i_codec;
700 p_descr->version = 2;
701 p_descr->revisionLevel = 0;
702 p_descr->vendor = 'mpla';
703 p_descr->width = p_vout->output.i_width;
704 p_descr->height = p_vout->output.i_height;
705 p_descr->hRes = Long2Fix(72);
706 p_descr->vRes = Long2Fix(72);
707 p_descr->spatialQuality = codecLosslessQuality;
708 p_descr->frameCount = 1;
709 p_descr->clutID = -1;
710 p_descr->dataSize = 0;
713 HUnlock( (Handle)p_vout->p_sys->h_img_descr );
715 if( ( err = DecompressSequenceBeginS(
716 &p_vout->p_sys->i_seq,
717 p_vout->p_sys->h_img_descr,
719 (p_descr->width * p_descr->height * 16) / 8,
720 p_vout->p_sys->p_qdport,
722 p_vout->p_sys->p_matrix,
723 srcCopy, p_vout->p_sys->clip_mask,
724 codecFlagUseImageBuffer,
725 codecLosslessQuality,
728 msg_Err( p_vout, "Failed to initialize QT: DecompressSequenceBeginS failed: %d", err );
735 /*****************************************************************************
736 * QTDestroySequence: destroy sequence
737 *****************************************************************************/
738 static void QTDestroySequence( vout_thread_t *p_vout )
740 CDSequenceEnd( p_vout->p_sys->i_seq );
743 /*****************************************************************************
744 * QTNewPicture: allocate a picture
745 *****************************************************************************
746 * Returns 0 on success, 1 otherwise
747 *****************************************************************************/
748 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
750 /* We know the chroma, allocate a buffer which will be used
751 * directly by the decoder */
752 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
754 if( p_pic->p_sys == NULL )
759 vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
760 p_vout->output.i_width, p_vout->output.i_height,
761 p_vout->output.i_aspect );
763 switch( p_vout->output.i_chroma )
765 case VLC_FOURCC('Y','U','Y','2'):
766 p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
768 /* Allocate the memory buffer */
769 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
770 16, p_pic->p_sys->i_size );
772 p_pic->p[0].p_pixels = p_pic->p_data;
773 p_pic->p[0].i_lines = p_vout->output.i_height;
774 p_pic->p[0].i_visible_lines = p_vout->output.i_height;
775 p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
776 p_pic->p[0].i_pixel_pitch = 1;
777 p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
780 p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
784 case VLC_FOURCC('I','4','2','0'):
785 p_pic->p_sys->p_data = (void *)&p_pic->p_sys->pixmap_i420;
786 p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
788 /* Allocate the memory buffer */
789 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
790 16, p_vout->output.i_width * p_vout->output.i_height * 3 / 2 );
793 p_pic->Y_PIXELS = p_pic->p_data;
794 p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
795 p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
796 p_pic->p[Y_PLANE].i_pitch = p_vout->output.i_width;
797 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
798 p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width;
801 p_pic->U_PIXELS = p_pic->Y_PIXELS + p_vout->output.i_height * p_vout->output.i_width;
802 p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
803 p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
804 p_pic->p[U_PLANE].i_pitch = p_vout->output.i_width / 2;
805 p_pic->p[U_PLANE].i_pixel_pitch = 1;
806 p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
809 p_pic->V_PIXELS = p_pic->U_PIXELS + p_vout->output.i_height * p_vout->output.i_width / 4;
810 p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
811 p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
812 p_pic->p[V_PLANE].i_pitch = p_vout->output.i_width / 2;
813 p_pic->p[V_PLANE].i_pixel_pitch = 1;
814 p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
816 /* We allocated 3 planes */
819 #define P p_pic->p_sys->pixmap_i420
820 P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
821 - p_pic->p_sys->p_data;
822 P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
823 - p_pic->p_sys->p_data;
824 P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
825 - p_pic->p_sys->p_data;
827 P.componentInfoY.rowBytes = p_vout->output.i_width;
828 P.componentInfoCb.rowBytes = p_vout->output.i_width / 2;
829 P.componentInfoCr.rowBytes = p_vout->output.i_width / 2;
834 /* Unknown chroma, tell the guy to get lost */
835 free( p_pic->p_sys );
836 msg_Err( p_vout, "Unknown chroma format 0x%.8x (%4.4s)",
837 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
845 /*****************************************************************************
846 * QTFreePicture: destroy a picture allocated with QTNewPicture
847 *****************************************************************************/
848 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
850 switch( p_vout->output.i_chroma )
852 case VLC_FOURCC('I','4','2','0'):
853 free( p_pic->p_data_orig );
857 free( p_pic->p_sys );
860 /*****************************************************************************
861 * VLCQTView implementation
862 *****************************************************************************/
863 @implementation VLCQTView
865 - (id) initWithVout:(vout_thread_t *)_p_vout
871 - (void)drawRect:(NSRect)rect
873 [[NSColor blackColor] set];
875 [super drawRect: rect];
877 p_vout->i_changes |= VOUT_SIZE_CHANGE;