Skip to content

Commit

Permalink
#614: add switches to control compressors and packet-encoders
Browse files Browse the repository at this point in the history
git-svn-id: https://xpra.org/svn/Xpra/trunk@6965 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Jul 27, 2014
1 parent cd7d37b commit a3116ed
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 45 deletions.
11 changes: 11 additions & 0 deletions src/etc/xpra/xpra.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,20 @@ mmap-group = no
# Share session with other users:
sharing = no

# Compressors:
#compressors = all
#compressors = none
#compressors = zlib
compressors = lz4, zlib, bz2

# Default compression (0 to 9):
compression_level = 1

# Packet encoders (at least one is required):
#packet-encoders = bencode
#packet-encoders = all
packet-encoders = rencode, bencode, yaml

# Socket directory:
#socket-dir = /tmp
#socket-dir = ~/.xpra
Expand Down
17 changes: 9 additions & 8 deletions src/xpra/client/ui_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from xpra.codecs.loader import codec_versions, has_codec, get_codec, PREFERED_ENCODING_ORDER, ALL_NEW_ENCODING_NAMES_TO_OLD, OLD_ENCODING_NAMES_TO_NEW
from xpra.codecs.video_helper import getVideoHelper, ALL_VIDEO_DECODER_OPTIONS, NO_GFX_CSC_OPTIONS
from xpra.simple_stats import std_unit
from xpra.net.compression import Compressed, use_lz4
from xpra.net import compression, packet_encoding
from xpra.daemon_thread import make_daemon_thread
from xpra.os_util import thread, Queue, os_info, platform_name, get_machine_id, get_user_uuid, bytestostr
from xpra.util import nn, nonl, std, AtomicInteger, AdHocStruct, log_screen_sizes, typedict
Expand Down Expand Up @@ -889,7 +889,7 @@ def make_hello(self):
"encoding.video_scaling" : True,
#separate plane is only supported by avcodec2:
"encoding.video_separateplane" : get_codec("dec_avcodec") is None and get_codec("dec_avcodec2") is not None,
"encoding.rgb_lz4" : use_lz4 and self.compression_level==1,
"encoding.rgb_lz4" : compression.use_lz4 and self.compression_level==1,
"encoding.webp_leaks" : False,
"encoding.transparency" : self.has_transparency(),
"rgb24zlib" : True,
Expand All @@ -912,11 +912,12 @@ def make_hello(self):
"encodings.core" : self.get_core_encodings(),
})
control_commands = ["show_session_info", "enable_bencode", "enable_zlib"]
from xpra.net.protocol import use_bencode, use_rencode, use_yaml
for k,b in {"lz4" : use_lz4,
"bencode" : use_bencode,
"rencode" : use_rencode,
"yaml" : use_yaml}.items():
for k,b in {"lz4" : compression.use_lz4,
"bz2" : compression.use_bz2,
"zlib" : compression.use_zlib,
"bencode" : packet_encoding.use_bencode,
"rencode" : packet_encoding.use_rencode,
"yaml" : packet_encoding.use_yaml}.items():
if b:
control_commands.append("enable_"+k)
capabilities["control_commands"] = control_commands
Expand Down Expand Up @@ -1549,7 +1550,7 @@ def start_sound_sink(self, codec):
def new_sound_buffer(self, sound_source, data, metadata):
soundlog("new_sound_buffer(%s, %s, %s) sound source=%s", sound_source, len(data or []), metadata, self.sound_source)
if self.sound_source:
self.send("sound-data", self.sound_source.codec, Compressed(self.sound_source.codec, data), metadata)
self.send("sound-data", self.sound_source.codec, compression.Compressed(self.sound_source.codec, data), metadata)

def _process_sound_data(self, packet):
codec, data, metadata = packet[1:4]
Expand Down
10 changes: 5 additions & 5 deletions src/xpra/net/compression.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

import os
import sys
import zlib
import bz2
Expand Down Expand Up @@ -34,8 +33,6 @@ def lz4_compress(packet, level):
has_lz4 = False
def lz4_compress(packet, level):
raise Exception("lz4 is not supported!")
use_lz4 = has_lz4 and os.environ.get("XPRA_USE_LZ4", "1")=="1"


