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 | 29 | #include "qemu_socket.h" |
30 | 30 | #include "qemu-timer.h" |
31 | 31 | #include "audio/audio.h" |
32 | +#include <zlib.h> | |
32 | 33 | |
33 | 34 | #define VNC_REFRESH_INTERVAL (1000 / 30) |
34 | 35 | |
... | ... | @@ -144,6 +145,10 @@ struct VncState |
144 | 145 | size_t read_handler_expect; |
145 | 146 | /* input */ |
146 | 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 | 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 | 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 | 585 | static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) |
485 | 586 | { |
486 | 587 | switch(vs->vnc_encoding) { |
588 | + case VNC_ENCODING_ZLIB: | |
589 | + send_framebuffer_update_zlib(vs, x, y, w, h); | |
590 | + break; | |
487 | 591 | case VNC_ENCODING_HEXTILE: |
488 | 592 | vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE); |
489 | 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 | 1273 | int i; |
1170 | 1274 | unsigned int enc = 0; |
1171 | 1275 | |
1276 | + vnc_zlib_init(vs); | |
1172 | 1277 | vs->features = 0; |
1173 | 1278 | vs->vnc_encoding = 0; |
1174 | 1279 | vs->tight_compression = 9; |
... | ... | @@ -1189,6 +1294,10 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) |
1189 | 1294 | vs->features |= VNC_FEATURE_HEXTILE_MASK; |
1190 | 1295 | vs->vnc_encoding = enc; |
1191 | 1296 | break; |
1297 | + case VNC_ENCODING_ZLIB: | |
1298 | + vs->features |= VNC_FEATURE_ZLIB_MASK; | |
1299 | + vs->vnc_encoding = enc; | |
1300 | + break; | |
1192 | 1301 | case VNC_ENCODING_DESKTOPRESIZE: |
1193 | 1302 | vs->features |= VNC_FEATURE_RESIZE_MASK; |
1194 | 1303 | break; | ... | ... |