/src/libvncserver/src/libvncserver/zrle.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 | | * zrle.c |
23 | | * |
24 | | * Routines to implement Zlib Run-length Encoding (ZRLE). |
25 | | */ |
26 | | |
27 | | #include "rfb/rfb.h" |
28 | | #include "private.h" |
29 | | #include "zrleoutstream.h" |
30 | | |
31 | | |
32 | 0 | #define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf) \ |
33 | 0 | { char *fbptr = (cl->scaledScreen->frameBuffer \ |
34 | 0 | + (cl->scaledScreen->paddedWidthInBytes * ty) \ |
35 | 0 | + (tx * (cl->scaledScreen->bitsPerPixel / 8))); \ |
36 | 0 | \ |
37 | 0 | (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,\ |
38 | 0 | &cl->format, fbptr, (char*)buf, \ |
39 | 0 | cl->scaledScreen->paddedWidthInBytes, tw, th); } |
40 | | |
41 | | #define EXTRA_ARGS , rfbClientPtr cl |
42 | | |
43 | | #define ENDIAN_LITTLE 0 |
44 | | #define ENDIAN_BIG 1 |
45 | | #define ENDIAN_NO 2 |
46 | 0 | #define BPP 8 |
47 | | #define ZYWRLE_ENDIAN ENDIAN_NO |
48 | | #include "zrleencodetemplate.c" |
49 | | #undef BPP |
50 | 0 | #define BPP 15 |
51 | | #undef ZYWRLE_ENDIAN |
52 | | #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
53 | | #include "zrleencodetemplate.c" |
54 | | #undef ZYWRLE_ENDIAN |
55 | | #define ZYWRLE_ENDIAN ENDIAN_BIG |
56 | | #include "zrleencodetemplate.c" |
57 | | #undef BPP |
58 | 0 | #define BPP 16 |
59 | | #undef ZYWRLE_ENDIAN |
60 | | #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
61 | | #include "zrleencodetemplate.c" |
62 | | #undef ZYWRLE_ENDIAN |
63 | | #define ZYWRLE_ENDIAN ENDIAN_BIG |
64 | | #include "zrleencodetemplate.c" |
65 | | #undef BPP |
66 | 0 | #define BPP 32 |
67 | | #undef ZYWRLE_ENDIAN |
68 | | #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
69 | | #include "zrleencodetemplate.c" |
70 | | #undef ZYWRLE_ENDIAN |
71 | | #define ZYWRLE_ENDIAN ENDIAN_BIG |
72 | | #include "zrleencodetemplate.c" |
73 | | #define CPIXEL 24A |
74 | | #undef ZYWRLE_ENDIAN |
75 | | #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
76 | | #include "zrleencodetemplate.c" |
77 | | #undef ZYWRLE_ENDIAN |
78 | | #define ZYWRLE_ENDIAN ENDIAN_BIG |
79 | | #include "zrleencodetemplate.c" |
80 | | #undef CPIXEL |
81 | | #define CPIXEL 24B |
82 | | #undef ZYWRLE_ENDIAN |
83 | | #define ZYWRLE_ENDIAN ENDIAN_LITTLE |
84 | | #include "zrleencodetemplate.c" |
85 | | #undef ZYWRLE_ENDIAN |
86 | | #define ZYWRLE_ENDIAN ENDIAN_BIG |
87 | | #include "zrleencodetemplate.c" |
88 | | #undef CPIXEL |
89 | | #undef BPP |
90 | | |
91 | | |
92 | | /* |
93 | | * zrleBeforeBuf contains pixel data in the client's format. It must be at |
94 | | * least one pixel bigger than the largest tile of pixel data, since the |
95 | | * ZRLE encoding algorithm writes to the position one past the end of the pixel |
96 | | * data. |
97 | | */ |
98 | | |
99 | | |
100 | | /* |
101 | | * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding. |
102 | | */ |
103 | | |
104 | | rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h) |
105 | 0 | { |
106 | 0 | zrleOutStream* zos; |
107 | 0 | rfbFramebufferUpdateRectHeader rect; |
108 | 0 | rfbZRLEHeader hdr; |
109 | 0 | int i; |
110 | 0 | char *zrleBeforeBuf; |
111 | |
|
112 | 0 | if (cl->zrleBeforeBuf == NULL) { |
113 | 0 | cl->zrleBeforeBuf = (char *) malloc(rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4); |
114 | 0 | } |
115 | 0 | zrleBeforeBuf = cl->zrleBeforeBuf; |
116 | |
|
117 | 0 | if (cl->preferredEncoding == rfbEncodingZYWRLE) { |
118 | 0 | if (cl->tightQualityLevel < 0) { |
119 | 0 | cl->zywrleLevel = 1; |
120 | 0 | } else if (cl->tightQualityLevel < 3) { |
121 | 0 | cl->zywrleLevel = 3; |
122 | 0 | } else if (cl->tightQualityLevel < 6) { |
123 | 0 | cl->zywrleLevel = 2; |
124 | 0 | } else { |
125 | 0 | cl->zywrleLevel = 1; |
126 | 0 | } |
127 | 0 | } else |
128 | 0 | cl->zywrleLevel = 0; |
129 | |
|
130 | 0 | if (!cl->zrleData) |
131 | 0 | cl->zrleData = zrleOutStreamNew(); |
132 | 0 | zos = cl->zrleData; |
133 | 0 | zos->in.ptr = zos->in.start; |
134 | 0 | zos->out.ptr = zos->out.start; |
135 | |
|
136 | 0 | switch (cl->format.bitsPerPixel) { |
137 | | |
138 | 0 | case 8: |
139 | 0 | zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl); |
140 | 0 | break; |
141 | | |
142 | 0 | case 16: |
143 | 0 | if (cl->format.greenMax > 0x1F) { |
144 | 0 | if (cl->format.bigEndian) |
145 | 0 | zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
146 | 0 | else |
147 | 0 | zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
148 | 0 | } else { |
149 | 0 | if (cl->format.bigEndian) |
150 | 0 | zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
151 | 0 | else |
152 | 0 | zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
153 | 0 | } |
154 | 0 | break; |
155 | | |
156 | 0 | case 32: { |
157 | 0 | rfbBool fitsInLS3Bytes |
158 | 0 | = ((cl->format.redMax << cl->format.redShift) < (1<<24) && |
159 | 0 | (cl->format.greenMax << cl->format.greenShift) < (1<<24) && |
160 | 0 | (cl->format.blueMax << cl->format.blueShift) < (1<<24)); |
161 | |
|
162 | 0 | rfbBool fitsInMS3Bytes = (cl->format.redShift > 7 && |
163 | 0 | cl->format.greenShift > 7 && |
164 | 0 | cl->format.blueShift > 7); |
165 | |
|
166 | 0 | if ((fitsInLS3Bytes && !cl->format.bigEndian) || |
167 | 0 | (fitsInMS3Bytes && cl->format.bigEndian)) { |
168 | 0 | if (cl->format.bigEndian) |
169 | 0 | zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl); |
170 | 0 | else |
171 | 0 | zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl); |
172 | 0 | } |
173 | 0 | else if ((fitsInLS3Bytes && cl->format.bigEndian) || |
174 | 0 | (fitsInMS3Bytes && !cl->format.bigEndian)) { |
175 | 0 | if (cl->format.bigEndian) |
176 | 0 | zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl); |
177 | 0 | else |
178 | 0 | zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl); |
179 | 0 | } |
180 | 0 | else { |
181 | 0 | if (cl->format.bigEndian) |
182 | 0 | zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
183 | 0 | else |
184 | 0 | zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
185 | 0 | } |
186 | 0 | } |
187 | 0 | break; |
188 | 0 | } |
189 | | |
190 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out), |
191 | 0 | + w * (cl->format.bitsPerPixel / 8) * h); |
192 | |
|
193 | 0 | if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader |
194 | 0 | > UPDATE_BUF_SIZE) |
195 | 0 | { |
196 | 0 | if (!rfbSendUpdateBuf(cl)) |
197 | 0 | return FALSE; |
198 | 0 | } |
199 | | |
200 | 0 | rect.r.x = Swap16IfLE(x); |
201 | 0 | rect.r.y = Swap16IfLE(y); |
202 | 0 | rect.r.w = Swap16IfLE(w); |
203 | 0 | rect.r.h = Swap16IfLE(h); |
204 | 0 | rect.encoding = Swap32IfLE(cl->preferredEncoding); |
205 | |
|
206 | 0 | memcpy(cl->updateBuf+cl->ublen, (char *)&rect, |
207 | 0 | sz_rfbFramebufferUpdateRectHeader); |
208 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
209 | |
|
210 | 0 | hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out)); |
211 | |
|
212 | 0 | memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader); |
213 | 0 | cl->ublen += sz_rfbZRLEHeader; |
214 | | |
215 | | /* copy into updateBuf and send from there. Maybe should send directly? */ |
216 | |
|
217 | 0 | for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) { |
218 | |
|
219 | 0 | int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; |
220 | |
|
221 | 0 | if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) { |
222 | 0 | bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i; |
223 | 0 | } |
224 | |
|
225 | 0 | memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy); |
226 | |
|
227 | 0 | cl->ublen += bytesToCopy; |
228 | 0 | i += bytesToCopy; |
229 | |
|
230 | 0 | if (cl->ublen == UPDATE_BUF_SIZE) { |
231 | 0 | if (!rfbSendUpdateBuf(cl)) |
232 | 0 | return FALSE; |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | 0 | return TRUE; |
237 | 0 | } |
238 | | |
239 | | |
240 | | void rfbFreeZrleData(rfbClientPtr cl) |
241 | 2.37k | { |
242 | 2.37k | if (cl->zrleData) { |
243 | 0 | zrleOutStreamFree(cl->zrleData); |
244 | 0 | } |
245 | 2.37k | cl->zrleData = NULL; |
246 | | |
247 | 2.37k | if (cl->zrleBeforeBuf) { |
248 | 0 | free(cl->zrleBeforeBuf); |
249 | 0 | } |
250 | 2.37k | cl->zrleBeforeBuf = NULL; |
251 | | |
252 | 2.37k | if (cl->paletteHelper) { |
253 | 0 | free(cl->paletteHelper); |
254 | 0 | } |
255 | | cl->paletteHelper = NULL; |
256 | 2.37k | } |
257 | | |