1 /*****************************************************************************
2 * mac.c: Screen capture module for the Mac.
3 *****************************************************************************
4 * Copyright (C) 2004 - 2013 VLC authors and VideoLAN
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 /*****************************************************************************
29 *****************************************************************************/
35 #import <vlc_common.h>
40 #import <ApplicationServices/ApplicationServices.h>
41 #import <QuartzCore/QuartzCore.h>
43 extern int CGSMainConnectionID();
44 extern CGImageRef
CGSCreateRegisteredCursorImage(int, char*, CGPoint
*);
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
));
76 /* fetch the screen we should capture */
77 p_data
->display_id
= kCGDirectMainDisplay
;
79 unsigned int displayCount
= 0;
80 returnedError
= CGGetOnlineDisplayList(0, NULL
, &displayCount
);
82 CGDirectDisplayID
*ids
;
83 ids
= (CGDirectDisplayID
*)malloc(displayCount
* sizeof(CGDirectDisplayID
));
84 returnedError
= CGGetOnlineDisplayList(displayCount
, ids
, &displayCount
);
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
];
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];
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
;
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;
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
);
140 block_Release(p_data
->p_block
);
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
;
155 /* forward cursor location */
158 CGEventRef event
= CGEventCreate(NULL
);
159 cursor_pos
= CGEventGetLocation(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
);
176 msg_Warn(p_demux
, "no image!");
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");
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");
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();
210 cursor_image
= CGSCreateRegisteredCursorImage(cid
, (char *)"com.apple.coregraphics.GlobalCurrent", &outHotSpot
);
212 /* draw screen image and cursor image */
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
);
224 p_block
= block_Alloc(p_data
->offscreen_bitmap_size
);
226 msg_Warn(p_demux
, "can't get block");
231 memmove(p_block
->p_buffer
, p_data
->offscreen_bitmap
, p_data
->offscreen_bitmap_size
);