vnc: Add ZRLE and ZYWRLE encodings.
Add ZRLE [1] and ZYWRLE [2] encodings. The code is inspire^W stolen from libvncserver (again), but have been rewriten to match QEMU coding style. [1] http://www.realvnc.com/docs/rfbproto.pdf [2] http://micro-vnc.jp/research/remote_desktop_ng/ZYWRLE/publications/ Signed-off-by: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
f8562e326b
commit
148954faca
@ -129,6 +129,7 @@ ui-obj-$(CONFIG_CURSES) += curses.o
|
||||
ui-obj-y += vnc.o d3des.o
|
||||
ui-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
|
||||
ui-obj-y += vnc-enc-tight.o vnc-palette.o
|
||||
ui-obj-y += vnc-enc-zrle.o
|
||||
ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
|
||||
ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
|
||||
ui-obj-$(CONFIG_COCOA) += cocoa.o
|
||||
|
263
ui/vnc-enc-zrle-template.c
Normal file
263
ui/vnc-enc-zrle-template.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
|
||||
*
|
||||
* From libvncserver/libvncserver/zrleencodetemplate.c
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Before including this file, you must define a number of CPP macros.
|
||||
*
|
||||
* ZRLE_BPP should be 8, 16 or 32 depending on the bits per pixel.
|
||||
*
|
||||
* Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
|
||||
* bigger than the largest tile of pixel data, since the ZRLE encoding
|
||||
* algorithm writes to the position one past the end of the pixel data.
|
||||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#undef ZRLE_ENDIAN_SUFFIX
|
||||
|
||||
#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
|
||||
#define ZRLE_ENDIAN_SUFFIX le
|
||||
#elif ZYWRLE_ENDIAN == ENDIAN_BIG
|
||||
#define ZRLE_ENDIAN_SUFFIX be
|
||||
#else
|
||||
#define ZRLE_ENDIAN_SUFFIX ne
|
||||
#endif
|
||||
|
||||
#ifndef ZRLE_CONCAT
|
||||
#define ZRLE_CONCAT_I(a, b) a##b
|
||||
#define ZRLE_CONCAT2(a, b) ZRLE_CONCAT_I(a, b)
|
||||
#define ZRLE_CONCAT3(a, b, c) ZRLE_CONCAT2(a, ZRLE_CONCAT2(b, c))
|
||||
#endif
|
||||
|
||||
#ifdef ZRLE_COMPACT_PIXEL
|
||||
#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_COMPACT_PIXEL,ZRLE_ENDIAN_SUFFIX)
|
||||
#define ZRLE_WRITE_SUFFIX ZRLE_COMPACT_PIXEL
|
||||
#define ZRLE_PIXEL ZRLE_CONCAT3(uint,ZRLE_BPP,_t)
|
||||
#define ZRLE_BPP_OUT 24
|
||||
#elif ZRLE_BPP == 15
|
||||
#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
|
||||
#define ZRLE_WRITE_SUFFIX 16
|
||||
#define ZRLE_PIXEL uint16_t
|
||||
#define ZRLE_BPP_OUT 16
|
||||
#else
|
||||
#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
|
||||
#define ZRLE_WRITE_SUFFIX ZRLE_BPP
|
||||
#define ZRLE_BPP_OUT ZRLE_BPP
|
||||
#define ZRLE_PIXEL ZRLE_CONCAT3(uint,ZRLE_BPP,_t)
|
||||
#endif
|
||||
|
||||
#define ZRLE_WRITE_PIXEL ZRLE_CONCAT2(zrle_write_u, ZRLE_WRITE_SUFFIX)
|
||||
#define ZRLE_ENCODE ZRLE_CONCAT2(zrle_encode_, ZRLE_ENCODE_SUFFIX)
|
||||
#define ZRLE_ENCODE_TILE ZRLE_CONCAT2(zrle_encode_tile, ZRLE_ENCODE_SUFFIX)
|
||||
#define ZRLE_WRITE_PALETTE ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX)
|
||||
|
||||
static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
|
||||
int zywrle_level);
|
||||
|
||||
#if ZRLE_BPP != 8
|
||||
#include "vnc-enc-zywrle-template.c"
|
||||
#endif
|
||||
|
||||
|
||||
static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h,
|
||||
int zywrle_level)
|
||||
{
|
||||
int ty;
|
||||
|
||||
for (ty = y; ty < y + h; ty += VNC_ZRLE_TILE_HEIGHT) {
|
||||
|
||||
int tx, th;
|
||||
|
||||
th = MIN(VNC_ZRLE_TILE_HEIGHT, y + h - ty);
|
||||
|
||||
for (tx = x; tx < x + w; tx += VNC_ZRLE_TILE_WIDTH) {
|
||||
int tw;
|
||||
ZRLE_PIXEL *buf;
|
||||
|
||||
tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx);
|
||||
|
||||
buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP);
|
||||
ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h,
|
||||
int zywrle_level)
|
||||
{
|
||||
VncPalette *palette = &vs->zrle.palette;
|
||||
|
||||
int runs = 0;
|
||||
int single_pixels = 0;
|
||||
|
||||
bool use_rle;
|
||||
bool use_palette;
|
||||
|
||||
int i;
|
||||
|
||||
ZRLE_PIXEL *ptr = data;
|
||||
ZRLE_PIXEL *end = ptr + h * w;
|
||||
*end = ~*(end-1); /* one past the end is different so the while loop ends */
|
||||
|
||||
/* Real limit is 127 but we wan't a way to know if there is more than 127 */
|
||||
palette_init(palette, 256, ZRLE_BPP);
|
||||
|
||||
while (ptr < end) {
|
||||
ZRLE_PIXEL pix = *ptr;
|
||||
if (*++ptr != pix) { /* FIXME */
|
||||
single_pixels++;
|
||||
} else {
|
||||
while (*++ptr == pix) ;
|
||||
runs++;
|
||||
}
|
||||
palette_put(palette, pix);
|
||||
}
|
||||
|
||||
/* Solid tile is a special case */
|
||||
|
||||
if (palette_size(palette) == 1) {
|
||||
bool found;
|
||||
|
||||
vnc_write_u8(vs, 1);
|
||||
ZRLE_WRITE_PIXEL(vs, palette_color(palette, 0, &found));
|
||||
return;
|
||||
}
|
||||
|
||||
zrle_choose_palette_rle(vs, w, h, palette, ZRLE_BPP_OUT,
|
||||
runs, single_pixels, zywrle_level,
|
||||
&use_rle, &use_palette);
|
||||
|
||||
if (!use_palette) {
|
||||
vnc_write_u8(vs, (use_rle ? 128 : 0));
|
||||
} else {
|
||||
uint32_t colors[VNC_PALETTE_MAX_SIZE];
|
||||
size_t size = palette_size(palette);
|
||||
|
||||
vnc_write_u8(vs, (use_rle ? 128 : 0) | size);
|
||||
palette_fill(palette, colors);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
ZRLE_WRITE_PIXEL(vs, colors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (use_rle) {
|
||||
ZRLE_PIXEL *ptr = data;
|
||||
ZRLE_PIXEL *end = ptr + w * h;
|
||||
ZRLE_PIXEL *run_start;
|
||||
ZRLE_PIXEL pix;
|
||||
|
||||
while (ptr < end) {
|
||||
int len;
|
||||
int index = 0;
|
||||
|
||||
run_start = ptr;
|
||||
pix = *ptr++;
|
||||
|
||||
while (*ptr == pix && ptr < end) {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
len = ptr - run_start;
|
||||
|
||||
if (use_palette)
|
||||
index = palette_idx(palette, pix);
|
||||
|
||||
if (len <= 2 && use_palette) {
|
||||
if (len == 2) {
|
||||
vnc_write_u8(vs, index);
|
||||
}
|
||||
vnc_write_u8(vs, index);
|
||||
continue;
|
||||
}
|
||||
if (use_palette) {
|
||||
vnc_write_u8(vs, index | 128);
|
||||
} else {
|
||||
ZRLE_WRITE_PIXEL(vs, pix);
|
||||
}
|
||||
|
||||
len -= 1;
|
||||
|
||||
while (len >= 255) {
|
||||
vnc_write_u8(vs, 255);
|
||||
len -= 255;
|
||||
}
|
||||
|
||||
vnc_write_u8(vs, len);
|
||||
}
|
||||
} else if (use_palette) { /* no RLE */
|
||||
int bppp;
|
||||
ZRLE_PIXEL *ptr = data;
|
||||
|
||||
/* packed pixels */
|
||||
|
||||
assert (palette_size(palette) < 17);
|
||||
|
||||
bppp = bits_per_packed_pixel[palette_size(palette)-1];
|
||||
|
||||
for (i = 0; i < h; i++) {
|
||||
uint8_t nbits = 0;
|
||||
uint8_t byte = 0;
|
||||
|
||||
ZRLE_PIXEL *eol = ptr + w;
|
||||
|
||||
while (ptr < eol) {
|
||||
ZRLE_PIXEL pix = *ptr++;
|
||||
uint8_t index = palette_idx(palette, pix);
|
||||
|
||||
byte = (byte << bppp) | index;
|
||||
nbits += bppp;
|
||||
if (nbits >= 8) {
|
||||
vnc_write_u8(vs, byte);
|
||||
nbits = 0;
|
||||
}
|
||||
}
|
||||
if (nbits > 0) {
|
||||
byte <<= 8 - nbits;
|
||||
vnc_write_u8(vs, byte);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
/* raw */
|
||||
|
||||
#if ZRLE_BPP != 8
|
||||
if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
|
||||
ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf);
|
||||
ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef ZRLE_COMPACT_PIXEL
|
||||
ZRLE_PIXEL *ptr;
|
||||
|
||||
for (ptr = data; ptr < data + w * h; ptr++) {
|
||||
ZRLE_WRITE_PIXEL(vs, *ptr);
|
||||
}
|
||||
#else
|
||||
vnc_write(vs, data, w * h * (ZRLE_BPP / 8));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef ZRLE_PIXEL
|
||||
#undef ZRLE_WRITE_PIXEL
|
||||
#undef ZRLE_ENCODE
|
||||
#undef ZRLE_ENCODE_TILE
|
||||
#undef ZYWRLE_ENCODE_TILE
|
||||
#undef ZRLE_BPP_OUT
|
||||
#undef ZRLE_WRITE_SUFFIX
|
||||
#undef ZRLE_ENCODE_SUFFIX
|
365
ui/vnc-enc-zrle.c
Normal file
365
ui/vnc-enc-zrle.c
Normal file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
* QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
|
||||
*
|
||||
* From libvncserver/libvncserver/zrle.c
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vnc.h"
|
||||
#include "vnc-enc-zrle.h"
|
||||
|
||||
static const int bits_per_packed_pixel[] = {
|
||||
0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
||||
};
|
||||
|
||||
|
||||
static void vnc_zrle_start(VncState *vs)
|
||||
{
|
||||
buffer_reset(&vs->zrle.zrle);
|
||||
|
||||
/* make the output buffer be the zlib buffer, so we can compress it later */
|
||||
vs->zrle.tmp = vs->output;
|
||||
vs->output = vs->zrle.zrle;
|
||||
}
|
||||
|
||||
static void vnc_zrle_stop(VncState *vs)
|
||||
{
|
||||
/* switch back to normal output/zlib buffers */
|
||||
vs->zrle.zrle = vs->output;
|
||||
vs->output = vs->zrle.tmp;
|
||||
}
|
||||
|
||||
static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h,
|
||||
int bpp)
|
||||
{
|
||||
Buffer tmp;
|
||||
|
||||
buffer_reset(&vs->zrle.fb);
|
||||
buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp);
|
||||
|
||||
tmp = vs->output;
|
||||
vs->output = vs->zrle.fb;
|
||||
|
||||
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
|
||||
|
||||
vs->zrle.fb = vs->output;
|
||||
vs->output = tmp;
|
||||
return vs->zrle.fb.buffer;
|
||||
}
|
||||
|
||||
static int zrle_compress_data(VncState *vs, int level)
|
||||
{
|
||||
z_streamp zstream = &vs->zrle.stream;
|
||||
|
||||
buffer_reset(&vs->zrle.zlib);
|
||||
|
||||
if (zstream->opaque != vs) {
|
||||
int err;
|
||||
|
||||
zstream->zalloc = vnc_zlib_zalloc;
|
||||
zstream->zfree = vnc_zlib_zfree;
|
||||
|
||||
err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS,
|
||||
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
|
||||
|
||||
if (err != Z_OK) {
|
||||
fprintf(stderr, "VNC: error initializing zlib\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
zstream->opaque = vs;
|
||||
}
|
||||
|
||||
/* reserve memory in output buffer */
|
||||
buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64);
|
||||
|
||||
/* set pointers */
|
||||
zstream->next_in = vs->zrle.zrle.buffer;
|
||||
zstream->avail_in = vs->zrle.zrle.offset;
|
||||
zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset;
|
||||
zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset;
|
||||
zstream->data_type = Z_BINARY;
|
||||
|
||||
/* start encoding */
|
||||
if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
|
||||
fprintf(stderr, "VNC: error during zrle compression\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out;
|
||||
return vs->zrle.zlib.offset;
|
||||
}
|
||||
|
||||
/* Try to work out whether to use RLE and/or a palette. We do this by
|
||||
* estimating the number of bytes which will be generated and picking the
|
||||
* method which results in the fewest bytes. Of course this may not result
|
||||
* in the fewest bytes after compression... */
|
||||
static void zrle_choose_palette_rle(VncState *vs, int w, int h,
|
||||
VncPalette *palette, int bpp_out,
|
||||
int runs, int single_pixels,
|
||||
int zywrle_level,
|
||||
bool *use_rle, bool *use_palette)
|
||||
{
|
||||
size_t estimated_bytes;
|
||||
size_t plain_rle_bytes;
|
||||
|
||||
*use_palette = *use_rle = false;
|
||||
|
||||
estimated_bytes = w * h * (bpp_out / 8); /* start assuming raw */
|
||||
|
||||
if (bpp_out != 8) {
|
||||
if (zywrle_level > 0 && !(zywrle_level & 0x80))
|
||||
estimated_bytes >>= zywrle_level;
|
||||
}
|
||||
|
||||
plain_rle_bytes = ((bpp_out / 8) + 1) * (runs + single_pixels);
|
||||
|
||||
if (plain_rle_bytes < estimated_bytes) {
|
||||
*use_rle = true;
|
||||
estimated_bytes = plain_rle_bytes;
|
||||
}
|
||||
|
||||
if (palette_size(palette) < 128) {
|
||||
int palette_rle_bytes;
|
||||
|
||||
palette_rle_bytes = (bpp_out / 8) * palette_size(palette);
|
||||
palette_rle_bytes += 2 * runs + single_pixels;
|
||||
|
||||
if (palette_rle_bytes < estimated_bytes) {
|
||||
*use_rle = true;
|
||||
*use_palette = true;
|
||||
estimated_bytes = palette_rle_bytes;
|
||||
}
|
||||
|
||||
if (palette_size(palette) < 17) {
|
||||
int packed_bytes;
|
||||
|
||||
packed_bytes = (bpp_out / 8) * palette_size(palette);
|
||||
packed_bytes += w * h *
|
||||
bits_per_packed_pixel[palette_size(palette)-1] / 8;
|
||||
|
||||
if (packed_bytes < estimated_bytes) {
|
||||
*use_rle = false;
|
||||
*use_palette = true;
|
||||
estimated_bytes = packed_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void zrle_write_u32(VncState *vs, uint32_t value)
|
||||
{
|
||||
vnc_write(vs, (uint8_t *)&value, 4);
|
||||
}
|
||||
|
||||
static void zrle_write_u24a(VncState *vs, uint32_t value)
|
||||
{
|
||||
vnc_write(vs, (uint8_t *)&value, 3);
|
||||
}
|
||||
|
||||
static void zrle_write_u24b(VncState *vs, uint32_t value)
|
||||
{
|
||||
vnc_write(vs, ((uint8_t *)&value) + 1, 3);
|
||||
}
|
||||
|
||||
static void zrle_write_u16(VncState *vs, uint16_t value)
|
||||
{
|
||||
vnc_write(vs, (uint8_t *)&value, 2);
|
||||
}
|
||||
|
||||
static void zrle_write_u8(VncState *vs, uint8_t value)
|
||||
{
|
||||
vnc_write_u8(vs, value);
|
||||
}
|
||||
|
||||
#define ENDIAN_LITTLE 0
|
||||
#define ENDIAN_BIG 1
|
||||
#define ENDIAN_NO 2
|
||||
|
||||
#define ZRLE_BPP 8
|
||||
#define ZYWRLE_ENDIAN ENDIAN_NO
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
#undef ZRLE_BPP
|
||||
|
||||
#define ZRLE_BPP 15
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#undef ZRLE_BPP
|
||||
#define ZRLE_BPP 16
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#undef ZRLE_BPP
|
||||
#define ZRLE_BPP 32
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#define ZRLE_COMPACT_PIXEL 24a
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#undef ZRLE_COMPACT_PIXEL
|
||||
#define ZRLE_COMPACT_PIXEL 24b
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_LITTLE
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
|
||||
#undef ZYWRLE_ENDIAN
|
||||
#define ZYWRLE_ENDIAN ENDIAN_BIG
|
||||
#include "vnc-enc-zrle-template.c"
|
||||
#undef ZRLE_COMPACT_PIXEL
|
||||
#undef ZRLE_BPP
|
||||
|
||||
static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
|
||||
int w, int h)
|
||||
{
|
||||
bool be = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
|
||||
size_t bytes;
|
||||
int zywrle_level;
|
||||
|
||||
if (vs->zrle.type == VNC_ENCODING_ZYWRLE) {
|
||||
if (!vs->vd->lossy || vs->tight.quality < 0 || vs->tight.quality == 9) {
|
||||
zywrle_level = 0;
|
||||
vs->zrle.type = VNC_ENCODING_ZRLE;
|
||||
} else if (vs->tight.quality < 3) {
|
||||
zywrle_level = 3;
|
||||
} else if (vs->tight.quality < 6) {
|
||||
zywrle_level = 2;
|
||||
} else {
|
||||
zywrle_level = 1;
|
||||
}
|
||||
} else {
|
||||
zywrle_level = 0;
|
||||
}
|
||||
|
||||
vnc_zrle_start(vs);
|
||||
|
||||
switch(vs->clientds.pf.bytes_per_pixel) {
|
||||
case 1:
|
||||
zrle_encode_8ne(vs, x, y, w, h, zywrle_level);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (vs->clientds.pf.gmax > 0x1F) {
|
||||
if (be) {
|
||||
zrle_encode_16be(vs, x, y, w, h, zywrle_level);
|
||||
} else {
|
||||
zrle_encode_16le(vs, x, y, w, h, zywrle_level);
|
||||
}
|
||||
} else {
|
||||
if (be) {
|
||||
zrle_encode_15be(vs, x, y, w, h, zywrle_level);
|
||||
} else {
|
||||
zrle_encode_15le(vs, x, y, w, h, zywrle_level);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
bool fits_in_ls3bytes;
|
||||
bool fits_in_ms3bytes;
|
||||
|
||||
fits_in_ls3bytes =
|
||||
((vs->clientds.pf.rmax << vs->clientds.pf.rshift) < (1 << 24) &&
|
||||
(vs->clientds.pf.gmax << vs->clientds.pf.gshift) < (1 << 24) &&
|
||||
(vs->clientds.pf.bmax << vs->clientds.pf.bshift) < (1 << 24));
|
||||
|
||||
fits_in_ms3bytes = (vs->clientds.pf.rshift > 7 &&
|
||||
vs->clientds.pf.gshift > 7 &&
|
||||
vs->clientds.pf.bshift > 7);
|
||||
|
||||
if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) {
|
||||
if (be) {
|
||||
zrle_encode_24abe(vs, x, y, w, h, zywrle_level);
|
||||
} else {
|
||||
zrle_encode_24ale(vs, x, y, w, h, zywrle_level);
|
||||
}
|
||||
} else if ((fits_in_ls3bytes && be) || (fits_in_ms3bytes && !be)) {
|
||||
if (be) {
|
||||
zrle_encode_24bbe(vs, x, y, w, h, zywrle_level);
|
||||
} else {
|
||||
zrle_encode_24ble(vs, x, y, w, h, zywrle_level);
|
||||
}
|
||||
} else {
|
||||
if (be) {
|
||||
zrle_encode_32be(vs, x, y, w, h, zywrle_level);
|
||||
} else {
|
||||
zrle_encode_32le(vs, x, y, w, h, zywrle_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
vnc_zrle_stop(vs);
|
||||
bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION);
|
||||
vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type);
|
||||
vnc_write_u32(vs, bytes);
|
||||
vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
|
||||
{
|
||||
vs->zrle.type = VNC_ENCODING_ZRLE;
|
||||
return zrle_send_framebuffer_update(vs, x, y, w, h);
|
||||
}
|
||||
|
||||
int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
|
||||
{
|
||||
vs->zrle.type = VNC_ENCODING_ZYWRLE;
|
||||
return zrle_send_framebuffer_update(vs, x, y, w, h);
|
||||
}
|
||||
|
||||
void vnc_zrle_clear(VncState *vs)
|
||||
{
|
||||
if (vs->zrle.stream.opaque) {
|
||||
deflateEnd(&vs->zrle.stream);
|
||||
}
|
||||
buffer_free(&vs->zrle.zrle);
|
||||
buffer_free(&vs->zrle.fb);
|
||||
buffer_free(&vs->zrle.zlib);
|
||||
}
|
40
ui/vnc-enc-zrle.h
Normal file
40
ui/vnc-enc-zrle.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
|
||||
*
|
||||
* From libvncserver/libvncserver/zrle.c
|
||||
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
||||
* Copyright (C) 2003 Sun Microsystems, Inc.
|
||||
*
|
||||
* Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef VNC_ENCODING_ZRLE_H
|
||||
#define VNC_ENCODING_ZRLE_H
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* ZRLE - encoding combining Zlib compression, tiling, palettisation and
|
||||
* run-length encoding.
|
||||
*/
|
||||
|
||||
#define VNC_ZRLE_TILE_WIDTH 64
|
||||
#define VNC_ZRLE_TILE_HEIGHT 64
|
||||
|
||||
#endif
|
170
ui/vnc-enc-zywrle-template.c
Normal file
170
ui/vnc-enc-zywrle-template.c
Normal file
@ -0,0 +1,170 @@
|
||||
|
||||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE. *
|
||||
* *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE. *
|
||||
* PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006 *
|
||||
* BY Hitachi Systems & Services, Ltd. *
|
||||
* (Noriaki Yamazaki, Research & Developement Center) *
|
||||
* *
|
||||
* *
|
||||
********************************************************************
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Hitachi Systems & Services, Ltd. nor
|
||||
the names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
********************************************************************/
|
||||
|
||||
/* Change Log:
|
||||
V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline
|
||||
(Thanks Johannes Schindelin, author of LibVNC
|
||||
Server/Client)
|
||||
V0.01 : 2007/02/06 : Initial release
|
||||
*/
|
||||
|
||||
/*
|
||||
[References]
|
||||
PLHarr:
|
||||
Senecal, J. G., P. Lindstrom, M. A. Duchaineau, and K. I. Joy,
|
||||
"An Improved N-Bit to N-Bit Reversible Haar-Like Transform,"
|
||||
Pacific Graphics 2004, October 2004, pp. 371-380.
|
||||
EZW:
|
||||
Shapiro, JM: Embedded Image Coding Using Zerotrees of Wavelet Coefficients,
|
||||
IEEE Trans. Signal. Process., Vol.41, pp.3445-3462 (1993).
|
||||
*/
|
||||
|
||||
|
||||
/* Template Macro stuffs. */
|
||||
#undef ZYWRLE_ANALYZE
|
||||
#undef ZYWRLE_SYNTHESIZE
|
||||
|
||||
#define ZYWRLE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
|
||||
|
||||
#define ZYWRLE_ANALYZE ZRLE_CONCAT2(zywrle_analyze_, ZYWRLE_SUFFIX)
|
||||
#define ZYWRLE_SYNTHESIZE ZRLE_CONCAT2(zywrle_synthesize_,ZYWRLE_SUFFIX)
|
||||
|
||||
#define ZYWRLE_RGBYUV ZRLE_CONCAT2(zywrle_rgbyuv_, ZYWRLE_SUFFIX)
|
||||
#define ZYWRLE_YUVRGB ZRLE_CONCAT2(zywrle_yuvrgb_, ZYWRLE_SUFFIX)
|
||||
#define ZYWRLE_YMASK ZRLE_CONCAT2(ZYWRLE_YMASK, ZRLE_BPP)
|
||||
#define ZYWRLE_UVMASK ZRLE_CONCAT2(ZYWRLE_UVMASK, ZRLE_BPP)
|
||||
#define ZYWRLE_LOAD_PIXEL ZRLE_CONCAT2(ZYWRLE_LOAD_PIXEL, ZRLE_BPP)
|
||||
#define ZYWRLE_SAVE_PIXEL ZRLE_CONCAT2(ZYWRLE_SAVE_PIXEL, ZRLE_BPP)
|
||||
|
||||
/* Packing/Unpacking pixel stuffs.
|
||||
Endian conversion stuffs. */
|
||||
#undef S_0
|
||||
#undef S_1
|
||||
#undef L_0
|
||||
#undef L_1
|
||||
#undef L_2
|
||||
|
||||
#if ZYWRLE_ENDIAN == ENDIAN_BIG
|
||||
# define S_0 1
|
||||
# define S_1 0
|
||||
# define L_0 3
|
||||
# define L_1 2
|
||||
# define L_2 1
|
||||
#else
|
||||
# define S_0 0
|
||||
# define S_1 1
|
||||
# define L_0 0
|
||||
# define L_1 1
|
||||
# define L_2 2
|
||||
#endif
|
||||
|
||||
#define ZYWRLE_QUANTIZE
|
||||
#include "vnc-enc-zywrle.h"
|
||||
|
||||
#ifndef ZRLE_COMPACT_PIXEL
|
||||
static inline void ZYWRLE_RGBYUV(int *buf, ZRLE_PIXEL *data,
|
||||
int width, int height, int scanline)
|
||||
{
|
||||
int r, g, b;
|
||||
int y, u, v;
|
||||
int *line;
|
||||
int *end;
|
||||
|
||||
end = buf + height * width;
|
||||
while (buf < end) {
|
||||
line = buf + width;
|
||||
while (buf < line) {
|
||||
ZYWRLE_LOAD_PIXEL(data, r, g, b);
|
||||
ZYWRLE_RGBYUV_(r, g, b, y, u, v, ZYWRLE_YMASK, ZYWRLE_UVMASK);
|
||||
ZYWRLE_SAVE_COEFF(buf, v, y, u);
|
||||
buf++;
|
||||
data++;
|
||||
}
|
||||
data += scanline - width;
|
||||
}
|
||||
}
|
||||
|
||||
static ZRLE_PIXEL *ZYWRLE_ANALYZE(ZRLE_PIXEL *dst, ZRLE_PIXEL *src,
|
||||
int w, int h, int scanline, int level,
|
||||
int *buf) {
|
||||
int l;
|
||||
int uw = w;
|
||||
int uh = h;
|
||||
int *top;
|
||||
int *end;
|
||||
int *line;
|
||||
ZRLE_PIXEL *p;
|
||||
int r, g, b;
|
||||
int s;
|
||||
int *ph;
|
||||
|
||||
zywrle_calc_size(&w, &h, level);
|
||||
|
||||
if (w == 0 || h == 0) {
|
||||
return NULL;
|
||||
}
|
||||
uw -= w;
|
||||
uh -= h;
|
||||
|
||||
p = dst;
|
||||
ZYWRLE_LOAD_UNALIGN(src,*(ZRLE_PIXEL*)top = *p;);
|
||||
ZYWRLE_RGBYUV(buf, src, w, h, scanline);
|
||||
wavelet(buf, w, h, level);
|
||||
for (l = 0; l < level; l++) {
|
||||
ZYWRLE_PACK_COEFF(buf, dst, 3, w, h, scanline, l);
|
||||
ZYWRLE_PACK_COEFF(buf, dst, 2, w, h, scanline, l);
|
||||
ZYWRLE_PACK_COEFF(buf, dst, 1, w, h, scanline, l);
|
||||
if (l == level - 1) {
|
||||
ZYWRLE_PACK_COEFF(buf, dst, 0, w, h, scanline, l);
|
||||
}
|
||||
}
|
||||
ZYWRLE_SAVE_UNALIGN(dst,*dst = *(ZRLE_PIXEL*)top;);
|
||||
return dst;
|
||||
}
|
||||
#endif /* ZRLE_COMPACT_PIXEL */
|
||||
|
||||
#undef ZYWRLE_RGBYUV
|
||||
#undef ZYWRLE_YUVRGB
|
||||
#undef ZYWRLE_LOAD_PIXEL
|
||||
#undef ZYWRLE_SAVE_PIXEL
|
659
ui/vnc-enc-zywrle.h
Normal file
659
ui/vnc-enc-zywrle.h
Normal file
@ -0,0 +1,659 @@
|
||||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE. *
|
||||
* *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE. *
|
||||
* PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006 *
|
||||
* BY Hitachi Systems & Services, Ltd. *
|
||||
* (Noriaki Yamazaki, Research & Developement Center) *
|
||||
* *
|
||||
* *
|
||||
********************************************************************
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Hitachi Systems & Services, Ltd. nor
|
||||
the names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef VNC_ENCODING_ZYWRLE_H
|
||||
#define VNC_ENCODING_ZYWRLE_H
|
||||
|
||||
/* Tables for Coefficients filtering. */
|
||||
#ifndef ZYWRLE_QUANTIZE
|
||||
/* Type A:lower bit omitting of EZW style. */
|
||||
static const unsigned int zywrle_param[3][3]={
|
||||
{0x0000F000, 0x00000000, 0x00000000},
|
||||
{0x0000C000, 0x00F0F0F0, 0x00000000},
|
||||
{0x0000C000, 0x00C0C0C0, 0x00F0F0F0},
|
||||
/* {0x0000FF00, 0x00000000, 0x00000000},
|
||||
{0x0000FF00, 0x00FFFFFF, 0x00000000},
|
||||
{0x0000FF00, 0x00FFFFFF, 0x00FFFFFF}, */
|
||||
};
|
||||
#else
|
||||
/* Type B:Non liner quantization filter. */
|
||||
static const int8_t zywrle_conv[4][256]={
|
||||
{ /* bi=5, bo=5 r=0.0:PSNR=24.849 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
{ /* bi=5, bo=5 r=2.0:PSNR=74.031 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32,
|
||||
48, 48, 48, 48, 48, 48, 48, 48,
|
||||
48, 48, 48, 56, 56, 56, 56, 56,
|
||||
56, 56, 56, 56, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 72, 72, 72, 72,
|
||||
72, 72, 72, 72, 80, 80, 80, 80,
|
||||
80, 80, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 96, 96,
|
||||
96, 96, 96, 104, 104, 104, 104, 104,
|
||||
104, 104, 104, 104, 104, 112, 112, 112,
|
||||
112, 112, 112, 112, 112, 112, 120, 120,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
0, -120, -120, -120, -120, -120, -120, -120,
|
||||
-120, -120, -120, -112, -112, -112, -112, -112,
|
||||
-112, -112, -112, -112, -104, -104, -104, -104,
|
||||
-104, -104, -104, -104, -104, -104, -96, -96,
|
||||
-96, -96, -96, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -80,
|
||||
-80, -80, -80, -80, -80, -72, -72, -72,
|
||||
-72, -72, -72, -72, -72, -64, -64, -64,
|
||||
-64, -64, -64, -64, -64, -56, -56, -56,
|
||||
-56, -56, -56, -56, -56, -56, -48, -48,
|
||||
-48, -48, -48, -48, -48, -48, -48, -48,
|
||||
-48, -32, -32, -32, -32, -32, -32, -32,
|
||||
-32, -32, -32, -32, -32, -32, -32, -32,
|
||||
-32, -32, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
{ /* bi=5, bo=4 r=2.0:PSNR=64.441 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
48, 48, 48, 48, 48, 48, 48, 48,
|
||||
48, 48, 48, 48, 48, 48, 48, 48,
|
||||
48, 48, 48, 48, 48, 48, 48, 48,
|
||||
64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64,
|
||||
80, 80, 80, 80, 80, 80, 80, 80,
|
||||
80, 80, 80, 80, 80, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
104, 104, 104, 104, 104, 104, 104, 104,
|
||||
104, 104, 104, 112, 112, 112, 112, 112,
|
||||
112, 112, 112, 112, 120, 120, 120, 120,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
0, -120, -120, -120, -120, -120, -120, -120,
|
||||
-120, -120, -120, -120, -120, -112, -112, -112,
|
||||
-112, -112, -112, -112, -112, -112, -104, -104,
|
||||
-104, -104, -104, -104, -104, -104, -104, -104,
|
||||
-104, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -80, -80, -80, -80,
|
||||
-80, -80, -80, -80, -80, -80, -80, -80,
|
||||
-80, -64, -64, -64, -64, -64, -64, -64,
|
||||
-64, -64, -64, -64, -64, -64, -64, -64,
|
||||
-64, -48, -48, -48, -48, -48, -48, -48,
|
||||
-48, -48, -48, -48, -48, -48, -48, -48,
|
||||
-48, -48, -48, -48, -48, -48, -48, -48,
|
||||
-48, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
},
|
||||
{ /* bi=5, bo=2 r=2.0:PSNR=43.175 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
88, 88, 88, 88, 88, 88, 88, 88,
|
||||
0, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, -88, -88, -88, -88, -88, -88, -88,
|
||||
-88, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
}
|
||||
};
|
||||
|
||||
static const int8_t *zywrle_param[3][3][3]={
|
||||
{{zywrle_conv[0], zywrle_conv[2], zywrle_conv[0]},
|
||||
{zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]},
|
||||
{zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}},
|
||||
{{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]},
|
||||
{zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]},
|
||||
{zywrle_conv[0], zywrle_conv[0], zywrle_conv[0]}},
|
||||
{{zywrle_conv[0], zywrle_conv[3], zywrle_conv[0]},
|
||||
{zywrle_conv[2], zywrle_conv[2], zywrle_conv[2]},
|
||||
{zywrle_conv[1], zywrle_conv[1], zywrle_conv[1]}},
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Load/Save pixel stuffs. */
|
||||
#define ZYWRLE_YMASK15 0xFFFFFFF8
|
||||
#define ZYWRLE_UVMASK15 0xFFFFFFF8
|
||||
#define ZYWRLE_LOAD_PIXEL15(src, r, g, b) \
|
||||
do { \
|
||||
r = (((uint8_t*)src)[S_1]<< 1)& 0xF8; \
|
||||
g = (((uint8_t*)src)[S_1]<< 6) | (((uint8_t*)src)[S_0]>> 2); \
|
||||
g &= 0xF8; \
|
||||
b = (((uint8_t*)src)[S_0]<< 3)& 0xF8; \
|
||||
} while (0)
|
||||
|
||||
#define ZYWRLE_SAVE_PIXEL15(dst, r, g, b) \
|
||||
do { \
|
||||
r &= 0xF8; \
|
||||
g &= 0xF8; \
|
||||
b &= 0xF8; \
|
||||
((uint8_t*)dst)[S_1] = (uint8_t)((r >> 1)|(g >> 6)); \
|
||||
((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 2))& 0xFF); \
|
||||
} while (0)
|
||||
|
||||
#define ZYWRLE_YMASK16 0xFFFFFFFC
|
||||
#define ZYWRLE_UVMASK16 0xFFFFFFF8
|
||||
#define ZYWRLE_LOAD_PIXEL16(src, r, g, b) \
|
||||
do { \
|
||||
r = ((uint8_t*)src)[S_1] & 0xF8; \
|
||||
g = (((uint8_t*)src)[S_1]<< 5) | (((uint8_t*)src)[S_0] >> 3); \
|
||||
g &= 0xFC; \
|
||||
b = (((uint8_t*)src)[S_0]<< 3) & 0xF8; \
|
||||
} while (0)
|
||||
|
||||
#define ZYWRLE_SAVE_PIXEL16(dst, r, g,b) \
|
||||
do { \
|
||||
r &= 0xF8; \
|
||||
g &= 0xFC; \
|
||||
b &= 0xF8; \
|
||||
((uint8_t*)dst)[S_1] = (uint8_t)(r | (g >> 5)); \
|
||||
((uint8_t*)dst)[S_0] = (uint8_t)(((b >> 3)|(g << 3)) & 0xFF); \
|
||||
} while (0)
|
||||
|
||||
#define ZYWRLE_YMASK32 0xFFFFFFFF
|
||||
#define ZYWRLE_UVMASK32 0xFFFFFFFF
|
||||
#define ZYWRLE_LOAD_PIXEL32(src, r, g, b) \
|
||||
do { \
|
||||
r = ((uint8_t*)src)[L_2]; \
|
||||
g = ((uint8_t*)src)[L_1]; \
|
||||
b = ((uint8_t*)src)[L_0]; \
|
||||
} while (0)
|
||||
#define ZYWRLE_SAVE_PIXEL32(dst, r, g, b) \
|
||||
do { \
|
||||
((uint8_t*)dst)[L_2] = (uint8_t)r; \
|
||||
((uint8_t*)dst)[L_1] = (uint8_t)g; \
|
||||
((uint8_t*)dst)[L_0] = (uint8_t)b; \
|
||||
} while (0)
|
||||
|
||||
static inline void harr(int8_t *px0, int8_t *px1)
|
||||
{
|
||||
/* Piecewise-Linear Harr(PLHarr) */
|
||||
int x0 = (int)*px0, x1 = (int)*px1;
|
||||
int orgx0 = x0, orgx1 = x1;
|
||||
|
||||
if ((x0 ^ x1) & 0x80) {
|
||||
/* differ sign */
|
||||
x1 += x0;
|
||||
if (((x1 ^ orgx1) & 0x80) == 0) {
|
||||
/* |x1| > |x0| */
|
||||
x0 -= x1; /* H = -B */
|
||||
}
|
||||
} else {
|
||||
/* same sign */
|
||||
x0 -= x1;
|
||||
if (((x0 ^ orgx0) & 0x80) == 0) {
|
||||
/* |x0| > |x1| */
|
||||
x1 += x0; /* L = A */
|
||||
}
|
||||
}
|
||||
*px0 = (int8_t)x1;
|
||||
*px1 = (int8_t)x0;
|
||||
}
|
||||
|
||||
/*
|
||||
1D-Wavelet transform.
|
||||
|
||||
In coefficients array, the famous 'pyramid' decomposition is well used.
|
||||
|
||||
1D Model:
|
||||
|L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0
|
||||
|L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1
|
||||
|
||||
But this method needs line buffer because H/L is different position from X0/X1.
|
||||
So, I used 'interleave' decomposition instead of it.
|
||||
|
||||
1D Model:
|
||||
|L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0
|
||||
|L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1
|
||||
|
||||
In this method, H/L and X0/X1 is always same position.
|
||||
This lead us to more speed and less memory.
|
||||
Of cause, the result of both method is quite same
|
||||
because it's only difference that coefficient position.
|
||||
*/
|
||||
static inline void wavelet_level(int *data, int size, int l, int skip_pixel)
|
||||
{
|
||||
int s, ofs;
|
||||
int8_t *px0;
|
||||
int8_t *end;
|
||||
|
||||
px0 = (int8_t*)data;
|
||||
s = (8 << l) * skip_pixel;
|
||||
end = px0 + (size >> (l + 1)) * s;
|
||||
s -= 2;
|
||||
ofs = (4 << l) * skip_pixel;
|
||||
|
||||
while (px0 < end) {
|
||||
harr(px0, px0 + ofs);
|
||||
px0++;
|
||||
harr(px0, px0 + ofs);
|
||||
px0++;
|
||||
harr(px0, px0 + ofs);
|
||||
px0 += s;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ZYWRLE_QUANTIZE
|
||||
/* Type A:lower bit omitting of EZW style. */
|
||||
static inline void filter_wavelet_square(int *buf, int width, int height,
|
||||
int level, int l)
|
||||
{
|
||||
int r, s;
|
||||
int x, y;
|
||||
int *h;
|
||||
const unsigned int *m;
|
||||
|
||||
m = &(zywrle_param[level - 1][l]);
|
||||
s = 2 << l;
|
||||
|
||||
for (r = 1; r < 4; r++) {
|
||||
h = buf;
|
||||
if (r & 0x01) {
|
||||
h += s >> 1;
|
||||
}
|
||||
if (r & 0x02) {
|
||||
h += (s >> 1) * width;
|
||||
}
|
||||
for (y = 0; y < height / s; y++) {
|
||||
for (x = 0; x < width / s; x++) {
|
||||
/*
|
||||
these are same following code.
|
||||
h[x] = h[x] / (~m[x]+1) * (~m[x]+1);
|
||||
( round h[x] with m[x] bit )
|
||||
'&' operator isn't 'round' but is 'floor'.
|
||||
So, we must offset when h[x] is negative.
|
||||
*/
|
||||
if (((int8_t*)h)[0] & 0x80) {
|
||||
((int8_t*)h)[0] += ~((int8_t*)m)[0];
|
||||
}
|
||||
if (((int8_t*)h)[1] & 0x80) {
|
||||
((int8_t*)h)[1] += ~((int8_t*)m)[1];
|
||||
}
|
||||
if (((int8_t*)h)[2] & 0x80) {
|
||||
((int8_t*)h)[2] += ~((int8_t*)m)[2];
|
||||
}
|
||||
*h &= *m;
|
||||
h += s;
|
||||
}
|
||||
h += (s-1)*width;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/*
|
||||
Type B:Non liner quantization filter.
|
||||
|
||||
Coefficients have Gaussian curve and smaller value which is
|
||||
large part of coefficients isn't more important than larger value.
|
||||
So, I use filter of Non liner quantize/dequantize table.
|
||||
In general, Non liner quantize formula is explained as following.
|
||||
|
||||
y=f(x) = sign(x)*round( ((abs(x)/(2^7))^ r )* 2^(bo-1) )*2^(8-bo)
|
||||
x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi)
|
||||
( r:power coefficient bi:effective MSB in input bo:effective MSB in output )
|
||||
|
||||
r < 1.0 : Smaller value is more important than larger value.
|
||||
r > 1.0 : Larger value is more important than smaller value.
|
||||
r = 1.0 : Liner quantization which is same with EZW style.
|
||||
|
||||
r = 0.75 is famous non liner quantization used in MP3 audio codec.
|
||||
In contrast to audio data, larger value is important in wavelet coefficients.
|
||||
So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ).
|
||||
|
||||
As compared with EZW style liner quantization, this filter tended to be
|
||||
more sharp edge and be more compression rate but be more blocking noise and be
|
||||
less quality. Especially, the surface of graphic objects has distinguishable
|
||||
noise in middle quality mode.
|
||||
|
||||
We need only quantized-dequantized(filtered) value rather than quantized value
|
||||
itself because all values are packed or palette-lized in later ZRLE section.
|
||||
This lead us not to need to modify client decoder when we change
|
||||
the filtering procedure in future.
|
||||
Client only decodes coefficients given by encoder.
|
||||
*/
|
||||
static inline void filter_wavelet_square(int *buf, int width, int height,
|
||||
int level, int l)
|
||||
{
|
||||
int r, s;
|
||||
int x, y;
|
||||
int *h;
|
||||
const int8_t **m;
|
||||
|
||||
m = zywrle_param[level - 1][l];
|
||||
s = 2 << l;
|
||||
|
||||
for (r = 1; r < 4; r++) {
|
||||
h = buf;
|
||||
if (r & 0x01) {
|
||||
h += s >> 1;
|
||||
}
|
||||
if (r & 0x02) {
|
||||
h += (s >> 1) * width;
|
||||
}
|
||||
for (y = 0; y < height / s; y++) {
|
||||
for (x = 0; x < width / s; x++) {
|
||||
((int8_t*)h)[0] = m[0][((uint8_t*)h)[0]];
|
||||
((int8_t*)h)[1] = m[1][((uint8_t*)h)[1]];
|
||||
((int8_t*)h)[2] = m[2][((uint8_t*)h)[2]];
|
||||
h += s;
|
||||
}
|
||||
h += (s - 1) * width;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void wavelet(int *buf, int width, int height, int level)
|
||||
{
|
||||
int l, s;
|
||||
int *top;
|
||||
int *end;
|
||||
|
||||
for (l = 0; l < level; l++) {
|
||||
top = buf;
|
||||
end = buf + height * width;
|
||||
s = width << l;
|
||||
while (top < end) {
|
||||
wavelet_level(top, width, l, 1);
|
||||
top += s;
|
||||
}
|
||||
top = buf;
|
||||
end = buf + width;
|
||||
s = 1<<l;
|
||||
while (top < end) {
|
||||
wavelet_level(top, height, l, width);
|
||||
top += s;
|
||||
}
|
||||
filter_wavelet_square(buf, width, height, level, l);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Load/Save coefficients stuffs.
|
||||
Coefficients manages as 24 bits little-endian pixel. */
|
||||
#define ZYWRLE_LOAD_COEFF(src, r, g, b) \
|
||||
do { \
|
||||
r = ((int8_t*)src)[2]; \
|
||||
g = ((int8_t*)src)[1]; \
|
||||
b = ((int8_t*)src)[0]; \
|
||||
} while (0)
|
||||
|
||||
#define ZYWRLE_SAVE_COEFF(dst, r, g, b) \
|
||||
do { \
|
||||
((int8_t*)dst)[2] = (int8_t)r; \
|
||||
((int8_t*)dst)[1] = (int8_t)g; \
|
||||
((int8_t*)dst)[0] = (int8_t)b; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
RGB <=> YUV conversion stuffs.
|
||||
YUV coversion is explained as following formula in strict meaning:
|
||||
Y = 0.299R + 0.587G + 0.114B ( 0<=Y<=255)
|
||||
U = -0.169R - 0.331G + 0.500B (-128<=U<=127)
|
||||
V = 0.500R - 0.419G - 0.081B (-128<=V<=127)
|
||||
|
||||
I use simple conversion RCT(reversible color transform) which is described
|
||||
in JPEG-2000 specification.
|
||||
Y = (R + 2G + B)/4 ( 0<=Y<=255)
|
||||
U = B-G (-256<=U<=255)
|
||||
V = R-G (-256<=V<=255)
|
||||
*/
|
||||
|
||||
/* RCT is N-bit RGB to N-bit Y and N+1-bit UV.
|
||||
For make Same N-bit, UV is lossy.
|
||||
More exact PLHarr, we reduce to odd range(-127<=x<=127). */
|
||||
#define ZYWRLE_RGBYUV_(r, g, b, y, u, v, ymask, uvmask) \
|
||||
do { \
|
||||
y = (r + (g << 1) + b) >> 2; \
|
||||
u = b - g; \
|
||||
v = r - g; \
|
||||
y -= 128; \
|
||||
u >>= 1; \
|
||||
v >>= 1; \
|
||||
y &= ymask; \
|
||||
u &= uvmask; \
|
||||
v &= uvmask; \
|
||||
if (y == -128) { \
|
||||
y += (0xFFFFFFFF - ymask + 1); \
|
||||
} \
|
||||
if (u == -128) { \
|
||||
u += (0xFFFFFFFF - uvmask + 1); \
|
||||
} \
|
||||
if (v == -128) { \
|
||||
v += (0xFFFFFFFF - uvmask + 1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
coefficient packing/unpacking stuffs.
|
||||
Wavelet transform makes 4 sub coefficient image from 1 original image.
|
||||
|
||||
model with pyramid decomposition:
|
||||
+------+------+
|
||||
| | |
|
||||
| L | Hx |
|
||||
| | |
|
||||
+------+------+
|
||||
| | |
|
||||
| H | Hxy |
|
||||
| | |
|
||||
+------+------+
|
||||
|
||||
So, we must transfer each sub images individually in strict meaning.
|
||||
But at least ZRLE meaning, following one decompositon image is same as
|
||||
avobe individual sub image. I use this format.
|
||||
(Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L)
|
||||
for simplified procedure for any wavelet level.)
|
||||
|
||||
+------+------+
|
||||
| L |
|
||||
+------+------+
|
||||
| Hx |
|
||||
+------+------+
|
||||
| Hy |
|
||||
+------+------+
|
||||
| Hxy |
|
||||
+------+------+
|
||||
*/
|
||||
#define ZYWRLE_INC_PTR(data) \
|
||||
do { \
|
||||
data++; \
|
||||
if( data - p >= (w + uw) ) { \
|
||||
data += scanline-(w + uw); \
|
||||
p = data; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ZYWRLE_TRANSFER_COEFF(buf, data, t, w, h, scanline, level, TRANS) \
|
||||
do { \
|
||||
ph = buf; \
|
||||
s = 2 << level; \
|
||||
if (t & 0x01) { \
|
||||
ph += s >> 1; \
|
||||
} \
|
||||
if (t & 0x02) { \
|
||||
ph += (s >> 1) * w; \
|
||||
} \
|
||||
end = ph + h * w; \
|
||||
while (ph < end) { \
|
||||
line = ph + w; \
|
||||
while (ph < line) { \
|
||||
TRANS \
|
||||
ZYWRLE_INC_PTR(data); \
|
||||
ph += s; \
|
||||
} \
|
||||
ph += (s - 1) * w; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ZYWRLE_PACK_COEFF(buf, data, t, width, height, scanline, level) \
|
||||
ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \
|
||||
ZYWRLE_LOAD_COEFF(ph, r, g, b); \
|
||||
ZYWRLE_SAVE_PIXEL(data, r, g, b);)
|
||||
|
||||
#define ZYWRLE_UNPACK_COEFF(buf, data, t, width, height, scanline, level) \
|
||||
ZYWRLE_TRANSFER_COEFF(buf, data, t, width, height, scanline, level, \
|
||||
ZYWRLE_LOAD_PIXEL(data, r, g, b); \
|
||||
ZYWRLE_SAVE_COEFF(ph, r, g, b);)
|
||||
|
||||
#define ZYWRLE_SAVE_UNALIGN(data, TRANS) \
|
||||
do { \
|
||||
top = buf + w * h; \
|
||||
end = buf + (w + uw) * (h + uh); \
|
||||
while (top < end) { \
|
||||
TRANS \
|
||||
ZYWRLE_INC_PTR(data); \
|
||||
top++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ZYWRLE_LOAD_UNALIGN(data,TRANS) \
|
||||
do { \
|
||||
top = buf + w * h; \
|
||||
if (uw) { \
|
||||
p = data + w; \
|
||||
end = (int*)(p + h * scanline); \
|
||||
while (p < (ZRLE_PIXEL*)end) { \
|
||||
line = (int*)(p + uw); \
|
||||
while (p < (ZRLE_PIXEL*)line) { \
|
||||
TRANS \
|
||||
p++; \
|
||||
top++; \
|
||||
} \
|
||||
p += scanline - uw; \
|
||||
} \
|
||||
} \
|
||||
if (uh) { \
|
||||
p = data + h * scanline; \
|
||||
end = (int*)(p + uh * scanline); \
|
||||
while (p < (ZRLE_PIXEL*)end) { \
|
||||
line = (int*)(p + w); \
|
||||
while (p < (ZRLE_PIXEL*)line) { \
|
||||
TRANS \
|
||||
p++; \
|
||||
top++; \
|
||||
} \
|
||||
p += scanline - w; \
|
||||
} \
|
||||
} \
|
||||
if (uw && uh) { \
|
||||
p= data + w + h * scanline; \
|
||||
end = (int*)(p + uh * scanline); \
|
||||
while (p < (ZRLE_PIXEL*)end) { \
|
||||
line = (int*)(p + uw); \
|
||||
while (p < (ZRLE_PIXEL*)line) { \
|
||||
TRANS \
|
||||
p++; \
|
||||
top++; \
|
||||
} \
|
||||
p += scanline-uw; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline void zywrle_calc_size(int *w, int *h, int level)
|
||||
{
|
||||
*w &= ~((1 << level) - 1);
|
||||
*h &= ~((1 << level) - 1);
|
||||
}
|
||||
|
||||
#endif
|
@ -172,6 +172,7 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
|
||||
local->tight = orig->tight;
|
||||
local->zlib = orig->zlib;
|
||||
local->hextile = orig->hextile;
|
||||
local->zrle = orig->zrle;
|
||||
local->output = queue->buffer;
|
||||
local->csock = -1; /* Don't do any network work on this thread */
|
||||
|
||||
@ -183,6 +184,7 @@ static void vnc_async_encoding_end(VncState *orig, VncState *local)
|
||||
orig->tight = local->tight;
|
||||
orig->zlib = local->zlib;
|
||||
orig->hextile = local->hextile;
|
||||
orig->zrle = local->zrle;
|
||||
orig->lossy_rect = local->lossy_rect;
|
||||
}
|
||||
|
||||
|
15
ui/vnc.c
15
ui/vnc.c
@ -696,6 +696,12 @@ int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
|
||||
case VNC_ENCODING_TIGHT_PNG:
|
||||
n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
|
||||
break;
|
||||
case VNC_ENCODING_ZRLE:
|
||||
n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
|
||||
break;
|
||||
case VNC_ENCODING_ZYWRLE:
|
||||
n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
|
||||
break;
|
||||
default:
|
||||
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
|
||||
n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
|
||||
@ -1028,6 +1034,7 @@ static void vnc_disconnect_finish(VncState *vs)
|
||||
|
||||
vnc_zlib_clear(vs);
|
||||
vnc_tight_clear(vs);
|
||||
vnc_zrle_clear(vs);
|
||||
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
vnc_tls_client_cleanup(vs);
|
||||
@ -1766,6 +1773,14 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
|
||||
vs->features |= VNC_FEATURE_ZLIB_MASK;
|
||||
vs->vnc_encoding = enc;
|
||||
break;
|
||||
case VNC_ENCODING_ZRLE:
|
||||
vs->features |= VNC_FEATURE_ZRLE_MASK;
|
||||
vs->vnc_encoding = enc;
|
||||
break;
|
||||
case VNC_ENCODING_ZYWRLE:
|
||||
vs->features |= VNC_FEATURE_ZYWRLE_MASK;
|
||||
vs->vnc_encoding = enc;
|
||||
break;
|
||||
case VNC_ENCODING_DESKTOPRESIZE:
|
||||
vs->features |= VNC_FEATURE_RESIZE_MASK;
|
||||
break;
|
||||
|
27
ui/vnc.h
27
ui/vnc.h
@ -39,6 +39,8 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "keymaps.h"
|
||||
#include "vnc-palette.h"
|
||||
#include "vnc-enc-zrle.h"
|
||||
|
||||
// #define _VNC_DEBUG 1
|
||||
|
||||
@ -180,6 +182,20 @@ typedef struct VncZlib {
|
||||
int level;
|
||||
} VncZlib;
|
||||
|
||||
typedef struct VncZrle {
|
||||
int type;
|
||||
Buffer fb;
|
||||
Buffer zrle;
|
||||
Buffer tmp;
|
||||
Buffer zlib;
|
||||
z_stream stream;
|
||||
VncPalette palette;
|
||||
} VncZrle;
|
||||
|
||||
typedef struct VncZywrle {
|
||||
int buf[VNC_ZRLE_TILE_WIDTH * VNC_ZRLE_TILE_HEIGHT];
|
||||
} VncZywrle;
|
||||
|
||||
#ifdef CONFIG_VNC_THREAD
|
||||
struct VncRect
|
||||
{
|
||||
@ -273,7 +289,8 @@ struct VncState
|
||||
VncTight tight;
|
||||
VncZlib zlib;
|
||||
VncHextile hextile;
|
||||
|
||||
VncZrle zrle;
|
||||
VncZywrle zywrle;
|
||||
|
||||
Notifier mouse_mode_notifier;
|
||||
|
||||
@ -377,6 +394,8 @@ enum {
|
||||
#define VNC_FEATURE_COPYRECT 6
|
||||
#define VNC_FEATURE_RICH_CURSOR 7
|
||||
#define VNC_FEATURE_TIGHT_PNG 8
|
||||
#define VNC_FEATURE_ZRLE 9
|
||||
#define VNC_FEATURE_ZYWRLE 10
|
||||
|
||||
#define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
|
||||
#define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE)
|
||||
@ -387,6 +406,8 @@ enum {
|
||||
#define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT)
|
||||
#define VNC_FEATURE_RICH_CURSOR_MASK (1 << VNC_FEATURE_RICH_CURSOR)
|
||||
#define VNC_FEATURE_TIGHT_PNG_MASK (1 << VNC_FEATURE_TIGHT_PNG)
|
||||
#define VNC_FEATURE_ZRLE_MASK (1 << VNC_FEATURE_ZRLE)
|
||||
#define VNC_FEATURE_ZYWRLE_MASK (1 << VNC_FEATURE_ZYWRLE)
|
||||
|
||||
|
||||
/* Client -> Server message IDs */
|
||||
@ -521,4 +542,8 @@ int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
|
||||
int w, int h);
|
||||
void vnc_tight_clear(VncState *vs);
|
||||
|
||||
int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
|
||||
int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
|
||||
void vnc_zrle_clear(VncState *vs);
|
||||
|
||||
#endif /* __QEMU_VNC_H */
|
||||
|
Loading…
Reference in New Issue
Block a user