1 /*****************************************************************************
2 * mac.c: Screen capture module for the Mac.
3 *****************************************************************************
4 * Copyright (C) 2004 the VideoLAN team
7 * Authors: Derk-Jan Hartman <hartman at videolan dot org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
30 #include <vlc/input.h>
32 #import <OpenGL/OpenGL.h>
34 #include <ApplicationServices/ApplicationServices.h>
36 typedef int CGSConnectionRef;
37 extern CGError CGSNewConnection( void *, CGSConnectionRef * );
38 extern CGError CGSReleaseConnection( CGSConnectionRef );
39 extern CGError CGSGetGlobalCursorDataSize( CGSConnectionRef, int * );
40 extern CGError CGSGetGlobalCursorData( CGSConnectionRef, unsigned char *,
41 int *, int *, CGRect *, CGPoint *,
42 int *, int *, int * );
43 extern CGError CGSGetCurrentCursorLocation( CGSConnectionRef, CGPoint * );
57 GLuint cursor_texture;
70 CGSConnectionRef connection;
73 int screen_InitCapture( demux_t *p_demux )
75 demux_sys_t *p_sys = p_demux->p_sys;
76 screen_data_t *p_data;
77 CGLPixelFormatAttribute attribs[4];
78 CGLPixelFormatObj pix;
82 p_sys->p_data = p_data =
83 ( screen_data_t * )malloc( sizeof( screen_data_t ) );
85 attribs[0] = kCGLPFAFullScreen;
86 attribs[1] = kCGLPFADisplayMask;
87 attribs[2] = CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() );
90 CGLChoosePixelFormat( attribs, &pix, &npix );
91 CGLCreateContext( pix, NULL, &( p_data->screen ) );
92 CGLDestroyPixelFormat( pix );
94 CGLSetCurrentContext( p_data->screen );
95 CGLSetFullScreen( p_data->screen );
97 glGetIntegerv( GL_VIEWPORT, viewport );
99 p_data->screen_width = viewport[2];
100 p_data->screen_height = viewport[3];
104 p_data->src_width = p_data->screen_width;
105 p_data->src_height = p_data->screen_height;
106 p_data->dest_width = p_data->src_width;
107 p_data->dest_height = p_data->src_height;
109 attribs [0] = kCGLPFAOffScreen;
110 attribs [1] = kCGLPFAColorSize;
114 CGLChoosePixelFormat( attribs, &pix, &npix );
115 CGLCreateContext( pix, NULL, &( p_data->scaled ) );
116 CGLDestroyPixelFormat( pix );
118 CGLSetCurrentContext( p_data->scaled );
119 p_data->scaled_image = ( char * )malloc( p_data->dest_width
120 * p_data->dest_height * 4 );
121 CGLSetOffScreen( p_data->scaled, p_data->dest_width, p_data->dest_height,
122 p_data->dest_width * 4, p_data->scaled_image );
124 es_format_Init( &p_sys->fmt, VIDEO_ES, VLC_FOURCC( 'R','V','3','2' ) );
126 p_sys->fmt.video.i_width = p_data->dest_width;
127 p_sys->fmt.video.i_visible_width = p_data->dest_width;
128 p_sys->fmt.video.i_height = p_data->dest_height;
129 p_sys->fmt.video.i_bits_per_pixel = 32;
131 glGenTextures( 1, &( p_data->texture ) );
132 glBindTexture( GL_TEXTURE_2D, p_data->texture );
134 p_data->texture_image
135 = ( char * )malloc( p_data->src_width * p_data->src_height * 4 );
137 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
138 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
139 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
140 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
142 glGenTextures( 1, &( p_data->cursor_texture ) );
143 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
145 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
146 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
147 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
148 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
150 CGSNewConnection( NULL, &( p_data->connection ) );
155 int screen_CloseCapture( demux_t *p_demux )
157 screen_data_t *p_data = ( screen_data_t * )p_demux->p_sys->p_data;
159 CGSReleaseConnection( p_data->connection );
161 CGLSetCurrentContext( NULL );
162 CGLClearDrawable( p_data->screen );
163 CGLDestroyContext( p_data->screen );
168 block_t *screen_Capture( demux_t *p_demux )
170 demux_sys_t *p_sys = p_demux->p_sys;
171 screen_data_t *p_data = ( screen_data_t * )p_sys->p_data;
175 i_size = p_sys->fmt.video.i_height * p_sys->fmt.video.i_width * 4;
177 if( !( p_block = block_New( p_demux, i_size ) ) )
179 msg_Warn( p_demux, "cannot get block" );
183 CGLSetCurrentContext( p_data->screen );
184 glReadPixels( p_data->left,
185 p_data->screen_height - p_data->top - p_data->src_height,
188 GL_RGBA, GL_UNSIGNED_BYTE,
189 p_data->texture_image );
191 CGLSetCurrentContext( p_data->scaled );
192 glEnable( GL_TEXTURE_2D );
193 glBindTexture( GL_TEXTURE_2D, p_data->texture );
194 glTexImage2D( GL_TEXTURE_2D, 0,
195 GL_RGBA8, p_data->src_width, p_data->src_height, 0,
196 GL_RGBA, GL_UNSIGNED_BYTE, p_data->texture_image );
198 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
199 glClear( GL_COLOR_BUFFER_BIT );
200 glColor3f( 1.0f, 1.0f, 1.0f );
201 glEnable( GL_TEXTURE_2D );
202 glBindTexture( GL_TEXTURE_2D, p_data->texture );
203 glBegin( GL_POLYGON );
204 glTexCoord2f( 0.0, 1.0 ); glVertex2f( -1.0, -1.0 );
205 glTexCoord2f( 1.0, 1.0 ); glVertex2f( 1.0, -1.0 );
206 glTexCoord2f( 1.0, 0.0 ); glVertex2f( 1.0, 1.0 );
207 glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, 1.0 );
209 glDisable( GL_TEXTURE_2D );
213 int tmp1, tmp2, tmp3, tmp4;
214 unsigned char *cursor_image;
221 if( CGSGetCurrentCursorLocation( p_data->connection, &cursor_pos )
223 && CGSGetGlobalCursorDataSize( p_data->connection, &size )
226 cursor_image = ( unsigned char* )malloc( size );
227 if( CGSGetGlobalCursorData( p_data->connection,
230 &cursor_rect, &cursor_hot,
231 &tmp2, &tmp3, &tmp4 )
234 glEnable( GL_TEXTURE_2D );
235 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
236 glTexImage2D( GL_TEXTURE_2D, 0,
238 ( int )( cursor_rect.size.width ),
239 ( int )( cursor_rect.size.height ), 0,
240 GL_RGBA, GL_UNSIGNED_BYTE,
241 ( char * )cursor_image );
243 cursor_rect.origin.x = cursor_pos.x - p_data->left - cursor_hot.x;
244 cursor_rect.origin.y = cursor_pos.y - p_data->top - cursor_hot.y;
247 = 2.0 * cursor_rect.origin.x / p_data->src_width - 1.0;
249 = 2.0 * cursor_rect.origin.y / p_data->src_height - 1.0;
250 cursor_rect.size.width
251 = 2.0 * cursor_rect.size.width / p_data->src_width;
252 cursor_rect.size.height
253 = 2.0 * cursor_rect.size.height / p_data->src_height;
255 glColor3f( 1.0f, 1.0f, 1.0f );
256 glEnable( GL_TEXTURE_2D );
257 glEnable( GL_BLEND );
258 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
259 glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
260 glBegin( GL_POLYGON );
261 glTexCoord2f( 0.0, 0.0 ); glVertex2f( cursor_rect.origin.x,
262 cursor_rect.origin.y );
263 glTexCoord2f( 1.0, 0.0 ); glVertex2f( cursor_rect.origin.x
264 + cursor_rect.size.width,
265 cursor_rect.origin.y );
266 glTexCoord2f( 1.0, 1.0 ); glVertex2f( cursor_rect.origin.x
267 + cursor_rect.size.width,
269 + cursor_rect.size.height );
270 glTexCoord2f( 0.0, 1.0 ); glVertex2f( cursor_rect.origin.x,
272 + cursor_rect.size.height );
274 glDisable( GL_BLEND );
275 glDisable( GL_TEXTURE_2D );
277 free( cursor_image );
283 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,