#stupid python version breakage:
if sys.version > '3':
Expand All @@ -60,8 +57,11 @@ def bzcompress(packet, level):
return level + BZ2_FLAG, bz2.compress(str(packet), level)
def nocompress(packet, level):
return 0, packet
use_zlib = os.environ.get("XPRA_USE_ZLIB", "1")=="1"
use_bz2 = os.environ.get("XPRA_USE_BZ2", "1")=="1"

#defaults to True if available:
use_zlib = True
use_bz2 = True
use_lz4 = has_lz4


class Compressed(object):
Expand Down
50 changes: 26 additions & 24 deletions src/xpra/net/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
from xpra.os_util import Queue, strtobytes
from xpra.util import repr_ellipsized
from xpra.net.bytestreams import ABORT
from xpra.net.compression import nocompress, zcompress, use_zlib, bzcompress, use_bz2, BZ2_FLAG, has_lz4, use_lz4, LZ4_FLAG, lz4_compress, LZ4_uncompress, Compressed, LevelCompressed
from xpra.net import compression
from xpra.net.compression import nocompress, zcompress, bzcompress, BZ2_FLAG, has_lz4, LZ4_FLAG, lz4_compress, LZ4_uncompress, Compressed, LevelCompressed
from xpra.net.header import unpack_header, pack_header, pack_header_and_data
from xpra.net.crypto import get_crypto_caps, get_cipher
from xpra.net.packet_encoding import rencode_dumps, rencode_loads, rencode_version, has_rencode, use_rencode, \
bencode, bdecode, bencode_version, has_bencode, use_bencode, \
yaml_encode, yaml_decode, yaml_version, has_yaml, use_yaml
from xpra.net import packet_encoding
from xpra.net.packet_encoding import rencode_dumps, rencode_loads, rencode_version, has_rencode, \
bencode, bdecode, bencode_version, has_bencode, \
yaml_encode, yaml_decode, yaml_version, has_yaml


#stupid python version breakage:
Expand Down Expand Up @@ -57,12 +59,12 @@ def get_network_caps(legacy=True):
mmap = False
caps = {
"digest" : ("hmac", "xor"),
"rencode" : use_rencode,
"bencode" : use_bencode,
"yaml" : use_yaml,
"lz4" : use_lz4,
"bz2" : use_bz2,
"zlib" : use_zlib,
"rencode" : packet_encoding.use_rencode,
"bencode" : packet_encoding.use_bencode,
"yaml" : packet_encoding.use_yaml,
"lz4" : compression.use_lz4,
"bz2" : compression.use_bz2,
"zlib" : compression.use_zlib,
"zlib.version" : zlib.__version__,
"mmap" : mmap,
}
Expand Down Expand Up @@ -397,11 +399,11 @@ def enable_default_encoder(self):
self.enable_yaml()

def enable_encoder_from_caps(self, caps):
if use_rencode and caps.boolget("rencode"):
if packet_encoding.use_rencode and caps.boolget("rencode"):
self.enable_rencode()
elif use_yaml and caps.boolget("yaml"):
elif packet_encoding.use_yaml and caps.boolget("yaml"):
self.enable_yaml()
elif use_bencode and caps.boolget("bencode", True):
elif packet_encoding.use_bencode and caps.boolget("bencode", True):
self.enable_bencode()
else:
raise Exception("no matching packet encoder found!")
Expand All @@ -423,11 +425,11 @@ def enable_yaml(self):


def enable_default_compressor(self):
if use_zlib:
if compression.use_zlib:
self.enable_zlib()
elif use_lz4:
elif compression.use_lz4:
self.enable_lz4()
elif use_bz2:
elif compression.use_bz2:
self.enable_yaml()
else:
self.enable_nocompress()
Expand All @@ -436,14 +438,14 @@ def enable_compressor_from_caps(self, caps):
if self.compression_level==0:
self.enable_nocompress()
return
if caps.boolget("lz4") and use_lz4 and self.compression_level==1:
if caps.boolget("lz4") and compression.use_lz4 and self.compression_level==1:
self.enable_lz4()
elif caps.boolget("zlib") and use_zlib:
elif caps.boolget("zlib") and compression.use_zlib:
self.enable_zlib()
elif caps.boolget("bz2") and use_bz2:
elif caps.boolget("bz2") and compression.use_bz2:
self.enable_bz2()
#retry lz4 (without level check)
elif caps.boolget("lz4") and use_lz4:
elif caps.boolget("lz4") and compression.use_lz4:
self.enable_lz4()
else:
log.error("no matching compressor found!")
Expand All @@ -458,7 +460,7 @@ def enable_zlib(self):
self._compress = zcompress

