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>
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #include <errno.h> /* ENOMEM */
32 #include <stdlib.h> /* free() */
33 #include <string.h> /* strerror() */
35 #include <QuickTime/QuickTime.h>
42 #define QT_MAX_DIRECTBUFFERS 10
43 #define VL_MAX_DISPLAYS 16
45 /*****************************************************************************
47 *****************************************************************************/
48 @interface VLCQTView : NSQuickDrawView
50 vout_thread_t * p_vout;
53 - (id) initWithVout:(vout_thread_t *)p_vout;
59 NSAutoreleasePool *o_pool;
61 VLCVoutView * o_vout_view;
63 vlc_bool_t b_saved_frame;
70 MatrixRecordPtr p_matrix;
71 DecompressorComponent img_dc;
72 ImageDescriptionHandle h_img_descr;
74 /* Mozilla plugin-related variables */
75 vlc_bool_t b_embedded;
85 /* When using I420 output */
86 PlanarPixmapInfoYUV420 pixmap_i420;
89 /*****************************************************************************
91 *****************************************************************************/
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 );
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 * );
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 )
113 vout_thread_t * p_vout = (vout_thread_t *)p_this;
115 vlc_value_t value_drawable;
117 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
118 if( p_vout->p_sys == NULL )
120 msg_Err( p_vout, "out of memory" );
124 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
126 p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
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;
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;
141 p_vout->p_sys->b_embedded = VLC_FALSE;
143 p_vout->p_sys->b_altivec = p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC;
144 msg_Dbg( p_vout, "We do%s have Altivec", p_vout->p_sys->b_altivec ? "" : "n't" );
146 /* Initialize QuickTime */
147 p_vout->p_sys->h_img_descr =
148 (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
149 p_vout->p_sys->p_matrix =
150 (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
152 if( ( err = EnterMovies() ) != noErr )
154 msg_Err( p_vout, "QT initialization failed: EnterMovies failed: %d", err );
155 free( p_vout->p_sys->p_matrix );
156 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
157 free( p_vout->p_sys );
161 /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
162 vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
164 /* Can we find the right chroma ? */
165 if( p_vout->p_sys->b_altivec )
167 err = FindCodec( kYUVSPixelFormat, bestSpeedCodec,
168 nil, &p_vout->p_sys->img_dc );
172 err = FindCodec( kYUV420CodecType, bestSpeedCodec,
173 nil, &p_vout->p_sys->img_dc );
175 vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
177 if( err == noErr && p_vout->p_sys->img_dc != 0 )
179 if( p_vout->p_sys->b_altivec )
181 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
182 p_vout->p_sys->i_codec = kYUVSPixelFormat;
186 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
187 p_vout->p_sys->i_codec = kYUV420CodecType;
192 msg_Err( p_vout, "QT doesn't support any appropriate chroma" );
195 if( p_vout->p_sys->img_dc == 0 )
197 free( p_vout->p_sys->p_matrix );
198 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
199 free( p_vout->p_sys );
203 #define o_qtview p_vout->p_sys->o_qtview
204 o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
205 [o_qtview autorelease];
207 if( p_vout->p_sys->b_embedded )
209 /* Zero the clipping rectangle */
210 p_vout->p_sys->clipping_rect.left = 0;
211 p_vout->p_sys->clipping_rect.right = 0;
212 p_vout->p_sys->clipping_rect.top = 0;
213 p_vout->p_sys->clipping_rect.bottom = 0;
218 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
219 subView: o_qtview frame: nil];
220 if( !p_vout->p_sys->o_vout_view )
226 /* Retrieve the QuickDraw port */
227 if( p_vout->p_sys->b_embedded )
229 /* Don't need (nor want) to lock the focus, since otherwise we crash
230 * (presumably because we don't own the window, but I'm not sure
231 * if this is the exact reason) -andrep */
232 p_vout->p_sys->p_qdport = [o_qtview qdPort];
236 [o_qtview lockFocus];
237 p_vout->p_sys->p_qdport = [o_qtview qdPort];
238 [o_qtview unlockFocus];
245 /*****************************************************************************
246 * CloseVideo: destroy video thread output method
247 *****************************************************************************/
248 void E_(CloseVideoQT) ( vlc_object_t *p_this )
250 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
251 vout_thread_t * p_vout = (vout_thread_t *)p_this;
253 if( !p_vout->p_sys->b_embedded )
254 [p_vout->p_sys->o_vout_view closeVout];
256 /* Clean Up Quicktime environment */
258 free( p_vout->p_sys->p_matrix );
259 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
262 free( p_vout->p_sys );
265 /*****************************************************************************
266 * InitVideo: initialize video thread output method
267 *****************************************************************************/
268 static int InitVideo ( vout_thread_t *p_vout )
273 I_OUTPUTPICTURES = 0;
275 /* Initialize the output structure; we already found a codec,
276 * and the corresponding chroma we will be using. Since we can
277 * arbitrary scale, stick to the coordinates and aspect. */
278 p_vout->output.i_width = p_vout->render.i_width;
279 p_vout->output.i_height = p_vout->render.i_height;
280 p_vout->output.i_aspect = p_vout->render.i_aspect;
282 /* If we are embedded (e.g. running as a Mozilla plugin), use the pointer
283 * stored in the "drawable" value as the CGrafPtr for the QuickDraw
285 if( p_vout->p_sys->b_embedded )
288 var_Get( p_vout->p_vlc, "drawable", &val );
289 p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
292 SetPort( p_vout->p_sys->p_qdport );
293 QTScaleMatrix( p_vout );
295 if( QTCreateSequence( p_vout ) )
297 msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
301 /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
302 while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
306 /* Find an empty picture slot */
307 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
309 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
311 p_pic = p_vout->p_picture + i_index;
316 /* Allocate the picture */
317 if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
322 p_pic->i_status = DESTROYED_PICTURE;
323 p_pic->i_type = DIRECT_PICTURE;
325 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
331 /*****************************************************************************
332 * EndVideo: terminate video thread output method
333 *****************************************************************************/
334 static void EndVideo( vout_thread_t *p_vout )
338 QTDestroySequence( p_vout );
340 /* Free the direct buffers we allocated */
341 for( i_index = I_OUTPUTPICTURES; i_index; )
344 QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
348 /*****************************************************************************
349 * ManageVideo: handle events
350 *****************************************************************************
351 * This function should be called regularly by video output thread. It manages
352 * console events. It returns a non null value on error.
353 *****************************************************************************/
354 static int ManageVideo( vout_thread_t *p_vout )
357 var_Get( p_vout->p_vlc, "drawableredraw", &val );
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->p_sys->b_embedded && val.i_int == 1 )
371 /* If we're embedded, the application is expected to indicate a
372 * window change (move/resize/etc) via the "drawableredraw" value.
373 * If that's the case, set the VOUT_SIZE_CHANGE flag so we do
374 * actually handle the window change. */
376 var_Set( p_vout->p_vlc, "drawableredraw", val );
378 p_vout->i_changes |= VOUT_SIZE_CHANGE;
381 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
383 QTScaleMatrix( p_vout );
384 SetDSequenceMatrix( p_vout->p_sys->i_seq,
385 p_vout->p_sys->p_matrix );
386 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
389 [p_vout->p_sys->o_vout_view manage];
394 /*****************************************************************************
395 * vout_Display: displays previously rendered output
396 *****************************************************************************
397 * This function sends the currently rendered image to the display.
398 *****************************************************************************/
399 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
405 RgnHandle saved_clip;
407 saved_clip = NewRgn();
409 if( p_vout->p_sys->b_embedded )
411 /* In the Mozilla plugin, the browser also draws things in the windows.
412 * So, we have to update the origin and clipping rectangle for each
413 * picture. FIXME: The vout should probably lock something ... */
415 /* Save the origin and clipping rectangle used by the host application
416 * (e.g. Mozilla), so we can restore it later */
417 GetPortBounds( p_vout->p_sys->p_qdport, &saved_rect );
418 GetClip( saved_clip );
420 /* The port gets unlocked at the end of this function */
421 LockPortBits( p_vout->p_sys->p_qdport );
423 /* Change the origin and clipping to the coordinates that the embedded
424 * window wants to draw at */
425 SetPort( p_vout->p_sys->p_qdport );
426 SetOrigin( p_vout->p_sys->portx , p_vout->p_sys->porty );
427 ClipRect( &p_vout->p_sys->clipping_rect );
430 if( ( err = DecompressSequenceFrameWhen(
431 p_vout->p_sys->i_seq,
432 p_pic->p_sys->p_data,
433 p_pic->p_sys->i_size,
434 codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
436 msg_Warn( p_vout, "QT failed to display the frame sequence: %d", err );
440 if( !p_vout->p_sys->b_embedded )
441 QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
444 if( p_vout->p_sys->b_embedded )
446 /* Restore the origin and clipping rectangle to the settings used
447 * by the host application */
448 SetOrigin( saved_rect.left, saved_rect.top );
449 SetClip( saved_clip );
451 UnlockPortBits( p_vout->p_sys->p_qdport );
455 /*****************************************************************************
456 * ControlVideo: control facility for the vout
457 *****************************************************************************/
458 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
464 case VOUT_SET_STAY_ON_TOP:
465 b_arg = va_arg( args, vlc_bool_t );
466 [p_vout->p_sys->o_vout_view setOnTop: b_arg];
472 return vout_vaControlDefault( p_vout, i_query, args );
476 /*****************************************************************************
477 * CoToggleFullscreen: toggle fullscreen
478 *****************************************************************************
479 * Returns 0 on success, 1 otherwise
480 *****************************************************************************/
481 static int CoToggleFullscreen( vout_thread_t *p_vout )
483 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
485 QTDestroySequence( p_vout );
487 if( !p_vout->b_fullscreen )
489 /* Save window size and position */
490 p_vout->p_sys->s_frame.size =
491 [p_vout->p_sys->o_vout_view frame].size;
492 p_vout->p_sys->s_frame.origin =
493 [[p_vout->p_sys->o_vout_view getWindow] frame].origin;
494 p_vout->p_sys->b_saved_frame = VLC_TRUE;
496 [p_vout->p_sys->o_vout_view closeVout];
498 p_vout->b_fullscreen = !p_vout->b_fullscreen;
500 #define o_qtview p_vout->p_sys->o_qtview
501 o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
502 [o_qtview autorelease];
504 if( p_vout->p_sys->b_saved_frame )
506 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
508 frame: &p_vout->p_sys->s_frame];
512 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
513 subView: o_qtview frame: nil];
516 /* Retrieve the QuickDraw port */
517 [o_qtview lockFocus];
518 p_vout->p_sys->p_qdport = [o_qtview qdPort];
519 [o_qtview unlockFocus];
522 SetPort( p_vout->p_sys->p_qdport );
523 QTScaleMatrix( p_vout );
525 if( QTCreateSequence( p_vout ) )
527 msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
535 /*****************************************************************************
536 * QTScaleMatrix: scale matrix
537 *****************************************************************************/
538 static void QTScaleMatrix( vout_thread_t *p_vout )
542 unsigned int i_width, i_height;
543 Fixed factor_x, factor_y;
544 unsigned int i_offset_x = 0;
545 unsigned int i_offset_y = 0;
547 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
549 i_width = s_rect.right - s_rect.left;
550 i_height = s_rect.bottom - s_rect.top;
552 if( p_vout->p_sys->b_embedded )
554 /* Embedded video get their drawing region from the host application
555 * by the drawable values here. Read those variables, and store them
556 * in the p_vout->p_sys structure so that other functions (such as
557 * DisplayVideo and ManageVideo) can use them later. */
558 vlc_value_t valt, vall, valb, valr, valx, valy, valw, valh,
561 var_Get( p_vout->p_vlc, "drawable", &val );
562 var_Get( p_vout->p_vlc, "drawablet", &valt );
563 var_Get( p_vout->p_vlc, "drawablel", &vall );
564 var_Get( p_vout->p_vlc, "drawableb", &valb );
565 var_Get( p_vout->p_vlc, "drawabler", &valr );
566 var_Get( p_vout->p_vlc, "drawablex", &valx );
567 var_Get( p_vout->p_vlc, "drawabley", &valy );
568 var_Get( p_vout->p_vlc, "drawablew", &valw );
569 var_Get( p_vout->p_vlc, "drawableh", &valh );
570 var_Get( p_vout->p_vlc, "drawableportx", &valportx );
571 var_Get( p_vout->p_vlc, "drawableporty", &valporty );
573 p_vout->p_sys->portx = valportx.i_int;
574 p_vout->p_sys->porty = valporty.i_int;
575 p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
576 i_width = valw.i_int;
577 i_height = valh.i_int;
579 p_vout->p_sys->clipping_rect.top = 0;
580 p_vout->p_sys->clipping_rect.left = 0;
581 p_vout->p_sys->clipping_rect.bottom = valb.i_int - valt.i_int;
582 p_vout->p_sys->clipping_rect.right = valr.i_int - vall.i_int;
585 var_Get( p_vout, "macosx-stretch", &val );
588 factor_x = FixDiv( Long2Fix( i_width ),
589 Long2Fix( p_vout->output.i_width ) );
590 factor_y = FixDiv( Long2Fix( i_height ),
591 Long2Fix( p_vout->output.i_height ) );
594 else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
596 int i_adj_width = i_height * p_vout->output.i_aspect /
599 factor_x = FixDiv( Long2Fix( i_adj_width ),
600 Long2Fix( p_vout->output.i_width ) );
601 factor_y = FixDiv( Long2Fix( i_height ),
602 Long2Fix( p_vout->output.i_height ) );
604 i_offset_x = (i_width - i_adj_width) / 2;
608 int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
609 p_vout->output.i_aspect;
611 factor_x = FixDiv( Long2Fix( i_width ),
612 Long2Fix( p_vout->output.i_width ) );
613 factor_y = FixDiv( Long2Fix( i_adj_height ),
614 Long2Fix( p_vout->output.i_height ) );
616 i_offset_y = (i_height - i_adj_height) / 2;
619 SetIdentityMatrix( p_vout->p_sys->p_matrix );
621 ScaleMatrix( p_vout->p_sys->p_matrix,
623 Long2Fix(0), Long2Fix(0) );
625 TranslateMatrix( p_vout->p_sys->p_matrix,
626 Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
629 /*****************************************************************************
630 * QTCreateSequence: create a new sequence
631 *****************************************************************************
632 * Returns 0 on success, 1 otherwise
633 *****************************************************************************/
634 static int QTCreateSequence( vout_thread_t *p_vout )
637 ImageDescriptionPtr p_descr;
639 HLock( (Handle)p_vout->p_sys->h_img_descr );
640 p_descr = *p_vout->p_sys->h_img_descr;
642 p_descr->idSize = sizeof(ImageDescription);
643 p_descr->cType = p_vout->p_sys->i_codec;
644 p_descr->version = 2;
645 p_descr->revisionLevel = 0;
646 p_descr->vendor = 'mpla';
647 p_descr->width = p_vout->output.i_width;
648 p_descr->height = p_vout->output.i_height;
649 p_descr->hRes = Long2Fix(72);
650 p_descr->vRes = Long2Fix(72);
651 p_descr->spatialQuality = codecLosslessQuality;
652 p_descr->frameCount = 1;
653 p_descr->clutID = -1;
654 p_descr->dataSize = 0;
657 HUnlock( (Handle)p_vout->p_sys->h_img_descr );
659 if( ( err = DecompressSequenceBeginS(
660 &p_vout->p_sys->i_seq,
661 p_vout->p_sys->h_img_descr,
663 (p_descr->width * p_descr->height * 16) / 8,
664 p_vout->p_sys->p_qdport,
666 p_vout->p_sys->p_matrix,
668 codecFlagUseImageBuffer,
669 codecLosslessQuality,
672 msg_Err( p_vout, "Failed to initialize QT: DecompressSequenceBeginS failed: %d", err );
679 /*****************************************************************************
680 * QTDestroySequence: destroy sequence
681 *****************************************************************************/
682 static void QTDestroySequence( vout_thread_t *p_vout )
684 CDSequenceEnd( p_vout->p_sys->i_seq );
687 /*****************************************************************************
688 * QTNewPicture: allocate a picture
689 *****************************************************************************
690 * Returns 0 on success, 1 otherwise
691 *****************************************************************************/
692 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
694 /* We know the chroma, allocate a buffer which will be used
695 * directly by the decoder */
696 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
698 if( p_pic->p_sys == NULL )
703 vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
704 p_vout->output.i_width, p_vout->output.i_height,
705 p_vout->output.i_aspect );
707 switch( p_vout->output.i_chroma )
709 case VLC_FOURCC('Y','U','Y','2'):
710 p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
712 /* Allocate the memory buffer */
713 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
714 16, p_pic->p_sys->i_size );
716 p_pic->p[0].p_pixels = p_pic->p_data;
717 p_pic->p[0].i_lines = p_vout->output.i_height;
718 p_pic->p[0].i_visible_lines = p_vout->output.i_height;
719 p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
720 p_pic->p[0].i_pixel_pitch = 1;
721 p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
724 p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
728 case VLC_FOURCC('I','4','2','0'):
729 p_pic->p_sys->p_data = (void *)&p_pic->p_sys->pixmap_i420;
730 p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
732 /* Allocate the memory buffer */
733 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
734 16, p_vout->output.i_width * p_vout->output.i_height * 3 / 2 );
737 p_pic->Y_PIXELS = p_pic->p_data;
738 p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
739 p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
740 p_pic->p[Y_PLANE].i_pitch = p_vout->output.i_width;
741 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
742 p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width;
745 p_pic->U_PIXELS = p_pic->Y_PIXELS + p_vout->output.i_height * p_vout->output.i_width;
746 p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
747 p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
748 p_pic->p[U_PLANE].i_pitch = p_vout->output.i_width / 2;
749 p_pic->p[U_PLANE].i_pixel_pitch = 1;
750 p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
753 p_pic->V_PIXELS = p_pic->U_PIXELS + p_vout->output.i_height * p_vout->output.i_width / 4;
754 p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
755 p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
756 p_pic->p[V_PLANE].i_pitch = p_vout->output.i_width / 2;
757 p_pic->p[V_PLANE].i_pixel_pitch = 1;
758 p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
760 /* We allocated 3 planes */
763 #define P p_pic->p_sys->pixmap_i420
764 P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
765 - p_pic->p_sys->p_data;
766 P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
767 - p_pic->p_sys->p_data;
768 P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
769 - p_pic->p_sys->p_data;
771 P.componentInfoY.rowBytes = p_vout->output.i_width;
772 P.componentInfoCb.rowBytes = p_vout->output.i_width / 2;
773 P.componentInfoCr.rowBytes = p_vout->output.i_width / 2;
778 /* Unknown chroma, tell the guy to get lost */
779 free( p_pic->p_sys );
780 msg_Err( p_vout, "Unknown chroma format 0x%.8x (%4.4s)",
781 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
789 /*****************************************************************************
790 * QTFreePicture: destroy a picture allocated with QTNewPicture
791 *****************************************************************************/
792 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
794 switch( p_vout->output.i_chroma )
796 case VLC_FOURCC('I','4','2','0'):
797 free( p_pic->p_data_orig );
801 free( p_pic->p_sys );
804 /*****************************************************************************
805 * VLCQTView implementation
806 *****************************************************************************/
807 @implementation VLCQTView
809 - (id) initWithVout:(vout_thread_t *)_p_vout
815 - (void)drawRect:(NSRect)rect
817 [[NSColor blackColor] set];
819 [super drawRect: rect];
821 p_vout->i_changes |= VOUT_SIZE_CHANGE;