]>
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 | ||
e16f4c87 | 29 | #include "qemu/osdep.h" |
148954fa CC |
30 | #include "vnc.h" |
31 | #include "vnc-enc-zrle.h" | |
32 | ||
33 | static const int bits_per_packed_pixel[] = { | |
34 | 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 | |
35 | }; | |
36 | ||
37 | ||
38 | static void vnc_zrle_start(VncState *vs) | |
39 | { | |
6bf21f3d | 40 | buffer_reset(&vs->zrle->zrle); |
148954fa CC |
41 | |
42 | /* make the output buffer be the zlib buffer, so we can compress it later */ | |
6bf21f3d LQ |
43 | vs->zrle->tmp = vs->output; |
44 | vs->output = vs->zrle->zrle; | |
148954fa CC |
45 | } |
46 | ||
47 | static void vnc_zrle_stop(VncState *vs) | |
48 | { | |
49 | /* switch back to normal output/zlib buffers */ | |
6bf21f3d LQ |
50 | vs->zrle->zrle = vs->output; |
51 | vs->output = vs->zrle->tmp; | |
148954fa CC |
52 | } |
53 | ||
54 | static void *zrle_convert_fb(VncState *vs, int x, int y, int w, int h, | |
55 | int bpp) | |
56 | { | |
57 | Buffer tmp; | |
58 | ||
6bf21f3d LQ |
59 | buffer_reset(&vs->zrle->fb); |
60 | buffer_reserve(&vs->zrle->fb, w * h * bpp + bpp); | |
148954fa CC |
61 | |
62 | tmp = vs->output; | |
6bf21f3d | 63 | vs->output = vs->zrle->fb; |
148954fa CC |
64 | |
65 | vnc_raw_send_framebuffer_update(vs, x, y, w, h); | |
66 | ||
6bf21f3d | 67 | vs->zrle->fb = vs->output; |
148954fa | 68 | vs->output = tmp; |
6bf21f3d | 69 | return vs->zrle->fb.buffer; |
148954fa CC |
70 | } |
71 | ||
72 | static int zrle_compress_data(VncState *vs, int level) | |
73 | { | |
6bf21f3d | 74 | z_streamp zstream = &vs->zrle->stream; |
148954fa | 75 | |
6bf21f3d | 76 | buffer_reset(&vs->zrle->zlib); |
148954fa CC |
77 | |
78 | if (zstream->opaque != vs) { | |
79 | int err; | |
80 | ||
81 | zstream->zalloc = vnc_zlib_zalloc; | |
82 | zstream->zfree = vnc_zlib_zfree; | |
83 | ||
84 | err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS, | |
85 | MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); | |
86 | ||
87 | if (err != Z_OK) { | |
88 | fprintf(stderr, "VNC: error initializing zlib\n"); | |
89 | return -1; | |
90 | } | |
91 | ||
92 | zstream->opaque = vs; | |
93 | } | |
94 | ||
95 | /* reserve memory in output buffer */ | |
6bf21f3d | 96 | buffer_reserve(&vs->zrle->zlib, vs->zrle->zrle.offset + 64); |
148954fa CC |
97 | |
98 | /* set pointers */ | |
6bf21f3d LQ |
99 | zstream->next_in = vs->zrle->zrle.buffer; |
100 | zstream->avail_in = vs->zrle->zrle.offset; | |
557ba0e5 CE |
101 | zstream->next_out = vs->zrle->zlib.buffer; |
102 | zstream->avail_out = vs->zrle->zlib.capacity; | |
148954fa CC |
103 | zstream->data_type = Z_BINARY; |
104 | ||
105 | /* start encoding */ | |
106 | if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { | |
107 | fprintf(stderr, "VNC: error during zrle compression\n"); | |
108 | return -1; | |
109 | } | |
110 | ||
6bf21f3d LQ |
111 | vs->zrle->zlib.offset = vs->zrle->zlib.capacity - zstream->avail_out; |
112 | return vs->zrle->zlib.offset; | |
148954fa CC |
113 | } |
114 | ||
115 | /* Try to work out whether to use RLE and/or a palette. We do this by | |
116 | * estimating the number of bytes which will be generated and picking the | |
117 | * method which results in the fewest bytes. Of course this may not result | |
118 | * in the fewest bytes after compression... */ | |
119 | static void zrle_choose_palette_rle(VncState *vs, int w, int h, | |
120 | VncPalette *palette, int bpp_out, | |
121 | int runs, int single_pixels, | |
122 | int zywrle_level, | |
123 | bool *use_rle, bool *use_palette) | |
124 | { | |
125 | size_t estimated_bytes; | |
126 | size_t plain_rle_bytes; | |
127 | ||
128 | *use_palette = *use_rle = false; | |
129 | ||
130 | estimated_bytes = w * h * (bpp_out / 8); /* start assuming raw */ | |
131 | ||
132 | if (bpp_out != 8) { | |
133 | if (zywrle_level > 0 && !(zywrle_level & 0x80)) | |
134 | estimated_bytes >>= zywrle_level; | |
135 | } | |
136 | ||
137 | plain_rle_bytes = ((bpp_out / 8) + 1) * (runs + single_pixels); | |
138 | ||
139 | if (plain_rle_bytes < estimated_bytes) { | |
140 | *use_rle = true; | |
141 | estimated_bytes = plain_rle_bytes; | |
142 | } | |
143 | ||
144 | if (palette_size(palette) < 128) { | |
145 | int palette_rle_bytes; | |
146 | ||
147 | palette_rle_bytes = (bpp_out / 8) * palette_size(palette); | |
148 | palette_rle_bytes += 2 * runs + single_pixels; | |
149 | ||
150 | if (palette_rle_bytes < estimated_bytes) { | |
151 | *use_rle = true; | |
152 | *use_palette = true; | |
153 | estimated_bytes = palette_rle_bytes; | |
154 | } | |
155 | ||
156 | if (palette_size(palette) < 17) { | |
157 | int packed_bytes; | |
158 | ||
159 | packed_bytes = (bpp_out / 8) * palette_size(palette); | |
160 | packed_bytes += w * h * | |
161 | bits_per_packed_pixel[palette_size(palette)-1] / 8; | |
162 | ||
163 | if (packed_bytes < estimated_bytes) { | |
164 | *use_rle = false; | |
165 | *use_palette = true; | |
148954fa CC |
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 | |
5b27a92d | 202 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
203 | #undef ZRLE_BPP |
204 | ||
205 | #define ZRLE_BPP 15 | |
206 | #undef ZYWRLE_ENDIAN | |
207 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
5b27a92d | 208 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
209 | |
210 | #undef ZYWRLE_ENDIAN | |
211 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
5b27a92d | 212 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
213 | |
214 | #undef ZRLE_BPP | |
215 | #define ZRLE_BPP 16 | |
216 | #undef ZYWRLE_ENDIAN | |
217 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
5b27a92d | 218 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
219 | |
220 | #undef ZYWRLE_ENDIAN | |
221 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
5b27a92d | 222 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
223 | |
224 | #undef ZRLE_BPP | |
225 | #define ZRLE_BPP 32 | |
226 | #undef ZYWRLE_ENDIAN | |
227 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
5b27a92d | 228 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
229 | |
230 | #undef ZYWRLE_ENDIAN | |
231 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
5b27a92d | 232 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
233 | |
234 | #define ZRLE_COMPACT_PIXEL 24a | |
235 | #undef ZYWRLE_ENDIAN | |
236 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
5b27a92d | 237 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
238 | |
239 | #undef ZYWRLE_ENDIAN | |
240 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
5b27a92d | 241 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
242 | |
243 | #undef ZRLE_COMPACT_PIXEL | |
244 | #define ZRLE_COMPACT_PIXEL 24b | |
245 | #undef ZYWRLE_ENDIAN | |
246 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE | |
5b27a92d | 247 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
248 | |
249 | #undef ZYWRLE_ENDIAN | |
250 | #define ZYWRLE_ENDIAN ENDIAN_BIG | |
5b27a92d | 251 | #include "vnc-enc-zrle.inc.c" |
148954fa CC |
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 | ||
6bf21f3d LQ |
262 | if (vs->zrle->type == VNC_ENCODING_ZYWRLE) { |
263 | if (!vs->vd->lossy || vs->tight->quality == (uint8_t)-1 | |
264 | || vs->tight->quality == 9) { | |
148954fa | 265 | zywrle_level = 0; |
6bf21f3d LQ |
266 | vs->zrle->type = VNC_ENCODING_ZRLE; |
267 | } else if (vs->tight->quality < 3) { | |
148954fa | 268 | zywrle_level = 3; |
6bf21f3d | 269 | } else if (vs->tight->quality < 6) { |
148954fa CC |
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); | |
6bf21f3d | 340 | vnc_framebuffer_update(vs, x, y, w, h, vs->zrle->type); |
148954fa | 341 | vnc_write_u32(vs, bytes); |
6bf21f3d | 342 | vnc_write(vs, vs->zrle->zlib.buffer, vs->zrle->zlib.offset); |
148954fa CC |
343 | return 1; |
344 | } | |
345 | ||
346 | int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) | |
347 | { | |
6bf21f3d | 348 | vs->zrle->type = VNC_ENCODING_ZRLE; |
148954fa CC |
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 | { | |
6bf21f3d | 354 | vs->zrle->type = VNC_ENCODING_ZYWRLE; |
148954fa CC |
355 | return zrle_send_framebuffer_update(vs, x, y, w, h); |
356 | } | |
357 | ||
358 | void vnc_zrle_clear(VncState *vs) | |
359 | { | |
6bf21f3d LQ |
360 | if (vs->zrle->stream.opaque) { |
361 | deflateEnd(&vs->zrle->stream); | |
148954fa | 362 | } |
6bf21f3d LQ |
363 | buffer_free(&vs->zrle->zrle); |
364 | buffer_free(&vs->zrle->fb); | |
365 | buffer_free(&vs->zrle->zlib); | |
148954fa | 366 | } |