Skip to content

Commit

Permalink
#1462 support r210 10-bit encode with x264
Browse files Browse the repository at this point in the history
git-svn-id: https://xpra.org/svn/Xpra/trunk@26908 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Jul 7, 2020
1 parent ea09abe commit ec1a015
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 3 deletions.
1 change: 1 addition & 0 deletions rpmbuild/x264-xpra.spec
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ This package contains the development files for %{name}.
--prefix="%{_prefix}" \
--libdir="%{_libdir}/xpra" \
--includedir="%{_includedir}/xpra" \
--bit-depth=all \
--enable-shared \
--enable-static

Expand Down
34 changes: 34 additions & 0 deletions src/xpra/codecs/argb/argb.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,40 @@ cdef r210data_to_rgb(unsigned int* r210,
return memoryview(output_buf)


def r210_to_bgr48(buf,
const unsigned int w, const unsigned int h,
const unsigned int src_stride, const unsigned int dst_stride):
assert buf, "no buffer"
assert w*4<=src_stride, "invalid source stride %i for width %i" % (src_stride, w)
assert w*6<=dst_stride, "invalid destination stride %i for width %i" % (dst_stride, w)
assert (dst_stride%2)==0, "invalid destination stride %i (odd number)" % (dst_stride)
cdef unsigned int* cbuf = <unsigned int *> 0
cdef Py_ssize_t cbuf_len = 0
assert as_buffer(buf, <const void**> &cbuf, &cbuf_len)==0, "cannot convert %s to a readable buffer" % type(buf)
assert cbuf_len>0, "invalid buffer size: %i" % cbuf_len
assert cbuf_len>=h*src_stride, "source buffer is %i bytes, which is too small for %ix%i" % (cbuf_len, src_stride, h)
return r210data_to_bgr48(cbuf, w, h, src_stride, dst_stride)

cdef r210data_to_bgr48(unsigned int* r210,
const unsigned int w, const unsigned int h,
const unsigned int src_stride, const unsigned int dst_stride):
cdef MemBuf output_buf = getbuf(h*dst_stride*10)
cdef unsigned short* rgba = <unsigned short*> output_buf.get_mem()
cdef unsigned int y = 0
cdef unsigned int i = 0
cdef unsigned int v
for y in range(h):
i = y*dst_stride//2
for x in range(w):
v = r210[x]
rgba[i] = v&0x000003ff
rgba[i+1] = (v&0x000ffc00) >> 10
rgba[i+2] = (v&0x3ff00000) >> 20
i = i + 3
r210 = <unsigned int*> ((<uintptr_t> r210) + src_stride)
return memoryview(output_buf)


def argb_to_rgba(buf):
assert len(buf) % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % len(buf)
# buf is a Python buffer object
Expand Down
1 change: 1 addition & 0 deletions src/xpra/codecs/codec_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"YUV422P" : ((1, 1), (2, 1), (2, 1)),
"YUV444P" : ((1, 1), (1, 1), (1, 1)),
"GBRP" : ((1, 1), (1, 1), (1, 1)),
"GBRP10" : ((1, 1), (1, 1), (1, 1)),
}
def get_subsampling_divs(pixel_format):
# Return size dividers for the given pixel format
Expand Down
23 changes: 21 additions & 2 deletions src/xpra/codecs/enc_x264/encoder.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ MIN_SLICED_THREADS_SPEED = envint("XPRA_X264_SLICED_THREADS", 60)
LOGGING = os.environ.get("XPRA_X264_LOGGING", "WARNING")
PROFILE = os.environ.get("XPRA_X264_PROFILE")
SUPPORT_24BPP = envbool("XPRA_X264_SUPPORT_24BPP")
SUPPORT_30BPP = envbool("XPRA_X264_SUPPORT_30BPP", True)
TUNE = os.environ.get("XPRA_X264_TUNE")
LOG_NALS = envbool("XPRA_X264_LOG_NALS")
SAVE_TO_FILE = os.environ.get("XPRA_SAVE_TO_FILE")
Expand Down Expand Up @@ -63,6 +64,9 @@ cdef extern from "x264.h":
int X264_CSP_BGR
int X264_CSP_BGRA
int X264_CSP_RGB
int X264_CSP_NV12
int X264_CSP_V210
int X264_CSP_HIGH_DEPTH

