xpra icon
Bug tracker and wiki

Ticket #1423: dec_jpeg.patch

File dec_jpeg.patch, 15.8 KB (added by Antoine Martin, 4 years ago)

decode jpeg to RGB24

  • xpra/client/gtk2/pixmap_backing.py

     
    2424    PIXMAP_RGB_MODES += ["BGRX", "BGRA", "BGR"]
    2525
    2626
    27 INTERP_DICT = {"nearest"    : gdk.INTERP_NEAREST,
    28                "tiles"      : gdk.INTERP_TILES,
    29                "bilinear"   : gdk.INTERP_BILINEAR,
    30                "hyper"      : gdk.INTERP_HYPER}
     27INTERP_DICT = {
     28    "nearest"    : gdk.INTERP_NEAREST,
     29    "tiles"      : gdk.INTERP_TILES,
     30    "bilinear"   : gdk.INTERP_BILINEAR,
     31    "hyper"      : gdk.INTERP_HYPER,
     32    }
    3133SCALING_INTERP_STR = os.environ.get("XPRA_SCALING_INTERPOLATION", "HYPER").lower()
    3234SCALING_INTERP = INTERP_DICT.get(SCALING_INTERP_STR)
    3335if not SCALING_INTERP:
  • xpra/client/window_backing_base.py

     
    2121
    2222DELTA_BUCKETS = envint("XPRA_DELTA_BUCKETS", 5)
    2323INTEGRITY_HASH = envbool("XPRA_INTEGRITY_HASH", False)
    24 WEBP_PILLOW = envbool("XPRA_WEBP_PILLOW", False)
    2524
    2625#ie:
    2726#CSC_OPTIONS = { "YUV420P" : {"RGBX" : [swscale.spec], "BGRX" : ...} }
     
    8685        PIL = get_codec("dec_pillow")
    8786        if PIL:
    8887            self._PIL_encodings = PIL.get_encodings()
     88        self.jpeg_decoder = get_codec("dec_jpeg")
    8989        self.draw_needs_refresh = True
    9090        self.mmap = None
    9191        self.mmap_enabled = False
     
    194194        return rgb_data
    195195
    196196
     197    def paint_jpeg(self, img_data, x, y, width, height, options, callbacks):
     198        image = self.jpeg_decoder.decompress(img_data, width, height, options)
     199        log.warn("paint_jpeg: image=%s", image)
     200        paint_options = typedict(options)
     201        rgb_format = "RGB"
     202        paint_options["rgb_format"] = rgb_format
     203        self.idle_add(self.do_paint_rgb, rgb_format, image.get_pixels(), x, y, width, height, image.get_rowstride(), paint_options, callbacks)
     204
     205
    197206    def paint_image(self, coding, img_data, x, y, width, height, options, callbacks):
    198207        """ can be called from any thread """
    199208        #log("paint_image(%s, %s bytes, %s, %s, %s, %s, %s, %s)", coding, len(img_data), x, y, width, height, options, callbacks)
     
    474483                self.paint_rgb(rgb_format, img_data, x, y, width, height, rowstride, options, callbacks)
    475484            elif coding in VIDEO_DECODERS:
    476485                self.paint_with_video_decoder(VIDEO_DECODERS.get(coding), coding, img_data, x, y, width, height, options, callbacks)
     486            elif coding=="jpeg" and self.jpeg_decoder:
     487                self.paint_jpeg(img_data, x, y, width, height, options, callbacks)
    477488            elif coding in self._PIL_encodings:
    478489                self.paint_image(coding, img_data, x, y, width, height, options, callbacks)
    479490            elif coding == "scroll":
  • xpra/codecs/jpeg/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2017 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/jpeg/decoder.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2017 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
     6from xpra.log import Logger
     7log = Logger("encoder", "jpeg")
     8
     9from xpra.buffers.membuf cimport getbuf, MemBuf
     10from xpra.codecs.image_wrapper import ImageWrapper
     11from libc.stdint cimport uint8_t, uint32_t, uintptr_t
     12from xpra.buffers.membuf cimport getbuf, MemBuf
     13
     14
     15ctypedef int boolean
     16ctypedef unsigned int JDIMENSION
     17
     18cdef extern from "jpeglib.h":
     19    int JPEG_LIB_VERSION
     20
     21    ctypedef int J_COLOR_SPACE
     22    J_COLOR_SPACE JCS_UNKNOWN           # error/unspecified
     23    J_COLOR_SPACE JCS_GRAYSCALE         # monochrome
     24    J_COLOR_SPACE JCS_RGB               # red/green/blue as specified by the RGB_RED
     25                                        # RGB_GREEN, RGB_BLUE, and RGB_PIXELSIZE macros
     26    J_COLOR_SPACE JCS_YCbCr             # Y/Cb/Cr (also known as YUV)
     27    J_COLOR_SPACE JCS_CMYK              # C/M/Y/K
     28    J_COLOR_SPACE JCS_YCCK              # Y/Cb/Cr/K
     29    J_COLOR_SPACE JCS_EXT_RGB           # red/green/blue
     30    J_COLOR_SPACE JCS_EXT_RGBX          # red/green/blue/x
     31    J_COLOR_SPACE JCS_EXT_BGR           # blue/green/red
     32    J_COLOR_SPACE JCS_EXT_BGRX          # blue/green/red/x
     33    J_COLOR_SPACE JCS_EXT_XBGR          # x/blue/green/red
     34    J_COLOR_SPACE JCS_EXT_XRGB          # x/red/green/blue
     35    #
     36    # When out_color_space it set to JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR,
     37    # or JCS_EXT_XRGB during decompression, the X byte is undefined, and in
     38    # order to ensure the best performance, libjpeg-turbo can set that byte to
     39    # whatever value it wishes.  Use the following colorspace constants to
     40    # ensure that the X byte is set to 0xFF, so that it can be interpreted as an
     41    # opaque alpha channel. */
     42    J_COLOR_SPACE JCS_EXT_RGBA          # red/green/blue/alpha
     43    J_COLOR_SPACE JCS_EXT_BGRA          # blue/green/red/alpha
     44    J_COLOR_SPACE JCS_EXT_ABGR          # alpha/blue/green/red
     45    J_COLOR_SPACE JCS_EXT_ARGB          # alpha/red/green/blue
     46    J_COLOR_SPACE JCS_RGB565            # 5-bit red/6-bit green/5-bit blue
     47
     48    cdef struct jpeg_common_struct:
     49        pass
     50    ctypedef jpeg_common_struct* j_common_ptr
     51
     52    cdef struct jpeg_source_mgr:
     53        pass
     54    cdef struct jpeg_decompress_struct:
     55        jpeg_error_mgr *err             # Error handler module
     56        jpeg_source_mgr *src
     57        int input_components            # # of color components in input image
     58        J_COLOR_SPACE in_color_space    # colorspace of input image
     59        J_COLOR_SPACE out_color_space   # colorspace for output
     60        JDIMENSION output_width         # scaled image width
     61        JDIMENSION output_height        # scaled image height
     62        int out_color_components        # # of color components in out_color_space
     63        int output_components           # # of color components returned
     64                                        # output_components is 1 (a colormap index) when quantizing colors
     65                                        # otherwise it equals out_color_components.
     66        JDIMENSION output_scanline      # 0 .. output_height-1
     67
     68
     69    cdef struct jpeg_error_mgr:
     70        # Error exit handler: does not return to caller
     71        void (*error_exit) (j_common_ptr cinfo)
     72        # Conditionally emit a trace or warning message
     73        void (*emit_message) (j_common_ptr cinfo, int msg_level)
     74        # Routine that actually outputs a trace or error message
     75        void (*output_message) (j_common_ptr cinfo)
     76        # Format a message string for the most recent JPEG error or message
     77        void (*format_message) (j_common_ptr cinfo, char *buffer)
     78        # Reset error state variables at start of a new image
     79        void (*reset_error_mgr) (j_common_ptr cinfo)
     80        # The message ID code and any parameters are saved here.
     81        # A message can have one string parameter or up to 8 int parameters.
     82        int msg_code
     83        #msg_parm union / TODO
     84        int trace_level                 # max msg_level that will be displayed
     85        long num_warnings               # number of corrupt-data warnings
     86
     87    jpeg_error_mgr * jpeg_std_error(jpeg_error_mgr *err)
     88
     89    ctypedef jpeg_decompress_struct* j_decompress_ptr
     90
     91    ctypedef unsigned char JSAMPLE
     92    ctypedef JSAMPLE *JSAMPROW          # ptr to one image row of pixel samples.
     93    ctypedef JSAMPROW *JSAMPARRAY       # ptr to some rows (a 2-D sample array)
     94    ctypedef JSAMPARRAY *JSAMPIMAGE
     95
     96    void jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize)
     97    void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer, unsigned long insize)
     98    boolean jpeg_start_decompress(j_decompress_ptr cinfo)
     99    int jpeg_read_header(j_decompress_ptr cinfo, boolean require_image)
     100    JDIMENSION jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)
     101    void jpeg_finish_decompress(j_decompress_ptr cinfo)
     102    void jpeg_destroy_decompress(j_decompress_ptr cinfo)
     103
     104
     105cdef extern from "jerror.h":
     106    pass
     107
     108cdef extern from "stdlib.h":
     109    void free(void *ptr)
     110
     111
     112cdef extern from "../../buffers/memalign.h":
     113    void *xmemalign(size_t size)
     114
     115cdef extern from "../../buffers/buffers.h":
     116    object memory_as_pybuffer(void* ptr, Py_ssize_t buf_len, int readonly)
     117    int    object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len)
     118
     119
     120def get_version():
     121    return JPEG_LIB_VERSION
     122
     123def get_encodings():
     124    return ["jpeg"]
     125
     126
     127cdef inline uint32_t roundup(uint32_t n, uint32_t m):
     128    return (n + m - 1) & ~(m - 1)
     129
     130
     131def decompress(data, int width, int height, options={}):
     132    cdef const uint8_t *buf
     133    cdef Py_ssize_t buf_len
     134    assert object_as_buffer(data, <const void**> &buf, &buf_len)==0, "unable to convert %s to a buffer" % type(data)
     135
     136    cdef jpeg_decompress_struct cinfo
     137    cdef jpeg_error_mgr jerr
     138    cinfo.err = jpeg_std_error(&jerr)
     139    jpeg_CreateDecompress(&cinfo, JPEG_LIB_VERSION, sizeof(jpeg_decompress_struct))
     140
     141    jpeg_mem_src(&cinfo, buf, buf_len)
     142    rc = jpeg_read_header(&cinfo, True)
     143    if rc!=1:
     144        log.error("Error: data does not seem to be a normal JPEG")
     145        return None
     146    jpeg_start_decompress(&cinfo)
     147    assert cinfo.output_width==width and cinfo.output_height==height, "invalid JPEG dimensions: expected %ix%i but got %ix%i" % (width, height, cinfo.output_width, cinfo.output_height)
     148    log("jpeg.decoder decompress image: %ix%i", cinfo.output_width, cinfo.output_height)
     149    cdef int pixel_size = cinfo.output_components
     150    cdef unsigned int rowstride = pixel_size * cinfo.output_width
     151    cdef size_t out_size = rowstride * cinfo.output_height
     152    cdef MemBuf pixels = getbuf(out_size)
     153    cdef uintptr_t rgb = <uintptr_t> pixels.get_mem()   
     154
     155    while cinfo.output_scanline < cinfo.output_height:
     156        assert jpeg_read_scanlines(&cinfo, <JSAMPARRAY> &rgb, 1)==1
     157        rgb += rowstride
     158
     159    jpeg_finish_decompress(&cinfo)
     160    jpeg_destroy_decompress(&cinfo)
     161    return ImageWrapper(0, 0, cinfo.output_width, cinfo.output_height, memoryview(pixels), "RGB", 24, rowstride, ImageWrapper.PACKED)
     162
     163def selftest(full=False):
     164    try:
     165        log("jpeg selftest")
     166        import binascii
     167        data = binascii.unhexlify("ffd8ffe000104a46494600010101004800480000fffe00134372656174656420776974682047494d50ffdb0043000302020302020303030304030304050805050404050a070706080c0a0c0c0b0a0b0b0d0e12100d0e110e0b0b1016101113141515150c0f171816141812141514ffdb00430103040405040509050509140d0b0d1414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414ffc20011080010001003011100021101031101ffc4001500010100000000000000000000000000000008ffc40014010100000000000000000000000000000000ffda000c03010002100310000001aa4007ffc40014100100000000000000000000000000000020ffda00080101000105021fffc40014110100000000000000000000000000000020ffda0008010301013f011fffc40014110100000000000000000000000000000020ffda0008010201013f011fffc40014100100000000000000000000000000000020ffda0008010100063f021fffc40014100100000000000000000000000000000020ffda0008010100013f211fffda000c03010002000300000010924fffc40014110100000000000000000000000000000020ffda0008010301013f101fffc40014110100000000000000000000000000000020ffda0008010201013f101fffc40014100100000000000000000000000000000020ffda0008010100013f101fffd9")
     168        img = decompress(data, 16, 16)
     169        log("decompress(%i bytes)=%s", len(data), img)
     170    finally:
     171        pass
  • xpra/codecs/loader.py

     
    183183        codec_import_check("dec_pillow", "Pillow decoder", "xpra.codecs.pillow", "xpra.codecs.pillow.decode", "decode")
    184184        add_codec_version("dec_pillow", "xpra.codecs.pillow.decode")
    185185
     186        codec_import_check("dec_jpeg", "JPEG decoder", "xpra.codecs.jpeg", "xpra.codecs.jpeg.decoder", "decoder")
     187        add_codec_version("dec_jpeg", "xpra.codecs.jpeg.decoder")
     188
    186189        codec_import_check("dec_vpx", "vpx decoder", "xpra.codecs.vpx", "xpra.codecs.vpx.decoder", "Decoder")
    187190        add_codec_version("vpx", "xpra.codecs.vpx.encoder")
    188191
     
    226229
    227230CSC_CODECS = "csc_swscale", "csc_libyuv"
    228231ENCODER_CODECS = "enc_pillow", "enc_vpx", "enc_x264", "enc_x265", "nvenc7", "enc_ffmpeg"
    229 DECODER_CODECS = "dec_pillow", "dec_vpx", "dec_avcodec2"
     232DECODER_CODECS = "dec_pillow", "dec_vpx", "dec_avcodec2", "dec_jpeg"
    230233
    231234ALL_CODECS = tuple(set(CSC_CODECS + ENCODER_CODECS + DECODER_CODECS))
    232235
  • xpra/log.py

     
    208208                ("libav"        , "libav common code (used by swscale, avcodec and ffmpeg)"),
    209209                ("ffmpeg"       , "ffmpeg encoder"),
    210210                ("pillow"       , "Pillow encoder and decoder"),
     211                ("jpeg"         , "JPEG codec"),
    211212                ("vpx"          , "libvpx encoder and decoder"),
    212213                ("nvenc"        , "nvenc encoder (all versions)"),
    213214                ("x264"         , "libx264 encoder"),
  • setup.py

     
    180180enc_x264_ENABLED        = DEFAULT and pkg_config_ok("--exists", "x264", fallback=WIN32)
    181181enc_x265_ENABLED        = DEFAULT and pkg_config_ok("--exists", "x265")
    182182pillow_ENABLED          = DEFAULT
     183jpeg_ENABLED            = DEFAULT and pkg_config_ok("--exists", "libjpeg")
    183184vpx_ENABLED             = DEFAULT and pkg_config_version("1.3", "vpx", fallback=WIN32)
    184185enc_ffmpeg_ENABLED      = DEFAULT and pkg_config_version("56", "libavcodec")
    185186webcam_ENABLED          = DEFAULT and not OSX
     
    214215#allow some of these flags to be modified on the command line:
    215216SWITCHES = ["enc_x264", "enc_x265", "enc_ffmpeg",
    216217            "nvenc7", "cuda_rebuild",
    217             "vpx", "pillow",
     218            "vpx", "pillow", "jpeg",
    218219            "v4l2",
    219220            "dec_avcodec2", "csc_swscale",
    220221            "csc_libyuv",
     
    941942                   "xpra/codecs/cuda_common/BGRA_to_YUV444.fatbin",
    942943                   "xpra/codecs/enc_x264/encoder.c",
    943944                   "xpra/codecs/enc_x265/encoder.c",
     945                   "xpra/codecs/jpeg/encode.c",
     946                   "xpra/codecs/jpeg/decode.c",
    944947                   "xpra/codecs/enc_ffmpeg/encoder.c",
    945948                   "xpra/codecs/v4l2/constants.pxi",
    946949                   "xpra/codecs/v4l2/pusher.c",
     
    23352338if pillow_ENABLED:
    23362339    external_includes += ["PIL", "PIL.Image", "PIL.WebPImagePlugin"]
    23372340
     2341toggle_packages(jpeg_ENABLED, "xpra.codecs.jpeg")
     2342if jpeg_ENABLED:
     2343    jpeg_pkgconfig = pkgconfig("libjpeg")
     2344    cython_add(Extension("xpra.codecs.jpeg.encoder",
     2345                ["xpra/codecs/jpeg/encoder.pyx", buffers_c],
     2346                **jpeg_pkgconfig))
     2347    cython_add(Extension("xpra.codecs.jpeg.decoder",
     2348                ["xpra/codecs/jpeg/decoder.pyx"]+membuffers_c,
     2349                **jpeg_pkgconfig))
     2350
    23382351#swscale and avcodec2 use libav_common/av_log:
    23392352libav_common = dec_avcodec2_ENABLED or csc_swscale_ENABLED
    23402353toggle_packages(libav_common, "xpra.codecs.libav_common")