4
* Routines to implement Compact Rise-and-Run-length Encoding (CoRRE). This
5
* code is based on krw's original javatel rfbserver.
9
* Copyright (C) 2002 RealVNC Ltd.
10
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
11
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
12
* All Rights Reserved.
14
* This is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License as published by
16
* the Free Software Foundation; either version 2 of the License, or
17
* (at your option) any later version.
19
* This software is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with this software; if not, write to the Free Software
26
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
33
* rreBeforeBuf contains pixel data in the client's format.
34
* rreAfterBuf contains the RRE encoded version. If the RRE encoded version is
35
* larger than the raw data or if it exceeds rreAfterBufSize then
36
* raw encoding is used instead.
39
static int rreBeforeBufSize = 0;
40
static char *rreBeforeBuf = NULL;
42
static int rreAfterBufSize = 0;
43
static char *rreAfterBuf = NULL;
44
static int rreAfterBufLen = 0;
46
static int subrectEncode8(uint8_t *data, int w, int h);
47
static int subrectEncode16(uint16_t *data, int w, int h);
48
static int subrectEncode32(uint32_t *data, int w, int h);
49
static uint32_t getBgColour(char *data, int size, int bpp);
50
static rfbBool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y,
53
void rfbCoRRECleanup(rfbScreenInfoPtr screen)
55
if (rreBeforeBufSize) {
59
if (rreAfterBufSize) {
66
* rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE
71
rfbSendRectEncodingCoRRE(rfbClientPtr cl,
77
if (h > cl->correMaxHeight) {
78
return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) &&
79
rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, w,
80
h - cl->correMaxHeight));
83
if (w > cl->correMaxWidth) {
84
return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) &&
85
rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y,
86
w - cl->correMaxWidth, h));
89
rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h);
96
* rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256)
97
* rectangle using CoRRE encoding.
101
rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl,
107
rfbFramebufferUpdateRectHeader rect;
111
char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
112
+ (x * (cl->scaledScreen->bitsPerPixel / 8)));
114
int maxRawSize = (cl->scaledScreen->width * cl->scaledScreen->height
115
* (cl->format.bitsPerPixel / 8));
117
if (rreBeforeBufSize < maxRawSize) {
118
rreBeforeBufSize = maxRawSize;
119
if (rreBeforeBuf == NULL)
120
rreBeforeBuf = (char *)malloc(rreBeforeBufSize);
122
rreBeforeBuf = (char *)realloc(rreBeforeBuf, rreBeforeBufSize);
125
if (rreAfterBufSize < maxRawSize) {
126
rreAfterBufSize = maxRawSize;
127
if (rreAfterBuf == NULL)
128
rreAfterBuf = (char *)malloc(rreAfterBufSize);
130
rreAfterBuf = (char *)realloc(rreAfterBuf, rreAfterBufSize);
133
(*cl->translateFn)(cl->translateLookupTable,&(cl->screen->serverFormat),
134
&cl->format, fbptr, rreBeforeBuf,
135
cl->scaledScreen->paddedWidthInBytes, w, h);
137
switch (cl->format.bitsPerPixel) {
139
nSubrects = subrectEncode8((uint8_t *)rreBeforeBuf, w, h);
142
nSubrects = subrectEncode16((uint16_t *)rreBeforeBuf, w, h);
145
nSubrects = subrectEncode32((uint32_t *)rreBeforeBuf, w, h);
148
rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
154
/* RRE encoding was too large, use raw */
156
return rfbSendRectEncodingRaw(cl, x, y, w, h);
159
rfbStatRecordEncodingSent(cl,rfbEncodingCoRRE,
160
sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + rreAfterBufLen,
161
sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8));
163
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
166
if (!rfbSendUpdateBuf(cl))
170
rect.r.x = Swap16IfLE(x);
171
rect.r.y = Swap16IfLE(y);
172
rect.r.w = Swap16IfLE(w);
173
rect.r.h = Swap16IfLE(h);
174
rect.encoding = Swap32IfLE(rfbEncodingCoRRE);
176
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
177
sz_rfbFramebufferUpdateRectHeader);
178
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
180
hdr.nSubrects = Swap32IfLE(nSubrects);
182
memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader);
183
cl->ublen += sz_rfbRREHeader;
185
for (i = 0; i < rreAfterBufLen;) {
187
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
189
if (i + bytesToCopy > rreAfterBufLen) {
190
bytesToCopy = rreAfterBufLen - i;
193
memcpy(&cl->updateBuf[cl->ublen], &rreAfterBuf[i], bytesToCopy);
195
cl->ublen += bytesToCopy;
198
if (cl->ublen == UPDATE_BUF_SIZE) {
199
if (!rfbSendUpdateBuf(cl))
210
* subrectEncode() encodes the given multicoloured rectangle as a background
211
* colour overwritten by single-coloured rectangles. It returns the number
212
* of subrectangles in the encoded buffer, or -1 if subrect encoding won't
213
* fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The
214
* single-colour rectangle partition is not optimal, but does find the biggest
215
* horizontal or vertical rectangle top-left anchored to each consecutive
216
* coordinate position.
218
* The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
219
* <subrect> is [<colour><x><y><w><h>].
222
#define DEFINE_SUBRECT_ENCODE(bpp) \
224
subrectEncode##bpp(uint##bpp##_t *data, int w, int h) { \
226
rfbCoRRERectangle subrect; \
229
int hx=0,hy,vx=0,vy; \
231
uint##bpp##_t *seg; \
232
uint##bpp##_t *line; \
234
int thex,they,thew,theh; \
237
uint##bpp##_t bg = (uint##bpp##_t)getBgColour((char*)data,w*h,bpp); \
239
*((uint##bpp##_t*)rreAfterBuf) = bg; \
241
rreAfterBufLen = (bpp/8); \
243
for (y=0; y<h; y++) { \
245
for (x=0; x<w; x++) { \
246
if (line[x] != bg) { \
250
for (j=y; j<h; j++) { \
252
if (seg[x] != cl) {break;} \
254
while ((seg[i] == cl) && (i < w)) i += 1; \
256
if (j == y) vx = hx = i; \
257
if (i < vx) vx = i; \
258
if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
262
/* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
263
* We'll choose the bigger of the two. \
273
if ((hw*hh) > (vw*vh)) { \
286
newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle; \
287
if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \
291
*((uint##bpp##_t*)(rreAfterBuf + rreAfterBufLen)) = cl; \
292
rreAfterBufLen += (bpp/8); \
293
memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle); \
294
rreAfterBufLen += sz_rfbCoRRERectangle; \
297
* Now mark the subrect as done. \
299
for (j=they; j < (they+theh); j++) { \
300
for (i=thex; i < (thex+thew); i++) { \
311
DEFINE_SUBRECT_ENCODE(8)
312
DEFINE_SUBRECT_ENCODE(16)
313
DEFINE_SUBRECT_ENCODE(32)
317
* getBgColour() gets the most prevalent colour in a byte array.
320
getBgColour(char *data, int size, int bpp)
325
static int counts[NUMCLRS];
333
return ((uint16_t *)data)[0];
334
} else if (bpp == 32) {
335
return ((uint32_t *)data)[0];
337
rfbLog("getBgColour: bpp %d?\n",bpp);
342
for (i=0; i<NUMCLRS; i++) {
346
for (j=0; j<size; j++) {
347
k = (int)(((uint8_t *)data)[j]);
349
rfbLog("getBgColour: unusual colour = %d\n", k);
353
if (counts[k] > maxcount) {
354
maxcount = counts[k];
355
maxclr = ((uint8_t *)data)[j];