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;
71 MatrixRecordPtr p_matrix;
72 DecompressorComponent img_dc;
73 ImageDescriptionHandle h_img_descr;
75 /* Mozilla plugin-related variables */
76 vlc_bool_t b_embedded;
86 /* When using I420 output */
87 PlanarPixmapInfoYUV420 pixmap_i420;
90 /*****************************************************************************
92 *****************************************************************************/
94 static int InitVideo ( vout_thread_t * );
95 static void EndVideo ( vout_thread_t * );
96 static int ManageVideo ( vout_thread_t * );
97 static void DisplayVideo ( vout_thread_t *, picture_t * );
98 static int ControlVideo ( vout_thread_t *, int, va_list );
100 static int CoToggleFullscreen( vout_thread_t *p_vout );
101 static void QTScaleMatrix ( vout_thread_t * );
102 static int QTCreateSequence ( vout_thread_t * );
103 static void QTDestroySequence ( vout_thread_t * );
104 static int QTNewPicture ( vout_thread_t *, picture_t * );
105 static void QTFreePicture ( vout_thread_t *, picture_t * );
107 /*****************************************************************************
108 * OpenVideo: allocates MacOS X video thread output method
109 *****************************************************************************
110 * This function allocates and initializes a MacOS X vout method.
111 *****************************************************************************/
112 int E_(OpenVideoQT) ( vlc_object_t *p_this )
114 vout_thread_t * p_vout = (vout_thread_t *)p_this;
116 vlc_value_t value_drawable;
118 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
119 if( p_vout->p_sys == NULL )
121 msg_Err( p_vout, "out of memory" );
125 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
127 p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
129 p_vout->pf_init = InitVideo;
130 p_vout->pf_end = EndVideo;
131 p_vout->pf_manage = ManageVideo;
132 p_vout->pf_render = NULL;
133 p_vout->pf_display = DisplayVideo;
134 p_vout->pf_control = ControlVideo;
136 /* Are we embedded? If so, the drawable value will be a pointer to a
137 * CGrafPtr that we're expected to use */
138 var_Get( p_vout->p_vlc, "drawable", &value_drawable );
139 if( value_drawable.i_int != 0 )
140 p_vout->p_sys->b_embedded = VLC_TRUE;
142 p_vout->p_sys->b_embedded = VLC_FALSE;
144 p_vout->p_sys->b_altivec = p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC;
145 msg_Dbg( p_vout, "we do%s have Altivec", p_vout->p_sys->b_altivec ? "" : "n't" );
147 /* Initialize QuickTime */
148 p_vout->p_sys->h_img_descr =
149 (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
150 p_vout->p_sys->p_matrix =
151 (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
153 if( ( err = EnterMovies() ) != noErr )
155 msg_Err( p_vout, "QT initialization failed: EnterMovies failed: %d", err );
156 free( p_vout->p_sys->p_matrix );
157 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
158 free( p_vout->p_sys );
162 /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
163 vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
165 /* Can we find the right chroma ? */
166 if( p_vout->p_sys->b_altivec )
168 err = FindCodec( kYUVSPixelFormat, bestSpeedCodec,
169 nil, &p_vout->p_sys->img_dc );
173 err = FindCodec( kYUV420CodecType, bestSpeedCodec,
174 nil, &p_vout->p_sys->img_dc );
176 vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
178 if( err == noErr && p_vout->p_sys->img_dc != 0 )
180 if( p_vout->p_sys->b_altivec )
182 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
183 p_vout->p_sys->i_codec = kYUVSPixelFormat;
187 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
188 p_vout->p_sys->i_codec = kYUV420CodecType;
193 msg_Err( p_vout, "QT doesn't support any appropriate chroma" );
196 if( p_vout->p_sys->img_dc == 0 )
198 free( p_vout->p_sys->p_matrix );
199 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
200 free( p_vout->p_sys );
204 #define o_qtview p_vout->p_sys->o_qtview
205 o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
206 [o_qtview autorelease];
208 if( p_vout->p_sys->b_embedded )
210 /* Zero the clipping rectangle */
211 p_vout->p_sys->clipping_rect.left = 0;
212 p_vout->p_sys->clipping_rect.right = 0;
213 p_vout->p_sys->clipping_rect.top = 0;
214 p_vout->p_sys->clipping_rect.bottom = 0;
219 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
220 subView: o_qtview frame: nil];
221 if( !p_vout->p_sys->o_vout_view )
227 /* Retrieve the QuickDraw port */
228 if( p_vout->p_sys->b_embedded )
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];
237 [o_qtview lockFocus];
238 p_vout->p_sys->p_qdport = [o_qtview qdPort];
239 [o_qtview unlockFocus];
246 /*****************************************************************************
247 * CloseVideo: destroy video thread output method
248 *****************************************************************************/
249 void E_(CloseVideoQT) ( vlc_object_t *p_this )
251 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
252 vout_thread_t * p_vout = (vout_thread_t *)p_this;
254 if( !p_vout->p_sys->b_embedded )
255 [p_vout->p_sys->o_vout_view closeVout];
257 /* Clean Up Quicktime environment */
259 free( p_vout->p_sys->p_matrix );
260 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
263 free( p_vout->p_sys );
266 /*****************************************************************************
267 * InitVideo: initialize video thread output method
268 *****************************************************************************/
269 static int InitVideo ( vout_thread_t *p_vout )
274 I_OUTPUTPICTURES = 0;
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;
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
286 if( p_vout->p_sys->b_embedded )
289 var_Get( p_vout->p_vlc, "drawable", &val );
290 p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
293 SetPort( p_vout->p_sys->p_qdport );
294 QTScaleMatrix( p_vout );
296 if( QTCreateSequence( p_vout ) )
298 msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
302 /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
303 while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
307 /* Find an empty picture slot */
308 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
310 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
312 p_pic = p_vout->p_picture + i_index;
317 /* Allocate the picture */
318 if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
323 p_pic->i_status = DESTROYED_PICTURE;
324 p_pic->i_type = DIRECT_PICTURE;
326 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
332 /*****************************************************************************
333 * EndVideo: terminate video thread output method
334 *****************************************************************************/
335 static void EndVideo( vout_thread_t *p_vout )
339 QTDestroySequence( p_vout );
341 /* Free the direct buffers we allocated */
342 for( i_index = I_OUTPUTPICTURES; i_index; )
345 QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
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 )
358 var_Get( p_vout->p_vlc, "drawableredraw", &val );
360 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
362 if( CoToggleFullscreen( p_vout ) )
367 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
370 if( p_vout->p_sys->b_embedded && val.i_int == 1 )
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. */
377 var_Set( p_vout->p_vlc, "drawableredraw", val );
379 p_vout->i_changes |= VOUT_SIZE_CHANGE;
382 if( p_vout->i_changes & VOUT_SIZE_CHANGE ||
383 p_vout->i_changes & VOUT_ASPECT_CHANGE )
385 QTScaleMatrix( p_vout );
386 SetDSequenceMatrix( p_vout->p_sys->i_seq,
387 p_vout->p_sys->p_matrix );
389 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
391 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
393 if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
395 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
397 [p_vout->p_sys->o_vout_view manage];
402 /*****************************************************************************
403 * vout_Display: displays previously rendered output
404 *****************************************************************************
405 * This function sends the currently rendered image to the display.
406 *****************************************************************************/
407 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
413 RgnHandle saved_clip;
415 saved_clip = NewRgn();
417 if( p_vout->p_sys->b_embedded )
419 /* In the Mozilla plugin, the browser also draws things in the windows.
420 * So, we have to update the origin and clipping rectangle for each
421 * picture. FIXME: The vout should probably lock something ... */
423 /* Save the origin and clipping rectangle used by the host application
424 * (e.g. Mozilla), so we can restore it later */
425 GetPortBounds( p_vout->p_sys->p_qdport, &saved_rect );
426 GetClip( saved_clip );
428 /* The port gets unlocked at the end of this function */
429 LockPortBits( p_vout->p_sys->p_qdport );
431 /* Change the origin and clipping to the coordinates that the embedded
432 * window wants to draw at */
433 SetPort( p_vout->p_sys->p_qdport );
434 SetOrigin( p_vout->p_sys->portx , p_vout->p_sys->porty );
435 ClipRect( &p_vout->p_sys->clipping_rect );
438 if( ( err = DecompressSequenceFrameWhen(
439 p_vout->p_sys->i_seq,
440 p_pic->p_sys->p_data,
441 p_pic->p_sys->i_size,
442 codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
444 msg_Warn( p_vout, "QT failed to display the frame sequence: %d", err );
448 if( !p_vout->p_sys->b_embedded )
449 QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
452 if( p_vout->p_sys->b_embedded )
454 /* Restore the origin and clipping rectangle to the settings used
455 * by the host application */
456 SetOrigin( saved_rect.left, saved_rect.top );
457 SetClip( saved_clip );
459 UnlockPortBits( p_vout->p_sys->p_qdport );
463 /*****************************************************************************
464 * ControlVideo: control facility for the vout
465 *****************************************************************************/
466 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
472 case VOUT_SET_STAY_ON_TOP:
473 b_arg = va_arg( args, vlc_bool_t );
474 [p_vout->p_sys->o_vout_view setOnTop: b_arg];
480 return vout_vaControlDefault( p_vout, i_query, args );
484 /*****************************************************************************
485 * CoToggleFullscreen: toggle fullscreen
486 *****************************************************************************
487 * Returns 0 on success, 1 otherwise
488 *****************************************************************************/
489 static int CoToggleFullscreen( vout_thread_t *p_vout )
491 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
493 QTDestroySequence( p_vout );
495 if( !p_vout->b_fullscreen )
497 /* Save window size and position */
498 p_vout->p_sys->s_frame.size =
499 [p_vout->p_sys->o_vout_view frame].size;
500 p_vout->p_sys->s_frame.origin =
501 [[p_vout->p_sys->o_vout_view getWindow] frame].origin;
502 p_vout->p_sys->b_saved_frame = VLC_TRUE;
504 [p_vout->p_sys->o_vout_view closeVout];
506 p_vout->b_fullscreen = !p_vout->b_fullscreen;
508 #define o_qtview p_vout->p_sys->o_qtview
509 o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
510 [o_qtview autorelease];
512 if( p_vout->p_sys->b_saved_frame )
514 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
516 frame: &p_vout->p_sys->s_frame];
520 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
521 subView: o_qtview frame: nil];
524 /* Retrieve the QuickDraw port */
525 [o_qtview lockFocus];
526 p_vout->p_sys->p_qdport = [o_qtview qdPort];
527 [o_qtview unlockFocus];
530 SetPort( p_vout->p_sys->p_qdport );
531 QTScaleMatrix( p_vout );
533 if( QTCreateSequence( p_vout ) )
535 msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
543 /*****************************************************************************
544 * QTScaleMatrix: scale matrix
545 *****************************************************************************/
546 static void QTScaleMatrix( vout_thread_t *p_vout )
550 unsigned int i_width, i_height;
551 Fixed factor_x, factor_y;
552 unsigned int i_offset_x = 0;
553 unsigned int i_offset_y = 0;
555 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
557 i_width = s_rect.right - s_rect.left;
558 i_height = s_rect.bottom - s_rect.top;
560 if( p_vout->p_sys->b_embedded )
562 /* Embedded video get their drawing region from the host application
563 * by the drawable values here. Read those variables, and store them
564 * in the p_vout->p_sys structure so that other functions (such as
565 * DisplayVideo and ManageVideo) can use them later. */
566 vlc_value_t valt, vall, valb, valr, valx, valy, valw, valh,
569 var_Get( p_vout->p_vlc, "drawable", &val );
570 var_Get( p_vout->p_vlc, "drawablet", &valt );
571 var_Get( p_vout->p_vlc, "drawablel", &vall );
572 var_Get( p_vout->p_vlc, "drawableb", &valb );
573 var_Get( p_vout->p_vlc, "drawabler", &valr );
574 var_Get( p_vout->p_vlc, "drawablex", &valx );
575 var_Get( p_vout->p_vlc, "drawabley", &valy );
576 var_Get( p_vout->p_vlc, "drawablew", &valw );
577 var_Get( p_vout->p_vlc, "drawableh", &valh );
578 var_Get( p_vout->p_vlc, "drawableportx", &valportx );
579 var_Get( p_vout->p_vlc, "drawableporty", &valporty );
581 p_vout->p_sys->portx = valportx.i_int;
582 p_vout->p_sys->porty = valporty.i_int;
583 p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
584 i_width = valw.i_int;
585 i_height = valh.i_int;
587 p_vout->p_sys->clipping_rect.top = 0;
588 p_vout->p_sys->clipping_rect.left = 0;
589 p_vout->p_sys->clipping_rect.bottom = valb.i_int - valt.i_int;
590 p_vout->p_sys->clipping_rect.right = valr.i_int - vall.i_int;
593 var_Get( p_vout, "macosx-stretch", &val );
596 factor_x = FixDiv( Long2Fix( i_width ),
597 Long2Fix( p_vout->output.i_width ) );
598 factor_y = FixDiv( Long2Fix( i_height ),
599 Long2Fix( p_vout->output.i_height ) );
602 else if( i_height * p_vout->fmt_in.i_visible_width *
603 p_vout->fmt_in.i_sar_num <
604 i_width * p_vout->fmt_in.i_visible_height *
605 p_vout->fmt_in.i_sar_den )
607 int i_adj_width = i_height * p_vout->fmt_in.i_visible_width *
608 p_vout->fmt_in.i_sar_num /
609 ( p_vout->fmt_in.i_sar_den *
610 p_vout->fmt_in.i_visible_height );
612 factor_x = FixDiv( Long2Fix( i_adj_width ),
613 Long2Fix( p_vout->fmt_in.i_visible_width ) );
614 factor_y = FixDiv( Long2Fix( i_height ),
615 Long2Fix( p_vout->fmt_in.i_visible_height ) );
617 i_offset_x = (i_width - i_adj_width) / 2;
621 int i_adj_height = i_width * p_vout->fmt_in.i_visible_height *
622 p_vout->fmt_in.i_sar_den /
623 ( p_vout->fmt_in.i_sar_num *
624 p_vout->fmt_in.i_visible_width );
626 factor_x = FixDiv( Long2Fix( i_width ),
627 Long2Fix( p_vout->fmt_in.i_visible_width ) );
628 factor_y = FixDiv( Long2Fix( i_adj_height ),
629 Long2Fix( p_vout->fmt_in.i_visible_height ) );
631 i_offset_y = (i_height - i_adj_height) / 2;
634 SetIdentityMatrix( p_vout->p_sys->p_matrix );
636 ScaleMatrix( p_vout->p_sys->p_matrix,
638 Long2Fix(0), Long2Fix(0) );
640 TranslateMatrix( p_vout->p_sys->p_matrix,
641 Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
644 /*****************************************************************************
645 * QTCreateSequence: create a new sequence
646 *****************************************************************************
647 * Returns 0 on success, 1 otherwise
648 *****************************************************************************/
649 static int QTCreateSequence( vout_thread_t *p_vout )
652 ImageDescriptionPtr p_descr;
654 HLock( (Handle)p_vout->p_sys->h_img_descr );
655 p_descr = *p_vout->p_sys->h_img_descr;
657 p_descr->idSize = sizeof(ImageDescription);
658 p_descr->cType = p_vout->p_sys->i_codec;
659 p_descr->version = 2;
660 p_descr->revisionLevel = 0;
661 p_descr->vendor = 'mpla';
662 p_descr->width = p_vout->output.i_width;
663 p_descr->height = p_vout->output.i_height;
664 p_descr->hRes = Long2Fix(72);
665 p_descr->vRes = Long2Fix(72);
666 p_descr->spatialQuality = codecLosslessQuality;
667 p_descr->frameCount = 1;
668 p_descr->clutID = -1;
669 p_descr->dataSize = 0;
672 HUnlock( (Handle)p_vout->p_sys->h_img_descr );
674 if( ( err = DecompressSequenceBeginS(
675 &p_vout->p_sys->i_seq,
676 p_vout->p_sys->h_img_descr,
678 (p_descr->width * p_descr->height * 16) / 8,
679 p_vout->p_sys->p_qdport,
681 p_vout->p_sys->p_matrix,
683 codecFlagUseImageBuffer,
684 codecLosslessQuality,
687 msg_Err( p_vout, "Failed to initialize QT: DecompressSequenceBeginS failed: %d", err );
694 /*****************************************************************************
695 * QTDestroySequence: destroy sequence
696 *****************************************************************************/
697 static void QTDestroySequence( vout_thread_t *p_vout )
699 CDSequenceEnd( p_vout->p_sys->i_seq );
702 /*****************************************************************************
703 * QTNewPicture: allocate a picture
704 *****************************************************************************
705 * Returns 0 on success, 1 otherwise
706 *****************************************************************************/
707 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
709 /* We know the chroma, allocate a buffer which will be used
710 * directly by the decoder */
711 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
713 if( p_pic->p_sys == NULL )
718 vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
719 p_vout->output.i_width, p_vout->output.i_height,
720 p_vout->output.i_aspect );
722 switch( p_vout->output.i_chroma )
724 case VLC_FOURCC('Y','U','Y','2'):
725 p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
727 /* Allocate the memory buffer */
728 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
729 16, p_pic->p_sys->i_size );
731 p_pic->p[0].p_pixels = p_pic->p_data;
732 p_pic->p[0].i_lines = p_vout->output.i_height;
733 p_pic->p[0].i_visible_lines = p_vout->output.i_height;
734 p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
735 p_pic->p[0].i_pixel_pitch = 1;
736 p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
739 p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
743 case VLC_FOURCC('I','4','2','0'):
744 p_pic->p_sys->p_data = (void *)&p_pic->p_sys->pixmap_i420;
745 p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
747 /* Allocate the memory buffer */
748 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
749 16, p_vout->output.i_width * p_vout->output.i_height * 3 / 2 );
752 p_pic->Y_PIXELS = p_pic->p_data;
753 p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
754 p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
755 p_pic->p[Y_PLANE].i_pitch = p_vout->output.i_width;
756 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
757 p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width;
760 p_pic->U_PIXELS = p_pic->Y_PIXELS + p_vout->output.i_height * p_vout->output.i_width;
761 p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
762 p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
763 p_pic->p[U_PLANE].i_pitch = p_vout->output.i_width / 2;
764 p_pic->p[U_PLANE].i_pixel_pitch = 1;
765 p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
768 p_pic->V_PIXELS = p_pic->U_PIXELS + p_vout->output.i_height * p_vout->output.i_width / 4;
769 p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
770 p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
771 p_pic->p[V_PLANE].i_pitch = p_vout->output.i_width / 2;
772 p_pic->p[V_PLANE].i_pixel_pitch = 1;
773 p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
775 /* We allocated 3 planes */
778 #define P p_pic->p_sys->pixmap_i420
779 P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
780 - p_pic->p_sys->p_data;
781 P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
782 - p_pic->p_sys->p_data;
783 P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
784 - p_pic->p_sys->p_data;
786 P.componentInfoY.rowBytes = p_vout->output.i_width;
787 P.componentInfoCb.rowBytes = p_vout->output.i_width / 2;
788 P.componentInfoCr.rowBytes = p_vout->output.i_width / 2;
793 /* Unknown chroma, tell the guy to get lost */
794 free( p_pic->p_sys );
795 msg_Err( p_vout, "Unknown chroma format 0x%.8x (%4.4s)",
796 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
804 /*****************************************************************************
805 * QTFreePicture: destroy a picture allocated with QTNewPicture
806 *****************************************************************************/
807 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
809 switch( p_vout->output.i_chroma )
811 case VLC_FOURCC('I','4','2','0'):
812 free( p_pic->p_data_orig );
816 free( p_pic->p_sys );
819 /*****************************************************************************
820 * VLCQTView implementation
821 *****************************************************************************/
822 @implementation VLCQTView
824 - (id) initWithVout:(vout_thread_t *)_p_vout
830 - (void)drawRect:(NSRect)rect
832 [[NSColor blackColor] set];
834 [super drawRect: rect];
836 p_vout->i_changes |= VOUT_SIZE_CHANGE;