xpra icon
Bug tracker and wiki

Ticket #328: yuv-codec-v3.patch

File yuv-codec-v3.patch, 93.7 KB (added by Antoine Martin, 7 years ago)

latest work in progress

  • setup.py

     
    3737
    3838
    3939
    40 x264_ENABLED = True
     40enc_x264_ENABLED = True
    4141
    4242
    4343
     
    121121
    122122
    123123
     124dec_avcodec_ENABLED = True
     125
     126
     127
     128csc_swscale_ENABLED = True
     129
     130
     131
     132csc_nvcuda_ENABLED = False
     133
     134
     135
    124136#allow some of these flags to be modified on the command line:
    125 SWITCHES = ("x264", "vpx", "webp", "rencode", "clipboard",
     137SWITCHES = ("enc_x264", "dec_avcodec", "csc_swscale", "csc_nvcuda", "vpx", "webp", "rencode", "clipboard",
    126138            "server", "client", "x11",
    127139            "gtk2", "gtk3", "qt4",
    128140            "sound", "cyxor", "cymaths", "opengl", "argb",
     
    423435                   "xpra/net/rencode/rencode.c",
    424436                   "xpra/codecs/vpx/encoder.c",
    425437                   "xpra/codecs/vpx/decoder.c",
    426                    "xpra/codecs/x264/encoder.c",
    427                    "xpra/codecs/x264/decoder.c",
     438                   "xpra/codecs/enc_x264/encoder.c",
     439                   "xpra/codecs/dec_avcodec/decoder.c",
     440                   "xpra/codecs/csc_swscale/colorspace_converter.c",
     441                   "xpra/codecs/csc_nvcuda/colorspace_converter.c",
    428442                   "xpra/codecs/xor/cyxor.c",
    429443                   "xpra/codecs/argb/argb.c",
    430444                   "xpra/server/stats/cymaths.c",
     
    492506    #and stdint.h:
    493507    win32_include_dir = os.path.join(os.getcwd(), "win32")
    494508
    495     #libav is needed for both swscale and x264,
    496     #you can find binary builds here:
    497     #http://win32.libav.org/releases/
    498     #the path after unzipping may look like this:
    499     #libav_path="C:\\libav-9.1-win32\\win32\\usr"
    500     #but we use something more generic, without the version numbers:
    501     libav_path="C:\\libav-win32\\win32\\usr"
    502     libav_include_dir   = os.path.join(libav_path, "include")
    503     libav_lib_dir       = os.path.join(libav_path, "lib")
    504     libav_bin_dir       = os.path.join(libav_path, "bin")
     509    #ffmpeg is needed for both swscale and x264:
     510    libffmpeg_path="C:\\ffmpeg-win32-bin"
     511    libffmpeg_include_dir   = os.path.join(libffmpeg_path, "include")
     512    libffmpeg_lib_dir       = os.path.join(libffmpeg_path, "lib")
     513    libffmpeg_bin_dir       = os.path.join(libffmpeg_path, "bin")
    505514    #x264 (direct from build dir.. yuk - sorry!):
    506515    x264_path ="C:\\x264"
    507516    x264_include_dir    = x264_path
     
    545554            if bindir not in sys.path:
    546555                sys.path.append(bindir)
    547556        kw = dict(ekw)
    548         if "x264" in packages[0]:
    549             add_to_PATH(libav_bin_dir)
     557        if "libavcodec" in packages[0]:
     558            add_to_PATH(libffmpeg_bin_dir)
     559            add_to_keywords(kw, 'include_dirs', win32_include_dir, libffmpeg_include_dir)
     560            add_to_keywords(kw, 'libraries', "avcodec", "avutil")
     561            add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libffmpeg_lib_dir)
     562            add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libffmpeg_bin_dir)
     563            add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
     564            checkdirs(libffmpeg_include_dir, libffmpeg_lib_dir, libffmpeg_bin_dir)
     565        elif "libswscale" in packages[0]:
     566            add_to_PATH(libffmpeg_bin_dir)
     567            add_to_keywords(kw, 'include_dirs', win32_include_dir, libffmpeg_include_dir)
     568            add_to_keywords(kw, 'libraries', "swscale", "avutil")
     569            add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libffmpeg_lib_dir)
     570            add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libffmpeg_bin_dir)
     571            add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
     572            checkdirs(libffmpeg_include_dir, libffmpeg_lib_dir, libffmpeg_bin_dir)
     573        elif "x264" in packages[0]:
     574            add_to_PATH(libffmpeg_bin_dir)
    550575            add_to_PATH(x264_bin_dir)
    551             add_to_keywords(kw, 'include_dirs', win32_include_dir, libav_include_dir, x264_include_dir)
    552             add_to_keywords(kw, 'libraries', "libx264", "swscale", "avcodec", "avutil")
    553             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libav_lib_dir)
    554             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libav_bin_dir)
     576            add_to_keywords(kw, 'include_dirs', win32_include_dir, x264_include_dir)
     577            add_to_keywords(kw, 'libraries', "libx264")
    555578            add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % x264_lib_dir)
    556579            add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
    557             checkdirs(libav_include_dir, libav_lib_dir, libav_bin_dir)
     580            checkdirs(x264_include_dir, x264_lib_dir)
    558581        elif "vpx" in packages[0]:
    559             add_to_PATH(libav_bin_dir)
    560             add_to_keywords(kw, 'include_dirs', win32_include_dir, vpx_include_dir, libav_include_dir)
    561             add_to_keywords(kw, 'libraries', "vpxmt", "vpxmtd", "swscale", "avcodec", "avutil")
     582            add_to_PATH(libffmpeg_bin_dir)
     583            add_to_keywords(kw, 'include_dirs', win32_include_dir, vpx_include_dir)
     584            add_to_keywords(kw, 'libraries', "vpxmt", "vpxmtd")
    562585            add_to_keywords(kw, 'extra_link_args', "/NODEFAULTLIB:LIBCMT")
    563586            add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % vpx_lib_dir)
    564             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libav_lib_dir)
    565             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libav_bin_dir)
    566587            add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
    567             checkdirs(libav_include_dir, vpx_lib_dir, libav_lib_dir, libav_bin_dir)
     588            checkdirs(vpx_include_dir, vpx_lib_dir)
    568589        elif "pygobject-2.0" in packages[0]:
    569590            dirs = (python_include_path,
    570591                    pygtk_include_dir, atk_include_dir, gtk2_include_dir,
     
    699720                   ('icons', glob.glob('icons\\*.*')),
    700721                   ('Microsoft.VC90.CRT', glob.glob('%s\\Microsoft.VC90.CRT\\*.*' % C_DLLs)),
    701722                   ('Microsoft.VC90.MFC', glob.glob('%s\\Microsoft.VC90.MFC\\*.*' % C_DLLs)),
    702                    ('', glob.glob('%s\\bin\\*.dll' % libav_path)),
     723                   ('', glob.glob('%s\\bin\\*.dll' % libffmpeg_path)),
    703724                   ]
    704725
    705726    if webp_ENABLED:
     
    909930
    910931
    911932
    912 toggle_packages(x264_ENABLED, "xpra.codecs.x264")
    913 if x264_ENABLED:
    914     x264_pkgconfig = pkgconfig("x264", "libswscale", "libavcodec")
    915     cython_add(Extension("xpra.codecs.x264.encoder",
    916                 ["xpra/codecs/x264/encoder.pyx", "xpra/codecs/x264/x264lib.c"],
     933toggle_packages(enc_x264_ENABLED, "xpra.codecs.enc_x264")
     934if enc_x264_ENABLED:
     935    x264_pkgconfig = pkgconfig("x264")
     936    cython_add(Extension("xpra.codecs.enc_x264.encoder",
     937                ["xpra/codecs/enc_x264/encoder.pyx", "xpra/codecs/enc_x264/enc_x264.c"],
    917938                **x264_pkgconfig), min_version=(0, 16))
    918     cython_add(Extension("xpra.codecs.x264.decoder",
    919                 ["xpra/codecs/x264/decoder.pyx", "xpra/codecs/x264/x264lib.c"],
    920                 **x264_pkgconfig), min_version=(0, 16))
    921939
     940toggle_packages(dec_avcodec_ENABLED, "xpra.codecs.dec_avcodec")
     941if dec_avcodec_ENABLED:
     942    avcodec_pkgconfig = pkgconfig("libavcodec")
     943    cython_add(Extension("xpra.codecs.dec_avcodec.decoder",
     944                ["xpra/codecs/dec_avcodec/decoder.pyx", "xpra/codecs/dec_avcodec/dec_avcodec.c"],
     945                **avcodec_pkgconfig), min_version=(0, 16))
    922946
     947toggle_packages(csc_swscale_ENABLED, "xpra.codecs.csc_swscale")
     948if csc_swscale_ENABLED:
     949    swscale_pkgconfig = pkgconfig("libswscale")
     950    cython_add(Extension("xpra.codecs.csc_swscale.colorspace_converter",
     951                ["xpra/codecs/csc_swscale/colorspace_converter.pyx", "xpra/codecs/csc_swscale/csc_swscale.c"],
     952                **swscale_pkgconfig), min_version=(0, 16))
    923953
     954toggle_packages(csc_nvcuda_ENABLED, "xpra.codecs.csc_nvcuda")
     955if csc_nvcuda_ENABLED:
     956    nvcuda_pkgconfig = pkgconfig("cuda")
     957    cython_add(Extension("xpra.codecs.csc_nvcuda.colorspace_converter",
     958                ["xpra/codecs/csc_nvcuda/colorspace_converter.pyx", "xpra/codecs/csc_nvcuda/csc_nvcuda.c"],
     959                **nvcuda_pkgconfig), min_version=(0, 16))
     960
     961
    924962toggle_packages(vpx_ENABLED, "xpra.codecs.vpx")
    925963if vpx_ENABLED:
    926     vpx_pkgconfig = pkgconfig(["libvpx", "vpx"], "libswscale", "libavcodec")
     964    vpx_pkgconfig = pkgconfig(["libvpx", "vpx"])
    927965    cython_add(Extension("xpra.codecs.vpx.encoder",
    928966                ["xpra/codecs/vpx/encoder.pyx", "xpra/codecs/vpx/vpxlib.c"],
    929967                **vpx_pkgconfig), min_version=(0, 16))
  • xpra/client/gl/gl_window_backing.py

     
    318318        drawable.gl_end()
    319319        return True
    320320
    321     def do_video_paint(self, coding, img_data, x, y, w, h, options, callbacks):
    322         debug("do_video_paint: options=%s, decoder=%s", options, type(self._video_decoder))
    323         err, rowstrides, data = self._video_decoder.decompress_image_to_yuv(img_data, options)
    324         csc_pixel_format = options.get("csc_pixel_format", -1)
    325         #this needs to be done here so we still hold the video_decoder lock:
    326         pixel_format = self._video_decoder.get_pixel_format(csc_pixel_format)
    327         success = err==0 and data and len(data)==3
    328         if not success:
    329             log.error("do_video_paint: %s decompression error %s on %s bytes of compressed picture data for %sx%s pixels, options=%s",
    330                       coding, err, len(img_data), w, h, options)
    331             gobject.idle_add(fire_paint_callbacks, callbacks, False)
    332             return
    333         gobject.idle_add(self.do_gl_yuv_paint, x, y, w, h, data, rowstrides, pixel_format, callbacks)
     321    def paint_yuv(self, x, y, w, h, img, pixel_format, options, callbacks):
     322        #we need to run in UI thread from here on!
     323        debug("paint_yuv(..) will call via idle_add")
     324        gobject.idle_add(self.do_gl_yuv_paint, x, y, w, h, img, pixel_format, callbacks)
    334325
    335     def do_gl_yuv_paint(self, x, y, w, h, img_data, rowstrides, pixel_format, callbacks):
     326    def do_gl_yuv_paint(self, x, y, w, h, img, pixel_format, callbacks):
    336327        #this function runs in the UI thread, no video_decoder lock held
    337328        drawable = self.gl_init()
    338329        if not drawable:
     
    341332            return
    342333        try:
    343334            try:
    344                 self.update_texture_yuv(img_data, x, y, w, h, rowstrides, pixel_format)
     335                self.update_texture_yuv(x, y, w, h, img, pixel_format)
    345336                if self.paint_screen:
    346337                    # Update FBO texture
    347338                    self.render_yuv_update(x, y, x+w, y+h)
     
    354345        finally:
    355346            drawable.gl_end()
    356347
    357     def update_texture_yuv(self, img_data, x, y, width, height, rowstrides, pixel_format):
     348    def update_texture_yuv(self, x, y, width, height, img, pixel_format):
    358349        assert x==0 and y==0
    359350        assert self.textures is not None, "no OpenGL textures!"
     351        debug("update_texture_yuv(%s)", (x, y, width, height, img, pixel_format))
    360352
    361353        if self.pixel_format is None or self.pixel_format!=pixel_format or self.texture_size!=(width, height):
    362354            self.pixel_format = pixel_format
     
    396388        divs = get_subsampling_divs(pixel_format)
    397389        U_width = 0
    398390        U_height = 0
     391        rowstrides = img.get_rowstride()
     392        img_data = img.get_pixels()
    399393        for texture, index in ((GL_TEXTURE0, 0), (GL_TEXTURE1, 1), (GL_TEXTURE2, 2)):
    400394            (div_w, div_h) = divs[index]
    401395            glActiveTexture(texture)
  • xpra/client/ui_client_base.py

     
    254254
    255255    def get_core_encodings(self):
    256256        encodings = ["rgb24"]
    257         from xpra.scripts.config import has_PIL, has_vpx, has_x264, has_webp
     257        from xpra.scripts.config import has_PIL, has_vpx_dec, has_dec_avcodec, has_webp, has_csc_swscale
    258258        encs = (
    259               (has_vpx    , ["vpx"]),
    260               (has_x264   , ["x264"]),
    261               (has_webp   , ["webp"]),
    262               (has_PIL    , ["png", "png/L", "png/P", "jpeg"]),
     259              (has_vpx_dec & has_csc_swscale        , ["vpx"]),
     260              (has_dec_avcodec & has_csc_swscale    , ["x264"]),
     261              (has_webp     , ["webp"]),
     262              (has_PIL      , ["png", "png/L", "png/P", "jpeg"]),
    263263               )
    264264        log("get_core_encodings() encs=%s", encs)
    265265        for test, formats in encs:
     
    423423        capabilities["bell"] = self.client_supports_bell
    424424        capabilities["encoding.client_options"] = True
    425425        capabilities["encoding_client_options"] = True
     426        capabilities["encoding.csc_atoms"] = True
    426427        capabilities["rgb24zlib"] = True
    427428        capabilities["encoding.rgb24zlib"] = True
    428429        capabilities["named_cursors"] = False
  • xpra/client/window_backing_base.py

     
    1616from xpra.os_util import BytesIOClass
    1717
    1818try:
    19     from xpra.codecs.x264.decoder import Decoder as x264_Decoder     #@UnresolvedImport
     19    from xpra.codecs.dec_avcodec.decoder import Decoder as x264_Decoder     #@UnresolvedImport
    2020except:
    2121    pass
    2222try:
     
    5757        self._last_pixmap_data = None
    5858        self._video_use_swscale = True
    5959        self._video_decoder = None
    60         self._video_decoder_lock = Lock()
     60        self._csc_decoder = None
     61        self._decoder_lock = Lock()
    6162        self.draw_needs_refresh = True
    6263        self.mmap = None
    6364        self.mmap_enabled = False
     
    6869
    6970    def close(self):
    7071        log("%s.close() video_decoder=%s", type(self), self._video_decoder)
    71         if self._video_decoder:
     72        if self._video_decoder or self._csc_decoder:
    7273            try:
    73                 self._video_decoder_lock.acquire()
    74                 self._video_decoder.clean()
    75                 self._video_decoder = None
     74                self._decoder_lock.acquire()
     75                self.do_clean_video_decoder()
     76                self.do_clean_csc_decoder()
    7677            finally:
    77                 self._video_decoder_lock.release()
     78                self._decoder_lock.release()
    7879
     80    def do_clean_video_decoder(self):
     81        if self._video_decoder:
     82            self._video_decoder.clean()
     83            self._video_decoder = None
    7984
     85    def do_clean_csc_decoder(self):
     86        if self._csc_decoder:
     87            self._csc_decoder.clean()
     88            self._csc_decoder = None
     89
    8090    def jpegimage(self, img_data, width, height):
    8191        """ can be called from any thread """
    8292        assert has_PIL
     
    212222    def paint_with_video_decoder(self, factory, coding, img_data, x, y, width, height, options, callbacks):
    213223        assert x==0 and y==0
    214224        try:
    215             self._video_decoder_lock.acquire()
     225            self._decoder_lock.acquire()
    216226            if self._video_decoder:
    217227                if self._video_decoder.get_type()!=coding:
    218228                    if DRAW_DEBUG:
     
    233243                log.info("paint_with_video_decoder: options=%s, decoder=%s", options, type(self._video_decoder))
    234244            self.do_video_paint(coding, img_data, x, y, width, height, options, callbacks)
    235245        finally:
    236             self._video_decoder_lock.release()
     246            self._decoder_lock.release()
    237247        return  False
    238248
    239249    def do_video_paint(self, coding, img_data, x, y, width, height, options, callbacks):
    240250        if DRAW_DEBUG:
    241251            log.info("paint_with_video_decoder: options=%s, decoder=%s", options, type(self._video_decoder))
    242         err, data, rowstride = self._video_decoder.decompress_image_to_rgb(img_data, options)
    243         success = err==0 and data is not None and rowstride>0
    244         if not success:
    245             raise Exception("paint_with_video_decoder: %s decompression error %s on %s bytes of picture data for %sx%s pixels, options=%s" % (
    246                       coding, err, len(img_data), width, height, options))
     252        img = self._video_decoder.decompress_image_to_yuv(img_data, options)
     253        if not img:
     254            raise Exception("paint_with_video_decoder: %s decompression error on %s bytes of picture data for %sx%s pixels, options=%s" % (
     255                      coding, len(img_data), width, height, options))
     256        YUV_FORMAT = "YUV420P"
     257        self.paint_yuv(x, y, width, height, img, YUV_FORMAT, options, callbacks)
     258
     259    def paint_yuv(self, x, y, w, h, img, pixel_format, options, callbacks):
     260        rgb_format = "RGB"  #we may want to be able to change this (RGBA, BGR, ..)
     261        if self._csc_decoder is not None:
     262            if self._csc_decoder.get_src_format()!=pixel_format:
     263                log.info("paint_yuv csc: switching src format from %s to %s", self.wid, self._csc_encoder.get_src_format(), pixel_format)
     264                self.do_clean_csc_decoder()
     265            if self._csc_decoder.get_dst_format()!=rgb_format:
     266                log.info("paint_yuv csc: switching dst format from %s to %s", self.wid, self._csc_encoder.get_dst_format(), rgb_format)
     267                self.do_clean_csc_decoder()
     268        if self._csc_decoder is None:
     269            from xpra.codecs.csc_swscale.colorspace_converter import ColorspaceConverter    #@UnresolvedImport
     270            self._csc_decoder = ColorspaceConverter()
     271            self._csc_decoder.init_context(w, h, pixel_format, rgb_format)
     272        rgb = self._csc_decoder.convert_image(img)
     273        assert rgb.get_planes()==1, "invalid number of planes for %s: %s" % (rgb_format, rgb.get_planes())
     274        data = rgb.get_pixels()[0]
     275        rowstride = rgb.get_rowstride()[0]
    247276        #this will also take care of firing callbacks (from the UI thread):
    248         self.idle_add(self.do_paint_rgb24, data, x, y, width, height, rowstride, options, callbacks)
     277        self.idle_add(self.do_paint_rgb24, data, x, y, w, h, rowstride, options, callbacks)
    249278
    250279    def paint_mmap(self, img_data, x, y, width, height, rowstride, options, callbacks):
    251280        """ must be called from UI thread """
  • xpra/codecs/__init__.pyc

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
  • xpra/codecs/codec_constants.py

    Property changes on: xpra/codecs/__init__.pyc
    ___________________________________________________________________
    Added: svn:mime-type
    ## -0,0 +1 ##
    +application/octet-stream
    \ No newline at end of property
     
    1111def get_subsampling_divs(pixel_format):
    1212    # Return size dividers for the given pixel format
    1313    #  (Y_w, Y_h), (U_w, U_h), (V_w, V_h)
    14     if pixel_format==YUV420P:
     14    if pixel_format==YUV420P or pixel_format=="YUV420P":
    1515        return (1, 1), (2, 2), (2, 2)
    16     elif pixel_format==YUV422P:
     16    elif pixel_format==YUV422P or pixel_format=="YUV422P":
    1717        return (1, 1), (2, 1), (2, 1)
    18     elif pixel_format==YUV444P:
     18    elif pixel_format==YUV444P or pixel_format=="YUV444P":
    1919        return (1, 1), (1, 1), (1, 1)
    2020    raise Exception("invalid pixel format: %s" % pixel_format)
    2121
  • xpra/codecs/csc_swscale/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2012, 2013 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
  • xpra/codecs/csc_swscale/colorspace_converter.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2013 Arthur Huillet
     3# Copyright (C) 2012, 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
     8from xpra.codecs.codec_constants import get_subsampling_divs, YUV420P
     9from xpra.server.image_wrapper import ImageWrapper
     10
     11cdef extern from "string.h":
     12    void * memcpy ( void * destination, void * source, size_t num )
     13    void * memset ( void * ptr, int value, size_t num )
     14
     15cdef extern from "stdlib.h":
     16    void free(void *ptr)
     17
     18cdef extern from *:
     19    ctypedef unsigned long size_t
     20
     21cdef extern from "Python.h":
     22    ctypedef int Py_ssize_t
     23    ctypedef object PyObject
     24    ctypedef void** const_void_pp "const void**"
     25    int PyObject_AsReadBuffer(object obj, void ** buffer, Py_ssize_t * buffer_len) except -1
     26
     27ctypedef unsigned char uint8_t
     28ctypedef void csc_swscale_ctx
     29cdef extern from "csc_swscale.h":
     30    csc_swscale_ctx *init_csc(int width, int height, const char *src_format_str, const char *dst_format_str)
     31    void free_csc(csc_swscale_ctx *ctx)
     32    int csc_image(csc_swscale_ctx *ctx, const uint8_t *input_image[3], const int in_stride[3], uint8_t *out[3], int out_stride[3])
     33    void free_csc_image(uint8_t *buf[3])
     34
     35PIXEL_FORMATS = ("XRGB", "BGRX", "ARGB", "BGRA", "RGB",
     36                 "YUV420P")   #, "YUV422P", "YUV444P")
     37
     38
     39cdef class CSCImage:
     40    """
     41        Allows us to call free_csc_image
     42        when this object is garbage collected
     43    """
     44    cdef uint8_t *buf[3]
     45    cdef int freed
     46
     47    cdef set_plane(self, int plane, uint8_t *buf):
     48        assert plane in (0, 1, 2)
     49        self.buf[plane] = buf
     50
     51    def __dealloc__(self):
     52        print("CSCImage.__dealloc__() calling free()")
     53        self.free()
     54
     55    def free(self):
     56        print("CSCImage.free() free_csc_image(..) already? %s" % self.freed)
     57        if self.freed==0:
     58            self.freed = 1
     59            free_csc_image(self.buf)
     60
     61
     62class YUVImageWrapper(ImageWrapper):
     63
     64    def free(self):                             #@DuplicatedSignature
     65        print("YUVImageWrapper.free() csc_image=%s" % self.csc_image)
     66        if self.csc_image:
     67            self.csc_image.free()
     68            self.csc_image = None
     69
     70cdef class ColorspaceConverter:
     71    cdef int frames
     72    cdef csc_swscale_ctx *context
     73    cdef int width
     74    cdef int height
     75    cdef char* src_format
     76    cdef char* dst_format
     77
     78    def init_context(self, int width, int height, src_format, dst_format):    #@DuplicatedSignature
     79        self.width = width
     80        self.height = height
     81        #ugly trick to use a string which won't go away from underneath us:
     82        assert src_format in PIXEL_FORMATS, "invalid source format: %s" % src_format
     83        for x in PIXEL_FORMATS:
     84            if x==src_format:
     85                self.src_format = x
     86                break
     87        assert dst_format in PIXEL_FORMATS, "invalid destination format: %s" % dst_format
     88        for x in PIXEL_FORMATS:
     89            if x==dst_format:
     90                self.dst_format = x
     91                break
     92        self.frames = 0
     93        self.context = init_csc(width, height, src_format, dst_format)
     94
     95    def is_closed(self):
     96        return self.context==NULL
     97
     98    def __dealloc__(self):                  #@DuplicatedSignature
     99        self.clean()
     100
     101    def get_width(self):
     102        return self.width
     103
     104    def get_height(self):
     105        return self.height
     106
     107    def get_type(self):
     108        return  "swscale"
     109
     110    def get_src_format(self):
     111        return self.src_format
     112
     113    def get_dst_format(self):
     114        return self.dst_format
     115
     116
     117    def clean(self):                        #@DuplicatedSignature
     118        if self.context!=NULL:
     119            free_csc(self.context)
     120            free(self.context)
     121            self.context = NULL
     122   
     123    def convert_image(self, image):
     124        cdef Py_ssize_t pic_buf_len = 0
     125        assert self.context!=NULL
     126        cdef const uint8_t *input_image[3]
     127        cdef uint8_t *output_image[3]
     128        cdef int input_stride[3]
     129        cdef int output_stride[3]
     130        cdef int planes
     131        cdef int i
     132        planes = image.get_planes()
     133        assert planes in (0, 1, 3), "invalid number of planes: %s" % planes
     134        input = image.get_pixels()
     135        strides = image.get_rowstride()
     136        if planes==0:
     137            #magic: if planes==0, this is an XImageWrapper... with raw pixels/rowstride
     138            input = [input]
     139            strides = [strides]
     140            planes = 1
     141        print("convert_image(%s) input=%s, strides=%s" % (image, len(input), strides))
     142        assert len(input)==planes, "expected %s planes but found %s" % (planes, len(input))
     143        assert len(strides)==planes, "expected %s rowstrides but found %s" % (planes, len(strides))
     144        for i in range(planes):
     145            input_stride[i] = strides[i]
     146            PyObject_AsReadBuffer(input[i], <const_void_pp> &input_image[i], &pic_buf_len)
     147        result = csc_image(self.context, input_image, input_stride, output_image, output_stride)
     148        if result != 0:
     149            return None
     150        #now parse the output:
     151        if self.dst_format.endswith("P"):
     152            nplanes = 3
     153            divs = get_subsampling_divs(self.dst_format)
     154        else:
     155            nplanes = 1
     156            divs = (1, 1),
     157        print("convert_image(%s) nplanes=%s, divs=%s" % (image, nplanes, divs))
     158        csci = CSCImage()           #keep a reference to memory for cleanup
     159        out = []
     160        strides = []
     161        for i in range(nplanes):
     162            _, dy = divs[i]
     163            if dy==1:
     164                height = self.height
     165            elif dy==2:
     166                height = (self.height+1)>>1
     167            else:
     168                raise Exception("invalid height divisor %s" % dy)
     169            stride = output_stride[i]
     170            if stride>0 and output_image[i]!=NULL:
     171                plane = (<char *>output_image[i])[:(height * stride)]
     172            else:
     173                stride = 0
     174                plane = None
     175            csci.set_plane(i, output_image[i])
     176            out.append(plane)
     177            strides.append(stride)
     178        yuv = YUVImageWrapper(0, 0, self.width, self.height, out, self.dst_format, 24, strides)
     179        yuv.csc_image = csci
     180        print("convert_image(%s)=%s" % (image, yuv))
     181        return yuv
  • xpra/codecs/csc_swscale/csc_swscale.c

     
     1/* This file is part of Xpra.
     2 * Copyright (C) 2012 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3 * Copyright (C) 2012, 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
     8#include <stdio.h>
     9#include <stdlib.h>
     10#include <string.h>
     11#include <sys/types.h>
     12#include <sys/stat.h>
     13#include <fcntl.h>
     14#include <stdint.h>
     15#include <inttypes.h>
     16
     17#ifdef _WIN32
     18#define _STDINT_H
     19#endif
     20#if !defined(__APPLE__)
     21#include <malloc.h>
     22#endif
     23
     24#include "csc_swscale.h"
     25#include <libswscale/swscale.h>
     26
     27//not honoured on MS Windows:
     28#define MEMALIGN 1
     29//not honoured on OSX:
     30#define MEMALIGN_ALIGNMENT 32
     31
     32static const int swscale_flags = SWS_BICUBLIN | SWS_ACCURATE_RND;
     33/*
     34Speed results at 1024x1024 on Athlon II X4 620:
     35
     36   BICUBLIN | SWS_ACCURATE_RND 11ms/frame
     37   BICUBIC | SWS_ACCURATE_RND 14ms/frame
     38   BICUBIC                                         7ms/frame
     39   FAST_BILINEAR | SWS_ACCURATE_RND 9ms/frame
     40   FAST_BILINEAR               6ms/frame
     41   */
     42
     43/** Context for csc_swscale_lib
     44 * convert colorspaces with libswscale
     45 */
     46struct csc_swscale_ctx {
     47        int width;
     48        int height;
     49        enum PixelFormat src_format;
     50        enum PixelFormat dst_format;
     51        struct SwsContext *sws_ctx;
     52};
     53
     54
     55/* string format name <-> swscale format correspondance */
     56static const struct {
     57        enum PixelFormat sws_pixfmt;
     58        float width_mult[3]; // width-to-stride multiplier for each plane
     59        float height_mult[3]; // height-to-plane-height multiplier for each plane
     60        const char *str;
     61} sws_formats[] = {
     62        { PIX_FMT_RGB24,   { 3, 0, 0 },     { 1, 0, 0 },     "RGB"  },
     63#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 14, 100)
     64        { PIX_FMT_0RGB,    { 4, 0, 0 },     { 1, 0, 0 },     "XRGB" },
     65        { PIX_FMT_BGR0,    { 4, 0, 0 },     { 1, 0, 0 },     "BGRX" },
     66#else
     67        { PIX_FMT_ARGB,    { 4, 0, 0 },     { 1, 0, 0 },     "XRGB" },
     68        { PIX_FMT_BGRA,    { 4, 0, 0 },     { 1, 0, 0 },     "BGRX" },
     69#endif
     70        { PIX_FMT_ARGB,    { 4, 0, 0 },     { 1, 0, 0 },     "ARGB" },
     71        { PIX_FMT_BGRA,    { 4, 0, 0 },     { 1, 0, 0 },     "BGRA" },
     72        { PIX_FMT_YUV420P, { 1, 0.5, 0.5 }, { 1, 0.5, 0.5 }, "YUV420P" },
     73        { PIX_FMT_YUV422P, { 1, 0.5, 0.5 }, { 1, 1, 1 },     "YUV422P" },
     74        { PIX_FMT_YUV444P, { 1, 1, 1 },     { 1, 1, 1 },     "YUV444P" }
     75};
     76
     77#define TOTAL_FORMATS (int)(sizeof(sws_formats)/sizeof(sws_formats[0]))
     78
     79static enum PixelFormat get_swscale_format(const char *str)
     80{
     81        int i;
     82        for (i = 0; i < TOTAL_FORMATS; i++) {
     83                if (!strcmp(sws_formats[i].str, str))
     84                        return sws_formats[i].sws_pixfmt;
     85        }
     86        fprintf(stderr, "Unknown pixel format specified: %s\n", str);
     87        return PIX_FMT_NONE;
     88}
     89
     90static int get_plane_dimensions(enum PixelFormat fmt, int width, int height, int stride[3], int plane_height[3])
     91{
     92        unsigned int i;
     93        int found = -1;
     94        for (i = 0; i < TOTAL_FORMATS; i++) {
     95                if (sws_formats[i].sws_pixfmt == fmt)
     96                        break;
     97        }
     98
     99        if (i == TOTAL_FORMATS) {
     100                fprintf(stderr, "Unknown pixel format specified: %d\n", fmt);
     101                return 1;
     102        }
     103
     104        found = i;
     105
     106#define ALIGN4(X) (((int)(X)+3)&~3)
     107        for (i = 0; i < 3; i++) {
     108                stride[i] = ALIGN4(width * sws_formats[found].width_mult[i]);
     109                plane_height[i] = height * sws_formats[found].height_mult[i];
     110        }
     111
     112        return 0;
     113}
     114
     115static void *xmemalign(size_t size)
     116{
     117#ifdef MEMALIGN
     118#ifdef _WIN32
     119        //_aligned_malloc and _aligned_free lead to a memleak
     120        //well done Microsoft, I didn't think you could screw up this badly
     121        //and thank you for wasting my time once again
     122        return malloc(size);
     123#elif defined(__APPLE__) || defined(__OSX__)
     124        //Crapple version: "all memory allocations are 16-byte aligned"
     125        //no choice, this is what you get
     126        return malloc(size);
     127#else
     128        //not WIN32 and not APPLE/OSX, assume POSIX:
     129        void *memptr = NULL;
     130        if (posix_memalign(&memptr, MEMALIGN_ALIGNMENT, size))
     131                return NULL;
     132        return memptr;
     133#endif
     134//MEMALIGN not set:
     135#else
     136        return malloc(size);
     137#endif
     138}
     139
     140struct csc_swscale_ctx *init_csc(int width, int height, const char *src_format_str, const char *dst_format_str)
     141{
     142        struct csc_swscale_ctx *ctx = malloc(sizeof(struct csc_swscale_ctx));
     143        if (!ctx)
     144                return NULL;
     145
     146        ctx->width = width;
     147        ctx->height = height;
     148        ctx->src_format = get_swscale_format(src_format_str);
     149        ctx->dst_format = get_swscale_format(dst_format_str);
     150
     151        if (ctx->src_format == PIX_FMT_NONE || ctx->dst_format == PIX_FMT_NONE) {
     152                fprintf(stderr, "Invalid source or destination pixel format\n");
     153                goto err;
     154        }
     155
     156        ctx->sws_ctx = sws_getContext(ctx->width, ctx->height, ctx->src_format, ctx->width, ctx->height, ctx->dst_format, swscale_flags, NULL, NULL, NULL);
     157
     158        if (!ctx->sws_ctx) {
     159                fprintf(stderr, "sws_getContext returned NULL\n");
     160                goto err;
     161        }
     162
     163        return ctx;
     164
     165err:
     166        free(ctx);
     167        return NULL;
     168}
     169
     170void free_csc(struct csc_swscale_ctx *ctx)
     171{
     172        if (ctx && ctx->sws_ctx)
     173                sws_freeContext(ctx->sws_ctx);
     174}
     175
     176void free_csc_image(uint8_t *buf[3])
     177{
     178        free(buf[0]);
     179        buf[0] = buf[1] = buf[2] = NULL;
     180}
     181
     182int csc_image(struct csc_swscale_ctx *ctx, const uint8_t *in[3], const int in_stride[3], uint8_t *out[3], int out_stride[3])
     183{
     184        int out_height[3];
     185        int buffer_size;
     186       
     187        if (!ctx || !ctx->sws_ctx)
     188                return 1;
     189
     190        // Compute output buffer size
     191        get_plane_dimensions(ctx->dst_format, ctx->width, ctx->height, out_stride, out_height);
     192        buffer_size = (out_stride[0] * out_height[0] + out_stride[1] * out_height[1] + out_stride[2] * out_height[2]);
     193
     194        // Allocate output buffer
     195        out[0] = xmemalign(buffer_size);
     196        out[1] = out[0] + out_stride[0] * out_height[0];
     197        out[2] = out[1] + out_stride[1] * out_height[1];
     198
     199        // Convert colorspace
     200        sws_scale(ctx->sws_ctx, in, in_stride, 0, ctx->height, out, out_stride);
     201
     202        return 0;
     203}
  • xpra/codecs/csc_swscale/csc_swscale.h

     
     1/* This file is part of Xpra.
     2 * Copyright (C) 2012, 2013 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3 * Copyright (C) 2012, 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
     8#include <stdint.h>
     9#include <inttypes.h>
     10
     11#ifdef _WIN32
     12#define _STDINT_H
     13#endif
     14
     15/** Opaque structure - "context". You must have a context to convert frames. */
     16struct csc_swscale_ctx;
     17
     18/** Create a CSC context */
     19struct csc_swscale_ctx *init_csc(int width, int height, const char *src_format_str, const char *dst_format_str);
     20
     21/** Free a CSC context */
     22void free_csc(struct csc_swscale_ctx *ctx);
     23
     24/**
     25 * Colorspace conversion.
     26 * @param in: array of pointers to the planes of input frame
     27 * @param in_stride: array of input plane strides
     28 * @param out: array that will be set to point to the planes of output frame
     29 * @param out_stride: array that will be set to the output strides
     30 * @return 0 if OK, non zero on error
     31 * Note: you must call free_csc_image() with the out[] array as argument when done
     32 */
     33int csc_image(struct csc_swscale_ctx *ctx, const uint8_t *in[3], const int in_stride[3], uint8_t *out[3], int out_stride[3]);
     34
     35/**
     36 * Free data output by csc_image()
     37 */
     38void free_csc_image(uint8_t *buf[3]);
  • xpra/codecs/dec_avcodec/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2012, 2013 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
  • xpra/codecs/dec_avcodec/dec_avcodec.c

     
     1/* This file is part of Xpra.
     2 * Copyright (C) 2012, 2013 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3 * Copyright (C) 2012, 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
     8#include <stdio.h>
     9#include <stdlib.h>
     10#include <string.h>
     11#include <sys/types.h>
     12#include <sys/stat.h>
     13#include <stdint.h>
     14#include <inttypes.h>
     15
     16#ifdef _WIN32
     17#define _STDINT_H
     18#endif
     19
     20#include "dec_avcodec.h"
     21#include <libavcodec/avcodec.h>
     22#include <libavutil/mem.h>
     23
     24/** Context for dec_avcodec_lib
     25 * decode video with libavcodec
     26 */
     27struct dec_avcodec_ctx{
     28        int width;
     29        int height;
     30        AVCodec *codec;
     31        AVCodecContext *codec_ctx;
     32        AVFrame *frame;
     33};
     34
     35/* string format name <-> swscale format correspondance */
     36static const struct {
     37        enum PixelFormat sws_pixfmt;
     38        const char *str;
     39} sws_formats[] = {
     40        { PIX_FMT_YUV420P, "YUV420P" },
     41        { PIX_FMT_YUV422P, "YUV422P" },
     42        { PIX_FMT_YUV444P, "YUV444P" },
     43        { PIX_FMT_RGB24,   "RGB"  },
     44#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 14, 100)
     45        { PIX_FMT_0RGB,    "XRGB" },
     46        { PIX_FMT_BGR0,    "BGRX" },
     47#else
     48        { PIX_FMT_ARGB,    "XRGB" },
     49        { PIX_FMT_BGRA,    "BGRX" },
     50#endif
     51        { PIX_FMT_ARGB,    "ARGB" },
     52        { PIX_FMT_BGRA,    "BGRA" },
     53};
     54
     55#define TOTAL_FORMATS (int)(sizeof(sws_formats)/sizeof(sws_formats[0]))
     56
     57static enum PixelFormat get_swscale_format(const char *str)
     58{
     59        int i;
     60        for (i = 0; i < TOTAL_FORMATS; i++) {
     61                if (!strcmp(sws_formats[i].str, str))
     62                        return sws_formats[i].sws_pixfmt;
     63        }
     64        fprintf(stderr, "Unknown pixel format specified: %s\n", str);
     65        return PIX_FMT_NONE;
     66}
     67
     68struct dec_avcodec_ctx *init_decoder(int width, int height, const char *colorspace)
     69{
     70        struct dec_avcodec_ctx *ctx = malloc(sizeof(struct dec_avcodec_ctx));
     71        if (!ctx)
     72                return NULL;
     73        memset(ctx, 0, sizeof(struct dec_avcodec_ctx));
     74       
     75        ctx->width = width;
     76        ctx->height = height;
     77
     78        avcodec_register_all();
     79
     80        ctx->codec = avcodec_find_decoder(CODEC_ID_H264);
     81        if (!ctx->codec) {
     82                fprintf(stderr, "codec H264 not found!\n");
     83                goto err;
     84        }
     85        ctx->codec_ctx = avcodec_alloc_context3(ctx->codec);
     86        if (!ctx->codec_ctx) {
     87                fprintf(stderr, "failed to allocate codec context!\n");
     88                goto err;
     89        }
     90        ctx->codec_ctx->width = ctx->width;
     91        ctx->codec_ctx->height = ctx->height;
     92        ctx->codec_ctx->pix_fmt = get_swscale_format(colorspace);
     93        if (avcodec_open2(ctx->codec_ctx, ctx->codec, NULL) < 0) {
     94                fprintf(stderr, "could not open codec\n");
     95                goto err;
     96        }
     97        ctx->frame = avcodec_alloc_frame();
     98        if (!ctx->frame) {
     99                fprintf(stderr, "could not allocate an AVFrame for decoding\n");
     100                goto err;
     101        }
     102        return ctx;
     103
     104err:
     105        clean_decoder(ctx);
     106        return NULL;
     107}
     108
     109void clean_decoder(struct dec_avcodec_ctx *ctx)
     110{
     111        if (ctx->frame) {
     112                avcodec_free_frame(&ctx->frame);
     113                ctx->frame = NULL;
     114        }
     115        if (ctx->codec_ctx) {
     116                avcodec_close(ctx->codec_ctx);
     117                av_free(ctx->codec_ctx);
     118                ctx->codec_ctx = NULL;
     119        }
     120}
     121
     122int decompress_image(struct dec_avcodec_ctx *ctx, const uint8_t *in, int size, uint8_t *out[3], int outstride[3])
     123{
     124        int got_picture;
     125        int len;
     126        int i;
     127        int outsize = 0;
     128        AVFrame *picture = ctx->frame;
     129        AVPacket avpkt;
     130
     131        av_init_packet(&avpkt);
     132
     133        if (!ctx->codec_ctx || !ctx->codec)
     134                return 1;
     135
     136        avcodec_get_frame_defaults(picture);
     137
     138        avpkt.data = (uint8_t *)in;
     139        avpkt.size = size;
     140
     141        len = avcodec_decode_video2(ctx->codec_ctx, picture, &got_picture, &avpkt);
     142        if (len < 0) {
     143                fprintf(stderr, "Error while decoding frame\n");
     144                out[0] = out[1] = out[2] = NULL;
     145                return 2;
     146        }
     147
     148        for (i = 0; i < 3; i++) {
     149                out[i] = picture->data[i];
     150                outsize += ctx->height * picture->linesize[i];
     151                outstride[i] = picture->linesize[i];
     152        }
     153
     154        if (outsize == 0) {
     155                fprintf(stderr, "Decoded image, size %d %d %d, ptr %p %p %p\n",
     156                        outstride[0] * ctx->height,
     157                        outstride[1] * ctx->height,
     158                        outstride[2] * ctx->height, picture->data[0],
     159                        picture->data[1], picture->data[2]);
     160                return 3;
     161        }
     162
     163        return 0;
     164}
     165
  • xpra/codecs/dec_avcodec/dec_avcodec.h

     
     1/* This file is part of Xpra.
     2 * Copyright (C) 2012, 2013 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3 * Copyright (C) 2012, 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
     8#include <stdint.h>
     9#include <inttypes.h>
     10
     11#ifdef _WIN32
     12#define _STDINT_H
     13#endif
     14
     15/** Opaque structure - "context". You must have a context to decode frames. */
     16struct dec_avcodec_ctx;
     17
     18/** Create a decoding context for images of a given size. */
     19struct dec_avcodec_ctx *init_decoder(int width, int height, const char *colorspace);
     20
     21/** Cleanup decoding context. */
     22void clean_decoder(struct dec_avcodec_ctx *);
     23
     24/** Decompress an image using the given context.
     25 @param in: Input buffer, format is H264.
     26 @param size: Input size.
     27 @param out: Will be filled to point to the output data in planar YUV420 format (3 planes). This data will be freed automatically upon next call to the decoder.
     28 @param outstride: Output strides (3 planes).
     29*/
     30int decompress_image(struct dec_avcodec_ctx *ctx, const uint8_t *in, int size, uint8_t *out[3], int outstride[3]);
     31
  • xpra/codecs/dec_avcodec/decoder.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2012, 2013 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6import os
     7from libc.stdlib cimport free
     8
     9from xpra.codecs.codec_constants import get_subsampling_divs, YUV420P
     10from xpra.server.image_wrapper import ImageWrapper
     11
     12cdef extern from "string.h":
     13    void * memcpy ( void * destination, void * source, size_t num )
     14    void * memset ( void * ptr, int value, size_t num )
     15
     16cdef extern from *:
     17    ctypedef unsigned long size_t
     18
     19cdef extern from "Python.h":
     20    ctypedef int Py_ssize_t
     21    ctypedef object PyObject
     22    ctypedef void** const_void_pp "const void**"
     23    int PyObject_AsReadBuffer(object obj, void ** buffer, Py_ssize_t * buffer_len) except -1
     24
     25ctypedef unsigned char uint8_t
     26ctypedef void dec_avcodec_ctx
     27cdef extern from "dec_avcodec.h":
     28    dec_avcodec_ctx *init_decoder(int width, int height, const char *colorspace)
     29    void set_decoder_csc_format(dec_avcodec_ctx *ctx, int csc_fmt)
     30    void clean_decoder(dec_avcodec_ctx *)
     31    int decompress_image(dec_avcodec_ctx *ctx, const uint8_t *input_image, int size, uint8_t *out[3], int outstride[3])
     32
     33
     34cdef class Decoder:
     35    cdef dec_avcodec_ctx *context
     36    cdef int width
     37    cdef int height
     38
     39    def init_context(self, width, height, colorspace, options):
     40        self.width = width
     41        self.height = height
     42        self.context = init_decoder(width, height, "YUV420P")
     43
     44    def is_closed(self):
     45        return self.context==NULL
     46
     47    def __dealloc__(self):
     48        self.clean()
     49
     50    def get_width(self):
     51        return self.width
     52
     53    def get_height(self):
     54        return self.height
     55
     56    def get_type(self):
     57        return "x264"
     58
     59    def clean(self):
     60        if self.context!=NULL:
     61            clean_decoder(self.context)
     62            self.context = NULL
     63
     64    def decompress_image_to_yuv(self, input, options):
     65        cdef uint8_t *dout[3]
     66        cdef int outstrides[3]
     67        cdef unsigned char * padded_buf = NULL
     68        cdef const unsigned char * buf = NULL
     69        cdef Py_ssize_t buf_len = 0
     70        cdef int i = 0
     71        assert self.context!=NULL
     72        PyObject_AsReadBuffer(input, <const_void_pp> &buf, &buf_len)
     73        i = decompress_image(self.context, buf, buf_len, dout, outstrides)
     74        if i!=0:
     75            return None
     76        out = []
     77        strides = []
     78        pixel_format = YUV420P #XXX self.get_pixel_format(csc_pixel_format)
     79        divs = get_subsampling_divs(pixel_format)
     80        for i in (0, 1, 2):
     81            _, dy = divs[i]
     82            if dy==1:
     83                height = self.height
     84            elif dy==2:
     85                height = (self.height+1)>>1
     86            else:
     87                raise Exception("invalid height divisor %s" % dy)
     88            stride = outstrides[i]
     89            plane = (<char *>dout[i])[:(height * stride)]
     90            out.append(plane)
     91            strides.append(outstrides[i])
     92        img = ImageWrapper(0, 0, self.width, self.height, out, pixel_format, 24, strides, 3)
     93        return  img
     94
     95    def get_pixel_format(self, csc_pixel_format):
     96        return YUV420P
  • xpra/codecs/enc_x264/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2012, 2013 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
  • xpra/codecs/enc_x264/enc_x264.c

     
     1/* This file is part of Xpra.
     2 * Copyright (C) 2012 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3 * Copyright (C) 2012, 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
     8#include <stdio.h>
     9#include <stdlib.h>
     10#include <string.h>
     11#include <sys/types.h>
     12#include <sys/stat.h>
     13#include <fcntl.h>
     14#include <stdint.h>
     15#include <inttypes.h>
     16
     17#ifdef _WIN32
     18#define _STDINT_H
     19#endif
     20#if !defined(__APPLE__)
     21#include <malloc.h>
     22#endif
     23
     24#include "enc_x264.h"
     25#include <x264.h>
     26
     27//not honoured on MS Windows:
     28#define MEMALIGN 1
     29//not honoured on OSX:
     30#define MEMALIGN_ALIGNMENT 32
     31//comment this out to turn off csc 422 and 444 colorspace modes
     32//(ie: when not supported by the library we build against)
     33#define SUPPORT_CSC_MODES 1
     34
     35#define MAX(a,b) ((a) > (b) ? a : b)
     36#define MIN(a,b) ((a) < (b) ? a : b)
     37
     38/** Context for enc_x264_lib
     39 * encode video with x264
     40 */
     41struct enc_x264_ctx {
     42        int width;
     43        int height;
     44        x264_t *x264_ctx;
     45        int speed;                                      //percentage 0-100
     46        int quality;                            //percentage 0-100
     47        int supports_csc_option;        //can we change colour sampling
     48        int encoding_preset;            //index in x264_preset_names, 0-9
     49        int color_sampling;                     //X264_CSP_I420, X264_CSP_I422 or X264_CSP_I444
     50        const char *I420_profile;
     51        const char *I422_profile;
     52        const char *I444_profile;
     53
     54        int I422_min;                           //lowest point where we will continue to use 422
     55        int I444_min;                           //lowest point where we will continue to use 444
     56        int I422_quality;                       //threshold where we want to raise CSC to 422
     57        int I444_quality;                       //threshold where we want to raise CSC to 444
     58        /*
     59         * Explanation:
     60         * We want to avoid changing CSC modes too often as this causes a full frame refresh.
     61         * So the "quality" attributes define the thresholds where we want to raise the CSC quality,
     62         * but once a CSC mode is set, we will only downgrade it if the quality then becomes
     63         * lower than the "min" value. This prevents the yoyo effect.
     64         * See get_x264_color_sampling and can_keep_color_sampling for the implementation.
     65         * configure_encoder will ensure that the values respect these rules:
     66         * 0 <= I422_min <= I422_quality <= 100
     67         * 0 <= I444_min <= I444_quality <= 100
     68         * I422_quality <= I444_quality
     69         */
     70};
     71
     72int get_x264_build_no(void)
     73{
     74        return X264_BUILD;
     75}
     76
     77int get_encoder_quality(struct enc_x264_ctx *ctx)
     78{
     79        return ctx->quality;
     80}
     81
     82int get_encoder_speed(struct enc_x264_ctx *ctx)
     83{
     84        return ctx->speed;
     85}
     86
     87/** Translate quality percentage (0 to 100)
     88 * into x264 constant quality factor (51 to 0)
     89 */
     90float get_x264_quality(int pct)
     91{
     92        return 50.0f - (MIN(100, MAX(0, pct)) * 49.0f / 100.0f);
     93}
     94
     95//Given a quality percentage (0 to 100),
     96//return the x264 color sampling to use
     97// as not all pixel formats are supported by all profiles.
     98int get_x264_color_sampling(struct enc_x264_ctx *ctx, int pct)
     99{
     100#ifdef SUPPORT_CSC_MODES
     101        if (!ctx->supports_csc_option)
     102                return X264_CSP_I420;
     103        if (pct < ctx->I422_quality)
     104                return X264_CSP_I420;
     105        else if (pct < ctx->I444_quality)
     106                return X264_CSP_I422;
     107        return X264_CSP_I444;
     108#else
     109        return X264_CSP_I420;
     110#endif
     111}
     112
     113#ifdef SUPPORT_CSC_MODES
     114const char* YUV_MODES[] = {"YUV420P", "YUV422P", "YUV444P"};
     115#else
     116const char* YUV_MODES[] = {"YUV420P"};
     117#endif
     118
     119char**  get_supported_yuv_modes(void)
     120{
     121        return YUV_MODES;
     122}
     123
     124int can_keep_color_sampling(struct enc_x264_ctx *ctx, int pct)
     125{
     126#ifdef SUPPORT_CSC_MODES
     127        if (!ctx->supports_csc_option)
     128                return (ctx->color_sampling == X264_CSP_I420);
     129        if (ctx->color_sampling == X264_CSP_I444)
     130                return (pct >= ctx->I444_min);
     131        if (ctx->color_sampling == X264_CSP_I422)
     132                return (pct >= ctx->I422_min && pct <= ctx->I444_quality);
     133        if (ctx->color_sampling == X264_CSP_I420)
     134                return (pct <= ctx->I422_quality);
     135        return -1;              //we should never get here!
     136#else
     137        //we can only use this one:
     138        return (ctx->color_sampling == X264_CSP_I420);
     139#endif
     140}
     141
     142const int DEFAULT_INITIAL_QUALITY = 70;
     143const int DEFAULT_INITIAL_SPEED = 20;
     144const char I420[] = "I420";
     145const char I422[] = "I422";
     146const char I444[] = "I444";
     147const char PROFILE_BASELINE[] = "baseline";
     148const char PROFILE_MAIN[] = "main";
     149const char PROFILE_HIGH[] = "high";
     150const char PROFILE_HIGH10[] = "high10";
     151const char PROFILE_HIGH422[] = "high422";
     152const char PROFILE_HIGH444_PREDICTIVE[] = "high444";
     153const char *I420_PROFILES[7] = {PROFILE_BASELINE, PROFILE_MAIN, PROFILE_HIGH, PROFILE_HIGH10, PROFILE_HIGH422, PROFILE_HIGH444_PREDICTIVE, NULL};
     154const char *I422_PROFILES[3] = {PROFILE_HIGH422, PROFILE_HIGH444_PREDICTIVE, NULL};
     155const char *I444_PROFILES[2] = {PROFILE_HIGH444_PREDICTIVE, NULL};
     156
     157const char *DEFAULT_I420_PROFILE = PROFILE_BASELINE;
     158const char *DEFAULT_I422_PROFILE = PROFILE_HIGH422;
     159const char *DEFAULT_I444_PROFILE = PROFILE_HIGH444_PREDICTIVE;
     160const int DEFAULT_I422_MIN_QUALITY = 80;
     161const int DEFAULT_I444_MIN_QUALITY = 90;
     162
     163//Given a quality percentage (0 to 100)
     164//return the profile to use
     165//IMPORTANT: changes here must be reflected in get_x264_color_sampling
     166// as not all pixel formats are supported by all profiles.
     167static const char *get_x264_profile_from_quality(struct enc_x264_ctx *ctx)
     168{
     169        if (ctx->quality < ctx->I422_quality)
     170                return ctx->I420_profile;
     171        if (ctx->quality < ctx->I444_quality)
     172                return ctx->I422_profile;
     173        return ctx->I444_profile;
     174}
     175
     176/**
     177 * Ensures that the profile given is valid and
     178 * returns a pointer to the const string for it.
     179 * (as we may pass temporary strings from python!)
     180 */
     181const char *get_valid_profile(const char *csc_mode, const char *profile, const char *profiles[], const char *default_profile)
     182{
     183        //printf("get_valid_profile(%s, %s, %p, %s)\n", csc_mode, profile, profiles, default_profile);
     184        int i = 0;
     185        if (profile == NULL)
     186                return default_profile;
     187        while (profiles[i] != NULL) {
     188                if (strcmp(profiles[i], profile) == 0) {
     189                        //printf("found valid %s profile: %s\n", csc_mode, profiles[i]);
     190                        return profiles[i];
     191                }
     192                i++;
     193        }
     194        fprintf(stderr, "invalid %s profile specified: %s\n", csc_mode, profile);
     195        return default_profile;
     196}
     197
     198/**
     199 * Configure values that will not change during the lifetime of the encoder.
     200 */
     201static void configure_encoder(struct enc_x264_ctx *ctx,
     202                int width, int height, const char *colorspace,
     203                int initial_quality, int initial_speed,
     204                int I422_quality, int I444_quality,
     205                int I422_min, int I444_min,
     206                char *i420_profile, char *i422_profile, char *i444_profile)
     207{
     208        //printf("configure_encoder(%p, %i, %i, %i, %i, %i, %i, %s, %s, %s)\n", ctx, width, height, initial_quality, supports_csc_option, I422_quality, I444_quality, i420_profile, i422_profile, i444_profile);
     209        ctx->width = width;
     210        ctx->height = height;
     211        if (initial_speed >= 0)
     212                ctx->speed = initial_speed;
     213        else
     214                ctx->speed = DEFAULT_INITIAL_SPEED;
     215        if (initial_quality >= 0)
     216                ctx->quality = initial_quality;
     217        else
     218                ctx->quality = DEFAULT_INITIAL_QUALITY;
     219        //printf("configure_encoder: %ix%i q=%i\n", ctx->width, ctx->height, ctx->quality);
     220        if (I422_quality >= 0 && I422_quality <= 100)
     221                ctx->I422_quality = I422_quality;
     222        else
     223                ctx->I422_quality = DEFAULT_I422_MIN_QUALITY;
     224        if (I444_quality >= 0 && I444_quality <= 100 && I444_quality >= ctx->I422_quality)
     225                ctx->I444_quality = I444_quality;
     226        else
     227                ctx->I444_quality = MIN(100, MAX(DEFAULT_I444_MIN_QUALITY, ctx->I422_quality + 10));
     228        //"min" values must be lower than the corresponding "quality" value:
     229        if (I422_min >= 0 && I422_min <= 100 && I422_min <= ctx->I422_quality)
     230                ctx->I422_min = I422_min;
     231        else
     232                ctx->I422_min = MAX(0, ctx->I422_quality - 10);
     233        if (I444_min >= 0 && I444_min <= 100 && I444_min <= ctx->I444_quality)
     234                ctx->I444_min = I444_min;
     235        else
     236                ctx->I444_min = MAX(0, MIN(ctx->I422_min, ctx->I444_quality - 10));
     237        //printf("configure_encoder: quality thresholds: I422=%i / I444=%i\n", ctx->I422_quality, ctx->I444_quality);
     238        //printf("configure_encoder: min quality: I422=%i / I444=%i\n", ctx->I422_min, ctx->I444_min);
     239        ctx->I420_profile = get_valid_profile(I420, i420_profile, I420_PROFILES, DEFAULT_I420_PROFILE);
     240        ctx->I422_profile = get_valid_profile(I422, i422_profile, I422_PROFILES, DEFAULT_I422_PROFILE);
     241        ctx->I444_profile = get_valid_profile(I444, i444_profile, I444_PROFILES, DEFAULT_I444_PROFILE);
     242        //printf("configure_encoder: profiles %s / %s / %s\n", ctx->I420_profile, ctx->I422_profile, ctx->I444_profile);
     243}
     244
     245/**
     246 * Actually initialize the encoder.
     247 * This may be called more than once if required, ie:
     248 * - if the dimensions change,
     249 * - if the csc mode changes.
     250 */
     251void do_init_encoder(struct enc_x264_ctx *ctx)
     252{
     253        x264_param_t param;
     254        ctx->color_sampling =
     255        ctx->encoding_preset = 2;
     256        //printf("do_init_encoder(%p, %i, %i, %i, %i) color_sampling=%i, initial quality=%d, initial profile=%s\n", ctx, ctx->width, ctx->height, ctx->quality, ctx->supports_csc_option, ctx->color_sampling, ctx->quality, ctx->profile);
     257
     258        x264_param_default_preset(&param, x264_preset_names[ctx->encoding_preset], "zerolatency");
     259        param.i_threads = 1;
     260        param.i_width = ctx->width;
     261        param.i_height = ctx->height;
     262        param.i_csp = X264_CSP_I420;
     263        param.rc.f_rf_constant = get_x264_quality(ctx->quality);
     264        param.i_log_level = X264_LOG_ERROR;
     265        param.i_keyint_max = 999999;    //we never lose frames or use seeking, so no need for regular I-frames
     266        param.i_keyint_min = 999999;    //we don't want IDR frames either
     267        param.b_intra_refresh = 0;              //no intra refresh
     268        param.b_open_gop = 1;                   //allow open gop
     269        x264_param_apply_profile(&param, get_x264_profile_from_quality(ctx));
     270        ctx->x264_ctx = x264_encoder_open(&param);
     271}
     272
     273struct enc_x264_ctx *init_encoder(int width, int height, const char *colorspace,
     274                                 int initial_quality, int initial_speed,
     275                                 int I422_quality,
     276                                 int I444_quality, int I422_min, int I444_min,
     277                                 char *i420_profile, char *i422_profile,
     278                                 char *i444_profile)
     279{
     280        struct enc_x264_ctx *ctx = malloc(sizeof(struct enc_x264_ctx));
     281        if (ctx == NULL)
     282                return NULL;
     283        memset(ctx, 0, sizeof(struct enc_x264_ctx));
     284        configure_encoder(ctx,
     285                          width, height, colorspace,
     286                          initial_quality, initial_speed,
     287                          I422_quality, I444_quality,
     288                          I422_min, I444_min,
     289                          i420_profile, i422_profile, i444_profile);
     290        do_init_encoder(ctx);
     291        return ctx;
     292}
     293
     294void clean_encoder(struct enc_x264_ctx *ctx)
     295{
     296        do_clean_encoder(ctx);
     297        free(ctx);
     298}
     299
     300void do_clean_encoder(struct enc_x264_ctx *ctx)
     301{
     302        if (ctx->x264_ctx) {
     303                x264_encoder_close(ctx->x264_ctx);
     304                ctx->x264_ctx = NULL;
     305        }
     306}
     307
     308int compress_image(struct enc_x264_ctx *ctx, uint8_t *in[3], int in_stride[3], uint8_t **out, int *outsz)
     309{
     310        x264_nal_t *nals = NULL;
     311        int i_nals = 0;
     312        x264_picture_t pic_out;
     313        x264_picture_t pic_in;
     314        int frame_size = 0;
     315
     316        memset(&pic_out, 0, sizeof(x264_picture_t));
     317        memset(&pic_in, 0, sizeof(x264_picture_t));
     318        pic_in.img.i_csp = X264_CSP_I420;
     319        pic_in.img.i_plane = 3;
     320        pic_in.img.i_stride[0] = in_stride[0];
     321        pic_in.img.i_stride[1] = in_stride[1];
     322        pic_in.img.i_stride[2] = in_stride[2];
     323        pic_in.img.i_stride[3] = 0;
     324        pic_in.img.plane[0] = in[0];
     325        pic_in.img.plane[1] = in[1];
     326        pic_in.img.plane[2] = in[2];
     327        pic_in.img.plane[3] = NULL;
     328
     329        /* Encoding */
     330        pic_in.i_pts = 1;
     331        frame_size = x264_encoder_encode(ctx->x264_ctx, &nals, &i_nals, &pic_in, &pic_out);
     332        if (frame_size < 0) {
     333                fprintf(stderr, "Problem during x264_encoder_encode: frame_size is invalid!\n");
     334                *out = NULL;
     335                *outsz = 0;
     336                return 2;
     337        }
     338        /* Do not clean that! */
     339        *out = nals[0].p_payload;
     340        *outsz = frame_size;
     341        return 0;
     342}
     343
     344/**
     345 * Change the speed of encoding (x264 preset).
     346 * @param percent: 100 for maximum ("ultrafast") with lowest compression, 0 for highest compression (slower)
     347 */
     348void set_encoding_speed(struct enc_x264_ctx *ctx, int pct)
     349{
     350        x264_param_t param;
     351        int new_preset = 7 - MAX(0, MIN(6, pct / 16));
     352        x264_encoder_parameters(ctx->x264_ctx, &param);
     353        ctx->speed = pct;
     354        if (new_preset == ctx->encoding_preset)
     355                return;
     356        //printf("set_encoding_speed(%i) old preset: %i=%s, new preset: %i=%s\n", pct, ctx->encoding_preset, x264_preset_names[ctx->encoding_preset], new_preset, x264_preset_names[new_preset]);
     357        ctx->encoding_preset = new_preset;
     358        x264_param_default_preset(&param, x264_preset_names[ctx->encoding_preset], "zerolatency");
     359        param.rc.f_rf_constant = get_x264_quality(ctx->quality);
     360        x264_param_apply_profile(&param, get_x264_profile_from_quality(ctx));
     361        x264_encoder_reconfig(ctx->x264_ctx, &param);
     362}
     363
     364/**
     365 * Change the quality of encoding
     366 * @param percent: 100 for best quality, 0 for lowest quality.
     367 */
     368void set_encoding_quality(struct enc_x264_ctx *ctx, int pct)
     369{
     370        if ((ctx->quality & ~0x1) != (pct & ~0x1)) {
     371                //float old_quality = ctx->x264_quality;
     372                //only f_rf_constant was changed,
     373                //read new configuration is sufficient
     374                x264_param_t param;
     375                // Retrieve current parameters
     376                x264_encoder_parameters(ctx->x264_ctx, &param);
     377                ctx->quality = pct;
     378                param.rc.f_rf_constant = get_x264_quality(pct);
     379                x264_encoder_reconfig(ctx->x264_ctx, &param);
     380        }
     381}
  • xpra/codecs/enc_x264/enc_x264.h

     
     1/* This file is part of Xpra.
     2 * Copyright (C) 2012, 2013 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3 * Copyright (C) 2012, 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
     8#include <stdint.h>
     9#include <inttypes.h>
     10
     11#ifdef _WIN32
     12#define _STDINT_H
     13#endif
     14
     15#define inline __inline
     16#include <x264.h>
     17
     18/** Opaque structure - "context". You must have a context to encode frames. */
     19struct enc_x264_ctx;
     20
     21/** Expose the X264_BUILD value */
     22int get_x264_build_no(void);
     23
     24/** Expose current quality setting */
     25int get_encoder_quality(struct enc_x264_ctx *ctx);
     26
     27/** Expose current speed setting */
     28int get_encoder_speed(struct enc_x264_ctx *ctx);
     29
     30/** Returns the pixel format using our own generic codec_constants */
     31int get_pixel_format(int csc);
     32
     33/** Cleanup encoding context. Without freeing the memory. */
     34void do_clean_encoder(struct enc_x264_ctx *ctx);
     35
     36/** Cleanup encoding context. Also frees the memory. */
     37void clean_encoder(struct enc_x264_ctx *);
     38
     39/** Compress an image using the given context.
     40 @param in: the input image, as returned by csc_image_rgb2yuv. It will be freed along with its container x264_picture_t automatically.
     41 @param out: Will be set to point to the output data. This output buffer MUST NOT BE FREED and will be erased on the
     42 next call to compress_image.
     43 @param outsz: Output size
     44 @param quality_override: Desired quality setting (0 to 100), -1 to use current settings.
     45*/
     46int compress_image(struct enc_x264_ctx *ctx, uint8_t *in[3], int in_stride[3], uint8_t **out, int *outsz);
     47
     48/**
     49 * Change the speed of encoding (x264 preset).
     50 * @param percent: 100 for maximum ("ultrafast") with lowest compression, 0 for highest compression (slower)
     51 */
     52void set_encoding_speed(struct enc_x264_ctx *ctx, int pct);
     53
     54/**
     55 * Change the quality of encoding (x264 f_rf_constant).
     56 * @param percent: 100 for maximum quality, 0 for lowest quality
     57 */
     58void set_encoding_quality(struct enc_x264_ctx *ctx, int pct);
     59
     60
     61/** Create an encoding context for images of a given size.  */
     62struct enc_x264_ctx *init_encoder(int width, int height, const char *colorspace,
     63                int initial_quality, int initial_speed,
     64                int I422_quality, int I444_quality,
     65                int I422_min, int I444_min,
     66        char *i420_profile, char *i422_profile, char *i444_profile);
     67
  • xpra/codecs/enc_x264/encoder.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2012, 2013 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6import os
     7from libc.stdlib cimport free
     8
     9from xpra.codecs.codec_constants import get_subsampling_divs, RGB_FORMATS, YUV420P
     10from xpra.codecs.csc_swscale.colorspace_converter import ColorspaceConverter
     11
     12DEFAULT_INITIAL_QUALITY = 70
     13DEFAULT_INITIAL_SPEED = 20
     14ALL_PROFILES = ["baseline", "main", "high", "high10", "high422", "high444"]
     15I420_PROFILES = ALL_PROFILES[:]
     16I422_PROFILES = ["high422", "high444"]
     17I444_PROFILES = ["high444"]
     18DEFAULT_I420_PROFILE = "baseline"
     19DEFAULT_I422_PROFILE = "high422"
     20DEFAULT_I444_PROFILE = "high444"
     21DEFAULT_I422_QUALITY = 70
     22DEFAULT_I422_MIN_QUALITY = 50
     23DEFAULT_I444_QUALITY = 90
     24DEFAULT_I444_MIN_QUALITY = 75
     25
     26cdef extern from "string.h":
     27    void * memcpy ( void * destination, void * source, size_t num )
     28    void * memset ( void * ptr, int value, size_t num )
     29
     30cdef extern from *:
     31    ctypedef unsigned long size_t
     32
     33cdef extern from "Python.h":
     34    ctypedef int Py_ssize_t
     35    ctypedef object PyObject
     36    ctypedef void** const_void_pp "const void**"
     37    int PyObject_AsReadBuffer(object obj, void ** buffer, Py_ssize_t * buffer_len) except -1
     38
     39ctypedef unsigned char uint8_t
     40ctypedef void enc_x264_ctx
     41cdef extern from "enc_x264.h":
     42    void* xmemalign(size_t size) nogil
     43    void xmemfree(void* ptr) nogil
     44
     45    int get_x264_build_no()
     46
     47    enc_x264_ctx *init_encoder(int width, int height, const char *colorspace,
     48        int initial_quality, int initial_speed,
     49        int I422_quality, int I444_quality,
     50        int I422_min, int I444_min,
     51        char *i420_profile, char *i422_profile, char *i444_profile)
     52    void clean_encoder(enc_x264_ctx *)
     53    int compress_image(enc_x264_ctx *ctx, uint8_t *input[3], int in_stride[3], uint8_t **out, int *outsz)
     54    int get_encoder_quality(enc_x264_ctx *ctx)
     55    int get_encoder_speed(enc_x264_ctx *ctx)
     56
     57    void set_encoding_speed(enc_x264_ctx *context, int pct)
     58    void set_encoding_quality(enc_x264_ctx *context, int pct)
     59
     60
     61def get_version():
     62    return get_x264_build_no()
     63
     64YUV_FORMATS = ("YUV420P",
     65               )
     66
     67cdef class Encoder:
     68    cdef int frames
     69    cdef int supports_options
     70    cdef enc_x264_ctx *context
     71    cdef int width
     72    cdef int height
     73    cdef char *src_format
     74
     75    def init_context(self, int width, int height, src_format, options):    #@DuplicatedSignature
     76        self.width = width
     77        self.height = height
     78        assert src_format in YUV_FORMATS, "invalid source format: %s" % src_format
     79        for x in YUV_FORMATS:
     80            if x==src_format:
     81                self.src_format = x
     82                break
     83        self.frames = 0
     84        self.supports_options = int(options.get("client_options", False))
     85        I420_profile = self._get_profile(options, "I420", DEFAULT_I420_PROFILE, I420_PROFILES)
     86        I422_profile = self._get_profile(options, "I422", DEFAULT_I422_PROFILE, I422_PROFILES)
     87        I444_profile = self._get_profile(options, "I444", DEFAULT_I444_PROFILE, I444_PROFILES)
     88        I422_quality = self._get_quality(options, "I422", DEFAULT_I422_QUALITY)
     89        I444_quality = self._get_quality(options, "I444", DEFAULT_I444_QUALITY)
     90        I422_min = self._get_min_quality(options, "I422", DEFAULT_I422_MIN_QUALITY)
     91        I444_min = self._get_min_quality(options, "I444", DEFAULT_I444_MIN_QUALITY)
     92        initial_quality = options.get("initial_quality", options.get("quality", DEFAULT_INITIAL_QUALITY))
     93        initial_speed = options.get("initial_speed", options.get("speed", DEFAULT_INITIAL_SPEED))
     94        initial_quality = min(100, max(0, initial_quality))
     95        initial_speed = min(100, max(0, initial_speed))
     96        self.context = init_encoder(width, height, "YUV420P",
     97                                    initial_quality, initial_speed,
     98                                    int(I422_quality), int(I444_quality),
     99                                    int(I422_min), int(I444_min),
     100                                    I420_profile, I422_profile, I444_profile)
     101
     102    def is_closed(self):
     103        return self.context==NULL
     104
     105    def __dealloc__(self):
     106        self.clean()
     107
     108    def get_width(self):
     109        return self.width
     110
     111    def get_height(self):
     112        return self.height
     113
     114    def get_type(self):
     115        return  "x264"
     116
     117    def get_src_format(self):
     118        return self.src_format
     119
     120    def _get_profile(self, options, csc_mode, default_value, valid_options):
     121        #try the environment as a default, fallback to hardcoded default:
     122        profile = os.environ.get("XPRA_X264_%s_PROFILE" % csc_mode, default_value)
     123        #now see if the client has requested a different value:
     124        profile = options.get("x264.%s.profile" % csc_mode, profile)
     125        if profile not in valid_options:
     126            print("invalid %s profile: %s" % (csc_mode, profile))
     127            return default_value
     128        return profile
     129
     130    def _get_min_quality(self, options, csc_mode, default_value):
     131        #try the environment as a default, fallback to hardcoded default:
     132        min_quality = int(os.environ.get("XPRA_X264_%s_MIN_QUALITY" % csc_mode, default_value))
     133        #now see if the client has requested a different value:
     134        min_quality = options.get("x264.%s.min_quality" % csc_mode, min_quality)
     135        #enforce valid range:
     136        return min(100, max(-1, min_quality))
     137
     138    def _get_quality(self, options, csc_mode, default_value):
     139        #try the environment as a default, fallback to hardcoded default:
     140        quality = int(os.environ.get("XPRA_X264_%s_QUALITY" % csc_mode, default_value))
     141        #now see if the client has requested a different value:
     142        quality = options.get("x264.%s.quality" % csc_mode, quality)
     143        #enforce valid range:
     144        return min(100, max(-1, quality))
     145
     146    def clean(self):                        #@DuplicatedSignature
     147        if self.context!=NULL:
     148            clean_encoder(self.context)
     149            self.context = NULL
     150
     151    def get_client_options(self, options):
     152        csc_pf = 0
     153        client_options = {
     154                "csc_pixel_format" : csc_pf,
     155                "frame" : self.frames
     156                }
     157        q = client_options.get("quality", -1)
     158        if q<0:
     159            q = get_encoder_quality(self.context)
     160        client_options["quality"] = q
     161        s = client_options.get("speed", -1)
     162        if s<0:
     163            s = get_encoder_speed(self.context)
     164        client_options["speed"] = s
     165        return  client_options
     166
     167    def compress_image(self, image, options):
     168        cdef uint8_t *pic_in[3]
     169        cdef int strides[3]
     170        cdef uint8_t *pic_buf
     171        cdef Py_ssize_t pic_buf_len = 0
     172        cdef int quality_override = options.get("quality", -1)
     173        cdef int speed_override = options.get("speed", -1)
     174        cdef int saved_quality = get_encoder_quality(self.context)
     175        cdef int saved_speed = get_encoder_speed(self.context)
     176        if speed_override>=0 and saved_speed!=speed_override:
     177            set_encoding_speed(self.context, speed_override)
     178        if quality_override>=0 and saved_quality!=quality_override:
     179            set_encoding_quality(self.context, quality_override)
     180        assert self.context!=NULL
     181        pixels = image.get_pixels()
     182        istrides = image.get_rowstride()
     183        assert len(pixels)==3, "image pixels does not have 3 planes! (found %s)" % len(pixels)
     184        assert len(istrides)==3, "image strides does not have 3 values! (found %s)" % len(istrides)
     185        for i in range(3):
     186            PyObject_AsReadBuffer(pixels[i], <const_void_pp> &pic_buf, &pic_buf_len)
     187            pic_in[i] = pic_buf
     188            strides[i] = istrides[i]
     189        try:
     190            return self.do_compress_image(pic_in, strides), self.get_client_options(options)
     191        finally:
     192            if speed_override>=0 and saved_speed!=speed_override:
     193                set_encoding_speed(self.context, saved_speed)
     194            if quality_override>=0 and saved_quality!=quality_override:
     195                set_encoding_quality(self.context, saved_quality)
     196
     197    cdef do_compress_image(self, uint8_t *pic_in[], int strides[]):
     198        #actual compression (no gil):
     199        cdef int i
     200        cdef uint8_t *cout
     201        cdef int coutsz
     202        i = compress_image(self.context, pic_in, strides, &cout, &coutsz)
     203        if i!=0:
     204            return None
     205        coutv = (<char *>cout)[:coutsz]
     206        self.frames += 1
     207        return  coutv
     208
     209    def set_encoding_speed(self, int pct):
     210        assert pct>=0 and pct<=100, "invalid percentage: %s" % pct
     211        assert self.context!=NULL, "context is closed!"
     212        set_encoding_speed(self.context, pct)
     213
     214    def set_encoding_quality(self, int pct):
     215        assert pct>=0 and pct<=100, "invalid percentage: %s" % pct
     216        assert self.context!=NULL, "context is closed!"
     217        set_encoding_quality(self.context, pct)
  • xpra/codecs/enc_x264/timer.h

     
     1#include <sys/time.h>
     2#include <stdarg.h>
     3#include <stdlib.h>
     4#include <stdio.h>
     5
     6struct my_timer {
     7        int msec_before;
     8        int msec_after;
     9        int msec;
     10};
     11
     12static void timer_reset(struct my_timer *t)
     13{
     14        struct timeval tv;
     15        t->msec = 0;
     16        gettimeofday(&tv, NULL);
     17        t->msec_before = tv.tv_sec * 1000 + tv.tv_usec / 1000;
     18}
     19
     20static struct my_timer *timer_alloc()
     21{
     22        struct my_timer *t = malloc(sizeof(struct my_timer));
     23        timer_reset(t);
     24        return t;
     25}
     26
     27static int timer_done(struct my_timer *t)
     28{
     29        struct timeval tv;
     30        gettimeofday(&tv, NULL);
     31        t->msec_after = tv.tv_sec * 1000 + tv.tv_usec / 1000;
     32        t->msec = t->msec_after - t->msec_before;
     33
     34        return t->msec;
     35}
     36
     37static void timer_display_and_reset(struct my_timer *t, const char *prefix)
     38{
     39        timer_done(t);
     40        printf("%s: %d msec\n", prefix, t->msec);
     41        timer_reset(t);
     42}
     43
  • xpra/codecs/vpx/decoder.pyx

     
    2323
    2424    vpx_codec_ctx_t* init_encoder(int width, int height)
    2525    void clean_encoder(vpx_codec_ctx_t *context)
    26     vpx_image_t* csc_image_rgb2yuv(vpx_codec_ctx_t *ctx, uint8_t *input, int stride)
    27     int csc_image_yuv2rgb(vpx_codec_ctx_t *ctx, uint8_t *input[3], int stride[3], uint8_t **out, int *outsz, int *outstride) nogil
    2826    int compress_image(vpx_codec_ctx_t *ctx, vpx_image_t *image, uint8_t **out, int *outsz) nogil
    2927
    3028    vpx_codec_ctx_t* init_decoder(int width, int height, int use_swscale)
     
    107105        if i!=0:
    108106            return i, None
    109107        with nogil:
    110             i = csc_image_yuv2rgb(self.context, yuvplanes, yuvstrides, &dout, &outsize, &outstride)
     108            i = 0   #csc_image_yuv2rgb(self.context, yuvplanes, yuvstrides, &dout, &outsize, &outstride)
    111109        if i!=0:
    112110            return i, None
    113111        outstr = (<char *>dout)[:outsize]
  • xpra/codecs/vpx/encoder.pyx

     
    2424
    2525    vpx_codec_ctx_t* init_encoder(int width, int height, char *rgb_format)
    2626    void clean_encoder(vpx_codec_ctx_t *context)
    27     vpx_image_t* csc_image_rgb2yuv(vpx_codec_ctx_t *ctx, uint8_t *input, int stride)
    28     int csc_image_yuv2rgb(vpx_codec_ctx_t *ctx, uint8_t *input[3], int stride[3], uint8_t **out, int *outsz, int *outstride) nogil
    2927    int compress_image(vpx_codec_ctx_t *ctx, vpx_image_t *image, uint8_t **out, int *outsz) nogil
    3028
    3129    vpx_codec_ctx_t* init_decoder(int width, int height, int use_swscale)
     
    8886        rowstride = image.get_rowstride()
    8987        #colourspace conversion with gil held:
    9088        assert PyObject_AsReadBuffer(input, <const_void_pp> &pic_buf, &pic_buf_len)==0
    91         pic_in = csc_image_rgb2yuv(self.context, pic_buf, rowstride)
     89        pic_in = NULL   #csc_image_rgb2yuv(self.context, pic_buf, rowstride)
    9290        assert pic_in!=NULL, "colourspace conversion failed"
    9391        return self.do_compress_image(pic_in), {"frame" : self.frames}
    9492
  • xpra/codecs/vpx/vpxlib.c

     
    3131#include "vpx/vpx_codec.h"
    3232#define fourcc    0x30385056
    3333#define IVF_FILE_HDR_SZ  (32)
    34 #include <libswscale/swscale.h>
    35 #include <libswscale/swscale.h>
    36 #include <libavutil/pixfmt.h>
    3734
    3835//supported rgb formats:
    3936const char RGB_FORMAT_RGB[]             = "RGB";
     
    5047
    5148struct vpx_context {
    5249        vpx_codec_ctx_t codec;
    53         int use_swscale;
    54         struct SwsContext *rgb2yuv;
    55         struct SwsContext *yuv2rgb;
    5650        int width;
    5751        int height;
    5852        const char *rgb_format;
     
    7569        return NULL;
    7670}
    7771
    78 int get_swscale_pixel_format(const char* rgb_format)
    79 {
    80         if (strcmp(RGB_FORMAT_RGB, rgb_format)==0)
    81                 return PIX_FMT_RGB24;
    82         else if (strcmp(RGB_FORMAT_XRGB, rgb_format)==0)
    83                 return PIX_FMT_0RGB;
    84         else if (strcmp(RGB_FORMAT_BGRX, rgb_format)==0)
    85                 return PIX_FMT_BGR0;
    86         else if (strcmp(RGB_FORMAT_ARGB, rgb_format)==0)
    87                 return PIX_FMT_ARGB;
    88         else if (strcmp(RGB_FORMAT_BGRA, rgb_format)==0)
    89                 return PIX_FMT_BGRA;
    90         else if (strcmp(RGB_FORMAT_RGB, rgb_format)==0) {
    91                 fprintf(stderr, "invalid rgb_format specified: %s\n", rgb_format);
    92                 return PIX_FMT_RGB24;
    93         }
    94 }
    95 
    96 
    9772static void codec_error(vpx_codec_ctx_t *ctx, const char *s) {
    9873    printf("%s: %s\n", s, vpx_codec_error(ctx));
    9974    return;
     
    125100                return NULL;
    126101        }
    127102        ctx->rgb_format = rgb;
    128         ctx->use_swscale = 1;
    129103        ctx->width = width;
    130104        ctx->height = height;
    131         if (ctx->use_swscale) {
    132                 int pf = get_swscale_pixel_format(ctx->rgb_format);
    133                 ctx->rgb2yuv = sws_getContext(width, height, pf, width, height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);
    134         }
    135105        return ctx;
    136106}
    137107
    138108void clean_encoder(struct vpx_context *ctx)
    139109{
    140         if (ctx->rgb2yuv)
    141                 sws_freeContext(ctx->rgb2yuv);
    142110        vpx_codec_destroy(&ctx->codec);
    143111        free(ctx);
    144112}
     
    160128                free(ctx);
    161129                return NULL;
    162130        }
    163         ctx->use_swscale = use_swscale;
    164131        ctx->width = width;
    165132        ctx->height = height;
    166         if (ctx->use_swscale)
    167                 ctx->yuv2rgb = sws_getContext(width, height, PIX_FMT_YUV420P, width, height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
    168133        return  ctx;
    169134}
    170135
    171136void clean_decoder(struct vpx_context *ctx)
    172137{
    173         if (ctx->yuv2rgb)
    174                 sws_freeContext(ctx->yuv2rgb);
    175138        vpx_codec_destroy(&ctx->codec);
    176139        free(ctx);
    177140}
    178141
    179 vpx_image_t* csc_image_rgb2yuv(struct vpx_context *ctx, const uint8_t *in, int stride)
    180 {
    181         vpx_image_t *image = malloc(sizeof(vpx_image_t));
    182         if (image==NULL)
    183                 return NULL;
    184         if (!vpx_img_alloc(image, VPX_IMG_FMT_I420, ctx->width, ctx->height, 1)) {
    185                 printf("Failed to allocate image %dx%d\n", ctx->width, ctx->height);
    186                 return NULL;
    187         }
    188         /* Colorspace conversion (RGB -> I420) */
    189         sws_scale(ctx->rgb2yuv, &in, &stride, 0, ctx->height, image->planes, image->stride);
    190         image->w = ctx->width;
    191         image->h = ctx->height;
    192         image->d_w = ctx->width;
    193         image->d_h = ctx->height;
    194         return image;
    195 }
    196 
    197142int compress_image(struct vpx_context *ctx, vpx_image_t *image, uint8_t **out, int *outsz)
    198143{
    199144        const vpx_codec_cx_pkt_t *pkt;
     
    223168        return 0;
    224169}
    225170
    226 int csc_image_yuv2rgb(struct vpx_context *ctx, uint8_t *in[3], const int stride[3], uint8_t **out, int *outsz, int *outstride)
    227 {
    228         uint8_t *dst[4] = { xmemalign(ctx->height * ctx->width * 3), NULL, NULL, NULL };
    229         int dststride[4] = { ctx->width * 3, 0, 0, 0 };
    230 
    231         if (!ctx->yuv2rgb)
    232                 return 1;
    233 
    234         sws_scale(ctx->yuv2rgb, (const uint8_t * const*) in, stride, 0, ctx->height, dst, dststride);
    235 
    236         /* Output (must be freed!) */
    237         *out = dst[0];
    238         *outsz = dststride[0] * ctx->height;
    239         *outstride = dststride[0];
    240 
    241         return 0;
    242 }
    243 
    244171int decompress_image(struct vpx_context *ctx, const uint8_t *in, int size, uint8_t *(*out)[3], int *outsize, int (*outstride)[3])
    245172{
    246173        vpx_image_t      *img;
  • xpra/codecs/vpx/vpxlib.h

     
    3131/** Cleanup decoding context. Must be freed after calling this function. */
    3232void clean_decoder(struct vpx_context *ctx);
    3333
    34 /** Colourspace conversion.
    35  * Note: you must call compress_image to free the image buffer.
    36  @param in: Input buffer, format is packed RGB24.
    37  @param stride: Input stride (size is taken from context).
    38  @return: the converted picture.
    39 */
    40 vpx_image_t* csc_image_rgb2yuv(struct vpx_context *ctx, const uint8_t *in, int stride);
    41 
    42 /** Colorspace conversion.
    43  @param in: Input picture (3 planes).
    44  @param stride: Input strides (3 planes).
    45  @param out: Will be set to point to the output data in packed RGB24 format. Must be freed after use by calling free().
    46  @param outsz: Will be set to the size of the output buffer.
    47  @param outstride: Output stride.
    48  @return non zero on error.
    49 */
    50 int csc_image_yuv2rgb(struct vpx_context *ctx, uint8_t *in[3], const int stride[3], uint8_t **out, int *outsz, int *outstride);
    51 
    5234/** Compress an image using the given context.
    5335 @param pic_in: the input image, as returned by csc_image
    5436 @param out: Will be set to point to the output data. This output buffer MUST NOT BE FREED and will be erased on the
  • xpra/scripts/config.py

     
    2121except:
    2222    has_PIL = False
    2323
    24 has_vpx = False
     24has_vpx_enc = False
     25has_vpx_dec = False
    2526try:
    2627    from xpra.codecs import vpx            #@UnusedImport
    2728    try:
    28         from xpra.codecs.vpx import encoder,decoder      #@UnusedImport @UnresolvedImport @Reimport
    29         has_vpx = True
     29        from xpra.codecs.vpx import encoder      #@UnusedImport @UnresolvedImport @Reimport
     30        has_vpx_enc = True
    3031    except Exception, e:
    31         warn("cannot load vpx codec: %s" % e)
     32        warn("cannot load vpx encoder: %s" % e)
     33    try:
     34        from xpra.codecs.vpx import decoder      #@UnusedImport @UnresolvedImport @Reimport
     35        has_vpx_dec = True
     36    except Exception, e:
     37        warn("cannot load vpx decoder: %s" % e)
    3238except ImportError, e:
    3339    #the vpx module does not exist
    3440    #xpra was probably built with --without-vpx
    3541    pass
    3642
    37 has_x264 = False
     43has_enc_x264 = False
    3844try:
    39     from xpra.codecs import x264           #@UnusedImport
     45    from xpra.codecs import enc_x264            #@UnusedImport
    4046    try:
    41         from xpra.codecs.x264 import encoder,decoder     #@UnusedImport @UnresolvedImport
    42         has_x264 = True
     47        from xpra.codecs.enc_x264 import encoder     #@UnusedImport @UnresolvedImport
     48        has_enc_x264 = True
    4349    except Exception, e:
    44         warn("cannot load x264 codec: %s" % e)
     50        warn("cannot load x264: %s" % e)
    4551except ImportError, e:
    4652    #the x264 module does not exist
    4753    #xpra was probably built with --without-x264
    4854    pass
    4955
     56has_csc_swscale = False
     57try:
     58    from xpra.codecs import csc_swscale         #@UnusedImport
     59    try:
     60        from xpra.codecs.csc_swscale import colorspace_converter    #@UnusedImport @UnresolvedImport
     61        has_csc_swscale = True
     62    except Exception, e:
     63        warn("cannot load colorspace_converter: %s" % e)
     64except ImportError, e:
     65    pass
     66
     67has_dec_avcodec = False
     68try:
     69    from xpra.codecs import dec_avcodec         #@UnusedImport
     70    try:
     71        from xpra.codecs.dec_avcodec import decoder    #@UnusedImport @UnresolvedImport
     72        has_dec_avcodec = True
     73    except Exception, e:
     74        warn("cannot load dec_avcodec: %s" % e)
     75except ImportError, e:
     76    pass
     77
    5078has_webp = False
    5179try:
    5280    bytearray()
  • xpra/server/batch_delay_calculator.py

     
    147147    if statistics.avg_decode_speed:
    148148        dec_lat = target_decode_speed/(statistics.avg_decode_speed or target_decode_speed)
    149149    target = max(dam_lat_abs, dam_lat_rel, dec_lat, 0.0)
    150     ms = min(100.0, max(min_speed, 0.0))
     150    ms = min(99.0, max(min_speed, 0.0))
    151151    target_speed = ms + (100.0-ms) * min(1.0, target)
    152152    if DEBUG_VIDEO:
    153153        msg = "get_target_speed: wid=%s, low_limit=%s, min speed=%s, min_damage_latency=%.3f, avg damage in latency=%.3f, target_damage_latency=%.3f, batch.delay=%.1f, dam_lat=%.3f / %.3f, dec_lat=%.3f, target=%i, new_speed=%i", \
  • xpra/server/image_wrapper.py

     
    77
    88class ImageWrapper(object):
    99
    10     def __init__(self, x, y, width, height, pixels, rgb_format, depth, rowstride):
     10    def __init__(self, x, y, width, height, pixels, rgb_format, depth, rowstride, planes=1):
    1111        self.x = x
    1212        self.y = y
    1313        self.width = width
     
    1616        self.rgb_format = rgb_format
    1717        self.depth = depth
    1818        self.rowstride = rowstride
     19        self.planes = planes
    1920
     21    def __str__(self):
     22        return "ImageWrapper(%s:%s)" % (self.rgb_format, self.get_geometry())
     23
    2024    def get_geometry(self):
    2125        return self.x, self.y, self.width, self.height, self.depth
    2226
     
    4751    def get_pixels(self):
    4852        return self.pixels
    4953
     54    def get_planes(self):
     55        return self.planes
    5056
     57
     58    def set_planes(self, planes):
     59        self.planes = planes
     60
    5161    def set_rowstride(self, rowstride):
    5262        self.rowstride = rowstride
    5363
     
    5666
    5767    def set_pixels(self, pixels):
    5868        self.pixels = pixels
     69
     70    def __del__(self):
     71        print("ImageWrapper.__del__()")
     72        self.free()
     73
     74    def free(self):
     75        print("ImageWrapper.free()")
  • xpra/server/server_base.py

     
    1919log = Logger()
    2020
    2121import xpra
    22 from xpra.scripts.config import ENCRYPTION_CIPHERS, PREFERED_ENCODING_ORDER, python_platform, get_codecs, has_PIL, has_vpx, has_x264, has_webp
     22from xpra.scripts.config import ENCRYPTION_CIPHERS, PREFERED_ENCODING_ORDER, python_platform, get_codecs, has_PIL, has_vpx_enc, has_enc_x264, has_webp
    2323from xpra.scripts.server import deadly_signal
    2424from xpra.net.bytestreams import SocketConnection
    2525from xpra.os_util import get_hex_uuid, SIGNAMES
     
    3333
    3434SERVER_CORE_ENCODINGS = ["rgb24", "rgb32"]
    3535for test, formats in (
    36                       (has_vpx    , ["vpx"]),
    37                       (has_x264   , ["x264"]),
     36                      (has_vpx_enc, ["vpx"]),
     37                      (has_enc_x264,["x264"]),
    3838                      (has_webp   , ["webp"]),
    3939                      (has_PIL    , ["png", "png/L", "png/P", "jpeg"]),
    4040                ):
  • xpra/server/window_source.py

     
    5252from xpra.net.protocol import zlib_compress, Compressed
    5353from xpra.server.window_stats import WindowPerformanceStatistics
    5454from xpra.simple_stats import add_list_stats
    55 from xpra.server.stats.maths import calculate_time_weighted_average
    5655from xpra.server.batch_delay_calculator import calculate_batch_delay, get_target_speed, get_target_quality
    5756from xpra.server.stats.maths import time_weighted_average
    5857try:
     
    167166        self.uses_swscale = encoding_options.get("uses_swscale", True)
    168167                                                        #client uses uses_swscale (has extra limits on sizes)
    169168                                                        #unused since we still use swscale on the server...
     169        self.uses_csc_atoms = encoding_options.get("csc_atoms", False)
    170170        from xpra.server.server_base import SERVER_CORE_ENCODINGS
    171171        self.SERVER_CORE_ENCODINGS = SERVER_CORE_ENCODINGS
    172172        self.supports_delta = []
     
    187187        self._mmap_size = mmap_size
    188188
    189189        # video codecs:
     190        self._csc_encoder = None
    190191        self._video_encoder = None
    191         self._video_encoder_lock = Lock()               #to ensure we serialize access to the encoder and its internals
     192        self._encoder_lock = Lock()               #to ensure we serialize access to the encoder and its internals
    192193        # general encoding tunables (mostly used by video encoders):
    193194        self._encoding_quality = maxdeque(NRECS)   #keep track of the target encoding_quality: (event time, encoding speed)
    194195        self._encoding_speed = maxdeque(NRECS)     #keep track of the target encoding_speed: (event time, encoding speed)
     
    203204
    204205    def cleanup(self):
    205206        self.cancel_damage()
    206         self.video_encoder_cleanup()
     207        self.encoder_cleanup()
    207208        self._damage_cancelled = float("inf")
    208209        self.statistics.reset()
    209210        debug("encoding_totals for wid=%s with primary encoding=%s : %s", self.wid, self.encoding, self.statistics.encoding_totals)
    210211
    211     def video_encoder_cleanup(self):
     212    def encoder_cleanup(self):
    212213        """ Video encoders (x264 and vpx) require us to run
    213214            cleanup code to free the memory they use.
    214215        """
    215216        try:
    216             self._video_encoder_lock.acquire()
     217            self._encoder_lock.acquire()
     218            if self._csc_encoder:
     219                self.do_csc_encoder_cleanup()
    217220            if self._video_encoder:
    218221                self.do_video_encoder_cleanup()
    219222        finally:
    220             self._video_encoder_lock.release()
     223            self._encoder_lock.release()
    221224
     225    def do_csc_encoder_cleanup(self):
     226        self._csc_encoder.clean()
     227        self._csc_encoder = None
     228
    222229    def do_video_encoder_cleanup(self):
    223230        self._video_encoder.clean()
    224231        self._video_encoder = None
     
    254261            #we must clean the video encoder to ensure
    255262            #we will resend a key frame because it looks like we will
    256263            #drop a frame which is being processed
    257             self.video_encoder_cleanup()
     264            self.encoder_cleanup()
    258265
    259266    def cancel_expire_timer(self):
    260267        if self.expire_timer:
     
    352359        if self._video_encoder and not self._video_encoder.is_closed():
    353360            #set them with the lock held:
    354361            try:
    355                 self._video_encoder_lock.acquire()
     362                self._encoder_lock.acquire()
    356363                if not self._video_encoder.is_closed():
    357364                    self._video_encoder.set_encoding_speed(self.get_current_encoding_speed())
    358365                    self._video_encoder.set_encoding_quality(self.get_current_encoding_quality())
    359366            finally:
    360                 self._video_encoder_lock.release()
     367                self._encoder_lock.release()
    361368
    362369
    363370    def damage(self, window, x, y, w, h, options={}):
     
    10131020    def make_video_encoder(self, coding):
    10141021        assert coding in self.SERVER_CORE_ENCODINGS
    10151022        if coding=="x264":
    1016             from xpra.codecs.x264.encoder import Encoder as x264Encoder   #@UnresolvedImport
     1023            from xpra.codecs.enc_x264.encoder import Encoder as x264Encoder   #@UnresolvedImport
    10171024            return x264Encoder()
    10181025        elif coding=="vpx":
    10191026            from xpra.codecs.vpx.encoder import Encoder as vpxEncoder     #@UnresolvedImport
     
    10361043        assert x==0 and y==0, "invalid position: %s,%s" % (x,y)
    10371044        rgb_format = image.get_rgb_format()
    10381045        try:
    1039             self._video_encoder_lock.acquire()
     1046            YUV_FORMAT = "YUV420P"
     1047            self._encoder_lock.acquire()
     1048            if self._csc_encoder:
     1049                if self._csc_encoder.get_src_format()!=rgb_format:
     1050                    debug("video_encode csc: wid=%s, switching rgb_format from %s to %s", self.wid, self._csc_encoder.get_src_format(), rgb_format)
     1051                    self.do_csc_encoder_cleanup()
     1052                elif self._csc_encoder.get_dst_format()!=YUV_FORMAT:
     1053                    debug("video_encode csc: wid=%s, switching yuv_format from %s to %s", self.wid, self._csc_encoder.get_dst_format(), YUV_FORMAT)
     1054                    self.do_csc_encoder_cleanup()
     1055                elif self._csc_encoder.get_width()!=w or self._video_encoder.get_height()!=h:
     1056                    debug("video_encode csc: %s: window dimensions have changed from %sx%s to %sx%s", coding, self._csc_encoder.get_width(), self._csc_encoder.get_height(), w, h)
     1057                    self.do_csc_encoder_cleanup()
     1058            if self._csc_encoder is None:
     1059                debug("video_encode csc: %s: new encoder for wid=%s %sx%s, using rgb_format=%s", coding, wid, w, h, rgb_format)
     1060                from xpra.codecs.csc_swscale.colorspace_converter import ColorspaceConverter    #@UnresolvedImport
     1061                self._csc_encoder = ColorspaceConverter()
     1062                self._csc_encoder.init_context(w, h, rgb_format, YUV_FORMAT)
     1063
     1064            yuv = self._csc_encoder.convert_image(image)
     1065            debug("video_encode csc: yuv image=%s", yuv)
     1066            if not yuv:
     1067                log.error("video_encode csc: ouch, %s conversion failed", self._csc_encoder.get_dst_format())
     1068                return None, None
     1069
    10401070            if self._video_encoder:
    1041                 if self._video_encoder.get_rgb_format()!=rgb_format:
    1042                     debug("video_encode: wid=%s, switching rgb_format from %s to %s", self.wid, self._video_encoder.get_rgb_format(), rgb_format)
     1071                if self._video_encoder.get_src_format()!=YUV_FORMAT:
     1072                    debug("video_encode encoder: wid=%s, switching video rgb_format from %s to %s", self.wid, self._video_encoder.get_src_format(), YUV_FORMAT)
    10431073                    self.do_video_encoder_cleanup()
    10441074                elif self._video_encoder.get_type()!=coding:
    1045                     debug("video_encode: wid=%s, switching encoding from %s to %s", self.wid, self._video_encoder.get_type(), coding)
     1075                    debug("video_encode encoder: wid=%s, switching video encoding from %s to %s", self.wid, self._video_encoder.get_type(), coding)
    10461076                    self.do_video_encoder_cleanup()
    10471077                elif self._video_encoder.get_width()!=w or self._video_encoder.get_height()!=h:
    1048                     debug("video_encode: %s: window dimensions have changed from %sx%s to %sx%s", coding, self._video_encoder.get_width(), self._video_encoder.get_height(), w, h)
    1049                     old_pc = self._video_encoder.get_width() * self._video_encoder.get_height()
     1078                    debug("video_encode encoder: %s: window dimensions have changed from %sx%s to %sx%s", coding, self._video_encoder.get_width(), self._video_encoder.get_height(), w, h)
    10501079                    self._video_encoder.clean()
    10511080                    self._video_encoder.init_context(w, h, rgb_format, self.encoding_options)
    1052                     #if we had an encoding speed set, restore it (also scaled):
    1053                     if len(self._encoding_speed)>0:
    1054                         _, recent_speed = calculate_time_weighted_average(list(self._encoding_speed))
    1055                         new_pc = w * h
    1056                         new_speed = max(0, min(100, recent_speed*new_pc/old_pc))
    1057                         self._video_encoder.set_encoding_speed(new_speed)
     1081                    #self._video_encoder.set_encoding_speed(self.get_current_encoding_speed())
    10581082            if self._video_encoder is None:
    1059                 debug("video_encode: %s: new encoder for wid=%s %sx%s, using rgb_format=%s", coding, wid, w, h, rgb_format)
     1083                debug("video_encode encoder: %s: new encoder for wid=%s %sx%s, using yuv_format=%s", coding, wid, w, h, YUV_FORMAT)
    10601084                self._video_encoder = self.make_video_encoder(coding)
    1061                 self._video_encoder.init_context(w, h, rgb_format, self.encoding_options)
    1062             data, client_options = self._video_encoder.compress_image(image, options)
     1085                self._video_encoder.init_context(w, h, YUV_FORMAT, self.encoding_options)
     1086
     1087            data, client_options = self._video_encoder.compress_image(yuv, options)
     1088            yuv.free()
     1089            del yuv
    10631090            if data is None:
    1064                 log.error("%s: ouch, compression failed", coding)
     1091                log.error("video_encode: ouch, %s compression failed", coding)
    10651092                return None, None
    1066             debug("video_encode: %s wid=%s, result is %s bytes, client options=%s", coding, wid, len(data), client_options)
     1093            debug("video_encode encoder: %s wid=%s, result is %s bytes, client options=%s", coding, wid, len(data), client_options)
    10671094            return Compressed(coding, data), client_options
    10681095        finally:
    1069             self._video_encoder_lock.release()
     1096            self._encoder_lock.release()
    10701097
    10711098    def rgb_reformat(self, image):
    10721099        #need to convert to a supported format!
  • xpra/x11/gtk_x11/gdk_bindings.pyx

     
    755755    cdef int height                                 #@DuplicatedSignature
    756756    cdef int depth                                  #@DuplicatedSignature
    757757    cdef int rowstride
     758    cdef int planes
    758759    cdef char *rgb_format
    759760    cdef char *pixels
    760761    cdef object del_callback
     
    771772        self.height = height
    772773        self.rgb_format = ""
    773774        self.rowstride = 0
     775        self.planes = 0
    774776
    775777    cdef set_image(self, XImage* image):
    776778        self.image = image
     
    811813    def get_rowstride(self):
    812814        return self.rowstride
    813815
     816    def get_planes(self):
     817        return self.planes
     818
    814819    def get_depth(self):
    815820        return self.depth
    816821