Commit 059cef4092cc1f558f8f74cf2f762cef41237434
1 parent
d2a0102a
Add zlib encoding support (Alexander Graf)
This patch adds zlib encoding support for VNC. It basically runs the raw traffic through zlib, providing a pretty good compression ratio. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6499 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
109 additions
and
0 deletions
vnc.c
@@ -29,6 +29,7 @@ | @@ -29,6 +29,7 @@ | ||
29 | #include "qemu_socket.h" | 29 | #include "qemu_socket.h" |
30 | #include "qemu-timer.h" | 30 | #include "qemu-timer.h" |
31 | #include "audio/audio.h" | 31 | #include "audio/audio.h" |
32 | +#include <zlib.h> | ||
32 | 33 | ||
33 | #define VNC_REFRESH_INTERVAL (1000 / 30) | 34 | #define VNC_REFRESH_INTERVAL (1000 / 30) |
34 | 35 | ||
@@ -144,6 +145,10 @@ struct VncState | @@ -144,6 +145,10 @@ struct VncState | ||
144 | size_t read_handler_expect; | 145 | size_t read_handler_expect; |
145 | /* input */ | 146 | /* input */ |
146 | uint8_t modifiers_state[256]; | 147 | uint8_t modifiers_state[256]; |
148 | + | ||
149 | + Buffer zlib; | ||
150 | + Buffer zlib_tmp; | ||
151 | + z_stream zlib_stream[4]; | ||
147 | }; | 152 | }; |
148 | 153 | ||
149 | static VncState *vnc_state; /* needed for info vnc */ | 154 | static VncState *vnc_state; /* needed for info vnc */ |
@@ -481,9 +486,108 @@ static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, i | @@ -481,9 +486,108 @@ static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, i | ||
481 | 486 | ||
482 | } | 487 | } |
483 | 488 | ||
489 | +static void vnc_zlib_init(VncState *vs) | ||
490 | +{ | ||
491 | + int i; | ||
492 | + for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++) | ||
493 | + vs->zlib_stream[i].opaque = NULL; | ||
494 | +} | ||
495 | + | ||
496 | +static void vnc_zlib_start(VncState *vs) | ||
497 | +{ | ||
498 | + buffer_reset(&vs->zlib); | ||
499 | + | ||
500 | + // make the output buffer be the zlib buffer, so we can compress it later | ||
501 | + vs->zlib_tmp = vs->output; | ||
502 | + vs->output = vs->zlib; | ||
503 | +} | ||
504 | + | ||
505 | +static int vnc_zlib_stop(VncState *vs, int stream_id) | ||
506 | +{ | ||
507 | + z_streamp zstream = &vs->zlib_stream[stream_id]; | ||
508 | + int previous_out; | ||
509 | + | ||
510 | + // switch back to normal output/zlib buffers | ||
511 | + vs->zlib = vs->output; | ||
512 | + vs->output = vs->zlib_tmp; | ||
513 | + | ||
514 | + // compress the zlib buffer | ||
515 | + | ||
516 | + // initialize the stream | ||
517 | + // XXX need one stream per session | ||
518 | + if (zstream->opaque != vs) { | ||
519 | + int err; | ||
520 | + | ||
521 | + VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id); | ||
522 | + VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs); | ||
523 | + zstream->zalloc = Z_NULL; | ||
524 | + zstream->zfree = Z_NULL; | ||
525 | + | ||
526 | + err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS, | ||
527 | + MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); | ||
528 | + | ||
529 | + if (err != Z_OK) { | ||
530 | + fprintf(stderr, "VNC: error initializing zlib\n"); | ||
531 | + return -1; | ||
532 | + } | ||
533 | + | ||
534 | + zstream->opaque = vs; | ||
535 | + } | ||
536 | + | ||
537 | + // XXX what to do if tight_compression changed in between? | ||
538 | + | ||
539 | + // reserve memory in output buffer | ||
540 | + buffer_reserve(&vs->output, vs->zlib.offset + 64); | ||
541 | + | ||
542 | + // set pointers | ||
543 | + zstream->next_in = vs->zlib.buffer; | ||
544 | + zstream->avail_in = vs->zlib.offset; | ||
545 | + zstream->next_out = vs->output.buffer + vs->output.offset; | ||
546 | + zstream->avail_out = vs->output.capacity - vs->output.offset; | ||
547 | + zstream->data_type = Z_BINARY; | ||
548 | + previous_out = zstream->total_out; | ||
549 | + | ||
550 | + // start encoding | ||
551 | + if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { | ||
552 | + fprintf(stderr, "VNC: error during zlib compression\n"); | ||
553 | + return -1; | ||
554 | + } | ||
555 | + | ||
556 | + vs->output.offset = vs->output.capacity - zstream->avail_out; | ||
557 | + return zstream->total_out - previous_out; | ||
558 | +} | ||
559 | + | ||
560 | +static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h) | ||
561 | +{ | ||
562 | + int old_offset, new_offset, bytes_written; | ||
563 | + | ||
564 | + vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB); | ||
565 | + | ||
566 | + // remember where we put in the follow-up size | ||
567 | + old_offset = vs->output.offset; | ||
568 | + vnc_write_s32(vs, 0); | ||
569 | + | ||
570 | + // compress the stream | ||
571 | + vnc_zlib_start(vs); | ||
572 | + send_framebuffer_update_raw(vs, x, y, w, h); | ||
573 | + bytes_written = vnc_zlib_stop(vs, 0); | ||
574 | + | ||
575 | + if (bytes_written == -1) | ||
576 | + return; | ||
577 | + | ||
578 | + // hack in the size | ||
579 | + new_offset = vs->output.offset; | ||
580 | + vs->output.offset = old_offset; | ||
581 | + vnc_write_u32(vs, bytes_written); | ||
582 | + vs->output.offset = new_offset; | ||
583 | +} | ||
584 | + | ||
484 | static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) | 585 | static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) |
485 | { | 586 | { |
486 | switch(vs->vnc_encoding) { | 587 | switch(vs->vnc_encoding) { |
588 | + case VNC_ENCODING_ZLIB: | ||
589 | + send_framebuffer_update_zlib(vs, x, y, w, h); | ||
590 | + break; | ||
487 | case VNC_ENCODING_HEXTILE: | 591 | case VNC_ENCODING_HEXTILE: |
488 | vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE); | 592 | vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE); |
489 | send_framebuffer_update_hextile(vs, x, y, w, h); | 593 | send_framebuffer_update_hextile(vs, x, y, w, h); |
@@ -1169,6 +1273,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) | @@ -1169,6 +1273,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) | ||
1169 | int i; | 1273 | int i; |
1170 | unsigned int enc = 0; | 1274 | unsigned int enc = 0; |
1171 | 1275 | ||
1276 | + vnc_zlib_init(vs); | ||
1172 | vs->features = 0; | 1277 | vs->features = 0; |
1173 | vs->vnc_encoding = 0; | 1278 | vs->vnc_encoding = 0; |
1174 | vs->tight_compression = 9; | 1279 | vs->tight_compression = 9; |
@@ -1189,6 +1294,10 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) | @@ -1189,6 +1294,10 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) | ||
1189 | vs->features |= VNC_FEATURE_HEXTILE_MASK; | 1294 | vs->features |= VNC_FEATURE_HEXTILE_MASK; |
1190 | vs->vnc_encoding = enc; | 1295 | vs->vnc_encoding = enc; |
1191 | break; | 1296 | break; |
1297 | + case VNC_ENCODING_ZLIB: | ||
1298 | + vs->features |= VNC_FEATURE_ZLIB_MASK; | ||
1299 | + vs->vnc_encoding = enc; | ||
1300 | + break; | ||
1192 | case VNC_ENCODING_DESKTOPRESIZE: | 1301 | case VNC_ENCODING_DESKTOPRESIZE: |
1193 | vs->features |= VNC_FEATURE_RESIZE_MASK; | 1302 | vs->features |= VNC_FEATURE_RESIZE_MASK; |
1194 | break; | 1303 | break; |