xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #94: xpra-x264-r4.2.patch

File xpra-x264-r4.2.patch, 27.0 KB (added by Antoine Martin, 10 years ago)

now using proper cython classes to simplify code

  • setup.py

     
    6464                ["xpra/wait_for_x_server.pyx"],
    6565                **pkgconfig("x11")
    6666                ),
     67      Extension("xpra.x264.encoder",
     68                ["xpra/x264/encoder.pyx", "xpra/x264/x264lib.c"],
     69                **pkgconfig("x264", "libswscale", "libavcodec")
     70                ),
     71      Extension("xpra.x264.decoder",
     72                ["xpra/x264/decoder.pyx", "xpra/x264/x264lib.c"],
     73                **pkgconfig("x264", "libswscale", "libavcodec")
     74                ),
    6775      ]
    6876
    6977    cmdclass = {'build_ext': build_ext}
     
    161169              "parti", "parti.trays", "parti.addons", "parti.scripts",
    162170              "xpra", "xpra.scripts", "xpra.platform",
    163171              "xpra.xposix", "xpra.win32", "xpra.darwin",
     172              "xpra.x264"
    164173              ]
    165174    scripts=["scripts/parti", "scripts/parti-repl",
    166175             "scripts/xpra",
  • xpra/server.py

     
    230230        self._damage_packet_queue = Queue(2)
    231231
    232232        self._closed = False
     233        self._on_close = []
    233234
    234235        def start_daemon_thread(target, name):
    235236            t = Thread(target=target)
     
    244245        self._closed = True
    245246        self._damage_request_queue.put(None, block=False)
    246247        self._damage_data_queue.put(None, block=False)
     248        for cb in self._on_close:
     249            try:
     250                log.info("calling %s", cb)
     251                cb()
     252            except:
     253                log.error("error on close callback %s", cb, exc_info=True)
     254        self._on_close = []
    247255
    248256    def _have_more(self):
    249257        return not self._closed and bool(self._ordinary_packets) or not self._damage_packet_queue.empty()
     
    411419                        (x, y, w, h) = get_rectangle_from_region(damage)
    412420                        pixel_count += w*h
    413421                        #favor full screen updates over many regions:
    414                         if pixel_count+4096*len(regions)>=full_pixels*9/10:
     422                        if pixel_count+4096*len(regions)>=full_pixels*9/10 or self._encoding=="x264":
    415423                            regions = [(0, 0, ww, wh, True)]
    416424                            break
    417425                        regions.append((x, y, w, h, False))
     
    478486                data = mmap_data
    479487        #encode to jpeg/png:
    480488        if coding in ["jpeg", "png"]:
     489            assert coding in ENCODINGS
    481490            import Image
    482491            im = Image.fromstring("RGB", (w, h), data, "raw", "RGB", rowstride)
    483492            buf = StringIO()
     
    493502                im.save(buf, self._encoding.upper())
    494503            data = buf.getvalue()
    495504            buf.close()
     505        elif coding=="x264":
     506            assert coding in ENCODINGS
     507            #x264 needs sizes divisible by 2:
     508            width = w & 0xFFFE
     509            height = h & 0xFFFE
     510            from xpra.x264.encoder import ENCODERS, Encoder
     511            encoder = ENCODERS.get(wid)
     512            def close_encoder():
     513                encoder.clean()
     514                del ENCODERS[wid]
     515            if encoder and (encoder.get_width()!=width or encoder.get_height()!=height):
     516                log.info("x264: window dimensions have changed from %s to %s", (encoder.get_width(), encoder.get_height()), (width, height))
     517                close_encoder()
     518                encoder = None
     519            if encoder is None:
     520                encoder = Encoder()
     521                encoder.init(width, height)
     522                ENCODERS[wid] = encoder
     523                self._on_close.append(close_encoder)
     524            err, size, data = encoder.compress_image(data, rowstride)
     525            if err!=0:
     526                log.error("x264: ouch, compression error %s", err)
     527                return None
     528            log.info("x264: compressed data(%sx%s) = %s, type=%s, first 10 bytes: %s", w, h, size, type(data), [ord(x) for x in data[:10]])
     529            w,h = width, height
    496530        #check cancellation list again since the code above may take some time:
    497531        #but always send mmap data so we can reclaim the space!
    498532        if coding!="mmap" and sequence>=0 and self._damage_cancelled.get(wid, 0)>=sequence:
  • xpra/x264/__init__.py

    Property changes on: xpra/x264
    ___________________________________________________________________
    Added: svn:ignore
       + codec.c
    
    
     
     1# This file is part of Parti.
     2# Copyright (C) 2012 Antoine Martin <antoine@devloop.org.uk>
     3# Parti 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/x264/testlib.c

     
     1#include <stdio.h>
     2#include <stdint.h>
     3#include <stdlib.h>
     4#include <string.h>
     5#include "x264lib.h"
     6
     7#define X 800
     8#define Y 600
     9#define totalSZ X*Y*3
     10int main(int argc, char **argv)
     11{
     12        struct x264lib_ctx *ctx = init_encoder(X, Y);
     13
     14        uint8_t *b = malloc(totalSZ);
     15        int i;
     16
     17        FILE *in = fopen("x264test.rgb", "r");
     18        fread(b, totalSZ, 1, in);
     19        fclose(in);
     20
     21        /*for (i = 0; i < totalSZ;) {
     22                b[i++] = i;
     23                b[i++] = 255-i;
     24                b[i++] = 0;
     25        }*/
     26
     27        uint8_t *out;
     28        int sz;
     29        printf("Compressing image, size %d...", totalSZ);
     30        compress_image(ctx, b, X*3, &out, &sz);
     31        printf("after compressing %d bytes, ratio %f\n", sz, (float)sz/totalSZ);
     32
     33        clean_encoder(ctx);
     34        free(ctx);
     35
     36        uint8_t *out2;
     37        int sz2;
     38        ctx = init_decoder(X, Y);
     39        decompress_image(ctx, out, sz, &out2, &sz2);
     40        printf("After decompressing, size %d...", sz2);
     41        if (sz2 != totalSZ) {
     42                printf("size doesn't match original!\n");
     43                return 1;
     44        } else
     45                printf("OK\n");
     46
     47        FILE *fout = fopen("decompressed.rgb", "w");
     48        fwrite(out2, sz2, 1, fout);
     49        fclose(fout);
     50        return 0;
     51}
  • xpra/x264/x264lib.c

     
     1/* Copyright (C) 2012 Serviware, Arthur Huillet <arthur dot huillet AT free dot fr>
     2   */
     3#include <stdint.h>
     4#include <stdio.h>
     5#include <stdlib.h>
     6#include <string.h>
     7#include <unistd.h>
     8#include <sys/types.h>
     9#include <sys/stat.h>
     10#include <fcntl.h>
     11#include <x264.h>
     12#include <libswscale/swscale.h>
     13#include <libavcodec/avcodec.h>
     14#include "x264lib.h"
     15
     16struct x264lib_ctx {
     17        // Encoding
     18        x264_t *encoder;
     19        struct SwsContext *rgb2yuv;
     20
     21        // Decoding
     22        AVCodec *codec;
     23    AVCodecContext *codec_ctx;
     24        struct SwsContext *yuv2rgb;
     25
     26        // Both
     27        int width;
     28        int height;
     29};
     30
     31struct x264lib_ctx *init_encoder(int width, int height)
     32{
     33        struct x264lib_ctx *ctx = malloc(sizeof(struct x264lib_ctx));
     34        x264_param_t param;
     35        x264_param_default_preset(&param, "veryfast", "zerolatency");
     36        param.i_threads = 1;
     37        param.i_width = width;
     38        param.i_height = height;
     39        param.i_csp = X264_CSP_I420;
     40        x264_param_apply_profile(&param, "baseline");
     41        ctx->encoder = x264_encoder_open(&param);
     42        ctx->width = width;
     43        ctx->height = height;
     44        ctx->rgb2yuv = sws_getContext(ctx->width, ctx->height, PIX_FMT_RGB24, ctx->width, ctx->height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);
     45
     46        return ctx;
     47}
     48
     49int clean_encoder(struct x264lib_ctx *ctx)
     50{
     51        sws_freeContext(ctx->rgb2yuv);
     52}
     53
     54struct x264lib_ctx *init_decoder(int width, int height)
     55{
     56        struct x264lib_ctx *ctx = malloc(sizeof(struct x264lib_ctx));
     57        ctx->width = width;
     58        ctx->height = height;
     59        ctx->yuv2rgb = sws_getContext(ctx->width, ctx->height, PIX_FMT_YUV420P, ctx->width, ctx->height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
     60
     61    avcodec_register_all();
     62
     63    ctx->codec = avcodec_find_decoder(CODEC_ID_H264);
     64    if (!ctx->codec) {
     65        fprintf(stderr, "codec not found\n");
     66                free(ctx);
     67        return NULL;
     68    }
     69        ctx->codec_ctx = avcodec_alloc_context3(ctx->codec);
     70        ctx->codec_ctx->width = ctx->width;
     71        ctx->codec_ctx->height = ctx->height;
     72        ctx->codec_ctx->pix_fmt = PIX_FMT_YUV420P;
     73        if (avcodec_open(ctx->codec_ctx, ctx->codec) < 0) {
     74        fprintf(stderr, "could not open codec\n");
     75                free(ctx);
     76        return NULL;
     77    }
     78
     79        return ctx;
     80}
     81
     82int clean_decoder(struct x264lib_ctx *ctx)
     83{
     84    avcodec_close(ctx->codec_ctx);
     85    av_free(ctx->codec_ctx);
     86        sws_freeContext(ctx->yuv2rgb);
     87}
     88
     89int compress_image(struct x264lib_ctx *ctx, const uint8_t *in, int stride, uint8_t **out, int *outsz)
     90{
     91        if (!ctx->encoder || !ctx->rgb2yuv)
     92                return 1;
     93
     94        x264_picture_t pic_in, pic_out;
     95        x264_picture_alloc(&pic_in, X264_CSP_I420, ctx->width, ctx->height);
     96
     97        /* Colorspace conversion (RGB -> I420) */
     98        sws_scale(ctx->rgb2yuv, &in, &stride, 0, ctx->height, pic_in.img.plane, pic_in.img.i_stride);
     99
     100        /* Encoding */
     101        pic_in.i_pts = 1;
     102
     103        x264_nal_t* nals;
     104        int i_nals;
     105        int frame_size = x264_encoder_encode(ctx->encoder, &nals, &i_nals, &pic_in, &pic_out);
     106        if (frame_size >= 0) {
     107                /* Do not free that! */
     108                *out = nals[0].p_payload;
     109                *outsz = frame_size;
     110        } else {
     111                fprintf(stderr, "Problem\n");
     112                return 2;
     113        }
     114
     115        return 0;
     116}
     117
     118int decompress_image(struct x264lib_ctx *ctx, uint8_t *in, int size, uint8_t **out, int *outsz)
     119{
     120        if (!ctx->yuv2rgb)
     121                return 1;
     122
     123    int got_picture, len;
     124    AVFrame *picture;
     125    AVPacket avpkt;
     126    av_init_packet(&avpkt);
     127
     128        if (!ctx->codec_ctx || !ctx->codec)
     129                return 1;
     130
     131    printf("Video decoding\n");
     132
     133    picture = avcodec_alloc_frame();
     134
     135        avpkt.data = in;
     136        avpkt.size = size;
     137       
     138        len = avcodec_decode_video2(ctx->codec_ctx, picture, &got_picture, &avpkt);
     139        if (len < 0) {
     140                fprintf(stderr, "Error while decoding frame\n");
     141                *out = NULL;
     142                *outsz = 0;
     143                return 2;
     144        }
     145
     146        AVPicture pic;
     147        avpicture_fill(&pic, malloc(ctx->height * ctx->width * 3), PIX_FMT_RGB24, ctx->width, ctx->height);
     148
     149        /* Colorspace conversion (I420 -> RGB) */
     150        sws_scale(ctx->yuv2rgb, picture->data, picture->linesize, 0, ctx->height, pic.data, pic.linesize);
     151   
     152        av_free(picture);
     153
     154        /* Output (must be freed!) */
     155        *out = pic.data[0];
     156        *outsz = pic.linesize[0] * ctx->height;
     157
     158        printf("Got %p, stride %d, size %d\n", pic.data[0], pic.linesize[0], *outsz);
     159        return 0;
     160}
  • xpra/x264/main.py

     
     1# This file is part of Parti.
     2# Copyright (C) 2012 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3# Copyright (C) 2012 Antoine Martin <antoine@devloop.org.uk>
     4# Parti 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
     7w = 640
     8h = 480
     9
     10f = None
     11try:
     12    f = open("x264test.rgb", mode='rb')
     13    data = f.read()
     14finally:
     15    if f:
     16        f.close()
     17
     18def main():
     19    from xpra.x264.encoder import Encoder
     20    encoder = Encoder()
     21    print("init_x264_encoder(%s,%s)" % (w, h))
     22    encoder.init(w, h)
     23    stride = 800*3
     24    try:
     25        err, size, compressed = encoder.compress_image(data, stride)
     26        if err!=0:
     27            raise Exception("error %s during compression" % err)
     28        print("x264_compress_image(%s bytes, %s)=%s,%s" % (len(data), stride, size, len(compressed)))
     29    finally:
     30        i = encoder.clean()
     31        print("clean_x264_encoder()=%s" % i)
     32
     33    from xpra.x264.decoder import Decoder
     34    decoder = Decoder()
     35    print("init_x264_decoder(%s,%s)" % (w, h))
     36    decoder.init(w, h)
     37    try:
     38        err, size, decompressed = decoder.decompress_image(compressed, size)
     39        print("x264_decompress_image(%s bytes, %s)=%s" % (len(compressed), size, (err, size, len(decompressed))))
     40        assert decompressed==data
     41        if err!=0:
     42            raise Exception("error %s during decompression" % err)
     43    finally:
     44        i = decoder.clean()
     45        print("clean_x264_decoder()=%s" % i)
     46
     47if __name__ == "__main__":
     48    main()
  • xpra/x264/Makefile

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: xpra/x264/x264test.rgb
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
     
     1# This file is part of Parti.
     2# Copyright (C) 2012 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3# Copyright (C) 2012 Antoine Martin <antoine@devloop.org.uk>
     4# Parti 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# This makefile is only used for experimenting/testing
     8# The library and python bindings are built using the standard setup.py file
     9
     10CFLAGS+=$(shell pkg-config  --cflags $(FFMPEG_LIBS))
     11LDFLAGS+=$(shell pkg-config --libs $(FFMPEG_LIBS)) -lm
     12
     13CFLAGS+=-fPIC -W -g3 -O1
     14
     15all: x264lib.so testlib
     16
     17x264lib.so: x264lib.o
     18        $(CC) -shared -Wl,-soname,x264lib.so -o $@ $(LDFLAGS) $< -l x264 -lswscale -lavcodec
     19
     20x264lib.o: x264lib.c x264lib.h
     21        $(CC) $(CFLAGS) x264lib.c -c -o $@
     22
     23testlib: x264lib.so testlib.c
     24        $(CC) $(CFLAGS) testlib.c -o $@ ./x264lib.so -l x264 -lswscale -lavcodec
     25
     26OBJS=$(addsuffix .o,$(EXAMPLES))
     27
     28.phony: all clean
     29
     30
     31clean:
     32        rm -rf x264lib.so x264lib.o
  • xpra/x264/encoder.pyx

     
     1# This file is part of Parti.
     2# Copyright (C) 2008 Nathaniel Smith <njs@pobox.com>
     3# Parti 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
     6#gcc -pthread -shared -O0 build/temp.linux-x86_64-2.7/xpra/x264/codec.o xpra/x264/x264lib.o -L/usr/lib64 -lx264 -lavcodec -lswscale -lpthread -lpython2.7 -o build/lib.linux-x86_64-2.7/xpra/x264/codec.so
     7
     8cdef extern from "Python.h":
     9    ctypedef int Py_ssize_t
     10    ctypedef object PyObject
     11    int PyObject_AsReadBuffer(object obj,
     12                              void ** buffer,
     13                              Py_ssize_t * buffer_len) except -1
     14
     15ctypedef unsigned char uint8_t
     16ctypedef void x264lib_ctx
     17cdef extern from "x264lib.h":
     18    x264lib_ctx* init_encoder(int width, int height)
     19    int clean_encoder(x264lib_ctx *context)
     20    int compress_image(x264lib_ctx *context, uint8_t *input, int stride, uint8_t **out, int *outsz)
     21
     22
     23ENCODERS = {}
     24
     25cdef class Encoder:
     26    cdef x264lib_ctx *context
     27    cdef int width
     28    cdef int height
     29
     30    def __cinit__(self):
     31        self.width = 0
     32        self.height = 0
     33
     34    def __dealloc__(self):
     35        self.clean()
     36
     37    def clean(self):
     38        i = -1
     39        if self.context!=NULL:
     40            i = clean_encoder(self.context)
     41            self.context = NULL
     42        return i
     43
     44    def init(self, width, height):
     45        self.context = init_encoder(width, height)
     46        assert self.context
     47        self.width = width
     48        self.height = height
     49   
     50    def get_width(self):
     51        return self.width
     52
     53    def get_height(self):
     54        return self.height
     55
     56    def compress_image(self, input, rowstride):
     57        cdef uint8_t *cout
     58        cdef int coutsz
     59        cdef uint8_t *buf = <uint8_t *> 0
     60        cdef Py_ssize_t buf_len = 0
     61        assert self.context!=NULL
     62        PyObject_AsReadBuffer(input, <void **>&buf, &buf_len)
     63        i = compress_image(self.context, buf, rowstride, &cout, &coutsz)
     64        if i!=0:
     65            return i, 0, ""
     66        print("x264_compress_image(..,%s) out size=%s" % (rowstride, coutsz))
     67        coutv = (<char *>cout)[:coutsz]
     68        return  i, coutsz, coutv
  • xpra/x264/x264lib.h

     
     1
     2/** Opaque structure - "context". You must have a context to encode images of a given size */
     3struct x264lib_ctx;
     4
     5/** Create an encoding context for images of a given size.  */
     6struct x264lib_ctx *init_encoder(int width, int height);
     7
     8/** Create a decoding context for images of a given size. */
     9struct x264lib_ctx *init_decoder(int width, int height);
     10
     11/** Cleanup encoding context. Must be freed after calling this function. */
     12int clean_encoder(struct x264lib_ctx *);
     13
     14/** Cleanup decoding context. Must be freed after calling this function. */
     15int clean_decoder(struct x264lib_ctx *);
     16
     17/** Compress an image using the given context.
     18 @param in: Input buffer, format is packed RGB24.
     19 @param stride: Input stride (size is taken from context).
     20 @param out: Will be set to point to the output data. This output buffer MUST NOT BE FREED and will be erased on the
     21 next call to compress_image.
     22 @param outsz: Output size
     23*/
     24int compress_image(struct x264lib_ctx *, const uint8_t *in, int stride, uint8_t **out, int *outsz);
     25
     26/** Decompress an image using the given context.
     27 @param in: Input buffer, format is H264.
     28 @param size: Input size.
     29 @param out: Will be set to point to the output data in RGB24 format.
     30 @param outsz: Output size.
     31*/
     32int decompress_image(struct x264lib_ctx *, uint8_t *in, int size, uint8_t **out, int *outsz);
  • xpra/x264/decoder.pyx

     
     1# This file is part of Parti.
     2# Copyright (C) 2008 Nathaniel Smith <njs@pobox.com>
     3# Parti 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
     6#gcc -pthread -shared -O0 build/temp.linux-x86_64-2.7/xpra/x264/codec.o xpra/x264/x264lib.o -L/usr/lib64 -lx264 -lavcodec -lswscale -lpthread -lpython2.7 -o build/lib.linux-x86_64-2.7/xpra/x264/codec.so
     7
     8from libc.stdlib cimport free
     9
     10cdef extern from "Python.h":
     11    ctypedef int Py_ssize_t
     12    ctypedef object PyObject
     13    int PyObject_AsReadBuffer(object obj,
     14                              void ** buffer,
     15                              Py_ssize_t * buffer_len) except -1
     16
     17ctypedef unsigned char uint8_t
     18ctypedef void x264lib_ctx
     19cdef extern from "x264lib.h":
     20    x264lib_ctx* init_decoder(int width, int height)
     21    int clean_decoder(x264lib_ctx *context)
     22    int decompress_image(x264lib_ctx *context, uint8_t *input, int size, uint8_t **out, int *outsz)
     23
     24
     25DECODERS = {}
     26
     27cdef class Decoder:
     28    cdef x264lib_ctx *context
     29    cdef uint8_t *last_image
     30    cdef int width
     31    cdef int height
     32
     33    def __cinit__(self):
     34        pass
     35
     36    def __dealloc__(self):
     37        self.clean()
     38
     39    def clean(self):
     40        i = -1
     41        if self.context!=NULL:
     42            i = clean_decoder(self.context)
     43            self.context = NULL
     44        return i
     45
     46    def init(self, width, height):
     47        self.context = init_decoder(width, height)
     48        assert self.context
     49        self.width = width
     50        self.height = height
     51   
     52    def get_width(self):
     53        return self.width
     54
     55    def get_height(self):
     56        return self.height
     57
     58    def decompress_image(self, input, size):
     59        cdef uint8_t *dout
     60        cdef int doutsz
     61        cdef unsigned char * buf = <uint8_t *> 0
     62        cdef Py_ssize_t buf_len = 0
     63        assert self.context!=NULL
     64        assert self.last_image==NULL
     65        PyObject_AsReadBuffer(input, <void **>&buf, &buf_len)
     66        i = decompress_image(self.context, buf, size, &dout, &doutsz)
     67        self.last_image = dout
     68        if i!=0:
     69            return i, 0, ""
     70        doutv = (<char *>dout)[:doutsz]
     71        return  i, doutsz, doutv
     72
     73    def free_image(self):
     74        assert self.last_image!=NULL
     75        free(self.last_image)
  • xpra/client.py

     
    181181        self.connect("notify::has-toplevel-focus", self._focus_change)
    182182
    183183    def new_backing(self, w, h):
    184         self._backing = new_backing(w, h, self._backing, self._client.supports_mmap, self._client.mmap)
     184        self._backing = new_backing(self._id, w, h, self._backing, self._client.supports_mmap, self._client.mmap)
    185185
    186186    def update_metadata(self, metadata):
    187187        self._metadata.update(metadata)
  • xpra/window_backing.py

     
    2929This is a complete waste of CPU! Please complain to pycairo.
    3030"""
    3131class CairoBacking(object):
    32     def __init__(self, w, h, old_backing, mmap_enabled, mmap):
     32    def __init__(self, wid, w, h, old_backing, mmap_enabled, mmap):
     33        self.wid = wid
    3334        self.mmap_enabled = mmap_enabled
    3435        self.mmap = mmap
    3536        self._backing = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
     
    165166"""
    166167class PixmapBacking(object):
    167168
    168     def __init__(self, w, h, old_backing, mmap_enabled, mmap):
     169    def __init__(self, wid, w, h, old_backing, mmap_enabled, mmap):
     170        self.wid = wid
    169171        self.mmap_enabled = mmap_enabled
    170172        self.mmap = mmap
    171173        self._backing = gdk.Pixmap(gdk.get_default_root_window(), w, h)
     
    188190        cr.set_source_rgb(1, 1, 1)
    189191        cr.fill()
    190192
     193    def paint_rgb24(self, img_data, x, y, width, height, rowstride):
     194        assert "rgb24" in ENCODINGS
     195        if rowstride>0:
     196            assert len(img_data) == rowstride * height
     197        else:
     198            assert len(img_data) == width * 3 * height
     199        gc = self._backing.new_gc()
     200        self._backing.draw_rgb_image(gc, x, y, width, height, gdk.RGB_DITHER_NONE, img_data, rowstride)
     201
     202    def paint_x264(self, img_data, x, y, width, height, rowstride):
     203        assert "x264" in ENCODINGS
     204        from xpra.x264.decoder import DECODERS, Decoder
     205        decoder = DECODERS.get(self.wid)
     206        def close_decoder():
     207            decoder.clean()
     208            del DECODERS[self.wid]
     209        if decoder and (decoder.get_width()!=width or decoder.get_height()!=height):
     210            log.info("paint_x264: window dimensions have changed from %s to %s", (decoder.width, decoder.height), (width, height))
     211            close_decoder()
     212            decoder = None
     213        if decoder is None:
     214            decoder = Decoder()
     215            decoder.init(width, height)
     216            DECODERS[self.wid] = decoder
     217        log.info("paint_x264: %sx%s img_data=%s, len=%s, first 10 bytes: %s", width, height, type(img_data), len(img_data), [ord(x) for x in img_data[:10]])
     218        #from io import BytesIO          #@Reimport
     219        #import array
     220        #a = array.array('i', img_data)
     221        #data = bytearray(a)
     222        #buf = BytesIO(data)
     223        err, size, data = decoder.decompress_image(img_data, rowstride)
     224        if err!=0:
     225            log.error("x264: ouch, decompression error %s", err)
     226            return
     227        log.info("paint_x264: decompressed to: %s bytes of rgb24 (size reported: %s)", len(data), size)
     228        try:
     229            self.paint_rgb24(data, x, y, width, height, rowstride)
     230        finally:
     231            decoder.free_image()
     232
     233    def paint_pixbuf(self, coding, img_data, x, y, width, height, rowstride):
     234        assert coding in ENCODINGS
     235        loader = gdk.PixbufLoader(coding)
     236        loader.write(img_data, len(img_data))
     237        loader.close()
     238        pixbuf = loader.get_pixbuf()
     239        if not pixbuf:
     240            log.error("failed %s pixbuf=%s data len=%s" % (coding, pixbuf, len(img_data)))
     241            return
     242        gc = self._backing.new_gc()
     243        self._backing.draw_pixbuf(gc, pixbuf, 0, 0, x, y, width, height)
     244
    191245    def draw_region(self, x, y, width, height, coding, img_data, rowstride):
    192         gc = self._backing.new_gc()
    193246        if coding == "mmap":
    194247            """ see _mmap_send() in server.py for details """
    195248            assert self.mmap_enabled
     
    199252                offset, length = img_data[0]
    200253                arraytype = ctypes.c_char * length
    201254                data = arraytype.from_buffer(self.mmap, offset)
    202                 self._backing.draw_rgb_image(gc, x, y, width, height, gdk.RGB_DITHER_NONE, data, rowstride)
     255                self.paint_rgb24(data, x, y, width, height, rowstride)
    203256                data_start.value = offset+length
    204257            else:
    205258                #re-construct the buffer from discontiguous chunks:
     
    209262                    self.mmap.seek(offset)
    210263                    data += self.mmap.read(length)
    211264                    data_start.value = offset+length
    212                 self._backing.draw_rgb_image(gc, x, y, width, height, gdk.RGB_DITHER_NONE, data, rowstride)
     265                self.paint_rgb24(data, x, y, width, height, rowstride)
    213266        elif coding == "rgb24":
    214             assert coding in ENCODINGS
    215             if rowstride>0:
    216                 assert len(img_data) == rowstride * height
    217             else:
    218                 assert len(img_data) == width * 3 * height
    219             self._backing.draw_rgb_image(gc, x, y, width, height, gdk.RGB_DITHER_NONE, img_data, rowstride)
     267            self.paint_rgb24(img_data, x, y, width, height, rowstride)
     268        elif coding == "x264":
     269            self.paint_x264(img_data, x, y, width, height, rowstride)
    220270        else:
    221             assert coding in ENCODINGS
    222             loader = gdk.PixbufLoader(coding)
    223             loader.write(img_data, len(img_data))
    224             loader.close()
    225             pixbuf = loader.get_pixbuf()
    226             if not pixbuf:
    227                 log.error("failed %s pixbuf=%s data len=%s" % (coding, pixbuf, len(img_data)))
    228             else:
    229                 self._backing.draw_pixbuf(gc, pixbuf, 0, 0, x, y, width, height)
     271            self.paint_pixbuf(self, coding, img_data, x, y, width, height, rowstride)
    230272
    231273    def cairo_draw(self, context, x, y):
    232274        try:
     
    238280            log.error("cairo_draw(%s)", context, exc_info=True)
    239281
    240282
    241 def new_backing(w, h, old_backing, mmap_enabled, mmap):
     283def new_backing(wid, w, h, old_backing, mmap_enabled, mmap):
    242284    if is_gtk3() or PREFER_CAIRO:
    243         return  CairoBacking(w, h, old_backing, mmap_enabled, mmap)
    244     return PixmapBacking(w, h, old_backing, mmap_enabled, mmap)
     285        return  CairoBacking(wid, w, h, old_backing, mmap_enabled, mmap)
     286    return PixmapBacking(wid, w, h, old_backing, mmap_enabled, mmap)
  • xpra/scripts/main.py

     
    4747        ENCODINGS.append("png")
    4848        ENCODINGS.append("jpeg")
    4949    ENCODINGS.append("rgb24")
     50#we need rgb24 for x264 (as well as the cython bindings and libraries):
     51if "rgb24" in ENCODINGS:
     52    try:
     53        from xpra.x264 import codec     #@UnusedImport
     54        ENCODINGS.append("x264")
     55    except:
     56        pass
    5057DEFAULT_ENCODING = ENCODINGS[0]
    5158
    5259