2 * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
3 * Copyright (C) 2003 Sun Microsystems, Inc.
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.
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.
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,
24 * Routines to implement Zlib Run-length Encoding (ZRLE).
29 #include "zrleoutstream.h"
32 #define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf) \
33 { char *fbptr = (cl->scaledScreen->frameBuffer \
34 + (cl->scaledScreen->paddedWidthInBytes * ty) \
35 + (tx * (cl->scaledScreen->bitsPerPixel / 8))); \
37 (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,\
38 &cl->format, fbptr, (char*)buf, \
39 cl->scaledScreen->paddedWidthInBytes, tw, th); }
41 #define EXTRA_ARGS , rfbClientPtr cl
43 #define ENDIAN_LITTLE 0
47 #define ZYWRLE_ENDIAN ENDIAN_NO
48 #include <zrleencodetemplate.c>
52 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
53 #include <zrleencodetemplate.c>
55 #define ZYWRLE_ENDIAN ENDIAN_BIG
56 #include <zrleencodetemplate.c>
60 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
61 #include <zrleencodetemplate.c>
63 #define ZYWRLE_ENDIAN ENDIAN_BIG
64 #include <zrleencodetemplate.c>
68 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
69 #include <zrleencodetemplate.c>
71 #define ZYWRLE_ENDIAN ENDIAN_BIG
72 #include <zrleencodetemplate.c>
75 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
76 #include <zrleencodetemplate.c>
78 #define ZYWRLE_ENDIAN ENDIAN_BIG
79 #include <zrleencodetemplate.c>
83 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
84 #include <zrleencodetemplate.c>
86 #define ZYWRLE_ENDIAN ENDIAN_BIG
87 #include <zrleencodetemplate.c>
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
99 /* TODO: put into rfbClient struct */
100 static char zrleBeforeBuf[rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4];
105 * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding.
109 rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
112 rfbFramebufferUpdateRectHeader rect;
116 if (cl->preferredEncoding == rfbEncodingZYWRLE) {
117 if (cl->tightQualityLevel < 0) {
119 } else if (cl->tightQualityLevel < 3) {
121 } else if (cl->tightQualityLevel < 6) {
130 cl->zrleData = zrleOutStreamNew();
132 zos->in.ptr = zos->in.start;
133 zos->out.ptr = zos->out.start;
135 switch (cl->format.bitsPerPixel) {
138 zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl);
142 if (cl->format.greenMax > 0x1F) {
143 if (cl->format.bigEndian)
144 zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl);
146 zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl);
148 if (cl->format.bigEndian)
149 zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl);
151 zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl);
156 rfbBool fitsInLS3Bytes
157 = ((cl->format.redMax << cl->format.redShift) < (1<<24) &&
158 (cl->format.greenMax << cl->format.greenShift) < (1<<24) &&
159 (cl->format.blueMax << cl->format.blueShift) < (1<<24));
161 rfbBool fitsInMS3Bytes = (cl->format.redShift > 7 &&
162 cl->format.greenShift > 7 &&
163 cl->format.blueShift > 7);
165 if ((fitsInLS3Bytes && !cl->format.bigEndian) ||
166 (fitsInMS3Bytes && cl->format.bigEndian)) {
167 if (cl->format.bigEndian)
168 zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl);
170 zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl);
172 else if ((fitsInLS3Bytes && cl->format.bigEndian) ||
173 (fitsInMS3Bytes && !cl->format.bigEndian)) {
174 if (cl->format.bigEndian)
175 zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl);
177 zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl);
180 if (cl->format.bigEndian)
181 zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl);
183 zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl);
189 rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out),
190 + w * (cl->format.bitsPerPixel / 8) * h);
192 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
195 if (!rfbSendUpdateBuf(cl))
199 rect.r.x = Swap16IfLE(x);
200 rect.r.y = Swap16IfLE(y);
201 rect.r.w = Swap16IfLE(w);
202 rect.r.h = Swap16IfLE(h);
203 rect.encoding = Swap32IfLE(cl->preferredEncoding);
205 memcpy(cl->updateBuf+cl->ublen, (char *)&rect,
206 sz_rfbFramebufferUpdateRectHeader);
207 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
209 hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out));
211 memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader);
212 cl->ublen += sz_rfbZRLEHeader;
214 /* copy into updateBuf and send from there. Maybe should send directly? */
216 for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) {
218 int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
220 if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) {
221 bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i;
224 memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy);
226 cl->ublen += bytesToCopy;
229 if (cl->ublen == UPDATE_BUF_SIZE) {
230 if (!rfbSendUpdateBuf(cl))
239 void rfbFreeZrleData(rfbClientPtr cl)
242 zrleOutStreamFree(cl->zrleData);