]>
Commit | Line | Data |
---|---|---|
148954fa CC |
1 | /* |
2 | * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE) | |
3 | * | |
4 | * From libvncserver/libvncserver/zrle.c | |
5 | * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. | |
6 | * Copyright (C) 2003 Sun Microsystems, Inc. | |
7 | * | |
8 | * Copyright (C) 2010 Corentin Chary <[email protected]> | |
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 "vnc.h" | |
30 | #include "vnc-enc-zrle.h" | |
31 | ||
32 | static const int bits_per_packed_pixel[] = { | |
33 | 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 | |
34 | }; | |
35 | ||
36 | ||
37 | static void vnc_zrle_start(VncState *vs) | |
38 | { | |
39 | buffer_reset(&vs->zrle.zrle); | |
40 | ||
41 | /* make the output buffer be the zlib buffer, so we can compress it later */ | |
42 | vs->zrle.tmp = vs->output; | |
43 | vs->output = vs->zrle.zrle; | |
44 | } | |
45 | ||
46 | static void vnc_zrle_stop(VncState *vs) | |
47 | { | |
48 | /* switch back to normal output/zlib buffers */ | |
49 | vs->zrle.zrle = vs->output; | |
50 | vs->output = vs->zrle.tmp; | |
51 | } | |
52 | ||
53 | static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h, | |
54 | int bpp) | |
55 | { | |
56 | Buffer tmp; | |
57 | ||
58 | buffer_reset(&vs->zrle.fb); | |
59 | buffer_reserve(&vs->zrle.fb, w * h * bpp + bpp); | |
60 | ||
61 | tmp = vs->output; | |
62 | vs->output = vs->zrle.fb; | |
63 | ||
64 | vnc_raw_send_framebuffer_update(vs, x, y, w, h); | |
65 | ||
66 | vs->zrle.fb = vs->output; | |
67 | vs->output = tmp; | |
68 | return vs->zrle.fb.buffer; | |
69 | } | |
70 | ||
71 | static int zrle_compress_data(VncState *vs, int level) | |
72 | { | |
73 | z_streamp zstream = &vs->zrle.stream; | |
74 | ||
75 | buffer_reset(&vs->zrle.zlib); | |
76 | ||
77 | if (zstream->opaque != vs) { | |
78 | int err; | |
79 | ||
80 | zstream->zalloc = vnc_zlib_zalloc; | |
81 | zstream->zfree = vnc_zlib_zfree; | |
82 | ||
83 | err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS, | |
84 | MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); | |
85 | ||
86 | if (err != Z_OK) { | |
87 | fprintf(stderr, "VNC: error initializing zlib\n"); | |
88 | return -1; | |
89 | } | |
90 | ||
91 | zstream->opaque = vs; | |
92 | } | |
93 | ||
94 | /* reserve memory in output buffer */ | |
95 | buffer_reserve(&vs->zrle.zlib, vs->zrle.zrle.offset + 64); | |
96 | ||
97 | /* set pointers */ | |
98 | zstream->next_in = vs->zrle.zrle.buffer; | |
99 | zstream->avail_in = vs->zrle.zrle.offset; | |
100 | zstream->next_out = vs->zrle.zlib.buffer + vs->zrle.zlib.offset; | |
101 | zstream->avail_out = vs->zrle.zlib.capacity - vs->zrle.zlib.offset; | |
102 | zstream->data_type = Z_BINARY; | |
103 | ||
104 | /* start encoding */ | |
105 | if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { | |
106 | fprintf(stderr, "VNC: error during zrle compression\n"); | |
107 | return -1; | |
108 | } | |
109 | ||
110 | vs->zrle.zlib.offset = vs->zrle.zlib.capacity - zstream->avail_out; | |
111 | return vs->zrle.zlib.offset; | |
112 | } | |
113 | ||
114 | /* Try to work out whether to use RLE and/or a palette. We do this by | |
115 | * estimating the number of bytes which will be generated and picking the | |
116 | * method which results in the fewest bytes. Of course this may not result | |
117 | * in the fewest bytes after compression... */ | |
118 | static void zrle_choose_palette_rle(VncState *vs, int w, int h, | |
119 | VncPalette *palette, int bpp_out, | |
120 | int runs, int single_pixels, | |
121 | int zywrle_level, | |
122 | bool *use_rle, bool *use_palette) | |
123 | { | |
124 | size_t estimated_bytes; | |
125 | size_t plain_rle_bytes; | |
126 | ||
127 | *use_palette = *use_rle = false; | |
128 | ||
129 | estimated_bytes = w * h * (bpp_out / 8); /* start assuming raw */ | |
130 | ||
131 | if (bpp_out != 8) { | |
132 | if (zywrle_level > 0 && !(zywrle_level & 0x80)) | |
133 | estimated_bytes >>= zywrle_level; | |
134 | } | |
135 | ||
136 | plain_rle_bytes = ((bpp_out / 8) + 1) * (runs + single_pixels); | |
137 | ||
138 | if (plain_rle_bytes < estimated_bytes) { | |
139 | *use_rle = true; | |
140 | estimated_bytes = plain_rle_bytes; | |
141 | } | |
142 | ||
143 | if (palette_size(palette) < 128) { | |
144 | int palette_rle_bytes; | |
145 | ||
146 | palette_rle_bytes = (bpp_out / 8) * palette_size(palette); | |
147 | palette_rle_bytes += 2 * runs + single_pixels; | |
148 | ||
149 | if (palette_rle_bytes < estimated_bytes) { | |
150 | *use_rle = true; | |
151 | *use_palette = true; | |
152 | estimated_bytes = palette_rle_bytes; | |
153 | } | |
154 | ||
155 | if (palette_size(palette) < 17) { | |
156 | int packed_bytes; | |
157 | ||
158 | packed_bytes = (bpp_out / 8) * palette_size(palette); | |
159 | packed_bytes += w * h * | |
160 | bits_per_packed_pixel[palette_size(palette)-1] / 8; | |
161 | ||
162 | if (packed_bytes < estimated_bytes) { | |
163 | *use_rle = false; | |
164 | *use_palette = true; | |
165 | estimated_bytes = packed_bytes; | |
166 | } | |
167 | } | |
168 | } | |
169 | } | |
170 | ||
171 | static void zrle_write_u32(VncState *vs, uint32_t value) | |
172 | { | |
173 | vnc_write(vs, (uint8_t *)&value, 4); | |
174 | } | |
175 | ||
176 | static void zrle_write_u24a(VncState *vs, uint32_t value) | |
177 | { | |
178 | vnc_write(vs, (uint8_t *)&value, 3); | |
179 | } | |
180 | ||
181 | static void zrle_write_u24b(VncState *vs, uint32_t value) | |
182 | { | |
183 | vnc_write(vs, ((uint8_t *)&value) + 1, 3); | |
184 | } | |
185 | ||
186 | static void zrle_write_u16(VncState *vs, uint16_t value) | |
187 | { | |
188 | vnc_write(vs, (uint8_t *)&value, 2); | |
189 | } | |
190 | ||
191 | static void zrle_write_u8(VncState *vs, uint8_t value) | |
192 | { | |
193 | vnc_write_u8(vs, value); | |
194 | } | |
195 | ||
196 | #define ENDIAN_LITTLE 0 | |
197 | #define ENDIAN_BIG 1 | |
198 | #define ENDIAN_NO 2 | |
199 | ||
200 | #define ZRLE_BPP 8 | |
201 | #define ZYWRLE_ENDIAN ENDIAN_NO | |
202 | #include "vnc-enc-zrle-template.c" | |
203 | #undef ZRLE_BPP | |
204 | ||
205 | #define ZRLE_BPP 15 | |
206 | #undef ZYWRLE_ENDIAN | |
207 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
208 | #include "vnc-enc-zrle-template.c" | |
209 | ||
210 | #undef ZYWRLE_ENDIAN | |
211 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
212 | #include "vnc-enc-zrle-template.c" | |
213 | ||
214 | #undef ZRLE_BPP | |
215 | #define ZRLE_BPP 16 | |
216 | #undef ZYWRLE_ENDIAN | |
217 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
218 | #include "vnc-enc-zrle-template.c" | |
219 | ||
220 | #undef ZYWRLE_ENDIAN | |
221 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
222 | #include "vnc-enc-zrle-template.c" | |
223 | ||
224 | #undef ZRLE_BPP | |
225 | #define ZRLE_BPP 32 | |
226 | #undef ZYWRLE_ENDIAN | |
227 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
228 | #include "vnc-enc-zrle-template.c" | |
229 | ||
230 | #undef ZYWRLE_ENDIAN | |
231 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
232 | #include "vnc-enc-zrle-template.c" | |
233 | ||
234 | #define ZRLE_COMPACT_PIXEL 24a | |
235 | #undef ZYWRLE_ENDIAN | |
236 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
237 | #include "vnc-enc-zrle-template.c" | |
238 | ||
239 | #undef ZYWRLE_ENDIAN | |
240 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
241 | #include "vnc-enc-zrle-template.c" | |
242 | ||
243 | #undef ZRLE_COMPACT_PIXEL | |
244 | #define ZRLE_COMPACT_PIXEL 24b | |
245 | #undef ZYWRLE_ENDIAN | |
246 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
247 | #include "vnc-enc-zrle-template.c" | |
248 | ||
249 | #undef ZYWRLE_ENDIAN | |
250 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
251 | #include "vnc-enc-zrle-template.c" | |
252 | #undef ZRLE_COMPACT_PIXEL | |
253 | #undef ZRLE_BPP | |
254 | ||
255 | static int zrle_send_framebuffer_update(VncState *vs, int x, int y, | |
256 | int w, int h) | |
257 | { | |
9f64916d | 258 | bool be = vs->client_be; |
148954fa CC |
259 | size_t bytes; |
260 | int zywrle_level; | |
261 | ||
262 | if (vs->zrle.type == VNC_ENCODING_ZYWRLE) { | |
368d2588 CC |
263 | if (!vs->vd->lossy || vs->tight.quality == (uint8_t)-1 |
264 | || vs->tight.quality == 9) { | |
148954fa CC |
265 | zywrle_level = 0; |
266 | vs->zrle.type = VNC_ENCODING_ZRLE; | |
267 | } else if (vs->tight.quality < 3) { | |
268 | zywrle_level = 3; | |
269 | } else if (vs->tight.quality < 6) { | |
270 | zywrle_level = 2; | |
271 | } else { | |
272 | zywrle_level = 1; | |
273 | } | |
274 | } else { | |
275 | zywrle_level = 0; | |
276 | } | |
277 | ||
278 | vnc_zrle_start(vs); | |
279 | ||
9f64916d | 280 | switch (vs->client_pf.bytes_per_pixel) { |
148954fa CC |
281 | case 1: |
282 | zrle_encode_8ne(vs, x, y, w, h, zywrle_level); | |
283 | break; | |
284 | ||
285 | case 2: | |
9f64916d | 286 | if (vs->client_pf.gmax > 0x1F) { |
148954fa CC |
287 | if (be) { |
288 | zrle_encode_16be(vs, x, y, w, h, zywrle_level); | |
289 | } else { | |
290 | zrle_encode_16le(vs, x, y, w, h, zywrle_level); | |
291 | } | |
292 | } else { | |
293 | if (be) { | |
294 | zrle_encode_15be(vs, x, y, w, h, zywrle_level); | |
295 | } else { | |
296 | zrle_encode_15le(vs, x, y, w, h, zywrle_level); | |
297 | } | |
298 | } | |
299 | break; | |
300 | ||
301 | case 4: | |
302 | { | |
303 | bool fits_in_ls3bytes; | |
304 | bool fits_in_ms3bytes; | |
305 | ||
306 | fits_in_ls3bytes = | |
9f64916d GH |
307 | ((vs->client_pf.rmax << vs->client_pf.rshift) < (1 << 24) && |
308 | (vs->client_pf.gmax << vs->client_pf.gshift) < (1 << 24) && | |
309 | (vs->client_pf.bmax << vs->client_pf.bshift) < (1 << 24)); | |
148954fa | 310 | |
9f64916d GH |
311 | fits_in_ms3bytes = (vs->client_pf.rshift > 7 && |
312 | vs->client_pf.gshift > 7 && | |
313 | vs->client_pf.bshift > 7); | |
148954fa CC |
314 | |
315 | if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) { | |
316 | if (be) { | |
317 | zrle_encode_24abe(vs, x, y, w, h, zywrle_level); | |
318 | } else { | |
319 | zrle_encode_24ale(vs, x, y, w, h, zywrle_level); | |
320 | } | |
321 | } else if ((fits_in_ls3bytes && be) || (fits_in_ms3bytes && !be)) { | |
322 | if (be) { | |
323 | zrle_encode_24bbe(vs, x, y, w, h, zywrle_level); | |
324 | } else { | |
325 | zrle_encode_24ble(vs, x, y, w, h, zywrle_level); | |
326 | } | |
327 | } else { | |
328 | if (be) { | |
329 | zrle_encode_32be(vs, x, y, w, h, zywrle_level); | |
330 | } else { | |
331 | zrle_encode_32le(vs, x, y, w, h, zywrle_level); | |
332 | } | |
333 | } | |
334 | } | |
335 | break; | |
336 | } | |
337 | ||
338 | vnc_zrle_stop(vs); | |
339 | bytes = zrle_compress_data(vs, Z_DEFAULT_COMPRESSION); | |
340 | vnc_framebuffer_update(vs, x, y, w, h, vs->zrle.type); | |
341 | vnc_write_u32(vs, bytes); | |
342 | vnc_write(vs, vs->zrle.zlib.buffer, vs->zrle.zlib.offset); | |
343 | return 1; | |
344 | } | |
345 | ||
346 | int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) | |
347 | { | |
348 | vs->zrle.type = VNC_ENCODING_ZRLE; | |
349 | return zrle_send_framebuffer_update(vs, x, y, w, h); | |
350 | } | |
351 | ||
352 | int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) | |
353 | { | |
354 | vs->zrle.type = VNC_ENCODING_ZYWRLE; | |
355 | return zrle_send_framebuffer_update(vs, x, y, w, h); | |
356 | } | |
357 | ||
358 | void vnc_zrle_clear(VncState *vs) | |
359 | { | |
360 | if (vs->zrle.stream.opaque) { | |
361 | deflateEnd(&vs->zrle.stream); | |
362 | } | |
363 | buffer_free(&vs->zrle.zrle); | |
364 | buffer_free(&vs->zrle.fb); | |
365 | buffer_free(&vs->zrle.zlib); | |
366 | } |