root / ui / vnc-enc-zrle-template.c @ 7fee199c
History | View | Annotate | Download (7 kB)
1 |
/*
|
---|---|
2 |
* QEMU VNC display driver: Zlib Run-length Encoding (ZRLE)
|
3 |
*
|
4 |
* From libvncserver/libvncserver/zrleencodetemplate.c
|
5 |
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
|
6 |
* Copyright (C) 2003 Sun Microsystems, Inc.
|
7 |
*
|
8 |
* Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
|
9 |
*
|
10 |
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
11 |
* See the COPYING file in the top-level directory.
|
12 |
*/
|
13 |
|
14 |
/*
|
15 |
* Before including this file, you must define a number of CPP macros.
|
16 |
*
|
17 |
* ZRLE_BPP should be 8, 16 or 32 depending on the bits per pixel.
|
18 |
*
|
19 |
* Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
|
20 |
* bigger than the largest tile of pixel data, since the ZRLE encoding
|
21 |
* algorithm writes to the position one past the end of the pixel data.
|
22 |
*/
|
23 |
|
24 |
|
25 |
#include <assert.h> |
26 |
|
27 |
#undef ZRLE_ENDIAN_SUFFIX
|
28 |
|
29 |
#if ZYWRLE_ENDIAN == ENDIAN_LITTLE
|
30 |
#define ZRLE_ENDIAN_SUFFIX le
|
31 |
#elif ZYWRLE_ENDIAN == ENDIAN_BIG
|
32 |
#define ZRLE_ENDIAN_SUFFIX be
|
33 |
#else
|
34 |
#define ZRLE_ENDIAN_SUFFIX ne
|
35 |
#endif
|
36 |
|
37 |
#ifndef ZRLE_CONCAT
|
38 |
#define ZRLE_CONCAT_I(a, b) a##b |
39 |
#define ZRLE_CONCAT2(a, b) ZRLE_CONCAT_I(a, b)
|
40 |
#define ZRLE_CONCAT3(a, b, c) ZRLE_CONCAT2(a, ZRLE_CONCAT2(b, c))
|
41 |
#endif
|
42 |
|
43 |
#ifdef ZRLE_COMPACT_PIXEL
|
44 |
#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_COMPACT_PIXEL,ZRLE_ENDIAN_SUFFIX)
|
45 |
#define ZRLE_WRITE_SUFFIX ZRLE_COMPACT_PIXEL
|
46 |
#define ZRLE_PIXEL ZRLE_CONCAT3(uint,ZRLE_BPP,_t)
|
47 |
#define ZRLE_BPP_OUT 24 |
48 |
#elif ZRLE_BPP == 15 |
49 |
#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
|
50 |
#define ZRLE_WRITE_SUFFIX 16 |
51 |
#define ZRLE_PIXEL uint16_t
|
52 |
#define ZRLE_BPP_OUT 16 |
53 |
#else
|
54 |
#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX)
|
55 |
#define ZRLE_WRITE_SUFFIX ZRLE_BPP
|
56 |
#define ZRLE_BPP_OUT ZRLE_BPP
|
57 |
#define ZRLE_PIXEL ZRLE_CONCAT3(uint,ZRLE_BPP,_t)
|
58 |
#endif
|
59 |
|
60 |
#define ZRLE_WRITE_PIXEL ZRLE_CONCAT2(zrle_write_u, ZRLE_WRITE_SUFFIX)
|
61 |
#define ZRLE_ENCODE ZRLE_CONCAT2(zrle_encode_, ZRLE_ENCODE_SUFFIX)
|
62 |
#define ZRLE_ENCODE_TILE ZRLE_CONCAT2(zrle_encode_tile, ZRLE_ENCODE_SUFFIX)
|
63 |
#define ZRLE_WRITE_PALETTE ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX)
|
64 |
|
65 |
static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, |
66 |
int zywrle_level);
|
67 |
|
68 |
#if ZRLE_BPP != 8 |
69 |
#include "vnc-enc-zywrle-template.c" |
70 |
#endif
|
71 |
|
72 |
|
73 |
static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h, |
74 |
int zywrle_level)
|
75 |
{ |
76 |
int ty;
|
77 |
|
78 |
for (ty = y; ty < y + h; ty += VNC_ZRLE_TILE_HEIGHT) {
|
79 |
|
80 |
int tx, th;
|
81 |
|
82 |
th = MIN(VNC_ZRLE_TILE_HEIGHT, y + h - ty); |
83 |
|
84 |
for (tx = x; tx < x + w; tx += VNC_ZRLE_TILE_WIDTH) {
|
85 |
int tw;
|
86 |
ZRLE_PIXEL *buf; |
87 |
|
88 |
tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx); |
89 |
|
90 |
buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP); |
91 |
ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level); |
92 |
} |
93 |
} |
94 |
} |
95 |
|
96 |
static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, |
97 |
int zywrle_level)
|
98 |
{ |
99 |
VncPalette *palette = &vs->zrle.palette; |
100 |
|
101 |
int runs = 0; |
102 |
int single_pixels = 0; |
103 |
|
104 |
bool use_rle;
|
105 |
bool use_palette;
|
106 |
|
107 |
int i;
|
108 |
|
109 |
ZRLE_PIXEL *ptr = data; |
110 |
ZRLE_PIXEL *end = ptr + h * w; |
111 |
*end = ~*(end-1); /* one past the end is different so the while loop ends */ |
112 |
|
113 |
/* Real limit is 127 but we wan't a way to know if there is more than 127 */
|
114 |
palette_init(palette, 256, ZRLE_BPP);
|
115 |
|
116 |
while (ptr < end) {
|
117 |
ZRLE_PIXEL pix = *ptr; |
118 |
if (*++ptr != pix) { /* FIXME */ |
119 |
single_pixels++; |
120 |
} else {
|
121 |
while (*++ptr == pix) ;
|
122 |
runs++; |
123 |
} |
124 |
palette_put(palette, pix); |
125 |
} |
126 |
|
127 |
/* Solid tile is a special case */
|
128 |
|
129 |
if (palette_size(palette) == 1) { |
130 |
bool found;
|
131 |
|
132 |
vnc_write_u8(vs, 1);
|
133 |
ZRLE_WRITE_PIXEL(vs, palette_color(palette, 0, &found));
|
134 |
return;
|
135 |
} |
136 |
|
137 |
zrle_choose_palette_rle(vs, w, h, palette, ZRLE_BPP_OUT, |
138 |
runs, single_pixels, zywrle_level, |
139 |
&use_rle, &use_palette); |
140 |
|
141 |
if (!use_palette) {
|
142 |
vnc_write_u8(vs, (use_rle ? 128 : 0)); |
143 |
} else {
|
144 |
uint32_t colors[VNC_PALETTE_MAX_SIZE]; |
145 |
size_t size = palette_size(palette); |
146 |
|
147 |
vnc_write_u8(vs, (use_rle ? 128 : 0) | size); |
148 |
palette_fill(palette, colors); |
149 |
|
150 |
for (i = 0; i < size; i++) { |
151 |
ZRLE_WRITE_PIXEL(vs, colors[i]); |
152 |
} |
153 |
} |
154 |
|
155 |
if (use_rle) {
|
156 |
ZRLE_PIXEL *ptr = data; |
157 |
ZRLE_PIXEL *end = ptr + w * h; |
158 |
ZRLE_PIXEL *run_start; |
159 |
ZRLE_PIXEL pix; |
160 |
|
161 |
while (ptr < end) {
|
162 |
int len;
|
163 |
int index = 0; |
164 |
|
165 |
run_start = ptr; |
166 |
pix = *ptr++; |
167 |
|
168 |
while (*ptr == pix && ptr < end) {
|
169 |
ptr++; |
170 |
} |
171 |
|
172 |
len = ptr - run_start; |
173 |
|
174 |
if (use_palette)
|
175 |
index = palette_idx(palette, pix); |
176 |
|
177 |
if (len <= 2 && use_palette) { |
178 |
if (len == 2) { |
179 |
vnc_write_u8(vs, index); |
180 |
} |
181 |
vnc_write_u8(vs, index); |
182 |
continue;
|
183 |
} |
184 |
if (use_palette) {
|
185 |
vnc_write_u8(vs, index | 128);
|
186 |
} else {
|
187 |
ZRLE_WRITE_PIXEL(vs, pix); |
188 |
} |
189 |
|
190 |
len -= 1;
|
191 |
|
192 |
while (len >= 255) { |
193 |
vnc_write_u8(vs, 255);
|
194 |
len -= 255;
|
195 |
} |
196 |
|
197 |
vnc_write_u8(vs, len); |
198 |
} |
199 |
} else if (use_palette) { /* no RLE */ |
200 |
int bppp;
|
201 |
ZRLE_PIXEL *ptr = data; |
202 |
|
203 |
/* packed pixels */
|
204 |
|
205 |
assert (palette_size(palette) < 17);
|
206 |
|
207 |
bppp = bits_per_packed_pixel[palette_size(palette)-1];
|
208 |
|
209 |
for (i = 0; i < h; i++) { |
210 |
uint8_t nbits = 0;
|
211 |
uint8_t byte = 0;
|
212 |
|
213 |
ZRLE_PIXEL *eol = ptr + w; |
214 |
|
215 |
while (ptr < eol) {
|
216 |
ZRLE_PIXEL pix = *ptr++; |
217 |
uint8_t index = palette_idx(palette, pix); |
218 |
|
219 |
byte = (byte << bppp) | index; |
220 |
nbits += bppp; |
221 |
if (nbits >= 8) { |
222 |
vnc_write_u8(vs, byte); |
223 |
nbits = 0;
|
224 |
} |
225 |
} |
226 |
if (nbits > 0) { |
227 |
byte <<= 8 - nbits;
|
228 |
vnc_write_u8(vs, byte); |
229 |
} |
230 |
} |
231 |
} else {
|
232 |
|
233 |
/* raw */
|
234 |
|
235 |
#if ZRLE_BPP != 8 |
236 |
if (zywrle_level > 0 && !(zywrle_level & 0x80)) { |
237 |
ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf); |
238 |
ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80);
|
239 |
} |
240 |
else
|
241 |
#endif
|
242 |
{ |
243 |
#ifdef ZRLE_COMPACT_PIXEL
|
244 |
ZRLE_PIXEL *ptr; |
245 |
|
246 |
for (ptr = data; ptr < data + w * h; ptr++) {
|
247 |
ZRLE_WRITE_PIXEL(vs, *ptr); |
248 |
} |
249 |
#else
|
250 |
vnc_write(vs, data, w * h * (ZRLE_BPP / 8));
|
251 |
#endif
|
252 |
} |
253 |
} |
254 |
} |
255 |
|
256 |
#undef ZRLE_PIXEL
|
257 |
#undef ZRLE_WRITE_PIXEL
|
258 |
#undef ZRLE_ENCODE
|
259 |
#undef ZRLE_ENCODE_TILE
|
260 |
#undef ZYWRLE_ENCODE_TILE
|
261 |
#undef ZRLE_BPP_OUT
|
262 |
#undef ZRLE_WRITE_SUFFIX
|
263 |
#undef ZRLE_ENCODE_SUFFIX
|