diff options
author | Marc-André Lureau <marcandre.lureau@gmail.com> | 2013-09-30 15:00:01 +0200 |
---|---|---|
committer | Fabiano Fidêncio <fidencio@redhat.com> | 2015-02-23 23:00:40 +0100 |
commit | 286a570895c04c3624c403120c20dd54b627fb58 (patch) | |
tree | 57adc8d905f3e7b4ea55a61c3286cd5ac4611c1f /server/glz-encoder.c | |
parent | c261e99df0257014c9ec16c76245bffa0fc73ca8 (diff) | |
download | spice-286a570895c04c3624c403120c20dd54b627fb58.tar.gz spice-286a570895c04c3624c403120c20dd54b627fb58.tar.xz spice-286a570895c04c3624c403120c20dd54b627fb58.zip |
server: rename files
Diffstat (limited to 'server/glz-encoder.c')
-rw-r--r-- | server/glz-encoder.c | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/server/glz-encoder.c b/server/glz-encoder.c new file mode 100644 index 00000000..a11bfb63 --- /dev/null +++ b/server/glz-encoder.c @@ -0,0 +1,310 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + 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 + +#include <pthread.h> +#include <stdio.h> +#include "glz-encoder.h" +#include "glz-encoder-priv.h" + + +/* Holds a specific data for one encoder, and data that is relevant for the current image encoded */ +typedef struct Encoder { + GlzEncoderUsrContext *usr; + uint8_t id; + SharedDictionary *dict; + + struct { + LzImageType type; + uint32_t id; + uint32_t first_win_seg; + } cur_image; + + struct { + uint8_t *start; + uint8_t *now; + uint8_t *end; + size_t bytes_count; + uint8_t *last_copy; // pointer to the last byte in which copy count was written + } io; +} Encoder; + + +/************************************************************************** +* Handling writing the encoded image to the output buffer +***************************************************************************/ +static inline int more_io_bytes(Encoder *encoder) +{ + uint8_t *io_ptr; + int num_io_bytes = encoder->usr->more_space(encoder->usr, &io_ptr); + encoder->io.bytes_count += num_io_bytes; + encoder->io.now = io_ptr; + encoder->io.end = encoder->io.now + num_io_bytes; + return num_io_bytes; +} + +static inline void encode(Encoder *encoder, uint8_t byte) +{ + if (encoder->io.now == encoder->io.end) { + if (more_io_bytes(encoder) <= 0) { + encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__); + } + GLZ_ASSERT(encoder->usr, encoder->io.now); + } + + GLZ_ASSERT(encoder->usr, encoder->io.now < encoder->io.end); + *(encoder->io.now++) = byte; +} + +static inline void encode_32(Encoder *encoder, unsigned int word) +{ + encode(encoder, (uint8_t)(word >> 24)); + encode(encoder, (uint8_t)(word >> 16) & 0x0000ff); + encode(encoder, (uint8_t)(word >> 8) & 0x0000ff); + encode(encoder, (uint8_t)(word & 0x0000ff)); +} + +static inline void encode_64(Encoder *encoder, uint64_t word) +{ + encode_32(encoder, (uint32_t)(word >> 32)); + encode_32(encoder, (uint32_t)(word & 0xffffff)); +} + +static inline void encode_copy_count(Encoder *encoder, uint8_t copy_count) +{ + encode(encoder, copy_count); + encoder->io.last_copy = encoder->io.now - 1; // io_now cannot be the first byte of the buffer +} + +static inline void update_copy_count(Encoder *encoder, uint8_t copy_count) +{ + GLZ_ASSERT(encoder->usr, encoder->io.last_copy); + *(encoder->io.last_copy) = copy_count; +} + +// decrease the io ptr by 1 +static inline void compress_output_prev(Encoder *encoder) +{ + // io_now cannot be the first byte of the buffer + encoder->io.now--; + // the function should be called only when copy count is written unnecessarily by glz_compress + GLZ_ASSERT(encoder->usr, encoder->io.now == encoder->io.last_copy) +} + +static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end) +{ + GLZ_ASSERT(encoder->usr, io_ptr <= io_ptr_end); + encoder->io.bytes_count = io_ptr_end - io_ptr; + encoder->io.start = io_ptr; + encoder->io.now = io_ptr; + encoder->io.end = io_ptr_end; + encoder->io.last_copy = NULL; + + return TRUE; +} + +/********************************************************** +* Encoding +***********************************************************/ + +GlzEncoderContext *glz_encoder_create(uint8_t id, GlzEncDictContext *dictionary, + GlzEncoderUsrContext *usr) +{ + Encoder *encoder; + + if (!usr || !usr->error || !usr->warn || !usr->info || !usr->malloc || + !usr->free || !usr->more_space) { + return NULL; + } + + if (!(encoder = (Encoder *)usr->malloc(usr, sizeof(Encoder)))) { + return NULL; + } + + encoder->id = id; + encoder->usr = usr; + encoder->dict = (SharedDictionary *)dictionary; + + return (GlzEncoderContext *)encoder; +} + +void glz_encoder_destroy(GlzEncoderContext *opaque_encoder) +{ + Encoder *encoder = (Encoder *)opaque_encoder; + + if (!opaque_encoder) { + return; + } + + encoder->usr->free(encoder->usr, encoder); +} + +/* + * Give hints to the compiler for branch prediction optimization. + */ +#if defined(__GNUC__) && (__GNUC__ > 2) +#define LZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) +#define LZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) +#else +#define LZ_EXPECT_CONDITIONAL(c) (c) +#define LZ_UNEXPECT_CONDITIONAL(c) (c) +#endif + + +typedef uint8_t BYTE; + +typedef struct __attribute__ ((__packed__)) one_byte_pixel_t { + BYTE a; +} one_byte_pixel_t; + +typedef struct __attribute__ ((__packed__)) rgb32_pixel_t { + BYTE b; + BYTE g; + BYTE r; + BYTE pad; +} rgb32_pixel_t; + +typedef struct __attribute__ ((__packed__)) rgb24_pixel_t { + BYTE b; + BYTE g; + BYTE r; +} rgb24_pixel_t; + +typedef uint16_t rgb16_pixel_t; + +#define BOUND_OFFSET 2 +#define LIMIT_OFFSET 6 +#define MIN_FILE_SIZE 4 + +#define MAX_PIXEL_SHORT_DISTANCE 4096 // (1 << 12) +#define MAX_PIXEL_MEDIUM_DISTANCE 131072 // (1 << 17) 2 ^ (12 + 5) +#define MAX_PIXEL_LONG_DISTANCE 33554432 // (1 << 25) 2 ^ (12 + 5 + 8) +#define MAX_IMAGE_DIST 16777215 // (1 << 24 - 1) + + +//#define DEBUG_ENCODE + + +#define GLZ_ENCODE_SIZE +#include "glz-encode-match.c.template" +#define GLZ_ENCODE_MATCH +#include "glz-encode-match.c.template" + +#define LZ_PLT +#include "glz-encode.c.template" + +#define LZ_RGB16 +#include "glz-encode.c.template" + +#define LZ_RGB24 +#include "glz-encode.c.template" + +#define LZ_RGB32 +#include "glz-encode.c.template" + +#define LZ_RGB_ALPHA +#include "glz-encode.c.template" + + +int glz_encode(GlzEncoderContext *opaque_encoder, + LzImageType type, int width, int height, int top_down, + uint8_t *lines, unsigned int num_lines, int stride, + uint8_t *io_ptr, unsigned int num_io_bytes, + GlzUsrImageContext *usr_context, GlzEncDictImageContext **o_enc_dict_context) +{ + Encoder *encoder = (Encoder *)opaque_encoder; + WindowImage *dict_image; + uint8_t *io_ptr_end = io_ptr + num_io_bytes; + uint32_t win_head_image_dist; + + if (IS_IMAGE_TYPE_PLT[type]) { + if (stride > (width / PLT_PIXELS_PER_BYTE[type])) { + if (((width % PLT_PIXELS_PER_BYTE[type]) == 0) || ( + (stride - (width / PLT_PIXELS_PER_BYTE[type])) > 1)) { + encoder->usr->error(encoder->usr, "stride overflows (plt)\n"); + } + } + } else { + if (stride != width * RGB_BYTES_PER_PIXEL[type]) { + encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb)\n"); + } + } + + // assign the output buffer + if (!encoder_reset(encoder, io_ptr, io_ptr_end)) { + encoder->usr->error(encoder->usr, "lz encoder io reset failed\n"); + } + + // first read the list of the image segments into the dictionary window + dict_image = glz_dictionary_pre_encode(encoder->id, encoder->usr, + encoder->dict, type, width, height, stride, + lines, num_lines, usr_context, &win_head_image_dist); + *o_enc_dict_context = (GlzEncDictImageContext *)dict_image; + + encoder->cur_image.type = type; + encoder->cur_image.id = dict_image->id; + encoder->cur_image.first_win_seg = dict_image->first_seg; + + encode_32(encoder, LZ_MAGIC); + encode_32(encoder, LZ_VERSION); + if (top_down) { + encode(encoder, (type & LZ_IMAGE_TYPE_MASK) | (1 << LZ_IMAGE_TYPE_LOG)); + } else { + encode(encoder, (type & LZ_IMAGE_TYPE_MASK)); + } + + encode_32(encoder, width); + encode_32(encoder, height); + encode_32(encoder, stride); + encode_64(encoder, dict_image->id); + encode_32(encoder, win_head_image_dist); + + switch (encoder->cur_image.type) { + case LZ_IMAGE_TYPE_PLT1_BE: + case LZ_IMAGE_TYPE_PLT1_LE: + case LZ_IMAGE_TYPE_PLT4_BE: + case LZ_IMAGE_TYPE_PLT4_LE: + case LZ_IMAGE_TYPE_PLT8: + glz_plt_compress(encoder); + break; + case LZ_IMAGE_TYPE_RGB16: + glz_rgb16_compress(encoder); + break; + case LZ_IMAGE_TYPE_RGB24: + glz_rgb24_compress(encoder); + break; + case LZ_IMAGE_TYPE_RGB32: + glz_rgb32_compress(encoder); + break; + case LZ_IMAGE_TYPE_RGBA: + glz_rgb32_compress(encoder); + glz_rgb_alpha_compress(encoder); + break; + case LZ_IMAGE_TYPE_INVALID: + default: + encoder->usr->error(encoder->usr, "bad image type\n"); + } + + glz_dictionary_post_encode(encoder->id, encoder->usr, encoder->dict); + + // move all the used segments to the free ones + encoder->io.bytes_count -= (encoder->io.end - encoder->io.now); + + return encoder->io.bytes_count; +} |