xpra icon
Bug tracker and wiki

Ticket #935: memoryview-buffer-wrapper.patch

File memoryview-buffer-wrapper.patch, 35.5 KB (added by Antoine Martin, 5 years ago)

switch to a wrapper class for memalign memory

  • 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
     7from cpython.buffer cimport PyBuffer_FillInfo
     8
     9cdef getbuf(size_t l)
     10cdef padbuf(size_t l, size_t padding)
     11
     12ctypedef void dealloc_callback(const void *p, size_t l, void *arg)
     13
     14cdef 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
     13from cpython.buffer cimport PyBuffer_FillInfo
     14from libc.stdlib cimport free
     15from libc.string cimport memcpy
     16
     17cdef extern from "memalign.h":
     18    void *xmemalign(size_t size) nogil
     19
     20
     21cdef void free_buf(const void *p, size_t l, void *arg):
     22    free(<void *>p)
     23
     24cdef getbuf(size_t l):
     25    cdef const void *p = xmemalign(l)
     26    return MemBuf_init(p, l, &free_buf, NULL)
     27
     28cdef 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
     33cdef 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
     55cdef 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, any
    5  * 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_FromBuffer
    15 //MAJOR<<24 + MINOR<<16 + MICRO<<8
    16 #if PY_VERSION_HEX<=0x3030000
    17 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     else
    24         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 #else
    32 PyObject *memory_as_pybuffer(void *ptr, Py_ssize_t buf_len, int readonly) {
    33         return PyMemoryView_FromMemory(ptr, buf_len, readonly);
    34 }
    35 #endif
    36 
    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, any
    5  * later version. See the file COPYING for details.
    6  */
    7 
    8 // Wrapper for PyObject_AsReadBuffer
    9 // (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 #endif
    20 
    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

     
    2121
    2222from xpra.codecs.codec_constants import codec_spec
    2323from xpra.codecs.image_wrapper import ImageWrapper
     24from xpra.buffers.membuf cimport padbuf, MemBuf
    2425
    2526cdef extern from "stdlib.h":
    2627    void free(void *ptr)
     
    3132    int    object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len)
    3233    int get_buffer_api_version()
    3334
    34 cdef extern from "../../buffers/memalign.h":
    35     int pad(int size) nogil
    36     void *xmemalign(size_t size) nogil
    37 
    3835from libc.stdint cimport uint8_t
    3936
    4037cdef inline int roundup(int n, int m):
     
    10198    return codec_spec(ColorspaceConverter, codec_type=get_type(), quality=50, speed=10, setup_cost=10, min_w=2, min_h=2, can_scale=True)
    10299
    103100
    104 class CythonImageWrapper(ImageWrapper):
    105 
    106     def free(self):                             #@DuplicatedSignature
    107         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 = 0
    112 
    113 
    114101DEF STRIDE_ROUNDUP = 16
    115102
    116103#Pre-calculate some coefficients and define them as constants
     
    184171    cdef object dst_format
    185172    cdef unsigned long[3] dst_strides
    186173    cdef unsigned long[3] dst_sizes
    187     cdef unsigned long[3] offsets
     174    cdef unsigned long[3] buffer_sizes
    188175
    189176    cdef convert_image_function
    190177
    191178    cdef unsigned long frames
    192179    cdef double time
    193     cdef unsigned long buffer_size
    194180
    195181    cdef object __weakref__
    196182
     
    211197        self.frames = 0
    212198
    213199        #explicity clear all strides / sizes / offsets:
    214         for i in range(2):
     200        for i in range(3):
    215201            self.dst_strides[i] = 0
    216             self.dst_sizes[i]   = 0
    217             self.offsets[i]    = 0
     202            self.dst_sizes[i] = 0
     203            self.buffer_sizes[i] = 0
    218204
    219205        if src_format=="BGRX" and dst_format=="YUV420P":
    220206            self.dst_strides[0] = roundup(self.dst_width,   STRIDE_ROUNDUP)
     
    221207            self.dst_strides[1] = roundup(self.dst_width/2, STRIDE_ROUNDUP)
    222208            self.dst_strides[2] = roundup(self.dst_width/2, STRIDE_ROUNDUP)
    223209            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
    233212            self.convert_image_function = self.BGRX_to_YUV420P
    234213        elif src_format=="YUV420P" and dst_format in ("RGBX", "BGRX", "RGB", "BGR"):
    235214            #3 or 4 bytes per pixel:
    236215            self.dst_strides[0] = roundup(self.dst_width*len(dst_format), STRIDE_ROUNDUP)
    237216            self.dst_sizes[0] = self.dst_strides[0] * self.dst_height
    238             self.offsets[0] = 0
    239             #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 
    242217            if dst_format=="RGBX":
    243218                self.convert_image_function = self.YUV420P_to_RGBX
    244219            elif dst_format=="BGRX":
     
    252227            #4 bytes per pixel:
    253228            self.dst_strides[0] = roundup(self.dst_width*4, STRIDE_ROUNDUP)
    254229            self.dst_sizes[0] = self.dst_strides[0] * self.dst_height
    255             self.offsets[0] = 0
    256             #output buffer ends after 1 line of padding:
    257             self.buffer_size = self.dst_sizes[0] + roundup(dst_width*4, STRIDE_ROUNDUP)
    258 
    259230            if dst_format=="RGBX":
    260231                self.convert_image_function = self.GBRP_to_RGBX
    261232            else:
     
    263234                self.convert_image_function = self.GBRP_to_BGRX
    264235        else:
    265236            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)
    266241
    267242    def clean(self):                        #@DuplicatedSignature
    268243        #overzealous clean is cheap!
     
    278253        for i in range(3):
    279254            self.dst_strides[i] = 0
    280255            self.dst_sizes[i] = 0
    281             self.offsets[i] = 0
     256            self.buffer_sizes[i] = 0
    282257        self.convert_image_function = None
    283         self.buffer_size = 0
    284258
    285259    def is_closed(self):
    286260        return bool(self.convert_image_function)
     
    348322        cdef unsigned short Rsum
    349323        cdef unsigned short Gsum
    350324        cdef unsigned short Bsum
    351         cdef unsigned char *Y
    352         cdef unsigned char *U
    353         cdef unsigned char *V
    354325
    355326        start = time.time()
    356327        iplanes = image.get_planes()
     
    364335
    365336        assert object_as_buffer(pixels, <const void**> &input_image, &pic_buf_len)==0
    366337        #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()
    371344
    372345        #copy to local variables (ensures C code will be optimized correctly)
    373346        Ystride = self.dst_strides[0]
     
    418391                        U[y*Ustride + x] = clamp(UR * Rsum + UG * Gsum + UB * Bsum + UC)
    419392                        V[y*Vstride + x] = clamp(VR * Rsum + VG * Gsum + VB * Bsum + VC)
    420393        #create python buffer from each plane:
    421         planes = []
     394        planes = [memoryview(YBuf), memoryview(UBuf), memoryview(VBuf)]
    422395        strides = []
    423396        for i in range(3):
    424397            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))
    426398        elapsed = time.time()-start
    427399        log("%s took %.1fms", self, 1000.0*elapsed)
    428400        self.time += elapsed
    429401        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)
    433403
    434404
    435405    def YUV420P_to_RGBX(self, image):
     
    486456        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)
    487457
    488458        #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()
    490461
    491462        #we process 4 pixels at a time:
    492463        workw = roundup(dst_width/2, 2)
     
    516487                            if Bpp==4:
    517488                                output_image[o + Xindex] = 255
    518489
    519         rgb = memory_as_pybuffer(<void *> output_image, self.dst_sizes[0], True)
    520490        elapsed = time.time()-start
    521491        log("%s took %.1fms", self, 1000.0*elapsed)
    522492        self.time += elapsed
    523493        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)
    527495
    528496
    529497    def GBRP_to_RGBX(self, image):
     
    576544        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())
    577545
    578546        #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()
    580549
    581550        #from now on, we can release the gil:
    582551        with nogil:
     
    594563                    output_image[o+Xdst] = 255
    595564                    o += 4
    596565
    597         rgb = memory_as_pybuffer(<void *> output_image, self.dst_sizes[0], True)
    598566        elapsed = time.time()-start
    599567        log("%s took %.1fms", self, 1000.0*elapsed)
    600568        self.time += elapsed
    601569        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)
    605571
    606572
    607573def selftest(full=False):
     
    608574    from xpra.codecs.codec_checks import testcsc
    609575    from xpra.codecs.csc_cython import colorspace_converter
    610576    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

     
    1515from xpra.codecs.codec_constants import codec_spec
    1616from xpra.codecs.image_wrapper import ImageWrapper
    1717from xpra.codecs.libav_common.av_log cimport override_logger, restore_logger #@UnresolvedImport
     18from xpra.buffers.membuf cimport padbuf, MemBuf
    1819
    1920
    2021cdef extern from "../../buffers/buffers.h":
    21     object memory_as_pybuffer(void* ptr, Py_ssize_t buf_len, int readonly)
    2222    int    object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len)
    2323    int get_buffer_api_version()
    2424
    25 cdef extern from "../../buffers/memalign.h":
    26     int pad(int size) nogil
    27     void *xmemalign(size_t size) nogil
    28 
    29 cdef extern from "stdlib.h":
    30     void free(void *ptr)
    31 
    3225cdef extern from "../../inline.h":
    3326    pass
    3427
     
    255248        COLORSPACES = []
    256249
    257250
    258 cdef class CSCImage:
    259     """
    260         Allows us to call free_csc_image
    261         when this object is garbage collected
    262     """
    263     cdef uint8_t *buf[4]
    264     cdef int freed
    265 
    266     cdef set_plane(self, int plane, uint8_t *buf):
    267         assert plane in (0, 1, 2, 3)
    268         self.buf[plane] = buf
    269 
    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 = 1
    281             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] = NULL
    286 
    287 
    288 class CSCImageWrapper(ImageWrapper):
    289 
    290     def free(self):                             #@DuplicatedSignature
    291         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 = None
    296 
    297 
    298251cdef class ColorspaceConverter:
    299252    cdef int src_width
    300253    cdef int src_height
     
    313266    cdef int out_height[4]
    314267    cdef int out_stride[4]
    315268    cdef unsigned long out_size[4]
    316     cdef unsigned long buffer_size
    317269
    318270    cdef object __weakref__
    319271
     
    335287        self.dst_format = dst_format
    336288        self.dst_format_enum = dst.av_enum
    337289        #pre-calculate plane heights:
    338         self.buffer_size = 0
    339290        cdef int subsampling = False
    340291        for i in range(4):
    341292            self.out_height[i] = (int) (dst_height * dst.height_mult[i])
     
    342293            self.out_stride[i] = roundup((int) (dst_width * dst.width_mult[i]), 16)
    343294            if i!=3 and (dst.height_mult[i]!=1.0 or dst.width_mult[i]!=1.0):
    344295                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]
    351297
    352298        self.src_width = src_width
    353299        self.src_height = src_height
     
    438384            self.out_height[i] = 0
    439385            self.out_stride[i] = 0
    440386            self.out_size[i] = 0
    441         self.buffer_size = 0
    442387
    443388    def is_closed(self):
    444389        return self.context!=NULL
     
    455400        cdef int height
    456401        cdef int stride
    457402        cdef int result
    458         cdef Py_buffer *py_buffer
     403        cdef size_t pad
    459404        start = time.time()
    460405        iplanes = image.get_planes()
    461406        pixels = image.get_pixels()
     
    468413            iplanes = 1
    469414        else:
    470415            planes = pixels
     416        if self.dst_format.endswith("P"):
     417            pad = self.dst_width
     418        else:
     419            pad = self.dst_width * 4
    471420        #print("convert_image(%s) input=%s, strides=%s" % (image, len(input), strides))
    472421        assert pixels, "failed to get pixels from %s" % image
    473422        assert image.get_width()>=self.src_width, "invalid image width: %s (minimum is %s)" % (image.get_width(), self.src_width)
     
    484433                #(so we just copy the last valid plane in the remaining slots - ugly!)
    485434                input_stride[i] = input_stride[iplanes-1]
    486435                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]
    487448        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]
    491449            result = sws_scale(self.context, input_image, input_stride, 0, self.src_height, output_image, self.out_stride)
    492450        assert result!=0, "sws_scale failed!"
    493451        assert result==self.dst_height, "invalid output height: %s, expected %s" % (result, self.dst_height)
    494452        #now parse the output:
    495         csci = CSCImage()           #keep a reference to memory for cleanup
    496         for i in range(4):
    497             csci.set_plane(i, NULL)
    498453        if self.dst_format.endswith("P"):
    499454            #planar mode, assume 3 planes:
    500455            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)]
    513458        else:
    514459            #assume no planes, plain RGB packed pixels:
    515460            oplanes = ImageWrapper.PACKED
    516461            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])
    519463        elapsed = time.time()-start
    520464        log("%s took %.1fms", self, 1000.0*elapsed)
    521465        self.time += elapsed
    522466        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)
    526468
    527469
    528470def selftest(full=False):
  • xpra/codecs/vpx/decoder.pyx

     
    66import os
    77from xpra.codecs.codec_constants import codec_spec, get_subsampling_divs
    88from xpra.codecs.image_wrapper import ImageWrapper
     9from xpra.buffers.membuf cimport padbuf, MemBuf
    910from xpra.os_util import bytestostr
    1011
    1112from xpra.log import Logger
     
    181182    return VPX_IMG_FMT_I420
    182183
    183184
    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 *ptr
    203         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 
    211185cdef class Decoder:
    212186
    213187    cdef vpx_codec_ctx_t *context
     
    300274        cdef vpx_codec_err_t ret
    301275        cdef int i = 0
    302276        cdef object image
    303         cdef void *padded_buf
     277        cdef MemBuf output_buf
     278        cdef void *output
    304279        cdef Py_ssize_t plane_len = 0
    305280        cdef uint8_t dx, dy
    306281        cdef unsigned int height
     
    322297        strides = []
    323298        pixels = []
    324299        divs = get_subsampling_divs(self.get_colorspace())
    325         image = VPXImageWrapper(0, 0, self.width, self.height, pixels, self.get_colorspace(), 24, strides, 3)
    326300        for i in range(3):
    327301            _, dy = divs[i]
    328302            if dy==1:
     
    335309            strides.append(stride)
    336310
    337311            plane_len = height * stride
     312           
    338313            #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)
    342318
    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)
    344321
    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 image
    348322
    349 
    350323def selftest(full=False):
    351324    global CODECS
    352325    from xpra.codecs.codec_checks import testdecoder
  • xpra/codecs/argb/argb.pyx

     
    66
    77#cython: boundscheck=False, wraparound=False, cdivision=True
    88
     9from xpra.buffers.membuf cimport getbuf, MemBuf
    910
    1011cdef extern from "../../buffers/buffers.h":
    1112    int    object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len)
     
    4647    if argb_len <= 0:
    4748        return None
    4849    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()
    5052    #number of pixels:
    5153    cdef unsigned int i = 0
    5254    while i < argb_len:
     
    5557        rgba[i+2]  = argb[i+3]              #B
    5658        rgba[i+3]  = argb[i]                #A
    5759        i = i + 4
    58     return rgba
     60    return memoryview(rgba_buf)
    5961
    6062def argb_to_rgb(buf):
    6163    assert len(buf) % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % len(buf)
     
    7274    #number of pixels:
    7375    cdef unsigned int mi = argb_len//4                #@DuplicateSignature
    7476    #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()
    7679    cdef unsigned int i = 0, di = 0                          #@DuplicateSignature
    7780    while i < argb_len:
    7881        rgb[di]   = argb[i+1]               #R
     
    8083        rgb[di+2] = argb[i+3]               #B
    8184        di += 3
    8285        i += 4
    83     return rgb
     86    return memoryview(rgb_buf)
    8487
    8588
    8689def bgra_to_rgb(buf):
     
    98101    #number of pixels:
    99102    cdef unsigned int mi = bgra_len//4                #@DuplicateSignature
    100103    #3 bytes per pixel:
    101     rgb = bytearray(mi*3)
    102     cdef unsigned int di = 0                         #@DuplicateSignature
    103     cdef unsigned int si = 0                         #@DuplicateSignature
     104    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
    104107    while si < bgra_len:
    105108        rgb[di]   = bgra[si+2]              #R
    106109        rgb[di+1] = bgra[si+1]              #G
     
    107110        rgb[di+2] = bgra[si]                #B
    108111        di += 3
    109112        si += 4
    110     return rgb
     113    return memoryview(rgb_buf)
    111114
    112115
    113116def bgra_to_rgba(buf):
     
    123126        return None
    124127    assert bgra_len % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % bgra_len
    125128    #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()
    127131    cdef unsigned int i = 0                      #@DuplicateSignature
    128132    while i < bgra_len:
    129133        rgba[i]   = bgra[i+2]           #R
     
    131135        rgba[i+2] = bgra[i]             #B
    132136        rgba[i+3] = bgra[i+3]           #A
    133137        i += 4
    134     return rgba
     138    return memoryview(rgba_buf)
    135139
    136140
    137141def premultiply_argb_in_place(buf):
     
    216220    cdef unsigned int argb                      #@DuplicateSignature
    217221    assert sizeof(int) == 4
    218222    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()
    220225    cdef int i                                  #@DuplicateSignature
    221226    for 0 <= i < argb_len // 4:
    222227        argb = argb_in[i]
     
    239244        argb_out[i*4+G] = g
    240245        argb_out[i*4+R] = r
    241246        argb_out[i*4+A] = a
    242     return argb_out
     247    return memoryview(argb_buf)
  • xpra/codecs/xor/cyxor.pyx

     
    33# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
    44# later version. See the file COPYING for details.
    55
    6 cdef extern from "stdlib.h":
    7     void* malloc(size_t __size)
    8     void free(void* mem)
     6from xpra.buffers.membuf cimport getbuf, MemBuf
    97
    10 
    118cdef extern from "../../buffers/memalign.h":
    129    void *xmemalign(size_t size) nogil
    1310
     
    2421    cdef Py_ssize_t xbuf_len = 0                    #@DuplicatedSignature
    2522    assert object_as_buffer(xor, <const void**> &xbuf, &xbuf_len)==0, "cannot get buffer pointer for %s: %s" % (type(xor), xor)
    2623    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()
    3226    cdef int i                                      #@DuplicatedSignature
    3327    for 0 <= i < cbuf_len:
    3428        obuf[i] = cbuf[i] ^ xbuf[i]
    35     return out_bytes
     29    return memoryview(out_buf)
  • setup.py

     
    165165    nvenc5_ENABLED          = pkg_config_ok("--exists", "nvenc5")
    166166
    167167csc_opencl_ENABLED      = pkg_config_ok("--exists", "OpenCL") and check_pyopencl_AMD()
    168 memoryview_ENABLED      = sys.version>='2.7'
    169168
    170169annotate_ENABLED        = True
    171170warn_ENABLED            = True
     
    183182            "vpx", "webp", "pillow",
    184183            "dec_avcodec2", "csc_swscale",
    185184            "csc_opencl", "csc_cython",
    186             "memoryview",
    187185            "bencode", "cython_bencode",
    188186            "clipboard",
    189187            "server", "client", "dbus", "x11", "gtk_x11",
     
    258256        print("Warning: you probably want to build at least the client or server!")
    259257    if not pillow_ENABLED:
    260258        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)
    264259
    265260
    266261#*******************************************************************************
     
    596591            add_to_keywords(kw, 'extra_link_args', "-Wall")
    597592    if strict_ENABLED:
    598593        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
    601595            add_to_keywords(kw, 'extra_link_args', "/WX")
    602596        else:
    603597            if os.environ.get("CC", "").find("clang")>=0:
     
    616610                        #/usr/include/gtk-2.0/gtk/gtkitemfactory.h:47:1: error: function declaration isn't a prototype [-Werror=strict-prototypes]
    617611                        #"-Wno-error=strict-prototypes",
    618612                        ]
    619             for eif in eifd:
    620                 add_to_keywords(kw, 'extra_compile_args', eif)
     613            add_to_keywords(kw, 'extra_compile_args', *eifd)
    621614    if PIC_ENABLED and not is_msvc():
    622615        add_to_keywords(kw, 'extra_compile_args', "-fPIC")
    623616    if debug_ENABLED:
     
    624617        if is_msvc():
    625618            add_to_keywords(kw, 'extra_compile_args', '/Zi')
    626619        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')
    629621            if get_gcc_version()>=[4, 8]:
    630622                add_to_keywords(kw, 'extra_compile_args', '-fsanitize=address')
    631623                add_to_keywords(kw, 'extra_link_args', '-fsanitize=address')
     
    17321724
    17331725
    17341726#*******************************************************************************
    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
     1727buffers_c = "xpra/buffers/buffers.c"
    17421728#convenience grouping for codecs:
    17431729membuffers_c = ["xpra/buffers/memalign.c", "xpra/inline.c", buffers_c]
    17441730
     
    17471733toggle_packages(server_ENABLED or gtk2_ENABLED or gtk3_ENABLED, "xpra.gtk_common", "xpra.clipboard")
    17481734
    17491735
     1736add_packages("xpra.buffers")
     1737buffers_pkgconfig = pkgconfig()
     1738cython_add(Extension("xpra.buffers.membuf",
     1739            ["xpra/buffers/membuf.pyx"]+membuffers_c, **buffers_pkgconfig))
     1740
     1741
    17501742toggle_packages(dbus_ENABLED, "xpra.dbus")
    17511743toggle_packages(x11_ENABLED, "xpra.x11", "xpra.x11.bindings")
    17521744if x11_ENABLED: