From d87038679bacdd8768317dd418a04827d1c4ba69 Mon Sep 17 00:00:00 2001 From: totaam Date: Sat, 27 Nov 2021 15:45:33 +0700 Subject: [PATCH] #3337 'jpeg' is now both a video and picture encoding so don't remove it from the list of 'non-video' encodings, also remove the 'nvjpeg' special case, improve debug logging --- xpra/server/window/window_source.py | 20 ++++++++++++-------- xpra/server/window/window_video_source.py | 15 ++++++++++----- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/xpra/server/window/window_source.py b/xpra/server/window/window_source.py index 4fc1f413f1..5b03fb3a69 100644 --- a/xpra/server/window/window_source.py +++ b/xpra/server/window/window_source.py @@ -14,7 +14,7 @@ from time import monotonic from xpra.os_util import strtobytes, bytestostr -from xpra.util import envint, envbool, csv, typedict, first_time, decode_str +from xpra.util import envint, envbool, csv, typedict, first_time, decode_str, repr_ellipsized from xpra.common import MAX_WINDOW_SIZE from xpra.server.window.windowicon_source import WindowIconSource from xpra.server.window.window_stats import WindowPerformanceStatistics @@ -109,8 +109,8 @@ def __init__(self, damage_time, regions, encoding, options): self.options = options or {} def __repr__(self): - return "DelayedRegion(time=%i, expired=%s, encoding=%s, %i regions, options=%s)" % ( - self.damage_time, self.expired, self.encoding, len(self.regions), self.options + return "DelayedRegion(time=%i, expired=%s, encoding=%s, regions=%s, options=%s)" % ( + self.damage_time, self.expired, self.encoding, repr_ellipsized(self.regions), self.options ) @@ -180,6 +180,7 @@ def __init__(self, self.encoding = encoding #the current encoding self.encodings = encodings #all the encodings supported by the client self.core_encodings = core_encodings #the core encodings supported by the client + self.picture_encodings = () #non-video only self.rgb_formats = rgb_formats #supported RGB formats (RGB, RGBA, ...) - used by mmap self.encoding_options = encoding_options #extra options which may be specific to the encoder (ie: x264) self.rgb_zlib = use("zlib") and encoding_options.boolget("rgb_zlib", True) #server and client support zlib pixel compression @@ -338,12 +339,15 @@ def init_encoders(self): self._all_encoders = {} self._encoders = {} self.full_csc_modes = typedict() + picture_encodings = [] def add(encoder_name): encoder = get_codec(encoder_name) if encoder: for encoding in encoder.get_encodings(): if encoding in self.server_core_encodings: self.add_encoder(encoding, encoder.encode) + if encoding not in picture_encodings: + picture_encodings.append(encoding) return encoder rgb = add("enc_rgb") assert rgb, "rgb encoder is missing" @@ -367,6 +371,7 @@ def add(encoder_name): if self.cuda_device_context: self.enc_nvjpeg = add("enc_nvjpeg") self.parse_csc_modes(self.encoding_options.dictget("full_csc_modes", default=None)) + self.picture_encodings = tuple(picture_encodings) def init_vars(self): @@ -993,11 +998,11 @@ def get_transparent_encoding(self, w, h, speed, quality, current_encoding): co = self.common_encodings def canuse(e): return e in co and e in TRANSPARENCY_ENCODINGS - lossless = quality>=100 + lossy = quality<100 if canuse("rgb32") and ( (pixel_count24 and self.client_bit_depth>24) + (not lossy and depth>24 and self.client_bit_depth>24) ): return "rgb32" if canuse("webp") and depth in (24, 32) and 16383>=w>=2 and 16383>=h>=2: @@ -1015,6 +1020,7 @@ def do_get_auto_encoding(self, w, h, speed, quality, current_encoding, encoding_ co = encoding_options depth = self.image_depth grayscale = self.encoding=="grayscale" + alpha = self._want_alpha or self.is_tray if w*h24 and self.client_bit_depth>24 and "rgb32" in co: return "rgb32" @@ -1024,11 +1030,9 @@ def do_get_auto_encoding(self, w, h, speed, quality, current_encoding, encoding_ webp = "webp" in co and 16383>=w>=2 and 16383>=h>=2 and not grayscale lossy = quality<100 if depth in (24, 32) and (jpeg or webp): - if jpeg and self.enc_nvjpeg and w>=8 and h>=8 and (lossy or not TRUE_LOSSLESS): - return "jpeg" if webp and (not lossy or w*h<=WEBP_EFFICIENCY_CUTOFF): return "webp" - if jpeg and (lossy or not TRUE_LOSSLESS): + if (lossy or not TRUE_LOSSLESS) and jpeg and not alpha: return "jpeg" if webp: return "webp" diff --git a/xpra/server/window/window_video_source.py b/xpra/server/window/window_video_source.py index d7190c5401..b6c9c72be4 100644 --- a/xpra/server/window/window_video_source.py +++ b/xpra/server/window/window_video_source.py @@ -414,12 +414,13 @@ def do_set_client_properties(self, properties): self.scaling_control = max(0, min(100, properties.intget("scaling.control", 0))) super().do_set_client_properties(properties) #encodings may have changed, so redo this: - nv_common = (set(self.server_core_encodings) & set(self.core_encodings)) - set(self.video_encodings) - self.non_video_encodings = [x for x in PREFERRED_ENCODING_ORDER if x in nv_common] + nv_common = set(self.picture_encodings) & set(self.core_encodings) + log("nv_common(%s & %s)=%s", self.picture_encodings, self.core_encodings, nv_common) + self.non_video_encodings = tuple(x for x in PREFERRED_ENCODING_ORDER if x in nv_common) if not VIDEO_SKIP_EDGE: try: - self.edge_encoding = [x for x in EDGE_ENCODING_ORDER if x in self.non_video_encodings][0] - except IndexError: + self.edge_encoding = next(x for x in EDGE_ENCODING_ORDER if x in self.non_video_encodings) + except StopIteration: self.edge_encoding = None log("do_set_client_properties(%s) full_csc_modes=%s, video_subregion=%s, non_video_encodings=%s, edge_encoding=%s, scaling_control=%s", properties, self.full_csc_modes, self.video_subregion.supported, self.non_video_encodings, self.edge_encoding, self.scaling_control) @@ -813,7 +814,11 @@ def send_nonvideo(regions=regions, encoding=coding, exclude_region=None, self.expire_timer = self.timeout_add(delay, self.expire_delayed_region) def must_encode_full_frame(self, encoding): - return self.full_frames_only or (encoding in self.video_encodings) or not self.non_video_encodings + non_video = self.non_video_encodings + r = self.full_frames_only or not non_video or (encoding in self.video_encodings and encoding not in non_video) + log("must_encode_full_frame(%s)=%s full_frames_only=%s, non_video=%s, video=%s", + encoding, r, self.full_frames_only, non_video, self.video_encodings) + return r def process_damage_region(self, damage_time, x, y, w, h, coding, options, flush=0):