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-r3.patch

File xpra-x264-r3.patch, 26.3 KB (added by Antoine Martin, 10 years ago)

patch with all the changes to client/server/main

  • setup.py

     
    6464                ["xpra/wait_for_x_server.pyx"],
    6565                **pkgconfig("x11")
    6666                ),
     67      Extension("xpra.x264.codec",
     68                ["xpra/x264/codec.pyx", "xpra/x264/x264lib.c"],
     69                **pkgconfig("x264", "libswscale", "libavcodec")
     70                ),
    6771      ]
    6872
    6973    cmdclass = {'build_ext': build_ext}
     
    161165              "parti", "parti.trays", "parti.addons", "parti.scripts",
    162166              "xpra", "xpra.scripts", "xpra.platform",
    163167              "xpra.xposix", "xpra.win32", "xpra.darwin",
     168              "xpra.x264"
    164169              ]
    165170    scripts=["scripts/parti", "scripts/parti-repl",
    166171             "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.codec import init_x264_encoder, x264_compress_image, get_encoder_dimensions, clean_x264_encoder
     511            dims = get_encoder_dimensions(wid)
     512            if dims and dims!=(width,height):
     513                log.info("x264: window dimensions have changed from %s to %s", dims, (width,height))
     514                clean_x264_encoder(wid)
     515                dims = None
     516            if not dims:
     517                log.info("x264: starting new encoder for window %s: %sx%s", wid, width, height)
     518                init_x264_encoder(wid, width, height)
     519                def close_x264():
     520                    clean_x264_encoder(wid)
     521                self._on_close.append(close_x264)
     522            err, size, data = x264_compress_image(wid, data, rowstride)
     523            if err!=0:
     524                log.error("x264: ouch, compression error %s", err)
     525                return None
     526            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]])
     527            w,h = width, height
    496528        #check cancellation list again since the code above may take some time:
    497529        #but always send mmap data so we can reclaim the space!
    498530        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/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, 800, 600);
     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
     7wid = 0
     8w = 640
     9h = 480
     10
     11f = None
     12try:
     13    f = open("x264test.rgb", mode='rb')
     14    data = f.read()
     15finally:
     16    if f:
     17        f.close()
     18
     19def main():
     20    from xpra.x264.codec import init_x264_encoder, clean_x264_encoder, x264_compress_image
     21    print("init_x264_encoder(%s,%s,%s)" % (wid, w, h))
     22    init_x264_encoder(wid, w, h)
     23    stride = 800*3
     24    try:
     25        err, size, compressed = x264_compress_image(wid, 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 = clean_x264_encoder(wid)
     31        print("clean_x264_encoder()=%s" % i)
     32
     33    from xpra.x264.codec import init_x264_decoder, clean_x264_decoder, x264_decompress_image
     34    print("init_x264_decoder(%s,%s,%s)" % (wid, w, h))
     35    init_x264_decoder(wid, w, h)
     36    try:
     37        err, size, decompressed = x264_decompress_image(wid, compressed, size)
     38        print("x264_decompress_image(%s, %s bytes, %s)=%s" % (wid, len(compressed), size, (err, size, len(decompressed))))
     39        assert decompressed==data
     40        if err!=0:
     41            raise Exception("error %s during decompression" % err)
     42    finally:
     43        i = clean_x264_decoder(wid)
     44        print("clean_x264_decoder()=%s" % i)
     45
     46
     47if __name__ == "__main__":
     48    main()
  • xpra/x264/codec.pyx

    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) 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 int uint8_t
     16ctypedef void x264lib_ctx
     17cdef extern from "x264lib.h":
     18    x264lib_ctx* init_encoder(int width, int height)
     19    x264lib_ctx* init_decoder(int width, int height)
     20    int clean_encoder(x264lib_ctx *context)
     21    int clean_decoder(x264lib_ctx *context)
     22    int compress_image(x264lib_ctx *context, uint8_t *input, int stride, uint8_t **out, int *outsz)
     23    int decompress_image(x264lib_ctx *context, uint8_t *input, int size, uint8_t **out, int *outsz)
     24
     25MAX_CONTEXTS = 32
     26cdef x264lib_ctx* encoder_contexts[32]
     27cdef x264lib_ctx* decoder_contexts[32]
     28#window-id as key, (C array index, width, height) as value:
     29window_to_encoder = {}
     30window_to_decoder = {}
     31
     32
     33def init_x264_encoder(wid, width, height):
     34    global encoder_contexts, window_to_encoder
     35    assert wid not in window_to_encoder, "window id %s already has an encoder context!"% wid
     36    cdef x264lib_ctx* encoder_context
     37    encoder_context = init_encoder(width, height)
     38    assert encoder_context
     39    for i in range(0, MAX_CONTEXTS):
     40        if encoder_contexts[i] == NULL:
     41            window_to_encoder[wid] = (i, width, height)
     42            encoder_contexts[i] = encoder_context
     43            return
     44    raise Exception("no more free contexts!")
     45
     46def init_x264_decoder(wid, width, height):
     47    global decoder_contexts, window_to_decoder
     48    assert wid not in window_to_decoder, "window id %s already has an encoder context!"% wid
     49    cdef x264lib_ctx* decoder_context
     50    decoder_context = init_decoder(width, height)
     51    assert decoder_context
     52    for i in range(0, MAX_CONTEXTS):
     53        if encoder_contexts[i] == NULL:
     54            window_to_decoder[wid] = (i, width, height)
     55            decoder_contexts[i] = decoder_context
     56            return
     57    raise Exception("no more free contexts!")
     58
     59cdef x264lib_ctx*   get_encoder_context(wid, clear_it=False):
     60    global encoder_contexts
     61    cdef x264lib_ctx* encoder_ctx
     62    assert wid in window_to_encoder, "no context found for %s"% wid
     63    index, _, _ = window_to_encoder.get(wid)
     64    assert index>=0 and index<=MAX_CONTEXTS
     65    encoder_ctx = encoder_contexts[index]
     66    assert encoder_ctx, "context is NULL for %s at index %s" % (wid, index)
     67    if clear_it:
     68        print("clearing encoder context for %s" % wid)
     69        encoder_contexts[index] = NULL
     70        del window_to_encoder[wid]
     71    return  encoder_ctx
     72
     73def get_encoder_dimensions(wid):
     74    global window_to_encoder
     75    if wid not in window_to_encoder:
     76        return  None
     77    _, w, h = window_to_encoder.get(wid)
     78    return w,h
     79
     80def clean_x264_encoder(wid):
     81    cdef x264lib_ctx* ce_context = get_encoder_context(wid, True)
     82    return clean_encoder(ce_context)
     83
     84cdef x264lib_ctx*   get_decoder_context(wid, clear_it=False):
     85    global decoder_contexts
     86    cdef x264lib_ctx* decoder_ctx
     87    assert wid in window_to_decoder, "no context found for %s"% wid
     88    index, _, _ = window_to_decoder.get(wid)
     89    assert index>=0 and index<=MAX_CONTEXTS
     90    decoder_ctx = decoder_contexts[index]
     91    assert decoder_ctx, "context is NULL for %s at index %s" % (wid, index)
     92    if clear_it:
     93        print("clearing decoder context for %s" % wid)
     94        decoder_contexts[index] = NULL
     95        del window_to_decoder[wid]
     96    return  decoder_ctx
     97
     98def get_decoder_dimensions(wid):
     99    global window_to_decoder
     100    if wid not in window_to_decoder:
     101        return  None
     102    _, w, h = window_to_decoder.get(wid)
     103    return w,h
     104
     105
     106def clean_x264_decoder(wid):
     107    cdef x264lib_ctx* cd_context = get_decoder_context(wid, True)
     108    return clean_decoder(cd_context)
     109
     110def x264_compress_image(wid, input, rowstride):
     111    cdef uint8_t *cout
     112    cdef int coutsz
     113    cdef unsigned int * c_cbuf = <uint8_t *> 0
     114    cdef Py_ssize_t c_cbuf_len = 0
     115    cdef x264lib_ctx* encoder
     116    encoder = get_encoder_context(wid, False)
     117    PyObject_AsReadBuffer(input, <void **>&c_cbuf, &c_cbuf_len)
     118    i = compress_image(encoder, c_cbuf, rowstride, &cout, &coutsz)
     119    if i!=0:
     120        return i, 0, ""
     121    print("x264_compress_image(..,%s) out size=%s" % (rowstride, coutsz))
     122    coutv = (<char *>cout)[:coutsz]
     123    return  i, coutsz, coutv
     124
     125def x264_decompress_image(wid, input, size):
     126    cdef uint8_t *dout
     127    cdef int doutsz
     128    cdef unsigned int * d_cbuf = <uint8_t *> 0
     129    cdef Py_ssize_t d_cbuf_len = 0
     130    cdef x264lib_ctx* decoder
     131    decoder = get_decoder_context(wid, False)
     132    PyObject_AsReadBuffer(input, <void **>&d_cbuf, &d_cbuf_len)
     133    i = decompress_image(decoder, d_cbuf, size, &dout, &doutsz)
     134    if i!=0:
     135        return i, 0, ""
     136    doutv = (<char *>dout)[:doutsz]
     137    return  i, doutsz, doutv
     138
     139def x264_free():
     140    pass
  • xpra/x264/Makefile

     
     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/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/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.codec import init_x264_decoder, x264_decompress_image, get_decoder_dimensions, clean_x264_decoder, x264_free
     205        dims = get_decoder_dimensions(self.wid)
     206        if dims is not None and dims!=(width,height):
     207            log.info("paint_x264: window dimensions have changed from %s to %s", dims, (width, height))
     208            clean_x264_decoder(self.wid)
     209            dims = None
     210        if not dims:
     211            log.info("paint_x264: starting new decoder for window %s: %sx%s", self.wid, width, height)
     212            init_x264_decoder(self.wid, width, height)
     213        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]])
     214        #from io import BytesIO          #@Reimport
     215        #import array
     216        #a = array.array('i', img_data)
     217        #data = bytearray(a)
     218        #buf = BytesIO(data)
     219        err, size, data = x264_decompress_image(self.wid, img_data, rowstride)
     220        if err!=0:
     221            log.error("x264: ouch, decompression error %s", err)
     222            return
     223        log.info("paint_x264: decompressed to: %s bytes of rgb24 (size reported: %s)", len(data), size)
     224        try:
     225            self.paint_rgb24(data, x, y, width, height, rowstride)
     226        finally:
     227            x264_free(data)
     228
     229    def paint_pixbuf(self, coding, img_data, x, y, width, height, rowstride):
     230        assert coding in ENCODINGS
     231        loader = gdk.PixbufLoader(coding)
     232        loader.write(img_data, len(img_data))
     233        loader.close()
     234        pixbuf = loader.get_pixbuf()
     235        if not pixbuf:
     236            log.error("failed %s pixbuf=%s data len=%s" % (coding, pixbuf, len(img_data)))
     237            return
     238        gc = self._backing.new_gc()
     239        self._backing.draw_pixbuf(gc, pixbuf, 0, 0, x, y, width, height)
     240
    191241    def draw_region(self, x, y, width, height, coding, img_data, rowstride):
    192         gc = self._backing.new_gc()
    193242        if coding == "mmap":
    194243            """ see _mmap_send() in server.py for details """
    195244            assert self.mmap_enabled
     
    199248                offset, length = img_data[0]
    200249                arraytype = ctypes.c_char * length
    201250                data = arraytype.from_buffer(self.mmap, offset)
    202                 self._backing.draw_rgb_image(gc, x, y, width, height, gdk.RGB_DITHER_NONE, data, rowstride)
     251                self.paint_rgb24(data, x, y, width, height, rowstride)
    203252                data_start.value = offset+length
    204253            else:
    205254                #re-construct the buffer from discontiguous chunks:
     
    209258                    self.mmap.seek(offset)
    210259                    data += self.mmap.read(length)
    211260                    data_start.value = offset+length
    212                 self._backing.draw_rgb_image(gc, x, y, width, height, gdk.RGB_DITHER_NONE, data, rowstride)
     261                self.paint_rgb24(data, x, y, width, height, rowstride)
    213262        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)
     263            self.paint_rgb24(img_data, x, y, width, height, rowstride)
     264        elif coding == "x264":
     265            self.paint_x264(img_data, x, y, width, height, rowstride)
    220266        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)
     267            self.paint_pixbuf(self, coding, img_data, x, y, width, height, rowstride)
    230268
    231269    def cairo_draw(self, context, x, y):
    232270        try:
     
    238276            log.error("cairo_draw(%s)", context, exc_info=True)
    239277
    240278
    241 def new_backing(w, h, old_backing, mmap_enabled, mmap):
     279def new_backing(wid, w, h, old_backing, mmap_enabled, mmap):
    242280    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)
     281        return  CairoBacking(wid, w, h, old_backing, mmap_enabled, mmap)
     282    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