Revision 380282b0
b/Makefile | ||
---|---|---|
124 | 124 |
|
125 | 125 |
vnc-encoding-hextile.o: vnc.h |
126 | 126 |
|
127 |
vnc-encoding-tight.o: vnc.h vnc-encoding-tight.h |
|
128 |
|
|
127 | 129 |
curses.o: curses.c keymaps.h curses_keys.h |
128 | 130 |
|
129 | 131 |
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) |
b/Makefile.objs | ||
---|---|---|
105 | 105 |
common-obj-$(CONFIG_CURSES) += curses.o |
106 | 106 |
common-obj-y += vnc.o acl.o d3des.o |
107 | 107 |
common-obj-y += vnc-encoding-zlib.o vnc-encoding-hextile.o |
108 |
common-obj-y += vnc-encoding-tight.o |
|
108 | 109 |
common-obj-y += iov.o |
109 | 110 |
common-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o |
110 | 111 |
common-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o |
b/vnc-encoding-tight.c | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU VNC display driver: tight encoding |
|
3 |
* |
|
4 |
* From libvncserver/libvncserver/tight.c |
|
5 |
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. |
|
6 |
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. |
|
7 |
* |
|
8 |
* Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> |
|
9 |
* |
|
10 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
11 |
* of this software and associated documentation files (the "Software"), to deal |
|
12 |
* in the Software without restriction, including without limitation the rights |
|
13 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
14 |
* copies of the Software, and to permit persons to whom the Software is |
|
15 |
* furnished to do so, subject to the following conditions: |
|
16 |
* |
|
17 |
* The above copyright notice and this permission notice shall be included in |
|
18 |
* all copies or substantial portions of the Software. |
|
19 |
* |
|
20 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
21 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
22 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
23 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
24 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
25 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
26 |
* THE SOFTWARE. |
|
27 |
*/ |
|
28 |
|
|
29 |
#include <stdbool.h> |
|
30 |
|
|
31 |
#include "vnc.h" |
|
32 |
#include "vnc-encoding-tight.h" |
|
33 |
|
|
34 |
/* Compression level stuff. The following array contains various |
|
35 |
encoder parameters for each of 10 compression levels (0..9). |
|
36 |
Last three parameters correspond to JPEG quality levels (0..9). */ |
|
37 |
|
|
38 |
static const struct { |
|
39 |
int max_rect_size, max_rect_width; |
|
40 |
int mono_min_rect_size, gradient_min_rect_size; |
|
41 |
int idx_zlib_level, mono_zlib_level, raw_zlib_level, gradient_zlib_level; |
|
42 |
int gradient_threshold, gradient_threshold24; |
|
43 |
int idx_max_colors_divisor; |
|
44 |
int jpeg_quality, jpeg_threshold, jpeg_threshold24; |
|
45 |
} tight_conf[] = { |
|
46 |
{ 512, 32, 6, 65536, 0, 0, 0, 0, 0, 0, 4, 5, 10000, 23000 }, |
|
47 |
{ 2048, 128, 6, 65536, 1, 1, 1, 0, 0, 0, 8, 10, 8000, 18000 }, |
|
48 |
{ 6144, 256, 8, 65536, 3, 3, 2, 0, 0, 0, 24, 15, 6500, 15000 }, |
|
49 |
{ 10240, 1024, 12, 65536, 5, 5, 3, 0, 0, 0, 32, 25, 5000, 12000 }, |
|
50 |
{ 16384, 2048, 12, 65536, 6, 6, 4, 0, 0, 0, 32, 37, 4000, 10000 }, |
|
51 |
{ 32768, 2048, 12, 4096, 7, 7, 5, 4, 150, 380, 32, 50, 3000, 8000 }, |
|
52 |
{ 65536, 2048, 16, 4096, 7, 7, 6, 4, 170, 420, 48, 60, 2000, 5000 }, |
|
53 |
{ 65536, 2048, 16, 4096, 8, 8, 7, 5, 180, 450, 64, 70, 1000, 2500 }, |
|
54 |
{ 65536, 2048, 32, 8192, 9, 9, 8, 6, 190, 475, 64, 75, 500, 1200 }, |
|
55 |
{ 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 } |
|
56 |
}; |
|
57 |
|
|
58 |
static int tight_init_stream(VncState *vs, int stream_id, |
|
59 |
int level, int strategy) |
|
60 |
{ |
|
61 |
z_streamp zstream = &vs->tight_stream[stream_id]; |
|
62 |
|
|
63 |
if (zstream->opaque == NULL) { |
|
64 |
int err; |
|
65 |
|
|
66 |
VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id); |
|
67 |
VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs); |
|
68 |
zstream->zalloc = vnc_zlib_zalloc; |
|
69 |
zstream->zfree = vnc_zlib_zfree; |
|
70 |
|
|
71 |
err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS, |
|
72 |
MAX_MEM_LEVEL, strategy); |
|
73 |
|
|
74 |
if (err != Z_OK) { |
|
75 |
fprintf(stderr, "VNC: error initializing zlib\n"); |
|
76 |
return -1; |
|
77 |
} |
|
78 |
|
|
79 |
vs->tight_levels[stream_id] = level; |
|
80 |
zstream->opaque = vs; |
|
81 |
} |
|
82 |
|
|
83 |
if (vs->tight_levels[stream_id] != level) { |
|
84 |
if (deflateParams(zstream, level, strategy) != Z_OK) { |
|
85 |
return -1; |
|
86 |
} |
|
87 |
vs->tight_levels[stream_id] = level; |
|
88 |
} |
|
89 |
return 0; |
|
90 |
} |
|
91 |
|
|
92 |
static void tight_send_compact_size(VncState *vs, size_t len) |
|
93 |
{ |
|
94 |
int lpc = 0; |
|
95 |
int bytes = 0; |
|
96 |
char buf[3] = {0, 0, 0}; |
|
97 |
|
|
98 |
buf[bytes++] = len & 0x7F; |
|
99 |
if (len > 0x7F) { |
|
100 |
buf[bytes-1] |= 0x80; |
|
101 |
buf[bytes++] = (len >> 7) & 0x7F; |
|
102 |
if (len > 0x3FFF) { |
|
103 |
buf[bytes-1] |= 0x80; |
|
104 |
buf[bytes++] = (len >> 14) & 0xFF; |
|
105 |
} |
|
106 |
} |
|
107 |
for(lpc = 0; lpc < bytes; lpc++) { |
|
108 |
vnc_write_u8(vs, buf[lpc]); |
|
109 |
} |
|
110 |
} |
|
111 |
|
|
112 |
static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, |
|
113 |
int level, int strategy) |
|
114 |
{ |
|
115 |
z_streamp zstream = &vs->tight_stream[stream_id]; |
|
116 |
int previous_out; |
|
117 |
|
|
118 |
if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) { |
|
119 |
vnc_write(vs, vs->tight.buffer, vs->tight.offset); |
|
120 |
return bytes; |
|
121 |
} |
|
122 |
|
|
123 |
if (tight_init_stream(vs, stream_id, level, strategy)) { |
|
124 |
return -1; |
|
125 |
} |
|
126 |
|
|
127 |
/* reserve memory in output buffer */ |
|
128 |
buffer_reserve(&vs->tight_zlib, bytes + 64); |
|
129 |
|
|
130 |
/* set pointers */ |
|
131 |
zstream->next_in = vs->tight.buffer; |
|
132 |
zstream->avail_in = vs->tight.offset; |
|
133 |
zstream->next_out = vs->tight_zlib.buffer + vs->tight_zlib.offset; |
|
134 |
zstream->avail_out = vs->tight_zlib.capacity - vs->tight_zlib.offset; |
|
135 |
zstream->data_type = Z_BINARY; |
|
136 |
previous_out = zstream->total_out; |
|
137 |
|
|
138 |
/* start encoding */ |
|
139 |
if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { |
|
140 |
fprintf(stderr, "VNC: error during tight compression\n"); |
|
141 |
return -1; |
|
142 |
} |
|
143 |
|
|
144 |
vs->tight_zlib.offset = vs->tight_zlib.capacity - zstream->avail_out; |
|
145 |
bytes = zstream->total_out - previous_out; |
|
146 |
|
|
147 |
tight_send_compact_size(vs, bytes); |
|
148 |
vnc_write(vs, vs->tight_zlib.buffer, bytes); |
|
149 |
|
|
150 |
buffer_reset(&vs->tight_zlib); |
|
151 |
|
|
152 |
return bytes; |
|
153 |
} |
|
154 |
|
|
155 |
/* |
|
156 |
* Subencoding implementations. |
|
157 |
*/ |
|
158 |
static void tight_pack24(VncState *vs, size_t count) |
|
159 |
{ |
|
160 |
unsigned char *buf; |
|
161 |
uint32_t *buf32; |
|
162 |
uint32_t pix; |
|
163 |
int rshift, gshift, bshift; |
|
164 |
|
|
165 |
buf = vs->tight.buffer; |
|
166 |
buf32 = (uint32_t *)buf; |
|
167 |
|
|
168 |
if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) == |
|
169 |
(vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) { |
|
170 |
rshift = vs->clientds.pf.rshift; |
|
171 |
gshift = vs->clientds.pf.gshift; |
|
172 |
bshift = vs->clientds.pf.bshift; |
|
173 |
} else { |
|
174 |
rshift = 24 - vs->clientds.pf.rshift; |
|
175 |
gshift = 24 - vs->clientds.pf.gshift; |
|
176 |
bshift = 24 - vs->clientds.pf.bshift; |
|
177 |
} |
|
178 |
|
|
179 |
vs->tight.offset = count * 3; |
|
180 |
|
|
181 |
while (count--) { |
|
182 |
pix = *buf32++; |
|
183 |
*buf++ = (char)(pix >> rshift); |
|
184 |
*buf++ = (char)(pix >> gshift); |
|
185 |
*buf++ = (char)(pix >> bshift); |
|
186 |
} |
|
187 |
} |
|
188 |
|
|
189 |
static int send_full_color_rect(VncState *vs, int w, int h) |
|
190 |
{ |
|
191 |
int stream = 0; |
|
192 |
size_t bytes; |
|
193 |
|
|
194 |
vnc_write_u8(vs, stream << 4); /* no flushing, no filter */ |
|
195 |
|
|
196 |
if (vs->tight_pixel24) { |
|
197 |
tight_pack24(vs, w * h); |
|
198 |
bytes = 3; |
|
199 |
} else { |
|
200 |
bytes = vs->clientds.pf.bytes_per_pixel; |
|
201 |
} |
|
202 |
|
|
203 |
bytes = tight_compress_data(vs, stream, w * h * bytes, |
|
204 |
tight_conf[vs->tight_compression].raw_zlib_level, |
|
205 |
Z_DEFAULT_STRATEGY); |
|
206 |
|
|
207 |
return (bytes >= 0); |
|
208 |
} |
|
209 |
|
|
210 |
static void vnc_tight_start(VncState *vs) |
|
211 |
{ |
|
212 |
buffer_reset(&vs->tight); |
|
213 |
|
|
214 |
// make the output buffer be the zlib buffer, so we can compress it later |
|
215 |
vs->tight_tmp = vs->output; |
|
216 |
vs->output = vs->tight; |
|
217 |
} |
|
218 |
|
|
219 |
static void vnc_tight_stop(VncState *vs) |
|
220 |
{ |
|
221 |
// switch back to normal output/zlib buffers |
|
222 |
vs->tight = vs->output; |
|
223 |
vs->output = vs->tight_tmp; |
|
224 |
} |
|
225 |
|
|
226 |
static int send_sub_rect(VncState *vs, int x, int y, int w, int h) |
|
227 |
{ |
|
228 |
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT); |
|
229 |
|
|
230 |
/* |
|
231 |
* Convert pixels and store them in vs->tight |
|
232 |
* We will probably rework that later, probably |
|
233 |
* when adding other sub-encodings |
|
234 |
*/ |
|
235 |
vnc_tight_start(vs); |
|
236 |
vnc_raw_send_framebuffer_update(vs, x, y, w, h); |
|
237 |
vnc_tight_stop(vs); |
|
238 |
|
|
239 |
return send_full_color_rect(vs, w, h); |
|
240 |
} |
|
241 |
|
|
242 |
static int send_rect_simple(VncState *vs, int x, int y, int w, int h) |
|
243 |
{ |
|
244 |
int max_size, max_width; |
|
245 |
int max_sub_width, max_sub_height; |
|
246 |
int dx, dy; |
|
247 |
int rw, rh; |
|
248 |
int n = 0; |
|
249 |
|
|
250 |
max_size = tight_conf[vs->tight_compression].max_rect_size; |
|
251 |
max_width = tight_conf[vs->tight_compression].max_rect_width; |
|
252 |
|
|
253 |
if (w > max_width || w * h > max_size) { |
|
254 |
max_sub_width = (w > max_width) ? max_width : w; |
|
255 |
max_sub_height = max_size / max_sub_width; |
|
256 |
|
|
257 |
for (dy = 0; dy < h; dy += max_sub_height) { |
|
258 |
for (dx = 0; dx < w; dx += max_width) { |
|
259 |
rw = MIN(max_sub_width, w - dx); |
|
260 |
rh = MIN(max_sub_height, h - dy); |
|
261 |
n += send_sub_rect(vs, x+dx, y+dy, rw, rh); |
|
262 |
} |
|
263 |
} |
|
264 |
} else { |
|
265 |
n += send_sub_rect(vs, x, y, w, h); |
|
266 |
} |
|
267 |
|
|
268 |
return n; |
|
269 |
} |
|
270 |
|
|
271 |
int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, |
|
272 |
int w, int h) |
|
273 |
{ |
|
274 |
if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF && |
|
275 |
vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) { |
|
276 |
vs->tight_pixel24 = true; |
|
277 |
} else { |
|
278 |
vs->tight_pixel24 = false; |
|
279 |
} |
|
280 |
|
|
281 |
return send_rect_simple(vs, x, y, w, h); |
|
282 |
} |
|
283 |
|
|
284 |
void vnc_tight_clear(VncState *vs) |
|
285 |
{ |
|
286 |
int i; |
|
287 |
for (i=0; i<ARRAY_SIZE(vs->tight_stream); i++) { |
|
288 |
if (vs->tight_stream[i].opaque) { |
|
289 |
deflateEnd(&vs->tight_stream[i]); |
|
290 |
} |
|
291 |
} |
|
292 |
|
|
293 |
buffer_free(&vs->tight); |
|
294 |
buffer_free(&vs->tight_zlib); |
|
295 |
} |
b/vnc-encoding-tight.h | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU VNC display driver: tight encoding |
|
3 |
* |
|
4 |
* From libvncserver/rfb/rfbproto.h |
|
5 |
* Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin |
|
6 |
* Copyright (C) 2000-2002 Constantin Kaplinsky. All Rights Reserved. |
|
7 |
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved. |
|
8 |
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. |
|
9 |
* |
|
10 |
* |
|
11 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
12 |
* of this software and associated documentation files (the "Software"), to deal |
|
13 |
* in the Software without restriction, including without limitation the rights |
|
14 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
15 |
* copies of the Software, and to permit persons to whom the Software is |
|
16 |
* furnished to do so, subject to the following conditions: |
|
17 |
* |
|
18 |
* The above copyright notice and this permission notice shall be included in |
|
19 |
* all copies or substantial portions of the Software. |
|
20 |
* |
|
21 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
22 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
23 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
24 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
25 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
26 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
27 |
* THE SOFTWARE. |
|
28 |
*/ |
|
29 |
|
|
30 |
#ifndef VNC_ENCODING_TIGHT_H |
|
31 |
#define VNC_ENCODING_TIGHT_H |
|
32 |
|
|
33 |
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
|
34 |
* Tight Encoding. |
|
35 |
* |
|
36 |
*-- The first byte of each Tight-encoded rectangle is a "compression control |
|
37 |
* byte". Its format is as follows (bit 0 is the least significant one): |
|
38 |
* |
|
39 |
* bit 0: if 1, then compression stream 0 should be reset; |
|
40 |
* bit 1: if 1, then compression stream 1 should be reset; |
|
41 |
* bit 2: if 1, then compression stream 2 should be reset; |
|
42 |
* bit 3: if 1, then compression stream 3 should be reset; |
|
43 |
* bits 7-4: if 1000 (0x08), then the compression type is "fill", |
|
44 |
* if 1001 (0x09), then the compression type is "jpeg", |
|
45 |
* if 0xxx, then the compression type is "basic", |
|
46 |
* values greater than 1001 are not valid. |
|
47 |
* |
|
48 |
* If the compression type is "basic", then bits 6..4 of the |
|
49 |
* compression control byte (those xxx in 0xxx) specify the following: |
|
50 |
* |
|
51 |
* bits 5-4: decimal representation is the index of a particular zlib |
|
52 |
* stream which should be used for decompressing the data; |
|
53 |
* bit 6: if 1, then a "filter id" byte is following this byte. |
|
54 |
* |
|
55 |
*-- The data that follows after the compression control byte described |
|
56 |
* above depends on the compression type ("fill", "jpeg" or "basic"). |
|
57 |
* |
|
58 |
*-- If the compression type is "fill", then the only pixel value follows, in |
|
59 |
* client pixel format (see NOTE 1). This value applies to all pixels of the |
|
60 |
* rectangle. |
|
61 |
* |
|
62 |
*-- If the compression type is "jpeg", the following data stream looks like |
|
63 |
* this: |
|
64 |
* |
|
65 |
* 1..3 bytes: data size (N) in compact representation; |
|
66 |
* N bytes: JPEG image. |
|
67 |
* |
|
68 |
* Data size is compactly represented in one, two or three bytes, according |
|
69 |
* to the following scheme: |
|
70 |
* |
|
71 |
* 0xxxxxxx (for values 0..127) |
|
72 |
* 1xxxxxxx 0yyyyyyy (for values 128..16383) |
|
73 |
* 1xxxxxxx 1yyyyyyy zzzzzzzz (for values 16384..4194303) |
|
74 |
* |
|
75 |
* Here each character denotes one bit, xxxxxxx are the least significant 7 |
|
76 |
* bits of the value (bits 0-6), yyyyyyy are bits 7-13, and zzzzzzzz are the |
|
77 |
* most significant 8 bits (bits 14-21). For example, decimal value 10000 |
|
78 |
* should be represented as two bytes: binary 10010000 01001110, or |
|
79 |
* hexadecimal 90 4E. |
|
80 |
* |
|
81 |
*-- If the compression type is "basic" and bit 6 of the compression control |
|
82 |
* byte was set to 1, then the next (second) byte specifies "filter id" which |
|
83 |
* tells the decoder what filter type was used by the encoder to pre-process |
|
84 |
* pixel data before the compression. The "filter id" byte can be one of the |
|
85 |
* following: |
|
86 |
* |
|
87 |
* 0: no filter ("copy" filter); |
|
88 |
* 1: "palette" filter; |
|
89 |
* 2: "gradient" filter. |
|
90 |
* |
|
91 |
*-- If bit 6 of the compression control byte is set to 0 (no "filter id" |
|
92 |
* byte), or if the filter id is 0, then raw pixel values in the client |
|
93 |
* format (see NOTE 1) will be compressed. See below details on the |
|
94 |
* compression. |
|
95 |
* |
|
96 |
*-- The "gradient" filter pre-processes pixel data with a simple algorithm |
|
97 |
* which converts each color component to a difference between a "predicted" |
|
98 |
* intensity and the actual intensity. Such a technique does not affect |
|
99 |
* uncompressed data size, but helps to compress photo-like images better. |
|
100 |
* Pseudo-code for converting intensities to differences is the following: |
|
101 |
* |
|
102 |
* P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1]; |
|
103 |
* if (P[i,j] < 0) then P[i,j] := 0; |
|
104 |
* if (P[i,j] > MAX) then P[i,j] := MAX; |
|
105 |
* D[i,j] := V[i,j] - P[i,j]; |
|
106 |
* |
|
107 |
* Here V[i,j] is the intensity of a color component for a pixel at |
|
108 |
* coordinates (i,j). MAX is the maximum value of intensity for a color |
|
109 |
* component. |
|
110 |
* |
|
111 |
*-- The "palette" filter converts true-color pixel data to indexed colors |
|
112 |
* and a palette which can consist of 2..256 colors. If the number of colors |
|
113 |
* is 2, then each pixel is encoded in 1 bit, otherwise 8 bits is used to |
|
114 |
* encode one pixel. 1-bit encoding is performed such way that the most |
|
115 |
* significant bits correspond to the leftmost pixels, and each raw of pixels |
|
116 |
* is aligned to the byte boundary. When "palette" filter is used, the |
|
117 |
* palette is sent before the pixel data. The palette begins with an unsigned |
|
118 |
* byte which value is the number of colors in the palette minus 1 (i.e. 1 |
|
119 |
* means 2 colors, 255 means 256 colors in the palette). Then follows the |
|
120 |
* palette itself which consist of pixel values in client pixel format (see |
|
121 |
* NOTE 1). |
|
122 |
* |
|
123 |
*-- The pixel data is compressed using the zlib library. But if the data |
|
124 |
* size after applying the filter but before the compression is less then 12, |
|
125 |
* then the data is sent as is, uncompressed. Four separate zlib streams |
|
126 |
* (0..3) can be used and the decoder should read the actual stream id from |
|
127 |
* the compression control byte (see NOTE 2). |
|
128 |
* |
|
129 |
* If the compression is not used, then the pixel data is sent as is, |
|
130 |
* otherwise the data stream looks like this: |
|
131 |
* |
|
132 |
* 1..3 bytes: data size (N) in compact representation; |
|
133 |
* N bytes: zlib-compressed data. |
|
134 |
* |
|
135 |
* Data size is compactly represented in one, two or three bytes, just like |
|
136 |
* in the "jpeg" compression method (see above). |
|
137 |
* |
|
138 |
*-- NOTE 1. If the color depth is 24, and all three color components are |
|
139 |
* 8-bit wide, then one pixel in Tight encoding is always represented by |
|
140 |
* three bytes, where the first byte is red component, the second byte is |
|
141 |
* green component, and the third byte is blue component of the pixel color |
|
142 |
* value. This applies to colors in palettes as well. |
|
143 |
* |
|
144 |
*-- NOTE 2. The decoder must reset compression streams' states before |
|
145 |
* decoding the rectangle, if some of bits 0,1,2,3 in the compression control |
|
146 |
* byte are set to 1. Note that the decoder must reset zlib streams even if |
|
147 |
* the compression type is "fill" or "jpeg". |
|
148 |
* |
|
149 |
*-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only |
|
150 |
* when bits-per-pixel value is either 16 or 32, not 8. |
|
151 |
* |
|
152 |
*-- NOTE 4. The width of any Tight-encoded rectangle cannot exceed 2048 |
|
153 |
* pixels. If a rectangle is wider, it must be split into several rectangles |
|
154 |
* and each one should be encoded separately. |
|
155 |
* |
|
156 |
*/ |
|
157 |
|
|
158 |
#define VNC_TIGHT_EXPLICIT_FILTER 0x04 |
|
159 |
#define VNC_TIGHT_FILL 0x08 |
|
160 |
#define VNC_TIGHT_JPEG 0x09 |
|
161 |
#define VNC_TIGHT_MAX_SUBENCODING 0x09 |
|
162 |
|
|
163 |
/* Filters to improve compression efficiency */ |
|
164 |
#define VNC_TIGHT_FILTER_COPY 0x00 |
|
165 |
#define VNC_TIGHT_FILTER_PALETTE 0x01 |
|
166 |
#define VNC_TIGHT_FILTER_GRADIENT 0x02 |
|
167 |
|
|
168 |
/* Note: The following constant should not be changed. */ |
|
169 |
#define VNC_TIGHT_MIN_TO_COMPRESS 12 |
|
170 |
|
|
171 |
/* The parameters below may be adjusted. */ |
|
172 |
#define VNC_TIGHT_MIN_SPLIT_RECT_SIZE 4096 |
|
173 |
#define VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE 2048 |
|
174 |
#define VNC_TIGHT_MAX_SPLIT_TILE_SIZE 16 |
|
175 |
|
|
176 |
#endif /* VNC_ENCODING_TIGHT_H */ |
b/vnc-encoding-zlib.c | ||
---|---|---|
28 | 28 |
|
29 | 29 |
#define ZALLOC_ALIGNMENT 16 |
30 | 30 |
|
31 |
static void *zalloc(void *x, unsigned items, unsigned size)
|
|
31 |
void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size)
|
|
32 | 32 |
{ |
33 | 33 |
void *p; |
34 | 34 |
|
... | ... | |
40 | 40 |
return (p); |
41 | 41 |
} |
42 | 42 |
|
43 |
static void zfree(void *x, void *addr)
|
|
43 |
void vnc_zlib_zfree(void *x, void *addr)
|
|
44 | 44 |
{ |
45 | 45 |
qemu_free(addr); |
46 | 46 |
} |
... | ... | |
72 | 72 |
|
73 | 73 |
VNC_DEBUG("VNC: initializing zlib stream\n"); |
74 | 74 |
VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs); |
75 |
zstream->zalloc = zalloc; |
|
76 |
zstream->zfree = zfree; |
|
75 |
zstream->zalloc = vnc_zlib_zalloc;
|
|
76 |
zstream->zfree = vnc_zlib_zfree;
|
|
77 | 77 |
|
78 | 78 |
err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS, |
79 | 79 |
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); |
b/vnc.c | ||
---|---|---|
678 | 678 |
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE); |
679 | 679 |
n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h); |
680 | 680 |
break; |
681 |
case VNC_ENCODING_TIGHT: |
|
682 |
n = vnc_tight_send_framebuffer_update(vs, x, y, w, h); |
|
683 |
break; |
|
681 | 684 |
default: |
682 | 685 |
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW); |
683 | 686 |
n = vnc_raw_send_framebuffer_update(vs, x, y, w, h); |
... | ... | |
982 | 985 |
qobject_decref(vs->info); |
983 | 986 |
|
984 | 987 |
vnc_zlib_clear(vs); |
988 |
vnc_tight_clear(vs); |
|
985 | 989 |
|
986 | 990 |
#ifdef CONFIG_VNC_TLS |
987 | 991 |
vnc_tls_client_cleanup(vs); |
... | ... | |
1677 | 1681 |
vs->features |= VNC_FEATURE_HEXTILE_MASK; |
1678 | 1682 |
vs->vnc_encoding = enc; |
1679 | 1683 |
break; |
1684 |
case VNC_ENCODING_TIGHT: |
|
1685 |
vs->features |= VNC_FEATURE_TIGHT_MASK; |
|
1686 |
vs->vnc_encoding = enc; |
|
1687 |
break; |
|
1680 | 1688 |
case VNC_ENCODING_ZLIB: |
1681 | 1689 |
vs->features |= VNC_FEATURE_ZLIB_MASK; |
1682 | 1690 |
vs->vnc_encoding = enc; |
b/vnc.h | ||
---|---|---|
170 | 170 |
/* Tight */ |
171 | 171 |
uint8_t tight_quality; |
172 | 172 |
uint8_t tight_compression; |
173 |
uint8_t tight_pixel24; |
|
174 |
Buffer tight; |
|
175 |
Buffer tight_tmp; |
|
176 |
Buffer tight_zlib; |
|
177 |
int tight_levels[4]; |
|
178 |
z_stream tight_stream[4]; |
|
173 | 179 |
|
174 | 180 |
/* Hextile */ |
175 | 181 |
VncSendHextileTile *send_hextile_tile; |
... | ... | |
404 | 410 |
int y, int w, int h); |
405 | 411 |
void vnc_hextile_set_pixel_conversion(VncState *vs, int generic); |
406 | 412 |
|
413 |
void *vnc_zlib_zalloc(void *x, unsigned items, unsigned size); |
|
414 |
void vnc_zlib_zfree(void *x, void *addr); |
|
407 | 415 |
int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); |
408 | 416 |
void vnc_zlib_clear(VncState *vs); |
409 | 417 |
|
418 |
|
|
419 |
int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); |
|
420 |
void vnc_tight_clear(VncState *vs); |
|
421 |
|
|
410 | 422 |
#endif /* __QEMU_VNC_H */ |
Also available in: Unified diff