1 /*****************************************************************************
2 * vout.m: MacOS X video output module
3 *****************************************************************************
4 * Copyright (C) 2001-2003 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #include <errno.h> /* ENOMEM */
32 #include <stdlib.h> /* free() */
33 #include <string.h> /* strerror() */
35 #include <QuickTime/QuickTime.h>
37 #include <OpenGL/OpenGL.h>
38 #include <OpenGL/gl.h>
39 #include <OpenGL/glext.h>
46 #define QT_MAX_DIRECTBUFFERS 10
47 #define VL_MAX_DISPLAYS 16
49 #define OPENGL_EFFECT_NONE 1
50 #define OPENGL_EFFECT_CUBE 2
51 #define OPENGL_EFFECT_TRANSPARENT_CUBE 4
59 /*****************************************************************************
61 *****************************************************************************/
63 static int InitVideo ( vout_thread_t * );
64 static void EndVideo ( vout_thread_t * );
65 static int ManageVideo ( vout_thread_t * );
66 static void DisplayVideo ( vout_thread_t *, picture_t * );
67 static int ControlVideo ( vout_thread_t *, int, va_list );
69 static int CoCreateWindow ( vout_thread_t * );
70 static int CoDestroyWindow ( vout_thread_t * );
72 static int CoToggleFullscreen ( vout_thread_t * );
73 static int CoSetWindowOnTop ( vout_thread_t *, BOOL );
74 static void VLCHideMouse ( vout_thread_t *, BOOL );
76 static void QTScaleMatrix ( vout_thread_t * );
77 static int QTCreateSequence ( vout_thread_t * );
78 static void QTDestroySequence ( vout_thread_t * );
79 static int QTNewPicture ( vout_thread_t *, picture_t * );
80 static void QTFreePicture ( vout_thread_t *, picture_t * );
82 /*****************************************************************************
83 * OpenVideo: allocates MacOS X video thread output method
84 *****************************************************************************
85 * This function allocates and initializes a MacOS X vout method.
86 *****************************************************************************/
87 int E_(OpenVideo) ( vlc_object_t *p_this )
89 vout_thread_t * p_vout = (vout_thread_t *)p_this;
94 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
95 if( p_vout->p_sys == NULL )
97 msg_Err( p_vout, "out of memory" );
101 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
103 /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
104 for( i_timeout = 20 ; i_timeout-- ; )
108 msleep( INTF_IDLE_SLEEP );
114 /* no MacOS X intf, unable to communicate with MT */
115 msg_Err( p_vout, "no MacOS X interface present" );
116 free( p_vout->p_sys );
120 p_vout->pf_init = InitVideo;
121 p_vout->pf_end = EndVideo;
122 p_vout->pf_manage = ManageVideo;
123 p_vout->pf_render = NULL;
124 p_vout->pf_display = DisplayVideo;
125 p_vout->pf_control = ControlVideo;
127 p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
128 p_vout->p_sys->b_mouse_moved = VLC_TRUE;
129 p_vout->p_sys->i_time_mouse_last_moved = mdate();
131 /* set original window size */
132 p_vout->p_sys->s_rect.size.width = p_vout->i_window_width;
133 p_vout->p_sys->s_rect.size.height = p_vout->i_window_height;
135 var_Create( p_vout, "macosx-vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
136 var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
137 var_Create( p_vout, "macosx-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
138 var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
139 var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
140 var_Create( p_vout, "macosx-opengl-effect", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
142 /* Check if we should use QuickTime or OpenGL */
143 var_Get( p_vout, "macosx-vout", &val);
145 if( !strncmp( val.psz_string, "auto", 4 ) )
147 p_vout->p_sys->i_opengl = CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay );
149 else if( !strncmp( val.psz_string, "opengl", 6 ) )
151 p_vout->p_sys->i_opengl = VLC_TRUE;
155 p_vout->p_sys->i_opengl = VLC_FALSE;
157 free( val.psz_string );
159 if( !p_vout->p_sys->i_opengl )
161 /* Initialize QuickTime */
162 p_vout->p_sys->h_img_descr =
163 (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
164 p_vout->p_sys->p_matrix =
165 (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
166 p_vout->p_sys->p_fullscreen_state = NULL;
168 if( ( err = EnterMovies() ) != noErr )
170 msg_Err( p_vout, "EnterMovies failed: %d", err );
171 free( p_vout->p_sys->p_matrix );
172 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
173 free( p_vout->p_sys );
177 /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
178 vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
180 /* Can we find the right chroma ? */
181 err = FindCodec( kComponentVideoUnsigned, bestSpeedCodec,
182 nil, &p_vout->p_sys->img_dc );
184 vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
186 if( err == noErr && p_vout->p_sys->img_dc != 0 )
188 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
189 p_vout->p_sys->i_codec = kComponentVideoUnsigned;
193 msg_Err( p_vout, "failed to find an appropriate codec" );
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 );
203 msg_Dbg( p_vout, "using Quartz mode" );
207 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
208 msg_Dbg( p_vout, "using OpenGL mode" );
211 /* Setup the menuitem for the multiple displays. Read the vlc preference (macosx-vdev) for the primary display */
212 NSArray * o_screens = [NSScreen screens];
213 if( [o_screens count] > 0 && var_Type( p_vout, "video-device" ) == 0 )
216 vlc_value_t val2, text;
219 var_Get( p_vout, "macosx-vdev", &val );
221 var_Create( p_vout, "video-device", VLC_VAR_INTEGER |
223 text.psz_string = _("Video device");
224 var_Change( p_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
226 NSEnumerator * o_enumerator = [o_screens objectEnumerator];
228 while( (o_screen = [o_enumerator nextObject]) != NULL )
231 NSRect s_rect = [o_screen frame];
233 snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
234 "%s %d (%dx%d)", _("Screen"), i,
235 (int)s_rect.size.width, (int)s_rect.size.height );
237 text.psz_string = psz_temp;
239 var_Change( p_vout, "video-device",
240 VLC_VAR_ADDCHOICE, &val2, &text );
242 if( ( i - 1 ) == val.i_int )
244 var_Set( p_vout, "video-device", val2 );
249 var_AddCallback( p_vout, "video-device", vout_VarCallback,
252 val2.b_bool = VLC_TRUE;
253 var_Set( p_vout, "intf-change", val2 );
257 if( CoCreateWindow( p_vout ) )
259 msg_Err( p_vout, "unable to create a window" );
260 if( !p_vout->p_sys->i_opengl )
262 free( p_vout->p_sys->p_matrix );
263 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
265 free( p_vout->p_sys );
272 /*****************************************************************************
273 * CloseVideo: destroy video thread output method
274 *****************************************************************************/
275 void E_(CloseVideo) ( vlc_object_t *p_this )
277 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
278 vout_thread_t * p_vout = (vout_thread_t *)p_this;
280 if( CoDestroyWindow( p_vout ) )
282 msg_Err( p_vout, "unable to destroy window" );
285 if ( p_vout->p_sys->p_fullscreen_state != NULL )
287 EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
290 if( !p_vout->p_sys->i_opengl )
292 /* Clean Up Quicktime environment */
294 free( p_vout->p_sys->p_matrix );
295 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
299 [p_vout->p_sys->o_glview cleanUp];
303 free( p_vout->p_sys );
306 /*****************************************************************************
307 * InitVideo: initialize video thread output method
308 *****************************************************************************/
309 static int InitOpenGL ( vout_thread_t *p_vout );
310 static int InitQuickTime( vout_thread_t *p_vout );
311 static int InitVideo ( vout_thread_t *p_vout )
313 I_OUTPUTPICTURES = 0;
315 /* Initialize the output structure; we already found a codec,
316 * and the corresponding chroma we will be using. Since we can
317 * arbitrary scale, stick to the coordinates and aspect. */
318 p_vout->output.i_width = p_vout->render.i_width;
319 p_vout->output.i_height = p_vout->render.i_height;
320 p_vout->output.i_aspect = p_vout->render.i_aspect;
322 if( p_vout->p_sys->i_opengl )
324 return InitOpenGL( p_vout );
328 return InitQuickTime( p_vout );
332 static int InitOpenGL( vout_thread_t *p_vout )
334 picture_t *p_pic = NULL;
338 /* Apple OpenGL extensions only accept YUV as YUY2 */
339 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
340 p_vout->output.i_rmask = 0xFF0000;
341 p_vout->output.i_gmask = 0x00FF00;
342 p_vout->output.i_bmask = 0x0000FF;
344 /* Allocate our 2 picture buffers */
345 i_bytes = 2 * p_vout->output.i_width * p_vout->output.i_height;
346 p_vout->p_sys->p_data[0] = vlc_memalign(
347 &p_vout->p_sys->p_data_orig[0], 16, i_bytes );
348 p_vout->p_sys->p_data[1] = vlc_memalign(
349 &p_vout->p_sys->p_data_orig[1], 16, i_bytes );
350 p_vout->p_sys->i_cur_pic = 1;
352 /* We declare only one picture and will switch buffers manually */
353 while( I_OUTPUTPICTURES < 1 )
355 /* Find an empty picture slot */
356 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
358 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
360 p_pic = p_vout->p_picture + i_index;
369 vout_InitPicture( VLC_OBJECT( p_vout ), p_pic,
370 p_vout->output.i_chroma, p_vout->output.i_width,
371 p_vout->output.i_height, p_vout->output.i_aspect );
372 p_pic->p_data = p_vout->p_sys->p_data[0];
373 p_pic->p[0].p_pixels = p_pic->p_data;
374 for( i_index = 1; i_index < p_pic->i_planes; i_index++ )
376 p_pic->p[i_index].p_pixels =
377 p_pic->p[i_index-1].p_pixels +
378 p_pic->p[i_index-1].i_lines *
379 p_pic->p[i_index-1].i_pitch;
382 p_pic->i_status = DESTROYED_PICTURE;
383 p_pic->i_type = DIRECT_PICTURE;
385 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
389 [p_vout->p_sys->o_glview lockFocus];
390 [p_vout->p_sys->o_glview initTextures];
391 [p_vout->p_sys->o_glview reshape];
392 [p_vout->p_sys->o_glview unlockFocus];
397 static int InitQuickTime( vout_thread_t *p_vout )
402 SetPort( p_vout->p_sys->p_qdport );
403 QTScaleMatrix( p_vout );
405 if( QTCreateSequence( p_vout ) )
407 msg_Err( p_vout, "unable to create sequence" );
411 /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
412 while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS )
416 /* Find an empty picture slot */
417 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
419 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
421 p_pic = p_vout->p_picture + i_index;
426 /* Allocate the picture */
427 if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) )
432 p_pic->i_status = DESTROYED_PICTURE;
433 p_pic->i_type = DIRECT_PICTURE;
435 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
441 /*****************************************************************************
442 * EndVideo: terminate video thread output method
443 *****************************************************************************/
444 static void EndVideo( vout_thread_t *p_vout )
448 if( !p_vout->p_sys->i_opengl )
450 QTDestroySequence( p_vout );
453 /* Free the direct buffers we allocated */
454 for( i_index = I_OUTPUTPICTURES; i_index; )
457 if( !p_vout->p_sys->i_opengl )
459 QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
463 free( p_vout->p_sys->p_data_orig[0] );
464 free( p_vout->p_sys->p_data_orig[1] );
469 /*****************************************************************************
470 * ManageVideo: handle events
471 *****************************************************************************
472 * This function should be called regularly by video output thread. It manages
473 * console events. It returns a non null value on error.
474 *****************************************************************************/
475 static int ManageVideo( vout_thread_t *p_vout )
477 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
479 if( CoToggleFullscreen( p_vout ) )
484 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
487 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
489 if( !p_vout->p_sys->i_opengl )
491 QTScaleMatrix( p_vout );
492 SetDSequenceMatrix( p_vout->p_sys->i_seq,
493 p_vout->p_sys->p_matrix );
496 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
499 /* hide/show mouse cursor
500 * this code looks unnecessarily complicated, but is necessary like this.
501 * it has to deal with multiple monitors and therefore checks a lot */
502 if( !p_vout->p_sys->b_mouse_moved && p_vout->b_fullscreen )
504 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 3000000 )
506 VLCHideMouse( p_vout, YES );
509 else if ( p_vout->p_sys->b_mouse_moved && p_vout->b_fullscreen )
511 VLCHideMouse( p_vout, NO );
514 /* disable screen saver */
515 UpdateSystemActivity( UsrActivity );
520 /*****************************************************************************
521 * vout_Display: displays previously rendered output
522 *****************************************************************************
523 * This function sends the currently rendered image to the display.
524 *****************************************************************************/
525 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
527 if( !p_vout->p_sys->i_opengl )
532 if( ( err = DecompressSequenceFrameWhen(
533 p_vout->p_sys->i_seq,
534 p_pic->p_sys->p_data,
535 p_pic->p_sys->i_size,
536 codecFlagUseImageBuffer, &flags, NULL, NULL ) != noErr ) )
538 msg_Warn( p_vout, "DecompressSequenceFrameWhen failed: %d", err );
542 QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
547 if( [p_vout->p_sys->o_glview lockFocusIfCanDraw] )
550 int i_old = p_vout->p_sys->i_cur_pic;
551 int i_new = ( i_old + 1 ) % 2;
553 /* Draw the new picture */
554 p_vout->p_sys->i_cur_pic = i_new;
555 [p_vout->p_sys->o_glview drawRect:
556 [p_vout->p_sys->o_glview bounds]];
558 /* Reload the other texture. Textures have to be reloaded
559 before the buffer is filled (thanks to gcc from
560 arstechnica forums) */
561 [p_vout->p_sys->o_glview reloadTexture: i_old];
564 p_pic->p_data = p_vout->p_sys->p_data[i_old];
565 p_pic->p[0].p_pixels = p_pic->p_data;
566 for( i_index = 1; i_index < p_pic->i_planes; i_index++ )
568 p_pic->p[i_index].p_pixels =
569 p_pic->p[i_index-1].p_pixels +
570 p_pic->p[i_index-1].i_lines *
571 p_pic->p[i_index-1].i_pitch;
573 [p_vout->p_sys->o_glview unlockFocus];
578 /*****************************************************************************
579 * ControlVideo: control facility for the vout
580 *****************************************************************************/
581 static int ControlVideo( vout_thread_t *p_vout, int i_query, va_list args )
587 case VOUT_SET_STAY_ON_TOP:
588 b_arg = va_arg( args, vlc_bool_t );
589 CoSetWindowOnTop( p_vout, b_arg );
595 return vout_vaControlDefault( p_vout, i_query, args );
599 /*****************************************************************************
600 * CoCreateWindow: create new window
601 *****************************************************************************
602 * Returns 0 on success, 1 otherwise
603 *****************************************************************************/
604 static int CoCreateWindow( vout_thread_t *p_vout )
608 vlc_bool_t b_main_screen;
609 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
611 /* Allocate the window. It will be autoreleased when it receives 'close' */
612 p_vout->p_sys->o_window = [VLCWindow alloc];
613 [p_vout->p_sys->o_window setReleasedWhenClosed: YES];
615 /* Find out on which screen to open the window */
616 var_Get( p_vout, "video-device", &val );
619 /* No preference specified. Use the main screen */
620 o_screen = [NSScreen mainScreen];
625 NSArray *o_screens = [NSScreen screens];
626 unsigned int i_index = val.i_int;
628 if( [o_screens count] < i_index )
630 o_screen = [NSScreen mainScreen];
636 o_screen = [o_screens objectAtIndex: i_index];
638 var_Set( p_vout, "macosx-vdev", val );
639 b_main_screen = (i_index == 0);
643 if( p_vout->b_fullscreen )
645 NSRect screen_rect = [o_screen frame];
646 screen_rect.origin.x = screen_rect.origin.y = 0;
648 if ( b_main_screen && p_vout->p_sys->p_fullscreen_state == NULL )
649 BeginFullScreen( &p_vout->p_sys->p_fullscreen_state, NULL, 0, 0,
650 NULL, NULL, fullScreenAllowEvents );
652 /* Creates a window with size: screen_rect on o_screen */
653 [p_vout->p_sys->o_window
654 initWithContentRect: screen_rect
655 styleMask: NSBorderlessWindowMask
656 backing: NSBackingStoreBuffered
657 defer: NO screen: o_screen];
659 [p_vout->p_sys->o_window setVout: p_vout];
660 p_vout->p_sys->b_mouse_moved = YES;
661 p_vout->p_sys->i_time_mouse_last_moved = mdate();
665 unsigned int i_stylemask = NSTitledWindowMask |
666 NSMiniaturizableWindowMask |
667 NSClosableWindowMask |
668 NSResizableWindowMask;
670 if ( p_vout->p_sys->p_fullscreen_state != NULL )
671 EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
672 p_vout->p_sys->p_fullscreen_state = NULL;
674 [p_vout->p_sys->o_window
675 initWithContentRect: p_vout->p_sys->s_rect
676 styleMask: i_stylemask
677 backing: NSBackingStoreBuffered
678 defer: NO screen: o_screen];
680 [p_vout->p_sys->o_window setVout: p_vout];
681 var_Get( p_vout, "macosx-opaqueness", &val);
682 [p_vout->p_sys->o_window setAlphaValue: val.f_float];
684 var_Get( p_vout, "video-on-top", &val );
685 if( val.b_bool ) [p_vout->p_sys->o_window setLevel: NSStatusWindowLevel];
687 if( !p_vout->p_sys->b_pos_saved ) [p_vout->p_sys->o_window center];
690 if( !p_vout->p_sys->i_opengl )
692 #define o_qtview p_vout->p_sys->o_qtview
693 o_qtview = [[VLCQTView alloc] init];
694 [p_vout->p_sys->o_window setContentView: o_qtview];
695 [o_qtview autorelease];
697 /* Retrieve the QuickDraw port */
698 [o_qtview lockFocus];
699 p_vout->p_sys->p_qdport = [o_qtview qdPort];
700 [o_qtview unlockFocus];
705 #define o_glview p_vout->p_sys->o_glview
706 o_glview = [[VLCGLView alloc] initWithFrame: p_vout->p_sys->s_rect vout: p_vout];
707 [p_vout->p_sys->o_window setContentView: o_glview];
708 [o_glview autorelease];
712 [p_vout->p_sys->o_window updateTitle];
713 [p_vout->p_sys->o_window makeKeyAndOrderFront: nil];
719 /*****************************************************************************
720 * CoDestroyWindow: destroy window
721 *****************************************************************************
722 * Returns 0 on success, 1 otherwise
723 *****************************************************************************/
724 static int CoDestroyWindow( vout_thread_t *p_vout )
726 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
727 VLCHideMouse( p_vout, NO );
729 if( !p_vout->b_fullscreen )
733 /* remember the window position before we enter fullscreen */
734 s_rect = [[p_vout->p_sys->o_window contentView] frame];
735 p_vout->p_sys->s_rect.size = s_rect.size;
737 s_rect = [p_vout->p_sys->o_window frame];
738 p_vout->p_sys->s_rect.origin = s_rect.origin;
740 p_vout->p_sys->b_pos_saved = YES;
743 p_vout->p_sys->p_qdport = nil;
744 [p_vout->p_sys->o_window close];
745 p_vout->p_sys->o_window = nil;
750 /*****************************************************************************
751 * CoToggleFullscreen: toggle fullscreen
752 *****************************************************************************
753 * Returns 0 on success, 1 otherwise
754 *****************************************************************************/
755 static int CoToggleFullscreen( vout_thread_t *p_vout )
757 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
759 if( !p_vout->p_sys->i_opengl )
761 QTDestroySequence( p_vout );
764 if( CoDestroyWindow( p_vout ) )
766 msg_Err( p_vout, "unable to destroy window" );
770 p_vout->b_fullscreen = !p_vout->b_fullscreen;
772 if( CoCreateWindow( p_vout ) )
774 msg_Err( p_vout, "unable to create window" );
778 if( p_vout->p_sys->i_opengl )
780 [p_vout->p_sys->o_glview lockFocus];
781 [p_vout->p_sys->o_glview initTextures];
782 [p_vout->p_sys->o_glview reshape];
783 [p_vout->p_sys->o_glview drawRect:
784 [p_vout->p_sys->o_glview bounds]];
785 [p_vout->p_sys->o_glview unlockFocus];
789 SetPort( p_vout->p_sys->p_qdport );
790 QTScaleMatrix( p_vout );
792 if( QTCreateSequence( p_vout ) )
794 msg_Err( p_vout, "unable to create sequence" );
803 /*****************************************************************************
804 * CoSetWindowOnTop: Switches the "always on top" state of the video window
805 *****************************************************************************
806 * Returns 0 on success, 1 otherwise
807 *****************************************************************************/
808 static int CoSetWindowOnTop( vout_thread_t *p_vout, BOOL b_on_top )
810 if( p_vout->p_sys->o_window )
814 [p_vout->p_sys->o_window setLevel: NSStatusWindowLevel];
818 [p_vout->p_sys->o_window setLevel: NSNormalWindowLevel];
825 /*****************************************************************************
826 * VLCHideMouse: if b_hide then hide the cursor
827 *****************************************************************************/
828 static void VLCHideMouse ( vout_thread_t *p_vout, BOOL b_hide )
833 NSWindow *o_window = p_vout->p_sys->o_window;
834 NSView *o_contents = [o_window contentView];
836 s_rect = [o_contents bounds];
837 ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
838 ml = [o_contents convertPoint:ml fromView:nil];
839 b_inside = [o_contents mouse: ml inRect: s_rect];
841 if ( b_hide && b_inside )
843 /* only hide if mouse over VLCQTView */
844 [NSCursor setHiddenUntilMouseMoves: YES];
848 [NSCursor setHiddenUntilMouseMoves: NO];
850 p_vout->p_sys->b_mouse_moved = NO;
851 p_vout->p_sys->i_time_mouse_last_moved = mdate();
855 /*****************************************************************************
856 * QTScaleMatrix: scale matrix
857 *****************************************************************************/
858 static void QTScaleMatrix( vout_thread_t *p_vout )
862 unsigned int i_width, i_height;
863 Fixed factor_x, factor_y;
864 unsigned int i_offset_x = 0;
865 unsigned int i_offset_y = 0;
867 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
869 i_width = s_rect.right - s_rect.left;
870 i_height = s_rect.bottom - s_rect.top;
872 var_Get( p_vout, "macosx-stretch", &val );
875 factor_x = FixDiv( Long2Fix( i_width ),
876 Long2Fix( p_vout->output.i_width ) );
877 factor_y = FixDiv( Long2Fix( i_height ),
878 Long2Fix( p_vout->output.i_height ) );
881 else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
883 int i_adj_width = i_height * p_vout->output.i_aspect /
886 factor_x = FixDiv( Long2Fix( i_adj_width ),
887 Long2Fix( p_vout->output.i_width ) );
888 factor_y = FixDiv( Long2Fix( i_height ),
889 Long2Fix( p_vout->output.i_height ) );
891 i_offset_x = (i_width - i_adj_width) / 2;
895 int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
896 p_vout->output.i_aspect;
898 factor_x = FixDiv( Long2Fix( i_width ),
899 Long2Fix( p_vout->output.i_width ) );
900 factor_y = FixDiv( Long2Fix( i_adj_height ),
901 Long2Fix( p_vout->output.i_height ) );
903 i_offset_y = (i_height - i_adj_height) / 2;
906 SetIdentityMatrix( p_vout->p_sys->p_matrix );
908 ScaleMatrix( p_vout->p_sys->p_matrix,
910 Long2Fix(0), Long2Fix(0) );
912 TranslateMatrix( p_vout->p_sys->p_matrix,
913 Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
916 /*****************************************************************************
917 * QTCreateSequence: create a new sequence
918 *****************************************************************************
919 * Returns 0 on success, 1 otherwise
920 *****************************************************************************/
921 static int QTCreateSequence( vout_thread_t *p_vout )
924 ImageDescriptionPtr p_descr;
926 HLock( (Handle)p_vout->p_sys->h_img_descr );
927 p_descr = *p_vout->p_sys->h_img_descr;
929 p_descr->idSize = sizeof(ImageDescription);
930 p_descr->cType = p_vout->p_sys->i_codec;
931 p_descr->version = 2;
932 p_descr->revisionLevel = 0;
933 p_descr->vendor = 'mpla';
934 p_descr->width = p_vout->output.i_width;
935 p_descr->height = p_vout->output.i_height;
936 p_descr->hRes = Long2Fix(72);
937 p_descr->vRes = Long2Fix(72);
938 p_descr->spatialQuality = codecLosslessQuality;
939 p_descr->frameCount = 1;
940 p_descr->clutID = -1;
941 p_descr->dataSize = 0;
944 HUnlock( (Handle)p_vout->p_sys->h_img_descr );
946 if( ( err = DecompressSequenceBeginS(
947 &p_vout->p_sys->i_seq,
948 p_vout->p_sys->h_img_descr,
950 (p_descr->width * p_descr->height * 16) / 8,
951 p_vout->p_sys->p_qdport,
953 p_vout->p_sys->p_matrix,
955 codecFlagUseImageBuffer,
956 codecLosslessQuality,
959 msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
966 /*****************************************************************************
967 * QTDestroySequence: destroy sequence
968 *****************************************************************************/
969 static void QTDestroySequence( vout_thread_t *p_vout )
971 CDSequenceEnd( p_vout->p_sys->i_seq );
974 /*****************************************************************************
975 * QTNewPicture: allocate a picture
976 *****************************************************************************
977 * Returns 0 on success, 1 otherwise
978 *****************************************************************************/
979 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
981 /* We know the chroma, allocate a buffer which will be used
982 * directly by the decoder */
983 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
985 if( p_pic->p_sys == NULL )
990 vout_InitPicture( VLC_OBJECT( p_vout), p_pic, p_vout->output.i_chroma,
991 p_vout->output.i_width, p_vout->output.i_height,
992 p_vout->output.i_aspect );
994 switch( p_vout->output.i_chroma )
996 case VLC_FOURCC('Y','U','Y','2'):
997 p_pic->p_sys->i_size = p_vout->output.i_width * p_vout->output.i_height * 2;
999 /* Allocate the memory buffer */
1000 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
1001 16, p_pic->p_sys->i_size );
1003 p_pic->p[0].p_pixels = p_pic->p_data;
1004 p_pic->p[0].i_lines = p_vout->output.i_height;
1005 p_pic->p[0].i_pitch = p_vout->output.i_width * 2;
1006 p_pic->p[0].i_pixel_pitch = 1;
1007 p_pic->p[0].i_visible_pitch = p_vout->output.i_width * 2;
1008 p_pic->i_planes = 1;
1010 p_pic->p_sys->p_data = (void *)p_pic->p[0].p_pixels;
1015 /* Unknown chroma, tell the guy to get lost */
1016 free( p_pic->p_sys );
1017 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
1018 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
1019 p_pic->i_planes = 0;
1026 /*****************************************************************************
1027 * QTFreePicture: destroy a picture allocated with QTNewPicture
1028 *****************************************************************************/
1029 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1031 switch( p_vout->output.i_chroma )
1033 case VLC_FOURCC('I','4','2','0'):
1034 free( p_pic->p_data_orig );
1038 free( p_pic->p_sys );
1041 /*****************************************************************************
1042 * VLCWindow implementation
1043 *****************************************************************************/
1044 @implementation VLCWindow
1046 - (void)setVout:(vout_thread_t *)_p_vout
1051 - (vout_thread_t *)getVout
1056 - (void)scaleWindowWithFactor: (float)factor
1059 int i_corrected_height, i_corrected_width;
1060 NSPoint topleftbase;
1061 NSPoint topleftscreen;
1063 if ( !p_vout->b_fullscreen )
1066 topleftbase.y = [self frame].size.height;
1067 topleftscreen = [self convertBaseToScreen: topleftbase];
1069 if( p_vout->output.i_height * p_vout->output.i_aspect >
1070 p_vout->output.i_width * VOUT_ASPECT_FACTOR )
1072 i_corrected_width = p_vout->output.i_height * p_vout->output.i_aspect /
1074 newsize.width = (int) ( i_corrected_width * factor );
1075 newsize.height = (int) ( p_vout->render.i_height * factor );
1079 i_corrected_height = p_vout->output.i_width * VOUT_ASPECT_FACTOR /
1080 p_vout->output.i_aspect;
1081 newsize.width = (int) ( p_vout->render.i_width * factor );
1082 newsize.height = (int) ( i_corrected_height * factor );
1085 [self setContentSize: newsize];
1087 [self setFrameTopLeftPoint: topleftscreen];
1088 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1092 - (void)toggleFloatOnTop
1095 if( var_Get( p_vout, "video-on-top", &val )>=0 && val.b_bool)
1097 val.b_bool = VLC_FALSE;
1098 var_Set( p_vout, "video-on-top", val );
1102 val.b_bool = VLC_TRUE;
1103 var_Set( p_vout, "video-on-top", val );
1107 - (void)toggleFullscreen
1110 val.b_bool = !p_vout->b_fullscreen;
1111 var_Set( p_vout, "fullscreen", val );
1114 - (BOOL)isFullscreen
1116 return( p_vout->b_fullscreen );
1119 - (BOOL)canBecomeKeyWindow
1124 /* Sometimes crashes VLC....
1125 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
1127 return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event];
1130 - (void)keyDown:(NSEvent *)o_event
1134 unsigned int i_pressed_modifiers = 0;
1137 i_pressed_modifiers = [o_event modifierFlags];
1139 if( i_pressed_modifiers & NSShiftKeyMask )
1140 val.i_int |= KEY_MODIFIER_SHIFT;
1141 if( i_pressed_modifiers & NSControlKeyMask )
1142 val.i_int |= KEY_MODIFIER_CTRL;
1143 if( i_pressed_modifiers & NSAlternateKeyMask )
1144 val.i_int |= KEY_MODIFIER_ALT;
1145 if( i_pressed_modifiers & NSCommandKeyMask )
1146 val.i_int |= KEY_MODIFIER_COMMAND;
1148 key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
1152 /* Escape should always get you out of fullscreen */
1153 if( key == (unichar) 0x1b )
1155 if( [self isFullscreen] )
1157 [self toggleFullscreen];
1160 else if ( key == ' ' )
1163 val.i_int = config_GetInt( p_vout, "key-play-pause" );
1164 var_Set( p_vout->p_vlc, "key-pressed", val );
1168 val.i_int |= CocoaKeyToVLC( key );
1169 var_Set( p_vout->p_vlc, "key-pressed", val );
1174 [super keyDown: o_event];
1180 NSMutableString * o_title;
1181 playlist_t * p_playlist;
1183 if( p_vout == NULL )
1188 p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1191 if( p_playlist == NULL )
1196 vlc_mutex_lock( &p_playlist->object_lock );
1197 o_title = [NSMutableString stringWithUTF8String:
1198 p_playlist->pp_items[p_playlist->i_index]->input.psz_uri];
1199 vlc_mutex_unlock( &p_playlist->object_lock );
1201 vlc_object_release( p_playlist );
1203 if( o_title != nil )
1205 NSRange prefix_range = [o_title rangeOfString: @"file:"];
1206 if( prefix_range.location != NSNotFound )
1208 [o_title deleteCharactersInRange: prefix_range];
1211 [self setTitleWithRepresentedFilename: o_title];
1216 [NSString stringWithCString: VOUT_TITLE " (QuickTime)"]];
1220 /* This is actually the same as VLCControls::stop. */
1221 - (BOOL)windowShouldClose:(id)sender
1223 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1225 if( p_playlist == NULL )
1230 playlist_Stop( p_playlist );
1231 vlc_object_release( p_playlist );
1233 /* The window will be closed by the intf later. */
1239 /* Common QT and OpenGL code to catch mouse events */
1240 #define CATCH_MOUSE_EVENTS \
1241 - (BOOL)acceptsFirstResponder \
1246 - (BOOL)becomeFirstResponder \
1248 id o_window = [self window]; \
1250 [o_window setAcceptsMouseMovedEvents: YES]; \
1254 - (BOOL)resignFirstResponder \
1256 vout_thread_t * vout; \
1257 id o_window = [self window]; \
1258 vout = (vout_thread_t *)[o_window getVout]; \
1260 [o_window setAcceptsMouseMovedEvents: NO]; \
1261 VLCHideMouse( vout, NO ); \
1265 - (void)mouseDown:(NSEvent *)o_event \
1267 vout_thread_t * vout; \
1268 id o_window = [self window]; \
1269 vout = (vout_thread_t *)[o_window getVout]; \
1272 switch( [o_event type] ) \
1274 case NSLeftMouseDown: \
1276 var_Get( vout, "mouse-button-down", &val ); \
1278 var_Set( vout, "mouse-button-down", val ); \
1283 [super mouseDown: o_event]; \
1288 - (void)otherMouseDown:(NSEvent *)o_event \
1290 vout_thread_t * vout; \
1291 id o_window = [self window]; \
1292 vout = (vout_thread_t *)[o_window getVout]; \
1295 switch( [o_event type] ) \
1297 case NSOtherMouseDown: \
1299 var_Get( vout, "mouse-button-down", &val ); \
1301 var_Set( vout, "mouse-button-down", val ); \
1306 [super mouseDown: o_event]; \
1311 - (void)rightMouseDown:(NSEvent *)o_event \
1313 vout_thread_t * vout; \
1314 id o_window = [self window]; \
1315 vout = (vout_thread_t *)[o_window getVout]; \
1318 switch( [o_event type] ) \
1320 case NSRightMouseDown: \
1322 var_Get( vout, "mouse-button-down", &val ); \
1324 var_Set( vout, "mouse-button-down", val ); \
1329 [super mouseDown: o_event]; \
1334 - (void)mouseUp:(NSEvent *)o_event \
1336 vout_thread_t * vout; \
1337 id o_window = [self window]; \
1338 vout = (vout_thread_t *)[o_window getVout]; \
1341 switch( [o_event type] ) \
1343 case NSLeftMouseUp: \
1345 vlc_value_t b_val; \
1346 b_val.b_bool = VLC_TRUE; \
1347 var_Set( vout, "mouse-clicked", b_val ); \
1349 var_Get( vout, "mouse-button-down", &val ); \
1351 var_Set( vout, "mouse-button-down", val ); \
1356 [super mouseUp: o_event]; \
1361 - (void)otherMouseUp:(NSEvent *)o_event \
1363 vout_thread_t * vout; \
1364 id o_window = [self window]; \
1365 vout = (vout_thread_t *)[o_window getVout]; \
1368 switch( [o_event type] ) \
1370 case NSOtherMouseUp: \
1372 var_Get( vout, "mouse-button-down", &val ); \
1374 var_Set( vout, "mouse-button-down", val ); \
1379 [super mouseUp: o_event]; \
1384 - (void)rightMouseUp:(NSEvent *)o_event \
1386 vout_thread_t * vout; \
1387 id o_window = [self window]; \
1388 vout = (vout_thread_t *)[o_window getVout]; \
1391 switch( [o_event type] ) \
1393 case NSRightMouseUp: \
1395 var_Get( vout, "mouse-button-down", &val ); \
1397 var_Set( vout, "mouse-button-down", val ); \
1402 [super mouseUp: o_event]; \
1407 - (void)mouseDragged:(NSEvent *)o_event \
1409 [self mouseMoved:o_event]; \
1412 - (void)otherMouseDragged:(NSEvent *)o_event \
1414 [self mouseMoved:o_event]; \
1417 - (void)rightMouseDragged:(NSEvent *)o_event \
1419 [self mouseMoved:o_event]; \
1422 /*****************************************************************************
1423 * VLCQTView implementation
1424 *****************************************************************************/
1425 @implementation VLCQTView
1427 - (void)drawRect:(NSRect)rect
1429 vout_thread_t * p_vout;
1430 id o_window = [self window];
1431 p_vout = (vout_thread_t *)[o_window getVout];
1433 [[NSColor blackColor] set];
1435 [super drawRect: rect];
1437 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1442 - (void)mouseMoved:(NSEvent *)o_event
1448 vout_thread_t * p_vout;
1449 id o_window = [self window];
1450 p_vout = (vout_thread_t *)[o_window getVout];
1452 s_rect = [self bounds];
1453 ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
1454 b_inside = [self mouse: ml inRect: s_rect];
1459 int i_width, i_height, i_x, i_y;
1461 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
1462 (unsigned int)s_rect.size.height,
1463 &i_x, &i_y, &i_width, &i_height );
1465 val.i_int = ( ((int)ml.x) - i_x ) *
1466 p_vout->render.i_width / i_width;
1467 var_Set( p_vout, "mouse-x", val );
1469 val.i_int = ( ((int)ml.y) - i_y ) *
1470 p_vout->render.i_height / i_height;
1471 var_Set( p_vout, "mouse-y", val );
1473 val.b_bool = VLC_TRUE;
1474 var_Set( p_vout, "mouse-moved", val );
1475 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1476 p_vout->p_sys->b_mouse_moved = YES;
1479 [super mouseMoved: o_event];
1484 /*****************************************************************************
1485 * VLCGLView implementation
1486 *****************************************************************************/
1487 @implementation VLCGLView
1490 - (id) initWithFrame: (NSRect) frame vout: (vout_thread_t*) _p_vout
1495 NSOpenGLPixelFormatAttribute attribs[] =
1497 NSOpenGLPFAAccelerated,
1498 NSOpenGLPFANoRecovery,
1499 NSOpenGLPFAColorSize, 24,
1500 NSOpenGLPFAAlphaSize, 8,
1501 NSOpenGLPFADepthSize, 24,
1506 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
1507 initWithAttributes: attribs];
1511 msg_Warn( p_vout, "Cannot create NSOpenGLPixelFormat" );
1515 self = [super initWithFrame:frame pixelFormat: fmt];
1518 [[self openGLContext] makeCurrentContext];
1519 [[self openGLContext] update];
1521 /* Black background */
1522 glClearColor( 0.0, 0.0, 0.0, 0.0 );
1524 /* Check if the user asked for useless visual effects */
1525 var_Get( p_vout, "macosx-opengl-effect", &val );
1526 if( !val.psz_string || !strcmp( val.psz_string, "none" ))
1528 i_effect = OPENGL_EFFECT_NONE;
1530 else if( !strcmp( val.psz_string, "cube" ) )
1532 i_effect = OPENGL_EFFECT_CUBE;
1534 glEnable( GL_DEPTH_TEST );
1536 else if( !strcmp( val.psz_string, "transparent-cube" ) )
1538 i_effect = OPENGL_EFFECT_TRANSPARENT_CUBE;
1540 glDisable( GL_DEPTH_TEST );
1541 glEnable( GL_BLEND );
1542 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
1546 msg_Warn( p_vout, "no valid opengl effect provided, using "
1548 i_effect = OPENGL_EFFECT_NONE;
1550 if( val.psz_string ) free( val.psz_string );
1552 if( i_effect & ( OPENGL_EFFECT_CUBE |
1553 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
1555 /* Set the perpective */
1556 glMatrixMode( GL_PROJECTION );
1558 glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
1559 glMatrixMode( GL_MODELVIEW );
1561 glTranslatef( 0.0, 0.0, - 5.0 );
1581 [[self openGLContext] makeCurrentContext];
1583 bounds = [self bounds];
1584 glViewport( 0, 0, (GLint) bounds.size.width,
1585 (GLint) bounds.size.height );
1587 var_Get( p_vout, "macosx-stretch", &val );
1595 /* Quad size is set in order to preserve the aspect ratio */
1596 var_Get( p_vout, "macosx-fill", &val );
1597 int fill = ( val.b_bool && p_vout->b_fullscreen );
1598 int large = ( bounds.size.height * p_vout->output.i_aspect <
1599 bounds.size.width * VOUT_ASPECT_FACTOR );
1600 if( ( large && !fill ) || ( !large && fill ) )
1602 f_x = bounds.size.height * p_vout->output.i_aspect /
1603 VOUT_ASPECT_FACTOR / bounds.size.width;
1609 f_y = bounds.size.width * VOUT_ASPECT_FACTOR /
1610 p_vout->output.i_aspect / bounds.size.height;
1615 - (void)initTextures
1618 [[self openGLContext] makeCurrentContext];
1620 /* Free previous texture if any */
1623 glDeleteTextures( 2, pi_textures );
1626 glEnable( GL_TEXTURE_RECTANGLE_EXT );
1627 glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
1629 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
1630 glPixelStorei( GL_UNPACK_ROW_LENGTH, p_vout->output.i_width );
1632 /* Tell the driver not to make a copy of the texture but to use
1634 glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );
1636 /* Create textures */
1637 glGenTextures( 2, pi_textures );
1639 for( i = 0; i < 2; i++ )
1641 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, pi_textures[i] );
1642 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
1644 /* Linear interpolation */
1645 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1646 GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1647 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1648 GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1650 /* Use VRAM texturing */
1651 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1652 GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE );
1654 glTexImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGB8,
1655 p_vout->output.i_width, p_vout->output.i_height, 0,
1656 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
1657 p_vout->p_sys->p_data[i] );
1660 /* Swap buffers only during the vertical retrace of the monitor.
1661 http://developer.apple.com/documentation/GraphicsImaging/
1662 Conceptual/OpenGL/chap5/chapter_5_section_44.html */
1663 long params[] = { 1 };
1664 CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
1670 - (void)reloadTexture: (int) index
1677 [[self openGLContext] makeCurrentContext];
1679 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, pi_textures[index] );
1680 glPixelStorei( GL_UNPACK_ROW_LENGTH, p_vout->output.i_width );
1682 /* glTexSubImage2D is faster than glTexImage2D
1683 http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/
1684 TextureRange/MainOpenGLView.m.htm */
1685 glTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0,
1686 p_vout->output.i_width, p_vout->output.i_height,
1687 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
1688 p_vout->p_sys->p_data[index] );
1698 glBegin( GL_QUADS );
1700 glTexCoord2f( 0.0, 0.0 );
1701 glVertex2f( - f_x, f_y );
1703 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1704 glVertex2f( - f_x, - f_y );
1706 glTexCoord2f( (float) p_vout->output.i_width,
1707 (float) p_vout->output.i_height );
1708 glVertex2f( f_x, - f_y );
1710 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1711 glVertex2f( f_x, f_y );
1717 glBegin( GL_QUADS );
1719 glTexCoord2f( 0.0, 0.0 );
1720 glVertex3f( - 1.0, 1.0, 1.0 );
1721 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1722 glVertex3f( - 1.0, - 1.0, 1.0 );
1723 glTexCoord2f( (float) p_vout->output.i_width,
1724 (float) p_vout->output.i_height );
1725 glVertex3f( 1.0, - 1.0, 1.0 );
1726 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1727 glVertex3f( 1.0, 1.0, 1.0 );
1730 glTexCoord2f( 0.0, 0.0 );
1731 glVertex3f( - 1.0, 1.0, - 1.0 );
1732 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1733 glVertex3f( - 1.0, - 1.0, - 1.0 );
1734 glTexCoord2f( (float) p_vout->output.i_width,
1735 (float) p_vout->output.i_height );
1736 glVertex3f( - 1.0, - 1.0, 1.0 );
1737 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1738 glVertex3f( - 1.0, 1.0, 1.0 );
1741 glTexCoord2f( 0.0, 0.0 );
1742 glVertex3f( 1.0, 1.0, - 1.0 );
1743 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1744 glVertex3f( 1.0, - 1.0, - 1.0 );
1745 glTexCoord2f( (float) p_vout->output.i_width,
1746 (float) p_vout->output.i_height );
1747 glVertex3f( - 1.0, - 1.0, - 1.0 );
1748 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1749 glVertex3f( - 1.0, 1.0, - 1.0 );
1752 glTexCoord2f( 0.0, 0.0 );
1753 glVertex3f( 1.0, 1.0, 1.0 );
1754 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1755 glVertex3f( 1.0, - 1.0, 1.0 );
1756 glTexCoord2f( (float) p_vout->output.i_width,
1757 (float) p_vout->output.i_height );
1758 glVertex3f( 1.0, - 1.0, - 1.0 );
1759 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1760 glVertex3f( 1.0, 1.0, - 1.0 );
1763 glTexCoord2f( 0.0, 0.0 );
1764 glVertex3f( - 1.0, 1.0, - 1.0 );
1765 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1766 glVertex3f( - 1.0, 1.0, 1.0 );
1767 glTexCoord2f( (float) p_vout->output.i_width,
1768 (float) p_vout->output.i_height );
1769 glVertex3f( 1.0, 1.0, 1.0 );
1770 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1771 glVertex3f( 1.0, 1.0, - 1.0 );
1774 glTexCoord2f( 0.0, 0.0 );
1775 glVertex3f( - 1.0, - 1.0, 1.0 );
1776 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1777 glVertex3f( - 1.0, - 1.0, - 1.0 );
1778 glTexCoord2f( (float) p_vout->output.i_width,
1779 (float) p_vout->output.i_height );
1780 glVertex3f( 1.0, - 1.0, - 1.0 );
1781 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1782 glVertex3f( 1.0, - 1.0, 1.0 );
1786 - (void) drawRect: (NSRect) rect
1788 [[self openGLContext] makeCurrentContext];
1790 /* Black background */
1791 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1800 glBindTexture( GL_TEXTURE_RECTANGLE_EXT,
1801 pi_textures[p_vout->p_sys->i_cur_pic] );
1802 if( i_effect & ( OPENGL_EFFECT_CUBE |
1803 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
1805 glRotatef( 1.0, 0.3, 0.5, 0.7 );
1819 - (void)mouseMoved:(NSEvent *)o_event
1825 s_rect = [self bounds];
1826 ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
1827 b_inside = [self mouse: ml inRect: s_rect];
1832 int i_width, i_height, i_x, i_y;
1834 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
1835 (unsigned int)s_rect.size.height,
1836 &i_x, &i_y, &i_width, &i_height );
1838 val.i_int = ( (int)ml.x - i_x ) *
1839 p_vout->render.i_width / i_width;
1840 var_Set( p_vout, "mouse-x", val );
1842 /* Y coordinate is inverted in OpenGL */
1843 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
1844 p_vout->render.i_height / i_height;
1845 var_Set( p_vout, "mouse-y", val );
1847 val.b_bool = VLC_TRUE;
1848 var_Set( p_vout, "mouse-moved", val );
1849 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1850 p_vout->p_sys->b_mouse_moved = YES;
1853 [super mouseMoved: o_event];