FreeRDP
Loading...
Searching...
No Matches
mf_mountain_lion.c
1
20#include <dispatch/dispatch.h>
21#include <CoreGraphics/CoreGraphics.h>
22#include <CoreVideo/CoreVideo.h>
23#include <IOKit/IOKitLib.h>
24#include <IOSurface/IOSurface.h>
25
26#include "mf_mountain_lion.h"
27
28dispatch_semaphore_t region_sem;
29dispatch_semaphore_t data_sem;
30dispatch_queue_t screen_update_q;
31CGDisplayStreamRef stream;
32
33CGDisplayStreamUpdateRef lastUpdate = NULL;
34
35BYTE* localBuf = NULL;
36
37BOOL ready = FALSE;
38
39void (^streamHandler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef,
40 CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status,
41 uint64_t displayTime, IOSurfaceRef frameSurface,
42 CGDisplayStreamUpdateRef updateRef) {
43 dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
44
45 // may need to move this down
46 if (ready == TRUE)
47 {
48
49 RFX_RECT rect;
50 unsigned long offset_beg;
51 unsigned long stride;
52
53 rect.x = 0;
54 rect.y = 0;
55 rect.width = 0;
56 rect.height = 0;
57 mf_mlion_peek_dirty_region(&rect);
58
59 // lock surface
60 IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
61 // get pointer
62 void* baseAddress = IOSurfaceGetBaseAddress(frameSurface);
63 // copy region
64
65 stride = IOSurfaceGetBytesPerRow(frameSurface);
66 // memcpy(localBuf, baseAddress + offset_beg, surflen);
67 for (int i = 0; i < rect.height; i++)
68 {
69 offset_beg = (stride * (rect.y + i) + (rect.x * 4));
70 memcpy(localBuf + offset_beg, baseAddress + offset_beg, rect.width * 4);
71 }
72
73 // unlock surface
74 IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
75
76 ready = FALSE;
77 dispatch_semaphore_signal(data_sem);
78 }
79
80 if (status != kCGDisplayStreamFrameStatusFrameComplete)
81 {
82 switch (status)
83 {
84 case kCGDisplayStreamFrameStatusFrameIdle:
85 break;
86
87 case kCGDisplayStreamFrameStatusStopped:
88 break;
89
90 case kCGDisplayStreamFrameStatusFrameBlank:
91 break;
92
93 default:
94 break;
95 }
96 }
97 else if (lastUpdate == NULL)
98 {
99 CFRetain(updateRef);
100 lastUpdate = updateRef;
101 }
102 else
103 {
104 CGDisplayStreamUpdateRef tmpRef;
105 tmpRef = lastUpdate;
106 lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
107 CFRelease(tmpRef);
108 }
109
110 dispatch_semaphore_signal(region_sem);
111};
112
113int mf_mlion_display_info(UINT32* disp_width, UINT32* disp_height, UINT32* scale)
114{
115 CGDirectDisplayID display_id;
116
117 display_id = CGMainDisplayID();
118
119 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
120
121 size_t pixelWidth = CGDisplayModeGetPixelWidth(mode);
122 // size_t pixelHeight = CGDisplayModeGetPixelHeight(mode);
123
124 size_t wide = CGDisplayPixelsWide(display_id);
125 size_t high = CGDisplayPixelsHigh(display_id);
126
127 CGDisplayModeRelease(mode);
128
129 *disp_width = wide; // pixelWidth;
130 *disp_height = high; // pixelHeight;
131 *scale = pixelWidth / wide;
132
133 return 0;
134}
135
136int mf_mlion_screen_updates_init()
137{
138 CGDirectDisplayID display_id;
139
140 display_id = CGMainDisplayID();
141
142 screen_update_q = dispatch_queue_create("mfreerdp.server.screenUpdate", NULL);
143
144 region_sem = dispatch_semaphore_create(1);
145 data_sem = dispatch_semaphore_create(1);
146
147 UINT32 pixelWidth;
148 UINT32 pixelHeight;
149 UINT32 scale;
150
151 mf_mlion_display_info(&pixelWidth, &pixelHeight, &scale);
152
153 localBuf = malloc(pixelWidth * pixelHeight * 4);
154 if (!localBuf)
155 return -1;
156
157 CFDictionaryRef opts;
158
159 void* keys[2];
160 void* values[2];
161
162 keys[0] = (void*)kCGDisplayStreamShowCursor;
163 values[0] = (void*)kCFBooleanFalse;
164
165 opts = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1,
166 NULL, NULL);
167
168 stream = CGDisplayStreamCreateWithDispatchQueue(display_id, pixelWidth, pixelHeight, 'BGRA',
169 opts, screen_update_q, streamHandler);
170
171 CFRelease(opts);
172
173 return 0;
174}
175
176int mf_mlion_start_getting_screen_updates()
177{
178 CGError err;
179
180 err = CGDisplayStreamStart(stream);
181
182 if (err != kCGErrorSuccess)
183 {
184 return 1;
185 }
186
187 return 0;
188}
189int mf_mlion_stop_getting_screen_updates()
190{
191 CGError err;
192
193 err = CGDisplayStreamStop(stream);
194
195 if (err != kCGErrorSuccess)
196 {
197 return 1;
198 }
199
200 return 0;
201}
202
203int mf_mlion_get_dirty_region(RFX_RECT* invalid)
204{
205 dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
206
207 if (lastUpdate != NULL)
208 {
209 mf_mlion_peek_dirty_region(invalid);
210 }
211
212 dispatch_semaphore_signal(region_sem);
213
214 return 0;
215}
216
217int mf_mlion_peek_dirty_region(RFX_RECT* invalid)
218{
219 size_t num_rects;
220 CGRect dirtyRegion;
221
222 const CGRect* rects =
223 CGDisplayStreamUpdateGetRects(lastUpdate, kCGDisplayStreamUpdateDirtyRects, &num_rects);
224
225 if (num_rects == 0)
226 {
227 return 0;
228 }
229
230 dirtyRegion = *rects;
231 for (size_t i = 0; i < num_rects; i++)
232 {
233 dirtyRegion = CGRectUnion(dirtyRegion, *(rects + i));
234 }
235
236 invalid->x = dirtyRegion.origin.x;
237 invalid->y = dirtyRegion.origin.y;
238 invalid->height = dirtyRegion.size.height;
239 invalid->width = dirtyRegion.size.width;
240
241 return 0;
242}
243
244int mf_mlion_clear_dirty_region()
245{
246 dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
247
248 CFRelease(lastUpdate);
249 lastUpdate = NULL;
250
251 dispatch_semaphore_signal(region_sem);
252
253 return 0;
254}
255
256int mf_mlion_get_pixelData(long x, long y, long width, long height, BYTE** pxData)
257{
258 dispatch_semaphore_wait(region_sem, DISPATCH_TIME_FOREVER);
259 ready = TRUE;
260 dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
261 dispatch_semaphore_signal(region_sem);
262
263 // this second wait allows us to block until data is copied... more on this later
264 dispatch_semaphore_wait(data_sem, DISPATCH_TIME_FOREVER);
265 *pxData = localBuf;
266 dispatch_semaphore_signal(data_sem);
267
268 return 0;
269}
Definition rfx.h:44