From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MWrbV-0005tD-0v for qemu-devel@nongnu.org; Fri, 31 Jul 2009 08:52:57 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MWrbM-0005qn-8l for qemu-devel@nongnu.org; Fri, 31 Jul 2009 08:52:53 -0400 Received: from [199.232.76.173] (port=56344 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MWrbL-0005qQ-Qt for qemu-devel@nongnu.org; Fri, 31 Jul 2009 08:52:48 -0400 Received: from smtp-out.google.com ([216.239.33.17]:19641) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1MWrbK-0001Dx-Q9 for qemu-devel@nongnu.org; Fri, 31 Jul 2009 08:52:47 -0400 Received: from spaceape24.eur.corp.google.com (spaceape24.eur.corp.google.com [172.28.16.76]) by smtp-out.google.com with ESMTP id n6VCqguN023630 for ; Fri, 31 Jul 2009 13:52:42 +0100 Received: from ey-out-2122.google.com (eyd9.prod.google.com [10.208.4.9]) by spaceape24.eur.corp.google.com with ESMTP id n6VCqdBp031573 for ; Fri, 31 Jul 2009 05:52:40 -0700 Received: by ey-out-2122.google.com with SMTP id 9so532052eyd.13 for ; Fri, 31 Jul 2009 05:52:39 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <1249024897-11100-1-git-send-email-agraf@suse.de> References: <1249024897-11100-1-git-send-email-agraf@suse.de> Date: Fri, 31 Jul 2009 14:52:39 +0200 Message-ID: <60cad3f0907310552q6b75422kad75f47381d8cd09@mail.gmail.com> Subject: Re: [Qemu-devel] [PATCH] Add JPEG encoding to VNC server From: David Turner Content-Type: multipart/alternative; boundary=001636c597f334a299046fffe58c List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Alexander Graf Cc: stefano.stabellini@eu.citrix.com, qemu-devel@nongnu.org, kraxel@redhat.com --001636c597f334a299046fffe58c Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit the feature check seems to use "vnc_tls=no" if -ljpeg linking doesn't work. shouldn't this be "vnc_jpeg=no" instead ? On Fri, Jul 31, 2009 at 9:21 AM, Alexander Graf wrote: > We know most of the tight protocol already, so implementing JPEG is rather > easy, especially considering that I had this implementation lying around > still anyways. > > The big concern Anthony raised about JPEG compression is that as soon as > you > use JPEG, CopyRect looks ugly for most use cases and most users probably > don't > want it anyways. > > So the road I went for this patch was to only enable JPEG encoding when > it's > the only available choice. Allow any other protocols? You don't get JPEG > then. > > While this might sound like it renders the whole implementation useless, it > does make sense to implement it nevertheless. I have some ideas to > implement > progressive encodings for video. > > So when we'd detect that one region is updated a lot in a short about of > time > with content that zlib can't really handle well, we'd just send a really > low > quality JPEG first and then send the update after a timer if the region > wasn't > updated within that timeframe. > > But this is all ideas so far. For now the JPEG implementation is stand > alone, > but would enable either me or someone else who'd like to do it worlds of > encoding fun :-). > > Also, if you're daring, you can always see if JPEG performs good for your > specific VNC workload and at least have the chance to use it. > > Signed-off-by: Alexander Graf > --- > Makefile.target | 4 + > configure | 24 ++++++++ > vnc.c | 178 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++- > vnc.h | 9 +++ > 4 files changed, 214 insertions(+), 1 deletions(-) > > diff --git a/Makefile.target b/Makefile.target > index 49ba08d..f1dd54d 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -303,6 +303,10 @@ CPPFLAGS += $(VNC_SASL_CFLAGS) > LIBS += $(VNC_SASL_LIBS) > endif > > +ifdef CONFIG_VNC_JPEG > +LIBS += $(CONFIG_VNC_JPEG_LIBS) > +endif > + > ifdef CONFIG_BLUEZ > LIBS += $(BLUEZ_LIBS) > endif > diff --git a/configure b/configure > index 8160bed..67fe51a 100755 > --- a/configure > +++ b/configure > @@ -175,6 +175,7 @@ fmod_inc="" > oss_lib="" > vnc_tls="yes" > vnc_sasl="yes" > +vnc_jpeg="yes" > bsd="no" > linux="no" > solaris="no" > @@ -428,6 +429,8 @@ for opt do > ;; > --disable-vnc-sasl) vnc_sasl="no" > ;; > + --disable-jpeg) vnc_jpeg="no" > + ;; > --disable-slirp) slirp="no" > ;; > --disable-vde) vde="no" > @@ -649,6 +652,7 @@ echo " --disable-xen disable xen backend > driver support" > echo " --disable-brlapi disable BrlAPI" > echo " --disable-vnc-tls disable TLS encryption for VNC server" > echo " --disable-vnc-sasl disable SASL encryption for VNC server" > +echo " --disable-jpeg disable JPEG compression for VNC server" > echo " --disable-curses disable curses output" > echo " --disable-curl disable curl connectivity" > echo " --disable-bluez disable bluez stack connectivity" > @@ -994,6 +998,21 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> > /dev/null ; then > fi > > ########################################## > +# VNC JPEG detection > +if test "$vnc_jpeg" = "yes" ; then > +cat > $TMPC < +#include > +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 > vde=no > @@ -1452,6 +1471,7 @@ if test "$vnc_sasl" = "yes" ; then > echo " SASL CFLAGS $vnc_sasl_cflags" > echo " SASL LIBS $vnc_sasl_libs" > fi > +echo "VNC JPEG support $vnc_jpeg" > if test -n "$sparc_cpu"; then > echo "Target Sparc Arch $sparc_cpu" > fi > @@ -1604,6 +1624,10 @@ fi > if test "$fnmatch" = "yes" ; then > echo "CONFIG_FNMATCH=y" >> $config_host_mak > fi > +if test "$vnc_jpeg" = "yes" ; then > + echo "CONFIG_VNC_JPEG=y" >> $config_host_mak > + echo "CONFIG_VNC_JPEG_LIBS=$vnc_jpeg_libs" >> $config_host_mak > +fi > qemu_version=`head $source_path/VERSION` > echo "VERSION=$qemu_version" >>$config_host_mak > echo "PKGVERSION=$pkgversion" >>$config_host_mak > diff --git a/vnc.c b/vnc.c > index 903dd95..4e0c967 100644 > --- a/vnc.c > +++ b/vnc.c > @@ -635,9 +635,171 @@ static void send_framebuffer_update_zlib(VncState > *vs, int x, int y, int w, int > vs->output.offset = new_offset; > } > > +#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 void jpeg_row2pixel(VncState *vs, char *in, char *out, int len) > +{ > + char *pi = in; > + char *po = out; > + int depth = vs->server.ds->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->server.ds->pf.rmask) >> vs->server.ds->pf.rshift) > + << vs->clientds.pf.rbits) >> vs->server.ds->pf.rbits); > + g = ((((v & vs->server.ds->pf.gmask) >> vs->server.ds->pf.gshift) > + << vs->clientds.pf.gbits) >> vs->server.ds->pf.gbits); > + b = ((((v & vs->server.ds->pf.bmask) >> vs->server.ds->pf.bshift) > + << vs->clientds.pf.bbits) >> vs->server.ds->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_ZLIB: > send_framebuffer_update_zlib(vs, x, y, w, h); > break; > @@ -1552,7 +1714,7 @@ static void set_encodings(VncState *vs, int32_t > *encodings, size_t n_encodings) > > vnc_zlib_init(vs); > vs->features = 0; > - vs->vnc_encoding = 0; > + vs->vnc_encoding = -1; > vs->tight_compression = 9; > vs->tight_quality = 9; > vs->absolute = -1; > @@ -1574,6 +1736,17 @@ 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_TIGHT: > +#ifdef CONFIG_VNC_JPEG > + buffer_reset(&vs->jpeg_buffer); > +#endif > + vs->features |= VNC_FEATURE_TIGHT_MASK; > + > + /* We don't want to do JPEG encoding by accident, so only > + * enable it when it's the only choice. */ > + if (vs->vnc_encoding == -1) > + vs->vnc_encoding = enc; > + break; > case VNC_ENCODING_DESKTOPRESIZE: > vs->features |= VNC_FEATURE_RESIZE_MASK; > break; > @@ -1601,6 +1774,9 @@ static void set_encodings(VncState *vs, int32_t > *encodings, size_t n_encodings) > } > } > > + if (vs->vnc_encoding == -1) > + vs->vnc_encoding = VNC_ENCODING_RAW; > + > check_pointer_type_change(vs, kbd_mouse_is_absolute()); > } > > diff --git a/vnc.h b/vnc.h > index 3ae95f3..b57081f 100644 > --- a/vnc.h > +++ b/vnc.h > @@ -33,6 +33,10 @@ > #include "audio/audio.h" > #include > > +#ifdef CONFIG_VNC_JPEG > +#include > +#endif /* CONFIG_VNC_JPEG */ > + > #include "keymaps.h" > > // #define _VNC_DEBUG 1 > @@ -161,6 +165,11 @@ struct VncState > Buffer zlib_tmp; > z_stream zlib_stream[4]; > > +#ifdef CONFIG_VNC_JPEG > + Buffer jpeg_buffer; > + struct jpeg_destination_mgr jpeg_dst_manager; > +#endif /* CONFIG_VNC_JPEG */ > + > VncState *next; > }; > > -- > 1.6.0.2 > > > > --001636c597f334a299046fffe58c Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable the feature check seems to use "vnc_tls=3Dno" if -ljpeg linking d= oesn't work.
shouldn't this be "vnc_jpeg=3Dno" instead= ?

On Fri, Jul 31, 2009 at 9:21 AM, Alexa= nder Graf <agraf@suse= .de> wrote:
We know most of t= he tight protocol already, so implementing JPEG is rather
easy, especially considering that I had this implementation lying around still anyways.

The big concern Anthony raised about JPEG compression is that as soon as yo= u
use JPEG, CopyRect looks ugly for most use cases and most users probably do= n't
want it anyways.

So the road I went for this patch was to only enable JPEG encoding when it&= #39;s
the only available choice. Allow any other protocols? You don't get JPE= G then.

While this might sound like it renders the whole implementation useless, it=
does make sense to implement it nevertheless. I have some ideas to implemen= t
progressive encodings for video.

So when we'd detect that one region is updated a lot in a short about o= f time
with content that zlib can't really handle well, we'd just send a r= eally low
quality JPEG first and then send the update after a timer if the region was= n't
updated within that timeframe.

But this is all ideas so far. For now the JPEG implementation is stand alon= e,
but would enable either me or someone else who'd like to do it worlds o= f
encoding fun :-).

Also, if you're daring, you can always see if JPEG performs good for yo= ur
specific VNC workload and at least have the chance to use it.

Signed-off-by: Alexander Graf <agraf@su= se.de>
---
=A0Makefile.target | =A0 =A04 +
=A0configure =A0 =A0 =A0 | =A0 24 ++++++++
=A0vnc.c =A0 =A0 =A0 =A0 =A0 | =A0178 +++++++++++++++++++++++++++++++++++++= +++++++++++++++++-
=A0vnc.h =A0 =A0 =A0 =A0 =A0 | =A0 =A09 +++
=A04 files changed, 214 insertions(+), 1 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index 49ba08d..f1dd54d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -303,6 +303,10 @@ CPPFLAGS +=3D $(VNC_SASL_CFLAGS)
=A0LIBS +=3D $(VNC_SASL_LIBS)
=A0endif

+ifdef CONFIG_VNC_JPEG
+LIBS +=3D $(CONFIG_VNC_JPEG_LIBS)
+endif
+
=A0ifdef CONFIG_BLUEZ
=A0LIBS +=3D $(BLUEZ_LIBS)
=A0endif
diff --git a/configure b/configure
index 8160bed..67fe51a 100755
--- a/configure
+++ b/configure
@@ -175,6 +175,7 @@ fmod_inc=3D""
=A0oss_lib=3D""
=A0vnc_tls=3D"yes"
=A0vnc_sasl=3D"yes"
+vnc_jpeg=3D"yes"
=A0bsd=3D"no"
=A0linux=3D"no"
=A0solaris=3D"no"
@@ -428,6 +429,8 @@ for opt do
=A0 ;;
=A0 --disable-vnc-sasl) vnc_sasl=3D"no"
=A0 ;;
+ =A0--disable-jpeg) vnc_jpeg=3D"no"
+ =A0;;
=A0 --disable-slirp) slirp=3D"no"
=A0 ;;
=A0 --disable-vde) vde=3D"no"
@@ -649,6 +652,7 @@ echo " =A0--disable-xen =A0 =A0 =A0 =A0 =A0 =A0dis= able xen backend driver support"
=A0echo " =A0--disable-brlapi =A0 =A0 =A0 =A0 disable BrlAPI"
=A0echo " =A0--disable-vnc-tls =A0 =A0 =A0 =A0disable TLS encryption f= or VNC server"
=A0echo " =A0--disable-vnc-sasl =A0 =A0 =A0 disable SASL encryption fo= r VNC server"
+echo " =A0--disable-jpeg =A0 =A0 =A0 =A0 =A0 disable JPEG compression= for VNC server"
=A0echo " =A0--disable-curses =A0 =A0 =A0 =A0 disable curses output&qu= ot;
=A0echo " =A0--disable-curl =A0 =A0 =A0 =A0 =A0 disable curl connectiv= ity"
=A0echo " =A0--disable-bluez =A0 =A0 =A0 =A0 =A0disable bluez stack co= nnectivity"
@@ -994,6 +998,21 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2>= ; /dev/null ; then
=A0fi

=A0##########################################
+# VNC JPEG detection
+if test "$vnc_jpeg" =3D "yes" ; then
+cat > $TMPC <<EOF
+#include <jpeglib.h>
+int main(void) { jpeg_compress_struct s; jpeg_create_compress(&s); ret= urn 0; }
+EOF
+ =A0 =A0vnc_jpeg_libs=3D"-ljpeg"
+ =A0 =A0if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC $vnc_jpeg_libs >= ; /dev/null 2> /dev/null ; then
+ =A0 =A0 =A0 :
+ =A0 =A0else
+ =A0 =A0 =A0 vnc_tls=3D"no"
+ =A0 =A0fi
+fi
+
+##########################################
=A0# vde libraries probe
=A0if test "$vde" =3D "yes" ; then
=A0 vde=3Dno
@@ -1452,6 +1471,7 @@ if test "$vnc_sasl" =3D "yes" ; t= hen
=A0 =A0 echo " =A0 =A0SASL CFLAGS =A0 =A0$vnc_sasl_cflags"
=A0 =A0 echo " =A0 =A0SASL LIBS =A0 =A0 =A0$vnc_sasl_libs"
=A0fi
+echo "VNC JPEG support =A0$vnc_jpeg"
=A0if test -n "$sparc_cpu"; then
=A0 =A0 echo "Target Sparc Arch $sparc_cpu"
=A0fi
@@ -1604,6 +1624,10 @@ fi
=A0if test "$fnmatch" =3D "yes" ; then
=A0 echo "CONFIG_FNMATCH=3Dy" >> $config_host_mak
=A0fi
+if test "$vnc_jpeg" =3D "yes" ; then
+ =A0echo "CONFIG_VNC_JPEG=3Dy" >> $config_host_mak
+ =A0echo "CONFIG_VNC_JPEG_LIBS=3D$vnc_jpeg_libs" >> $confi= g_host_mak
+fi
=A0qemu_version=3D`head $source_path/VERSION`
=A0echo "VERSION=3D$qemu_version" >>$config_host_mak
=A0echo "PKGVERSION=3D$pkgversion" >>$config_host_mak
diff --git a/vnc.c b/vnc.c
index 903dd95..4e0c967 100644
--- a/vnc.c
+++ b/vnc.c
@@ -635,9 +635,171 @@ static void send_framebuffer_update_zlib(VncState *vs= , int x, int y, int w, int
=A0 =A0 vs->output.offset =3D new_offset;
=A0}

+#ifdef CONFIG_VNC_JPEG
+/* This is called once per encoding */
+static void jpeg_init_destination(j_compress_ptr cinfo)
+{
+ =A0 =A0VncState *vs =3D (VncState*)cinfo->client_data;
+ =A0 =A0Buffer *buffer =3D &vs->jpeg_buffer;
+
+ =A0 =A0cinfo->dest->next_output_byte =3D (JOCTET *)buffer->buffe= r + buffer->offset;
+ =A0 =A0cinfo->dest->free_in_buffer =3D (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)
+{
+ =A0 =A0VncState *vs =3D (VncState*)cinfo->client_data;
+ =A0 =A0Buffer *buffer =3D &vs->jpeg_buffer;
+
+ =A0 =A0buffer->offset =3D buffer->capacity;
+ =A0 =A0buffer_reserve(buffer, 2048);
+ =A0 =A0jpeg_init_destination(cinfo);
+ =A0 =A0return TRUE;
+}
+
+/* This is called when we are done processing data */
+static void jpeg_term_destination(j_compress_ptr cinfo)
+{
+ =A0 =A0VncState *vs =3D (VncState*)cinfo->client_data;
+ =A0 =A0Buffer *buffer =3D &vs->jpeg_buffer;
+
+ =A0 =A0buffer->offset =3D buffer->capacity - cinfo->dest->fre= e_in_buffer;
+}
+
+
+static void vnc_send_compact_size(VncState *vs, int len)
+{
+ =A0 =A0char buf[3];
+ =A0 =A0int lpc =3D 0;
+ =A0 =A0int bytes =3D 0;
+
+ =A0 =A0/* Adapted from SendCompressedData() in Xvnc/programs/Xserver/hw/v= nc/tight.c */
+ =A0 =A0buf[bytes++] =3D len & 0x7F;
+ =A0 =A0if (len > 0x7F) {
+ =A0 =A0 =A0 buf[bytes-1] |=3D 0x80;
+ =A0 =A0 =A0 buf[bytes++] =3D len >> 7 & 0x7F;
+ =A0 =A0 =A0 if (len > 0x3FFF) {
+ =A0 =A0 =A0 =A0 =A0 buf[bytes-1] |=3D 0x80;
+ =A0 =A0 =A0 =A0 =A0 buf[bytes++] =3D len >> 14 & 0xFF;
+ =A0 =A0 =A0 }
+ =A0 =A0}
+
+ =A0 =A0for(lpc =3D 0; lpc < bytes; lpc++) {
+ =A0 =A0 =A0 vnc_write_u8(vs, buf[lpc]);
+ =A0 =A0}
+}
+
+static void jpeg_row2pixel(VncState *vs, char *in, char *out, int len)
+{
+ =A0 =A0char *pi =3D in;
+ =A0 =A0char *po =3D out;
+ =A0 =A0int depth =3D vs->server.ds->pf.bytes_per_pixel;
+ =A0 =A0int i;
+
+ =A0 =A0for (i =3D 0; i < len; i++) {
+ =A0 =A0 =A0 =A0uint32_t v;
+ =A0 =A0 =A0 =A0uint8_t r, g, b;
+ =A0 =A0 =A0 =A0switch (depth) {
+ =A0 =A0 =A0 =A0 =A0 =A0case 1:
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0po[0] =3D pi[0];
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0po[1] =3D pi[0];
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0po[2] =3D pi[0];
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0continue;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0case 2:
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0v =3D *((uint16_t*)pi);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0case 4:
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0v =3D *((uint32_t*)pi);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0r =3D ((((v & vs->server.ds->pf.rmask) >> = vs->server.ds->pf.rshift)
+ =A0 =A0 =A0 =A0 =A0 =A0<< vs->clientds.pf.rbits) >> vs->= ;server.ds->pf.rbits);
+ =A0 =A0 =A0 =A0g =3D ((((v & vs->server.ds->pf.gmask) >> = vs->server.ds->pf.gshift)
+ =A0 =A0 =A0 =A0 =A0 =A0<< vs->clientds.pf.gbits) >> vs->= ;server.ds->pf.gbits);
+ =A0 =A0 =A0 =A0b =3D ((((v & vs->server.ds->pf.bmask) >> = vs->server.ds->pf.bshift)
+ =A0 =A0 =A0 =A0 =A0 =A0<< vs->clientds.pf.bbits) >> vs->= ;server.ds->pf.bbits);
+
+ =A0 =A0 =A0 =A0po[0] =3D r;
+ =A0 =A0 =A0 =A0po[1] =3D g;
+ =A0 =A0 =A0 =A0po[2] =3D b;
+
+ =A0 =A0 =A0 =A0pi +=3D depth;
+ =A0 =A0 =A0 =A0po +=3D 3; // RGB
+ =A0 =A0}
+}
+
+static void send_framebuffer_update_tight(VncState *vs, int x, int y, int = w, int h)
+{
+ =A0 =A0struct jpeg_compress_struct cinfo;
+ =A0 =A0struct jpeg_error_mgr jerr;
+ =A0 =A0uint8_t *row =3D ds_get_data(vs->ds) +
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 y * ds_get_linesize(vs->ds) +
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 x * ds_get_bytes_per_pixel(vs->ds)= ;
+ =A0 =A0int dy;
+ =A0 =A0JSAMPROW row_pointer[1];
+
+ =A0 =A0if(vnc_has_feature(vs, VNC_FEATURE_HEXTILE) && (w * h) <= ; 300) {
+ =A0 =A0 =A0 /* Below a certain size its actually more efficient to send h= extiles
+ =A0 =A0 =A0 =A0* Take a rough stab in the dark at 300 for text-based disp= lays */
+ =A0 =A0 =A0 =A0send_framebuffer_update_hextile(vs, x, y, w, h);
+ =A0 =A0 =A0 =A0return;
+ =A0 =A0}
+
+ =A0 =A0vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
+
+ =A0 =A0// XXX For now let's be stupid and always send JPEG data. Tigh= t can do a lot more!
+
+ =A0 =A0// Indicate its a Jpeg data stream
+ =A0 =A0vnc_write_u8(vs, VNC_TIGHT_CCB_TYPE_JPEG);
+
+ =A0 =A0// Compress data
+ =A0 =A0cinfo.client_data =3D vs;
+ =A0 =A0cinfo.err =3D jpeg_std_error(&jerr);
+ =A0 =A0jpeg_create_compress(&cinfo);
+ =A0 =A0cinfo.image_width =3D w;
+ =A0 =A0cinfo.image_height =3D h;
+ =A0 =A0cinfo.input_components =3D 3;
+ =A0 =A0cinfo.in_color_space =3D JCS_RGB;
+
+ =A0 =A0jpeg_set_defaults(&cinfo);
+ =A0 =A0jpeg_set_quality(&cinfo, (vs->tight_quality+1) * 10, TRUE);=
+
+ =A0 =A0buffer_reserve(&vs->jpeg_buffer, 1024);
+ =A0 =A0vs->jpeg_dst_manager.init_destination =3D jpeg_init_destination= ;
+ =A0 =A0vs->jpeg_dst_manager.empty_output_buffer =3D jpeg_empty_output_= buffer;
+ =A0 =A0vs->jpeg_dst_manager.term_destination =3D jpeg_term_destination= ;
+ =A0 =A0cinfo.dest =3D &vs->jpeg_dst_manager;
+
+ =A0 =A0jpeg_start_compress(&cinfo, TRUE);
+
+ =A0 =A0row_pointer[0] =3D qemu_malloc(3 * w);
+ =A0 =A0for (dy =3D 0; dy < h; dy++) {
+ =A0 =A0 =A0 =A0jpeg_row2pixel(vs, (char*)row, (char*)row_pointer[0], w);<= br> + =A0 =A0 =A0 =A0jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ =A0 =A0 =A0 =A0row +=3D ds_get_linesize(vs->ds);
+ =A0 =A0}
+ =A0 =A0qemu_free(row_pointer[0]);
+
+ =A0 =A0jpeg_finish_compress(&cinfo);
+ =A0 =A0jpeg_destroy_compress(&cinfo);
+
+ =A0 =A0VNC_DEBUG("JPEG: Sending %d bytes of jpeg data\n", (int)= vs->jpeg_buffer.offset);
+ =A0 =A0vnc_send_compact_size(vs, vs->jpeg_buffer.offset);
+ =A0 =A0vnc_write(vs, vs->jpeg_buffer.buffer, vs->jpeg_buffer.offset= );
+ =A0 =A0buffer_reset(&vs->jpeg_buffer);
+}
+#endif /* CONFIG_VNC_JPEG */
+
=A0static void send_framebuffer_update(VncState *vs, int x, int y, int w, i= nt h)
=A0{
=A0 =A0 switch(vs->vnc_encoding) {
+#ifdef CONFIG_VNC_JPEG
+ =A0 =A0 =A0 =A0case VNC_ENCODING_TIGHT:
+ =A0 =A0 =A0 =A0 =A0 send_framebuffer_update_tight(vs, x, y, w, h);
+ =A0 =A0 =A0 =A0 =A0 break;
+#endif /* CONFIG_VNC_JPEG */
=A0 =A0 =A0 =A0 case VNC_ENCODING_ZLIB:
=A0 =A0 =A0 =A0 =A0 =A0 send_framebuffer_update_zlib(vs, x, y, w, h);
=A0 =A0 =A0 =A0 =A0 =A0 break;
@@ -1552,7 +1714,7 @@ static void set_encodings(VncState *vs, int32_t *enco= dings, size_t n_encodings)

=A0 =A0 vnc_zlib_init(vs);
=A0 =A0 vs->features =3D 0;
- =A0 =A0vs->vnc_encoding =3D 0;
+ =A0 =A0vs->vnc_encoding =3D -1;
=A0 =A0 vs->tight_compression =3D 9;
=A0 =A0 vs->tight_quality =3D 9;
=A0 =A0 vs->absolute =3D -1;
@@ -1574,6 +1736,17 @@ static void set_encodings(VncState *vs, int32_t *enc= odings, size_t n_encodings)
=A0 =A0 =A0 =A0 =A0 =A0 vs->features |=3D VNC_FEATURE_ZLIB_MASK;
=A0 =A0 =A0 =A0 =A0 =A0 vs->vnc_encoding =3D enc;
=A0 =A0 =A0 =A0 =A0 =A0 break;
+ =A0 =A0 =A0 =A0case VNC_ENCODING_TIGHT:
+#ifdef CONFIG_VNC_JPEG
+ =A0 =A0 =A0 =A0 =A0 =A0buffer_reset(&vs->jpeg_buffer);
+#endif
+ =A0 =A0 =A0 =A0 =A0 =A0vs->features |=3D VNC_FEATURE_TIGHT_MASK;
+
+ =A0 =A0 =A0 =A0 =A0 =A0/* We don't want to do JPEG encoding by accide= nt, so only
+ =A0 =A0 =A0 =A0 =A0 =A0 * enable it when it's the only choice. */
+ =A0 =A0 =A0 =A0 =A0 =A0if (vs->vnc_encoding =3D=3D -1)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vs->vnc_encoding =3D enc;
+ =A0 =A0 =A0 =A0 =A0 =A0break;
=A0 =A0 =A0 =A0 case VNC_ENCODING_DESKTOPRESIZE:
=A0 =A0 =A0 =A0 =A0 =A0 vs->features |=3D VNC_FEATURE_RESIZE_MASK;
=A0 =A0 =A0 =A0 =A0 =A0 break;
@@ -1601,6 +1774,9 @@ static void set_encodings(VncState *vs, int32_t *enco= dings, size_t n_encodings)
=A0 =A0 =A0 =A0 }
=A0 =A0 }

+ =A0 =A0if (vs->vnc_encoding =3D=3D -1)
+ =A0 =A0 =A0 =A0vs->vnc_encoding =3D VNC_ENCODING_RAW;
+
=A0 =A0 check_pointer_type_change(vs, kbd_mouse_is_absolute());
=A0}

diff --git a/vnc.h b/vnc.h
index 3ae95f3..b57081f 100644
--- a/vnc.h
+++ b/vnc.h
@@ -33,6 +33,10 @@
=A0#include "audio/audio.h"
=A0#include <zlib.h>

+#ifdef CONFIG_VNC_JPEG
+#include <jpeglib.h>
+#endif /* CONFIG_VNC_JPEG */
+
=A0#include "keymaps.h"

=A0// #define _VNC_DEBUG 1
@@ -161,6 +165,11 @@ struct VncState
=A0 =A0 Buffer zlib_tmp;
=A0 =A0 z_stream zlib_stream[4];

+#ifdef CONFIG_VNC_JPEG
+ =A0 =A0Buffer jpeg_buffer;
+ =A0 =A0struct jpeg_destination_mgr jpeg_dst_manager;
+#endif /* CONFIG_VNC_JPEG */
+
=A0 =A0 VncState *next;
=A0};

--
1.6.0.2




--001636c597f334a299046fffe58c--