diff options
Diffstat (limited to 'krfb/libvncserver/rre.c')
-rw-r--r-- | krfb/libvncserver/rre.c | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/krfb/libvncserver/rre.c b/krfb/libvncserver/rre.c new file mode 100644 index 00000000..9a552cb0 --- /dev/null +++ b/krfb/libvncserver/rre.c @@ -0,0 +1,322 @@ +/* + * rre.c + * + * Routines to implement Rise-and-Run-length Encoding (RRE). This + * code is based on krw's original javatel rfbserver. + */ + +/* + * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>. + * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge. + * All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <stdio.h> +#include "rfb.h" + +/* + * rreBeforeBuf contains pixel data in the client's format. + * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is + * larger than the raw data or if it exceeds rreAfterBufSize then + * raw encoding is used instead. + */ + +static int rreBeforeBufSize = 0; +static char *rreBeforeBuf = NULL; + +static int rreAfterBufSize = 0; +static char *rreAfterBuf = NULL; +static int rreAfterBufLen; + +static int subrectEncode8(CARD8 *data, int w, int h); +static int subrectEncode16(CARD16 *data, int w, int h); +static int subrectEncode32(CARD32 *data, int w, int h); +static CARD32 getBgColour(char *data, int size, int bpp); + + +/* + * rfbSendRectEncodingRRE - send a given rectangle using RRE encoding. + */ + +Bool +rfbSendRectEncodingRRE(cl, x, y, w, h) + rfbClientPtr cl; + int x, y, w, h; +{ + rfbFramebufferUpdateRectHeader rect; + rfbRREHeader hdr; + int nSubrects; + int i; + char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y) + + (x * (cl->screen->bitsPerPixel / 8))); + + int maxRawSize = (cl->screen->width * cl->screen->height + * (cl->format.bitsPerPixel / 8)); + + if (rreBeforeBufSize < maxRawSize) { + rreBeforeBufSize = maxRawSize; + if (rreBeforeBuf == NULL) + rreBeforeBuf = (char *)malloc(rreBeforeBufSize); + else + rreBeforeBuf = (char *)realloc(rreBeforeBuf, rreBeforeBufSize); + } + + if (rreAfterBufSize < maxRawSize) { + rreAfterBufSize = maxRawSize; + if (rreAfterBuf == NULL) + rreAfterBuf = (char *)malloc(rreAfterBufSize); + else + rreAfterBuf = (char *)realloc(rreAfterBuf, rreAfterBufSize); + } + + (*cl->translateFn)(cl->translateLookupTable, + &(cl->screen->rfbServerFormat), + &cl->format, fbptr, rreBeforeBuf, + cl->screen->paddedWidthInBytes, w, h); + + switch (cl->format.bitsPerPixel) { + case 8: + nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h); + break; + case 16: + nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h); + break; + case 32: + nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h); + break; + default: + rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); + exit(1); + } + + if (nSubrects < 0) { + + /* RRE encoding was too large, use raw */ + + return rfbSendRectEncodingRaw(cl, x, y, w, h); + } + + cl->rfbRectanglesSent[rfbEncodingRRE]++; + cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader + + sz_rfbRREHeader + rreAfterBufLen); + + if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + > UPDATE_BUF_SIZE) + { + if (!rfbSendUpdateBuf(cl)) + return FALSE; + } + + rect.r.x = Swap16IfLE(x); + rect.r.y = Swap16IfLE(y); + rect.r.w = Swap16IfLE(w); + rect.r.h = Swap16IfLE(h); + rect.encoding = Swap32IfLE(rfbEncodingRRE); + + memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, + sz_rfbFramebufferUpdateRectHeader); + cl->ublen += sz_rfbFramebufferUpdateRectHeader; + + hdr.nSubrects = Swap32IfLE(nSubrects); + + memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader); + cl->ublen += sz_rfbRREHeader; + + for (i = 0; i < rreAfterBufLen;) { + + int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; + + if (i + bytesToCopy > rreAfterBufLen) { + bytesToCopy = rreAfterBufLen - i; + } + + memcpy(&cl->updateBuf[cl->ublen], &rreAfterBuf[i], bytesToCopy); + + cl->ublen += bytesToCopy; + i += bytesToCopy; + + if (cl->ublen == UPDATE_BUF_SIZE) { + if (!rfbSendUpdateBuf(cl)) + return FALSE; + } + } + + return TRUE; +} + + + +/* + * subrectEncode() encodes the given multicoloured rectangle as a background + * colour overwritten by single-coloured rectangles. It returns the number + * of subrectangles in the encoded buffer, or -1 if subrect encoding won't + * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The + * single-colour rectangle partition is not optimal, but does find the biggest + * horizontal or vertical rectangle top-left anchored to each consecutive + * coordinate position. + * + * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each + * <subrect> is [<colour><x><y><w><h>]. + */ + +#define DEFINE_SUBRECT_ENCODE(bpp) \ +static int \ +subrectEncode##bpp(data,w,h) \ + CARD##bpp *data; \ + int w; \ + int h; \ +{ \ + CARD##bpp cl; \ + rfbRectangle subrect; \ + int x,y; \ + int i,j; \ + int hx=0,hy,vx=0,vy; \ + int hyflag; \ + CARD##bpp *seg; \ + CARD##bpp *line; \ + int hw,hh,vw,vh; \ + int thex,they,thew,theh; \ + int numsubs = 0; \ + int newLen; \ + CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp); \ + \ + *((CARD##bpp*)rreAfterBuf) = bg; \ + \ + rreAfterBufLen = (bpp/8); \ + \ + for (y=0; y<h; y++) { \ + line = data+(y*w); \ + for (x=0; x<w; x++) { \ + if (line[x] != bg) { \ + cl = line[x]; \ + hy = y-1; \ + hyflag = 1; \ + for (j=y; j<h; j++) { \ + seg = data+(j*w); \ + if (seg[x] != cl) {break;} \ + i = x; \ + while ((seg[i] == cl) && (i < w)) i += 1; \ + i -= 1; \ + if (j == y) vx = hx = i; \ + if (i < vx) vx = i; \ + if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \ + } \ + vy = j-1; \ + \ + /* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \ + * We'll choose the bigger of the two. \ + */ \ + hw = hx-x+1; \ + hh = hy-y+1; \ + vw = vx-x+1; \ + vh = vy-y+1; \ + \ + thex = x; \ + they = y; \ + \ + if ((hw*hh) > (vw*vh)) { \ + thew = hw; \ + theh = hh; \ + } else { \ + thew = vw; \ + theh = vh; \ + } \ + \ + subrect.x = Swap16IfLE(thex); \ + subrect.y = Swap16IfLE(they); \ + subrect.w = Swap16IfLE(thew); \ + subrect.h = Swap16IfLE(theh); \ + \ + newLen = rreAfterBufLen + (bpp/8) + sz_rfbRectangle; \ + if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \ + return -1; \ + \ + numsubs += 1; \ + *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl; \ + rreAfterBufLen += (bpp/8); \ + memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbRectangle); \ + rreAfterBufLen += sz_rfbRectangle; \ + \ + /* \ + * Now mark the subrect as done. \ + */ \ + for (j=they; j < (they+theh); j++) { \ + for (i=thex; i < (thex+thew); i++) { \ + data[j*w+i] = bg; \ + } \ + } \ + } \ + } \ + } \ + \ + return numsubs; \ +} + +DEFINE_SUBRECT_ENCODE(8) +DEFINE_SUBRECT_ENCODE(16) +DEFINE_SUBRECT_ENCODE(32) + + +/* + * getBgColour() gets the most prevalent colour in a byte array. + */ +static CARD32 +getBgColour(data,size,bpp) + char *data; + int size; + int bpp; +{ + +#define NUMCLRS 256 + + static int counts[NUMCLRS]; + int i,j,k; + + int maxcount = 0; + CARD8 maxclr = 0; + + if (bpp != 8) { + if (bpp == 16) { + return ((CARD16 *)data)[0]; + } else if (bpp == 32) { + return ((CARD32 *)data)[0]; + } else { + rfbLog("getBgColour: bpp %d?\n",bpp); + exit(1); + } + } + + for (i=0; i<NUMCLRS; i++) { + counts[i] = 0; + } + + for (j=0; j<size; j++) { + k = (int)(((CARD8 *)data)[j]); + if (k >= NUMCLRS) { + rfbLog("getBgColour: unusual colour = %d\n", k); + exit(1); + } + counts[k] += 1; + if (counts[k] > maxcount) { + maxcount = counts[k]; + maxclr = ((CARD8 *)data)[j]; + } + } + + return maxclr; +} |