4
* Routines to implement zlib based encoding (deflate).
8
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
9
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
11
* This is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* This software is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with this software; if not, write to the Free Software
23
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26
* For the latest source code, please check:
28
* http://www.developVNC.org/
30
* or send email to feedback@developvnc.org.
36
* zlibBeforeBuf contains pixel data in the client's format.
37
* zlibAfterBuf contains the zlib (deflated) encoding version.
38
* If the zlib compressed/encoded version is
39
* larger than the raw data or if it exceeds zlibAfterBufSize then
40
* raw encoding is used instead.
43
static int zlibBeforeBufSize = 0;
44
static char *zlibBeforeBuf = NULL;
46
static int zlibAfterBufSize = 0;
47
static char *zlibAfterBuf = NULL;
48
static int zlibAfterBufLen;
51
* rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
56
rfbSendOneRectEncodingZlib(cl, x, y, w, h)
60
rfbFramebufferUpdateRectHeader rect;
65
char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
66
+ (x * (cl->screen->bitsPerPixel / 8)));
71
maxRawSize = (cl->screen->width * cl->screen->height
72
* (cl->format.bitsPerPixel / 8));
74
if (zlibBeforeBufSize < maxRawSize) {
75
zlibBeforeBufSize = maxRawSize;
76
if (zlibBeforeBuf == NULL)
77
zlibBeforeBuf = (char *)malloc(zlibBeforeBufSize);
79
zlibBeforeBuf = (char *)realloc(zlibBeforeBuf, zlibBeforeBufSize);
82
/* zlib compression is not useful for very small data sets.
83
* So, we just send these raw without any compression.
85
if (( w * h * (cl->screen->bitsPerPixel / 8)) <
86
VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) {
90
/* The translation function (used also by the in raw encoding)
91
* requires 4/2/1 byte alignment in the output buffer (which is
92
* updateBuf for the raw encoding) based on the bitsPerPixel of
93
* the viewer/client. This prevents SIGBUS errors on some
94
* architectures like SPARC, PARISC...
96
if (( cl->format.bitsPerPixel > 8 ) &&
97
( cl->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) {
98
if (!rfbSendUpdateBuf(cl))
102
result = rfbSendRectEncodingRaw(cl, x, y, w, h);
109
* zlib requires output buffer to be slightly larger than the input
110
* buffer, in the worst case.
112
maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12;
114
if (zlibAfterBufSize < maxCompSize) {
115
zlibAfterBufSize = maxCompSize;
116
if (zlibAfterBuf == NULL)
117
zlibAfterBuf = (char *)malloc(zlibAfterBufSize);
119
zlibAfterBuf = (char *)realloc(zlibAfterBuf, zlibAfterBufSize);
123
* Convert pixel data to client format.
125
(*cl->translateFn)(cl->translateLookupTable, &cl->screen->rfbServerFormat,
126
&cl->format, fbptr, zlibBeforeBuf,
127
cl->screen->paddedWidthInBytes, w, h);
129
cl->compStream.next_in = ( Bytef * )zlibBeforeBuf;
130
cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8);
131
cl->compStream.next_out = ( Bytef * )zlibAfterBuf;
132
cl->compStream.avail_out = maxCompSize;
133
cl->compStream.data_type = Z_BINARY;
135
/* Initialize the deflation state. */
136
if ( cl->compStreamInited == FALSE ) {
138
cl->compStream.total_in = 0;
139
cl->compStream.total_out = 0;
140
cl->compStream.zalloc = Z_NULL;
141
cl->compStream.zfree = Z_NULL;
142
cl->compStream.opaque = Z_NULL;
144
deflateInit2( &(cl->compStream),
145
cl->zlibCompressLevel,
149
Z_DEFAULT_STRATEGY );
150
/* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */
151
/* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */
152
cl->compStreamInited = TRUE;
156
previousOut = cl->compStream.total_out;
158
/* Perform the compression here. */
159
deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH );
161
/* Find the total size of the resulting compressed data. */
162
zlibAfterBufLen = cl->compStream.total_out - previousOut;
164
if ( deflateResult != Z_OK ) {
165
rfbErr("zlib deflation error: %s\n", cl->compStream.msg);
169
/* Note that it is not possible to switch zlib parameters based on
170
* the results of the compression pass. The reason is
171
* that we rely on the compressor and decompressor states being
172
* in sync. Compressing and then discarding the results would
173
* cause lose of synchronization.
177
cl->rfbRectanglesSent[rfbEncodingZlib]++;
178
cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader
179
+ sz_rfbZlibHeader + zlibAfterBufLen);
181
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
184
if (!rfbSendUpdateBuf(cl))
188
rect.r.x = Swap16IfLE(x);
189
rect.r.y = Swap16IfLE(y);
190
rect.r.w = Swap16IfLE(w);
191
rect.r.h = Swap16IfLE(h);
192
rect.encoding = Swap32IfLE(rfbEncodingZlib);
194
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
195
sz_rfbFramebufferUpdateRectHeader);
196
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
198
hdr.nBytes = Swap32IfLE(zlibAfterBufLen);
200
memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
201
cl->ublen += sz_rfbZlibHeader;
203
for (i = 0; i < zlibAfterBufLen;) {
205
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
207
if (i + bytesToCopy > zlibAfterBufLen) {
208
bytesToCopy = zlibAfterBufLen - i;
211
memcpy(&cl->updateBuf[cl->ublen], &zlibAfterBuf[i], bytesToCopy);
213
cl->ublen += bytesToCopy;
216
if (cl->ublen == UPDATE_BUF_SIZE) {
217
if (!rfbSendUpdateBuf(cl))
228
* rfbSendRectEncodingZlib - send a given rectangle using one or more
229
* Zlib encoding rectangles.
233
rfbSendRectEncodingZlib(cl, x, y, w, h)
239
rfbRectangle partialRect;
246
/* Determine maximum pixel/scan lines allowed per rectangle. */
247
maxLines = ( ZLIB_MAX_SIZE(w) / w );
249
/* Initialize number of scan lines left to do. */
252
/* Loop until all work is done. */
253
while ( linesRemaining > 0 ) {
257
if ( maxLines < linesRemaining )
258
linesToComp = maxLines;
260
linesToComp = linesRemaining;
262
partialRect.h = linesToComp;
264
/* Encode (compress) and send the next rectangle. */
265
if ( ! rfbSendOneRectEncodingZlib( cl,
274
/* Technically, flushing the buffer here is not extrememly
275
* efficient. However, this improves the overall throughput
276
* of the system over very slow networks. By flushing
277
* the buffer with every maximum size zlib rectangle, we
278
* improve the pipelining usage of the server CPU, network,
279
* and viewer CPU components. Insuring that these components
280
* are working in parallel actually improves the performance
282
* Since, zlib is most useful for slow networks, this flush
283
* is appropriate for the desired behavior of the zlib encoding.
285
if (( cl->ublen > 0 ) &&
286
( linesToComp == maxLines )) {
287
if (!rfbSendUpdateBuf(cl)) {
293
/* Update remaining and incremental rectangle location. */
294
linesRemaining -= linesToComp;
295
partialRect.y += linesToComp;