1 /*****************************************************************************
2 * mac.c: Screen capture module for the Mac.
3 *****************************************************************************
4 * Copyright (C) 2004, 2008 the VideoLAN team
7 * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8 * arai <arai_a@mac.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #import <vlc_common.h>
35 // Fix ourselves ColorSync headers that gets included in ApplicationServices.
36 #define DisposeCMProfileIterateUPP(a) DisposeCMProfileIterateUPP(CMProfileIterateUPP userUPP __attribute__((unused)))
37 #define DisposeCMMIterateUPP(a) DisposeCMMIterateUPP(CMProfileIterateUPP userUPP __attribute__((unused)))
38 #define __MACHINEEXCEPTIONS__
39 #import <ApplicationServices/ApplicationServices.h>
41 #import <OpenGL/OpenGL.h>
45 typedef int CGSConnectionRef;
46 extern CGError CGSNewConnection( void *, CGSConnectionRef * );
47 extern CGError CGSReleaseConnection( CGSConnectionRef );
48 extern CGError CGSGetGlobalCursorDataSize( CGSConnectionRef, int * );
49 extern CGError CGSGetGlobalCursorData( CGSConnectionRef, unsigned char *,
50 int *, int *, CGRect *, CGPoint *,
51 int *, int *, int * );
52 extern CGError CGSGetCurrentCursorLocation( CGSConnectionRef, CGPoint * );
66 GLuint cursor_texture;
79 CGSConnectionRef connection;
82 int screen_InitCapture( demux_t *p_demux )
84 demux_sys_t *p_sys = p_demux->p_sys;
85 screen_data_t *p_data;
86 CGLPixelFormatAttribute attribs[4];
87 CGLPixelFormatObj pix;
91 p_sys->p_data = p_data =
92 ( screen_data_t * )malloc( sizeof( screen_data_t ) );
94 attribs[0] = kCGLPFAFullScreen;
95 attribs[1] = kCGLPFADisplayMask;
96 attribs[2] = CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() );
99 CGLChoosePixelFormat( attribs, &pix, &npix );
100 CGLCreateContext( pix, NULL, &( p_data->screen ) );
101 CGLDestroyPixelFormat( pix );
103 CGLSetCurrentContext( p_data->screen );
104 CGLSetFullScreen( p_data->screen );
106 glGetIntegerv( GL_VIEWPORT, viewport );
108 p_data->screen_width = viewport[2];
109 p_data->screen_height = viewport[3];
111 p_data->left = p_sys->i_left;
112 p_data->top = p_sys->i_top;
113 p_data->src_width = var_CreateGetInteger( p_demux, "screen-width" );
114 p_data->src_height = var_CreateGetInteger( p_demux, "screen-height" );
115 if (p_data->src_width <= 0 || p_data->src_height <= 0) {
116 p_data->src_width = p_data->screen_width;
117 p_data->src_height = p_data->screen_height;
119 p_data->dest_width = p_data->src_width;
120 p_data->dest_height = p_data->src_height;
122 attribs [0] = kCGLPFAOffScreen;
123 attribs [1] = kCGLPFAColorSize;
127 CGLChoosePixelFormat( attribs, &pix, &npix );
128 CGLCreateContext( pix, NULL, &( p_data->scaled ) );
129 CGLDestroyPixelFormat( pix );
131 CGLSetCurrentContext( p_data->scaled );
132 p_data->scaled_image = ( char * )malloc( p_data->dest_width
133 * p_data->dest_height * 4 );
134 CGLSetOffScreen( p_data->scaled, p_data->dest_width, p_data->dest_height,
135 p_data->dest_width * 4, p_data->scaled_image );
137 es_format_Init( &p_sys->fmt, VIDEO_ES, VLC_CODEC_RGB32 );
139 /* p_sys->fmt.video.i_* must set to screen size, not subscreen size */
140 p_sys->fmt.video.i_width = p_data->screen_width;
141 p_sys->fmt.video.i_visible_width = p_data->screen_width;
142 p_sys->fmt.video.i_height = p_data->screen_height;
143 p_sys->fmt.video.i_bits_per_pixel = 32;
145 glGenTextures( 1, &( p_data->texture ) );
146 glBindTexture( GL_TEXTURE_2D, p_data->texture );
148 p_data->texture_image
149 = ( char * )malloc( p_data->src_width * p_data->src_height * 4 );
151 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
152 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
153 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
154 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
156 glGenTextures( 1, &( p_data->cursor_texture ) );
157 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
159 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
160 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
161 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
162 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
164 CGSNewConnection( NULL, &( p_data->connection ) );
169 int screen_CloseCapture( demux_t *p_demux )
171 screen_data_t *p_data = ( screen_data_t * )p_demux->p_sys->p_data;
173 CGSReleaseConnection( p_data->connection );
175 CGLSetCurrentContext( NULL );
176 CGLClearDrawable( p_data->screen );
177 CGLDestroyContext( p_data->screen );
182 block_t *screen_Capture( demux_t *p_demux )
184 demux_sys_t *p_sys = p_demux->p_sys;
185 screen_data_t *p_data = ( screen_data_t * )p_sys->p_data;
189 i_size = p_sys->fmt.video.i_height * p_sys->fmt.video.i_width * 4;
191 if( !( p_block = block_New( p_demux, i_size ) ) )
193 msg_Warn( p_demux, "cannot get block" );
198 CGError cursor_result;
204 = CGSGetCurrentCursorLocation( p_data->connection, &cursor_pos );
206 if( p_sys->b_follow_mouse
207 && cursor_result == kCGErrorSuccess )
209 FollowMouse( p_sys, cursor_pos.x, cursor_pos.y );
210 p_data->left = p_sys->i_left;
211 p_data->top = p_sys->i_top;
214 CGLSetCurrentContext( p_data->screen );
215 glReadPixels( p_data->left,
216 p_data->screen_height - p_data->top - p_data->src_height,
219 GL_RGBA, GL_UNSIGNED_BYTE,
220 p_data->texture_image );
222 CGLSetCurrentContext( p_data->scaled );
223 glEnable( GL_TEXTURE_2D );
224 glBindTexture( GL_TEXTURE_2D, p_data->texture );
225 glTexImage2D( GL_TEXTURE_2D, 0,
226 GL_RGBA8, p_data->src_width, p_data->src_height, 0,
227 GL_RGBA, GL_UNSIGNED_BYTE, p_data->texture_image );
229 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
230 glClear( GL_COLOR_BUFFER_BIT );
231 glColor3f( 1.0f, 1.0f, 1.0f );
232 glEnable( GL_TEXTURE_2D );
233 glBindTexture( GL_TEXTURE_2D, p_data->texture );
234 glBegin( GL_POLYGON );
235 glTexCoord2f( 0.0, 1.0 ); glVertex2f( -1.0, -1.0 );
236 glTexCoord2f( 1.0, 1.0 ); glVertex2f( 1.0, -1.0 );
237 glTexCoord2f( 1.0, 0.0 ); glVertex2f( 1.0, 1.0 );
238 glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, 1.0 );
240 glDisable( GL_TEXTURE_2D );
243 int tmp1, tmp2, tmp3, tmp4;
244 unsigned char *cursor_image;
248 if( cursor_result == kCGErrorSuccess
249 && CGSGetGlobalCursorDataSize( p_data->connection, &size )
252 cursor_image = ( unsigned char* )malloc( size );
253 if( CGSGetGlobalCursorData( p_data->connection,
256 &cursor_rect, &cursor_hot,
257 &tmp2, &tmp3, &tmp4 )
260 glEnable( GL_TEXTURE_2D );
261 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
262 glTexImage2D( GL_TEXTURE_2D, 0,
264 ( int )( cursor_rect.size.width ),
265 ( int )( cursor_rect.size.height ), 0,
266 GL_RGBA, GL_UNSIGNED_BYTE,
267 ( char * )cursor_image );
269 cursor_rect.origin.x = cursor_pos.x - p_data->left - cursor_hot.x;
270 cursor_rect.origin.y = cursor_pos.y - p_data->top - cursor_hot.y;
273 = 2.0 * cursor_rect.origin.x / p_data->src_width - 1.0;
275 = 2.0 * cursor_rect.origin.y / p_data->src_height - 1.0;
276 cursor_rect.size.width
277 = 2.0 * cursor_rect.size.width / p_data->src_width;
278 cursor_rect.size.height
279 = 2.0 * cursor_rect.size.height / p_data->src_height;
281 glColor3f( 1.0f, 1.0f, 1.0f );
282 glEnable( GL_TEXTURE_2D );
283 glEnable( GL_BLEND );
284 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
285 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
286 glBegin( GL_POLYGON );
287 glTexCoord2f( 0.0, 0.0 ); glVertex2f( cursor_rect.origin.x,
288 cursor_rect.origin.y );
289 glTexCoord2f( 1.0, 0.0 ); glVertex2f( cursor_rect.origin.x
290 + cursor_rect.size.width,
291 cursor_rect.origin.y );
292 glTexCoord2f( 1.0, 1.0 ); glVertex2f( cursor_rect.origin.x
293 + cursor_rect.size.width,
295 + cursor_rect.size.height );
296 glTexCoord2f( 0.0, 1.0 ); glVertex2f( cursor_rect.origin.x,
298 + cursor_rect.size.height );
300 glDisable( GL_BLEND );
301 glDisable( GL_TEXTURE_2D );
303 free( cursor_image );
309 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,