You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
7.1 KiB
257 lines
7.1 KiB
/* |
|
* Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. |
|
* Copyright (C) 2003 Sun Microsystems, Inc. |
|
* |
|
* 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. |
|
*/ |
|
|
|
/* |
|
* zrle.c |
|
* |
|
* Routines to implement Zlib Run-length Encoding (ZRLE). |
|
*/ |
|
|
|
#include "rfb/rfb.h" |
|
#include "private.h" |
|
#include "zrleoutstream.h" |
|
|
|
|
|
#define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf) \ |
|
{ char *fbptr = (cl->scaledScreen->frameBuffer \ |
|
+ (cl->scaledScreen->paddedWidthInBytes * ty) \ |
|
+ (tx * (cl->scaledScreen->bitsPerPixel / 8))); \ |
|
\ |
|
(*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,\ |
|
&cl->format, fbptr, (char*)buf, \ |
|
cl->scaledScreen->paddedWidthInBytes, tw, th); } |
|
|
|
#define EXTRA_ARGS , rfbClientPtr cl |
|
|
|
#define ENDIAN_LITTLE 0 |
|
#define ENDIAN_BIG 1 |
|
#define ENDIAN_NO 2 |
|
#define BPP 8 |
|
#define ZYWRLE_ENDIAN ENDIAN_NO |
|
#include <zrleencodetemplate.c> |
|
#undef BPP |
|
#define BPP 15 |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_LITTLE |
|
#include <zrleencodetemplate.c> |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_BIG |
|
#include <zrleencodetemplate.c> |
|
#undef BPP |
|
#define BPP 16 |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_LITTLE |
|
#include <zrleencodetemplate.c> |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_BIG |
|
#include <zrleencodetemplate.c> |
|
#undef BPP |
|
#define BPP 32 |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_LITTLE |
|
#include <zrleencodetemplate.c> |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_BIG |
|
#include <zrleencodetemplate.c> |
|
#define CPIXEL 24A |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_LITTLE |
|
#include <zrleencodetemplate.c> |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_BIG |
|
#include <zrleencodetemplate.c> |
|
#undef CPIXEL |
|
#define CPIXEL 24B |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_LITTLE |
|
#include <zrleencodetemplate.c> |
|
#undef ZYWRLE_ENDIAN |
|
#define ZYWRLE_ENDIAN ENDIAN_BIG |
|
#include <zrleencodetemplate.c> |
|
#undef CPIXEL |
|
#undef BPP |
|
|
|
|
|
/* |
|
* zrleBeforeBuf contains pixel data in the client's format. It must be at |
|
* least one pixel bigger than the largest tile of pixel data, since the |
|
* ZRLE encoding algorithm writes to the position one past the end of the pixel |
|
* data. |
|
*/ |
|
|
|
|
|
/* |
|
* rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding. |
|
*/ |
|
|
|
rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h) |
|
{ |
|
zrleOutStream* zos; |
|
rfbFramebufferUpdateRectHeader rect; |
|
rfbZRLEHeader hdr; |
|
int i; |
|
char *zrleBeforeBuf; |
|
|
|
if (cl->zrleBeforeBuf == NULL) { |
|
cl->zrleBeforeBuf = (char *) malloc(rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4); |
|
} |
|
zrleBeforeBuf = cl->zrleBeforeBuf; |
|
|
|
if (cl->preferredEncoding == rfbEncodingZYWRLE) { |
|
if (cl->tightQualityLevel < 0) { |
|
cl->zywrleLevel = 1; |
|
} else if (cl->tightQualityLevel < 3) { |
|
cl->zywrleLevel = 3; |
|
} else if (cl->tightQualityLevel < 6) { |
|
cl->zywrleLevel = 2; |
|
} else { |
|
cl->zywrleLevel = 1; |
|
} |
|
} else |
|
cl->zywrleLevel = 0; |
|
|
|
if (!cl->zrleData) |
|
cl->zrleData = zrleOutStreamNew(); |
|
zos = cl->zrleData; |
|
zos->in.ptr = zos->in.start; |
|
zos->out.ptr = zos->out.start; |
|
|
|
switch (cl->format.bitsPerPixel) { |
|
|
|
case 8: |
|
zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
break; |
|
|
|
case 16: |
|
if (cl->format.greenMax > 0x1F) { |
|
if (cl->format.bigEndian) |
|
zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
else |
|
zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
} else { |
|
if (cl->format.bigEndian) |
|
zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
else |
|
zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
} |
|
break; |
|
|
|
case 32: { |
|
rfbBool fitsInLS3Bytes |
|
= ((cl->format.redMax << cl->format.redShift) < (1<<24) && |
|
(cl->format.greenMax << cl->format.greenShift) < (1<<24) && |
|
(cl->format.blueMax << cl->format.blueShift) < (1<<24)); |
|
|
|
rfbBool fitsInMS3Bytes = (cl->format.redShift > 7 && |
|
cl->format.greenShift > 7 && |
|
cl->format.blueShift > 7); |
|
|
|
if ((fitsInLS3Bytes && !cl->format.bigEndian) || |
|
(fitsInMS3Bytes && cl->format.bigEndian)) { |
|
if (cl->format.bigEndian) |
|
zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
else |
|
zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
} |
|
else if ((fitsInLS3Bytes && cl->format.bigEndian) || |
|
(fitsInMS3Bytes && !cl->format.bigEndian)) { |
|
if (cl->format.bigEndian) |
|
zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
else |
|
zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
} |
|
else { |
|
if (cl->format.bigEndian) |
|
zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
else |
|
zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl); |
|
} |
|
} |
|
break; |
|
} |
|
|
|
rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out), |
|
+ w * (cl->format.bitsPerPixel / 8) * h); |
|
|
|
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader |
|
> 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(cl->preferredEncoding); |
|
|
|
memcpy(cl->updateBuf+cl->ublen, (char *)&rect, |
|
sz_rfbFramebufferUpdateRectHeader); |
|
cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
|
|
|
hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out)); |
|
|
|
memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader); |
|
cl->ublen += sz_rfbZRLEHeader; |
|
|
|
/* copy into updateBuf and send from there. Maybe should send directly? */ |
|
|
|
for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) { |
|
|
|
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; |
|
|
|
if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) { |
|
bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i; |
|
} |
|
|
|
memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy); |
|
|
|
cl->ublen += bytesToCopy; |
|
i += bytesToCopy; |
|
|
|
if (cl->ublen == UPDATE_BUF_SIZE) { |
|
if (!rfbSendUpdateBuf(cl)) |
|
return FALSE; |
|
} |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
|
|
void rfbFreeZrleData(rfbClientPtr cl) |
|
{ |
|
if (cl->zrleData) { |
|
zrleOutStreamFree(cl->zrleData); |
|
} |
|
cl->zrleData = NULL; |
|
|
|
if (cl->zrleBeforeBuf) { |
|
free(cl->zrleBeforeBuf); |
|
} |
|
cl->zrleBeforeBuf = NULL; |
|
|
|
if (cl->paletteHelper) { |
|
free(cl->paletteHelper); |
|
} |
|
cl->paletteHelper = NULL; |
|
} |
|
|
|
|