/src/libvncserver/src/libvncserver/zrleencodetemplate.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. |
3 | | * Copyright (C) 2003 Sun Microsystems, Inc. |
4 | | * |
5 | | * This is free software; you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation; either version 2 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This software is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this software; if not, write to the Free Software |
17 | | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
18 | | * USA. |
19 | | */ |
20 | | |
21 | | /* |
22 | | * Before including this file, you must define a number of CPP macros. |
23 | | * |
24 | | * BPP should be 8, 16 or 32 depending on the bits per pixel. |
25 | | * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data |
26 | | * into the given buffer. EXTRA_ARGS can be defined to pass any other |
27 | | * arguments needed by GET_IMAGE_INTO_BUF. |
28 | | * |
29 | | * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel |
30 | | * bigger than the largest tile of pixel data, since the ZRLE encoding |
31 | | * algorithm writes to the position one past the end of the pixel data. |
32 | | */ |
33 | | |
34 | | #include "zrleoutstream.h" |
35 | | #include "zrlepalettehelper.h" |
36 | | #include <assert.h> |
37 | | |
38 | | /* __RFB_CONCAT2 concatenates its two arguments. __RFB_CONCAT2E does the same |
39 | | but also expands its arguments if they are macros */ |
40 | | |
41 | | #ifndef __RFB_CONCAT2E |
42 | 0 | #define __RFB_CONCAT2(a,b) a##b |
43 | 0 | #define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b) |
44 | | #endif |
45 | | |
46 | | #ifndef __RFB_CONCAT3E |
47 | 0 | #define __RFB_CONCAT3(a,b,c) a##b##c |
48 | 0 | #define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c) |
49 | | #endif |
50 | | |
51 | | #undef END_FIX |
52 | | #if ZYWRLE_ENDIAN == ENDIAN_LITTLE |
53 | | # define END_FIX LE |
54 | | #elif ZYWRLE_ENDIAN == ENDIAN_BIG |
55 | | # define END_FIX BE |
56 | | #else |
57 | | # define END_FIX NE |
58 | | #endif |
59 | | |
60 | | #ifdef CPIXEL |
61 | 0 | #define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP) |
62 | 0 | #define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL) |
63 | | #define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX) |
64 | 0 | #define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX) |
65 | 0 | #define BPPOUT 24 |
66 | | #elif BPP==15 |
67 | 0 | #define PIXEL_T __RFB_CONCAT2E(zrle_U,16) |
68 | 0 | #define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16) |
69 | | #define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX) |
70 | 0 | #define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX) |
71 | 0 | #define BPPOUT 16 |
72 | | #else |
73 | 0 | #define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP) |
74 | 0 | #define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP) |
75 | | #define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX) |
76 | 0 | #define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX) |
77 | 0 | #define BPPOUT BPP |
78 | | #endif |
79 | | |
80 | | #ifndef ZRLE_ONCE |
81 | | #define ZRLE_ONCE |
82 | | |
83 | | static const int bitsPerPackedPixel[] = { |
84 | | 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 |
85 | | }; |
86 | | |
87 | | #endif /* ZRLE_ONCE */ |
88 | | |
89 | | void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os, |
90 | | int zywrle_level, int *zywrleBuf, void *paletteHelper); |
91 | | |
92 | | #if BPP!=8 |
93 | | #define ZYWRLE_ENCODE |
94 | | #include "zywrletemplate.c" |
95 | | #endif |
96 | | |
97 | | static void ZRLE_ENCODE (int x, int y, int w, int h, |
98 | | zrleOutStream* os, void* buf |
99 | | EXTRA_ARGS |
100 | | ) |
101 | 0 | { |
102 | 0 | int ty; |
103 | 0 | for (ty = y; ty < y+h; ty += rfbZRLETileHeight) { |
104 | 0 | int tx, th = rfbZRLETileHeight; |
105 | 0 | if (th > y+h-ty) th = y+h-ty; |
106 | 0 | for (tx = x; tx < x+w; tx += rfbZRLETileWidth) { |
107 | 0 | int tw = rfbZRLETileWidth; |
108 | 0 | if (tw > x+w-tx) tw = x+w-tx; |
109 | |
|
110 | 0 | GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf); |
111 | |
|
112 | 0 | if (cl->paletteHelper == NULL) { |
113 | 0 | cl->paletteHelper = (void *) calloc(sizeof(zrlePaletteHelper), 1); |
114 | 0 | } |
115 | |
|
116 | 0 | ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os, |
117 | 0 | cl->zywrleLevel, cl->zywrleBuf, cl->paletteHelper); |
118 | 0 | } |
119 | 0 | } |
120 | 0 | zrleOutStreamFlush(os); |
121 | 0 | } Unexecuted instantiation: zrle.c:zrleEncode8NE Unexecuted instantiation: zrle.c:zrleEncode16BE Unexecuted instantiation: zrle.c:zrleEncode16LE Unexecuted instantiation: zrle.c:zrleEncode15BE Unexecuted instantiation: zrle.c:zrleEncode15LE Unexecuted instantiation: zrle.c:zrleEncode24ABE Unexecuted instantiation: zrle.c:zrleEncode24ALE Unexecuted instantiation: zrle.c:zrleEncode24BBE Unexecuted instantiation: zrle.c:zrleEncode24BLE Unexecuted instantiation: zrle.c:zrleEncode32BE Unexecuted instantiation: zrle.c:zrleEncode32LE |
122 | | |
123 | | |
124 | | void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os, |
125 | | int zywrle_level, int *zywrleBuf, void *paletteHelper) |
126 | 0 | { |
127 | | /* First find the palette and the number of runs */ |
128 | |
|
129 | 0 | zrlePaletteHelper *ph; |
130 | |
|
131 | 0 | int runs = 0; |
132 | 0 | int singlePixels = 0; |
133 | |
|
134 | 0 | rfbBool useRle; |
135 | 0 | rfbBool usePalette; |
136 | |
|
137 | 0 | int estimatedBytes; |
138 | 0 | int plainRleBytes; |
139 | 0 | int i; |
140 | |
|
141 | 0 | PIXEL_T* ptr = data; |
142 | 0 | PIXEL_T* end = ptr + h * w; |
143 | 0 | *end = ~*(end-1); /* one past the end is different so the while loop ends */ |
144 | |
|
145 | 0 | ph = (zrlePaletteHelper *) paletteHelper; |
146 | 0 | zrlePaletteHelperInit(ph); |
147 | |
|
148 | 0 | while (ptr < end) { |
149 | 0 | PIXEL_T pix = *ptr; |
150 | 0 | if (*++ptr != pix) { |
151 | 0 | singlePixels++; |
152 | 0 | } else { |
153 | 0 | while (*++ptr == pix) ; |
154 | 0 | runs++; |
155 | 0 | } |
156 | 0 | zrlePaletteHelperInsert(ph, pix); |
157 | 0 | } |
158 | | |
159 | | /* Solid tile is a special case */ |
160 | |
|
161 | 0 | if (ph->size == 1) { |
162 | 0 | zrleOutStreamWriteU8(os, 1); |
163 | 0 | zrleOutStreamWRITE_PIXEL(os, ph->palette[0]); |
164 | 0 | return; |
165 | 0 | } |
166 | | |
167 | | /* Try to work out whether to use RLE and/or a palette. We do this by |
168 | | estimating the number of bytes which will be generated and picking the |
169 | | method which results in the fewest bytes. Of course this may not result |
170 | | in the fewest bytes after compression... */ |
171 | | |
172 | 0 | useRle = FALSE; |
173 | 0 | usePalette = FALSE; |
174 | |
|
175 | 0 | estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */ |
176 | |
|
177 | | #if BPP!=8 |
178 | 0 | if (zywrle_level > 0 && !(zywrle_level & 0x80)) |
179 | 0 | estimatedBytes >>= zywrle_level; |
180 | | #endif |
181 | |
|
182 | 0 | plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels); |
183 | |
|
184 | 0 | if (plainRleBytes < estimatedBytes) { |
185 | 0 | useRle = TRUE; |
186 | 0 | estimatedBytes = plainRleBytes; |
187 | 0 | } |
188 | |
|
189 | 0 | if (ph->size < 128) { |
190 | 0 | int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels; |
191 | |
|
192 | 0 | if (paletteRleBytes < estimatedBytes) { |
193 | 0 | useRle = TRUE; |
194 | 0 | usePalette = TRUE; |
195 | 0 | estimatedBytes = paletteRleBytes; |
196 | 0 | } |
197 | |
|
198 | 0 | if (ph->size < 17) { |
199 | 0 | int packedBytes = ((BPPOUT/8) * ph->size + |
200 | 0 | w * h * bitsPerPackedPixel[ph->size-1] / 8); |
201 | |
|
202 | 0 | if (packedBytes < estimatedBytes) { |
203 | 0 | useRle = FALSE; |
204 | 0 | usePalette = TRUE; |
205 | 0 | estimatedBytes = packedBytes; |
206 | 0 | } |
207 | 0 | } |
208 | 0 | } |
209 | |
|
210 | 0 | if (!usePalette) ph->size = 0; |
211 | |
|
212 | 0 | zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size); |
213 | |
|
214 | 0 | for (i = 0; i < ph->size; i++) { |
215 | 0 | zrleOutStreamWRITE_PIXEL(os, ph->palette[i]); |
216 | 0 | } |
217 | |
|
218 | 0 | if (useRle) { |
219 | |
|
220 | 0 | PIXEL_T* ptr = data; |
221 | 0 | PIXEL_T* end = ptr + w * h; |
222 | 0 | PIXEL_T* runStart; |
223 | 0 | PIXEL_T pix; |
224 | 0 | while (ptr < end) { |
225 | 0 | int len; |
226 | 0 | runStart = ptr; |
227 | 0 | pix = *ptr++; |
228 | 0 | while (*ptr == pix && ptr < end) |
229 | 0 | ptr++; |
230 | 0 | len = ptr - runStart; |
231 | 0 | if (len <= 2 && usePalette) { |
232 | 0 | int index = zrlePaletteHelperLookup(ph, pix); |
233 | 0 | if (len == 2) |
234 | 0 | zrleOutStreamWriteU8(os, index); |
235 | 0 | zrleOutStreamWriteU8(os, index); |
236 | 0 | continue; |
237 | 0 | } |
238 | 0 | if (usePalette) { |
239 | 0 | int index = zrlePaletteHelperLookup(ph, pix); |
240 | 0 | zrleOutStreamWriteU8(os, index | 128); |
241 | 0 | } else { |
242 | 0 | zrleOutStreamWRITE_PIXEL(os, pix); |
243 | 0 | } |
244 | 0 | len -= 1; |
245 | 0 | while (len >= 255) { |
246 | 0 | zrleOutStreamWriteU8(os, 255); |
247 | 0 | len -= 255; |
248 | 0 | } |
249 | 0 | zrleOutStreamWriteU8(os, len); |
250 | 0 | } |
251 | |
|
252 | 0 | } else { |
253 | | |
254 | | /* no RLE */ |
255 | |
|
256 | 0 | if (usePalette) { |
257 | 0 | int bppp; |
258 | 0 | PIXEL_T* ptr = data; |
259 | | |
260 | | /* packed pixels */ |
261 | |
|
262 | 0 | assert (ph->size < 17); |
263 | |
|
264 | 0 | bppp = bitsPerPackedPixel[ph->size-1]; |
265 | |
|
266 | 0 | for (i = 0; i < h; i++) { |
267 | 0 | zrle_U8 nbits = 0; |
268 | 0 | zrle_U8 byte = 0; |
269 | |
|
270 | 0 | PIXEL_T* eol = ptr + w; |
271 | |
|
272 | 0 | while (ptr < eol) { |
273 | 0 | PIXEL_T pix = *ptr++; |
274 | 0 | zrle_U8 index = zrlePaletteHelperLookup(ph, pix); |
275 | 0 | byte = (byte << bppp) | index; |
276 | 0 | nbits += bppp; |
277 | 0 | if (nbits >= 8) { |
278 | 0 | zrleOutStreamWriteU8(os, byte); |
279 | 0 | nbits = 0; |
280 | 0 | } |
281 | 0 | } |
282 | 0 | if (nbits > 0) { |
283 | 0 | byte <<= 8 - nbits; |
284 | 0 | zrleOutStreamWriteU8(os, byte); |
285 | 0 | } |
286 | 0 | } |
287 | 0 | } else { |
288 | | |
289 | | /* raw */ |
290 | |
|
291 | | #if BPP!=8 |
292 | 0 | if (zywrle_level > 0 && !(zywrle_level & 0x80)) { |
293 | 0 | ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf); |
294 | 0 | ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf, paletteHelper); |
295 | 0 | } |
296 | 0 | else |
297 | 0 | #endif |
298 | 0 | { |
299 | | #ifdef CPIXEL |
300 | 0 | PIXEL_T *ptr; |
301 | 0 | for (ptr = data; ptr < data+w*h; ptr++) |
302 | 0 | zrleOutStreamWRITE_PIXEL(os, *ptr); |
303 | | #else |
304 | 0 | zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8)); |
305 | | #endif |
306 | 0 | } |
307 | 0 | } |
308 | 0 | } |
309 | 0 | } Unexecuted instantiation: zrleEncodeTile8NE Unexecuted instantiation: zrleEncodeTile15LE Unexecuted instantiation: zrleEncodeTile15BE Unexecuted instantiation: zrleEncodeTile16LE Unexecuted instantiation: zrleEncodeTile16BE Unexecuted instantiation: zrleEncodeTile32LE Unexecuted instantiation: zrleEncodeTile32BE Unexecuted instantiation: zrleEncodeTile24ALE Unexecuted instantiation: zrleEncodeTile24ABE Unexecuted instantiation: zrleEncodeTile24BLE Unexecuted instantiation: zrleEncodeTile24BBE |
310 | | |
311 | | #undef PIXEL_T |
312 | | #undef zrleOutStreamWRITE_PIXEL |
313 | | #undef ZRLE_ENCODE |
314 | | #undef ZRLE_ENCODE_TILE |
315 | | #undef ZYWRLE_ENCODE_TILE |
316 | | #undef BPPOUT |