diff --git a/src/xpra/client/gl/gl_window_backing_base.py b/src/xpra/client/gl/gl_window_backing_base.py index 51f3399722..4fb9a200d6 100644 --- a/src/xpra/client/gl/gl_window_backing_base.py +++ b/src/xpra/client/gl/gl_window_backing_base.py @@ -55,7 +55,7 @@ POSIX, DummyContextManager, ) -from xpra.util import envint, envbool, repr_ellipsized +from xpra.util import envint, envbool, repr_ellipsized, first_time from xpra.client.paint_colors import get_paint_box_color from xpra.codecs.codec_constants import get_subsampling_divs from xpra.client.window_backing_base import ( @@ -122,6 +122,8 @@ "YUV420P" : GL_UNSIGNED_BYTE, "YUV422P" : GL_UNSIGNED_BYTE, "YUV444P" : GL_UNSIGNED_BYTE, + "GBRP" : GL_UNSIGNED_BYTE, + "GBRP10" : GL_UNSIGNED_SHORT, } CONSTANT_TO_PIXEL_FORMAT = { GL_BGR : "BGR", @@ -142,6 +144,7 @@ GL_UNSIGNED_INT_2_10_10_10_REV : "UNSIGNED_INT_2_10_10_10_REV", GL_UNSIGNED_INT_10_10_10_2 : "UNSIGNED_INT_10_10_10_2", GL_UNSIGNED_BYTE : "UNSIGNED_BYTE", + GL_UNSIGNED_SHORT : "UNSIGNED_SHORT", GL_UNSIGNED_SHORT_5_6_5 : "UNSIGNED_SHORT_5_6_5", } @@ -299,10 +302,12 @@ def init_formats(self): if self.bit_depth>32: self.internal_format = GL_RGBA16 self.RGB_MODES.append("r210") + self.RGB_MODES.append("GBRP10") elif self.bit_depth==30: self.internal_format = GL_RGB10_A2 self.RGB_MODES.append("r210") - elif self.bit_depth==16: + self.RGB_MODES.append("GBRP10") + elif 0 4 + bytes_per_pixel = len(pixel_format) #ie: BGRX -> 4, Y -> 1, YY -> 2 # Compute alignment and row length row_length = 0 alignment = 1 @@ -1104,7 +1111,7 @@ def do_video_paint(self, img, x : int, y : int, enc_width : int, enc_height : in #copy so the data will be usable (usually a str) img.clone_pixel_data() pixel_format = img.get_pixel_format() - if pixel_format=="GBRP": + if pixel_format.startswith("GBRP"): shader = RGBP2RGB_SHADER else: shader = YUV2RGB_SHADER @@ -1119,7 +1126,7 @@ def gl_paint_planar(self, shader, flush, encoding, img, x, y = self.gravity_adjust(x, y, options) try: pixel_format = img.get_pixel_format() - assert pixel_format in ("YUV420P", "YUV422P", "YUV444P", "GBRP", ), \ + assert pixel_format in ("YUV420P", "YUV422P", "YUV444P", "GBRP", "GBRP10"), \ "sorry the GL backing does not handle pixel format '%s' yet!" % (pixel_format) context = self.gl_context() @@ -1184,7 +1191,7 @@ def update_planar_textures(self, width : int, height : int, img, pixel_format, s self.gl_marker("updating planar textures: %sx%s %s", width, height, pixel_format) rowstrides = img.get_rowstride() img_data = img.get_pixels() - BPP = 1 + BPP = 2 if pixel_format.endswith("P10") else 1 assert len(rowstrides)==3 and len(img_data)==3 for texture, index, tex_name in ( (GL_TEXTURE0, TEX_Y, "Y"*BPP), @@ -1218,7 +1225,7 @@ def update_planar_textures(self, width : int, height : int, img, pixel_format, s def render_planar_update(self, rx : int, ry : int, rw : int, rh : int, x_scale=1, y_scale=1, shader=YUV2RGB_SHADER): log("%s.render_planar_update%s pixel_format=%s", self, (rx, ry, rw, rh, x_scale, y_scale, shader), self.pixel_format) - if self.pixel_format not in ("YUV420P", "YUV422P", "YUV444P", "GBRP"): + if self.pixel_format not in ("YUV420P", "YUV422P", "YUV444P", "GBRP", "GBRP10"): #not ready to render yet return self.gl_marker("painting planar update, format %s", self.pixel_format) diff --git a/src/xpra/codecs/dec_avcodec2/decoder.pyx b/src/xpra/codecs/dec_avcodec2/decoder.pyx index ac0331e641..0597b4479c 100644 --- a/src/xpra/codecs/dec_avcodec2/decoder.pyx +++ b/src/xpra/codecs/dec_avcodec2/decoder.pyx @@ -503,6 +503,9 @@ FORMAT_TO_STR = { #AV_PIX_FMT_NB : "NB", } +#given one of our format names, +#describing the pixel data fed to the encoder, +#what ffmpeg AV_PIX_FMT we expect to find in the output: FORMAT_TO_ENUM = { "YUV420P" : AV_PIX_FMT_YUV420P, "YUV422P" : AV_PIX_FMT_YUV422P, @@ -513,6 +516,7 @@ FORMAT_TO_ENUM = { "ARGB" : AV_PIX_FMT_ARGB, "BGRA" : AV_PIX_FMT_BGRA, "GBRP" : AV_PIX_FMT_GBRP, + "BGR48" : AV_PIX_FMT_GBRP10LE, } #for planar formats, this is the number of bytes per channel BYTES_PER_PIXEL = { @@ -525,12 +529,18 @@ BYTES_PER_PIXEL = { AV_PIX_FMT_ARGB : 4, AV_PIX_FMT_BGRA : 4, AV_PIX_FMT_GBRP : 1, + AV_PIX_FMT_GBRP10LE : 6, } +#given an ffmpeg pixel format, +#what is our format name for it: COLORSPACES = tuple(FORMAT_TO_ENUM.keys()) ENUM_TO_FORMAT = {} for pix_fmt, av_enum in FORMAT_TO_ENUM.items(): ENUM_TO_FORMAT[av_enum] = pix_fmt +#ENUM_TO_FORMAT[AV_PIX_FMT_YUV422P10LE] = "YUV422P10" +ENUM_TO_FORMAT[AV_PIX_FMT_GBRP10LE] = "GBRP10" + def get_version(): return (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO) @@ -596,9 +606,12 @@ def get_input_colorspaces(encoding): def get_output_colorspace(encoding, csc): if encoding not in CODECS: return "" - if encoding=="h264" and csc in ("RGB", "XRGB", "BGRX", "ARGB", "BGRA"): - #h264 from plain RGB data is returned as "GBRP"! - return "GBRP" + if encoding=="h264": + if csc in ("RGB", "XRGB", "BGRX", "ARGB", "BGRA"): + #h264 from plain RGB data is returned as "GBRP"! + return "GBRP" + if csc=="BGR48": + return "GBRP10" elif encoding in ("vp8", "mpeg4", "mpeg1", "mpeg2"): return "YUV420P" #everything else as normal: @@ -951,7 +964,8 @@ cdef class Decoder: log("avcodec actual output pixel format is %s (%s), expected %s (%s)", self.actual_pix_fmt, self.get_actual_colorspace(), self.pix_fmt, self.colorspace) cs = self.get_actual_colorspace() - if cs.endswith("P"): + log("actual_colorspace(%s)=%s", self.actual_pix_fmt, cs) + if cs.find("P")>0: #ie: GBRP, YUV420P, YUV422P10LE etc divs = get_subsampling_divs(cs) nplanes = 3 for i in range(3): @@ -968,16 +982,30 @@ cdef class Decoder: size = height * stride outsize += size - out.append(memory_as_pybuffer(av_frame.data[i], size, True)) + if cs=="GBRP10": + b = bytearray(size) + for z in range(size//2): + b[z*2] = av_frame.data[i][z*2+1] + b[z*2+1] = av_frame.data[i][z*2] + obuf = bytes(b) + else: + obuf = memory_as_pybuffer(av_frame.data[i], size, True) + out.append(obuf) + #if cs=="GBRP10": + # from xpra.os_util import memoryview_to_bytes + # for y in range(12): + # line = height*y//12 + # line_data = memoryview_to_bytes(out[-1])[line*stride:(line+1)*stride] + # log("plane %s line %3i %s..%s", cs[i:i+1], line, hexstr(line_data[:10]), hexstr(line_data[-10:])) strides.append(stride) - log("decompress_image() read back yuv plane %s: %s bytes", i, size) + log("decompress_image() read back '%s' plane: %s bytes", cs[i:i+1], size) else: #RGB mode: "out" is a single buffer strides = av_frame.linesize[0]+av_frame.linesize[1]+av_frame.linesize[2] outsize = self.codec_ctx.height * strides out = memory_as_pybuffer(av_frame.data[0], outsize, True) nplanes = 0 - log("decompress_image() read back rgb buffer: %s bytes", outsize) + log("decompress_image() read back '%s' buffer: %s bytes", cs, outsize) if outsize==0: av_frame_unref(av_frame)