def get_CG_imagewrapper(rect=None): from xpra.codecs.image_wrapper import ImageWrapper assert CG, "cannot capture without Quartz.CoreGraphics" if rect is None: x = 0 y = 0 region = CG.CGRectInfinite else: x, y, w, h = rect region = CG.CGRectMake(x, y, roundup(w, 2), roundup(h, 2)) image = CG.CGWindowListCreateImage( region, CG.kCGWindowListOptionOnScreenOnly, CG.kCGNullWindowID, CG.kCGWindowImageNominalResolution) #CG.kCGWindowImageDefault) width = CG.CGImageGetWidth(image) height = CG.CGImageGetHeight(image) bpc = CG.CGImageGetBitsPerComponent(image) bpp = CG.CGImageGetBitsPerPixel(image) rowstride = CG.CGImageGetBytesPerRow(image) alpha = CG.CGImageGetAlphaInfo(image) alpha_str = ALPHA.get(alpha, alpha) log( "get_CG_imagewrapper(..) image size: %sx%s, bpc=%s, bpp=%s, rowstride=%s, alpha=%s", width, height, bpc, bpp, rowstride, alpha_str) prov = CG.CGImageGetDataProvider(image) argb = CG.CGDataProviderCopyData(prov) return ImageWrapper(x, y, width, height, argb, "BGRX", 24, rowstride)
def make_test_image(pixel_format, w, h): from xpra.codecs.image_wrapper import ImageWrapper from xpra.codecs.codec_constants import get_subsampling_divs #import time #start = monotonic() if pixel_format.startswith("YUV") or pixel_format.startswith( "GBRP") or pixel_format == "NV12": divs = get_subsampling_divs(pixel_format) try: depth = int(pixel_format.split("P")[1]) #ie: YUV444P10 -> 10 except (IndexError, ValueError): depth = 8 Bpp = roundup(depth, 8) // 8 nplanes = len(divs) ydiv = divs[0] #always (1, 1) y = makebuf(w // ydiv[0] * h // ydiv[1] * Bpp) udiv = divs[1] u = makebuf(w // udiv[0] * h // udiv[1] * Bpp) planes = [y, u] strides = [w // ydiv[0] * Bpp, w // udiv[0] * Bpp] if nplanes == 3: vdiv = divs[2] v = makebuf(w // vdiv[0] * h // vdiv[1] * Bpp) planes.append(v) strides.append(w // vdiv[0] * Bpp) image = ImageWrapper(0, 0, w, h, planes, pixel_format, 32, strides, planes=nplanes, thread_safe=True) #l = len(y)+len(u)+len(v) elif pixel_format in ("RGB", "BGR", "RGBX", "BGRX", "XRGB", "BGRA", "RGBA", "r210", "BGR48"): if pixel_format == "BGR48": stride = w * 6 else: stride = w * len(pixel_format) rgb_data = makebuf(stride * h) image = ImageWrapper(0, 0, w, h, rgb_data, pixel_format, 32, stride, planes=ImageWrapper.PACKED, thread_safe=True) #l = len(rgb_data) else: raise Exception("don't know how to create a %s image" % pixel_format) #log("make_test_image%30s took %3ims for %6iMBytes", # (pixel_format, w, h), 1000*(monotonic()-start), l//1024//1024) return image
def init_client_mmap(mmap_group=None, socket_filename=None, size=128 * 1024 * 1024, filename=None): """ Initializes an mmap area, writes the token in it and returns: (success flag, mmap_area, mmap_size, temp_file, mmap_filename) The caller must keep hold of temp_file to ensure it does not get deleted! This is used by the client. """ def rerr(): return False, False, None, 0, None, None log("init_mmap%s", (mmap_group, socket_filename, size, filename)) mmap_filename = filename mmap_temp_file = None delete = True def validate_size(size): assert size >= 64 * 1024 * 1024, "mmap size is too small: %sB (minimum is 64MB)" % std_unit( size) assert size <= 4 * 1024 * 1024 * 1024, "mmap is too big: %sB (maximum is 4GB)" % std_unit( size) try: import mmap unit = max(4096, mmap.PAGESIZE) #add 8 bytes for the mmap area control header zone: mmap_size = roundup(size + 8, unit) if WIN32: validate_size(mmap_size) if not filename: from xpra.net.crypto import get_hex_uuid filename = "xpra-%s" % get_hex_uuid() mmap_filename = filename mmap_area = mmap.mmap(0, mmap_size, filename) #not a real file: delete = False mmap_temp_file = None else: assert POSIX if filename: if os.path.exists(filename): fd = os.open(filename, os.O_EXCL | os.O_RDWR) mmap_size = os.path.getsize(mmap_filename) validate_size(mmap_size) #mmap_size = 4*1024*1024 #size restriction needed with ivshmem delete = False log.info("Using existing mmap file '%s': %sMB", mmap_filename, mmap_size // 1024 // 1024) else: validate_size(mmap_size) import errno flags = os.O_CREAT | os.O_EXCL | os.O_RDWR try: fd = os.open(filename, flags) mmap_temp_file = None #os.fdopen(fd, 'w') mmap_filename = filename except OSError as e: if e.errno == errno.EEXIST: log.error( "Error: the mmap file '%s' already exists", filename) return rerr() raise else: validate_size(mmap_size) import tempfile from xpra.platform.paths import get_mmap_dir mmap_dir = get_mmap_dir() subs = os.environ.copy() subs.update({ "UID": os.getuid(), "GID": os.getgid(), "PID": os.getpid(), }) mmap_dir = shellsub(mmap_dir, subs) if mmap_dir and not os.path.exists(mmap_dir): os.mkdir(mmap_dir, 0o700) if not mmap_dir or not os.path.exists(mmap_dir): raise Exception("mmap directory %s does not exist!" % mmap_dir) #create the mmap file, the mkstemp that is called via NamedTemporaryFile ensures #that the file is readable and writable only by the creating user ID try: temp = tempfile.NamedTemporaryFile(prefix="xpra.", suffix=".mmap", dir=mmap_dir) except OSError as e: log.error("Error: cannot create mmap file:") log.error(" %s", e) return rerr() #keep a reference to it so it does not disappear! mmap_temp_file = temp mmap_filename = temp.name fd = temp.file.fileno() #set the group permissions and gid if the mmap-group option is specified if mmap_group and type(socket_filename) == str and os.path.exists( socket_filename): from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP s = os.stat(socket_filename) os.fchown(fd, -1, s.st_gid) os.fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) log("using mmap file %s, fd=%s, size=%s", mmap_filename, fd, mmap_size) os.lseek(fd, mmap_size - 1, os.SEEK_SET) assert os.write(fd, b'\x00') os.lseek(fd, 0, os.SEEK_SET) mmap_area = mmap.mmap(fd, length=mmap_size) return True, delete, mmap_area, mmap_size, mmap_temp_file, mmap_filename except Exception as e: log("failed to setup mmap: %s", e, exc_info=True) log.error("Error: mmap setup failed:") log.error(" %s", e) clean_mmap(mmap_filename) return rerr()
def get_image(self, x=0, y=0, width=0, height=0): start = time.time() metrics = get_virtualscreenmetrics() if self.metrics is None or self.metrics != metrics: #new metrics, start from scratch: self.metrics = metrics self.clean() log("get_image%s metrics=%s", (x, y, width, height), metrics) dx, dy, dw, dh = metrics if width == 0: width = dw if height == 0: height = dh #clamp rectangle requested to the virtual desktop size: if x < dx: width -= x - dx x = dx if y < dy: height -= y - dy y = dy if width > dw: width = dw if height > dh: height = dh if not self.dc: self.wnd = GetDesktopWindow() self.dc = GetWindowDC(self.wnd) assert self.dc, "failed to get a drawing context from the desktop window %s" % self.wnd self.bit_depth = GetDeviceCaps(self.dc, win32con.BITSPIXEL) self.memdc = CreateCompatibleDC(self.dc) assert self.memdc, "failed to get a compatible drawing context from %s" % self.dc bitmap = CreateCompatibleBitmap(self.dc, width, height) assert bitmap, "failed to get a compatible bitmap from %s" % self.dc r = SelectObject(self.memdc, bitmap) if r == 0: log.error("Error: cannot select bitmap object") return None select_time = time.time() log("get_image up to SelectObject (%s) took %ims", REGION_CONSTS.get(r, r), (select_time - start) * 1000) try: if BitBlt(self.memdc, 0, 0, width, height, self.dc, x, y, win32con.SRCCOPY) == 0: e = ctypes.get_last_error() #rate limit the error message: now = time.time() if now - self.bitblt_err_time > 10: log.error("Error: failed to blit the screen, error %i", e) self.bitblt_err_time = now return None except Exception as e: log("BitBlt error", exc_info=True) log.error("Error: cannot capture screen") log.error(" %s", e) return None bitblt_time = time.time() log("get_image BitBlt took %ims", (bitblt_time - select_time) * 1000) rowstride = roundup(width * self.bit_depth // 8, 2) buf_size = rowstride * height pixels = ctypes.create_string_buffer(b"", buf_size) log("GetBitmapBits(%#x, %#x, %#x)", bitmap, buf_size, ctypes.addressof(pixels)) r = GetBitmapBits(bitmap, buf_size, ctypes.byref(pixels)) if r == 0: log.error("Error: failed to copy screen bitmap data") return None if r != buf_size: log.warn( "Warning: truncating pixel buffer, got %i bytes but expected %i", r, buf_size) pixels = pixels[:r] log("get_image GetBitmapBits took %ims", (time.time() - bitblt_time) * 1000) DeleteObject(bitmap) assert pixels, "no pixels returned from GetBitmapBits" if self.bit_depth == 32: rgb_format = "BGRX" elif self.bit_depth == 30: rgb_format = "r210" elif self.bit_depth == 24: rgb_format = "BGR" elif self.bit_depth == 16: rgb_format = "BGR565" elif self.bit_depth == 8: rgb_format = "RLE8" else: raise Exception("unsupported bit depth: %s" % self.bit_depth) bpp = self.bit_depth // 8 v = ImageWrapper(0, 0, width, height, pixels, rgb_format, self.bit_depth, rowstride, bpp, planes=ImageWrapper.PACKED, thread_safe=True) if self.bit_depth == 8: count = GetSystemPaletteEntries(self.dc, 0, 0, None) log("palette size: %s", count) palette = [] if count > 0: buf = (PALETTEENTRY * count)() r = GetSystemPaletteEntries(self.dc, 0, count, ctypes.byref(buf)) #we expect 16-bit values, so bit-shift them: for p in buf: palette.append( (p.peRed << 8, p.peGreen << 8, p.peBlue << 8)) v.set_palette(palette) log("get_image%s=%s took %ims", (x, y, width, height), v, (time.time() - start) * 1000) return v
def may_restride(self): newstride = roundup(self.width*self.bytesperpixel, 4) if self.rowstride>newstride: return self.restride(newstride) return False
check_devices() print("pycuda import") from pycuda import driver #@UnresolvedImport cuda_device = driver.Device(0) print("cuda_device=%s" % cuda_device) cuda_context = cuda_device.make_context(flags=driver.ctx_flags.SCHED_AUTO | driver.ctx_flags.MAP_HOST) try: print("cuda_context=%s" % cuda_context) BGRA2NV12 = get_CUDA_function(0, "BGRA_to_NV12") print("BGRA2NV12=%s" % BGRA2NV12) w = roundup(512, 32) h = roundup(512, 32) log("w=%s, h=%s", w, h) cudaInputBuffer, inputPitch = driver.mem_alloc_pitch(w, h * 3 / 2, 16) log("CUDA Input Buffer=%s, pitch=%s", hex(int(cudaInputBuffer)), inputPitch) #allocate CUDA NV12 buffer (on device): cudaNV12Buffer, NV12Pitch = driver.mem_alloc_pitch(w, h * 3 / 2, 16) log("CUDA NV12 Buffer=%s, pitch=%s", hex(int(cudaNV12Buffer)), NV12Pitch) #host buffers: inputBuffer = driver.pagelocked_zeros(inputPitch * h * 3 / 2, dtype=numpy.byte) log("inputBuffer=%s", inputBuffer)
def got_clipboard_lock(): if COMPRESSED_IMAGES: fmt_name = LPCSTR(img_format.upper().encode("latin1") + b"\0") #ie: "PNG" fmt = RegisterClipboardFormatA(fmt_name) if fmt: data_handle = GetClipboardData(fmt) if data_handle: size = GlobalSize(data_handle) data = GlobalLock(data_handle) log("GetClipboardData(%s)=%#x size=%s, data=%#x", img_format.upper(), data_handle, size, data) if data and size: try: cdata = (c_char * size).from_address(data) finally: GlobalUnlock(data) got_image(bytes(cdata), False) return True data_handle = GetClipboardData(win32con.CF_DIBV5) log("CF_BITMAP=%s", data_handle) data = GlobalLock(data_handle) if not data: log("failed to lock data handle %#x (may try again)", data_handle) return False try: header = cast(data, PBITMAPV5HEADER).contents offset = header.bV5Size + header.bV5ClrUsed * 4 w, h = header.bV5Width, abs(header.bV5Height) bits = header.bV5BitCount log( "offset=%s, width=%i, height=%i, compression=%s", offset, w, h, BI_FORMATS.get(header.bV5Compression, header.bV5Compression)) log("planes=%i, bitcount=%i", header.bV5Planes, bits) log("colorspace=%s", COLOR_PROFILES.get(header.bV5CSType, header.bV5CSType)) #if header.bV5Compression in (BI_JPEG, BI_PNG): # pass if header.bV5Compression != BI_RGB: errback( "cannot handle %s compression yet" % BI_FORMATS.get( header.bV5Compression, header.bV5Compression)) return True if bits == 24: save_format = "RGB" rgb_format = "BGR" stride = roundup(w * 3, 4) elif bits == 32: save_format = "RGBA" rgb_format = "BGRA" stride = w * 4 else: errback( "cannot handle image data with %i bits per pixel yet" % bits) return True img_size = stride * h rgb_data = (c_char * img_size).from_address(data + offset) from PIL import Image, ImageOps img = Image.frombytes(save_format, (w, h), rgb_data, "raw", rgb_format, stride, 1) if header.bV5Height > 0: img = ImageOps.flip(img) buf = BytesIO() img.save(buf, format=save_format) data = buf.getvalue() buf.close() got_image(data, True) return True finally: GlobalUnlock(data)
def init_client_mmap(mmap_group=None, socket_filename=None, size=128*1024*1024, filename=None): """ Initializes an mmap area, writes the token in it and returns: (success flag, mmap_area, mmap_size, temp_file, mmap_filename) The caller must keep hold of temp_file to ensure it does not get deleted! This is used by the client. """ def rerr(): return False, False, None, 0, None, None log("init_mmap%s", (mmap_group, socket_filename, size, filename)) mmap_filename = filename mmap_temp_file = None delete = True def validate_size(size : int): assert size>=64*1024*1024, "mmap size is too small: %sB (minimum is 64MB)" % std_unit(size) assert size<=4*1024*1024*1024, "mmap is too big: %sB (maximum is 4GB)" % std_unit(size) try: import mmap unit = max(4096, mmap.PAGESIZE) #add 8 bytes for the mmap area control header zone: mmap_size = roundup(size + 8, unit) if WIN32: validate_size(mmap_size) if not filename: from xpra.os_util import get_hex_uuid filename = "xpra-%s" % get_hex_uuid() mmap_filename = filename mmap_area = mmap.mmap(0, mmap_size, filename) #not a real file: delete = False else: assert POSIX if filename: if os.path.exists(filename): fd = os.open(filename, os.O_EXCL | os.O_RDWR) mmap_size = os.path.getsize(mmap_filename) validate_size(mmap_size) #mmap_size = 4*1024*1024 #size restriction needed with ivshmem delete = False log.info("Using existing mmap file '%s': %sMB", mmap_filename, mmap_size//1024//1024) else: validate_size(mmap_size) flags = os.O_CREAT | os.O_EXCL | os.O_RDWR try: fd = os.open(filename, flags) mmap_temp_file = None #os.fdopen(fd, 'w') mmap_filename = filename except FileExistsError: log.error("Error: the mmap file '%s' already exists", filename) return rerr() else: validate_size(mmap_size) import tempfile from xpra.platform.paths import get_mmap_dir mmap_dir = get_mmap_dir() subs = os.environ.copy() subs.update({ "UID" : os.getuid(), "GID" : os.getgid(), "PID" : os.getpid(), }) mmap_dir = shellsub(mmap_dir, subs) if mmap_dir and not os.path.exists(mmap_dir): os.mkdir(mmap_dir, 0o700) if not mmap_dir or not os.path.exists(mmap_dir): raise Exception("mmap directory %s does not exist!" % mmap_dir) #create the mmap file, the mkstemp that is called via NamedTemporaryFile ensures #that the file is readable and writable only by the creating user ID try: temp = tempfile.NamedTemporaryFile(prefix="xpra.", suffix=".mmap", dir=mmap_dir) except OSError as e: log.error("Error: cannot create mmap file:") log.error(" %s", e) return rerr() #keep a reference to it so it does not disappear! mmap_temp_file = temp mmap_filename = temp.name fd = temp.file.fileno() #set the group permissions and gid if the mmap-group option is specified mmap_group = (mmap_group or "") if POSIX and mmap_group and mmap_group not in FALSE_OPTIONS: group_id = None if mmap_group=="SOCKET": group_id = get_socket_group(socket_filename) elif mmap_group.lower()=="auto": group_id = xpra_group() if not group_id and socket_filename: group_id = get_socket_group(socket_filename) elif mmap_group.lower() in TRUE_OPTIONS: log.info("parsing legacy mmap-group value '%s' as 'auto'", mmap_group) log.info(" please update your configuration") group_id = xpra_group() or get_socket_group(socket_filename) else: group_id = get_group_id(mmap_group) if group_id>0: log("setting mmap file %s to group id=%i", mmap_filename, group_id) try: os.fchown(fd, -1, group_id) except OSError as e: log("fchown(%i, %i, %i) on %s", fd, -1, group_id, mmap_filename, exc_info=True) log.error("Error: failed to change group ownership of mmap file to '%s':", mmap_group) log.error(" %s", e) from stat import S_IRUSR,S_IWUSR,S_IRGRP,S_IWGRP os.fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) log("using mmap file %s, fd=%s, size=%s", mmap_filename, fd, mmap_size) os.lseek(fd, mmap_size-1, os.SEEK_SET) assert os.write(fd, b'\x00') os.lseek(fd, 0, os.SEEK_SET) mmap_area = mmap.mmap(fd, length=mmap_size) return True, delete, mmap_area, mmap_size, mmap_temp_file, mmap_filename except Exception as e: log("failed to setup mmap: %s", e, exc_info=True) log.error("Error: mmap setup failed:") log.error(" %s", e) if delete: if mmap_temp_file: try: mmap_temp_file.close() except OSError: log("%s()", mmap_temp_file.close, exc_info=True) log.error(" failed to remove the mmap temp file: %s", e) else: clean_mmap(mmap_filename) return rerr()
def get_image(self, x=0, y=0, width=0, height=0): start = time.time() x, y, width, height = self.get_capture_coords(x, y, width, height) if not self.dc: self.wnd = GetDesktopWindow() if not self.wnd: log.error("Error: cannot access the desktop window") log.error(" capturing the screen is not possible") return None self.dc = GetWindowDC(self.wnd) if not self.dc: log.error("Error: cannot get a drawing context") log.error(" capturing the screen is not possible") log.error(" desktop window=%#x", self.wnd) return None self.bit_depth = GetDeviceCaps(self.dc, win32con.BITSPIXEL) self.memdc = CreateCompatibleDC(self.dc) assert self.memdc, "failed to get a compatible drawing context from %s" % self.dc bitmap = CreateCompatibleBitmap(self.dc, width, height) if not bitmap: log.error("Error: failed to get a compatible bitmap") log.error(" from drawing context %#x with size %ix%i", self.dc, width, height) self.clean_dc() return None r = SelectObject(self.memdc, bitmap) if not r: log.error("Error: cannot select bitmap object") return None select_time = time.time() log("get_image up to SelectObject (%s) took %ims", REGION_CONSTS.get(r, r), (select_time - start) * 1000) try: if BitBlt(self.memdc, 0, 0, width, height, self.dc, x, y, win32con.SRCCOPY) == 0: e = ctypes.get_last_error() #rate limit the error message: now = time.time() if now - self.bitblt_err_time > 10: log.error("Error: failed to blit the screen, error %i", e) self.bitblt_err_time = now return None except Exception as e: log("BitBlt error", exc_info=True) log.error("Error: cannot capture screen with BitBlt") log.error(" %s", e) self.clean_dc() return None bitblt_time = time.time() log("get_image BitBlt took %ims", (bitblt_time - select_time) * 1000) rowstride = roundup(width * self.bit_depth // 8, 2) buf_size = rowstride * height pixels = ctypes.create_string_buffer(b"", buf_size) log("GetBitmapBits(%#x, %#x, %#x)", bitmap, buf_size, ctypes.addressof(pixels)) r = GetBitmapBits(bitmap, buf_size, ctypes.byref(pixels)) if not r: log.error("Error: failed to copy screen bitmap data") self.clean_dc() return None if r != buf_size: log.warn( "Warning: truncating pixel buffer, got %i bytes but expected %i", r, buf_size) pixels = pixels[:r] log("get_image GetBitmapBits took %ims", (time.time() - bitblt_time) * 1000) DeleteObject(bitmap) assert pixels, "no pixels returned from GetBitmapBits" rgb_format = RGB_FORMATS.get(self.bit_depth) if not rgb_format: raise Exception("unsupported bit depth: %s" % self.bit_depth) bpp = self.bit_depth // 8 v = ImageWrapper(0, 0, width, height, pixels, rgb_format, self.bit_depth, rowstride, bpp, planes=ImageWrapper.PACKED, thread_safe=True) if self.bit_depth == 8: palette = get_palette(self.dc) v.set_palette(palette) log("get_image%s=%s took %ims", (x, y, width, height), v, (time.time() - start) * 1000) return v