Skip to content

Commit

Permalink
#3337 'jpeg' is now both a video and picture encoding
Browse files Browse the repository at this point in the history
so don't remove it from the list of 'non-video' encodings,
also remove the 'nvjpeg' special case,
improve debug logging
  • Loading branch information
totaam committed Nov 27, 2021
1 parent 81f241e commit d870386
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 13 deletions.
20 changes: 12 additions & 8 deletions xpra/server/window/window_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)


Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand All @@ -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):
Expand Down Expand Up @@ -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_count<self._rgb_auto_threshold) or
#the only encoding that can preserve higher bit depth at present:
(lossless and depth>24 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:
Expand All @@ -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*h<self._rgb_auto_threshold and not grayscale:
if depth>24 and self.client_bit_depth>24 and "rgb32" in co:
return "rgb32"
Expand All @@ -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"
Expand Down
15 changes: 10 additions & 5 deletions xpra/server/window/window_video_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit d870386

Please sign in to comment.