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

File xpra-x264-r2.patch, 14.6 KB (added by Antoine Martin, 9 years ago)

v2 of the patch with support for up to 32 contexts

  • xpra/x264/x264lib.c

    Property changes on: xpra/x264
    ___________________________________________________________________
    Added: svn:ignore
       + codec.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};
     31
     32struct x264lib_ctx *init_encoder(int width, int height)
     33{
     34        struct x264lib_ctx *ctx = malloc(sizeof(struct x264lib_ctx));
     35        x264_param_t param;
     36        x264_param_default_preset(&param, "veryfast", "zerolatency");
     37        param.i_threads = 1;
     38        param.i_width = width;
     39        param.i_height = height;
     40        param.i_csp = X264_CSP_I420;
     41        x264_param_apply_profile(&param, "baseline");
     42        ctx->encoder = x264_encoder_open(&param);
     43        ctx->width = width;
     44        ctx->height = height;
     45        ctx->rgb2yuv = sws_getContext(ctx->width, ctx->height, PIX_FMT_RGB24, ctx->width, ctx->height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);
     46
     47        return ctx;
     48}
     49
     50int clean_encoder(struct x264lib_ctx *ctx)
     51{
     52        sws_freeContext(ctx->rgb2yuv);
     53}
     54
     55struct x264lib_ctx *init_decoder(int width, int height)
     56{
     57        struct x264lib_ctx *ctx = malloc(sizeof(struct x264lib_ctx));
     58        ctx->width = width;
     59        ctx->height = height;
     60        ctx->yuv2rgb = sws_getContext(ctx->width, ctx->height, PIX_FMT_YUV420P, ctx->width, ctx->height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
     61
     62    avcodec_register_all();
     63
     64    ctx->codec = avcodec_find_decoder(CODEC_ID_H264);
     65    if (!ctx->codec) {
     66        fprintf(stderr, "codec not found\n");
     67                free(ctx);
     68        return NULL;
     69    }
     70        ctx->codec_ctx = avcodec_alloc_context3(ctx->codec);
     71        ctx->codec_ctx->width = ctx->width;
     72        ctx->codec_ctx->height = ctx->height;
     73        ctx->codec_ctx->pix_fmt = PIX_FMT_YUV420P;
     74        if (avcodec_open(ctx->codec_ctx, ctx->codec) < 0) {
     75        fprintf(stderr, "could not open codec\n");
     76                free(ctx);
     77        return NULL;
     78    }
     79
     80        return ctx;
     81}
     82
     83int clean_decoder(struct x264lib_ctx *ctx)
     84{
     85    avcodec_close(ctx->codec_ctx);
     86    av_free(ctx->codec_ctx);
     87        sws_freeContext(ctx->yuv2rgb);
     88}
     89
     90int compress_image(struct x264lib_ctx *ctx, const uint8_t *in, int stride, uint8_t **out, int *outsz)
     91{
     92        if (!ctx->encoder || !ctx->rgb2yuv)
     93                return 1;
     94
     95        x264_picture_t pic_in, pic_out;
     96        x264_picture_alloc(&pic_in, X264_CSP_I420, ctx->width, ctx->height);
     97
     98        /* Colorspace conversion (RGB -> I420) */
     99        sws_scale(ctx->rgb2yuv, &in, &stride, 0, ctx->height, pic_in.img.plane, pic_in.img.i_stride);
     100
     101        /* Encoding */
     102        pic_in.i_pts = 1;
     103
     104        x264_nal_t* nals;
     105        int i_nals;
     106        int frame_size = x264_encoder_encode(ctx->encoder, &nals, &i_nals, &pic_in, &pic_out);
     107        if (frame_size >= 0) {
     108                /* Do not free that! */
     109                *out = nals[0].p_payload;
     110                *outsz = frame_size;
     111        } else {
     112                fprintf(stderr, "Problem\n");
     113                return 2;
     114        }
     115
     116        return 0;
     117}
     118
     119int decompress_image(struct x264lib_ctx *ctx, uint8_t *in, int size, uint8_t **out, int *outsz)
     120{
     121        if (!ctx->yuv2rgb)
     122                return 1;
     123
     124    int got_picture, len;
     125    AVFrame *picture;
     126    AVPacket avpkt;
     127    av_init_packet(&avpkt);
     128
     129        if (!ctx->codec_ctx || !ctx->codec)
     130                return 1;
     131
     132    printf("Video decoding\n");
     133
     134    picture = avcodec_alloc_frame();
     135
     136        avpkt.data = in;
     137        avpkt.size = size;
     138       
     139        len = avcodec_decode_video2(ctx->codec_ctx, picture, &got_picture, &avpkt);
     140        if (len < 0) {
     141                fprintf(stderr, "Error while decoding frame\n");
     142                *out = NULL;
     143                *outsz = 0;
     144                return 2;
     145        }
     146
     147        AVPicture pic;
     148        avpicture_fill(&pic, malloc(ctx->height * ctx->width * 3), PIX_FMT_RGB24, 800, 600);
     149
     150        /* Colorspace conversion (I420 -> RGB) */
     151        sws_scale(ctx->yuv2rgb, picture->data, picture->linesize, 0, ctx->height, pic.data, pic.linesize);
     152   
     153        av_free(picture);
     154
     155        /* Output (must be freed!) */
     156        *out = pic.data[0];
     157        *outsz = pic.linesize[0] * ctx->height;
     158
     159        printf("Got %p, stride %d, size %d\n", pic.data[0], pic.linesize[0], *outsz);
     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
     7def main():
     8    from xpra.x264.codec import init_x264_encoder, clean_x264_encoder, x264_compress_image
     9    w = 640
     10    h = 480
     11    i = init_x264_encoder(0, w, h)
     12    print("init_x264_encoder(%s,%s)=%s" % (w, h, i))
     13    f = None
     14    try:
     15        f = open("x264test.rgb", mode='rb')
     16        data = f.read()
     17    finally:
     18        if f:
     19            f.close()
     20    stride = 800*3
     21    size, compressed = x264_compress_image(0, data, stride)
     22    print("x264_compress_image(%s bytes, %s)=%s,%s" % (len(data), stride, size, len(compressed)))
     23    i = clean_x264_encoder(0)
     24    print("clean_x264_encoder()=%s" % i)
     25
     26
     27if __name__ == "__main__":
     28    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]
     28window_to_encoder_context_index = {}
     29window_to_decoder_context_index = {}
     30
     31
     32def init_x264_encoder(wid, width, height):
     33    global encoder_contexts
     34    assert wid not in window_to_encoder_context_index, "window id %s already has an encoder context!"% wid
     35    cdef x264lib_ctx* encoder_context
     36    encoder_context = init_encoder(width, height)
     37    assert encoder_context
     38    for i in range(0, MAX_CONTEXTS):
     39        if encoder_contexts[i] == NULL:
     40            window_to_encoder_context_index[wid] = i
     41            encoder_contexts[i] = encoder_context
     42            return
     43    raise Exception("no more free contexts!")
     44
     45def init_x264_decoder(wid, width, height):
     46    global decoder_contexts
     47    assert wid not in window_to_decoder_context_index, "window id %s already has an encoder context!"% wid
     48    cdef x264lib_ctx* decoder_context
     49    decoder_context = init_decoder(width, height)
     50    assert decoder_context
     51    for i in range(0, MAX_CONTEXTS):
     52        if encoder_contexts[i] == NULL:
     53            window_to_decoder_context_index[wid] = i
     54            encoder_contexts[i] = decoder_context
     55            return
     56    raise Exception("no more free contexts!")
     57
     58cdef x264lib_ctx*   get_encoder_context(wid, clear_it=False):
     59    cdef x264lib_ctx* encoder_ctx
     60    global encoder_contexts
     61    assert wid in window_to_encoder_context_index, "no context found for %s"% wid
     62    index = window_to_encoder_context_index.get(wid)
     63    assert index>=0 and index<=MAX_CONTEXTS
     64    encoder_ctx = encoder_contexts[index]
     65    assert encoder_ctx, "context is NULL for %s" % wid
     66    if clear_it:
     67        encoder_contexts[index] = NULL
     68        del window_to_encoder_context_index[wid]
     69    return  encoder_ctx
     70
     71def clean_x264_encoder(wid):
     72    cdef x264lib_ctx* ce_context = get_encoder_context(wid, True)
     73    return clean_encoder(ce_context)
     74
     75cdef x264lib_ctx*   get_decoder_context(wid, clear_it=False):
     76    cdef x264lib_ctx* decoder_ctx
     77    global decoder_contexts
     78    assert wid in window_to_decoder_context_index, "no context found for %s"% wid
     79    index = window_to_decoder_context_index.get(wid)
     80    assert index>=0 and index<=MAX_CONTEXTS
     81    decoder_ctx = decoder_contexts[index]
     82    assert decoder_ctx, "context is NULL for %s" % wid
     83    if clear_it:
     84        decoder_contexts[index] = NULL
     85        del window_to_decoder_context_index[wid]
     86    return  decoder_ctx
     87
     88
     89def clean_x264_decoder(wid):
     90    cdef x264lib_ctx* cd_context = get_decoder_context(wid, True)
     91    return clean_decoder(cd_context)
     92
     93def x264_compress_image(wid, input, rowstride):
     94    cdef uint8_t *cout
     95    cdef int coutsz
     96    cdef unsigned int * c_cbuf = <uint8_t *> 0
     97    cdef Py_ssize_t c_cbuf_len = 0
     98    cdef x264lib_ctx* encoder
     99    encoder = get_encoder_context(wid)
     100    PyObject_AsReadBuffer(input, <void **>&c_cbuf, &c_cbuf_len)
     101    i = compress_image(encoder, c_cbuf, rowstride, &cout, &coutsz)
     102    print("x264_compress_image(..,%s) out size=%s" % (rowstride, coutsz))
     103    coutv = (<char *>cout)[:coutsz]
     104    return  coutsz, coutv
     105
     106def x264_decompress_image(wid, input, size):
     107    cdef uint8_t *dout
     108    cdef int doutsz
     109    cdef unsigned int * d_cbuf = <uint8_t *> 0
     110    cdef Py_ssize_t d_cbuf_len = 0
     111    cdef x264lib_ctx* decoder
     112    decoder = get_decoder_context(wid)
     113    PyObject_AsReadBuffer(input, <void **>&d_cbuf, &d_cbuf_len)
     114    i = decompress_image(decoder, d_cbuf, size, &dout, &doutsz)
     115    doutv = (<char *>dout)[:doutsz]
     116    return  doutsz, doutv
  • 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/x264/__init__.py

     
     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.
  • 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",