Ticket #935: memoryview-buffer-wrapper.patch
File memoryview-buffer-wrapper.patch, 35.5 KB (added by , 5 years ago) |
---|
-
xpra/buffers/membuf.pxd
1 # This file is part of Xpra. 2 # Copyright (C) 2008, 2009 Nathaniel Smith <njs@pobox.com> 3 # Copyright (C) 2013 Antoine Martin <antoine@devloop.org.uk> 4 # Xpra is released under the terms of the GNU GPL v2, or, at your option, any 5 # later version. See the file COPYING for details. 6 7 from cpython.buffer cimport PyBuffer_FillInfo 8 9 cdef getbuf(size_t l) 10 cdef padbuf(size_t l, size_t padding) 11 12 ctypedef void dealloc_callback(const void *p, size_t l, void *arg) 13 14 cdef class MemBuf: 15 cdef const void *p 16 cdef size_t l 17 cdef dealloc_callback *dealloc_cb_p 18 cdef void *dealloc_cb_arg 19 20 cdef const void *get_mem(self) -
xpra/buffers/membuf.pyx
1 # coding=utf8 2 # This file is part of Xpra. 3 # Copyright (C) 2015 Antoine Martin <antoine@devloop.org.uk> 4 # Xpra is released under the terms of the GNU GPL v2, or, at your option, any 5 # later version. See the file COPYING for details. 6 7 #Buffer code found here: 8 #http://stackoverflow.com/a/28166272/428751 9 #Allows to return a malloced python buffer, 10 #which will be freed when the python object is garbage collected 11 #(also uses memalign to allocate the buffer) 12 13 from cpython.buffer cimport PyBuffer_FillInfo 14 from libc.stdlib cimport free 15 from libc.string cimport memcpy 16 17 cdef extern from "memalign.h": 18 void *xmemalign(size_t size) nogil 19 20 21 cdef void free_buf(const void *p, size_t l, void *arg): 22 free(<void *>p) 23 24 cdef getbuf(size_t l): 25 cdef const void *p = xmemalign(l) 26 return MemBuf_init(p, l, &free_buf, NULL) 27 28 cdef padbuf(size_t l, size_t padding): 29 cdef const void *p = xmemalign(l+padding) 30 return MemBuf_init(p, l, &free_buf, NULL) 31 32 33 cdef class MemBuf: 34 35 def __len__(self): 36 return self.l 37 38 cdef const void *get_mem(self): 39 return self.p 40 41 def __getbuffer__(self, Py_buffer *view, int flags): 42 PyBuffer_FillInfo(view, self, <void *>self.p, self.l, 1, flags) 43 44 def __releasebuffer__(self, Py_buffer *view): 45 pass 46 47 def __dealloc__(self): 48 if self.dealloc_cb_p != NULL: 49 self.dealloc_cb_p(self.p, self.l, self.dealloc_cb_arg) 50 51 # Call this instead of constructing a MemBuf directly. The __cinit__ 52 # and __init__ methods can only take Python objects, so the real 53 # constructor is here. See: 54 # https://mail.python.org/pipermail/cython-devel/2012-June/002734.html 55 cdef MemBuf MemBuf_init(const void *p, size_t l, 56 dealloc_callback *dealloc_cb_p, 57 void *dealloc_cb_arg): 58 cdef MemBuf ret = MemBuf() 59 ret.p = p 60 ret.l = l 61 ret.dealloc_cb_p = dealloc_cb_p 62 ret.dealloc_cb_arg = dealloc_cb_arg 63 return ret -
xpra/buffers/new_buffers.c
1 /**2 * This file is part of Xpra.3 * Copyright (C) 2014 Antoine Martin <antoine@devloop.org.uk>4 * Xpra is released under the terms of the GNU GPL v2, or, at your option, any5 * later version. See the file COPYING for details.6 */7 8 #include "Python.h"9 10 int get_buffer_api_version(void) {11 return 1;12 }13 14 //Before Python 3.3, use PyMemoryView_FromBuffer15 //MAJOR<<24 + MINOR<<16 + MICRO<<816 #if PY_VERSION_HEX<=0x303000017 PyObject *memory_as_pybuffer(void *ptr, Py_ssize_t buf_len, int readonly) {18 Py_buffer pybuf;19 Py_ssize_t shape[] = {buf_len};20 int ret;21 if (readonly)22 ret = PyBuffer_FillInfo(&pybuf, NULL, ptr, buf_len, 0, PyBUF_SIMPLE);23 else24 ret = PyBuffer_FillInfo(&pybuf, NULL, ptr, buf_len, 0, PyBUF_WRITABLE);25 if (ret!=0)26 return NULL;27 pybuf.format = "B";28 pybuf.shape = shape;29 return PyMemoryView_FromBuffer(&pybuf);30 }31 #else32 PyObject *memory_as_pybuffer(void *ptr, Py_ssize_t buf_len, int readonly) {33 return PyMemoryView_FromMemory(ptr, buf_len, readonly);34 }35 #endif36 37 int object_as_buffer(PyObject *obj, const void ** buffer, Py_ssize_t * buffer_len) {38 Py_buffer *rpybuf;39 if (PyMemoryView_Check(obj)) {40 rpybuf = PyMemoryView_GET_BUFFER(obj);41 if (rpybuf->buf==NULL)42 return -1;43 buffer[0] = rpybuf->buf;44 *buffer_len = rpybuf->len;45 return 0;46 }47 return PyObject_AsReadBuffer(obj, buffer, buffer_len);48 }49 50 int object_as_write_buffer(PyObject *obj, void ** buffer, Py_ssize_t * buffer_len) {51 Py_buffer *wpybuf;52 if (PyMemoryView_Check(obj)) {53 wpybuf = PyMemoryView_GET_BUFFER(obj);54 if (wpybuf->buf==NULL)55 return -1;56 buffer[0] = wpybuf->buf;57 *buffer_len = wpybuf->len;58 return 0;59 }60 return PyObject_AsWriteBuffer(obj, buffer, buffer_len);61 } -
xpra/buffers/old_buffers.c
1 /**2 * This file is part of Xpra.3 * Copyright (C) 2014 Antoine Martin <antoine@devloop.org.uk>4 * Xpra is released under the terms of the GNU GPL v2, or, at your option, any5 * later version. See the file COPYING for details.6 */7 8 // Wrapper for PyObject_AsReadBuffer9 // (so we can more easily replace it with "new-style buffers")10 11 #include "Python.h"12 13 int get_buffer_api_version(void) {14 return 0;15 }16 17 #if (PY_VERSION_HEX < 0x02050000)18 typedef int Py_ssize_t;19 #endif20 21 PyObject *memory_as_pybuffer(void *ptr, Py_ssize_t buf_len, int readonly) {22 if (readonly)23 return PyBuffer_FromMemory(ptr, buf_len);24 return PyBuffer_FromReadWriteMemory(ptr, buf_len);25 }26 27 int object_as_buffer(PyObject *obj, const void ** buffer, Py_ssize_t * buffer_len) {28 return PyObject_AsReadBuffer(obj, buffer, buffer_len);29 }30 31 int object_as_write_buffer(PyObject *obj, void ** buffer, Py_ssize_t * buffer_len) {32 return PyObject_AsWriteBuffer(obj, buffer, buffer_len);33 } -
xpra/codecs/csc_cython/colorspace_converter.pyx
21 21 22 22 from xpra.codecs.codec_constants import codec_spec 23 23 from xpra.codecs.image_wrapper import ImageWrapper 24 from xpra.buffers.membuf cimport padbuf, MemBuf 24 25 25 26 cdef extern from "stdlib.h": 26 27 void free(void *ptr) … … 31 32 int object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len) 32 33 int get_buffer_api_version() 33 34 34 cdef extern from "../../buffers/memalign.h":35 int pad(int size) nogil36 void *xmemalign(size_t size) nogil37 38 35 from libc.stdint cimport uint8_t 39 36 40 37 cdef inline int roundup(int n, int m): … … 101 98 return codec_spec(ColorspaceConverter, codec_type=get_type(), quality=50, speed=10, setup_cost=10, min_w=2, min_h=2, can_scale=True) 102 99 103 100 104 class CythonImageWrapper(ImageWrapper):105 106 def free(self): #@DuplicatedSignature107 log("CythonImageWrapper.free() cython_buffer=%#x", <unsigned long> self.cython_buffer)108 ImageWrapper.free(self)109 if self.cython_buffer>0:110 free(<void *> (<unsigned long> self.cython_buffer))111 self.cython_buffer = 0112 113 114 101 DEF STRIDE_ROUNDUP = 16 115 102 116 103 #Pre-calculate some coefficients and define them as constants … … 184 171 cdef object dst_format 185 172 cdef unsigned long[3] dst_strides 186 173 cdef unsigned long[3] dst_sizes 187 cdef unsigned long[3] offsets174 cdef unsigned long[3] buffer_sizes 188 175 189 176 cdef convert_image_function 190 177 191 178 cdef unsigned long frames 192 179 cdef double time 193 cdef unsigned long buffer_size194 180 195 181 cdef object __weakref__ 196 182 … … 211 197 self.frames = 0 212 198 213 199 #explicity clear all strides / sizes / offsets: 214 for i in range( 2):200 for i in range(3): 215 201 self.dst_strides[i] = 0 216 self.dst_sizes[i] 217 self. offsets[i]= 0202 self.dst_sizes[i] = 0 203 self.buffer_sizes[i] = 0 218 204 219 205 if src_format=="BGRX" and dst_format=="YUV420P": 220 206 self.dst_strides[0] = roundup(self.dst_width, STRIDE_ROUNDUP) … … 221 207 self.dst_strides[1] = roundup(self.dst_width/2, STRIDE_ROUNDUP) 222 208 self.dst_strides[2] = roundup(self.dst_width/2, STRIDE_ROUNDUP) 223 209 self.dst_sizes[0] = self.dst_strides[0] * self.dst_height 224 self.dst_sizes[1] = self.dst_strides[1] * self.dst_height/2 225 self.dst_sizes[2] = self.dst_strides[2] * self.dst_height/2 226 #U channel follows Y with 1 line padding, V follows U with another line of padding: 227 self.offsets[0] = 0 228 self.offsets[1] = self.dst_strides[0] * (self.dst_height+1) 229 self.offsets[2] = self.offsets[1] + (self.dst_strides[1] * (self.dst_height/2+1)) 230 #output buffer ends after V + 1 line of padding: 231 self.buffer_size = self.offsets[2] + (self.dst_strides[2] * (self.dst_height/2+1)) 232 210 self.dst_sizes[1] = self.dst_strides[1] * self.dst_height//2 211 self.dst_sizes[2] = self.dst_strides[2] * self.dst_height//2 233 212 self.convert_image_function = self.BGRX_to_YUV420P 234 213 elif src_format=="YUV420P" and dst_format in ("RGBX", "BGRX", "RGB", "BGR"): 235 214 #3 or 4 bytes per pixel: 236 215 self.dst_strides[0] = roundup(self.dst_width*len(dst_format), STRIDE_ROUNDUP) 237 216 self.dst_sizes[0] = self.dst_strides[0] * self.dst_height 238 self.offsets[0] = 0239 #output buffer ends after 1 line of padding:240 self.buffer_size = self.dst_sizes[0] + roundup(dst_width*len(dst_format), STRIDE_ROUNDUP)241 242 217 if dst_format=="RGBX": 243 218 self.convert_image_function = self.YUV420P_to_RGBX 244 219 elif dst_format=="BGRX": … … 252 227 #4 bytes per pixel: 253 228 self.dst_strides[0] = roundup(self.dst_width*4, STRIDE_ROUNDUP) 254 229 self.dst_sizes[0] = self.dst_strides[0] * self.dst_height 255 self.offsets[0] = 0256 #output buffer ends after 1 line of padding:257 self.buffer_size = self.dst_sizes[0] + roundup(dst_width*4, STRIDE_ROUNDUP)258 259 230 if dst_format=="RGBX": 260 231 self.convert_image_function = self.GBRP_to_RGBX 261 232 else: … … 263 234 self.convert_image_function = self.GBRP_to_BGRX 264 235 else: 265 236 raise Exception("BUG: src_format=%s, dst_format=%s", src_format, dst_format) 237 #output buffers ends have 1 line of padding: 238 for i in range(3): 239 if self.dst_sizes[i]>0: 240 self.buffer_sizes[i] = self.dst_sizes[i] + roundup(self.dst_strides[i]*len(dst_format), STRIDE_ROUNDUP) 266 241 267 242 def clean(self): #@DuplicatedSignature 268 243 #overzealous clean is cheap! … … 278 253 for i in range(3): 279 254 self.dst_strides[i] = 0 280 255 self.dst_sizes[i] = 0 281 self. offsets[i] = 0256 self.buffer_sizes[i] = 0 282 257 self.convert_image_function = None 283 self.buffer_size = 0284 258 285 259 def is_closed(self): 286 260 return bool(self.convert_image_function) … … 348 322 cdef unsigned short Rsum 349 323 cdef unsigned short Gsum 350 324 cdef unsigned short Bsum 351 cdef unsigned char *Y352 cdef unsigned char *U353 cdef unsigned char *V354 325 355 326 start = time.time() 356 327 iplanes = image.get_planes() … … 364 335 365 336 assert object_as_buffer(pixels, <const void**> &input_image, &pic_buf_len)==0 366 337 #allocate output buffer: 367 output_image = <unsigned char*> xmemalign(self.buffer_size) 368 Y = output_image + self.offsets[0] 369 U = output_image + self.offsets[1] 370 V = output_image + self.offsets[2] 338 cdef MemBuf YBuf = padbuf(self.buffer_sizes[0], self.dst_width) 339 cdef unsigned char *Y = <unsigned char *> YBuf.get_mem() 340 cdef MemBuf UBuf = padbuf(self.buffer_sizes[1], self.dst_width//2) 341 cdef unsigned char *U = <unsigned char *> UBuf.get_mem() 342 cdef MemBuf VBuf = padbuf(self.buffer_sizes[2], self.dst_width//2) 343 cdef unsigned char *V = <unsigned char *> VBuf.get_mem() 371 344 372 345 #copy to local variables (ensures C code will be optimized correctly) 373 346 Ystride = self.dst_strides[0] … … 418 391 U[y*Ustride + x] = clamp(UR * Rsum + UG * Gsum + UB * Bsum + UC) 419 392 V[y*Vstride + x] = clamp(VR * Rsum + VG * Gsum + VB * Bsum + VC) 420 393 #create python buffer from each plane: 421 planes = [ ]394 planes = [memoryview(YBuf), memoryview(UBuf), memoryview(VBuf)] 422 395 strides = [] 423 396 for i in range(3): 424 397 strides.append(self.dst_strides[i]) 425 planes.append(memory_as_pybuffer(<void *> (<unsigned long> (output_image + self.offsets[i])), self.dst_sizes[i], True))426 398 elapsed = time.time()-start 427 399 log("%s took %.1fms", self, 1000.0*elapsed) 428 400 self.time += elapsed 429 401 self.frames += 1 430 out_image = CythonImageWrapper(0, 0, dst_width, dst_height, planes, self.dst_format, 24, strides, ImageWrapper._3_PLANES) 431 out_image.cython_buffer = <unsigned long> output_image 432 return out_image 402 return ImageWrapper(0, 0, dst_width, dst_height, planes, self.dst_format, 24, strides, ImageWrapper._3_PLANES) 433 403 434 404 435 405 def YUV420P_to_RGBX(self, image): … … 486 456 assert buf_len>=Vstride*image.get_height()/2, "buffer for V plane is too small: %s bytes, expected at least %s" % (buf_len, Vstride*image.get_height()/2) 487 457 488 458 #allocate output buffer: 489 output_image = <unsigned char*> xmemalign(self.buffer_size) 459 cdef MemBuf output_buf = padbuf(self.buffer_sizes[0], self.dst_width*Bpp) 460 output_image = <unsigned char*> output_buf.get_mem() 490 461 491 462 #we process 4 pixels at a time: 492 463 workw = roundup(dst_width/2, 2) … … 516 487 if Bpp==4: 517 488 output_image[o + Xindex] = 255 518 489 519 rgb = memory_as_pybuffer(<void *> output_image, self.dst_sizes[0], True)520 490 elapsed = time.time()-start 521 491 log("%s took %.1fms", self, 1000.0*elapsed) 522 492 self.time += elapsed 523 493 self.frames += 1 524 out_image = CythonImageWrapper(0, 0, dst_width, dst_height, rgb, self.dst_format, 24, stride, ImageWrapper.PACKED) 525 out_image.cython_buffer = <unsigned long> output_image 526 return out_image 494 return ImageWrapper(0, 0, dst_width, dst_height, memoryview(output_buf), self.dst_format, 24, stride, ImageWrapper.PACKED) 527 495 528 496 529 497 def GBRP_to_RGBX(self, image): … … 576 544 assert buf_len>=Bstride*image.get_height(), "buffer for B plane is too small: %s bytes, expected at least %s" % (buf_len, Bstride*image.get_height()) 577 545 578 546 #allocate output buffer: 579 output_image = <unsigned char*> xmemalign(self.buffer_size) 547 cdef MemBuf output_buf = padbuf(self.buffer_sizes[0], self.dst_width*4) 548 output_image = <unsigned char*> output_buf.get_mem() 580 549 581 550 #from now on, we can release the gil: 582 551 with nogil: … … 594 563 output_image[o+Xdst] = 255 595 564 o += 4 596 565 597 rgb = memory_as_pybuffer(<void *> output_image, self.dst_sizes[0], True)598 566 elapsed = time.time()-start 599 567 log("%s took %.1fms", self, 1000.0*elapsed) 600 568 self.time += elapsed 601 569 self.frames += 1 602 out_image = CythonImageWrapper(0, 0, dst_width, dst_height, rgb, self.dst_format, 24, stride, ImageWrapper.PACKED) 603 out_image.cython_buffer = <unsigned long> output_image 604 return out_image 570 return ImageWrapper(0, 0, dst_width, dst_height, memoryview(output_buf), self.dst_format, 24, stride, ImageWrapper.PACKED) 605 571 606 572 607 573 def selftest(full=False): … … 608 574 from xpra.codecs.codec_checks import testcsc 609 575 from xpra.codecs.csc_cython import colorspace_converter 610 576 testcsc(colorspace_converter, full) 577 578 log.info("testing buf bits") 579 cdef MemBuf b = padbuf(100, 10) 580 log.info("buffer: %s", b) 581 log.info("memoryview: %s", memoryview(b).tobytes()) -
xpra/codecs/csc_swscale/colorspace_converter.pyx
15 15 from xpra.codecs.codec_constants import codec_spec 16 16 from xpra.codecs.image_wrapper import ImageWrapper 17 17 from xpra.codecs.libav_common.av_log cimport override_logger, restore_logger #@UnresolvedImport 18 from xpra.buffers.membuf cimport padbuf, MemBuf 18 19 19 20 20 21 cdef extern from "../../buffers/buffers.h": 21 object memory_as_pybuffer(void* ptr, Py_ssize_t buf_len, int readonly)22 22 int object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len) 23 23 int get_buffer_api_version() 24 24 25 cdef extern from "../../buffers/memalign.h":26 int pad(int size) nogil27 void *xmemalign(size_t size) nogil28 29 cdef extern from "stdlib.h":30 void free(void *ptr)31 32 25 cdef extern from "../../inline.h": 33 26 pass 34 27 … … 255 248 COLORSPACES = [] 256 249 257 250 258 cdef class CSCImage:259 """260 Allows us to call free_csc_image261 when this object is garbage collected262 """263 cdef uint8_t *buf[4]264 cdef int freed265 266 cdef set_plane(self, int plane, uint8_t *buf):267 assert plane in (0, 1, 2, 3)268 self.buf[plane] = buf269 270 def __repr__(self):271 return "CSCImage(%#x, freed=%s)" % (<unsigned long> self.buf, self.freed)272 273 def __dealloc__(self):274 #log("CSCImage.__dealloc__()")275 self.free()276 277 def free(self):278 #log("CSCImage.free() freed=%s", bool(self.freed))279 if self.freed==0:280 self.freed = 1281 if self.buf[0]==NULL:282 raise Exception("buffer is already freed!?")283 free(self.buf[0])284 for i in range(4):285 self.buf[i] = NULL286 287 288 class CSCImageWrapper(ImageWrapper):289 290 def free(self): #@DuplicatedSignature291 log("CSCImageWrapper.free() csc_image=%s", self.csc_image)292 ImageWrapper.free(self)293 if self.csc_image:294 self.csc_image.free()295 self.csc_image = None296 297 298 251 cdef class ColorspaceConverter: 299 252 cdef int src_width 300 253 cdef int src_height … … 313 266 cdef int out_height[4] 314 267 cdef int out_stride[4] 315 268 cdef unsigned long out_size[4] 316 cdef unsigned long buffer_size317 269 318 270 cdef object __weakref__ 319 271 … … 335 287 self.dst_format = dst_format 336 288 self.dst_format_enum = dst.av_enum 337 289 #pre-calculate plane heights: 338 self.buffer_size = 0339 290 cdef int subsampling = False 340 291 for i in range(4): 341 292 self.out_height[i] = (int) (dst_height * dst.height_mult[i]) … … 342 293 self.out_stride[i] = roundup((int) (dst_width * dst.width_mult[i]), 16) 343 294 if i!=3 and (dst.height_mult[i]!=1.0 or dst.width_mult[i]!=1.0): 344 295 subsampling = True 345 #add one extra line to height so we can read a full rowstride 346 #no matter where we start to read on the last line. 347 #MEMALIGN may be redundant here but it is very cheap 348 self.out_size[i] = pad(self.out_stride[i] * (self.out_height[i]+1)) 349 self.buffer_size += self.out_size[i] 350 log("buffer size=%s", self.buffer_size) 296 self.out_size[i] = self.out_stride[i] * self.out_height[i] 351 297 352 298 self.src_width = src_width 353 299 self.src_height = src_height … … 438 384 self.out_height[i] = 0 439 385 self.out_stride[i] = 0 440 386 self.out_size[i] = 0 441 self.buffer_size = 0442 387 443 388 def is_closed(self): 444 389 return self.context!=NULL … … 455 400 cdef int height 456 401 cdef int stride 457 402 cdef int result 458 cdef Py_buffer *py_buffer403 cdef size_t pad 459 404 start = time.time() 460 405 iplanes = image.get_planes() 461 406 pixels = image.get_pixels() … … 468 413 iplanes = 1 469 414 else: 470 415 planes = pixels 416 if self.dst_format.endswith("P"): 417 pad = self.dst_width 418 else: 419 pad = self.dst_width * 4 471 420 #print("convert_image(%s) input=%s, strides=%s" % (image, len(input), strides)) 472 421 assert pixels, "failed to get pixels from %s" % image 473 422 assert image.get_width()>=self.src_width, "invalid image width: %s (minimum is %s)" % (image.get_width(), self.src_width) … … 484 433 #(so we just copy the last valid plane in the remaining slots - ugly!) 485 434 input_stride[i] = input_stride[iplanes-1] 486 435 input_image[i] = input_image[iplanes-1] 436 437 #allocate the output buffer(s): 438 output_buf = [] 439 cdef MemBuf mb 440 for i in range(3): 441 if self.out_size[i]>0: 442 mb = padbuf(self.out_size[i], pad) 443 output_buf.append(mb) 444 output_image[i] = <uint8_t *> mb.get_mem() 445 else: 446 #the buffer may not be used, but is not allowed to be NULL: 447 output_image[i] = output_image[0] 487 448 with nogil: 488 output_image[0] = <uint8_t*> xmemalign(self.buffer_size)489 for i in range(3):490 output_image[1+i] = output_image[i] + self.out_size[i]491 449 result = sws_scale(self.context, input_image, input_stride, 0, self.src_height, output_image, self.out_stride) 492 450 assert result!=0, "sws_scale failed!" 493 451 assert result==self.dst_height, "invalid output height: %s, expected %s" % (result, self.dst_height) 494 452 #now parse the output: 495 csci = CSCImage() #keep a reference to memory for cleanup496 for i in range(4):497 csci.set_plane(i, NULL)498 453 if self.dst_format.endswith("P"): 499 454 #planar mode, assume 3 planes: 500 455 oplanes = ImageWrapper._3_PLANES 501 out = [] 502 strides = [] 503 for i in range(3): 504 if self.out_stride[i]>0 and output_image[i]!=NULL: 505 stride = self.out_stride[i] 506 plane = memory_as_pybuffer(<void *>output_image[i], self.out_height[i] * self.out_stride[i], True) 507 else: 508 stride = 0 509 plane = None 510 csci.set_plane(i, output_image[i]) 511 out.append(plane) 512 strides.append(stride) 456 out = [memoryview(output_buf[i]) for i in range(3)] 457 strides = [self.out_stride[i] for i in range(3)] 513 458 else: 514 459 #assume no planes, plain RGB packed pixels: 515 460 oplanes = ImageWrapper.PACKED 516 461 strides = self.out_stride[0] 517 out = memory_as_pybuffer(<void *>output_image[0], self.out_height[0] * self.out_stride[0], True) 518 csci.set_plane(0, output_image[0]) 462 out = memoryview(output_buf[0]) 519 463 elapsed = time.time()-start 520 464 log("%s took %.1fms", self, 1000.0*elapsed) 521 465 self.time += elapsed 522 466 self.frames += 1 523 out_image = CSCImageWrapper(0, 0, self.dst_width, self.dst_height, out, self.dst_format, 24, strides, oplanes) 524 out_image.csc_image = csci 525 return out_image 467 return ImageWrapper(0, 0, self.dst_width, self.dst_height, out, self.dst_format, 24, strides, oplanes) 526 468 527 469 528 470 def selftest(full=False): -
xpra/codecs/vpx/decoder.pyx
6 6 import os 7 7 from xpra.codecs.codec_constants import codec_spec, get_subsampling_divs 8 8 from xpra.codecs.image_wrapper import ImageWrapper 9 from xpra.buffers.membuf cimport padbuf, MemBuf 9 10 from xpra.os_util import bytestostr 10 11 11 12 from xpra.log import Logger … … 181 182 return VPX_IMG_FMT_I420 182 183 183 184 184 class VPXImageWrapper(ImageWrapper):185 186 def __init__(self, *args, **kwargs):187 ImageWrapper.__init__(self, *args, **kwargs)188 self.buffers = []189 190 def add_buffer(self, ptr):191 self.buffers.append(ptr)192 193 def clone_pixel_data(self):194 ImageWrapper.clone_pixel_data(self)195 self.free_buffers()196 197 def free(self):198 ImageWrapper.free(self)199 self.free_buffers()200 201 def free_buffers(self):202 cdef void *ptr203 if self.buffers:204 for x in self.buffers:205 #cython magic:206 ptr = <void *> (<unsigned long> x)207 free(ptr)208 self.buffers = []209 210 211 185 cdef class Decoder: 212 186 213 187 cdef vpx_codec_ctx_t *context … … 300 274 cdef vpx_codec_err_t ret 301 275 cdef int i = 0 302 276 cdef object image 303 cdef void *padded_buf 277 cdef MemBuf output_buf 278 cdef void *output 304 279 cdef Py_ssize_t plane_len = 0 305 280 cdef uint8_t dx, dy 306 281 cdef unsigned int height … … 322 297 strides = [] 323 298 pixels = [] 324 299 divs = get_subsampling_divs(self.get_colorspace()) 325 image = VPXImageWrapper(0, 0, self.width, self.height, pixels, self.get_colorspace(), 24, strides, 3)326 300 for i in range(3): 327 301 _, dy = divs[i] 328 302 if dy==1: … … 335 309 strides.append(stride) 336 310 337 311 plane_len = height * stride 312 338 313 #add one extra line of padding: 339 padded_buf = xmemalign(plane_len + stride) 340 memcpy(padded_buf, <void *>img.planes[i], plane_len) 341 memset(<void *>((<char *>padded_buf)+plane_len), 0, stride) 314 output_buf = padbuf(plane_len, stride) 315 output = <void *>output_buf.get_mem() 316 memcpy(output, <void *>img.planes[i], plane_len) 317 memset(<void *>((<char *>output)+plane_len), 0, stride) 342 318 343 pixels.append(memory_as_pybuffer(padded_buf, plane_len, True)) 319 pixels.append(memoryview(output_buf)) 320 return ImageWrapper(0, 0, self.width, self.height, pixels, self.get_colorspace(), 24, strides, 3) 344 321 345 image.add_buffer(<unsigned long> padded_buf)346 log("vpx returning decoded %s image %s with colorspace=%s", self.encoding, image, image.get_pixel_format())347 return image348 322 349 350 323 def selftest(full=False): 351 324 global CODECS 352 325 from xpra.codecs.codec_checks import testdecoder -
xpra/codecs/argb/argb.pyx
6 6 7 7 #cython: boundscheck=False, wraparound=False, cdivision=True 8 8 9 from xpra.buffers.membuf cimport getbuf, MemBuf 9 10 10 11 cdef extern from "../../buffers/buffers.h": 11 12 int object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len) … … 46 47 if argb_len <= 0: 47 48 return None 48 49 assert argb_len % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % argb_len 49 rgba = bytearray(argb_len) 50 cdef MemBuf rgba_buf = getbuf(argb_len) 51 cdef unsigned char *rgba = <unsigned char*> rgba_buf.get_mem() 50 52 #number of pixels: 51 53 cdef unsigned int i = 0 52 54 while i < argb_len: … … 55 57 rgba[i+2] = argb[i+3] #B 56 58 rgba[i+3] = argb[i] #A 57 59 i = i + 4 58 return rgba60 return memoryview(rgba_buf) 59 61 60 62 def argb_to_rgb(buf): 61 63 assert len(buf) % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % len(buf) … … 72 74 #number of pixels: 73 75 cdef unsigned int mi = argb_len//4 #@DuplicateSignature 74 76 #3 bytes per pixel: 75 rgb = bytearray(mi*3) 77 cdef MemBuf rgb_buf = getbuf(mi*3) 78 cdef unsigned char *rgb = <unsigned char*> rgb_buf.get_mem() 76 79 cdef unsigned int i = 0, di = 0 #@DuplicateSignature 77 80 while i < argb_len: 78 81 rgb[di] = argb[i+1] #R … … 80 83 rgb[di+2] = argb[i+3] #B 81 84 di += 3 82 85 i += 4 83 return rgb86 return memoryview(rgb_buf) 84 87 85 88 86 89 def bgra_to_rgb(buf): … … 98 101 #number of pixels: 99 102 cdef unsigned int mi = bgra_len//4 #@DuplicateSignature 100 103 #3 bytes per pixel: 101 rgb = bytearray(mi*3)102 cdef unsigned int di = 0 #@DuplicateSignature103 cdef unsigned int si = 0#@DuplicateSignature104 cdef MemBuf rgb_buf = getbuf(mi*3) 105 cdef unsigned char *rgb = <unsigned char*> rgb_buf.get_mem() 106 cdef unsigned int di = 0, si = 0 #@DuplicateSignature 104 107 while si < bgra_len: 105 108 rgb[di] = bgra[si+2] #R 106 109 rgb[di+1] = bgra[si+1] #G … … 107 110 rgb[di+2] = bgra[si] #B 108 111 di += 3 109 112 si += 4 110 return rgb113 return memoryview(rgb_buf) 111 114 112 115 113 116 def bgra_to_rgba(buf): … … 123 126 return None 124 127 assert bgra_len % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % bgra_len 125 128 #same number of bytes: 126 rgba = bytearray(bgra_len) 129 cdef MemBuf rgba_buf = getbuf(bgra_len) 130 cdef unsigned char *rgba = <unsigned char*> rgba_buf.get_mem() 127 131 cdef unsigned int i = 0 #@DuplicateSignature 128 132 while i < bgra_len: 129 133 rgba[i] = bgra[i+2] #R … … 131 135 rgba[i+2] = bgra[i] #B 132 136 rgba[i+3] = bgra[i+3] #A 133 137 i += 4 134 return rgba138 return memoryview(rgba_buf) 135 139 136 140 137 141 def premultiply_argb_in_place(buf): … … 216 220 cdef unsigned int argb #@DuplicateSignature 217 221 assert sizeof(int) == 4 218 222 assert argb_len % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % argb_len 219 argb_out = bytearray(argb_len) 223 cdef MemBuf argb_buf = getbuf(argb_len) 224 cdef unsigned char *argb_out = <unsigned char*> argb_buf.get_mem() 220 225 cdef int i #@DuplicateSignature 221 226 for 0 <= i < argb_len // 4: 222 227 argb = argb_in[i] … … 239 244 argb_out[i*4+G] = g 240 245 argb_out[i*4+R] = r 241 246 argb_out[i*4+A] = a 242 return argb_out247 return memoryview(argb_buf) -
xpra/codecs/xor/cyxor.pyx
3 3 # Xpra is released under the terms of the GNU GPL v2, or, at your option, any 4 4 # later version. See the file COPYING for details. 5 5 6 cdef extern from "stdlib.h": 7 void* malloc(size_t __size) 8 void free(void* mem) 6 from xpra.buffers.membuf cimport getbuf, MemBuf 9 7 10 11 8 cdef extern from "../../buffers/memalign.h": 12 9 void *xmemalign(size_t size) nogil 13 10 … … 24 21 cdef Py_ssize_t xbuf_len = 0 #@DuplicatedSignature 25 22 assert object_as_buffer(xor, <const void**> &xbuf, &xbuf_len)==0, "cannot get buffer pointer for %s: %s" % (type(xor), xor) 26 23 assert cbuf_len == xbuf_len, "python or cython bug? buffers don't have the same length?" 27 out_bytes = bytearray(cbuf_len) 28 cdef unsigned char * obuf #@DuplicatedSignature 29 cdef Py_ssize_t obuf_len = 0 #@DuplicatedSignature 30 assert object_as_buffer(out_bytes, <const void**> &obuf, &obuf_len)==0, "cannot get buffer pointer for %s: %s" % (type(obuf), obuf) 31 assert obuf_len==cbuf_len 24 cdef MemBuf out_buf = getbuf(cbuf_len) 25 cdef unsigned char *obuf = <unsigned char*> out_buf.get_mem() 32 26 cdef int i #@DuplicatedSignature 33 27 for 0 <= i < cbuf_len: 34 28 obuf[i] = cbuf[i] ^ xbuf[i] 35 return out_bytes29 return memoryview(out_buf) -
setup.py
165 165 nvenc5_ENABLED = pkg_config_ok("--exists", "nvenc5") 166 166 167 167 csc_opencl_ENABLED = pkg_config_ok("--exists", "OpenCL") and check_pyopencl_AMD() 168 memoryview_ENABLED = sys.version>='2.7'169 168 170 169 annotate_ENABLED = True 171 170 warn_ENABLED = True … … 183 182 "vpx", "webp", "pillow", 184 183 "dec_avcodec2", "csc_swscale", 185 184 "csc_opencl", "csc_cython", 186 "memoryview",187 185 "bencode", "cython_bencode", 188 186 "clipboard", 189 187 "server", "client", "dbus", "x11", "gtk_x11", … … 258 256 print("Warning: you probably want to build at least the client or server!") 259 257 if not pillow_ENABLED: 260 258 print("Warning: including Python Pillow is VERY STRONGLY recommended") 261 if memoryview_ENABLED and sys.version<"2.7":262 print("Error: memoryview support requires Python version 2.7 or greater")263 exit(1)264 259 265 260 266 261 #******************************************************************************* … … 596 591 add_to_keywords(kw, 'extra_link_args', "-Wall") 597 592 if strict_ENABLED: 598 593 if is_msvc(): 599 add_to_keywords(kw, 'extra_compile_args', "/wd4005") #macro redifined with vpx vs stdint.h 600 add_to_keywords(kw, 'extra_compile_args', "/WX") 594 add_to_keywords(kw, 'extra_compile_args', "/wd4005", "/WX") #macro redifined with vpx vs stdint.h 601 595 add_to_keywords(kw, 'extra_link_args', "/WX") 602 596 else: 603 597 if os.environ.get("CC", "").find("clang")>=0: … … 616 610 #/usr/include/gtk-2.0/gtk/gtkitemfactory.h:47:1: error: function declaration isn't a prototype [-Werror=strict-prototypes] 617 611 #"-Wno-error=strict-prototypes", 618 612 ] 619 for eif in eifd: 620 add_to_keywords(kw, 'extra_compile_args', eif) 613 add_to_keywords(kw, 'extra_compile_args', *eifd) 621 614 if PIC_ENABLED and not is_msvc(): 622 615 add_to_keywords(kw, 'extra_compile_args', "-fPIC") 623 616 if debug_ENABLED: … … 624 617 if is_msvc(): 625 618 add_to_keywords(kw, 'extra_compile_args', '/Zi') 626 619 else: 627 add_to_keywords(kw, 'extra_compile_args', '-g') 628 add_to_keywords(kw, 'extra_compile_args', '-ggdb') 620 add_to_keywords(kw, 'extra_compile_args', '-g', '-ggdb') 629 621 if get_gcc_version()>=[4, 8]: 630 622 add_to_keywords(kw, 'extra_compile_args', '-fsanitize=address') 631 623 add_to_keywords(kw, 'extra_link_args', '-fsanitize=address') … … 1732 1724 1733 1725 1734 1726 #******************************************************************************* 1735 #which file to link against (new-style buffers or old?): 1736 if memoryview_ENABLED: 1737 bmod = "new" 1738 else: 1739 assert not PYTHON3 1740 bmod = "old" 1741 buffers_c = "xpra/buffers/%s_buffers.c" % bmod 1727 buffers_c = "xpra/buffers/buffers.c" 1742 1728 #convenience grouping for codecs: 1743 1729 membuffers_c = ["xpra/buffers/memalign.c", "xpra/inline.c", buffers_c] 1744 1730 … … 1747 1733 toggle_packages(server_ENABLED or gtk2_ENABLED or gtk3_ENABLED, "xpra.gtk_common", "xpra.clipboard") 1748 1734 1749 1735 1736 add_packages("xpra.buffers") 1737 buffers_pkgconfig = pkgconfig() 1738 cython_add(Extension("xpra.buffers.membuf", 1739 ["xpra/buffers/membuf.pyx"]+membuffers_c, **buffers_pkgconfig)) 1740 1741 1750 1742 toggle_packages(dbus_ENABLED, "xpra.dbus") 1751 1743 toggle_packages(x11_ENABLED, "xpra.x11", "xpra.x11.bindings") 1752 1744 if x11_ENABLED: