summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.target1
-rwxr-xr-xconfigure37
-rw-r--r--ui/vnc-enc-tight.c316
-rw-r--r--ui/vnc-enc-tight.h16
-rw-r--r--ui/vnc.c11
-rw-r--r--ui/vnc.h15
6 files changed, 342 insertions, 54 deletions
diff --git a/Makefile.target b/Makefile.target
index cd97b83935..8a9c427b55 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -178,6 +178,7 @@ LIBS+=-lz
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
+QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
# xen backend driver support
obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
diff --git a/configure b/configure
index 33e98a4993..59e9385b70 100755
--- a/configure
+++ b/configure
@@ -269,6 +269,7 @@ vde=""
vnc_tls=""
vnc_sasl=""
vnc_jpeg=""
+vnc_png=""
xen=""
linux_aio=""
attr=""
@@ -580,6 +581,10 @@ for opt do
;;
--enable-vnc-jpeg) vnc_jpeg="yes"
;;
+ --disable-vnc-png) vnc_png="no"
+ ;;
+ --enable-vnc-png) vnc_png="yes"
+ ;;
--disable-slirp) slirp="no"
;;
--disable-uuid) uuid="no"
@@ -832,6 +837,8 @@ echo " --disable-vnc-sasl disable SASL encryption for VNC server"
echo " --enable-vnc-sasl enable SASL encryption for VNC server"
echo " --disable-vnc-jpeg disable JPEG lossy compression for VNC server"
echo " --enable-vnc-jpeg enable JPEG lossy compression for VNC server"
+echo " --disable-vnc-png disable PNG compression for VNC server"
+echo " --enable-vnc-png enable PNG compression for VNC server"
echo " --disable-curses disable curses output"
echo " --enable-curses enable curses output"
echo " --disable-curl disable curl connectivity"
@@ -1274,6 +1281,31 @@ EOF
fi
##########################################
+# VNC PNG detection
+if test "$vnc_png" = "yes" ; then
+cat > $TMPC <<EOF
+//#include <stdio.h>
+#include <png.h>
+int main(void) {
+ png_structp png_ptr;
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ return 0;
+}
+EOF
+ vnc_png_cflags=""
+ vnc_png_libs="-lpng"
+ if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then
+ vnc_png=yes
+ libs_softmmu="$vnc_png_libs $libs_softmmu"
+ else
+ if test "$vnc_png" = "yes" ; then
+ feature_not_found "vnc-png"
+ fi
+ vnc_png=no
+ fi
+fi
+
+##########################################
# fnmatch() probe, used for ACL routines
fnmatch="no"
cat > $TMPC << EOF
@@ -2123,6 +2155,7 @@ echo "Mixer emulation $mixemu"
echo "VNC TLS support $vnc_tls"
echo "VNC SASL support $vnc_sasl"
echo "VNC JPEG support $vnc_jpeg"
+echo "VNC PNG support $vnc_png"
if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
fi
@@ -2264,6 +2297,10 @@ if test "$vnc_jpeg" = "yes" ; then
echo "CONFIG_VNC_JPEG=y" >> $config_host_mak
echo "VNC_JPEG_CFLAGS=$vnc_jpeg_cflags" >> $config_host_mak
fi
+if test "$vnc_png" = "yes" ; then
+ echo "CONFIG_VNC_PNG=y" >> $config_host_mak
+ echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak
+fi
if test "$fnmatch" = "yes" ; then
echo "CONFIG_FNMATCH=y" >> $config_host_mak
fi
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 4ff88a8b03..cc57c26796 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -26,13 +26,18 @@
* THE SOFTWARE.
*/
-#include "qemu-common.h"
+#include "config-host.h"
+#ifdef CONFIG_VNC_PNG
+#include <png.h>
+#endif
#ifdef CONFIG_VNC_JPEG
#include <stdio.h>
#include <jpeglib.h>
#endif
+#include "qemu-common.h"
+
#include "bswap.h"
#include "qdict.h"
#include "qint.h"
@@ -63,6 +68,29 @@ static const struct {
{ 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 }
};
+
+static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+ int w, int h);
+
+#ifdef CONFIG_VNC_PNG
+static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+ QDict *palette);
+
+static bool tight_can_send_png_rect(VncState *vs, int w, int h)
+{
+ if (vs->tight_type != VNC_ENCODING_TIGHT_PNG) {
+ return false;
+ }
+
+ if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
+ vs->clientds.pf.bytes_per_pixel == 1) {
+ return false;
+ }
+
+ return true;
+}
+#endif
+
/*
* Code to guess if given rectangle is suitable for smooth image
* compression (by applying "gradient" filter or JPEG coder).
@@ -466,6 +494,7 @@ static void print_palette(const char *key, QObject *obj, void *opaque)
src = (uint##bpp##_t *) buf; \
\
for (i = 0; i < count; i++) { \
+ \
rgb = *src++; \
rep = 0; \
while (i < count && *src == rgb) { \
@@ -937,11 +966,17 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
}
}
-static int send_full_color_rect(VncState *vs, int w, int h)
+static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
{
int stream = 0;
size_t bytes;
+#ifdef CONFIG_VNC_PNG
+ if (tight_can_send_png_rect(vs, w, h)) {
+ return send_png_rect(vs, x, y, w, h, NULL);
+ }
+#endif
+
vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
if (vs->tight_pixel24) {
@@ -975,12 +1010,27 @@ static int send_solid_rect(VncState *vs)
return 1;
}
-static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg)
+static int send_mono_rect(VncState *vs, int x, int y,
+ int w, int h, uint32_t bg, uint32_t fg)
{
size_t bytes;
int stream = 1;
int level = tight_conf[vs->tight_compression].mono_zlib_level;
+#ifdef CONFIG_VNC_PNG
+ if (tight_can_send_png_rect(vs, w, h)) {
+ int ret;
+ QDict *palette = qdict_new();
+ int bpp = vs->clientds.pf.bytes_per_pixel * 8;
+
+ tight_palette_insert(palette, bg, bpp, 2);
+ tight_palette_insert(palette, fg, bpp, 2);
+ ret = send_png_rect(vs, x, y, w, h, palette);
+ QDECREF(palette);
+ return ret;
+ }
+#endif
+
bytes = ((w + 7) / 8) * h;
vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
@@ -1021,6 +1071,9 @@ static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg)
struct palette_cb_priv {
VncState *vs;
uint8_t *header;
+#ifdef CONFIG_VNC_PNG
+ png_colorp png_palette;
+#endif
};
static void write_palette(const char *key, QObject *obj, void *opaque)
@@ -1041,14 +1094,14 @@ static void write_palette(const char *key, QObject *obj, void *opaque)
}
}
-static bool send_gradient_rect(VncState *vs, int w, int h)
+static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
{
int stream = 3;
int level = tight_conf[vs->tight_compression].gradient_zlib_level;
size_t bytes;
if (vs->clientds.pf.bytes_per_pixel == 1)
- return send_full_color_rect(vs, w, h);
+ return send_full_color_rect(vs, x, y, w, h);
vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
@@ -1076,13 +1129,20 @@ static bool send_gradient_rect(VncState *vs, int w, int h)
return (bytes >= 0);
}
-static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
+static int send_palette_rect(VncState *vs, int x, int y,
+ int w, int h, struct QDict *palette)
{
int stream = 2;
int level = tight_conf[vs->tight_compression].idx_zlib_level;
int colors;
size_t bytes;
+#ifdef CONFIG_VNC_PNG
+ if (tight_can_send_png_rect(vs, w, h)) {
+ return send_png_rect(vs, x, y, w, h, palette);
+ }
+#endif
+
colors = qdict_size(palette);
vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
@@ -1130,12 +1190,9 @@ static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
return (bytes >= 0);
}
-/*
- * JPEG compression stuff.
- */
-#ifdef CONFIG_VNC_JPEG
-static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
- int count)
+#if defined(CONFIG_VNC_JPEG) || defined(CONFIG_VNC_PNG)
+static void rgb_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
+ int count)
{
VncDisplay *vd = vs->vd;
uint32_t *fbptr;
@@ -1152,11 +1209,11 @@ static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
}
}
-#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \
+#define DEFINE_RGB_GET_ROW_FUNCTION(bpp) \
\
static void \
- jpeg_prepare_row##bpp(VncState *vs, uint8_t *dst, \
- int x, int y, int count) \
+ rgb_prepare_row##bpp(VncState *vs, uint8_t *dst, \
+ int x, int y, int count) \
{ \
VncDisplay *vd = vs->vd; \
uint##bpp##_t *fbptr; \
@@ -1186,21 +1243,26 @@ static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
} \
}
-DEFINE_JPEG_GET_ROW_FUNCTION(16)
-DEFINE_JPEG_GET_ROW_FUNCTION(32)
+DEFINE_RGB_GET_ROW_FUNCTION(16)
+DEFINE_RGB_GET_ROW_FUNCTION(32)
-static void jpeg_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
- int count)
+static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
+ int count)
{
if (vs->tight_pixel24)
- jpeg_prepare_row24(vs, dst, x, y, count);
+ rgb_prepare_row24(vs, dst, x, y, count);
else if (ds_get_bytes_per_pixel(vs->ds) == 4)
- jpeg_prepare_row32(vs, dst, x, y, count);
+ rgb_prepare_row32(vs, dst, x, y, count);
else
- jpeg_prepare_row16(vs, dst, x, y, count);
+ rgb_prepare_row16(vs, dst, x, y, count);
}
+#endif /* CONFIG_VNC_JPEG or CONFIG_VNC_PNG */
/*
+ * JPEG compression stuff.
+ */
+#ifdef CONFIG_VNC_JPEG
+/*
* Destination manager implementation for JPEG library.
*/
@@ -1245,7 +1307,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
int dy;
if (ds_get_bytes_per_pixel(vs->ds) == 1)
- return send_full_color_rect(vs, w, h);
+ return send_full_color_rect(vs, x, y, w, h);
buffer_reserve(&vs->tight_jpeg, 2048);
@@ -1271,7 +1333,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
buf = qemu_malloc(w * 3);
row[0] = buf;
for (dy = 0; dy < h; dy++) {
- jpeg_prepare_row(vs, buf, x, y + dy, w);
+ rgb_prepare_row(vs, buf, x, y + dy, w);
jpeg_write_scanlines(&cinfo, row, 1);
}
qemu_free(buf);
@@ -1289,6 +1351,162 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
}
#endif /* CONFIG_VNC_JPEG */
+/*
+ * PNG compression stuff.
+ */
+#ifdef CONFIG_VNC_PNG
+static void write_png_palette(const char *key, QObject *obj, void *opaque)
+{
+ struct palette_cb_priv *priv = opaque;
+ VncState *vs = priv->vs;
+ uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
+ uint8_t idx = qint_get_int(qobject_to_qint(obj));
+ png_colorp color = &priv->png_palette[idx];
+ uint32_t pix;
+
+ if (bytes == 4) {
+ pix = tight_palette_buf2rgb(32, (uint8_t *)key);
+ } else {
+ pix = tight_palette_buf2rgb(16, (uint8_t *)key);
+ }
+
+ if (vs->tight_pixel24)
+ {
+ color->red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax;
+ color->green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax;
+ color->blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax;
+ }
+ else
+ {
+ int red, green, blue;
+
+ red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax;
+ green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax;
+ blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax;
+ color->red = ((red * 255 + vs->clientds.pf.rmax / 2) /
+ vs->clientds.pf.rmax);
+ color->green = ((green * 255 + vs->clientds.pf.gmax / 2) /
+ vs->clientds.pf.gmax);
+ color->blue = ((blue * 255 + vs->clientds.pf.bmax / 2) /
+ vs->clientds.pf.bmax);
+ }
+}
+
+static void png_write_data(png_structp png_ptr, png_bytep data,
+ png_size_t length)
+{
+ VncState *vs = png_get_io_ptr(png_ptr);
+
+ buffer_reserve(&vs->tight_png, vs->tight_png.offset + length);
+ memcpy(vs->tight_png.buffer + vs->tight_png.offset, data, length);
+
+ vs->tight_png.offset += length;
+}
+
+static void png_flush_data(png_structp png_ptr)
+{
+}
+
+static void *vnc_png_malloc(png_structp png_ptr, png_size_t size)
+{
+ return qemu_malloc(size);
+}
+
+static void vnc_png_free(png_structp png_ptr, png_voidp ptr)
+{
+ qemu_free(ptr);
+}
+
+static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+ QDict *palette)
+{
+ png_byte color_type;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_colorp png_palette = NULL;
+ size_t offset;
+ int level = tight_conf[vs->tight_compression].raw_zlib_level;
+ uint8_t *buf;
+ int dy;
+
+ png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
+ NULL, vnc_png_malloc, vnc_png_free);
+
+ if (png_ptr == NULL)
+ return -1;
+
+ info_ptr = png_create_info_struct(png_ptr);
+
+ if (info_ptr == NULL) {
+ png_destroy_write_struct(&png_ptr, NULL);
+ return -1;
+ }
+
+ png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data);
+ png_set_compression_level(png_ptr, level);
+
+ if (palette) {
+ color_type = PNG_COLOR_TYPE_PALETTE;
+ } else {
+ color_type = PNG_COLOR_TYPE_RGB;
+ }
+
+ png_set_IHDR(png_ptr, info_ptr, w, h,
+ 8, color_type, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
+ struct palette_cb_priv priv;
+
+ png_palette = png_malloc(png_ptr, sizeof(*png_palette) *
+ qdict_size(palette));
+
+ priv.vs = vs;
+ priv.png_palette = png_palette;
+ qdict_iter(palette, write_png_palette, &priv);
+
+ png_set_PLTE(png_ptr, info_ptr, png_palette, qdict_size(palette));
+
+ offset = vs->tight.offset;
+ if (vs->clientds.pf.bytes_per_pixel == 4) {
+ tight_encode_indexed_rect32(vs->tight.buffer, w * h, palette);
+ } else {
+ tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
+ }
+ }
+
+ png_write_info(png_ptr, info_ptr);
+
+ buffer_reserve(&vs->tight_png, 2048);
+ buf = qemu_malloc(w * 3);
+ for (dy = 0; dy < h; dy++)
+ {
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
+ memcpy(buf, vs->tight.buffer + (dy * w), w);
+ } else {
+ rgb_prepare_row(vs, buf, x, y + dy, w);
+ }
+ png_write_row(png_ptr, buf);
+ }
+ qemu_free(buf);
+
+ png_write_end(png_ptr, NULL);
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
+ png_free(png_ptr, png_palette);
+ }
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
+
+ tight_send_compact_size(vs, vs->tight_png.offset);
+ vnc_write(vs, vs->tight_png.buffer, vs->tight_png.offset);
+ buffer_reset(&vs->tight_png);
+ return 1;
+}
+#endif /* CONFIG_VNC_PNG */
+
static void vnc_tight_start(VncState *vs)
{
buffer_reset(&vs->tight);
@@ -1312,7 +1530,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
int colors;
int ret = 0;
- vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
+ vnc_framebuffer_update(vs, x, y, w, h, vs->tight_type);
vnc_tight_start(vs);
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
@@ -1323,23 +1541,23 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
if (colors == 0) {
if (tight_detect_smooth_image(vs, w, h)) {
if (vs->tight_quality == -1) {
- ret = send_gradient_rect(vs, w, h);
+ ret = send_gradient_rect(vs, x, y, w, h);
} else {
#ifdef CONFIG_VNC_JPEG
int quality = tight_conf[vs->tight_quality].jpeg_quality;
ret = send_jpeg_rect(vs, x, y, w, h, quality);
#else
- ret = send_full_color_rect(vs, w, h);
+ ret = send_full_color_rect(vs, x, y, w, h);
#endif
}
} else {
- ret = send_full_color_rect(vs, w, h);
+ ret = send_full_color_rect(vs, x, y, w, h);
}
} else if (colors == 1) {
ret = send_solid_rect(vs);
} else if (colors == 2) {
- ret = send_mono_rect(vs, w, h, bg, fg);
+ ret = send_mono_rect(vs, x, y, w, h, bg, fg);
} else if (colors <= 256) {
#ifdef CONFIG_VNC_JPEG
if (colors > 96 && vs->tight_quality != -1 && vs->tight_quality <= 3 &&
@@ -1348,10 +1566,10 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
ret = send_jpeg_rect(vs, x, y, w, h, quality);
} else {
- ret = send_palette_rect(vs, w, h, palette);
+ ret = send_palette_rect(vs, x, y, w, h, palette);
}
#else
- ret = send_palette_rect(vs, w, h, palette);
+ ret = send_palette_rect(vs, x, y, w, h, palette);
#endif
}
QDECREF(palette);
@@ -1360,7 +1578,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
{
- vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
+ vnc_framebuffer_update(vs, x, y, w, h, vs->tight_type);
vnc_tight_start(vs);
vnc_raw_send_framebuffer_update(vs, x, y, w, h);
@@ -1453,8 +1671,8 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
n += send_rect_simple(vs, x, y, w, y_best-y);
}
if (x_best != x) {
- n += vnc_tight_send_framebuffer_update(vs, x, y_best,
- x_best-x, h_best);
+ n += tight_send_framebuffer_update(vs, x, y_best,
+ x_best-x, h_best);
}
/* Send solid-color rectangle. */
@@ -1463,14 +1681,14 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
/* Send remaining rectangles (at right and bottom). */
if (x_best + w_best != x + w) {
- n += vnc_tight_send_framebuffer_update(vs, x_best+w_best,
- y_best,
- w-(x_best-x)-w_best,
- h_best);
+ n += tight_send_framebuffer_update(vs, x_best+w_best,
+ y_best,
+ w-(x_best-x)-w_best,
+ h_best);
}
if (y_best + h_best != y + h) {
- n += vnc_tight_send_framebuffer_update(vs, x, y_best+h_best,
- w, h-(y_best-y)-h_best);
+ n += tight_send_framebuffer_update(vs, x, y_best+h_best,
+ w, h-(y_best-y)-h_best);
}
/* Return after all recursive calls are done. */
@@ -1480,8 +1698,8 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
return n + send_rect_simple(vs, x, y, w, h);
}
-int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
- int w, int h)
+static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+ int w, int h)
{
int max_rows;
@@ -1503,6 +1721,20 @@ int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
}
+int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
+ int w, int h)
+{
+ vs->tight_type = VNC_ENCODING_TIGHT;
+ return tight_send_framebuffer_update(vs, x, y, w, h);
+}
+
+int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
+ int w, int h)
+{
+ vs->tight_type = VNC_ENCODING_TIGHT_PNG;
+ return tight_send_framebuffer_update(vs, x, y, w, h);
+}
+
void vnc_tight_clear(VncState *vs)
{
int i;
diff --git a/ui/vnc-enc-tight.h b/ui/vnc-enc-tight.h
index 9b0910c79a..a3add788e2 100644
--- a/ui/vnc-enc-tight.h
+++ b/ui/vnc-enc-tight.h
@@ -42,8 +42,9 @@
* bit 3: if 1, then compression stream 3 should be reset;
* bits 7-4: if 1000 (0x08), then the compression type is "fill",
* if 1001 (0x09), then the compression type is "jpeg",
+ * if 1010 (0x0A), then the compression type is "png",
* if 0xxx, then the compression type is "basic",
- * values greater than 1001 are not valid.
+ * values greater than 1010 are not valid.
*
* If the compression type is "basic", then bits 6..4 of the
* compression control byte (those xxx in 0xxx) specify the following:
@@ -53,17 +54,17 @@
* bit 6: if 1, then a "filter id" byte is following this byte.
*
*-- The data that follows after the compression control byte described
- * above depends on the compression type ("fill", "jpeg" or "basic").
+ * above depends on the compression type ("fill", "jpeg", "png" or "basic").
*
*-- If the compression type is "fill", then the only pixel value follows, in
* client pixel format (see NOTE 1). This value applies to all pixels of the
* rectangle.
*
- *-- If the compression type is "jpeg", the following data stream looks like
- * this:
+ *-- If the compression type is "jpeg" or "png", the following data stream
+ * looks like this:
*
* 1..3 bytes: data size (N) in compact representation;
- * N bytes: JPEG image.
+ * N bytes: JPEG or PNG image.
*
* Data size is compactly represented in one, two or three bytes, according
* to the following scheme:
@@ -144,7 +145,7 @@
*-- NOTE 2. The decoder must reset compression streams' states before
* decoding the rectangle, if some of bits 0,1,2,3 in the compression control
* byte are set to 1. Note that the decoder must reset zlib streams even if
- * the compression type is "fill" or "jpeg".
+ * the compression type is "fill", "jpeg" or "png".
*
*-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
* when bits-per-pixel value is either 16 or 32, not 8.
@@ -158,7 +159,8 @@
#define VNC_TIGHT_EXPLICIT_FILTER 0x04
#define VNC_TIGHT_FILL 0x08
#define VNC_TIGHT_JPEG 0x09
-#define VNC_TIGHT_MAX_SUBENCODING 0x09
+#define VNC_TIGHT_PNG 0x0A
+#define VNC_TIGHT_MAX_SUBENCODING 0x0A
/* Filters to improve compression efficiency */
#define VNC_TIGHT_FILTER_COPY 0x00
diff --git a/ui/vnc.c b/ui/vnc.c
index ccd7aad86b..1fc6d387d9 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -351,10 +351,6 @@ void do_info_vnc(Monitor *mon, QObject **ret_data)
}
}
-static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
- return (vs->features & (1 << feature));
-}
-
/* TODO
1) Get the queue working for IO.
2) there is some weirdness when using the -S option (the screen is grey
@@ -661,6 +657,9 @@ static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
case VNC_ENCODING_TIGHT:
n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
break;
+ case VNC_ENCODING_TIGHT_PNG:
+ n = vnc_tight_png_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);
@@ -1669,6 +1668,10 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
vs->features |= VNC_FEATURE_TIGHT_MASK;
vs->vnc_encoding = enc;
break;
+ case VNC_ENCODING_TIGHT_PNG:
+ vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
+ vs->vnc_encoding = enc;
+ break;
case VNC_ENCODING_ZLIB:
vs->features |= VNC_FEATURE_ZLIB_MASK;
vs->vnc_encoding = enc;
diff --git a/ui/vnc.h b/ui/vnc.h
index ec90cd389c..3b8b91122a 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -172,6 +172,7 @@ struct VncState
/* Encoding specific */
/* Tight */
+ int tight_type;
uint8_t tight_quality;
uint8_t tight_compression;
uint8_t tight_pixel24;
@@ -182,6 +183,9 @@ struct VncState
#ifdef CONFIG_VNC_JPEG
Buffer tight_jpeg;
#endif
+#ifdef CONFIG_VNC_PNG
+ Buffer tight_png;
+#endif
int tight_levels[4];
z_stream tight_stream[4];
@@ -259,6 +263,7 @@ enum {
#define VNC_ENCODING_POINTER_TYPE_CHANGE 0XFFFFFEFF /* -257 */
#define VNC_ENCODING_EXT_KEY_EVENT 0XFFFFFEFE /* -258 */
#define VNC_ENCODING_AUDIO 0XFFFFFEFD /* -259 */
+#define VNC_ENCODING_TIGHT_PNG 0xFFFFFEFC /* -260 */
#define VNC_ENCODING_WMVi 0x574D5669
/*****************************************************************************
@@ -275,6 +280,7 @@ enum {
#define VNC_TIGHT_CCB_TYPE_MASK (0x0f << 4)
#define VNC_TIGHT_CCB_TYPE_FILL (0x08 << 4)
#define VNC_TIGHT_CCB_TYPE_JPEG (0x09 << 4)
+#define VNC_TIGHT_CCB_TYPE_PNG (0x0A << 4)
#define VNC_TIGHT_CCB_BASIC_MAX (0x07 << 4)
#define VNC_TIGHT_CCB_BASIC_ZLIB (0x03 << 4)
#define VNC_TIGHT_CCB_BASIC_FILTER (0x04 << 4)
@@ -293,6 +299,7 @@ enum {
#define VNC_FEATURE_ZLIB 5
#define VNC_FEATURE_COPYRECT 6
#define VNC_FEATURE_RICH_CURSOR 7
+#define VNC_FEATURE_TIGHT_PNG 8
#define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
#define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE)
@@ -302,6 +309,7 @@ enum {
#define VNC_FEATURE_ZLIB_MASK (1 << VNC_FEATURE_ZLIB)
#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)
/* Client -> Server message IDs */
@@ -405,6 +413,10 @@ void buffer_append(Buffer *buffer, const void *data, size_t len);
char *vnc_socket_local_addr(const char *format, int fd);
char *vnc_socket_remote_addr(const char *format, int fd);
+static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
+ return (vs->features & (1 << feature));
+}
+
/* Framebuffer */
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
int32_t encoding);
@@ -423,8 +435,9 @@ void vnc_zlib_zfree(void *x, void *addr);
int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
void vnc_zlib_clear(VncState *vs);
-
int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
+ int w, int h);
void vnc_tight_clear(VncState *vs);
#endif /* __QEMU_VNC_H */