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