2 * QEMU VNC display driver: tight encoding
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.
8 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
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:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
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
32 #include "vnc-encoding-tight.h"
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). */
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
;
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 }
58 static int tight_init_stream(VncState
*vs
, int stream_id
,
59 int level
, int strategy
)
61 z_streamp zstream
= &vs
->tight_stream
[stream_id
];
63 if (zstream
->opaque
== NULL
) {
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
;
71 err
= deflateInit2(zstream
, level
, Z_DEFLATED
, MAX_WBITS
,
72 MAX_MEM_LEVEL
, strategy
);
75 fprintf(stderr
, "VNC: error initializing zlib\n");
79 vs
->tight_levels
[stream_id
] = level
;
83 if (vs
->tight_levels
[stream_id
] != level
) {
84 if (deflateParams(zstream
, level
, strategy
) != Z_OK
) {
87 vs
->tight_levels
[stream_id
] = level
;
92 static void tight_send_compact_size(VncState
*vs
, size_t len
)
96 char buf
[3] = {0, 0, 0};
98 buf
[bytes
++] = len
& 0x7F;
100 buf
[bytes
-1] |= 0x80;
101 buf
[bytes
++] = (len
>> 7) & 0x7F;
103 buf
[bytes
-1] |= 0x80;
104 buf
[bytes
++] = (len
>> 14) & 0xFF;
107 for(lpc
= 0; lpc
< bytes
; lpc
++) {
108 vnc_write_u8(vs
, buf
[lpc
]);
112 static int tight_compress_data(VncState
*vs
, int stream_id
, size_t bytes
,
113 int level
, int strategy
)
115 z_streamp zstream
= &vs
->tight_stream
[stream_id
];
118 if (bytes
< VNC_TIGHT_MIN_TO_COMPRESS
) {
119 vnc_write(vs
, vs
->tight
.buffer
, vs
->tight
.offset
);
123 if (tight_init_stream(vs
, stream_id
, level
, strategy
)) {
127 /* reserve memory in output buffer */
128 buffer_reserve(&vs
->tight_zlib
, bytes
+ 64);
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
;
139 if (deflate(zstream
, Z_SYNC_FLUSH
) != Z_OK
) {
140 fprintf(stderr
, "VNC: error during tight compression\n");
144 vs
->tight_zlib
.offset
= vs
->tight_zlib
.capacity
- zstream
->avail_out
;
145 bytes
= zstream
->total_out
- previous_out
;
147 tight_send_compact_size(vs
, bytes
);
148 vnc_write(vs
, vs
->tight_zlib
.buffer
, bytes
);
150 buffer_reset(&vs
->tight_zlib
);
156 * Subencoding implementations.
158 static void tight_pack24(VncState
*vs
, size_t count
)
163 int rshift
, gshift
, bshift
;
165 buf
= vs
->tight
.buffer
;
166 buf32
= (uint32_t *)buf
;
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
;
174 rshift
= 24 - vs
->clientds
.pf
.rshift
;
175 gshift
= 24 - vs
->clientds
.pf
.gshift
;
176 bshift
= 24 - vs
->clientds
.pf
.bshift
;
179 vs
->tight
.offset
= count
* 3;
183 *buf
++ = (char)(pix
>> rshift
);
184 *buf
++ = (char)(pix
>> gshift
);
185 *buf
++ = (char)(pix
>> bshift
);
189 static int send_full_color_rect(VncState
*vs
, int w
, int h
)
194 vnc_write_u8(vs
, stream
<< 4); /* no flushing, no filter */
196 if (vs
->tight_pixel24
) {
197 tight_pack24(vs
, w
* h
);
200 bytes
= vs
->clientds
.pf
.bytes_per_pixel
;
203 bytes
= tight_compress_data(vs
, stream
, w
* h
* bytes
,
204 tight_conf
[vs
->tight_compression
].raw_zlib_level
,
210 static void vnc_tight_start(VncState
*vs
)
212 buffer_reset(&vs
->tight
);
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
;
219 static void vnc_tight_stop(VncState
*vs
)
221 // switch back to normal output/zlib buffers
222 vs
->tight
= vs
->output
;
223 vs
->output
= vs
->tight_tmp
;
226 static int send_sub_rect(VncState
*vs
, int x
, int y
, int w
, int h
)
228 vnc_framebuffer_update(vs
, x
, y
, w
, h
, VNC_ENCODING_TIGHT
);
231 * Convert pixels and store them in vs->tight
232 * We will probably rework that later, probably
233 * when adding other sub-encodings
236 vnc_raw_send_framebuffer_update(vs
, x
, y
, w
, h
);
239 return send_full_color_rect(vs
, w
, h
);
242 static int send_rect_simple(VncState
*vs
, int x
, int y
, int w
, int h
)
244 int max_size
, max_width
;
245 int max_sub_width
, max_sub_height
;
250 max_size
= tight_conf
[vs
->tight_compression
].max_rect_size
;
251 max_width
= tight_conf
[vs
->tight_compression
].max_rect_width
;
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
;
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
);
265 n
+= send_sub_rect(vs
, x
, y
, w
, h
);
271 int vnc_tight_send_framebuffer_update(VncState
*vs
, int x
, int y
,
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;
278 vs
->tight_pixel24
= false;
281 return send_rect_simple(vs
, x
, y
, w
, h
);
284 void vnc_tight_clear(VncState
*vs
)
287 for (i
=0; i
<ARRAY_SIZE(vs
->tight_stream
); i
++) {
288 if (vs
->tight_stream
[i
].opaque
) {
289 deflateEnd(&vs
->tight_stream
[i
]);
293 buffer_free(&vs
->tight
);
294 buffer_free(&vs
->tight_zlib
);