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 /* 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_altivec = p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC;
150 msg_Dbg( p_vout, "we do%s have Altivec", p_vout->p_sys->b_altivec ? "" : "n't" );
152 /* Initialize QuickTime */
153 p_vout->p_sys->h_img_descr =
154 (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
155 p_vout->p_sys->p_matrix =
156 (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
158 if( ( err = EnterMovies() ) != noErr )
160 msg_Err( p_vout, "QT initialization failed: EnterMovies failed: %d", err );
161 free( p_vout->p_sys->p_matrix );
162 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
163 free( p_vout->p_sys );
167 /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
168 vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
170 /* Can we find the right chroma ? */
171 if( p_vout->p_sys->b_altivec )
173 err = FindCodec( kYUVSPixelFormat, bestSpeedCodec,
174 nil, &p_vout->p_sys->img_dc );
178 err = FindCodec( kYUV420CodecType, bestSpeedCodec,
179 nil, &p_vout->p_sys->img_dc );
181 vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
183 if( err == noErr && p_vout->p_sys->img_dc != 0 )
185 if( p_vout->p_sys->b_altivec )
187 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
188 p_vout->p_sys->i_codec = kYUVSPixelFormat;
192 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
193 p_vout->p_sys->i_codec = kYUV420CodecType;
198 msg_Err( p_vout, "QT doesn't support any appropriate chroma" );
201 if( p_vout->p_sys->img_dc == 0 )
203 free( p_vout->p_sys->p_matrix );
204 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
205 free( p_vout->p_sys );
209 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
212 #define o_qtview p_vout->p_sys->o_qtview
213 o_qtview = [[VLCQTView alloc] initWithVout: p_vout];
214 [o_qtview autorelease];
216 p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout
217 subView: o_qtview frame: nil];
218 if( !p_vout->p_sys->o_vout_view )
222 [o_qtview lockFocus];
223 p_vout->p_sys->p_qdport = [o_qtview qdPort];
224 [o_qtview unlockFocus];
231 /*****************************************************************************
232 * CloseVideo: destroy video thread output method
233 *****************************************************************************/
234 void E_(CloseVideoQT) ( vlc_object_t *p_this )
236 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
237 vout_thread_t * p_vout = (vout_thread_t *)p_this;
239 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
240 [p_vout->p_sys->o_vout_view closeVout];
242 /* Clean Up Quicktime environment */
244 free( p_vout->p_sys->p_matrix );
245 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
248 free( p_vout->p_sys );
251 /*****************************************************************************
252 * InitVideo: initialize video thread output method
253 *****************************************************************************/
254 static int InitVideo ( vout_thread_t *p_vout )
259 I_OUTPUTPICTURES = 0;
261 /* Initialize the output structure; we already found a codec,
262 * and the corresponding chroma we will be using. Since we can
263 * arbitrary scale, stick to the coordinates and aspect. */
264 p_vout->output.i_width = p_vout->render.i_width;
265 p_vout->output.i_height = p_vout->render.i_height;
266 p_vout->output.i_aspect = p_vout->render.i_aspect;
268 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
271 p_vout->p_sys->clip_mask = NULL;
272 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
273 p_vout->p_sys->i_origx = s_rect.left;
274 p_vout->p_sys->i_origy = s_rect.top;
275 p_vout->p_sys->i_width = s_rect.right - s_rect.left;
276 p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
280 /* As we are embedded (e.g. running as a Mozilla plugin), use the pointer
281 * stored in the "drawable" value as the CGrafPtr for the QuickDraw
283 /* Create the clipping mask */
284 p_vout->p_sys->clip_mask = NewRgn();
285 UpdateEmbeddedGeometry(p_vout);
286 var_AddCallback(p_vout->p_vlc, "drawableredraw", DrawableRedraw, p_vout);
289 QTScaleMatrix( p_vout );
291 if( QTCreateSequence( p_vout ) )
293 msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
297 /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
298 while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
302 /* Find an empty picture slot */
303 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
305 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
307 p_pic = p_vout->p_picture + i_index;
312 /* Allocate the picture */
313 if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
318 p_pic->i_status = DESTROYED_PICTURE;
319 p_pic->i_type = DIRECT_PICTURE;
321 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
327 /*****************************************************************************
328 * EndVideo: terminate video thread output method
329 *****************************************************************************/
330 static void EndVideo( vout_thread_t *p_vout )
334 QTDestroySequence( p_vout );
336 if( !p_vout->b_fullscreen && p_vout->p_sys->b_embedded )
338 var_DelCallback(p_vout->p_vlc, "drawableredraw", DrawableRedraw, p_vout);
339 DisposeRgn(p_vout->p_sys->clip_mask);
342 /* Free the direct buffers we allocated */
343 for( i_index = I_OUTPUTPICTURES; i_index; )
346 QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
350 /*****************************************************************************
351 * ManageVideo: handle events
352 *****************************************************************************
353 * This function should be called regularly by video output thread. It manages
354 * console events. It returns a non null value on error.
355 *****************************************************************************/
356 static int ManageVideo( vout_thread_t *p_vout )
358 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
360 if( CoToggleFullscreen( p_vout ) )
365 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
368 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
370 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
372 /* get the geometry from NSQuickDrawView */
374 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
375 p_vout->p_sys->i_origx = s_rect.left;
376 p_vout->p_sys->i_origy = s_rect.top;
377 p_vout->p_sys->i_width = s_rect.right - s_rect.left;
378 p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
382 /* As we're embedded, get the geometry from Mozilla/Safari NPWindow object */
383 UpdateEmbeddedGeometry( p_vout );
384 SetDSequenceMask(p_vout->p_sys->i_seq,
385 p_vout->p_sys->clip_mask);
389 if( p_vout->i_changes & VOUT_SIZE_CHANGE ||
390 p_vout->i_changes & VOUT_ASPECT_CHANGE )
392 QTScaleMatrix( p_vout );
393 SetDSequenceMatrix( p_vout->p_sys->i_seq,
394 p_vout->p_sys->p_matrix );
396 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
398 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
400 if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
402 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
406 [p_vout->p_sys->o_vout_view manage];
411 /*****************************************************************************
412 * vout_Display: displays previously rendered output
413 *****************************************************************************
414 * This function sends the currently rendered image to the display.
415 *****************************************************************************/
416 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
420 if( (NULL == p_vout->p_sys->clip_mask) || !EmptyRgn(p_vout->p_sys->clip_mask) )
425 /* since there is not way to lock a QuickDraw port for exclusive use
426 there is a potential problem that the frame will be displayed
427 in the wrong place if other embedded plugins redraws as the port
428 origin may be changed */
430 //GetPortBounds(p_vout->p_sys->p_qdport, &oldBounds);
431 SetPort(p_vout->p_sys->p_qdport);
432 SetOrigin(p_vout->p_sys->i_origx, p_vout->p_sys->i_origy);
433 if( ( err = DecompressSequenceFrameWhen(
434 p_vout->p_sys->i_seq,
435 p_pic->p_sys->p_data,
436 p_pic->p_sys->i_size,
437 codecFlagUseImageBuffer, &flags, NULL, NULL ) == noErr ) )
439 QDFlushPortBuffer( p_vout->p_sys->p_qdport, p_vout->p_sys->clip_mask );
440 //QDFlushPortBuffer( p_vout->p_sys->p_qdport, NULL );
444 msg_Warn( p_vout, "QT failed to display the frame sequence: %d", err );
446 //SetPortBounds(p_vout->p_sys->p_qdport, &oldBounds);
451 /*****************************************************************************
452 * ControlVideo: control facility for the vout
453 *****************************************************************************/
454 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
460 case VOUT_SET_STAY_ON_TOP:
461 b_arg = va_arg( args, vlc_bool_t );
462 [p_vout->p_sys->o_vout_view setOnTop: b_arg];
468 return vout_vaControlDefault( p_vout, i_query, args );
472 /*****************************************************************************
473 * CoToggleFullscreen: toggle fullscreen
474 *****************************************************************************
475 * Returns 0 on success, 1 otherwise
476 *****************************************************************************/
477 static int CoToggleFullscreen( vout_thread_t *p_vout )
479 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
481 QTDestroySequence( p_vout );
483 if( !p_vout->b_fullscreen )
485 if( !p_vout->p_sys->b_embedded )
487 /* Save window size and position */
488 p_vout->p_sys->s_frame.size =
489 [p_vout->p_sys->o_vout_view frame].size;
490 p_vout->p_sys->s_frame.origin =
491 [[p_vout->p_sys->o_vout_view getWindow] frame].origin;
492 p_vout->p_sys->b_saved_frame = VLC_TRUE;
496 var_DelCallback(p_vout->p_vlc, "drawableredraw", DrawableRedraw, p_vout);
497 DisposeRgn(p_vout->p_sys->clip_mask);
500 [p_vout->p_sys->o_vout_view closeVout];
502 p_vout->b_fullscreen = !p_vout->b_fullscreen;
504 if( p_vout->b_fullscreen || !p_vout->p_sys->b_embedded )
507 p_vout->p_sys->clip_mask = NULL;
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];
529 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
530 p_vout->p_sys->i_origx = s_rect.left;
531 p_vout->p_sys->i_origy = s_rect.top;
532 p_vout->p_sys->i_width = s_rect.right - s_rect.left;
533 p_vout->p_sys->i_height = s_rect.bottom - s_rect.top;
537 /* Create the clipping mask */
538 p_vout->p_sys->clip_mask = NewRgn();
539 UpdateEmbeddedGeometry(p_vout);
540 var_AddCallback(p_vout->p_vlc, "drawableredraw", DrawableRedraw, p_vout);
542 QTScaleMatrix( p_vout );
544 if( QTCreateSequence( p_vout ) )
546 msg_Err( p_vout, "unable to initialize QT: QTCreateSequence failed" );
554 /* If we're embedded, the application is expected to indicate a
555 * window change (move/resize/etc) via the "drawableredraw" value.
556 * If that's the case, set the VOUT_SIZE_CHANGE flag so we do
557 * actually handle the window change. */
559 static int DrawableRedraw( vlc_object_t *p_this, const char *psz_name,
560 vlc_value_t oval, vlc_value_t nval, void *param)
562 /* ignore changes until we are ready for them */
563 if( (oval.i_int != nval.i_int) && (nval.i_int == 1) )
565 vout_thread_t *p_vout = (vout_thread_t *)param;
566 /* prevent QT from rendering any more video until we have updated
568 SetEmptyRgn(p_vout->p_sys->clip_mask);
569 SetDSequenceMask(p_vout->p_sys->i_seq,
570 p_vout->p_sys->clip_mask);
572 p_vout->i_changes |= VOUT_SIZE_CHANGE;
577 /* Embedded video get their drawing region from the host application
578 * by the drawable values here. Read those variables, and store them
579 * in the p_vout->p_sys structure so that other functions (such as
580 * DisplayVideo and ManageVideo) can use them later. */
582 static void UpdateEmbeddedGeometry( vout_thread_t *p_vout )
585 vlc_value_t valt, vall, valb, valr, valx, valy, valw, valh,
588 var_Get( p_vout->p_vlc, "drawable", &val );
589 var_Get( p_vout->p_vlc, "drawablet", &valt );
590 var_Get( p_vout->p_vlc, "drawablel", &vall );
591 var_Get( p_vout->p_vlc, "drawableb", &valb );
592 var_Get( p_vout->p_vlc, "drawabler", &valr );
593 var_Get( p_vout->p_vlc, "drawablex", &valx );
594 var_Get( p_vout->p_vlc, "drawabley", &valy );
595 var_Get( p_vout->p_vlc, "drawablew", &valw );
596 var_Get( p_vout->p_vlc, "drawableh", &valh );
597 var_Get( p_vout->p_vlc, "drawableportx", &valportx );
598 var_Get( p_vout->p_vlc, "drawableporty", &valporty );
600 /* portx, porty contains values for SetOrigin() function
601 which isn't used, instead use QT Translate matrix */
602 p_vout->p_sys->i_origx = valportx.i_int;
603 p_vout->p_sys->i_origy = valporty.i_int;
604 p_vout->p_sys->p_qdport = (CGrafPtr) val.i_int;
605 p_vout->p_sys->i_width = valw.i_int;
606 p_vout->p_sys->i_height = valh.i_int;
608 /* update video clipping mask */
609 /*SetRectRgn( p_vout->p_sys->clip_mask , vall.i_int ,
610 valt.i_int, valr.i_int, valb.i_int );*/
611 SetRectRgn( p_vout->p_sys->clip_mask , vall.i_int + valportx.i_int ,
612 valt.i_int + valporty.i_int , valr.i_int + valportx.i_int ,
613 valb.i_int + valporty.i_int );
615 /* reset drawableredraw variable indicating we are ready
616 to take changes in video geometry */
618 var_Set( p_vout->p_vlc, "drawableredraw", val );
621 /*****************************************************************************
622 * QTScaleMatrix: scale matrix
623 *****************************************************************************/
624 static void QTScaleMatrix( vout_thread_t *p_vout )
627 Fixed factor_x, factor_y;
628 unsigned int i_offset_x = 0;
629 unsigned int i_offset_y = 0;
630 int i_width = p_vout->p_sys->i_width;
631 int i_height = p_vout->p_sys->i_height;
633 var_Get( p_vout, "macosx-stretch", &val );
636 factor_x = FixDiv( Long2Fix( i_width ),
637 Long2Fix( p_vout->output.i_width ) );
638 factor_y = FixDiv( Long2Fix( i_height ),
639 Long2Fix( p_vout->output.i_height ) );
642 else if( i_height * p_vout->fmt_in.i_visible_width *
643 p_vout->fmt_in.i_sar_num <
644 i_width * p_vout->fmt_in.i_visible_height *
645 p_vout->fmt_in.i_sar_den )
647 int i_adj_width = i_height * p_vout->fmt_in.i_visible_width *
648 p_vout->fmt_in.i_sar_num /
649 ( p_vout->fmt_in.i_sar_den *
650 p_vout->fmt_in.i_visible_height );
652 factor_x = FixDiv( Long2Fix( i_adj_width ),
653 Long2Fix( p_vout->fmt_in.i_visible_width ) );
654 factor_y = FixDiv( Long2Fix( i_height ),
655 Long2Fix( p_vout->fmt_in.i_visible_height ) );
657 i_offset_x = (i_width - i_adj_width) / 2;
661 int i_adj_height = i_width * p_vout->fmt_in.i_visible_height *
662 p_vout->fmt_in.i_sar_den /
663 ( p_vout->fmt_in.i_sar_num *
664 p_vout->fmt_in.i_visible_width );
666 factor_x = FixDiv( Long2Fix( i_width ),
667 Long2Fix( p_vout->fmt_in.i_visible_width ) );
668 factor_y = FixDiv( Long2Fix( i_adj_height ),
669 Long2Fix( p_vout->fmt_in.i_visible_height ) );
671 i_offset_y = (i_height - i_adj_height) / 2;
674 SetIdentityMatrix( p_vout->p_sys->p_matrix );
676 ScaleMatrix( p_vout->p_sys->p_matrix,
678 Long2Fix(0), Long2Fix(0) );
680 TranslateMatrix( p_vout->p_sys->p_matrix,
681 Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
684 /*****************************************************************************
685 * QTCreateSequence: create a new sequence
686 *****************************************************************************
687 * Returns 0 on success, 1 otherwise
688 *****************************************************************************/
689 static int QTCreateSequence( vout_thread_t *p_vout )
692 ImageDescriptionPtr p_descr;
694 HLock( (Handle)p_vout->p_sys->h_img_descr );
695 p_descr = *p_vout->p_sys->h_img_descr;
697 p_descr->idSize = sizeof(ImageDescription);
698 p_descr->cType = p_vout->p_sys->i_codec;
699 p_descr->version = 2;
700 p_descr->revisionLevel = 0;
701 p_descr->vendor = 'mpla';
702 p_descr->width = p_vout->output.i_width;
703 p_descr->height = p_vout->output.i_height;
704 p_descr->hRes = Long2Fix(72);
705 p_descr->vRes = Long2Fix(72);
706 p_descr->spatialQuality = codecLosslessQuality;
707 p_descr->frameCount = 1;
708 p_descr->clutID = -1;
709 p_descr->dataSize = 0;
712 HUnlock( (Handle)p_vout->p_sys->h_img_descr );
714 if( ( err = DecompressSequenceBeginS(
715 &p_vout->p_sys->i_seq,
716 p_vout->p_sys->h_img_descr,
718 (p_descr->width * p_descr->height * 16) / 8,
719 p_vout->p_sys->p_qdport,
721 p_vout->p_sys->p_matrix,
722 srcCopy, p_vout->p_sys->clip_mask,
723 codecFlagUseImageBuffer,
724 codecLosslessQuality,
727 msg_Err( p_vout, "Failed to initialize QT: DecompressSequenceBeginS failed: %d", err );
734 /*****************************************************************************
735 * QTDestroySequence: destroy sequence
736 *****************************************************************************/
737 static void QTDestroySequence( vout_thread_t *p_vout )
739 CDSequenceEnd( p_vout->p_sys->i_seq );
742 /*****************************************************************************
743 * QTNewPicture: allocate a picture
744 *****************************************************************************
745 * Returns 0 on success, 1 otherwise
746 *****************************************************************************/
747 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
749 /* We know the chroma, allocate a buffer which will be used
750 * directly by the decoder */
751 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
753 if( p_pic->p_sys == NULL )
758 vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
759 p_vout->output.i_width, p_vout->output.i_height,
760 p_vout->output.i_aspect );
762 switch( p_vout->output.i_chroma )
764 case VLC_FOURCC('Y','U','Y','2'):
765 p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
767 /* Allocate the memory buffer */
768 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
769 16, p_pic->p_sys->i_size );
771 p_pic->p[0].p_pixels = p_pic->p_data;
772 p_pic->p[0].i_lines = p_vout->output.i_height;
773 p_pic->p[0].i_visible_lines = p_vout->output.i_height;
774 p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
775 p_pic->p[0].i_pixel_pitch = 1;
776 p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
779 p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
783 case VLC_FOURCC('I','4','2','0'):
784 p_pic->p_sys->p_data = (void *)&p_pic->p_sys->pixmap_i420;
785 p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
787 /* Allocate the memory buffer */
788 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
789 16, p_vout->output.i_width * p_vout->output.i_height * 3 / 2 );
792 p_pic->Y_PIXELS = p_pic->p_data;
793 p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
794 p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
795 p_pic->p[Y_PLANE].i_pitch = p_vout->output.i_width;
796 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
797 p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width;
800 p_pic->U_PIXELS = p_pic->Y_PIXELS + p_vout->output.i_height * p_vout->output.i_width;
801 p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
802 p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
803 p_pic->p[U_PLANE].i_pitch = p_vout->output.i_width / 2;
804 p_pic->p[U_PLANE].i_pixel_pitch = 1;
805 p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
808 p_pic->V_PIXELS = p_pic->U_PIXELS + p_vout->output.i_height * p_vout->output.i_width / 4;
809 p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
810 p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
811 p_pic->p[V_PLANE].i_pitch = p_vout->output.i_width / 2;
812 p_pic->p[V_PLANE].i_pixel_pitch = 1;
813 p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2;
815 /* We allocated 3 planes */
818 #define P p_pic->p_sys->pixmap_i420
819 P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
820 - p_pic->p_sys->p_data;
821 P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
822 - p_pic->p_sys->p_data;
823 P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
824 - p_pic->p_sys->p_data;
826 P.componentInfoY.rowBytes = p_vout->output.i_width;
827 P.componentInfoCb.rowBytes = p_vout->output.i_width / 2;
828 P.componentInfoCr.rowBytes = p_vout->output.i_width / 2;
833 /* Unknown chroma, tell the guy to get lost */
834 free( p_pic->p_sys );
835 msg_Err( p_vout, "Unknown chroma format 0x%.8x (%4.4s)",
836 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
844 /*****************************************************************************
845 * QTFreePicture: destroy a picture allocated with QTNewPicture
846 *****************************************************************************/
847 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
849 switch( p_vout->output.i_chroma )
851 case VLC_FOURCC('I','4','2','0'):
852 free( p_pic->p_data_orig );
856 free( p_pic->p_sys );
859 /*****************************************************************************
860 * VLCQTView implementation
861 *****************************************************************************/
862 @implementation VLCQTView
864 - (id) initWithVout:(vout_thread_t *)_p_vout
870 - (void)drawRect:(NSRect)rect
872 [[NSColor blackColor] set];
874 [super drawRect: rect];
876 p_vout->i_changes |= VOUT_SIZE_CHANGE;