def has_stream_compressor(stream_compressor): if stream_compressor not in ("lz4", "lzo"): log.warn("Warning: invalid stream compressor '%s'", stream_compressor) return False from xpra.net.compression import use if stream_compressor=="lz4" and not use("lz4"): return False if stream_compressor=="lzo" and not use("lzo"): return False return True
def test_main(self): compression.init_all() assert compression.use("zlib") assert compression.get_compression_caps() assert compression.get_enabled_compressors() for x in compression.get_enabled_compressors(): assert compression.get_compressor(x)
def init_state(self): self.wants_encodings = False self.wants_features = False #contains default values, some of which may be supplied by the client: self.default_batch_config = batch_config.DamageBatchConfig() self.global_batch_config = self.default_batch_config.clone() #global batch config self.supports_transparency = False self.encoding = None #the default encoding for all windows self.encodings = () #all the encodings supported by the client self.core_encodings = () self.encodings_packet = False #supports delayed encodings initialization? self.window_icon_encodings = ["premult_argb32"] self.rgb_formats = ("RGB",) self.encoding_options = typedict() self.icons_encoding_options = typedict() self.default_encoding_options = typedict() self.auto_refresh_delay = 0 self.zlib = True self.lz4 = use("lz4") #for managing the recalculate_delays work: self.calculate_window_pixels = {} self.calculate_window_ids = set() self.calculate_timer = 0 self.calculate_last_time = 0 #if we "proxy video", we will modify the video helper to add #new encoders, so we must make a deep copy to preserve the original #which may be used by other clients (other ServerSource instances) self.video_helper = getVideoHelper().clone() self.cuda_device_context = None
def test_compressed_wrapper(self): r = compression.compressed_wrapper("test", b"a"*(compression.MIN_COMPRESS_SIZE+1)) if not r.datatype.startswith("raw"): raise Exception("should not be able to use the wrapper without enabling a compressor, but got %s" % r) for x in ("lz4", "brotli", "zlib", "none"): if not compression.use(x): continue kwargs = {x : True} for level in (0, 1, 5, 10): for data in ( b"0"*1024, b"0"*16, b"\0", memoryview(b"hello"), bytearray(b"hello"), b"1"*1024*1024*16, ): v = compression.compressed_wrapper("test", data, level=level, **kwargs) assert v assert repr(v) assert compression.get_compression_type(v.level) #and back: try: d = compression.decompress_by_name(v.data, v.algorithm) assert d if x!="none": #we can't do none, #because it would be mistaken for "zlib" #(for historical reasons - 'zlib' uses level=0, and 'none' has no level) d = compression.decompress(v.data, v.level) assert d except Exception: print("error decompressing %s - generated with settings: %s" % (v, kwargs)) raise
def compress_clipboard(): log( "compress_clipboard() compressing %s, server compressors=%s", compressible, self.server_compressors) from xpra.net import compression if "brotli" in self.server_compressors and compression.use( "brotli"): return compression.compressed_wrapper( compressible.datatype, compressible.data, level=9, brotli=True, can_inline=False) return self.compressed_wrapper(compressible.datatype, compressible.data)
def compressed_wrapper(self, datatype, data, level=5, **kwargs): if level>0 and len(data)>=256: kw = {} #brotli is not enabled by default as a generic compressor #but callers may choose to enable it via kwargs: for algo, defval in { "zlib" : True, "lz4" : True, "brotli" : False, }.items(): kw[algo] = algo in self.server_compressors and compression.use(algo) and kwargs.get(algo, defval) cw = compression.compressed_wrapper(datatype, data, level=level, can_inline=False, **kw) if len(cw)<len(data): #the compressed version is smaller, use it: return cw #we can't compress, so at least avoid warnings in the protocol layer: return compression.Compressed("raw %s" % datatype, data, can_inline=True)
def parse_client_caps(self, c : typedict): #batch options: def batch_value(prop, default, minv=None, maxv=None): assert default is not None def parse_batch_int(value, varname): if value is not None: try: return int(value) except (TypeError, ValueError): log.error("Error: invalid value '%s' for batch option %s", value, varname) return None #from client caps first: cpname = "batch.%s" % prop v = parse_batch_int(c.get(cpname), cpname) #try env: if v is None: evname = "XPRA_BATCH_%s" % prop.upper() v = parse_batch_int(os.environ.get(evname), evname) #fallback to default: if v is None: v = default if minv is not None: v = max(minv, v) if maxv is not None: v = min(maxv, v) assert v is not None return v #general features: self.zlib = c.boolget("zlib", True) self.lz4 = c.boolget("lz4", False) and use("lz4") self.brotli = c.boolget("brotli", False) and use("brotli") log("compressors: zlib=%s, lz4=%s, brotli=%s", self.zlib, self.lz4, self.brotli) delay = batch_config.START_DELAY dbc = self.default_batch_config dbc.always = bool(batch_value("always", batch_config.ALWAYS)) dbc.min_delay = batch_value("min_delay", batch_config.MIN_DELAY, 0, 1000) dbc.max_delay = batch_value("max_delay", batch_config.MAX_DELAY, 1, 15000) dbc.max_events = batch_value("max_events", batch_config.MAX_EVENTS) dbc.max_pixels = batch_value("max_pixels", batch_config.MAX_PIXELS) dbc.time_unit = batch_value("time_unit", batch_config.TIME_UNIT, 1) self.vrefresh = c.intget("vrefresh", -1) dbc.match_vrefresh(self.vrefresh) dbc.delay = batch_value("delay", delay, dbc.min_delay) log("default batch config: %s", dbc) #encodings: self.encodings_packet = c.boolget("encodings.packet", False) self.encodings = c.strtupleget("encodings") self.core_encodings = c.strtupleget("encodings.core", self.encodings) log("encodings=%s, core_encodings=%s", self.encodings, self.core_encodings) #we can't assume that the window mixin is loaded, #or that the ui_client flag exists: send_ui = getattr(self, "ui_client", True) and getattr(self, "send_windows", True) if send_ui and not self.core_encodings: raise ClientException("client failed to specify any supported encodings") self.window_icon_encodings = c.strtupleget("encodings.window-icon", ("premult_argb32",)) #try both spellings for older versions: for x in ("encodings", "encoding",): self.rgb_formats = c.strtupleget(x+".rgb_formats", self.rgb_formats) #skip all other encoding related settings if we don't send pixels: if not send_ui: log("windows/pixels forwarding is disabled for this client") else: self.parse_encoding_caps(c)