[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 7/7] Add tight encoding (jpeg) to vnc.c
From: |
Alexander Graf |
Subject: |
[Qemu-devel] [PATCH 7/7] Add tight encoding (jpeg) to vnc.c |
Date: |
Thu, 29 Jan 2009 12:24:58 +0100 |
Because we can now speak the tight protocol, let's use it to
transmit jpeg data to the client!
This patch adds a really easy implementation of the jpeg tight
encoding. Tight in general can do a lot more, but let's take small
steps here and see how things perform.
Signed-off-by: Alexander Graf <address@hidden>
---
Makefile.target | 4 +
configure | 25 ++++++++
vnc.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 207 insertions(+), 0 deletions(-)
diff --git a/Makefile.target b/Makefile.target
index a091ce9..7b54748 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -554,6 +554,10 @@ CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
LIBS += $(CONFIG_VNC_TLS_LIBS)
endif
+ifdef CONFIG_VNC_JPEG
+LIBS += $(CONFIG_VNC_JPEG_LIBS)
+endif
+
ifdef CONFIG_BLUEZ
LIBS += $(CONFIG_BLUEZ_LIBS)
endif
diff --git a/configure b/configure
index c3fbbbe..44e2e0b 100755
--- a/configure
+++ b/configure
@@ -164,6 +164,7 @@ fmod_lib=""
fmod_inc=""
oss_lib=""
vnc_tls="yes"
+vnc_jpeg="yes"
bsd="no"
linux="no"
solaris="no"
@@ -387,6 +388,8 @@ for opt do
;;
--disable-vnc-tls) vnc_tls="no"
;;
+ --disable-jpeg) vnc_jpeg="no"
+ ;;
--disable-slirp) slirp="no"
;;
--disable-vde) vde="no"
@@ -544,6 +547,7 @@ echo " Available cards:
$audio_possible_cards"
echo " --enable-mixemu enable mixer emulation"
echo " --disable-brlapi disable BrlAPI"
echo " --disable-vnc-tls disable TLS encryption for VNC server"
+echo " --disable-jpeg disable JPEG compression for VNC server"
echo " --disable-curses disable curses output"
echo " --disable-bluez disable bluez stack connectivity"
echo " --disable-kvm disable KVM acceleration support"
@@ -823,6 +827,21 @@ EOF
fi
##########################################
+# VNC JPEG detection
+if test "$vnc_jpeg" = "yes" ; then
+cat > $TMPC <<EOF
+#include <jpeglib.h>
+int main(void) { jpeg_compress_struct s; jpeg_create_compress(&s); return 0; }
+EOF
+ vnc_jpeg_libs="-ljpeg"
+ if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC $vnc_jpeg_libs > /dev/null
2> /dev/null ; then
+ :
+ else
+ vnc_tls="no"
+ fi
+fi
+
+##########################################
# vde libraries probe
if test "$vde" = "yes" ; then
cat > $TMPC << EOF
@@ -1130,6 +1149,7 @@ if test "$vnc_tls" = "yes" ; then
echo " TLS CFLAGS $vnc_tls_cflags"
echo " TLS LIBS $vnc_tls_libs"
fi
+echo "VNC JPEG support $vnc_jpeg"
if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
fi
@@ -1371,6 +1391,11 @@ if test "$vnc_tls" = "yes" ; then
echo "CONFIG_VNC_TLS_LIBS=$vnc_tls_libs" >> $config_mak
echo "#define CONFIG_VNC_TLS 1" >> $config_h
fi
+if test "$vnc_jpeg" = "yes" ; then
+ echo "CONFIG_VNC_JPEG=yes" >> $config_mak
+ echo "CONFIG_VNC_JPEG_LIBS=$vnc_jpeg_libs" >> $config_mak
+ echo "#define CONFIG_VNC_JPEG 1" >> $config_h
+fi
qemu_version=`head $source_path/VERSION`
echo "VERSION=$qemu_version" >>$config_mak
echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
diff --git a/vnc.c b/vnc.c
index 86e2a1b..7a7ec94 100644
--- a/vnc.c
+++ b/vnc.c
@@ -37,6 +37,10 @@
#include "keymaps.c"
#include "d3des.h"
+#ifdef CONFIG_VNC_JPEG
+#include <jpeglib.h>
+#endif /* CONFIG_VNC_JPEG */
+
#ifdef CONFIG_VNC_TLS
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
@@ -144,6 +148,11 @@ struct VncState
size_t read_handler_expect;
/* input */
uint8_t modifiers_state[256];
+
+#ifdef CONFIG_VNC_JPEG
+ Buffer jpeg_buffer;
+ struct jpeg_destination_mgr jpeg_dst_manager;
+#endif /* CONFIG_VNC_JPEG */
};
static VncState *vnc_state; /* needed for info vnc */
@@ -185,6 +194,8 @@ static void vnc_flush(VncState *vs);
static void vnc_update_client(void *opaque);
static void vnc_client_read(void *opaque);
static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len);
+static void buffer_reserve(Buffer *buffer, size_t len);
+static void buffer_reset(Buffer *buffer);
static void vnc_colordepth(DisplayState *ds);
@@ -453,9 +464,172 @@ static void send_framebuffer_update_hextile(VncState *vs,
int x, int y, int w, i
}
+#ifdef CONFIG_VNC_JPEG
+/* This is called once per encoding */
+static void jpeg_init_destination(j_compress_ptr cinfo)
+{
+ VncState *vs = (VncState*)cinfo->client_data;
+ Buffer *buffer = &vs->jpeg_buffer;
+
+ cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
+ cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
+}
+
+/* This is called when we ran out of buffer (shouldn't happen!) */
+static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
+{
+ VncState *vs = (VncState*)cinfo->client_data;
+ Buffer *buffer = &vs->jpeg_buffer;
+
+ buffer->offset = buffer->capacity;
+ buffer_reserve(buffer, 2048);
+ jpeg_init_destination(cinfo);
+ return TRUE;
+}
+
+/* This is called when we are done processing data */
+static void jpeg_term_destination(j_compress_ptr cinfo)
+{
+ VncState *vs = (VncState*)cinfo->client_data;
+ Buffer *buffer = &vs->jpeg_buffer;
+
+ buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
+}
+
+
+static void vnc_send_compact_size(VncState *vs, int len)
+{
+ char buf[3];
+ int lpc = 0;
+ int bytes = 0;
+
+ /* Adapted from SendCompressedData() in
Xvnc/programs/Xserver/hw/vnc/tight.c */
+ buf[bytes++] = len & 0x7F;
+ if (len > 0x7F) {
+ buf[bytes-1] |= 0x80;
+ buf[bytes++] = len >> 7 & 0x7F;
+ if (len > 0x3FFF) {
+ buf[bytes-1] |= 0x80;
+ buf[bytes++] = len >> 14 & 0xFF;
+ }
+ }
+
+ for(lpc = 0; lpc < bytes; lpc++) {
+ vnc_write_u8(vs, buf[lpc]);
+ }
+}
+
+static int32_t read_s32(uint8_t *data, size_t offset);
+static void jpeg_row2pixel(VncState *vs, char *in, char *out, int len)
+{
+ char *pi = in;
+ char *po = out;
+ int depth = vs->serverds.pf.bytes_per_pixel;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ uint32_t v;
+ uint8_t r, g, b;
+ switch (depth) {
+ case 1:
+ po[0] = pi[0];
+ po[1] = pi[0];
+ po[2] = pi[0];
+ continue;
+ break;
+ case 2:
+ v = *((uint16_t*)pi);
+ break;
+ case 4:
+ v = *((uint32_t*)pi);
+ break;
+ }
+ r = ((((v & vs->serverds.pf.rmask) >> vs->serverds.pf.rshift)
+ << vs->clientds.pf.rbits) >> vs->serverds.pf.rbits);
+ g = ((((v & vs->serverds.pf.gmask) >> vs->serverds.pf.gshift)
+ << vs->clientds.pf.gbits) >> vs->serverds.pf.gbits);
+ b = ((((v & vs->serverds.pf.bmask) >> vs->serverds.pf.bshift)
+ << vs->clientds.pf.bbits) >> vs->serverds.pf.bbits);
+
+ po[0] = r;
+ po[1] = g;
+ po[2] = b;
+
+ pi += depth;
+ po += 3; // RGB
+ }
+}
+
+static void send_framebuffer_update_tight(VncState *vs, int x, int y, int w,
int h)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ uint8_t *row = ds_get_data(vs->ds) +
+ y * ds_get_linesize(vs->ds) +
+ x * ds_get_bytes_per_pixel(vs->ds);
+ int dy;
+ JSAMPROW row_pointer[1];
+
+ if(vnc_has_feature(vs, VNC_FEATURE_HEXTILE) && (w * h) < 300) {
+ /* Below a certain size its actually more efficient to send hextiles
+ * Take a rough stab in the dark at 300 for text-based displays */
+ send_framebuffer_update_hextile(vs, x, y, w, h);
+ return;
+ }
+
+ vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
+
+ // XXX For now let's be stupid and always send JPEG data. Tight can do a
lot more!
+
+ // Indicate its a Jpeg data stream
+ vnc_write_u8(vs, VNC_TIGHT_CCB_TYPE_JPEG);
+
+ // Compress data
+ cinfo.client_data = vs;
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ cinfo.image_width = w;
+ cinfo.image_height = h;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, (vs->tight_quality+1) * 10, TRUE);
+
+ buffer_reserve(&vs->jpeg_buffer, 1024);
+ vs->jpeg_dst_manager.init_destination = jpeg_init_destination;
+ vs->jpeg_dst_manager.empty_output_buffer = jpeg_empty_output_buffer;
+ vs->jpeg_dst_manager.term_destination = jpeg_term_destination;
+ cinfo.dest = &vs->jpeg_dst_manager;
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+ row_pointer[0] = qemu_malloc(3 * w);
+ for (dy = 0; dy < h; dy++) {
+ jpeg_row2pixel(vs, (char*)row, (char*)row_pointer[0], w);
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ row += ds_get_linesize(vs->ds);
+ }
+ qemu_free(row_pointer[0]);
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ VNC_DEBUG("JPEG: Sending %d bytes of jpeg data\n",
(int)vs->jpeg_buffer.offset);
+ vnc_send_compact_size(vs, vs->jpeg_buffer.offset);
+ vnc_write(vs, vs->jpeg_buffer.buffer, vs->jpeg_buffer.offset);
+ buffer_reset(&vs->jpeg_buffer);
+}
+#endif /* CONFIG_VNC_JPEG */
+
static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
{
switch(vs->vnc_encoding) {
+#ifdef CONFIG_VNC_JPEG
+ case VNC_ENCODING_TIGHT:
+ send_framebuffer_update_tight(vs, x, y, w, h);
+ break;
+#endif /* CONFIG_VNC_JPEG */
case VNC_ENCODING_HEXTILE:
send_framebuffer_update_hextile(vs, x, y, w, h);
break;
@@ -1204,7 +1378,11 @@ static void set_encodings(VncState *vs, int32_t
*encodings, size_t n_encodings)
vs->vnc_encoding = enc;
break;
case VNC_ENCODING_TIGHT:
+#ifdef CONFIG_VNC_JPEG
+ buffer_reset(&vs->jpeg_buffer);
+#endif
vs->features |= VNC_FEATURE_TIGHT_MASK;
+ vs->vnc_encoding = enc;
break;
case VNC_ENCODING_DESKTOPRESIZE:
vs->features |= VNC_FEATURE_RESIZE_MASK;
--
1.6.0.2
- [Qemu-devel] [PATCH 0/7] Add tight support to VNC, Alexander Graf, 2009/01/29
- [Qemu-devel] [PATCH 1/7] Split VNC defines to vnc.h, Alexander Graf, 2009/01/29
- [Qemu-devel] [PATCH 2/7] Use VNC protocol defines, Alexander Graf, 2009/01/29
- [Qemu-devel] [PATCH 3/7] Fix invalid #if in vnc.c when debugging is enabled, Alexander Graf, 2009/01/29
- [Qemu-devel] [PATCH 4/7] Make vnc buffer big-chunk aware, Alexander Graf, 2009/01/29
- [Qemu-devel] [PATCH 5/7] Split vnc authentication code, Alexander Graf, 2009/01/29
- [Qemu-devel] [PATCH 6/7] Add tight protocol awareness to vnc.c, Alexander Graf, 2009/01/29
- [Qemu-devel] [PATCH 7/7] Add tight encoding (jpeg) to vnc.c,
Alexander Graf <=
- [Qemu-devel] Re: [PATCH 7/7] Add tight encoding (jpeg) to vnc.c, Anthony Liguori, 2009/01/29
- Re: [Qemu-devel] Re: [PATCH 7/7] Add tight encoding (jpeg) to vnc.c, Stefano Stabellini, 2009/01/29
- Re: [Qemu-devel] Re: [PATCH 7/7] Add tight encoding (jpeg) to vnc.c, Anthony Liguori, 2009/01/29
- [Qemu-devel] Re: [PATCH 6/7] Add tight protocol awareness to vnc.c, Anthony Liguori, 2009/01/29
- [Qemu-devel] Re: [PATCH 6/7] Add tight protocol awareness to vnc.c, Alexander Graf, 2009/01/29
- [Qemu-devel] Re: [PATCH 6/7] Add tight protocol awareness to vnc.c, Anthony Liguori, 2009/01/29
- [Qemu-devel] Re: [PATCH 4/7] Make vnc buffer big-chunk aware, Anthony Liguori, 2009/01/29
- [Qemu-devel] Re: [PATCH 4/7] Make vnc buffer big-chunk aware, Alexander Graf, 2009/01/29
[Qemu-devel] Re: [PATCH 1/7] Split VNC defines to vnc.h, Anthony Liguori, 2009/01/29