diff options
author | Javier Celaya <javier.celaya@flexvm.es> | 2014-11-13 17:00:58 +0100 |
---|---|---|
committer | Christophe Fergeau <cfergeau@redhat.com> | 2014-12-02 19:41:17 +0100 |
commit | b532ef0866cefe260ad0f08550f7c40d3580d0d7 (patch) | |
tree | 29a0c98c41d61178cc0ac66db359073caacd05b8 /server/lz4_encoder.c | |
parent | 84b3a5079d6014d50e3018b24949d5a2e18e3c78 (diff) | |
download | spice-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.c | 122 |
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 |