A little more detail regarding using my github copies of the code with where it's...
[vlc/adversarial.git] / modules / access / screen / mac.c
blob698e3625b1097e6eaf40d7af32728bc2c1592580
1 /*****************************************************************************
2 * mac.c: Screen capture module for the Mac.
3 *****************************************************************************
4 * Copyright (C) 2004 - 2013 VLC authors and VideoLAN
5 * $Id$
7 * Authors: FUJISAWA Tooru <arai_a@mac.com>
8 * Derk-Jan Hartman <hartman at videolan dot org>
9 * Pierre d'Herbemont <pdherbemont # videolan org>
10 * Felix Paul Kühne <fkuehne # videolan org>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
35 #import <vlc_common.h>
36 #import <vlc_block.h>
38 #import "screen.h"
40 #import <ApplicationServices/ApplicationServices.h>
41 #import <QuartzCore/QuartzCore.h>
43 extern int CGSMainConnectionID();
44 extern CGImageRef CGSCreateRegisteredCursorImage(int, char*, CGPoint*);
46 struct screen_data_t
48 block_t *p_block;
50 int width;
51 int height;
53 int screen_top;
54 int screen_left;
55 int screen_width;
56 int screen_height;
58 CGDirectDisplayID display_id;
60 CGContextRef offscreen_context;
61 CGRect offscreen_rect;
62 void *offscreen_bitmap;
63 size_t offscreen_bitmap_size;
66 int screen_InitCapture(demux_t *p_demux)
68 demux_sys_t *p_sys = p_demux->p_sys;
69 screen_data_t *p_data;
70 CGLError returnedError;
72 p_sys->p_data = p_data = calloc(1, sizeof(screen_data_t));
73 if (!p_data)
74 return VLC_ENOMEM;
76 /* fetch the screen we should capture */
77 p_data->display_id = kCGDirectMainDisplay;
79 unsigned int displayCount = 0;
80 returnedError = CGGetOnlineDisplayList(0, NULL, &displayCount);
81 if (!returnedError) {
82 CGDirectDisplayID *ids;
83 ids = (CGDirectDisplayID *)malloc(displayCount * sizeof(CGDirectDisplayID));
84 returnedError = CGGetOnlineDisplayList(displayCount, ids, &displayCount);
85 if (!returnedError) {
86 if (p_sys->i_display_id > 0) {
87 for (unsigned int i = 0; i < displayCount; i++) {
88 if (p_sys->i_display_id == ids[i]) {
89 p_data->display_id = ids[i];
90 break;
93 } else if (p_sys->i_screen_index > 0 && p_sys->i_screen_index <= displayCount)
94 p_data->display_id = ids[p_sys->i_screen_index - 1];
96 free(ids);
99 /* Get the device context for the whole screen */
100 CGRect rect = CGDisplayBounds(p_data->display_id);
101 p_data->screen_left = rect.origin.x;
102 p_data->screen_top = rect.origin.y;
103 p_data->screen_width = rect.size.width;
104 p_data->screen_height = rect.size.height;
106 p_data->width = p_sys->i_width;
107 p_data->height = p_sys->i_height;
108 if (p_data->width <= 0 || p_data->height <= 0) {
109 p_data->width = p_data->screen_width;
110 p_data->height = p_data->screen_height;
113 /* setup format */
114 es_format_Init(&p_sys->fmt, VIDEO_ES, VLC_CODEC_RGB32);
115 p_sys->fmt.video.i_visible_width =
116 p_sys->fmt.video.i_width = rect.size.width;
117 p_sys->fmt.video.i_visible_height =
118 p_sys->fmt.video.i_height = rect.size.height;
119 p_sys->fmt.video.i_bits_per_pixel = 32;
120 p_sys->fmt.video.i_chroma = VLC_CODEC_RGB32;
121 p_sys->fmt.video.i_rmask = 0x00ff0000;
122 p_sys->fmt.video.i_gmask = 0x0000ff00;
123 p_sys->fmt.video.i_bmask = 0x000000ff;
125 return VLC_SUCCESS;
128 int screen_CloseCapture(demux_t *p_demux)
130 demux_sys_t *p_sys = p_demux->p_sys;
131 screen_data_t *p_data = p_sys->p_data;
133 if (p_data->offscreen_context)
134 CFRelease(p_data->offscreen_context);
136 if (p_data->offscreen_bitmap)
137 free(p_data->offscreen_bitmap);
139 if (p_data->p_block)
140 block_Release(p_data->p_block);
142 free(p_data);
144 return VLC_SUCCESS;
147 block_t *screen_Capture(demux_t *p_demux)
149 demux_sys_t *p_sys = p_demux->p_sys;
150 screen_data_t *p_data = (screen_data_t *)p_sys->p_data;
151 block_t *p_block;
152 CGRect capture_rect;
153 CGImageRef image;
155 /* forward cursor location */
156 CGPoint cursor_pos;
158 CGEventRef event = CGEventCreate(NULL);
159 cursor_pos = CGEventGetLocation(event);
160 CFRelease(event);
162 cursor_pos.x -= p_data->screen_left;
163 cursor_pos.y -= p_data->screen_top;
165 if (p_sys->b_follow_mouse)
166 FollowMouse(p_sys, cursor_pos.x, cursor_pos.y);
168 capture_rect.origin.x = p_sys->i_left;
169 capture_rect.origin.y = p_sys->i_top;
170 capture_rect.size.width = p_data->width;
171 capture_rect.size.height = p_data->height;
173 /* fetch image data */
174 image = CGDisplayCreateImageForRect(p_data->display_id, capture_rect);
175 if (!image) {
176 msg_Warn(p_demux, "no image!");
177 return NULL;
180 /* create offscreen context */
181 if (!p_data->offscreen_context) {
182 CGColorSpaceRef colorspace;
184 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
186 p_data->offscreen_bitmap_size = p_sys->fmt.video.i_width * p_sys->fmt.video.i_height * 4;
187 p_data->offscreen_bitmap = calloc(1, p_data->offscreen_bitmap_size);
188 if (p_data->offscreen_bitmap == NULL) {
189 msg_Warn(p_demux, "can't allocate offscreen bitmap");
190 CFRelease(image);
191 return NULL;
194 p_data->offscreen_context = CGBitmapContextCreate(p_data->offscreen_bitmap, p_sys->fmt.video.i_width, p_sys->fmt.video.i_height, 8, p_sys->fmt.video.i_width * 4, colorspace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
195 if (!p_data->offscreen_context) {
196 msg_Warn(p_demux, "can't create offscreen bitmap context");
197 CFRelease(image);
198 return NULL;
201 CGColorSpaceRelease(colorspace);
203 p_data->offscreen_rect = CGRectMake(0, 0, p_sys->fmt.video.i_width, p_sys->fmt.video.i_height);
206 /* fetch cursor image */
207 CGImageRef cursor_image;
208 int cid = CGSMainConnectionID();
209 CGPoint outHotSpot;
210 cursor_image = CGSCreateRegisteredCursorImage(cid, (char *)"com.apple.coregraphics.GlobalCurrent", &outHotSpot);
212 /* draw screen image and cursor image */
213 CGRect cursor_rect;
214 cursor_rect.size.width = CGImageGetWidth(cursor_image);
215 cursor_rect.size.height = CGImageGetHeight(cursor_image);
216 cursor_rect.origin.x = cursor_pos.x - p_sys->i_left - outHotSpot.x;
217 cursor_rect.origin.y = p_data->offscreen_rect.size.height
218 - (cursor_pos.y + cursor_rect.size.height - p_sys->i_top - outHotSpot.y);
220 CGContextDrawImage(p_data->offscreen_context, p_data->offscreen_rect, image);
221 CGContextDrawImage(p_data->offscreen_context, cursor_rect, cursor_image);
223 /* build block */
224 p_block = block_Alloc(p_data->offscreen_bitmap_size);
225 if (!p_block) {
226 msg_Warn(p_demux, "can't get block");
227 CFRelease(image);
228 return NULL;
231 memmove(p_block->p_buffer, p_data->offscreen_bitmap, p_data->offscreen_bitmap_size);
233 CFRelease(image);
235 return p_block;