FreeRDP
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 
28 dispatch_semaphore_t region_sem;
29 dispatch_semaphore_t data_sem;
30 dispatch_queue_t screen_update_q;
31 CGDisplayStreamRef stream;
32 
33 CGDisplayStreamUpdateRef lastUpdate = NULL;
34 
35 BYTE* localBuf = NULL;
36 
37 BOOL ready = FALSE;
38 
39 void (^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 
113 int 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 
136 int 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 
176 int 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 }
189 int 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 
203 int 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 
217 int 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 
244 int 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 
256 int 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