4 * Routines to implement Rise-and-Run-length Encoding (RRE). This
5 * code is based on krw's original javatel rfbserver.
9 * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
10 * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
11 * All Rights Reserved.
13 * This is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This software is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this software; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
32 * rreBeforeBuf contains pixel data in the client's format.
33 * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is
34 * larger than the raw data or if it exceeds rreAfterBufSize then
35 * raw encoding is used instead.
38 static int rreBeforeBufSize = 0;
39 static char *rreBeforeBuf = NULL;
41 static int rreAfterBufSize = 0;
42 static char *rreAfterBuf = NULL;
43 static int rreAfterBufLen=0;
45 static int subrectEncode8(uint8_t *data, int w, int h);
46 static int subrectEncode16(uint16_t *data, int w, int h);
47 static int subrectEncode32(uint32_t *data, int w, int h);
48 static uint32_t getBgColour(char *data, int size, int bpp);
51 void rfbRRECleanup(rfbScreenInfoPtr screen)
53 if (rreBeforeBufSize) {
57 if (rreAfterBufSize) {
65 * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding.
69 rfbSendRectEncodingRRE(rfbClientPtr cl,
75 rfbFramebufferUpdateRectHeader rect;
79 char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
80 + (x * (cl->scaledScreen->bitsPerPixel / 8)));
82 int maxRawSize = (cl->scaledScreen->width * cl->scaledScreen->height
83 * (cl->format.bitsPerPixel / 8));
85 if (rreBeforeBufSize < maxRawSize) {
86 rreBeforeBufSize = maxRawSize;
87 if (rreBeforeBuf == NULL)
88 rreBeforeBuf = (char *)malloc(rreBeforeBufSize);
90 rreBeforeBuf = (char *)realloc(rreBeforeBuf, rreBeforeBufSize);
93 if (rreAfterBufSize < maxRawSize) {
94 rreAfterBufSize = maxRawSize;
95 if (rreAfterBuf == NULL)
96 rreAfterBuf = (char *)malloc(rreAfterBufSize);
98 rreAfterBuf = (char *)realloc(rreAfterBuf, rreAfterBufSize);
101 (*cl->translateFn)(cl->translateLookupTable,
102 &(cl->screen->serverFormat),
103 &cl->format, fbptr, rreBeforeBuf,
104 cl->scaledScreen->paddedWidthInBytes, w, h);
106 switch (cl->format.bitsPerPixel) {
108 nSubrects = subrectEncode8((uint8_t *)rreBeforeBuf, w, h);
111 nSubrects = subrectEncode16((uint16_t *)rreBeforeBuf, w, h);
114 nSubrects = subrectEncode32((uint32_t *)rreBeforeBuf, w, h);
117 rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
123 /* RRE encoding was too large, use raw */
125 return rfbSendRectEncodingRaw(cl, x, y, w, h);
128 rfbStatRecordEncodingSent(cl, rfbEncodingRRE,
129 sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + rreAfterBufLen,
130 sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8));
132 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
135 if (!rfbSendUpdateBuf(cl))
139 rect.r.x = Swap16IfLE(x);
140 rect.r.y = Swap16IfLE(y);
141 rect.r.w = Swap16IfLE(w);
142 rect.r.h = Swap16IfLE(h);
143 rect.encoding = Swap32IfLE(rfbEncodingRRE);
145 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
146 sz_rfbFramebufferUpdateRectHeader);
147 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
149 hdr.nSubrects = Swap32IfLE(nSubrects);
151 memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader);
152 cl->ublen += sz_rfbRREHeader;
154 for (i = 0; i < rreAfterBufLen;) {
156 int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
158 if (i + bytesToCopy > rreAfterBufLen) {
159 bytesToCopy = rreAfterBufLen - i;
162 memcpy(&cl->updateBuf[cl->ublen], &rreAfterBuf[i], bytesToCopy);
164 cl->ublen += bytesToCopy;
167 if (cl->ublen == UPDATE_BUF_SIZE) {
168 if (!rfbSendUpdateBuf(cl))
179 * subrectEncode() encodes the given multicoloured rectangle as a background
180 * colour overwritten by single-coloured rectangles. It returns the number
181 * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
182 * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The
183 * single-colour rectangle partition is not optimal, but does find the biggest
184 * horizontal or vertical rectangle top-left anchored to each consecutive
185 * coordinate position.
187 * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
188 * <subrect> is [<colour><x><y><w><h>].
191 #define DEFINE_SUBRECT_ENCODE(bpp) \
193 subrectEncode##bpp(uint##bpp##_t *data, int w, int h) { \
195 rfbRectangle subrect; \
198 int hx=0,hy,vx=0,vy; \
200 uint##bpp##_t *seg; \
201 uint##bpp##_t *line; \
203 int thex,they,thew,theh; \
206 uint##bpp##_t bg = (uint##bpp##_t)getBgColour((char*)data,w*h,bpp); \
208 *((uint##bpp##_t*)rreAfterBuf) = bg; \
210 rreAfterBufLen = (bpp/8); \
212 for (y=0; y<h; y++) { \
214 for (x=0; x<w; x++) { \
215 if (line[x] != bg) { \
219 for (j=y; j<h; j++) { \
221 if (seg[x] != cl) {break;} \
223 while ((seg[i] == cl) && (i < w)) i += 1; \
225 if (j == y) vx = hx = i; \
226 if (i < vx) vx = i; \
227 if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
231 /* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
232 * We'll choose the bigger of the two. \
242 if ((hw*hh) > (vw*vh)) { \
250 subrect.x = Swap16IfLE(thex); \
251 subrect.y = Swap16IfLE(they); \
252 subrect.w = Swap16IfLE(thew); \
253 subrect.h = Swap16IfLE(theh); \
255 newLen = rreAfterBufLen + (bpp/8) + sz_rfbRectangle; \
256 if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \
260 *((uint##bpp##_t*)(rreAfterBuf + rreAfterBufLen)) = cl; \
261 rreAfterBufLen += (bpp/8); \
262 memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbRectangle); \
263 rreAfterBufLen += sz_rfbRectangle; \
266 * Now mark the subrect as done. \
268 for (j=they; j < (they+theh); j++) { \
269 for (i=thex; i < (thex+thew); i++) { \
280 DEFINE_SUBRECT_ENCODE(8)
281 DEFINE_SUBRECT_ENCODE(16)
282 DEFINE_SUBRECT_ENCODE(32)
286 * getBgColour() gets the most prevalent colour in a byte array.
289 getBgColour(char *data, int size, int bpp)
294 static int counts[NUMCLRS];
302 return ((uint16_t *)data)[0];
303 } else if (bpp == 32) {
304 return ((uint32_t *)data)[0];
306 rfbLog("getBgColour: bpp %d?\n",bpp);
311 for (i=0; i<NUMCLRS; i++) {
315 for (j=0; j<size; j++) {
316 k = (int)(((uint8_t *)data)[j]);
318 rfbErr("getBgColour: unusual colour = %d\n", k);
322 if (counts[k] > maxcount) {
323 maxcount = counts[k];
324 maxclr = ((uint8_t *)data)[j];