xpra icon
Bug tracker and wiki

Ticket #328: yuv-codec.patch

File yuv-codec.patch, 15.5 KB (added by Antoine Martin, 6 years ago)

work in progress yuv codec

  • setup.py

     
    4545
    4646
    4747
     48yuv_ENABLED = True
     49
     50
     51
    4852webp_ENABLED = True
    4953
    5054
     
    118122
    119123
    120124#allow some of these flags to be modified on the command line:
    121 SWITCHES = ("x264", "vpx", "webp", "rencode", "clipboard",
     125SWITCHES = ("x264", "vpx", "yuv",
     126            "webp", "rencode", "clipboard",
    122127            "server", "client", "x11",
    123128            "gtk2", "gtk3", "qt4",
    124129            "sound", "cyxor", "cymaths", "opengl",
     
    182187    print("Warning: enabling x11 on MS Windows is unlikely to work!")
    183188if client_ENABLED and not gtk2_ENABLED and not gtk3_ENABLED and not qt4_ENABLED:
    184189    print("Warning: client is enabled but none of the client toolkits are!?")
     190if (x264_ENABLED or vpx_ENABLED) and not yuv_ENABLED:
     191    print("Warning: to use vpx or x264 without yuv will only work with the opengl client!")
    185192if not client_ENABLED and not server_ENABLED:
    186193    print("Error: you must build at least the client or server!")
    187194    exit(1)
     
    852859
    853860
    854861
     862toggle_packages(yuv_ENABLED, "xpra.codecs.yuv")
     863if yuv_ENABLED:
     864    cython_add(Extension("xpra.codecs.yuv.codec",
     865                ["xpra/codecs/yuv/codec.pyx", "xpra/codecs/yuv/yuvlib.c"],
     866                **pkgconfig("libswscale", "libavcodec")
     867                ), min_version=(0, 16))
     868
     869
     870
    855871toggle_packages(rencode_ENABLED, "xpra.net.rencode")
    856872if rencode_ENABLED:
    857873    extra_compile_args = []
  • xpra/codecs/codec_base.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
     6cdef class YUVImage:
     7    cdef uint8_t* planes[3]
     8    cdef uint8_t* rowstrides[3]
     9
     10    def __dealloc__(self):
     11        self.clean()
     12
     13    def clean(self):
     14        pass
     15
     16""" utility superclass for all codecs """
     17cdef class xcoder:
     18    cdef int width
     19    cdef int height
     20
     21    def init(self, width, height):
     22        self.width = width
     23        self.height = height
     24
     25    def is_closed(self):
     26        return self.context==NULL
     27
     28    def __dealloc__(self):
     29        self.clean()
     30
     31    def get_width(self):
     32        return self.width
     33
     34    def get_height(self):
     35        return self.height
  • xpra/codecs/yuv/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 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/yuv/codec.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
     9cdef extern from *:
     10    ctypedef unsigned long size_t
     11
     12cdef extern from "Python.h":
     13    ctypedef int Py_ssize_t
     14    ctypedef object PyObject
     15    ctypedef void** const_void_pp "const void**"
     16    int PyObject_AsReadBuffer(object obj, void ** buffer, Py_ssize_t * buffer_len) except -1
     17
     18ctypedef unsigned char uint8_t
     19ctypedef void yuvlib_ctx
     20cdef extern from "yuvlib.h":
     21    void* xmemalign(size_t size) nogil
     22    void xmemfree(void* ptr) nogil
     23
     24    #int get_x264_build_no()
     25    yuvlib_ctx* init_encoder(int width, int height)
     26    void clean_encoder(yuvlib_ctx *context)
     27    uint8_t* rgb2yuv(yuvlib_ctx *ctx, uint8_t *input, int stride, uint8_t **out, int *outstride)
     28
     29    yuvlib_ctx* init_decoder(int width, int height, int csc_fmt)
     30    void set_decoder_csc_format(yuvlib_ctx *context, int csc_fmt)
     31    void clean_decoder(yuvlib_ctx *context)
     32    int yuv2rgb(yuvlib_ctx *ctx, uint8_t *input[3], int stride[3], uint8_t **out, int *outstride)
     33
     34
     35def get_version():
     36    return 0
     37
     38
     39""" common superclass for Decoder and Encoder """
     40cdef class xcoder:
     41    cdef yuvlib_ctx *context
     42    cdef int width
     43    cdef int height
     44
     45    def init(self, width, height):
     46        self.width = width
     47        self.height = height
     48
     49    def is_closed(self):
     50        return self.context==NULL
     51
     52    def __dealloc__(self):
     53        self.clean()
     54
     55    def get_width(self):
     56        return self.width
     57
     58    def get_height(self):
     59        return self.height
     60
     61    def get_type(self):
     62        return  "yuv"
     63
     64
     65cdef class Decoder(xcoder):
     66
     67    def init_context(self, width, height, options):
     68        self.init(width, height)
     69        csc_fmt = options.get("csc_pixel_format", -1)
     70        self.context = init_decoder(width, height, csc_fmt)
     71
     72    def clean(self):
     73        if self.context!=NULL:
     74            clean_decoder(self.context)
     75            self.context = NULL
     76
     77    #def get_pixel_format(self, csc_pixel_format):
     78    #    return get_pixel_format(csc_pixel_format)
     79
     80    def yuv2rgb(self, input, options):
     81        cdef uint8_t *yuvplanes[3]
     82        cdef uint8_t *dout
     83        cdef int yuvstrides[3]
     84        cdef int outstrides[3]
     85        cdef unsigned char * padded_buf = NULL  #@DuplicatedSignature
     86        cdef unsigned char * buf = NULL         #@DuplicatedSignature
     87        cdef Py_ssize_t buf_len = 0             #@DuplicatedSignature
     88        cdef int i = 0                          #@DuplicatedSignature
     89        assert self.context!=NULL
     90        PyObject_AsReadBuffer(input, <const_void_pp> &buf, &buf_len)
     91        i = yuv2rgb(self.context, yuvplanes, yuvstrides, &dout, outstrides)
     92        if i!=0:
     93            if dout!=NULL:
     94                xmemfree(dout)
     95            return i, "", 0
     96        xmemfree(dout)
     97        return  i
     98
     99
     100cdef class Encoder(xcoder):
     101    cdef int frames
     102    cdef int supports_options
     103
     104    def init_context(self, int width, int height, options):    #@DuplicatedSignature
     105        self.init(width, height)
     106        self.frames = 0
     107        self.context = init_encoder(width, height)
     108
     109    def clean(self):                        #@DuplicatedSignature
     110        if self.context!=NULL:
     111            clean_encoder(self.context)
     112            self.context = NULL
     113
     114    def get_client_options(self, options):
     115        return  {}
     116
     117    def rgb2yuv(self, input, rowstride, options):
     118        cdef uint8_t *pic_buf = NULL
     119        cdef uint8_t *dout                  #@DuplicatedSignature
     120        cdef int outstrides[3]              #@DuplicatedSignature
     121        cdef Py_ssize_t pic_buf_len = 0
     122        assert self.context!=NULL
     123        #colourspace conversion with gil held:
     124        PyObject_AsReadBuffer(input, <const_void_pp> &pic_buf, &pic_buf_len)
     125        r = rgb2yuv(self.context, pic_buf, rowstride, &dout, outstrides)
  • xpra/codecs/yuv/yuvlib.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 <libswscale/swscale.h>
     25#include <libavcodec/avcodec.h>
     26#include <libavutil/mem.h>
     27
     28
     29//not honoured on MS Windows:
     30#define MEMALIGN 1
     31//not honoured on OSX:
     32#define MEMALIGN_ALIGNMENT 32
     33//comment this out to turn off csc 422 and 444 colourspace modes
     34//(ie: when not supported by the library we build against)
     35#define SUPPORT_CSC_MODES 1
     36
     37
     38//beware that these macros may evaluate a or b twice!
     39//ie: do not use them for something like: MAX(i++, N)
     40#define MAX(a,b) ((a) > (b) ? a : b)
     41#define MIN(a,b) ((a) < (b) ? a : b)
     42
     43
     44struct yuvlib_ctx {
     45        // Both
     46        int width;
     47        int height;
     48        int csc_format;                         //PIX_FMT_YUV420P, X264_CSP_I422, PIX_FMT_YUV444P
     49
     50        // Decoding
     51        AVCodec *codec;
     52        AVCodecContext *codec_ctx;
     53        AVFrame *frame;
     54        struct SwsContext *yuv2rgb;
     55
     56        // Encoding
     57        struct SwsContext *rgb2yuv;
     58};
     59
     60/**
     61 * Configure values that will not change during the lifetime of the encoder.
     62 */
     63void configure_encoder(struct yuvlib_ctx *ctx, int width, int height)
     64{
     65        //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);
     66        ctx->width = width;
     67        ctx->height = height;
     68}
     69
     70/**
     71 * Actually initialize the encoder.
     72 * This may be called more than once if required, ie:
     73 * - if the dimensions change,
     74 * - if the csc mode changes.
     75 */
     76void do_init_encoder(struct yuvlib_ctx *ctx)
     77{
     78        x264_param_t param;
     79        ctx->csc_format = get_csc_format_for_x264_format(ctx->colour_sampling);
     80        ctx->csc_algo = get_csc_algo_for_quality(ctx->quality);
     81        //printf("do_init_encoder(%p, %i, %i, %i, %i) colour_sampling=%i, initial x264_quality=%f, initial profile=%s\n", ctx, ctx->width, ctx->height, ctx->quality, ctx->supports_csc_option, ctx->colour_sampling, ctx->x264_quality, ctx->profile);
     82        ctx->rgb2yuv = init_encoder_csc(ctx);
     83}
     84
     85struct yuvlib_ctx *init_encoder(int width, int height)
     86{
     87        struct yuvlib_ctx *ctx = malloc(sizeof(struct yuvlib_ctx));
     88        if (ctx==NULL)
     89                return NULL;
     90        memset(ctx, 0, sizeof(struct yuvlib_ctx));
     91        configure_encoder(ctx, width, height);
     92        do_init_encoder(ctx);
     93        return ctx;
     94}
     95
     96
     97void clean_encoder(struct yuvlib_ctx *ctx)
     98{
     99        do_clean_encoder(ctx);
     100        free(ctx);
     101}
     102void do_clean_encoder(struct yuvlib_ctx *ctx)
     103{
     104        if (ctx->rgb2yuv) {
     105                sws_freeContext(ctx->rgb2yuv);
     106                ctx->rgb2yuv = NULL;
     107        }
     108}
     109
     110
     111int init_decoder_context(struct yuvlib_ctx *ctx, int width, int height, int use_swscale, int csc_fmt)
     112{
     113        if (csc_fmt<0)
     114                csc_fmt = PIX_FMT_YUV420P;
     115        ctx->width = width;
     116        ctx->height = height;
     117        ctx->csc_format = csc_fmt;
     118        ctx->csc_algo = get_csc_algo_for_quality(100);
     119        ctx->yuv2rgb = sws_getContext(ctx->width, ctx->height, ctx->csc_format, ctx->width, ctx->height, PIX_FMT_RGB24, ctx->csc_algo, NULL, NULL, NULL);
     120        return 0;
     121}
     122struct yuvlib_ctx *init_decoder(int width, int height, int use_swscale, int csc_fmt)
     123{
     124        struct yuvlib_ctx *ctx = malloc(sizeof(struct yuvlib_ctx));
     125        if (ctx==NULL)
     126                return NULL;
     127        memset(ctx, 0, sizeof(struct yuvlib_ctx));
     128        if (init_decoder_context(ctx, width, height, use_swscale, csc_fmt)) {
     129                clean_decoder(ctx);
     130                return NULL;
     131        }
     132        return ctx;
     133}
     134
     135void do_clean_decoder(struct yuvlib_ctx *ctx)
     136{
     137        if (ctx->yuv2rgb) {
     138                sws_freeContext(ctx->yuv2rgb);
     139                ctx->yuv2rgb = NULL;
     140        }
     141}
     142void clean_decoder(struct yuvlib_ctx *ctx)
     143{
     144        do_clean_decoder(ctx);
     145        free(ctx);
     146}
     147
     148
     149int rgb2yuv(struct yuvlib_ctx *ctx, const uint8_t *in, int stride, uint8_t **out, uint8_t **outStride)
     150{
     151        if (ctx==NULL || !ctx->rgb2yuv)
     152                return 1;
     153        sws_scale(ctx->rgb2yuv, &in, &stride, 0, ctx->height, out, outStride);
     154        return 0;
     155}
     156
     157static void free_csc_image(x264_picture_t *image)
     158{
     159        x264_picture_clean(image);
     160        free(image);
     161}
     162
     163int yuv2rgb(struct yuvlib_ctx *ctx, uint8_t *in[3], const int stride[3], uint8_t **out, uint8_t **outStride)
     164{
     165        if (!ctx->yuv2rgb)
     166                return 1;
     167        sws_scale(ctx->yuv2rgb, (const uint8_t * const*) in, stride, 0, ctx->height, out, outStride);
     168        /* Output (must be freed!) */
     169        return 0;
     170}
     171
     172void set_decoder_csc_format(struct yuvlib_ctx *ctx, int csc_fmt)
     173{
     174        if (csc_fmt<0)
     175                csc_fmt = PIX_FMT_YUV420P;
     176        if (ctx->csc_format!=csc_fmt) {
     177                //we need to re-initialize with the new format:
     178                do_clean_decoder(ctx);
     179                if (init_decoder_context(ctx, ctx->width, ctx->height, ctx->use_swscale, csc_fmt)) {
     180                        fprintf(stderr, "Failed to reconfigure decoder\n");
     181                }
     182        }
     183}
     184
     185
     186void* xmemalign(size_t size)
     187{
     188#ifdef MEMALIGN
     189#ifdef _WIN32
     190        //_aligned_malloc and _aligned_free lead to a memleak
     191        //well done Microsoft, I didn't think you could screw up this badly
     192        //and thank you for wasting my time once again
     193        return malloc(size);
     194#elif defined(__APPLE__) || defined(__OSX__)
     195        //Crapple version: "all memory allocations are 16-byte aligned"
     196        //no choice, this is what you get
     197        return malloc(size);
     198#else
     199        //not WIN32 and not APPLE/OSX, assume POSIX:
     200        void* memptr=NULL;
     201        if (posix_memalign(&memptr, MEMALIGN_ALIGNMENT, size))
     202                return  NULL;
     203        return  memptr;
     204#endif
     205//MEMALIGN not set:
     206#else
     207        return  malloc(size);
     208#endif
     209}
     210
     211void xmemfree(void *ptr)
     212{
     213        free(ptr);
     214}
  • xpra/codecs/yuv/yuvlib.h

     
     1/* This file is part of Parti.
     2 * Copyright (C) 2012 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
     3 * Copyright (C) 2012, 2013 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
     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 images of a given size */
     19struct yuvlib_ctx;
     20
     21/** Create an encoding context for images of a given size.  */
     22struct yuvlib_ctx *init_encoder(int width, int height, int csc_fmt);
     23
     24/** Create a decoding context for images of a given size. */
     25struct yuvlib_ctx *init_decoder(int width, int height, int csc_fmt);
     26
     27/** Cleanup encoding context. Without freeing the memory. */
     28void do_clean_encoder(struct yuvlib_ctx *ctx);
     29
     30/** Cleanup encoding context. Also frees the memory. */
     31void clean_encoder(struct yuvlib_ctx *);
     32
     33/** Cleanup decoding context. Without freeing the memory. */
     34void do_clean_decoder(struct yuvlib_ctx *ctx);
     35
     36/** Cleanup decoding context. Also frees the memory. */
     37void clean_decoder(struct yuvlib_ctx *);
     38
     39/** Colorspace conversion.
     40 * Note: you must call compress_image to free the image buffer.
     41 @param in: Input buffer, format is packed RGB24.
     42 @param stride: Input stride (size is taken from context).
     43 @return: the converted picture.
     44*/
     45int yuv2rgb(struct yuvlib_ctx *ctx, uint8_t *in[3], const int stride[3], uint8_t **out, uint8_t **outStride);
     46
     47/** Colorspace conversion.
     48 @param in: Input picture (3 planes).
     49 @param stride: Input strides (3 planes).
     50 @param out: Will be set to point to the output data in packed RGB24 format. Must be freed after use by calling free().
     51 @param outsz: Will be set to the size of the output buffer.
     52 @param outstride: Output stride.
     53 @return non zero on error.
     54*/
     55int rgb2yuv(struct yuvlib_ctx *ctx, const uint8_t *in, int stride, uint8_t **out, uint8_t **outStride);
     56
     57/**
     58 * Define our own memalign function so we can more easily
     59 * workaround platforms that lack posix_memalign.
     60 * It does its best to provide sse compatible memory allocation.
     61 */
     62void* xmemalign(size_t size);
     63
     64/**
     65 * Frees memory allocated with xmemalign
     66 */
     67void xmemfree(void *ptr);