20 #include <freerdp/config.h>
22 #include <winpr/crt.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30 #include <X11/extensions/XShm.h>
32 #include <freerdp/log.h>
33 #include <freerdp/client/tsmf.h>
40 #include <X11/extensions/Xv.h>
41 #include <X11/extensions/Xvlib.h>
43 static long xv_port = 0;
48 Atom xv_colorkey_atom;
54 typedef struct xf_xv_context xfXvContext;
56 #define TAG CLIENT_TAG("x11")
58 static BOOL xf_tsmf_is_format_supported(xfXvContext* xv, UINT32 pixfmt)
63 for (
int i = 0; xv->xv_pixfmts[i]; i++)
65 if (xv->xv_pixfmts[i] == pixfmt)
82 XvImage* image = NULL;
85 xfContext* xfc = NULL;
86 xfXvContext* xv = NULL;
87 XRectangle* xrects = NULL;
88 XShmSegmentInfo shminfo;
89 BOOL converti420yv12 = FALSE;
94 xfc = (xfContext*)tsmf->custom;
99 xv = (xfXvContext*)xfc->xv_context;
104 if (xv->xv_port == 0)
108 if (event->x < -2048 || event->y < -2048 || event->numVisibleRects == 0)
114 numRects =
event->numVisibleRects;
118 xrects = (XRectangle*)calloc(numRects,
sizeof(XRectangle));
123 for (
int i = 0; i < numRects; i++)
125 x =
event->x +
event->visibleRects[i].left;
126 y =
event->y +
event->visibleRects[i].top;
127 width =
event->visibleRects[i].right -
event->visibleRects[i].left;
128 height =
event->visibleRects[i].bottom -
event->visibleRects[i].top;
132 xrects[i].width = width;
133 xrects[i].height = height;
137 if (xv->xv_colorkey_atom != None)
139 XvGetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, &colorkey);
140 XSetFunction(xfc->display, xfc->gc, GXcopy);
141 XSetFillStyle(xfc->display, xfc->gc, FillSolid);
142 XSetForeground(xfc->display, xfc->gc, colorkey);
144 if (event->numVisibleRects < 1)
146 XSetClipMask(xfc->display, xfc->gc, None);
150 XFillRectangles(xfc->display, xfc->window->handle, xfc->gc, xrects, numRects);
155 XSetFunction(xfc->display, xfc->gc, GXcopy);
156 XSetFillStyle(xfc->display, xfc->gc, FillSolid);
158 if (event->numVisibleRects < 1)
160 XSetClipMask(xfc->display, xfc->gc, None);
164 XSetClipRectangles(xfc->display, xfc->gc, 0, 0, xrects, numRects, YXBanded);
168 pixfmt =
event->framePixFmt;
170 if (xf_tsmf_is_format_supported(xv, pixfmt))
174 else if (pixfmt == RDP_PIXFMT_I420 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_YV12))
176 xvpixfmt = RDP_PIXFMT_YV12;
177 converti420yv12 = TRUE;
179 else if (pixfmt == RDP_PIXFMT_YV12 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_I420))
181 xvpixfmt = RDP_PIXFMT_I420;
182 converti420yv12 = TRUE;
186 WLog_DBG(TAG,
"pixel format 0x%" PRIX32
" not supported by hardware.", pixfmt);
191 image = XvShmCreateImage(xfc->display, xv->xv_port, xvpixfmt, 0, event->frameWidth,
192 event->frameHeight, &shminfo);
194 if (xv->xv_image_size != image->data_size)
196 if (xv->xv_image_size > 0)
198 shmdt(xv->xv_shmaddr);
199 shmctl(xv->xv_shmid, IPC_RMID, NULL);
202 xv->xv_image_size = image->data_size;
203 xv->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
204 xv->xv_shmaddr = shmat(xv->xv_shmid, 0, 0);
207 shminfo.shmid = xv->xv_shmid;
208 shminfo.shmaddr = image->data = xv->xv_shmaddr;
209 shminfo.readOnly = FALSE;
211 if (!XShmAttach(xfc->display, &shminfo))
215 WLog_DBG(TAG,
"XShmAttach failed.");
223 case RDP_PIXFMT_I420:
224 case RDP_PIXFMT_YV12:
226 if (image->pitches[0] == event->frameWidth)
228 CopyMemory(image->data + image->offsets[0], event->frameData,
229 1ULL * event->frameWidth * event->frameHeight);
233 for (
int i = 0; i <
event->frameHeight; i++)
235 CopyMemory(image->data + 1ULL * image->offsets[0] +
236 1ULL * i * image->pitches[0],
237 event->frameData + 1ULL * i * event->frameWidth, event->frameWidth);
242 if (!converti420yv12)
244 data1 =
event->frameData + 1ULL *
event->frameWidth *
event->frameHeight;
245 data2 =
event->frameData + 1ULL *
event->frameWidth *
event->frameHeight +
246 1ULL *
event->frameWidth *
event->frameHeight / 4;
250 data2 =
event->frameData + 1ULL *
event->frameWidth *
event->frameHeight;
251 data1 =
event->frameData + 1ULL *
event->frameWidth *
event->frameHeight +
252 1ULL *
event->frameWidth *
event->frameHeight / 4;
253 image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420;
256 if (image->pitches[1] * 2 == event->frameWidth)
258 CopyMemory(image->data + image->offsets[1], data1,
259 event->frameWidth * event->frameHeight / 4);
260 CopyMemory(image->data + image->offsets[2], data2,
261 event->frameWidth * event->frameHeight / 4);
265 for (
int i = 0; i <
event->frameHeight / 2; i++)
267 CopyMemory(image->data + 1ULL * image->offsets[1] +
268 1ULL * i * image->pitches[1],
269 data1 + 1ULL * i * event->frameWidth / 2, event->frameWidth / 2);
270 CopyMemory(image->data + 1ULL * image->offsets[2] +
271 1ULL * i * image->pitches[2],
272 data2 + 1ULL * i * event->frameWidth / 2, event->frameWidth / 2);
278 if (image->data_size < 0)
285 const size_t size = ((UINT32)image->data_size <= event->frameSize)
286 ? (UINT32)image->data_size
288 CopyMemory(image->data, event->frameData, size);
293 XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc, image, 0, 0,
294 image->width, image->height, event->x, event->y, event->width, event->height,
297 if (xv->xv_colorkey_atom == None)
298 XSetClipMask(xfc->display, xfc->gc, None);
300 XSync(xfc->display, FALSE);
302 XShmDetach(xfc->display, &shminfo);
310 static int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf)
313 unsigned int version = 0;
314 unsigned int release = 0;
315 unsigned int event_base = 0;
316 unsigned int error_base = 0;
317 unsigned int request_base = 0;
318 unsigned int num_adaptors = 0;
319 xfXvContext* xv = NULL;
320 XvAdaptorInfo* ai = NULL;
321 XvAttribute* attr = NULL;
322 XvImageFormatValues* fo = NULL;
327 xv = (xfXvContext*)calloc(1,
sizeof(xfXvContext));
332 xfc->xv_context = xv;
334 xv->xv_colorkey_atom = None;
335 xv->xv_image_size = 0;
336 xv->xv_port = xv_port;
338 if (!XShmQueryExtension(xfc->display))
340 WLog_DBG(TAG,
"no xshm available.");
345 XvQueryExtension(xfc->display, &version, &release, &request_base, &event_base, &error_base);
349 WLog_DBG(TAG,
"XvQueryExtension failed %d.", ret);
353 WLog_DBG(TAG,
"version %u release %u", version, release);
355 ret = XvQueryAdaptors(xfc->display, DefaultRootWindow(xfc->display), &num_adaptors, &ai);
359 WLog_DBG(TAG,
"XvQueryAdaptors failed %d.", ret);
363 for (
unsigned int i = 0; i < num_adaptors; i++)
365 WLog_DBG(TAG,
"adapter port %lu-%lu (%s)", ai[i].base_id,
366 ai[i].base_id + ai[i].num_ports - 1, ai[i].name);
368 if (xv->xv_port == 0 && i == num_adaptors - 1)
369 xv->xv_port = ai[i].base_id;
372 if (num_adaptors > 0)
373 XvFreeAdaptorInfo(ai);
375 if (xv->xv_port == 0)
377 WLog_DBG(TAG,
"no adapter selected, video frames will not be processed.");
380 WLog_DBG(TAG,
"selected %ld", xv->xv_port);
382 attr = XvQueryPortAttributes(xfc->display, xv->xv_port, &ret);
385 for (; i < (
unsigned int)ret; i++)
387 if (strcmp(attr[i].name,
"XV_COLORKEY") == 0)
389 static wLog* log = NULL;
392 xv->xv_colorkey_atom = Logging_XInternAtom(log, xfc->display,
"XV_COLORKEY", FALSE);
393 XvSetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom,
394 attr[i].min_value + 1);
400 WLog_DBG(TAG,
"xf_tsmf_init: pixel format ");
402 fo = XvListImageFormats(xfc->display, xv->xv_port, &ret);
406 xv->xv_pixfmts = (UINT32*)calloc((ret + 1),
sizeof(UINT32));
409 for (; x < (size_t)ret; x++)
411 xv->xv_pixfmts[x] = fo[x].id;
412 WLog_DBG(TAG,
"%c%c%c%c ", ((
char*)(xv->xv_pixfmts + x))[0],
413 ((
char*)(xv->xv_pixfmts + x))[1], ((
char*)(xv->xv_pixfmts + x))[2],
414 ((
char*)(xv->xv_pixfmts + x))[3]);
416 xv->xv_pixfmts[x] = 0;
423 tsmf->custom = (
void*)xfc;
425 tsmf->FrameEvent = xf_tsmf_xv_video_frame_event;
431 static int xf_tsmf_xv_uninit(xfContext* xfc, TsmfClientContext* tsmf)
433 xfXvContext* xv = (xfXvContext*)xfc->xv_context;
438 if (xv->xv_image_size > 0)
440 shmdt(xv->xv_shmaddr);
441 shmctl(xv->xv_shmid, IPC_RMID, NULL);
445 free(xv->xv_pixfmts);
446 xv->xv_pixfmts = NULL;
449 xfc->xv_context = NULL;
454 xfc->tsmf->custom = NULL;
463 int xf_tsmf_init(xfContext* xfc, TsmfClientContext* tsmf)
466 return xf_tsmf_xv_init(xfc, tsmf);
472 int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf)
475 return xf_tsmf_xv_uninit(xfc, tsmf);