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:
Corentin Chary 2011-02-04 09:06:01 +01:00 committed by Anthony Liguori
parent f8562e326b
commit 148954faca
9 changed files with 1541 additions and 1 deletions

View file

@ -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
View 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
View 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
View 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

View 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
View 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

View file

@ -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;
}

View file

@ -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;

View file

@ -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 */