Commit 148954fa authored by Corentin Chary's avatar Corentin Chary Committed by Anthony Liguori

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: default avatarCorentin Chary <corentincj@iksaif.net>
Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parent f8562e32
......@@ -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
......
/*
* 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
This diff is collapsed.
/*
* 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
/********************************************************************
* *
* 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
This diff is collapsed.
......@@ -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;
}
......
......@@ -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;
......
......@@ -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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment