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 *****************************************************************************/
34 #import <vlc_common.h>
36 #import <ApplicationServices/ApplicationServices.h>
37 #import <OpenGL/OpenGL.h>
40 typedef int CGSConnectionRef;
41 extern CGError CGSNewConnection( void *, CGSConnectionRef * );
42 extern CGError CGSReleaseConnection( CGSConnectionRef );
43 extern CGError CGSGetGlobalCursorDataSize( CGSConnectionRef, int * );
44 extern CGError CGSGetGlobalCursorData( CGSConnectionRef, unsigned char *,
45 int *, int *, CGRect *, CGPoint *,
46 int *, int *, int * );
47 extern CGError CGSGetCurrentCursorLocation( CGSConnectionRef, CGPoint * );
61 GLuint cursor_texture;
74 CGSConnectionRef connection;
77 int screen_InitCapture( demux_t *p_demux )
79 demux_sys_t *p_sys = p_demux->p_sys;
80 screen_data_t *p_data;
81 CGLPixelFormatAttribute attribs[4];
82 CGLPixelFormatObj pix;
86 p_sys->p_data = p_data =
87 ( screen_data_t * )malloc( sizeof( screen_data_t ) );
89 attribs[0] = kCGLPFAFullScreen;
90 attribs[1] = kCGLPFADisplayMask;
91 attribs[2] = CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() );
94 CGLChoosePixelFormat( attribs, &pix, &npix );
95 CGLCreateContext( pix, NULL, &( p_data->screen ) );
96 CGLDestroyPixelFormat( pix );
98 CGLSetCurrentContext( p_data->screen );
99 CGLSetFullScreen( p_data->screen );
101 glGetIntegerv( GL_VIEWPORT, viewport );
103 p_data->screen_width = viewport[2];
104 p_data->screen_height = viewport[3];
108 p_data->src_width = p_data->screen_width;
109 p_data->src_height = p_data->screen_height;
110 p_data->dest_width = p_data->src_width;
111 p_data->dest_height = p_data->src_height;
113 attribs [0] = kCGLPFAOffScreen;
114 attribs [1] = kCGLPFAColorSize;
118 CGLChoosePixelFormat( attribs, &pix, &npix );
119 CGLCreateContext( pix, NULL, &( p_data->scaled ) );
120 CGLDestroyPixelFormat( pix );
122 CGLSetCurrentContext( p_data->scaled );
123 p_data->scaled_image = ( char * )malloc( p_data->dest_width
124 * p_data->dest_height * 4 );
125 CGLSetOffScreen( p_data->scaled, p_data->dest_width, p_data->dest_height,
126 p_data->dest_width * 4, p_data->scaled_image );
128 es_format_Init( &p_sys->fmt, VIDEO_ES, VLC_FOURCC( 'R','V','3','2' ) );
130 p_sys->fmt.video.i_width = p_data->dest_width;
131 p_sys->fmt.video.i_visible_width = p_data->dest_width;
132 p_sys->fmt.video.i_height = p_data->dest_height;
133 p_sys->fmt.video.i_bits_per_pixel = 32;
135 glGenTextures( 1, &( p_data->texture ) );
136 glBindTexture( GL_TEXTURE_2D, p_data->texture );
138 p_data->texture_image
139 = ( char * )malloc( p_data->src_width * p_data->src_height * 4 );
141 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
142 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
143 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
144 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
146 glGenTextures( 1, &( p_data->cursor_texture ) );
147 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
149 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
150 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
151 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
152 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
154 CGSNewConnection( NULL, &( p_data->connection ) );
159 int screen_CloseCapture( demux_t *p_demux )
161 screen_data_t *p_data = ( screen_data_t * )p_demux->p_sys->p_data;
163 CGSReleaseConnection( p_data->connection );
165 CGLSetCurrentContext( NULL );
166 CGLClearDrawable( p_data->screen );
167 CGLDestroyContext( p_data->screen );
172 block_t *screen_Capture( demux_t *p_demux )
174 demux_sys_t *p_sys = p_demux->p_sys;
175 screen_data_t *p_data = ( screen_data_t * )p_sys->p_data;
179 i_size = p_sys->fmt.video.i_height * p_sys->fmt.video.i_width * 4;
181 if( !( p_block = block_New( p_demux, i_size ) ) )
183 msg_Warn( p_demux, "cannot get block" );
187 CGLSetCurrentContext( p_data->screen );
188 glReadPixels( p_data->left,
189 p_data->screen_height - p_data->top - p_data->src_height,
192 GL_RGBA, GL_UNSIGNED_BYTE,
193 p_data->texture_image );
195 CGLSetCurrentContext( p_data->scaled );
196 glEnable( GL_TEXTURE_2D );
197 glBindTexture( GL_TEXTURE_2D, p_data->texture );
198 glTexImage2D( GL_TEXTURE_2D, 0,
199 GL_RGBA8, p_data->src_width, p_data->src_height, 0,
200 GL_RGBA, GL_UNSIGNED_BYTE, p_data->texture_image );
202 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
203 glClear( GL_COLOR_BUFFER_BIT );
204 glColor3f( 1.0f, 1.0f, 1.0f );
205 glEnable( GL_TEXTURE_2D );
206 glBindTexture( GL_TEXTURE_2D, p_data->texture );
207 glBegin( GL_POLYGON );
208 glTexCoord2f( 0.0, 1.0 ); glVertex2f( -1.0, -1.0 );
209 glTexCoord2f( 1.0, 1.0 ); glVertex2f( 1.0, -1.0 );
210 glTexCoord2f( 1.0, 0.0 ); glVertex2f( 1.0, 1.0 );
211 glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, 1.0 );
213 glDisable( GL_TEXTURE_2D );
217 int tmp1, tmp2, tmp3, tmp4;
218 unsigned char *cursor_image;
225 if( CGSGetCurrentCursorLocation( p_data->connection, &cursor_pos )
227 && CGSGetGlobalCursorDataSize( p_data->connection, &size )
230 cursor_image = ( unsigned char* )malloc( size );
231 if( CGSGetGlobalCursorData( p_data->connection,
234 &cursor_rect, &cursor_hot,
235 &tmp2, &tmp3, &tmp4 )
238 glEnable( GL_TEXTURE_2D );
239 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
240 glTexImage2D( GL_TEXTURE_2D, 0,
242 ( int )( cursor_rect.size.width ),
243 ( int )( cursor_rect.size.height ), 0,
244 GL_RGBA, GL_UNSIGNED_BYTE,
245 ( char * )cursor_image );
247 cursor_rect.origin.x = cursor_pos.x - p_data->left - cursor_hot.x;
248 cursor_rect.origin.y = cursor_pos.y - p_data->top - cursor_hot.y;
251 = 2.0 * cursor_rect.origin.x / p_data->src_width - 1.0;
253 = 2.0 * cursor_rect.origin.y / p_data->src_height - 1.0;
254 cursor_rect.size.width
255 = 2.0 * cursor_rect.size.width / p_data->src_width;
256 cursor_rect.size.height
257 = 2.0 * cursor_rect.size.height / p_data->src_height;
259 glColor3f( 1.0f, 1.0f, 1.0f );
260 glEnable( GL_TEXTURE_2D );
261 glEnable( GL_BLEND );
262 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
263 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
264 glBegin( GL_POLYGON );
265 glTexCoord2f( 0.0, 0.0 ); glVertex2f( cursor_rect.origin.x,
266 cursor_rect.origin.y );
267 glTexCoord2f( 1.0, 0.0 ); glVertex2f( cursor_rect.origin.x
268 + cursor_rect.size.width,
269 cursor_rect.origin.y );
270 glTexCoord2f( 1.0, 1.0 ); glVertex2f( cursor_rect.origin.x
271 + cursor_rect.size.width,
273 + cursor_rect.size.height );
274 glTexCoord2f( 0.0, 1.0 ); glVertex2f( cursor_rect.origin.x,
276 + cursor_rect.size.height );
278 glDisable( GL_BLEND );
279 glDisable( GL_TEXTURE_2D );
281 free( cursor_image );
287 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,