diff --git a/src/xpra/vpx/codec.pyx b/src/xpra/vpx/codec.pyx index ff87fca7fb..da360519c1 100644 --- a/src/xpra/vpx/codec.pyx +++ b/src/xpra/vpx/codec.pyx @@ -16,12 +16,13 @@ ctypedef void vpx_image_t cdef extern from "vpxlib.h": vpx_codec_ctx_t* init_encoder(int width, int height) void clean_encoder(vpx_codec_ctx_t *context) - vpx_image_t* csc_image(vpx_codec_ctx_t *ctx, uint8_t *input, int stride) + vpx_image_t* csc_image_rgb2yuv(vpx_codec_ctx_t *ctx, uint8_t *input, int stride) + int csc_image_yuv2rgb(vpx_codec_ctx_t *ctx, uint8_t *input[3], int stride[3], uint8_t **out, int *outsz, int *outstride) int compress_image(vpx_codec_ctx_t *ctx, vpx_image_t *image, uint8_t **out, int *outsz) nogil vpx_codec_ctx_t* init_decoder(int width, int height) void clean_decoder(vpx_codec_ctx_t *context) - int decompress_image(vpx_codec_ctx_t *context, uint8_t *input, int size, uint8_t **out, int *outsize, int *outstride) + int decompress_image(vpx_codec_ctx_t *context, uint8_t *input, int size, uint8_t *(*out)[3], int *outsize, int (*outstride)[3]) ENCODERS = {} @@ -64,19 +65,42 @@ cdef class Decoder(xcoder): clean_decoder(self.context) self.context = NULL + def decompress_image_to_yuv(self, input): + cdef uint8_t *dout[3] + cdef int outsize + cdef int outstrides[3] + cdef unsigned char * buf = 0 + cdef Py_ssize_t buf_len = 0 + assert self.context!=NULL + PyObject_AsReadBuffer(input, &buf, &buf_len) + i = decompress_image(self.context, buf, buf_len, &dout, &outsize, &outstrides) + if i!=0: + return i, [0, 0, 0], ["", "", ""] + doutvY = (dout[0])[:self.height * outstrides[0]] + doutvU = (dout[1])[:self.height * outstrides[1]] + doutvV = (dout[2])[:self.height * outstrides[2]] + out = [doutvY, doutvU, doutvV] + strides = [outstrides[0], outstrides[1], outstrides[2]] + return i, strides, out + def decompress_image_to_rgb(self, input): + cdef uint8_t *yuvplanes[3] cdef uint8_t *dout cdef int outsize + cdef int yuvstrides[3] cdef int outstride cdef unsigned char * buf = 0 cdef Py_ssize_t buf_len = 0 assert self.context!=NULL assert self.last_image==NULL PyObject_AsReadBuffer(input, &buf, &buf_len) - i = decompress_image(self.context, buf, buf_len, &dout, &outsize, &outstride) - self.last_image = dout + i = decompress_image(self.context, buf, buf_len, &yuvplanes, &outsize, &yuvstrides) if i!=0: return i, 0, "" + i = csc_image_yuv2rgb(self.context, yuvplanes, yuvstrides, &dout, &outsize, &outstride) + if i!=0: + return i, 0, "" + self.last_image = dout doutv = (dout)[:outsize] return i, outstride, doutv @@ -105,7 +129,7 @@ cdef class Encoder(xcoder): assert self.context!=NULL #colourspace conversion with gil held: PyObject_AsReadBuffer(input, &buf, &buf_len) - pic_in = csc_image(self.context, buf, rowstride) + pic_in = csc_image_rgb2yuv(self.context, buf, rowstride) assert pic_in!=NULL, "colourspace conversion failed" #actual compression (no gil): with nogil: diff --git a/src/xpra/vpx/vpxlib.c b/src/xpra/vpx/vpxlib.c index 10272c9af2..b5d5dc39dd 100644 --- a/src/xpra/vpx/vpxlib.c +++ b/src/xpra/vpx/vpxlib.c @@ -99,7 +99,7 @@ void clean_decoder(struct vpx_context *ctx) free(ctx); } -vpx_image_t* csc_image(struct vpx_context *ctx, const uint8_t *in, int stride) +vpx_image_t* csc_image_rgb2yuv(struct vpx_context *ctx, const uint8_t *in, int stride) { vpx_image_t *image = malloc(sizeof(vpx_image_t)); if (!vpx_img_alloc(image, VPX_IMG_FMT_I420, ctx->width, ctx->height, 1)) { @@ -144,7 +144,26 @@ int compress_image(struct vpx_context *ctx, vpx_image_t *image, uint8_t **out, i return 0; } -int decompress_image(struct vpx_context *ctx, uint8_t *in, int size, uint8_t **out, int *outsize, int *outstride) +int csc_image_yuv2rgb(struct vpx_context *ctx, uint8_t *in[3], const int stride[3], uint8_t **out, int *outsz, int *outstride) +{ + int aligned_width; + uint8_t *dst[4] = { malloc(ctx->height * ctx->width * 3), NULL, NULL, NULL }; + int dststride[4] = { ctx->width * 3, 0, 0, 0 }; + + if (!ctx->yuv2rgb) + return 1; + + sws_scale(ctx->yuv2rgb, in, stride, 0, ctx->height, dst, dststride); + + /* Output (must be freed!) */ + *out = dst[0]; + *outsz = dststride[0] * ctx->height; + *outstride = dststride[0]; + + return 0; +} + +int decompress_image(struct vpx_context *ctx, uint8_t *in, int size, uint8_t *(*out)[3], int *outsize, int (*outstride)[3]) { vpx_image_t *img; int frame_sz = size; @@ -152,7 +171,6 @@ int decompress_image(struct vpx_context *ctx, uint8_t *in, int size, uint8_t **o uint8_t* frame = in; int outstrides[4]; uint8_t* outs[4]; - int stride = 0; int i = 0; if (vpx_codec_decode(&ctx->codec, frame, frame_sz, NULL, 0)) { @@ -164,19 +182,13 @@ int decompress_image(struct vpx_context *ctx, uint8_t *in, int size, uint8_t **o codec_error(&ctx->codec, "vpx_codec_get_frame"); return -1; } - for (i=0; i<4; i++) - stride += img->stride[i]; - *outsize = stride * img->h; - - *out = malloc(*outsize); - for (i=0; i<4; i++) { - outstrides[i] = img->w*3; - outs[i] = *out; + + *outsize = 0; + for (i = 0; i < 3; i++) { + (*out)[i] = img->planes[i]; + (*outstride)[i] = img->stride[i]; + *outsize += img->stride[i] * img->h; } - sws_scale(ctx->yuv2rgb, img->planes, img->stride, 0, img->h, outs, outstrides); - stride = 0; - for (i=0; i<4; i++) - stride += img->stride[i]; - *outstride = stride; + return 0; } diff --git a/src/xpra/vpx/vpxlib.h b/src/xpra/vpx/vpxlib.h index 2f5f659d53..735f1d8922 100644 --- a/src/xpra/vpx/vpxlib.h +++ b/src/xpra/vpx/vpxlib.h @@ -27,7 +27,17 @@ void clean_decoder(struct vpx_context *ctx); @param stride: Input stride (size is taken from context). @return: the converted picture. */ -vpx_image_t* csc_image(struct vpx_context *ctx, const uint8_t *in, int stride); +vpx_image_t* csc_image_rgb2yuv(struct vpx_context *ctx, const uint8_t *in, int stride); + +/** Colorspace conversion. + @param in: Input picture (3 planes). + @param stride: Input strides (3 planes). + @param out: Will be set to point to the output data in packed RGB24 format. Must be freed after use by calling free(). + @param outsz: Will be set to the size of the output buffer. + @param outstride: Output stride. + @return non zero on error. +*/ +int csc_image_yuv2rgb(struct vpx_context *ctx, uint8_t *in[3], const int stride[3], uint8_t **out, int *outsz, int *outstride); /** Compress an image using the given context. @param pic_in: the input image, as returned by csc_image @@ -40,7 +50,8 @@ int compress_image(struct vpx_context *ctx, vpx_image_t *image, uint8_t **out, i /** Decompress an image using the given context. @param in: Input buffer, format is H264. @param size: Input size. - @param out: Will be set to point to the output data in RGB24 format. - @param outstride: Output stride. + @param out: Will be filled to point to the output data in planar YUV420 format (3 planes). This data will be freed automatically upon next call to the decoder. + @param outsize: Output size. + @param outstride: Output strides (3 planes). */ -int decompress_image(struct vpx_context *ctx, uint8_t *in, int size, uint8_t **out, int *outsize, int *outstride); +int decompress_image(struct vpx_context *ctx, uint8_t *in, int size, uint8_t *(*out)[3], int *outsize, int (*outstride)[3]); diff --git a/src/xpra/x264/x264lib.h b/src/xpra/x264/x264lib.h index 9cb639a48d..33bc74a5c3 100644 --- a/src/xpra/x264/x264lib.h +++ b/src/xpra/x264/x264lib.h @@ -35,7 +35,6 @@ void clean_decoder(struct x264lib_ctx *); x264_picture_t *csc_image_rgb2yuv(struct x264lib_ctx *ctx, const uint8_t *in, int stride); /** Colorspace conversion. - * Note: you must call compress_image to free the image buffer. @param in: Input picture (3 planes). @param stride: Input strides (3 planes). @param out: Will be set to point to the output data in packed RGB24 format. Must be freed after use by calling free().