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; | ... | ... |