1 /*****************************************************************************
2 * vout.m: MacOS X video output module
3 *****************************************************************************
4 * Copyright (C) 2001-2003 VideoLAN
5 * $Id: vout.m,v 1.79 2004/02/09 14:02:25 titer Exp $
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
57 /* When using I420 output */
58 PlanarPixmapInfoYUV420 pixmap_i420;
61 /*****************************************************************************
63 *****************************************************************************/
65 static int vout_Init ( vout_thread_t * );
66 static void vout_End ( vout_thread_t * );
67 static int vout_Manage ( vout_thread_t * );
68 static void vout_Display ( vout_thread_t *, picture_t * );
70 static int CoSendRequest ( vout_thread_t *, SEL );
71 static int CoCreateWindow ( vout_thread_t * );
72 static int CoDestroyWindow ( vout_thread_t * );
73 static int CoToggleFullscreen ( vout_thread_t * );
75 static void VLCHideMouse ( vout_thread_t *, BOOL );
77 static void QTScaleMatrix ( vout_thread_t * );
78 static int QTCreateSequence ( vout_thread_t * );
79 static void QTDestroySequence ( vout_thread_t * );
80 static int QTNewPicture ( vout_thread_t *, picture_t * );
81 static void QTFreePicture ( vout_thread_t *, picture_t * );
83 /*****************************************************************************
84 * OpenVideo: allocates MacOS X video thread output method
85 *****************************************************************************
86 * This function allocates and initializes a MacOS X vout method.
87 *****************************************************************************/
88 int E_(OpenVideo) ( vlc_object_t *p_this )
90 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 if( [NSApp respondsToSelector: @selector(getIntf)] )
122 intf_thread_t * p_intf;
124 for( i_timeout = 10 ; i_timeout-- ; )
126 if( ( p_intf = [NSApp getIntf] ) == NULL )
128 msleep( INTF_IDLE_SLEEP );
134 msg_Err( p_vout, "MacOS X intf has getIntf, but is NULL" );
135 free( p_vout->p_sys );
140 p_vout->p_sys->b_mouse_moved = VLC_TRUE;
141 p_vout->p_sys->i_time_mouse_last_moved = mdate();
143 /* set window size */
144 p_vout->p_sys->s_rect.size.width = p_vout->i_window_width;
145 p_vout->p_sys->s_rect.size.height = p_vout->i_window_height;
147 /* Check if we should use QuickTime or OpenGL */
148 p_vout->p_sys->i_opengl = config_GetInt( p_vout, "macosx-opengl" );
150 if( !p_vout->p_sys->i_opengl )
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) );
157 p_vout->p_sys->p_fullscreen_state = NULL;
159 if( ( err = EnterMovies() ) != noErr )
161 msg_Err( p_vout, "EnterMovies failed: %d", err );
162 free( p_vout->p_sys->p_matrix );
163 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
164 free( p_vout->p_sys );
168 /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
169 vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
171 err = FindCodec( kYUV420CodecType, bestSpeedCodec,
172 nil, &p_vout->p_sys->img_dc );
174 vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
175 if( err == noErr && p_vout->p_sys->img_dc != 0 )
177 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
178 p_vout->p_sys->i_codec = kYUV420CodecType;
182 msg_Err( p_vout, "failed to find an appropriate codec" );
185 if( p_vout->p_sys->img_dc == 0 )
187 free( p_vout->p_sys->p_matrix );
188 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
189 free( p_vout->p_sys );
194 NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
195 NSArray * o_screens = [NSScreen screens];
196 if( [o_screens count] > 0 && var_Type( p_vout, "video-device" ) == 0 )
199 vlc_value_t val, text;
202 int i_option = config_GetInt( p_vout, "macosx-vdev" );
204 var_Create( p_vout, "video-device", VLC_VAR_INTEGER |
206 text.psz_string = _("Video device");
207 var_Change( p_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
209 NSEnumerator * o_enumerator = [o_screens objectEnumerator];
211 while( (o_screen = [o_enumerator nextObject]) != NULL )
214 NSRect s_rect = [o_screen frame];
216 snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
217 "%s %d (%dx%d)", _("Screen"), i,
218 (int)s_rect.size.width, (int)s_rect.size.height );
220 text.psz_string = psz_temp;
222 var_Change( p_vout, "video-device",
223 VLC_VAR_ADDCHOICE, &val, &text );
225 if( ( i - 1 ) == i_option )
227 var_Set( p_vout, "video-device", val );
232 var_AddCallback( p_vout, "video-device", vout_VarCallback,
235 val.b_bool = VLC_TRUE;
236 var_Set( p_vout, "intf-change", val );
240 if( CoCreateWindow( p_vout ) )
242 msg_Err( p_vout, "unable to create window" );
243 if( !p_vout->p_sys->i_opengl )
245 free( p_vout->p_sys->p_matrix );
246 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
248 free( p_vout->p_sys );
252 p_vout->pf_init = vout_Init;
253 p_vout->pf_end = vout_End;
254 p_vout->pf_manage = vout_Manage;
255 p_vout->pf_render = NULL;
256 p_vout->pf_display = vout_Display;
261 /*****************************************************************************
262 * vout_Init: initialize video thread output method
263 *****************************************************************************/
264 static int vout_Init( vout_thread_t *p_vout )
269 I_OUTPUTPICTURES = 0;
271 /* Initialize the output structure; we already found a codec,
272 * and the corresponding chroma we will be using. Since we can
273 * arbitrary scale, stick to the coordinates and aspect. */
274 p_vout->output.i_width = p_vout->render.i_width;
275 p_vout->output.i_height = p_vout->render.i_height;
276 p_vout->output.i_aspect = p_vout->render.i_aspect;
278 if( !p_vout->p_sys->i_opengl )
280 SetPort( p_vout->p_sys->p_qdport );
281 QTScaleMatrix( p_vout );
283 if( QTCreateSequence( p_vout ) )
285 msg_Err( p_vout, "unable to create sequence" );
291 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
292 p_vout->output.i_rmask = 0xFF0000;
293 p_vout->output.i_gmask = 0x00FF00;
294 p_vout->output.i_bmask = 0x0000FF;
297 /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
298 while( I_OUTPUTPICTURES <
299 p_vout->p_sys->i_opengl ? 1 : QT_MAX_DIRECTBUFFERS )
303 /* Find an empty picture slot */
304 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
306 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
308 p_pic = p_vout->p_picture + i_index;
313 /* Allocate the picture */
319 if( !p_vout->p_sys->i_opengl )
321 if( QTNewPicture( p_vout, p_pic ) )
328 /* Nothing special to do, we just need a basic allocated
330 vout_AllocatePicture( p_vout, p_pic, p_vout->output.i_chroma,
331 p_vout->output.i_width, p_vout->output.i_height,
332 p_vout->output.i_aspect );
335 p_pic->i_status = DESTROYED_PICTURE;
336 p_pic->i_type = DIRECT_PICTURE;
338 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
343 if( p_vout->p_sys->i_opengl )
345 [p_vout->p_sys->o_glview lockFocus];
346 [p_vout->p_sys->o_glview initTextures];
347 [p_vout->p_sys->o_glview unlockFocus];
353 /*****************************************************************************
354 * vout_End: terminate video thread output method
355 *****************************************************************************/
356 static void vout_End( vout_thread_t *p_vout )
360 if( !p_vout->p_sys->i_opengl )
362 QTDestroySequence( p_vout );
365 /* Free the direct buffers we allocated */
366 for( i_index = I_OUTPUTPICTURES; i_index; )
369 if( !p_vout->p_sys->i_opengl )
371 QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
375 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
380 /*****************************************************************************
381 * CloseVideo: destroy video thread output method
382 *****************************************************************************/
383 void E_(CloseVideo) ( vlc_object_t *p_this )
385 vout_thread_t * p_vout = (vout_thread_t *)p_this;
387 if( CoDestroyWindow( p_vout ) )
389 msg_Err( p_vout, "unable to destroy window" );
392 if( !p_vout->p_sys->i_opengl )
394 if ( p_vout->p_sys->p_fullscreen_state != NULL )
395 EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
399 free( p_vout->p_sys->p_matrix );
400 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
403 free( p_vout->p_sys );
406 /*****************************************************************************
407 * vout_Manage: handle events
408 *****************************************************************************
409 * This function should be called regularly by video output thread. It manages
410 * console events. It returns a non null value on error.
411 *****************************************************************************/
412 static int vout_Manage( vout_thread_t *p_vout )
414 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
416 if( CoToggleFullscreen( p_vout ) )
421 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
424 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
426 if( !p_vout->p_sys->i_opengl )
428 QTScaleMatrix( p_vout );
429 SetDSequenceMatrix( p_vout->p_sys->i_seq,
430 p_vout->p_sys->p_matrix );
433 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
436 /* hide/show mouse cursor
437 * this code looks unnecessarily complicated, but is necessary like this.
438 * it has to deal with multiple monitors and therefore checks a lot */
439 if( !p_vout->p_sys->b_mouse_moved && p_vout->b_fullscreen )
441 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 3000000 )
443 VLCHideMouse( p_vout, YES );
446 else if ( p_vout->p_sys->b_mouse_moved && p_vout->b_fullscreen )
448 VLCHideMouse( p_vout, NO );
451 /* disable screen saver */
452 UpdateSystemActivity( UsrActivity );
457 /*****************************************************************************
458 * vout_Display: displays previously rendered output
459 *****************************************************************************
460 * This function sends the currently rendered image to the display.
461 *****************************************************************************/
462 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
464 if( !p_vout->p_sys->i_opengl )
469 if( ( err = DecompressSequenceFrameS(
470 p_vout->p_sys->i_seq,
471 p_pic->p_sys->p_info,
472 p_pic->p_sys->i_size,
473 codecFlagUseImageBuffer, &flags, nil ) != noErr ) )
475 msg_Warn( p_vout, "DecompressSequenceFrameS failed: %d", err );
479 QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
484 if( [p_vout->p_sys->o_glview lockFocusIfCanDraw] )
486 /* Texture gotta be reload before the buffer is filled
487 (thanks to gcc from arstechnica forums) */
488 [p_vout->p_sys->o_glview drawRect:
489 [p_vout->p_sys->o_glview bounds]];
490 [p_vout->p_sys->o_glview reloadTexture];
491 [p_vout->p_sys->o_glview unlockFocus];
496 /*****************************************************************************
497 * CoSendRequest: send request to interface thread
498 *****************************************************************************
499 * Returns 0 on success, 1 otherwise
500 *****************************************************************************/
501 static int CoSendRequest( vout_thread_t *p_vout, SEL sel )
505 intf_thread_t * p_intf;
507 VLCVout * o_vlv = [[VLCVout alloc] init];
509 if( ( i_ret = ExecuteOnMainThread( o_vlv, sel, (void *)p_vout ) ) )
511 msg_Err( p_vout, "SendRequest: no way to communicate with mt" );
516 /*This makes this function dependant of the presence of a macosx
517 interface. We do not check if this interface exists, since it has
518 already been done before.*/
520 p_intf = [NSApp getIntf];
522 val.b_bool = VLC_TRUE;
523 var_Create(p_intf,"intf-change",VLC_VAR_BOOL);
524 var_Set(p_intf, "intf-change",val);
529 /*****************************************************************************
530 * CoCreateWindow: create new window
531 *****************************************************************************
532 * Returns 0 on success, 1 otherwise
533 *****************************************************************************/
534 static int CoCreateWindow( vout_thread_t *p_vout )
536 if( CoSendRequest( p_vout, @selector(createWindow:) ) )
538 msg_Err( p_vout, "CoSendRequest (createWindow) failed" );
545 /*****************************************************************************
546 * CoDestroyWindow: destroy window
547 *****************************************************************************
548 * Returns 0 on success, 1 otherwise
549 *****************************************************************************/
550 static int CoDestroyWindow( vout_thread_t *p_vout )
553 VLCHideMouse( p_vout, NO );
555 if( CoSendRequest( p_vout, @selector(destroyWindow:) ) )
557 msg_Err( p_vout, "CoSendRequest (destroyWindow) failed" );
564 /*****************************************************************************
565 * CoToggleFullscreen: toggle fullscreen
566 *****************************************************************************
567 * Returns 0 on success, 1 otherwise
568 *****************************************************************************/
569 static int CoToggleFullscreen( vout_thread_t *p_vout )
571 if( p_vout->p_sys->i_opengl )
577 QTDestroySequence( p_vout );
579 if( CoDestroyWindow( p_vout ) )
581 msg_Err( p_vout, "unable to destroy window" );
585 p_vout->b_fullscreen = !p_vout->b_fullscreen;
587 if( CoCreateWindow( p_vout ) )
589 msg_Err( p_vout, "unable to create window" );
593 SetPort( p_vout->p_sys->p_qdport );
594 QTScaleMatrix( p_vout );
596 if( QTCreateSequence( p_vout ) )
598 msg_Err( p_vout, "unable to create sequence" );
605 /*****************************************************************************
606 * VLCHideMouse: if b_hide then hide the cursor
607 *****************************************************************************/
608 static void VLCHideMouse ( vout_thread_t *p_vout, BOOL b_hide )
613 NSWindow *o_window = p_vout->p_sys->o_window;
614 NSView *o_contents = [o_window contentView];
616 s_rect = [o_contents bounds];
617 ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
618 ml = [o_contents convertPoint:ml fromView:nil];
619 b_inside = [o_contents mouse: ml inRect: s_rect];
621 if ( b_hide && b_inside )
623 /* only hide if mouse over VLCQTView */
624 [NSCursor setHiddenUntilMouseMoves: YES];
628 [NSCursor setHiddenUntilMouseMoves: NO];
630 p_vout->p_sys->b_mouse_moved = NO;
631 p_vout->p_sys->i_time_mouse_last_moved = mdate();
635 /*****************************************************************************
636 * QTScaleMatrix: scale matrix
637 *****************************************************************************/
638 static void QTScaleMatrix( vout_thread_t *p_vout )
641 unsigned int i_width, i_height;
642 Fixed factor_x, factor_y;
643 unsigned int i_offset_x = 0;
644 unsigned int i_offset_y = 0;
646 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
648 i_width = s_rect.right - s_rect.left;
649 i_height = s_rect.bottom - s_rect.top;
651 if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
653 int i_adj_width = i_height * p_vout->output.i_aspect /
656 factor_x = FixDiv( Long2Fix( i_adj_width ),
657 Long2Fix( p_vout->output.i_width ) );
658 factor_y = FixDiv( Long2Fix( i_height ),
659 Long2Fix( p_vout->output.i_height ) );
661 i_offset_x = (i_width - i_adj_width) / 2;
665 int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
666 p_vout->output.i_aspect;
668 factor_x = FixDiv( Long2Fix( i_width ),
669 Long2Fix( p_vout->output.i_width ) );
670 factor_y = FixDiv( Long2Fix( i_adj_height ),
671 Long2Fix( p_vout->output.i_height ) );
673 i_offset_y = (i_height - i_adj_height) / 2;
676 SetIdentityMatrix( p_vout->p_sys->p_matrix );
678 ScaleMatrix( p_vout->p_sys->p_matrix,
680 Long2Fix(0), Long2Fix(0) );
682 TranslateMatrix( p_vout->p_sys->p_matrix,
683 Long2Fix(i_offset_x),
684 Long2Fix(i_offset_y) );
688 /*****************************************************************************
689 * QTCreateSequence: create a new sequence
690 *****************************************************************************
691 * Returns 0 on success, 1 otherwise
692 *****************************************************************************/
693 static int QTCreateSequence( vout_thread_t *p_vout )
696 ImageDescriptionPtr p_descr;
698 HLock( (Handle)p_vout->p_sys->h_img_descr );
699 p_descr = *p_vout->p_sys->h_img_descr;
701 p_descr->idSize = sizeof(ImageDescription);
702 p_descr->cType = p_vout->p_sys->i_codec;
703 p_descr->version = 1;
704 p_descr->revisionLevel = 0;
705 p_descr->vendor = 'appl';
706 p_descr->width = p_vout->output.i_width;
707 p_descr->height = p_vout->output.i_height;
708 p_descr->hRes = Long2Fix(72);
709 p_descr->vRes = Long2Fix(72);
710 p_descr->spatialQuality = codecLosslessQuality;
711 p_descr->frameCount = 1;
712 p_descr->clutID = -1;
713 p_descr->dataSize = 0;
716 HUnlock( (Handle)p_vout->p_sys->h_img_descr );
718 if( ( err = DecompressSequenceBeginS(
719 &p_vout->p_sys->i_seq,
720 p_vout->p_sys->h_img_descr,
722 p_vout->p_sys->p_qdport,
724 p_vout->p_sys->p_matrix,
726 codecFlagUseImageBuffer,
727 codecLosslessQuality,
728 p_vout->p_sys->img_dc ) ) )
730 msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
737 /*****************************************************************************
738 * QTDestroySequence: destroy sequence
739 *****************************************************************************/
740 static void QTDestroySequence( vout_thread_t *p_vout )
742 CDSequenceEnd( p_vout->p_sys->i_seq );
745 /*****************************************************************************
746 * QTNewPicture: allocate a picture
747 *****************************************************************************
748 * Returns 0 on success, 1 otherwise
749 *****************************************************************************/
750 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
752 int i_width = p_vout->output.i_width;
753 int i_height = p_vout->output.i_height;
755 /* We know the chroma, allocate a buffer which will be used
756 * directly by the decoder */
757 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
759 if( p_pic->p_sys == NULL )
764 switch( p_vout->output.i_chroma )
766 case VLC_FOURCC('I','4','2','0'):
768 p_pic->p_sys->p_info = (void *)&p_pic->p_sys->pixmap_i420;
769 p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
771 /* Allocate the memory buffer */
772 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
773 16, i_width * i_height * 3 / 2 );
776 p_pic->Y_PIXELS = p_pic->p_data;
777 p_pic->p[Y_PLANE].i_lines = i_height;
778 p_pic->p[Y_PLANE].i_pitch = i_width;
779 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
780 p_pic->p[Y_PLANE].i_visible_pitch = i_width;
783 p_pic->U_PIXELS = p_pic->Y_PIXELS + i_height * i_width;
784 p_pic->p[U_PLANE].i_lines = i_height / 2;
785 p_pic->p[U_PLANE].i_pitch = i_width / 2;
786 p_pic->p[U_PLANE].i_pixel_pitch = 1;
787 p_pic->p[U_PLANE].i_visible_pitch = i_width / 2;
790 p_pic->V_PIXELS = p_pic->U_PIXELS + i_height * i_width / 4;
791 p_pic->p[V_PLANE].i_lines = i_height / 2;
792 p_pic->p[V_PLANE].i_pitch = i_width / 2;
793 p_pic->p[V_PLANE].i_pixel_pitch = 1;
794 p_pic->p[V_PLANE].i_visible_pitch = i_width / 2;
796 /* We allocated 3 planes */
799 #define P p_pic->p_sys->pixmap_i420
800 P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
801 - p_pic->p_sys->p_info;
802 P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
803 - p_pic->p_sys->p_info;
804 P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
805 - p_pic->p_sys->p_info;
807 P.componentInfoY.rowBytes = i_width;
808 P.componentInfoCb.rowBytes = i_width / 2;
809 P.componentInfoCr.rowBytes = i_width / 2;
815 /* Unknown chroma, tell the guy to get lost */
816 free( p_pic->p_sys );
817 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
818 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
826 /*****************************************************************************
827 * QTFreePicture: destroy a picture allocated with QTNewPicture
828 *****************************************************************************/
829 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
831 switch( p_vout->output.i_chroma )
833 case VLC_FOURCC('I','4','2','0'):
834 free( p_pic->p_data_orig );
838 free( p_pic->p_sys );
841 /*****************************************************************************
842 * VLCWindow implementation
843 *****************************************************************************/
844 @implementation VLCWindow
846 - (void)setVout:(vout_thread_t *)_p_vout
851 - (vout_thread_t *)getVout
856 - (void)scaleWindowWithFactor: (float)factor
859 int i_corrected_height, i_corrected_width;
861 NSPoint topleftscreen;
863 if ( !p_vout->b_fullscreen )
866 topleftbase.y = [self frame].size.height;
867 topleftscreen = [self convertBaseToScreen: topleftbase];
869 if( p_vout->output.i_height * p_vout->output.i_aspect >
870 p_vout->output.i_width * VOUT_ASPECT_FACTOR )
872 i_corrected_width = p_vout->output.i_height * p_vout->output.i_aspect /
874 newsize.width = (int) ( i_corrected_width * factor );
875 newsize.height = (int) ( p_vout->render.i_height * factor );
879 i_corrected_height = p_vout->output.i_width * VOUT_ASPECT_FACTOR /
880 p_vout->output.i_aspect;
881 newsize.width = (int) ( p_vout->render.i_width * factor );
882 newsize.height = (int) ( i_corrected_height * factor );
885 [self setContentSize: newsize];
887 [self setFrameTopLeftPoint: topleftscreen];
888 p_vout->i_changes |= VOUT_SIZE_CHANGE;
892 - (void)toggleFloatOnTop
894 if( config_GetInt( p_vout, "video-on-top" ) )
896 config_PutInt( p_vout, "video-on-top", 0 );
897 [p_vout->p_sys->o_window setLevel: NSNormalWindowLevel];
901 config_PutInt( p_vout, "video-on-top", 1 );
902 [p_vout->p_sys->o_window setLevel: NSStatusWindowLevel];
906 - (void)toggleFullscreen
908 config_PutInt(p_vout, "fullscreen", !p_vout->b_fullscreen);
909 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
914 return( p_vout->b_fullscreen );
917 - (BOOL)canBecomeKeyWindow
922 - (void)keyDown:(NSEvent *)o_event
926 unsigned int i_pressed_modifiers = 0;
929 i_pressed_modifiers = [o_event modifierFlags];
931 if( i_pressed_modifiers & NSShiftKeyMask )
932 val.i_int |= KEY_MODIFIER_SHIFT;
933 if( i_pressed_modifiers & NSControlKeyMask )
934 val.i_int |= KEY_MODIFIER_CTRL;
935 if( i_pressed_modifiers & NSAlternateKeyMask )
936 val.i_int |= KEY_MODIFIER_ALT;
937 if( i_pressed_modifiers & NSCommandKeyMask )
938 val.i_int |= KEY_MODIFIER_COMMAND;
940 key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
944 /* Escape should always get you out of fullscreen */
945 if( key == (unichar) 0x1b )
947 if( [self isFullscreen] )
949 [self toggleFullscreen];
952 else if ( key == ' ' )
954 playlist_t *p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
956 if ( p_playlist != NULL )
958 playlist_Pause( p_playlist );
959 vlc_object_release( p_playlist);
964 val.i_int |= CocoaKeyToVLC( key );
965 var_Set( p_vout->p_vlc, "key-pressed", val );
970 [super keyDown: o_event];
976 NSMutableString * o_title;
977 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
980 if( p_playlist == NULL )
985 vlc_mutex_lock( &p_playlist->object_lock );
986 o_title = [NSMutableString stringWithUTF8String:
987 p_playlist->pp_items[p_playlist->i_index]->psz_uri];
988 vlc_mutex_unlock( &p_playlist->object_lock );
990 vlc_object_release( p_playlist );
994 NSRange prefix_range = [o_title rangeOfString: @"file:"];
995 if( prefix_range.location != NSNotFound )
997 [o_title deleteCharactersInRange: prefix_range];
1000 [self setTitleWithRepresentedFilename: o_title];
1005 [NSString stringWithCString: VOUT_TITLE " (QuickTime)"]];
1009 /* This is actually the same as VLCControls::stop. */
1010 - (BOOL)windowShouldClose:(id)sender
1012 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1014 if( p_playlist == NULL )
1019 playlist_Stop( p_playlist );
1020 vlc_object_release( p_playlist );
1022 /* The window will be closed by the intf later. */
1028 /*****************************************************************************
1029 * VLCQTView implementation
1030 *****************************************************************************/
1031 @implementation VLCQTView
1033 - (void)drawRect:(NSRect)rect
1035 vout_thread_t * p_vout;
1036 id o_window = [self window];
1037 p_vout = (vout_thread_t *)[o_window getVout];
1039 [[NSColor blackColor] set];
1041 [super drawRect: rect];
1043 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1046 - (BOOL)acceptsFirstResponder
1051 - (BOOL)becomeFirstResponder
1053 vout_thread_t * p_vout;
1054 id o_window = [self window];
1055 p_vout = (vout_thread_t *)[o_window getVout];
1057 [o_window setAcceptsMouseMovedEvents: YES];
1061 - (BOOL)resignFirstResponder
1063 vout_thread_t * p_vout;
1064 id o_window = [self window];
1065 p_vout = (vout_thread_t *)[o_window getVout];
1067 [o_window setAcceptsMouseMovedEvents: NO];
1068 VLCHideMouse( p_vout, NO );
1072 - (void)mouseDown:(NSEvent *)o_event
1074 vout_thread_t * p_vout;
1075 id o_window = [self window];
1076 p_vout = (vout_thread_t *)[o_window getVout];
1079 switch( [o_event type] )
1081 case NSLeftMouseDown:
1083 var_Get( p_vout, "mouse-button-down", &val );
1085 var_Set( p_vout, "mouse-button-down", val );
1090 [super mouseDown: o_event];
1095 - (void)otherMouseDown:(NSEvent *)o_event
1097 /* This is not the the wheel button. you need to poll the
1098 * mouseWheel event for that. other is a third, forth or fifth button */
1099 vout_thread_t * p_vout;
1100 id o_window = [self window];
1101 p_vout = (vout_thread_t *)[o_window getVout];
1104 switch( [o_event type] )
1106 case NSOtherMouseDown:
1108 var_Get( p_vout, "mouse-button-down", &val );
1110 var_Set( p_vout, "mouse-button-down", val );
1115 [super mouseDown: o_event];
1120 - (void)rightMouseDown:(NSEvent *)o_event
1122 vout_thread_t * p_vout;
1123 id o_window = [self window];
1124 p_vout = (vout_thread_t *)[o_window getVout];
1127 switch( [o_event type] )
1129 case NSRightMouseDown:
1131 var_Get( p_vout, "mouse-button-down", &val );
1133 var_Set( p_vout, "mouse-button-down", val );
1138 [super mouseDown: o_event];
1143 - (void)mouseUp:(NSEvent *)o_event
1145 vout_thread_t * p_vout;
1146 id o_window = [self window];
1147 p_vout = (vout_thread_t *)[o_window getVout];
1150 switch( [o_event type] )
1155 b_val.b_bool = VLC_TRUE;
1156 var_Set( p_vout, "mouse-clicked", b_val );
1158 var_Get( p_vout, "mouse-button-down", &val );
1160 var_Set( p_vout, "mouse-button-down", val );
1165 [super mouseUp: o_event];
1170 - (void)otherMouseUp:(NSEvent *)o_event
1172 vout_thread_t * p_vout;
1173 id o_window = [self window];
1174 p_vout = (vout_thread_t *)[o_window getVout];
1177 switch( [o_event type] )
1179 case NSOtherMouseUp:
1181 var_Get( p_vout, "mouse-button-down", &val );
1183 var_Set( p_vout, "mouse-button-down", val );
1188 [super mouseUp: o_event];
1193 - (void)rightMouseUp:(NSEvent *)o_event
1195 vout_thread_t * p_vout;
1196 id o_window = [self window];
1197 p_vout = (vout_thread_t *)[o_window getVout];
1200 switch( [o_event type] )
1202 case NSRightMouseUp:
1204 var_Get( p_vout, "mouse-button-down", &val );
1206 var_Set( p_vout, "mouse-button-down", val );
1211 [super mouseUp: o_event];
1216 - (void)mouseDragged:(NSEvent *)o_event
1218 [self mouseMoved:o_event];
1221 - (void)otherMouseDragged:(NSEvent *)o_event
1223 [self mouseMoved:o_event];
1226 - (void)rightMouseDragged:(NSEvent *)o_event
1228 [self mouseMoved:o_event];
1231 - (void)mouseMoved:(NSEvent *)o_event
1237 vout_thread_t * p_vout;
1238 id o_window = [self window];
1239 p_vout = (vout_thread_t *)[o_window getVout];
1241 s_rect = [self bounds];
1242 ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
1243 b_inside = [self mouse: ml inRect: s_rect];
1248 int i_width, i_height, i_x, i_y;
1250 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
1251 (unsigned int)s_rect.size.height,
1252 &i_x, &i_y, &i_width, &i_height );
1254 val.i_int = ( ((int)ml.x) - i_x ) *
1255 p_vout->render.i_width / i_width;
1256 var_Set( p_vout, "mouse-x", val );
1258 val.i_int = ( ((int)ml.y) - i_y ) *
1259 p_vout->render.i_height / i_height;
1260 var_Set( p_vout, "mouse-y", val );
1262 val.b_bool = VLC_TRUE;
1263 var_Set( p_vout, "mouse-moved", val );
1264 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1265 p_vout->p_sys->b_mouse_moved = YES;
1268 [super mouseMoved: o_event];
1273 /*****************************************************************************
1274 * VLCGLView implementation
1275 *****************************************************************************/
1276 @implementation VLCGLView
1279 - (id) initWithFrame: (NSRect) frame vout: (vout_thread_t*) _p_vout
1284 NSOpenGLPixelFormatAttribute attribs[] =
1286 NSOpenGLPFAAccelerated,
1287 NSOpenGLPFANoRecovery,
1288 NSOpenGLPFADoubleBuffer,
1293 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
1294 initWithAttributes: attribs];
1298 fprintf( stderr, "Cannot create NSOpenGLPixelFormat\n" );
1302 self = [super initWithFrame:frame pixelFormat: fmt];
1304 [[self openGLContext] makeCurrentContext];
1305 [[self openGLContext] update];
1308 /* Black bacjground */
1309 glClearColor( 0.0, 0.0, 0.0, 0.0 );
1311 /* Check if the user asked for useless visual effects */
1312 psz_effect = config_GetPsz( p_vout, "macosx-opengl-effect" );
1313 if( !strcmp( psz_effect, "none" ) )
1315 i_effect = OPENGL_EFFECT_NONE;
1317 else if( !strcmp( psz_effect, "cube" ) )
1319 i_effect = OPENGL_EFFECT_CUBE;
1320 glMatrixMode( GL_PROJECTION );
1322 glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
1323 glMatrixMode( GL_MODELVIEW );
1325 glTranslatef( 0.0, 0.0, - 5.0 );
1326 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
1327 glEnable( GL_BLEND );
1328 glEnable( GL_POLYGON_SMOOTH );
1329 glDisable( GL_DEPTH_TEST );
1333 msg_Warn( p_vout, "no valid opengl effect provided, using "
1335 i_effect = OPENGL_EFFECT_NONE;
1345 [[self openGLContext] makeCurrentContext];
1347 NSRect bounds = [self bounds];
1349 glViewport( 0, 0, (GLint) bounds.size.width,
1350 (GLint) bounds.size.height );
1352 /* Quad size is set in order to preserve the aspect ratio */
1353 if( bounds.size.height * p_vout->output.i_aspect <
1354 bounds.size.width * VOUT_ASPECT_FACTOR )
1356 f_x = bounds.size.height * p_vout->render.i_aspect /
1357 VOUT_ASPECT_FACTOR / bounds.size.width;
1363 f_y = bounds.size.width * VOUT_ASPECT_FACTOR /
1364 p_vout->render.i_aspect / bounds.size.height;
1368 - (void) initTextures
1370 [[self openGLContext] makeCurrentContext];
1372 /* Create textures */
1373 glGenTextures( 1, &i_texture );
1375 glEnable( GL_TEXTURE_RECTANGLE_EXT );
1376 glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
1378 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1380 /* Use VRAM texturing */
1381 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1382 GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE );
1384 /* Tell the driver not to make a copy of the texture but to use
1386 glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );
1388 /* Linear interpolation */
1389 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1390 GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1391 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1392 GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1394 /* I have no idea what this exactly does, but it seems to be
1395 necessary for scaling */
1396 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1397 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1398 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1399 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1400 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
1402 glTexImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,
1403 p_vout->output.i_width, p_vout->output.i_height, 0,
1404 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
1405 PP_OUTPUTPICTURE[0]->p_data );
1410 - (void) reloadTexture
1412 [[self openGLContext] makeCurrentContext];
1414 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1416 /* glTexSubImage2D is faster than glTexImage2D
1417 http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/
1418 TextureRange/MainOpenGLView.m.htm */
1419 glTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0,
1420 p_vout->output.i_width, p_vout->output.i_height,
1421 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
1422 PP_OUTPUTPICTURE[0]->p_data );
1427 glBegin( GL_QUADS );
1429 glTexCoord2f( 0.0, 0.0 );
1430 glVertex2f( - f_x, f_y );
1432 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1433 glVertex2f( - f_x, - f_y );
1435 glTexCoord2f( (float) p_vout->output.i_width,
1436 (float) p_vout->output.i_height );
1437 glVertex2f( f_x, - f_y );
1439 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1440 glVertex2f( f_x, f_y );
1446 glBegin( GL_QUADS );
1447 glTexCoord2f( 0.0, 0.0 );
1448 glVertex3f( - 1.0, 1.0, 1.0 );
1449 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1450 glVertex3f( - 1.0, - 1.0, 1.0 );
1451 glTexCoord2f( (float) p_vout->output.i_width,
1452 (float) p_vout->output.i_height );
1453 glVertex3f( 1.0, - 1.0, 1.0 );
1454 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1455 glVertex3f( 1.0, 1.0, 1.0 );
1457 glBegin( GL_QUADS );
1458 glTexCoord2f( 0.0, 0.0 );
1459 glVertex3f( - 1.0, 1.0, - 1.0 );
1460 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1461 glVertex3f( - 1.0, - 1.0, - 1.0 );
1462 glTexCoord2f( (float) p_vout->output.i_width,
1463 (float) p_vout->output.i_height );
1464 glVertex3f( - 1.0, - 1.0, 1.0 );
1465 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1466 glVertex3f( - 1.0, 1.0, 1.0 );
1468 glBegin( GL_QUADS );
1469 glTexCoord2f( 0.0, 0.0 );
1470 glVertex3f( 1.0, 1.0, - 1.0 );
1471 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1472 glVertex3f( 1.0, - 1.0, - 1.0 );
1473 glTexCoord2f( (float) p_vout->output.i_width,
1474 (float) p_vout->output.i_height );
1475 glVertex3f( - 1.0, - 1.0, - 1.0 );
1476 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1477 glVertex3f( - 1.0, 1.0, - 1.0 );
1479 glBegin( GL_QUADS );
1480 glTexCoord2f( 0.0, 0.0 );
1481 glVertex3f( 1.0, 1.0, 1.0 );
1482 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1483 glVertex3f( 1.0, - 1.0, 1.0 );
1484 glTexCoord2f( (float) p_vout->output.i_width,
1485 (float) p_vout->output.i_height );
1486 glVertex3f( 1.0, - 1.0, - 1.0 );
1487 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1488 glVertex3f( 1.0, 1.0, - 1.0 );
1490 glBegin( GL_QUADS );
1491 glTexCoord2f( 0.0, 0.0 );
1492 glVertex3f( - 1.0, 1.0, - 1.0 );
1493 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1494 glVertex3f( - 1.0, 1.0, 1.0 );
1495 glTexCoord2f( (float) p_vout->output.i_width,
1496 (float) p_vout->output.i_height );
1497 glVertex3f( 1.0, 1.0, 1.0 );
1498 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1499 glVertex3f( 1.0, 1.0, - 1.0 );
1501 glBegin( GL_QUADS );
1502 glTexCoord2f( 0.0, 0.0 );
1503 glVertex3f( - 1.0, - 1.0, 1.0 );
1504 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1505 glVertex3f( - 1.0, - 1.0, - 1.0 );
1506 glTexCoord2f( (float) p_vout->output.i_width,
1507 (float) p_vout->output.i_height );
1508 glVertex3f( 1.0, - 1.0, - 1.0 );
1509 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1510 glVertex3f( 1.0, - 1.0, 1.0 );
1514 - (void) drawRect: (NSRect) rect
1516 [[self openGLContext] makeCurrentContext];
1518 /* Swap buffers only during the vertical retrace of the monitor.
1519 http://developer.apple.com/documentation/GraphicsImaging/
1520 Conceptual/OpenGL/chap5/chapter_5_section_44.html */
1521 long params[] = { 1 };
1522 CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
1525 /* Black background */
1526 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1530 [[self openGLContext] flushBuffer];
1535 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1536 if( i_effect == OPENGL_EFFECT_CUBE )
1538 glRotatef( 1.0, 0.5, 0.5, 1.0 );
1546 /* Wait for the job to be done */
1547 [[self openGLContext] flushBuffer];
1552 /*****************************************************************************
1553 * VLCVout implementation
1554 *****************************************************************************/
1555 @implementation VLCVout
1557 - (void)createWindow:(NSValue *)o_value
1561 NSScreen * o_screen;
1562 vout_thread_t * p_vout;
1563 vlc_bool_t b_main_screen;
1565 p_vout = (vout_thread_t *)[o_value pointerValue];
1567 p_vout->p_sys->o_window = [VLCWindow alloc];
1568 [p_vout->p_sys->o_window setVout: p_vout];
1569 [p_vout->p_sys->o_window setReleasedWhenClosed: YES];
1571 if( var_Get( p_vout, "video-device", &val ) < 0 )
1573 o_screen = [NSScreen mainScreen];
1578 NSArray *o_screens = [NSScreen screens];
1579 unsigned int i_index = val.i_int;
1581 if( [o_screens count] < i_index )
1583 o_screen = [NSScreen mainScreen];
1589 o_screen = [o_screens objectAtIndex: i_index];
1590 config_PutInt( p_vout, "macosx-vdev", i_index );
1591 b_main_screen = (i_index == 0);
1595 if( p_vout->p_sys->i_opengl )
1597 /* XXX Fix fullscreen mode */
1598 p_vout->b_fullscreen = 0;
1601 if( p_vout->b_fullscreen )
1603 NSRect screen_rect = [o_screen frame];
1604 screen_rect.origin.x = screen_rect.origin.y = 0;
1606 if ( b_main_screen && p_vout->p_sys->p_fullscreen_state == NULL )
1607 BeginFullScreen( &p_vout->p_sys->p_fullscreen_state, NULL, 0, 0,
1608 NULL, NULL, fullScreenAllowEvents );
1610 [p_vout->p_sys->o_window
1611 initWithContentRect: screen_rect
1612 styleMask: NSBorderlessWindowMask
1613 backing: NSBackingStoreBuffered
1614 defer: NO screen: o_screen];
1616 //[p_vout->p_sys->o_window setLevel: NSPopUpMenuWindowLevel - 1];
1617 p_vout->p_sys->b_mouse_moved = YES;
1618 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1622 unsigned int i_stylemask = NSTitledWindowMask |
1623 NSMiniaturizableWindowMask |
1624 NSClosableWindowMask |
1625 NSResizableWindowMask;
1627 if( !p_vout->p_sys->i_opengl )
1629 if ( p_vout->p_sys->p_fullscreen_state != NULL )
1630 EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
1631 p_vout->p_sys->p_fullscreen_state = NULL;
1634 [p_vout->p_sys->o_window
1635 initWithContentRect: p_vout->p_sys->s_rect
1636 styleMask: i_stylemask
1637 backing: NSBackingStoreBuffered
1638 defer: NO screen: o_screen];
1640 [p_vout->p_sys->o_window setAlphaValue: config_GetFloat( p_vout, "macosx-opaqueness" )];
1642 if( config_GetInt( p_vout, "video-on-top" ) )
1644 [p_vout->p_sys->o_window setLevel: NSStatusWindowLevel];
1647 if( !p_vout->p_sys->b_pos_saved )
1649 [p_vout->p_sys->o_window center];
1653 if( !p_vout->p_sys->i_opengl )
1655 o_view = [[VLCQTView alloc] init];
1656 /* FIXME: [o_view setMenu:] */
1657 [p_vout->p_sys->o_window setContentView: o_view];
1658 [o_view autorelease];
1661 p_vout->p_sys->p_qdport = [o_view qdPort];
1662 [o_view unlockFocus];
1666 #define o_glview p_vout->p_sys->o_glview
1667 o_glview = [[VLCGLView alloc] initWithFrame: p_vout->p_sys->s_rect vout: p_vout];
1668 [p_vout->p_sys->o_window setContentView: o_glview];
1669 [o_glview autorelease];
1673 [p_vout->p_sys->o_window updateTitle];
1674 [p_vout->p_sys->o_window makeKeyAndOrderFront: nil];
1678 - (void)destroyWindow:(NSValue *)o_value
1680 vout_thread_t * p_vout;
1682 p_vout = (vout_thread_t *)[o_value pointerValue];
1684 if( !p_vout->b_fullscreen )
1688 s_rect = [[p_vout->p_sys->o_window contentView] frame];
1689 p_vout->p_sys->s_rect.size = s_rect.size;
1691 s_rect = [p_vout->p_sys->o_window frame];
1692 p_vout->p_sys->s_rect.origin = s_rect.origin;
1694 p_vout->p_sys->b_pos_saved = YES;
1697 p_vout->p_sys->p_qdport = nil;
1698 [p_vout->p_sys->o_window close];
1699 p_vout->p_sys->o_window = nil;