def enable_lz4(self):
assert has_lz4, "lz4 cannot be enabled: the module failed to load!"
assert compression.use_lz4, "lz4 cannot be enabled: the module failed to load!"
log("enable_lz4()")
self._compress = lz4_compress

Expand Down Expand Up @@ -771,15 +773,15 @@ def debug_str(s):
if compression_level & LZ4_FLAG:
ctype = "lz4"
assert has_lz4, "lz4 is not available"
assert use_lz4, "lz4 is not enabled"
assert compression.use_lz4, "lz4 is not enabled"
data = LZ4_uncompress(data)
elif compression_level & BZ2_FLAG:
ctype = "bz2"
assert use_bz2, "bz2 is not enabled"
assert compression.use_bz2, "bz2 is not enabled"
data = bz2.decompress(data)
else:
ctype = "zlib"
assert use_zlib, "zlib is not enabled"
assert compression.use_zlib, "zlib is not enabled"
data = zlib.decompress(data)
except Exception, e:
log("%s packet decompression failed", ctype, exc_info=True)
Expand Down
6 changes: 5 additions & 1 deletion src/xpra/scripts/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def read_config(conf_file):
continue
lines.append(sline)
f.close()
#aggregate any lines with trailing bacakslash
#aggregate any lines with trailing backslash
agg_lines = []
l = ""
for line in lines:
Expand Down Expand Up @@ -295,6 +295,8 @@ def read_xpra_defaults(conf_dir=DEFAULT_XPRA_CONF_DIR):
"csc-modules" : list,
"speaker-codec" : list,
"microphone-codec" : list,
"compressors" : list,
"packet-encoders" : list,
"key-shortcut" : list,
"start-child" : list,
"bind-tcp" : list,
Expand Down Expand Up @@ -387,6 +389,8 @@ def get_defaults():
"csc-modules" : [],
"speaker-codec" : [],
"microphone-codec" : [],
"compressors" : [],
"packet-encoders" : [],
"key-shortcut" : ["Meta+Shift+F4:quit", "Meta+Shift+F8:magic_key", "Meta+Shift+F11:show_session_info"],
"bind-tcp" : None,
"start-child" : None,
Expand Down
40 changes: 39 additions & 1 deletion src/xpra/scripts/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ def parse_cmdline(cmdline):
hidden_options["microphone"] = False
hidden_options["microphone_codec"] = []

group = OptionGroup(parser, "Picture Encoding and Compression Options",
group = OptionGroup(parser, "Encoding and Compression Options",
"These options are used by the client to specify the desired picture and network data compression."
"They may also be specified on the server as default values for those clients that do not set them.")
parser.add_option_group(group)
Expand Down Expand Up @@ -368,6 +368,12 @@ def parse_cmdline(cmdline):
help="Idle delay in seconds before doing an automatic lossless refresh."
+ " 0.0 to disable."
+ " Default: %default.")
group.add_option("--compressors", action="store",
dest="compressors", default=", ".join(defaults.compressors),
help="The packet compressors to enable (default: %default)")
group.add_option("--packet-encoders", action="store",
dest="packet_encoders", default=", ".join(defaults.packet_encoders),
help="The packet encoders to enable (default: %default)")
group.add_option("-z", "--compress", action="store",
dest="compression_level", type="int", default=defaults.compression_level,
metavar="LEVEL",
Expand Down Expand Up @@ -509,6 +515,38 @@ def parse_cmdline(cmdline):
from xpra.codecs.loader import ALL_OLD_ENCODING_NAMES_TO_NEW
options.encoding = ALL_OLD_ENCODING_NAMES_TO_NEW.get(options.encoding, options.encoding)

#set network attributes:
from xpra.net import compression
compressors = [x.strip() for x in options.compressors.split(",")]
c_map = {"lz4" : compression.has_lz4, "bz2" : True, "zlib": True}
if "all" in compressors:
compressors = [x for x,b in c_map.items() if b]
else:
unknown = [x for x in compressors if x and x not in c_map]
if unknown:
print("warning: invalid compressor(s) specified: %s" % (", ".join(unknown)))
for x,b in c_map.items():
enabled = b and x in compressors
setattr(compression, "use_%s" % x, enabled)
from xpra.net import packet_encoding
packet_encoders = [x.strip() for x in options.packet_encoders.split(",")]
pe_map = {"bencode" : packet_encoding.has_bencode,
"rencode" : packet_encoding.has_rencode,
"yaml" : packet_encoding.has_yaml,
}
if "all" in packet_encoders:
packet_encoders = [x for x,b in pe_map.items() if b]
else:
unknown = [x for x in packet_encoders if x and x not in pe_map]
if unknown:
print("warning: invalid packet encoder(s) specified: %s" % (", ".join(unknown)))
for x,b in pe_map.items():
enabled = b and x in packet_encoders
setattr(packet_encoding, "use_%s" % x, enabled)
#verify that at least one encoder is available:
if not [x for x in pe_map.keys() if getattr(packet_encoding, "use_%s" % x)]:
parser.error("at least one valid packet encoder must be enabled")

#special case for video encoders and csc, stored as lists, but command line option is a CSV string:
if (supports_server or supports_shadow):
if type(options.video_encoders)==str:
Expand Down
12 changes: 6 additions & 6 deletions src/xpra/server/picture_encode.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from xpra.log import Logger
log = Logger("window", "encoding")

from xpra.net.compression import compressed_wrapper, Compressed, use_lz4
from xpra.net import compression
try:
from xpra.codecs.argb.argb import bgra_to_rgb, bgra_to_rgba, argb_to_rgb, argb_to_rgba #@UnresolvedImport
except Exception, e:
Expand Down Expand Up @@ -61,7 +61,7 @@ def webp_encode(coding, image, supports_transparency, quality, speed, options):
client_options["quality"] = quality
if alpha:
client_options["has_alpha"] = True
return "webp", Compressed("webp", cdata), client_options, image.get_width(), image.get_height(), 0, 24
return "webp", compression.Compressed("webp", cdata), client_options, image.get_width(), image.get_height(), 0, 24
#fallback to PIL
return PIL_encode(coding, image, quality, speed, supports_transparency)

Expand Down Expand Up @@ -120,8 +120,8 @@ def rgb_encode(coding, image, rgb_formats, supports_transparency, speed, rgb_zli
#fewer pixels, make it more likely we won't bother compressing:
level = level / 2
if level>0:
lz4 = use_lz4 and rgb_lz4 and level<=3
wire_data = compressed_wrapper(coding, pixels, level=level, lz4=lz4)
lz4 = compression.use_lz4 and rgb_lz4 and level<=3
wire_data = compression.compressed_wrapper(coding, pixels, level=level, lz4=lz4)
raw_data = wire_data.data
#log("%s/%s data compressed from %s bytes down to %s (%s%%) with lz4=%s",
# coding, pixel_format, len(pixels), len(raw_data), int(100.0*len(raw_data)/len(pixels)), self.rgb_lz4)
Expand All @@ -146,7 +146,7 @@ def rgb_encode(coding, image, rgb_formats, supports_transparency, speed, rgb_zli
return coding, wire_data, {}, width, height, stride, bpp
#wrap it using "Compressed" so the network layer receiving it
#won't decompress it (leave it to the client's draw thread)
return coding, Compressed(coding, raw_data), options, width, height, stride, bpp
return coding, compression.Compressed(coding, raw_data), options, width, height, stride, bpp


def PIL_encode(coding, image, quality, speed, supports_transparency):
Expand Down Expand Up @@ -242,7 +242,7 @@ def mask_value(a):
log("sending %sx%s %s as %s, mode=%s, options=%s", w, h, pixel_format, coding, im.mode, kwargs)
data = buf.getvalue()
buf.close()
return coding, Compressed(coding, data), client_options, image.get_width(), image.get_height(), 0, bpp
return coding, compression.Compressed(coding, data), client_options, image.get_width(), image.get_height(), 0, bpp


def argb_swap(image, rgb_formats, supports_transparency):
Expand Down

0 comments on commit a3116ed

Please sign in to comment.