int X264_RC_CQP
int X264_RC_CRF
Expand Down Expand Up @@ -168,6 +172,7 @@ cdef extern from "x264.h":
int i_width
int i_height
int i_csp #CSP of encoded bitstream
int i_bitdepth
int i_level_idc
int i_frame_total #number of frames to encode if known, else 0

Expand Down Expand Up @@ -344,6 +349,7 @@ COLORSPACE_FORMATS = {
"YUV444P" : (X264_CSP_I444, PROFILE_HIGH444_PREDICTIVE, I444_PROFILES),
"BGRA" : (X264_CSP_BGRA, PROFILE_HIGH444_PREDICTIVE, RGB_PROFILES),
"BGRX" : (X264_CSP_BGRA, PROFILE_HIGH444_PREDICTIVE, RGB_PROFILES),
"r210" : (X264_CSP_BGR | X264_CSP_HIGH_DEPTH, PROFILE_HIGH444_PREDICTIVE, RGB_PROFILES),
}
if SUPPORT_24BPP:
COLORSPACE_FORMATS.update({
Expand All @@ -358,6 +364,8 @@ COLORSPACES = {
"BGRA" : ("BGRA",),
"BGRX" : ("BGRX",),
}
if SUPPORT_30BPP:
COLORSPACES["r210"] = ("r210", )
if SUPPORT_24BPP:
COLORSPACES.update({
"BGR" : ("BGR",),
Expand Down Expand Up @@ -610,6 +618,10 @@ cdef class Encoder:
param.i_width = self.width
param.i_height = self.height
param.i_csp = self.colorspace
if (self.colorspace & X264_CSP_HIGH_DEPTH)>0:
param.i_bitdepth = 10
else:
param.i_bitdepth = 8
#logging hook:
param.pf_log = <void *> X264_log
param.i_log_level = LOG_LEVEL
Expand Down Expand Up @@ -818,24 +830,30 @@ cdef class Encoder:

x264_picture_init(&pic_in)

if self.src_format.find("RGB")>=0 or self.src_format.find("BGR")>=0:
if self.src_format.find("RGB")>=0 or self.src_format.find("BGR")>=0 or self.src_format=="r210":
assert len(pixels)>0
assert istrides>0
if self.src_format=="r210":
#CSC should be moved elsewhere!
from xpra.codecs.argb.argb import r210_to_bgr48
pixels = r210_to_bgr48(pixels, self.width, self.height, istrides, self.width*6)
istrides = self.width*6
assert object_as_buffer(pixels, <const void**> &pic_buf, &pic_buf_len)==0, "unable to convert %s to a buffer" % type(pixels)
for i in range(3):
pic_in.img.plane[i] = pic_buf
pic_in.img.i_stride[i] = istrides
self.bytes_in += pic_buf_len
pic_in.img.i_plane = 1
else:
assert len(pixels)==3, "image pixels does not have 3 planes! (found %s)" % len(pixels)
assert len(istrides)==3, "image strides does not have 3 values! (found %s)" % len(istrides)
for i in range(3):
assert object_as_buffer(pixels[i], <const void**> &pic_buf, &pic_buf_len)==0, "unable to convert %s to a buffer (plane=%s)" % (type(pixels[i]), i)
pic_in.img.plane[i] = pic_buf
pic_in.img.i_stride[i] = istrides[i]
pic_in.img.i_plane = 3

pic_in.img.i_csp = self.colorspace
pic_in.img.i_plane = 3
pic_in.i_pts = image.get_timestamp()-self.first_frame_timestamp
return self.do_compress_image(&pic_in, quality, speed)

Expand Down Expand Up @@ -990,6 +1008,7 @@ cdef class Encoder:


def selftest(full=False):
log("enc_x264 selftest: %s", get_info())
global SAVE_TO_FILE
from xpra.codecs.codec_checks import testencoder, get_encoder_max_sizes
from xpra.codecs.enc_x264 import encoder
Expand Down
2 changes: 1 addition & 1 deletion src/xpra/server/window/window_video_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -2130,7 +2130,7 @@ def do_video_encode(self, encoding, image, options):
if not self.common_video_encodings:
#we have to send using a non-video encoding as that's all we have!
return self.video_fallback(image, options)
if self.image_depth not in (24, 32):
if self.image_depth not in (24, 30, 32):
#this image depth is not supported for video
return self.video_fallback(image, options)

Expand Down

0 comments on commit ec1a015

Please sign in to comment.