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 <thedj@users.sourceforge.net>
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
58 /* When using I420 output */
59 PlanarPixmapInfoYUV420 pixmap_i420;
62 /*****************************************************************************
64 *****************************************************************************/
66 static int vout_Init ( vout_thread_t * );
67 static void vout_End ( vout_thread_t * );
68 static int vout_Manage ( vout_thread_t * );
69 static void vout_Display ( vout_thread_t *, picture_t * );
71 static int CoSendRequest ( vout_thread_t *, SEL );
72 static int CoCreateWindow ( vout_thread_t * );
73 static int CoDestroyWindow ( vout_thread_t * );
74 static int CoToggleFullscreen ( vout_thread_t * );
76 static void VLCHideMouse ( vout_thread_t *, BOOL );
78 static void QTScaleMatrix ( vout_thread_t * );
79 static int QTCreateSequence ( vout_thread_t * );
80 static void QTDestroySequence ( vout_thread_t * );
81 static int QTNewPicture ( vout_thread_t *, picture_t * );
82 static void QTFreePicture ( vout_thread_t *, picture_t * );
84 /*****************************************************************************
85 * OpenVideo: allocates MacOS X video thread output method
86 *****************************************************************************
87 * This function allocates and initializes a MacOS X vout method.
88 *****************************************************************************/
89 int E_(OpenVideo) ( vlc_object_t *p_this )
91 vout_thread_t * p_vout = (vout_thread_t *)p_this;
96 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
97 if( p_vout->p_sys == NULL )
99 msg_Err( p_vout, "out of memory" );
103 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
105 /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
106 for( i_timeout = 20 ; i_timeout-- ; )
110 msleep( INTF_IDLE_SLEEP );
116 /* no MacOS X intf, unable to communicate with MT */
117 msg_Err( p_vout, "no MacOS X interface present" );
118 free( p_vout->p_sys );
122 if( [NSApp respondsToSelector: @selector(getIntf)] )
124 intf_thread_t * p_intf;
126 for( i_timeout = 10 ; i_timeout-- ; )
128 if( ( p_intf = [NSApp getIntf] ) == NULL )
130 msleep( INTF_IDLE_SLEEP );
136 msg_Err( p_vout, "MacOS X intf has getIntf, but is NULL" );
137 free( p_vout->p_sys );
142 p_vout->p_sys->b_mouse_moved = VLC_TRUE;
143 p_vout->p_sys->i_time_mouse_last_moved = mdate();
145 /* set window size */
146 p_vout->p_sys->s_rect.size.width = p_vout->i_window_width;
147 p_vout->p_sys->s_rect.size.height = p_vout->i_window_height;
149 /* Check if we should use QuickTime or OpenGL */
150 psz_vout_type = config_GetPsz( p_vout, "macosx-vout" );
152 if( !strncmp( psz_vout_type, "auto", 4 ) )
154 p_vout->p_sys->i_opengl = CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay );
156 else if( !strncmp( psz_vout_type, "opengl", 6 ) )
158 p_vout->p_sys->i_opengl = VLC_TRUE;
162 p_vout->p_sys->i_opengl = VLC_FALSE;
164 free( psz_vout_type );
166 if( !p_vout->p_sys->i_opengl )
168 /* Initialize QuickTime */
169 p_vout->p_sys->h_img_descr =
170 (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
171 p_vout->p_sys->p_matrix =
172 (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
173 p_vout->p_sys->p_fullscreen_state = NULL;
175 if( ( err = EnterMovies() ) != noErr )
177 msg_Err( p_vout, "EnterMovies failed: %d", err );
178 free( p_vout->p_sys->p_matrix );
179 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
180 free( p_vout->p_sys );
184 /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
185 vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
187 err = FindCodec( kYUV420CodecType, bestSpeedCodec,
188 nil, &p_vout->p_sys->img_dc );
190 vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
191 if( err == noErr && p_vout->p_sys->img_dc != 0 )
193 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
194 p_vout->p_sys->i_codec = kYUV420CodecType;
198 msg_Err( p_vout, "failed to find an appropriate codec" );
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 );
208 msg_Dbg( p_vout, "using Quartz mode" );
212 msg_Dbg( p_vout, "using OpenGL mode" );
215 NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
216 NSArray * o_screens = [NSScreen screens];
217 if( [o_screens count] > 0 && var_Type( p_vout, "video-device" ) == 0 )
220 vlc_value_t val, text;
223 int i_option = config_GetInt( p_vout, "macosx-vdev" );
225 var_Create( p_vout, "video-device", VLC_VAR_INTEGER |
227 text.psz_string = _("Video device");
228 var_Change( p_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
230 NSEnumerator * o_enumerator = [o_screens objectEnumerator];
232 while( (o_screen = [o_enumerator nextObject]) != NULL )
235 NSRect s_rect = [o_screen frame];
237 snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
238 "%s %d (%dx%d)", _("Screen"), i,
239 (int)s_rect.size.width, (int)s_rect.size.height );
241 text.psz_string = psz_temp;
243 var_Change( p_vout, "video-device",
244 VLC_VAR_ADDCHOICE, &val, &text );
246 if( ( i - 1 ) == i_option )
248 var_Set( p_vout, "video-device", val );
253 var_AddCallback( p_vout, "video-device", vout_VarCallback,
256 val.b_bool = VLC_TRUE;
257 var_Set( p_vout, "intf-change", val );
261 if( CoCreateWindow( p_vout ) )
263 msg_Err( p_vout, "unable to create window" );
264 if( !p_vout->p_sys->i_opengl )
266 free( p_vout->p_sys->p_matrix );
267 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
269 free( p_vout->p_sys );
273 p_vout->pf_init = vout_Init;
274 p_vout->pf_end = vout_End;
275 p_vout->pf_manage = vout_Manage;
276 p_vout->pf_render = NULL;
277 p_vout->pf_display = vout_Display;
282 /*****************************************************************************
283 * vout_Init: initialize video thread output method
284 *****************************************************************************/
285 static int vout_Init( vout_thread_t *p_vout )
290 I_OUTPUTPICTURES = 0;
292 /* Initialize the output structure; we already found a codec,
293 * and the corresponding chroma we will be using. Since we can
294 * arbitrary scale, stick to the coordinates and aspect. */
295 p_vout->output.i_width = p_vout->render.i_width;
296 p_vout->output.i_height = p_vout->render.i_height;
297 p_vout->output.i_aspect = p_vout->render.i_aspect;
299 if( !p_vout->p_sys->i_opengl )
301 SetPort( p_vout->p_sys->p_qdport );
302 QTScaleMatrix( p_vout );
304 if( QTCreateSequence( p_vout ) )
306 msg_Err( p_vout, "unable to create sequence" );
312 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
313 p_vout->output.i_rmask = 0xFF0000;
314 p_vout->output.i_gmask = 0x00FF00;
315 p_vout->output.i_bmask = 0x0000FF;
318 /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
319 while( I_OUTPUTPICTURES <
320 p_vout->p_sys->i_opengl ? 1 : QT_MAX_DIRECTBUFFERS )
324 /* Find an empty picture slot */
325 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
327 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
329 p_pic = p_vout->p_picture + i_index;
334 /* Allocate the picture */
340 if( !p_vout->p_sys->i_opengl )
342 if( QTNewPicture( p_vout, p_pic ) )
349 /* Nothing special to do, we just need a basic allocated
351 vout_AllocatePicture( VLC_OBJECT( p_vout ), p_pic,
352 p_vout->output.i_chroma, p_vout->output.i_width,
353 p_vout->output.i_height, p_vout->output.i_aspect );
356 p_pic->i_status = DESTROYED_PICTURE;
357 p_pic->i_type = DIRECT_PICTURE;
359 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
364 if( p_vout->p_sys->i_opengl )
366 [p_vout->p_sys->o_glview lockFocus];
367 [p_vout->p_sys->o_glview initTextures];
368 [p_vout->p_sys->o_glview reshape];
369 [p_vout->p_sys->o_glview unlockFocus];
375 /*****************************************************************************
376 * vout_End: terminate video thread output method
377 *****************************************************************************/
378 static void vout_End( vout_thread_t *p_vout )
382 if( !p_vout->p_sys->i_opengl )
384 QTDestroySequence( p_vout );
388 [p_vout->p_sys->o_glview cleanUp];
391 /* Free the direct buffers we allocated */
392 for( i_index = I_OUTPUTPICTURES; i_index; )
395 if( !p_vout->p_sys->i_opengl )
397 QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
401 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
406 /*****************************************************************************
407 * CloseVideo: destroy video thread output method
408 *****************************************************************************/
409 void E_(CloseVideo) ( vlc_object_t *p_this )
411 vout_thread_t * p_vout = (vout_thread_t *)p_this;
413 if( CoDestroyWindow( p_vout ) )
415 msg_Err( p_vout, "unable to destroy window" );
418 if( !p_vout->p_sys->i_opengl )
420 if ( p_vout->p_sys->p_fullscreen_state != NULL )
421 EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
425 free( p_vout->p_sys->p_matrix );
426 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
429 free( p_vout->p_sys );
432 /*****************************************************************************
433 * vout_Manage: handle events
434 *****************************************************************************
435 * This function should be called regularly by video output thread. It manages
436 * console events. It returns a non null value on error.
437 *****************************************************************************/
438 static int vout_Manage( vout_thread_t *p_vout )
440 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
442 if( CoToggleFullscreen( p_vout ) )
447 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
450 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
452 if( !p_vout->p_sys->i_opengl )
454 QTScaleMatrix( p_vout );
455 SetDSequenceMatrix( p_vout->p_sys->i_seq,
456 p_vout->p_sys->p_matrix );
459 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
462 /* hide/show mouse cursor
463 * this code looks unnecessarily complicated, but is necessary like this.
464 * it has to deal with multiple monitors and therefore checks a lot */
465 if( !p_vout->p_sys->b_mouse_moved && p_vout->b_fullscreen )
467 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 3000000 )
469 VLCHideMouse( p_vout, YES );
472 else if ( p_vout->p_sys->b_mouse_moved && p_vout->b_fullscreen )
474 VLCHideMouse( p_vout, NO );
477 /* disable screen saver */
478 UpdateSystemActivity( UsrActivity );
483 /*****************************************************************************
484 * vout_Display: displays previously rendered output
485 *****************************************************************************
486 * This function sends the currently rendered image to the display.
487 *****************************************************************************/
488 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
490 if( !p_vout->p_sys->i_opengl )
495 if( ( err = DecompressSequenceFrameS(
496 p_vout->p_sys->i_seq,
497 p_pic->p_sys->p_info,
498 p_pic->p_sys->i_size,
499 codecFlagUseImageBuffer, &flags, nil ) != noErr ) )
501 msg_Warn( p_vout, "DecompressSequenceFrameS failed: %d", err );
505 QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
510 if( [p_vout->p_sys->o_glview lockFocusIfCanDraw] )
512 /* Texture gotta be reload before the buffer is filled
513 (thanks to gcc from arstechnica forums) */
514 [p_vout->p_sys->o_glview drawRect:
515 [p_vout->p_sys->o_glview bounds]];
516 [p_vout->p_sys->o_glview reloadTexture];
517 [p_vout->p_sys->o_glview unlockFocus];
522 /*****************************************************************************
523 * CoSendRequest: send request to interface thread
524 *****************************************************************************
525 * Returns 0 on success, 1 otherwise
526 *****************************************************************************/
527 static int CoSendRequest( vout_thread_t *p_vout, SEL sel )
531 intf_thread_t * p_intf;
533 VLCVout * o_vlv = [[VLCVout alloc] init];
535 if( ( i_ret = ExecuteOnMainThread( o_vlv, sel, (void *)p_vout ) ) )
537 msg_Err( p_vout, "SendRequest: no way to communicate with mt" );
542 /*This makes this function dependant of the presence of a macosx
543 interface. We do not check if this interface exists, since it has
544 already been done before.*/
546 p_intf = [NSApp getIntf];
548 val.b_bool = VLC_TRUE;
549 var_Create(p_intf,"intf-change",VLC_VAR_BOOL);
550 var_Set(p_intf, "intf-change",val);
555 /*****************************************************************************
556 * CoCreateWindow: create new window
557 *****************************************************************************
558 * Returns 0 on success, 1 otherwise
559 *****************************************************************************/
560 static int CoCreateWindow( vout_thread_t *p_vout )
562 if( CoSendRequest( p_vout, @selector(createWindow:) ) )
564 msg_Err( p_vout, "CoSendRequest (createWindow) failed" );
571 /*****************************************************************************
572 * CoDestroyWindow: destroy window
573 *****************************************************************************
574 * Returns 0 on success, 1 otherwise
575 *****************************************************************************/
576 static int CoDestroyWindow( vout_thread_t *p_vout )
579 VLCHideMouse( p_vout, NO );
581 if( CoSendRequest( p_vout, @selector(destroyWindow:) ) )
583 msg_Err( p_vout, "CoSendRequest (destroyWindow) failed" );
590 /*****************************************************************************
591 * CoToggleFullscreen: toggle fullscreen
592 *****************************************************************************
593 * Returns 0 on success, 1 otherwise
594 *****************************************************************************/
595 static int CoToggleFullscreen( vout_thread_t *p_vout )
599 intf_thread_t * p_intf;
601 if( p_vout->p_sys->i_opengl )
603 p_vout->b_fullscreen = !p_vout->b_fullscreen;
604 if( p_vout->b_fullscreen )
606 [p_vout->p_sys->o_glview goFullScreen];
610 [p_vout->p_sys->o_glview exitFullScreen];
612 /*This makes this function dependant of the presence of a macosx
613 interface. We do not check if this interface exists, since it has
614 already been done before.*/
616 p_intf = [NSApp getIntf];
618 val.b_bool = VLC_TRUE;
619 var_Create(p_intf,"intf-change",VLC_VAR_BOOL);
620 var_Set(p_intf, "intf-change",val);
625 QTDestroySequence( p_vout );
627 if( CoDestroyWindow( p_vout ) )
629 msg_Err( p_vout, "unable to destroy window" );
633 p_vout->b_fullscreen = !p_vout->b_fullscreen;
635 if( CoCreateWindow( p_vout ) )
637 msg_Err( p_vout, "unable to create window" );
641 SetPort( p_vout->p_sys->p_qdport );
642 QTScaleMatrix( p_vout );
644 if( QTCreateSequence( p_vout ) )
646 msg_Err( p_vout, "unable to create sequence" );
653 /*****************************************************************************
654 * VLCHideMouse: if b_hide then hide the cursor
655 *****************************************************************************/
656 static void VLCHideMouse ( vout_thread_t *p_vout, BOOL b_hide )
661 NSWindow *o_window = p_vout->p_sys->o_window;
662 NSView *o_contents = [o_window contentView];
664 s_rect = [o_contents bounds];
665 ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
666 ml = [o_contents convertPoint:ml fromView:nil];
667 b_inside = [o_contents mouse: ml inRect: s_rect];
669 if ( b_hide && b_inside )
671 /* only hide if mouse over VLCQTView */
672 [NSCursor setHiddenUntilMouseMoves: YES];
676 [NSCursor setHiddenUntilMouseMoves: NO];
678 p_vout->p_sys->b_mouse_moved = NO;
679 p_vout->p_sys->i_time_mouse_last_moved = mdate();
683 /*****************************************************************************
684 * QTScaleMatrix: scale matrix
685 *****************************************************************************/
686 static void QTScaleMatrix( vout_thread_t *p_vout )
689 unsigned int i_width, i_height;
690 Fixed factor_x, factor_y;
691 unsigned int i_offset_x = 0;
692 unsigned int i_offset_y = 0;
694 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
696 i_width = s_rect.right - s_rect.left;
697 i_height = s_rect.bottom - s_rect.top;
699 if( config_GetInt( p_vout, "macosx-stretch" ) )
701 factor_x = FixDiv( Long2Fix( i_width ),
702 Long2Fix( p_vout->output.i_width ) );
703 factor_y = FixDiv( Long2Fix( i_height ),
704 Long2Fix( p_vout->output.i_height ) );
707 else if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
709 int i_adj_width = i_height * p_vout->output.i_aspect /
712 factor_x = FixDiv( Long2Fix( i_adj_width ),
713 Long2Fix( p_vout->output.i_width ) );
714 factor_y = FixDiv( Long2Fix( i_height ),
715 Long2Fix( p_vout->output.i_height ) );
717 i_offset_x = (i_width - i_adj_width) / 2;
721 int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
722 p_vout->output.i_aspect;
724 factor_x = FixDiv( Long2Fix( i_width ),
725 Long2Fix( p_vout->output.i_width ) );
726 factor_y = FixDiv( Long2Fix( i_adj_height ),
727 Long2Fix( p_vout->output.i_height ) );
729 i_offset_y = (i_height - i_adj_height) / 2;
732 SetIdentityMatrix( p_vout->p_sys->p_matrix );
734 ScaleMatrix( p_vout->p_sys->p_matrix,
736 Long2Fix(0), Long2Fix(0) );
738 TranslateMatrix( p_vout->p_sys->p_matrix,
739 Long2Fix(i_offset_x), Long2Fix(i_offset_y) );
742 /*****************************************************************************
743 * QTCreateSequence: create a new sequence
744 *****************************************************************************
745 * Returns 0 on success, 1 otherwise
746 *****************************************************************************/
747 static int QTCreateSequence( vout_thread_t *p_vout )
750 ImageDescriptionPtr p_descr;
752 HLock( (Handle)p_vout->p_sys->h_img_descr );
753 p_descr = *p_vout->p_sys->h_img_descr;
755 p_descr->idSize = sizeof(ImageDescription);
756 p_descr->cType = p_vout->p_sys->i_codec;
757 p_descr->version = 1;
758 p_descr->revisionLevel = 0;
759 p_descr->vendor = 'appl';
760 p_descr->width = p_vout->output.i_width;
761 p_descr->height = p_vout->output.i_height;
762 p_descr->hRes = Long2Fix(72);
763 p_descr->vRes = Long2Fix(72);
764 p_descr->spatialQuality = codecLosslessQuality;
765 p_descr->frameCount = 1;
766 p_descr->clutID = -1;
767 p_descr->dataSize = 0;
770 HUnlock( (Handle)p_vout->p_sys->h_img_descr );
772 if( ( err = DecompressSequenceBeginS(
773 &p_vout->p_sys->i_seq,
774 p_vout->p_sys->h_img_descr,
776 p_vout->p_sys->p_qdport,
778 p_vout->p_sys->p_matrix,
780 codecFlagUseImageBuffer,
781 codecLosslessQuality,
782 p_vout->p_sys->img_dc ) ) )
784 msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
791 /*****************************************************************************
792 * QTDestroySequence: destroy sequence
793 *****************************************************************************/
794 static void QTDestroySequence( vout_thread_t *p_vout )
796 CDSequenceEnd( p_vout->p_sys->i_seq );
799 /*****************************************************************************
800 * QTNewPicture: allocate a picture
801 *****************************************************************************
802 * Returns 0 on success, 1 otherwise
803 *****************************************************************************/
804 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
806 int i_width = p_vout->output.i_width;
807 int i_height = p_vout->output.i_height;
809 /* We know the chroma, allocate a buffer which will be used
810 * directly by the decoder */
811 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
813 if( p_pic->p_sys == NULL )
818 switch( p_vout->output.i_chroma )
820 case VLC_FOURCC('I','4','2','0'):
822 p_pic->p_sys->p_info = (void *)&p_pic->p_sys->pixmap_i420;
823 p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
825 /* Allocate the memory buffer */
826 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
827 16, i_width * i_height * 3 / 2 );
830 p_pic->Y_PIXELS = p_pic->p_data;
831 p_pic->p[Y_PLANE].i_lines = i_height;
832 p_pic->p[Y_PLANE].i_pitch = i_width;
833 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
834 p_pic->p[Y_PLANE].i_visible_pitch = i_width;
837 p_pic->U_PIXELS = p_pic->Y_PIXELS + i_height * i_width;
838 p_pic->p[U_PLANE].i_lines = i_height / 2;
839 p_pic->p[U_PLANE].i_pitch = i_width / 2;
840 p_pic->p[U_PLANE].i_pixel_pitch = 1;
841 p_pic->p[U_PLANE].i_visible_pitch = i_width / 2;
844 p_pic->V_PIXELS = p_pic->U_PIXELS + i_height * i_width / 4;
845 p_pic->p[V_PLANE].i_lines = i_height / 2;
846 p_pic->p[V_PLANE].i_pitch = i_width / 2;
847 p_pic->p[V_PLANE].i_pixel_pitch = 1;
848 p_pic->p[V_PLANE].i_visible_pitch = i_width / 2;
850 /* We allocated 3 planes */
853 #define P p_pic->p_sys->pixmap_i420
854 P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
855 - p_pic->p_sys->p_info;
856 P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
857 - p_pic->p_sys->p_info;
858 P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
859 - p_pic->p_sys->p_info;
861 P.componentInfoY.rowBytes = i_width;
862 P.componentInfoCb.rowBytes = i_width / 2;
863 P.componentInfoCr.rowBytes = i_width / 2;
869 /* Unknown chroma, tell the guy to get lost */
870 free( p_pic->p_sys );
871 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
872 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
880 /*****************************************************************************
881 * QTFreePicture: destroy a picture allocated with QTNewPicture
882 *****************************************************************************/
883 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
885 switch( p_vout->output.i_chroma )
887 case VLC_FOURCC('I','4','2','0'):
888 free( p_pic->p_data_orig );
892 free( p_pic->p_sys );
895 /*****************************************************************************
896 * VLCWindow implementation
897 *****************************************************************************/
898 @implementation VLCWindow
900 - (void)setVout:(vout_thread_t *)_p_vout
905 - (vout_thread_t *)getVout
910 - (void)scaleWindowWithFactor: (float)factor
913 int i_corrected_height, i_corrected_width;
915 NSPoint topleftscreen;
917 if ( !p_vout->b_fullscreen )
920 topleftbase.y = [self frame].size.height;
921 topleftscreen = [self convertBaseToScreen: topleftbase];
923 if( p_vout->output.i_height * p_vout->output.i_aspect >
924 p_vout->output.i_width * VOUT_ASPECT_FACTOR )
926 i_corrected_width = p_vout->output.i_height * p_vout->output.i_aspect /
928 newsize.width = (int) ( i_corrected_width * factor );
929 newsize.height = (int) ( p_vout->render.i_height * factor );
933 i_corrected_height = p_vout->output.i_width * VOUT_ASPECT_FACTOR /
934 p_vout->output.i_aspect;
935 newsize.width = (int) ( p_vout->render.i_width * factor );
936 newsize.height = (int) ( i_corrected_height * factor );
939 [self setContentSize: newsize];
941 [self setFrameTopLeftPoint: topleftscreen];
942 p_vout->i_changes |= VOUT_SIZE_CHANGE;
946 - (void)toggleFloatOnTop
949 if( var_Get( p_vout, "video-on-top", &val )>=0 && val.b_bool)
951 val.b_bool = VLC_FALSE;
952 var_Set( p_vout, "video-on-top", val );
953 [p_vout->p_sys->o_window setLevel: NSNormalWindowLevel];
957 val.b_bool = VLC_TRUE;
958 var_Set( p_vout, "video-on-top", val );
959 [p_vout->p_sys->o_window setLevel: NSStatusWindowLevel];
963 - (void)toggleFullscreen
966 val.b_bool = !p_vout->b_fullscreen;
967 var_Set( p_vout, "fullscreen", val );
972 return( p_vout->b_fullscreen );
975 - (BOOL)canBecomeKeyWindow
980 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
982 return [(VLCApplication *) [VLCApplication sharedApplication]
983 hasDefinedShortcutKey:o_event];
986 - (void)keyDown:(NSEvent *)o_event
990 unsigned int i_pressed_modifiers = 0;
993 i_pressed_modifiers = [o_event modifierFlags];
995 if( i_pressed_modifiers & NSShiftKeyMask )
996 val.i_int |= KEY_MODIFIER_SHIFT;
997 if( i_pressed_modifiers & NSControlKeyMask )
998 val.i_int |= KEY_MODIFIER_CTRL;
999 if( i_pressed_modifiers & NSAlternateKeyMask )
1000 val.i_int |= KEY_MODIFIER_ALT;
1001 if( i_pressed_modifiers & NSCommandKeyMask )
1002 val.i_int |= KEY_MODIFIER_COMMAND;
1004 key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
1008 /* Escape should always get you out of fullscreen */
1009 if( key == (unichar) 0x1b )
1011 if( [self isFullscreen] )
1013 [self toggleFullscreen];
1016 else if ( key == ' ' )
1018 playlist_t *p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1020 if ( p_playlist != NULL )
1022 playlist_Pause( p_playlist );
1023 vlc_object_release( p_playlist);
1028 val.i_int |= CocoaKeyToVLC( key );
1029 var_Set( p_vout->p_vlc, "key-pressed", val );
1034 [super keyDown: o_event];
1040 NSMutableString * o_title;
1041 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1044 if( p_playlist == NULL )
1049 vlc_mutex_lock( &p_playlist->object_lock );
1050 o_title = [NSMutableString stringWithUTF8String:
1051 p_playlist->pp_items[p_playlist->i_index]->input.psz_uri];
1052 vlc_mutex_unlock( &p_playlist->object_lock );
1054 vlc_object_release( p_playlist );
1056 if( o_title != nil )
1058 NSRange prefix_range = [o_title rangeOfString: @"file:"];
1059 if( prefix_range.location != NSNotFound )
1061 [o_title deleteCharactersInRange: prefix_range];
1064 [self setTitleWithRepresentedFilename: o_title];
1069 [NSString stringWithCString: VOUT_TITLE " (QuickTime)"]];
1073 /* This is actually the same as VLCControls::stop. */
1074 - (BOOL)windowShouldClose:(id)sender
1076 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1078 if( p_playlist == NULL )
1083 playlist_Stop( p_playlist );
1084 vlc_object_release( p_playlist );
1086 /* The window will be closed by the intf later. */
1092 /*****************************************************************************
1093 * VLCQTView implementation
1094 *****************************************************************************/
1095 @implementation VLCQTView
1097 - (void)drawRect:(NSRect)rect
1099 vout_thread_t * p_vout;
1100 id o_window = [self window];
1101 p_vout = (vout_thread_t *)[o_window getVout];
1103 [[NSColor blackColor] set];
1105 [super drawRect: rect];
1107 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1110 - (BOOL)acceptsFirstResponder
1115 - (BOOL)becomeFirstResponder
1117 vout_thread_t * p_vout;
1118 id o_window = [self window];
1119 p_vout = (vout_thread_t *)[o_window getVout];
1121 [o_window setAcceptsMouseMovedEvents: YES];
1125 - (BOOL)resignFirstResponder
1127 vout_thread_t * p_vout;
1128 id o_window = [self window];
1129 p_vout = (vout_thread_t *)[o_window getVout];
1131 [o_window setAcceptsMouseMovedEvents: NO];
1132 VLCHideMouse( p_vout, NO );
1136 - (void)mouseDown:(NSEvent *)o_event
1138 vout_thread_t * p_vout;
1139 id o_window = [self window];
1140 p_vout = (vout_thread_t *)[o_window getVout];
1143 switch( [o_event type] )
1145 case NSLeftMouseDown:
1147 var_Get( p_vout, "mouse-button-down", &val );
1149 var_Set( p_vout, "mouse-button-down", val );
1154 [super mouseDown: o_event];
1159 - (void)otherMouseDown:(NSEvent *)o_event
1161 /* This is not the the wheel button. you need to poll the
1162 * mouseWheel event for that. other is a third, forth or fifth button */
1163 vout_thread_t * p_vout;
1164 id o_window = [self window];
1165 p_vout = (vout_thread_t *)[o_window getVout];
1168 switch( [o_event type] )
1170 case NSOtherMouseDown:
1172 var_Get( p_vout, "mouse-button-down", &val );
1174 var_Set( p_vout, "mouse-button-down", val );
1179 [super mouseDown: o_event];
1184 - (void)rightMouseDown:(NSEvent *)o_event
1186 vout_thread_t * p_vout;
1187 id o_window = [self window];
1188 p_vout = (vout_thread_t *)[o_window getVout];
1191 switch( [o_event type] )
1193 case NSRightMouseDown:
1195 var_Get( p_vout, "mouse-button-down", &val );
1197 var_Set( p_vout, "mouse-button-down", val );
1202 [super mouseDown: o_event];
1207 - (void)mouseUp:(NSEvent *)o_event
1209 vout_thread_t * p_vout;
1210 id o_window = [self window];
1211 p_vout = (vout_thread_t *)[o_window getVout];
1214 switch( [o_event type] )
1219 b_val.b_bool = VLC_TRUE;
1220 var_Set( p_vout, "mouse-clicked", b_val );
1222 var_Get( p_vout, "mouse-button-down", &val );
1224 var_Set( p_vout, "mouse-button-down", val );
1229 [super mouseUp: o_event];
1234 - (void)otherMouseUp:(NSEvent *)o_event
1236 vout_thread_t * p_vout;
1237 id o_window = [self window];
1238 p_vout = (vout_thread_t *)[o_window getVout];
1241 switch( [o_event type] )
1243 case NSOtherMouseUp:
1245 var_Get( p_vout, "mouse-button-down", &val );
1247 var_Set( p_vout, "mouse-button-down", val );
1252 [super mouseUp: o_event];
1257 - (void)rightMouseUp:(NSEvent *)o_event
1259 vout_thread_t * p_vout;
1260 id o_window = [self window];
1261 p_vout = (vout_thread_t *)[o_window getVout];
1264 switch( [o_event type] )
1266 case NSRightMouseUp:
1268 var_Get( p_vout, "mouse-button-down", &val );
1270 var_Set( p_vout, "mouse-button-down", val );
1275 [super mouseUp: o_event];
1280 - (void)mouseDragged:(NSEvent *)o_event
1282 [self mouseMoved:o_event];
1285 - (void)otherMouseDragged:(NSEvent *)o_event
1287 [self mouseMoved:o_event];
1290 - (void)rightMouseDragged:(NSEvent *)o_event
1292 [self mouseMoved:o_event];
1295 - (void)mouseMoved:(NSEvent *)o_event
1301 vout_thread_t * p_vout;
1302 id o_window = [self window];
1303 p_vout = (vout_thread_t *)[o_window getVout];
1305 s_rect = [self bounds];
1306 ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
1307 b_inside = [self mouse: ml inRect: s_rect];
1312 int i_width, i_height, i_x, i_y;
1314 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
1315 (unsigned int)s_rect.size.height,
1316 &i_x, &i_y, &i_width, &i_height );
1318 val.i_int = ( ((int)ml.x) - i_x ) *
1319 p_vout->render.i_width / i_width;
1320 var_Set( p_vout, "mouse-x", val );
1322 val.i_int = ( ((int)ml.y) - i_y ) *
1323 p_vout->render.i_height / i_height;
1324 var_Set( p_vout, "mouse-y", val );
1326 val.b_bool = VLC_TRUE;
1327 var_Set( p_vout, "mouse-moved", val );
1328 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1329 p_vout->p_sys->b_mouse_moved = YES;
1332 [super mouseMoved: o_event];
1337 /*****************************************************************************
1338 * VLCGLView implementation
1339 *****************************************************************************/
1340 @implementation VLCGLView
1343 - (id) initWithFrame: (NSRect) frame vout: (vout_thread_t*) _p_vout
1348 NSOpenGLPixelFormatAttribute attribs[] =
1350 NSOpenGLPFAAccelerated,
1351 NSOpenGLPFANoRecovery,
1352 NSOpenGLPFADoubleBuffer,
1353 NSOpenGLPFAColorSize, 24,
1354 NSOpenGLPFAAlphaSize, 8,
1355 NSOpenGLPFADepthSize, 24,
1360 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
1361 initWithAttributes: attribs];
1365 msg_Warn( p_vout, "Cannot create NSOpenGLPixelFormat" );
1369 self = [super initWithFrame:frame pixelFormat: fmt];
1371 currentContext = [self openGLContext];
1372 [currentContext makeCurrentContext];
1373 [currentContext update];
1375 /* Black background */
1376 glClearColor( 0.0, 0.0, 0.0, 0.0 );
1378 /* Check if the user asked for useless visual effects */
1379 psz_effect = config_GetPsz( p_vout, "macosx-opengl-effect" );
1380 if( !psz_effect || !strcmp( psz_effect, "none" ))
1382 i_effect = OPENGL_EFFECT_NONE;
1384 else if( !strcmp( psz_effect, "cube" ) )
1386 i_effect = OPENGL_EFFECT_CUBE;
1388 glEnable( GL_DEPTH_TEST );
1390 else if( !strcmp( psz_effect, "transparent-cube" ) )
1392 i_effect = OPENGL_EFFECT_TRANSPARENT_CUBE;
1394 glDisable( GL_DEPTH_TEST );
1395 glEnable( GL_BLEND );
1396 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
1400 msg_Warn( p_vout, "no valid opengl effect provided, using "
1402 i_effect = OPENGL_EFFECT_NONE;
1405 if( i_effect & ( OPENGL_EFFECT_CUBE |
1406 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
1408 /* Set the perpective */
1409 glMatrixMode( GL_PROJECTION );
1411 glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
1412 glMatrixMode( GL_MODELVIEW );
1414 glTranslatef( 0.0, 0.0, - 5.0 );
1431 [currentContext makeCurrentContext];
1433 NSRect bounds = [self bounds];
1434 glViewport( 0, 0, (GLint) bounds.size.width,
1435 (GLint) bounds.size.height );
1437 /* Quad size is set in order to preserve the aspect ratio */
1438 if( config_GetInt( p_vout, "macosx-stretch" ) )
1443 else if( bounds.size.height * p_vout->output.i_aspect <
1444 bounds.size.width * VOUT_ASPECT_FACTOR )
1446 f_x = bounds.size.height * p_vout->output.i_aspect /
1447 VOUT_ASPECT_FACTOR / bounds.size.width;
1453 f_y = bounds.size.width * VOUT_ASPECT_FACTOR /
1454 p_vout->output.i_aspect / bounds.size.height;
1458 - (void) initTextures
1460 [currentContext makeCurrentContext];
1462 /* Free previous texture if any */
1465 glDeleteTextures( 1, &i_texture );
1468 /* Create textures */
1469 glGenTextures( 1, &i_texture );
1471 glEnable( GL_TEXTURE_RECTANGLE_EXT );
1472 glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
1474 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1476 /* Use VRAM texturing */
1477 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1478 GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE );
1480 /* Tell the driver not to make a copy of the texture but to use
1482 glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );
1484 /* Linear interpolation */
1485 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1486 GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1487 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1488 GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1490 /* I have no idea what this exactly does, but it seems to be
1491 necessary for scaling */
1492 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1493 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1494 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1495 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1496 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
1498 glTexImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,
1499 p_vout->output.i_width, p_vout->output.i_height, 0,
1500 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
1501 PP_OUTPUTPICTURE[0]->p_data );
1506 - (void)reloadTexture
1513 [currentContext makeCurrentContext];
1515 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1517 /* glTexSubImage2D is faster than glTexImage2D
1518 http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/
1519 TextureRange/MainOpenGLView.m.htm */
1520 glTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0,
1521 p_vout->output.i_width, p_vout->output.i_height,
1522 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
1523 PP_OUTPUTPICTURE[0]->p_data );
1526 - (void)goFullScreen
1528 /* Create the new pixel format */
1529 NSOpenGLPixelFormatAttribute attribs[] =
1531 NSOpenGLPFAAccelerated,
1532 NSOpenGLPFANoRecovery,
1533 NSOpenGLPFADoubleBuffer,
1534 NSOpenGLPFAColorSize, 24,
1535 NSOpenGLPFAAlphaSize, 8,
1536 NSOpenGLPFADepthSize, 24,
1537 NSOpenGLPFAFullScreen,
1538 NSOpenGLPFAScreenMask,
1539 /* TODO handle macosx-vdev */
1540 CGDisplayIDToOpenGLDisplayMask( kCGDirectMainDisplay ),
1543 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
1544 initWithAttributes: attribs];
1547 msg_Warn( p_vout, "Cannot create NSOpenGLPixelFormat" );
1551 /* Create the new OpenGL context */
1552 fullScreenContext = [[NSOpenGLContext alloc]
1553 initWithFormat: fmt shareContext: nil];
1554 if( !fullScreenContext )
1556 msg_Warn( p_vout, "Failed to create new NSOpenGLContext" );
1559 currentContext = fullScreenContext;
1561 /* Capture display, switch to fullscreen */
1562 if( CGCaptureAllDisplays() != CGDisplayNoErr )
1564 msg_Warn( p_vout, "CGCaptureAllDisplays() failed" );
1567 [fullScreenContext setFullScreen];
1568 [fullScreenContext makeCurrentContext];
1571 unsigned width = CGDisplayPixelsWide( kCGDirectMainDisplay );
1572 unsigned height = CGDisplayPixelsHigh( kCGDirectMainDisplay );
1573 int stretch = config_GetInt( p_vout, "macosx-stretch" );
1574 int fill = config_GetInt( p_vout, "macosx-fill" );
1575 int bigRatio = ( height * p_vout->output.i_aspect <
1576 width * VOUT_ASPECT_FACTOR );
1582 else if( ( bigRatio && !fill ) || ( !bigRatio && fill ) )
1584 f_x = (float) height * p_vout->output.i_aspect /
1585 width / VOUT_ASPECT_FACTOR;
1591 f_y = (float) width * VOUT_ASPECT_FACTOR /
1592 p_vout->output.i_aspect / height;
1595 /* Update viewport, re-init textures */
1596 glViewport( 0, 0, width, height );
1597 [self initTextures];
1599 /* Redraw the last picture */
1600 [self setNeedsDisplay: YES];
1605 - (void)exitFullScreen
1607 /* Free current OpenGL context */
1608 [NSOpenGLContext clearCurrentContext];
1609 [fullScreenContext clearDrawable];
1610 [fullScreenContext release];
1611 CGReleaseAllDisplays();
1613 currentContext = [self openGLContext];
1614 [self initTextures];
1617 /* Redraw the last picture */
1618 [self setNeedsDisplay: YES];
1627 [self exitFullScreen];
1634 glBegin( GL_QUADS );
1636 glTexCoord2f( 0.0, 0.0 );
1637 glVertex2f( - f_x, f_y );
1639 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1640 glVertex2f( - f_x, - f_y );
1642 glTexCoord2f( (float) p_vout->output.i_width,
1643 (float) p_vout->output.i_height );
1644 glVertex2f( f_x, - f_y );
1646 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1647 glVertex2f( f_x, f_y );
1653 glBegin( GL_QUADS );
1655 glTexCoord2f( 0.0, 0.0 );
1656 glVertex3f( - 1.0, 1.0, 1.0 );
1657 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1658 glVertex3f( - 1.0, - 1.0, 1.0 );
1659 glTexCoord2f( (float) p_vout->output.i_width,
1660 (float) p_vout->output.i_height );
1661 glVertex3f( 1.0, - 1.0, 1.0 );
1662 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1663 glVertex3f( 1.0, 1.0, 1.0 );
1666 glTexCoord2f( 0.0, 0.0 );
1667 glVertex3f( - 1.0, 1.0, - 1.0 );
1668 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1669 glVertex3f( - 1.0, - 1.0, - 1.0 );
1670 glTexCoord2f( (float) p_vout->output.i_width,
1671 (float) p_vout->output.i_height );
1672 glVertex3f( - 1.0, - 1.0, 1.0 );
1673 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1674 glVertex3f( - 1.0, 1.0, 1.0 );
1677 glTexCoord2f( 0.0, 0.0 );
1678 glVertex3f( 1.0, 1.0, - 1.0 );
1679 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1680 glVertex3f( 1.0, - 1.0, - 1.0 );
1681 glTexCoord2f( (float) p_vout->output.i_width,
1682 (float) p_vout->output.i_height );
1683 glVertex3f( - 1.0, - 1.0, - 1.0 );
1684 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1685 glVertex3f( - 1.0, 1.0, - 1.0 );
1688 glTexCoord2f( 0.0, 0.0 );
1689 glVertex3f( 1.0, 1.0, 1.0 );
1690 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1691 glVertex3f( 1.0, - 1.0, 1.0 );
1692 glTexCoord2f( (float) p_vout->output.i_width,
1693 (float) p_vout->output.i_height );
1694 glVertex3f( 1.0, - 1.0, - 1.0 );
1695 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1696 glVertex3f( 1.0, 1.0, - 1.0 );
1699 glTexCoord2f( 0.0, 0.0 );
1700 glVertex3f( - 1.0, 1.0, - 1.0 );
1701 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1702 glVertex3f( - 1.0, 1.0, 1.0 );
1703 glTexCoord2f( (float) p_vout->output.i_width,
1704 (float) p_vout->output.i_height );
1705 glVertex3f( 1.0, 1.0, 1.0 );
1706 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1707 glVertex3f( 1.0, 1.0, - 1.0 );
1710 glTexCoord2f( 0.0, 0.0 );
1711 glVertex3f( - 1.0, - 1.0, 1.0 );
1712 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1713 glVertex3f( - 1.0, - 1.0, - 1.0 );
1714 glTexCoord2f( (float) p_vout->output.i_width,
1715 (float) p_vout->output.i_height );
1716 glVertex3f( 1.0, - 1.0, - 1.0 );
1717 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1718 glVertex3f( 1.0, - 1.0, 1.0 );
1722 - (void) drawRect: (NSRect) rect
1724 [currentContext makeCurrentContext];
1726 /* Swap buffers only during the vertical retrace of the monitor.
1727 http://developer.apple.com/documentation/GraphicsImaging/
1728 Conceptual/OpenGL/chap5/chapter_5_section_44.html */
1729 long params[] = { 1 };
1730 CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
1733 /* Black background */
1734 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1738 [currentContext flushBuffer];
1743 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1744 if( i_effect & ( OPENGL_EFFECT_CUBE |
1745 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
1747 glRotatef( 1.0, 0.3, 0.5, 0.7 );
1755 /* Wait for the job to be done */
1756 [currentContext flushBuffer];
1761 /*****************************************************************************
1762 * VLCVout implementation
1763 *****************************************************************************/
1764 @implementation VLCVout
1766 - (void)createWindow:(NSValue *)o_value
1770 NSScreen * o_screen;
1771 vout_thread_t * p_vout;
1772 vlc_bool_t b_main_screen;
1774 p_vout = (vout_thread_t *)[o_value pointerValue];
1776 p_vout->p_sys->o_window = [VLCWindow alloc];
1777 [p_vout->p_sys->o_window setVout: p_vout];
1778 [p_vout->p_sys->o_window setReleasedWhenClosed: YES];
1780 if( var_Get( p_vout, "video-device", &val ) < 0 )
1782 o_screen = [NSScreen mainScreen];
1787 NSArray *o_screens = [NSScreen screens];
1788 unsigned int i_index = val.i_int;
1790 if( [o_screens count] < i_index )
1792 o_screen = [NSScreen mainScreen];
1798 o_screen = [o_screens objectAtIndex: i_index];
1799 config_PutInt( p_vout, "macosx-vdev", i_index );
1800 b_main_screen = (i_index == 0);
1804 if( p_vout->b_fullscreen && !p_vout->p_sys->i_opengl )
1806 NSRect screen_rect = [o_screen frame];
1807 screen_rect.origin.x = screen_rect.origin.y = 0;
1809 if ( b_main_screen && p_vout->p_sys->p_fullscreen_state == NULL )
1810 BeginFullScreen( &p_vout->p_sys->p_fullscreen_state, NULL, 0, 0,
1811 NULL, NULL, fullScreenAllowEvents );
1813 [p_vout->p_sys->o_window
1814 initWithContentRect: screen_rect
1815 styleMask: NSBorderlessWindowMask
1816 backing: NSBackingStoreBuffered
1817 defer: NO screen: o_screen];
1819 //[p_vout->p_sys->o_window setLevel: NSPopUpMenuWindowLevel - 1];
1820 p_vout->p_sys->b_mouse_moved = YES;
1821 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1825 unsigned int i_stylemask = NSTitledWindowMask |
1826 NSMiniaturizableWindowMask |
1827 NSClosableWindowMask |
1828 NSResizableWindowMask;
1830 if( !p_vout->p_sys->i_opengl )
1832 if ( p_vout->p_sys->p_fullscreen_state != NULL )
1833 EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
1834 p_vout->p_sys->p_fullscreen_state = NULL;
1837 [p_vout->p_sys->o_window
1838 initWithContentRect: p_vout->p_sys->s_rect
1839 styleMask: i_stylemask
1840 backing: NSBackingStoreBuffered
1841 defer: NO screen: o_screen];
1843 [p_vout->p_sys->o_window setAlphaValue: config_GetFloat( p_vout, "macosx-opaqueness" )];
1845 if( config_GetInt( p_vout, "video-on-top" ) )
1847 [p_vout->p_sys->o_window setLevel: NSStatusWindowLevel];
1850 if( !p_vout->p_sys->b_pos_saved )
1852 [p_vout->p_sys->o_window center];
1856 if( !p_vout->p_sys->i_opengl )
1858 o_view = [[VLCQTView alloc] init];
1859 /* FIXME: [o_view setMenu:] */
1860 [p_vout->p_sys->o_window setContentView: o_view];
1861 [o_view autorelease];
1864 p_vout->p_sys->p_qdport = [o_view qdPort];
1865 [o_view unlockFocus];
1869 #define o_glview p_vout->p_sys->o_glview
1870 o_glview = [[VLCGLView alloc] initWithFrame: p_vout->p_sys->s_rect vout: p_vout];
1871 [p_vout->p_sys->o_window setContentView: o_glview];
1872 [o_glview autorelease];
1876 [p_vout->p_sys->o_window updateTitle];
1877 [p_vout->p_sys->o_window makeKeyAndOrderFront: nil];
1881 - (void)destroyWindow:(NSValue *)o_value
1883 vout_thread_t * p_vout;
1885 p_vout = (vout_thread_t *)[o_value pointerValue];
1887 if( !p_vout->b_fullscreen )
1891 s_rect = [[p_vout->p_sys->o_window contentView] frame];
1892 p_vout->p_sys->s_rect.size = s_rect.size;
1894 s_rect = [p_vout->p_sys->o_window frame];
1895 p_vout->p_sys->s_rect.origin = s_rect.origin;
1897 p_vout->p_sys->b_pos_saved = YES;
1900 p_vout->p_sys->p_qdport = nil;
1901 [p_vout->p_sys->o_window close];
1902 p_vout->p_sys->o_window = nil;