]> git.sesse.net Git - vlc/blob - modules/access/screen/mac.c
Update LGPL license blurb, choosing v2.1+.
[vlc] / modules / access / screen / mac.c
1 /*****************************************************************************
2  * mac.c: Screen capture module for the Mac.
3  *****************************************************************************
4  * Copyright (C) 2004, 2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *          arai <arai_a@mac.com>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # import "config.h"
31 #endif
32
33 #import <vlc_common.h>
34
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>
40
41 #import <OpenGL/OpenGL.h>
42 #import <OpenGL/gl.h>
43 #import <stdlib.h>
44
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 * );
53
54 #import "screen.h"
55
56 struct screen_data_t
57 {
58   CGLContextObj screen;
59   
60   CGLContextObj scaled;
61   char *scaled_image;
62   
63   GLuint texture;
64   char *texture_image;
65   
66   GLuint cursor_texture;
67   
68   int left;
69   int top;
70   int src_width;
71   int src_height;
72   
73   int dest_width;
74   int dest_height;
75   
76   int screen_width;
77   int screen_height;
78   
79   CGSConnectionRef connection;
80 };
81
82 int screen_InitCapture( demux_t *p_demux )
83 {
84     demux_sys_t   *p_sys = p_demux->p_sys;
85     screen_data_t *p_data;
86     CGLPixelFormatAttribute attribs[4];
87     CGLPixelFormatObj pix;
88     GLint npix;
89     GLint viewport[4];
90     
91     p_sys->p_data = p_data =
92         ( screen_data_t * )malloc( sizeof( screen_data_t ) );
93     
94     attribs[0] = kCGLPFAFullScreen;
95     attribs[1] = kCGLPFADisplayMask;
96     attribs[2] = CGDisplayIDToOpenGLDisplayMask( CGMainDisplayID() );
97     attribs[3] = 0;
98     
99     CGLChoosePixelFormat( attribs, &pix, &npix );
100     CGLCreateContext( pix, NULL, &( p_data->screen ) );
101     CGLDestroyPixelFormat( pix );
102
103     CGLSetCurrentContext( p_data->screen );
104     CGLSetFullScreen( p_data->screen );
105     
106     glGetIntegerv( GL_VIEWPORT, viewport );
107     
108     p_data->screen_width = viewport[2];
109     p_data->screen_height = viewport[3];
110     
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;
118     }
119     p_data->dest_width = p_data->src_width;
120     p_data->dest_height = p_data->src_height;
121     
122     attribs [0] = kCGLPFAOffScreen;
123     attribs [1] = kCGLPFAColorSize;
124     attribs [2] = 32;
125     attribs [3] = 0;
126     
127     CGLChoosePixelFormat( attribs, &pix, &npix );
128     CGLCreateContext( pix, NULL, &( p_data->scaled ) );
129     CGLDestroyPixelFormat( pix );
130
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 );
136     
137     es_format_Init( &p_sys->fmt, VIDEO_ES, VLC_CODEC_RGB32 );
138     
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;
144     
145     glGenTextures( 1, &( p_data->texture ) );
146     glBindTexture( GL_TEXTURE_2D, p_data->texture );
147     
148     p_data->texture_image
149       = ( char * )malloc( p_data->src_width * p_data->src_height * 4 );
150     
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 );
155
156     glGenTextures( 1, &( p_data->cursor_texture ) );
157     glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
158     
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 );
163     
164     CGSNewConnection( NULL, &( p_data->connection ) );
165     
166     return VLC_SUCCESS;
167 }
168
169 int screen_CloseCapture( demux_t *p_demux )
170 {
171     screen_data_t *p_data = ( screen_data_t * )p_demux->p_sys->p_data;
172     
173     CGSReleaseConnection( p_data->connection );
174     
175     CGLSetCurrentContext( NULL );
176     CGLClearDrawable( p_data->screen );
177     CGLDestroyContext( p_data->screen );
178     
179     return VLC_SUCCESS;
180 }
181
182 block_t *screen_Capture( demux_t *p_demux )
183 {
184     demux_sys_t *p_sys = p_demux->p_sys;
185     screen_data_t *p_data = ( screen_data_t * )p_sys->p_data;
186     block_t *p_block;
187     int i_size;
188     
189     i_size = p_sys->fmt.video.i_height * p_sys->fmt.video.i_width * 4; 
190     
191     if( !( p_block = block_New( p_demux, i_size ) ) )
192     {
193         msg_Warn( p_demux, "cannot get block" );
194         return NULL;
195     }
196     
197     CGPoint cursor_pos;
198     CGError cursor_result;
199     
200     cursor_pos.x = 0;
201     cursor_pos.y = 0;
202     
203     cursor_result
204       = CGSGetCurrentCursorLocation( p_data->connection, &cursor_pos );
205     
206     if( p_sys->b_follow_mouse
207         && cursor_result == kCGErrorSuccess )
208     {
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;
212     }
213     
214     CGLSetCurrentContext( p_data->screen );
215     glReadPixels( p_data->left,
216                   p_data->screen_height - p_data->top - p_data->src_height,
217                   p_data->src_width,
218                   p_data->src_height,
219                   GL_RGBA, GL_UNSIGNED_BYTE,
220                   p_data->texture_image );
221     
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 );
228     
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 );
239     glEnd();
240     glDisable( GL_TEXTURE_2D );
241     
242     int size;
243     int tmp1, tmp2, tmp3, tmp4;
244     unsigned char *cursor_image;
245     CGRect cursor_rect;
246     CGPoint cursor_hot;
247     
248     if( cursor_result == kCGErrorSuccess
249         && CGSGetGlobalCursorDataSize( p_data->connection, &size )
250         == kCGErrorSuccess )
251     {
252         cursor_image = ( unsigned char* )malloc( size );
253         if( CGSGetGlobalCursorData( p_data->connection,
254                                     cursor_image, &size,
255                                     &tmp1,
256                                     &cursor_rect, &cursor_hot,
257                                     &tmp2, &tmp3, &tmp4 )
258             == kCGErrorSuccess )
259         {
260             glEnable( GL_TEXTURE_2D );
261             glBindTexture( GL_TEXTURE_2D, p_data->cursor_texture );
262             glTexImage2D( GL_TEXTURE_2D, 0,
263                           GL_RGBA8,
264                           ( int )( cursor_rect.size.width ),
265                           ( int )( cursor_rect.size.height ), 0,
266                           GL_RGBA, GL_UNSIGNED_BYTE,
267                           ( char * )cursor_image );
268             
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;
271             
272             cursor_rect.origin.x
273               = 2.0 * cursor_rect.origin.x / p_data->src_width - 1.0;
274             cursor_rect.origin.y
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;
280             
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,
294                                                   cursor_rect.origin.y
295                                                   + cursor_rect.size.height );
296             glTexCoord2f( 0.0, 1.0 ); glVertex2f( cursor_rect.origin.x,
297                                                   cursor_rect.origin.y
298                                                   + cursor_rect.size.height );
299             glEnd();
300             glDisable( GL_BLEND );
301             glDisable( GL_TEXTURE_2D );
302         }
303         free( cursor_image );
304     }
305     
306     glReadPixels( 0, 0, 
307                   p_data->dest_width,
308                   p_data->dest_height,
309                   GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
310                   p_block->p_buffer );
311     
312     return p_block;
313 }