Browse Source
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>remotes/github/stable-0.15
committed by
Anthony Liguori
9 changed files with 1541 additions and 1 deletions
@ -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 |
|||
@ -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); |
|||
} |
|||
@ -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 |
|||
@ -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 |
|||
@ -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 |
|||
Loading…
Reference in new issue