summaryrefslogtreecommitdiffstats
path: root/server/lz4_encoder.c
diff options
context:
space:
mode:
authorJavier Celaya <javier.celaya@flexvm.es>2014-11-13 17:00:58 +0100
committerChristophe Fergeau <cfergeau@redhat.com>2014-12-02 19:41:17 +0100
commitb532ef0866cefe260ad0f08550f7c40d3580d0d7 (patch)
tree29a0c98c41d61178cc0ac66db359073caacd05b8 /server/lz4_encoder.c
parent84b3a5079d6014d50e3018b24949d5a2e18e3c78 (diff)
downloadspice-b532ef0866cefe260ad0f08550f7c40d3580d0d7.tar.gz
spice-b532ef0866cefe260ad0f08550f7c40d3580d0d7.tar.xz
spice-b532ef0866cefe260ad0f08550f7c40d3580d0d7.zip
Add LZ4 compression support.
- Add lz4 encoder to compress an image of type LZ4 (see spice_common). - Add code in red_worker to use LZ4 when it is enabled, and the client supports it through its display capability, or fallback to LZ. - Add enable_lz4 switch in the configure script. Show LZ4 support at the end.
Diffstat (limited to 'server/lz4_encoder.c')
-rw-r--r--server/lz4_encoder.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/server/lz4_encoder.c b/server/lz4_encoder.c
new file mode 100644
index 00000000..531ab4bc
--- /dev/null
+++ b/server/lz4_encoder.c
@@ -0,0 +1,122 @@
+/*
+ Copyright (C) 2014 Flexible Software Solutions S.L.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_LZ4
+
+#define SPICE_LOG_DOMAIN "SpiceLz4Encoder"
+
+#include <arpa/inet.h>
+#include <lz4.h>
+#include "red_common.h"
+#include "lz4_encoder.h"
+
+typedef struct Lz4Encoder {
+ Lz4EncoderUsrContext *usr;
+} Lz4Encoder;
+
+Lz4EncoderContext* lz4_encoder_create(Lz4EncoderUsrContext *usr)
+{
+ Lz4Encoder *enc;
+ if (!usr->more_space || !usr->more_lines) {
+ return NULL;
+ }
+
+ enc = spice_new0(Lz4Encoder, 1);
+ enc->usr = usr;
+
+ return (Lz4EncoderContext*)enc;
+}
+
+void lz4_encoder_destroy(Lz4EncoderContext* encoder)
+{
+ free(encoder);
+}
+
+int lz4_encode(Lz4EncoderContext *lz4, int height, int stride,
+ uint8_t *io_ptr, unsigned int num_io_bytes)
+{
+ Lz4Encoder *enc = (Lz4Encoder *)lz4;
+ uint8_t *lines;
+ int num_lines = 0;
+ int total_lines = 0;
+ int in_size, enc_size, out_size = 0, already_copied;
+ int stride_abs = abs(stride);
+ uint8_t *in_buf, *compressed_lines;
+ uint8_t *out_buf = io_ptr;
+ LZ4_stream_t *stream = LZ4_createStream();
+
+ // Encode direction
+ *(out_buf++) = stride < 0 ? 1 : 0;
+ num_io_bytes--;
+
+ do {
+ num_lines = enc->usr->more_lines(enc->usr, &lines);
+ if (num_lines <= 0) {
+ spice_error("more lines failed");
+ LZ4_freeStream(stream);
+ return 0;
+ }
+ in_buf = stride < 0 ? lines - (stride_abs * (num_lines - 1)) : lines;
+ lines += stride * num_lines;
+ in_size = stride_abs * num_lines;
+ compressed_lines = (uint8_t *) malloc(LZ4_compressBound(in_size) + 4);
+ enc_size = LZ4_compress_continue(stream, (const char *) in_buf,
+ (char *) compressed_lines + 4, in_size);
+ if (enc_size <= 0) {
+ spice_error("compress failed!");
+ free(compressed_lines);
+ LZ4_freeStream(stream);
+ return 0;
+ }
+ *((uint32_t *)compressed_lines) = htonl(enc_size);
+
+ out_size += enc_size += 4;
+ already_copied = 0;
+ while (num_io_bytes < enc_size) {
+ memcpy(out_buf, compressed_lines + already_copied, num_io_bytes);
+ already_copied += num_io_bytes;
+ enc_size -= num_io_bytes;
+ num_io_bytes = enc->usr->more_space(enc->usr, &io_ptr);
+ if (num_io_bytes <= 0) {
+ spice_error("more space failed");
+ free(compressed_lines);
+ LZ4_freeStream(stream);
+ return 0;
+ }
+ out_buf = io_ptr;
+ }
+ memcpy(out_buf, compressed_lines + already_copied, enc_size);
+ out_buf += enc_size;
+ num_io_bytes -= enc_size;
+
+ free(compressed_lines);
+ total_lines += num_lines;
+ } while (total_lines < height);
+
+ LZ4_freeStream(stream);
+ if (total_lines != height) {
+ spice_error("too many lines\n");
+ out_size = 0;
+ }
+
+ return out_size;
+}
+
+#endif // USE_LZ4