~ubuntu-branches/debian/lenny/italc/lenny

« back to all changes in this revision

Viewing changes to ica/x11/libvncserver/zlib.c

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mfrom: (1.2.1 upstream) (4.1.1 gutsy)
  • Revision ID: james.westby@ubuntu.com-20080617134654-cl0gi4u524cv1ici
Tags: 1:1.0.9~rc3-1
* Package new upstream version
  - upstream ported the code to qt4.4 (Closes: #481974)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * zlib.c
 
3
 *
 
4
 * Routines to implement zlib based encoding (deflate).
 
5
 */
 
6
 
 
7
/*
 
8
 *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
 
9
 *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
 
10
 *
 
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.
 
15
 *
 
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.
 
20
 *
 
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,
 
24
 *  USA.
 
25
 *
 
26
 * For the latest source code, please check:
 
27
 *
 
28
 * http://www.developVNC.org/
 
29
 *
 
30
 * or send email to feedback@developvnc.org.
 
31
 */
 
32
 
 
33
#include <rfb/rfb.h>
 
34
 
 
35
/*
 
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.
 
41
 */
 
42
 
 
43
static int zlibBeforeBufSize = 0;
 
44
static char *zlibBeforeBuf = NULL;
 
45
 
 
46
static int zlibAfterBufSize = 0;
 
47
static char *zlibAfterBuf = NULL;
 
48
static int zlibAfterBufLen;
 
49
 
 
50
void rfbZlibCleanup(rfbScreenInfoPtr screen)
 
51
{
 
52
  if (zlibBeforeBufSize) {
 
53
    free(zlibBeforeBuf);
 
54
    zlibBeforeBufSize=0;
 
55
  }
 
56
  if (zlibAfterBufSize) {
 
57
    zlibAfterBufSize=0;
 
58
    free(zlibAfterBuf);
 
59
  }
 
60
}
 
61
 
 
62
 
 
63
/*
 
64
 * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
 
65
 *                              rectangle encoding.
 
66
 */
 
67
 
 
68
static rfbBool
 
69
rfbSendOneRectEncodingZlib(rfbClientPtr cl,
 
70
                           int x,
 
71
                           int y,
 
72
                           int w,
 
73
                           int h)
 
74
{
 
75
    rfbFramebufferUpdateRectHeader rect;
 
76
    rfbZlibHeader hdr;
 
77
    int deflateResult;
 
78
    int previousOut;
 
79
    int i;
 
80
    char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
 
81
           + (x * (cl->scaledScreen->bitsPerPixel / 8)));
 
82
 
 
83
    int maxRawSize;
 
84
    int maxCompSize;
 
85
 
 
86
    maxRawSize = (cl->scaledScreen->width * cl->scaledScreen->height
 
87
                  * (cl->format.bitsPerPixel / 8));
 
88
 
 
89
    if (zlibBeforeBufSize < maxRawSize) {
 
90
        zlibBeforeBufSize = maxRawSize;
 
91
        if (zlibBeforeBuf == NULL)
 
92
            zlibBeforeBuf = (char *)malloc(zlibBeforeBufSize);
 
93
        else
 
94
            zlibBeforeBuf = (char *)realloc(zlibBeforeBuf, zlibBeforeBufSize);
 
95
    }
 
96
 
 
97
    /* zlib compression is not useful for very small data sets.
 
98
     * So, we just send these raw without any compression.
 
99
     */
 
100
    if (( w * h * (cl->scaledScreen->bitsPerPixel / 8)) <
 
101
          VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) {
 
102
 
 
103
        int result;
 
104
 
 
105
        /* The translation function (used also by the in raw encoding)
 
106
         * requires 4/2/1 byte alignment in the output buffer (which is
 
107
         * updateBuf for the raw encoding) based on the bitsPerPixel of
 
108
         * the viewer/client.  This prevents SIGBUS errors on some
 
109
         * architectures like SPARC, PARISC...
 
110
         */
 
111
        if (( cl->format.bitsPerPixel > 8 ) &&
 
112
            ( cl->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) {
 
113
            if (!rfbSendUpdateBuf(cl))
 
114
                return FALSE;
 
115
        }
 
116
 
 
117
        result = rfbSendRectEncodingRaw(cl, x, y, w, h);
 
118
 
 
119
        return result;
 
120
 
 
121
    }
 
122
 
 
123
    /*
 
124
     * zlib requires output buffer to be slightly larger than the input
 
125
     * buffer, in the worst case.
 
126
     */
 
127
    maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12;
 
128
 
 
129
    if (zlibAfterBufSize < maxCompSize) {
 
130
        zlibAfterBufSize = maxCompSize;
 
131
        if (zlibAfterBuf == NULL)
 
132
            zlibAfterBuf = (char *)malloc(zlibAfterBufSize);
 
133
        else
 
134
            zlibAfterBuf = (char *)realloc(zlibAfterBuf, zlibAfterBufSize);
 
135
    }
 
136
 
 
137
 
 
138
    /* 
 
139
     * Convert pixel data to client format.
 
140
     */
 
141
    (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
 
142
                       &cl->format, fbptr, zlibBeforeBuf,
 
143
                       cl->scaledScreen->paddedWidthInBytes, w, h);
 
144
 
 
145
    cl->compStream.next_in = ( Bytef * )zlibBeforeBuf;
 
146
    cl->compStream.avail_in = w * h * (cl->format.bitsPerPixel / 8);
 
147
    cl->compStream.next_out = ( Bytef * )zlibAfterBuf;
 
148
    cl->compStream.avail_out = maxCompSize;
 
149
    cl->compStream.data_type = Z_BINARY;
 
150
 
 
151
    /* Initialize the deflation state. */
 
152
    if ( cl->compStreamInited == FALSE ) {
 
153
 
 
154
        cl->compStream.total_in = 0;
 
155
        cl->compStream.total_out = 0;
 
156
        cl->compStream.zalloc = Z_NULL;
 
157
        cl->compStream.zfree = Z_NULL;
 
158
        cl->compStream.opaque = Z_NULL;
 
159
 
 
160
        deflateInit2( &(cl->compStream),
 
161
                        cl->zlibCompressLevel,
 
162
                        Z_DEFLATED,
 
163
                        MAX_WBITS,
 
164
                        MAX_MEM_LEVEL,
 
165
                        Z_DEFAULT_STRATEGY );
 
166
        /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */
 
167
        /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */
 
168
        cl->compStreamInited = TRUE;
 
169
 
 
170
    }
 
171
 
 
172
    previousOut = cl->compStream.total_out;
 
173
 
 
174
    /* Perform the compression here. */
 
175
    deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH );
 
176
 
 
177
    /* Find the total size of the resulting compressed data. */
 
178
    zlibAfterBufLen = cl->compStream.total_out - previousOut;
 
179
 
 
180
    if ( deflateResult != Z_OK ) {
 
181
        rfbErr("zlib deflation error: %s\n", cl->compStream.msg);
 
182
        return FALSE;
 
183
    }
 
184
 
 
185
    /* Note that it is not possible to switch zlib parameters based on
 
186
     * the results of the compression pass.  The reason is
 
187
     * that we rely on the compressor and decompressor states being
 
188
     * in sync.  Compressing and then discarding the results would
 
189
     * cause lose of synchronization.
 
190
     */
 
191
 
 
192
    /* Update statics */
 
193
    rfbStatRecordEncodingSent(cl, rfbEncodingZlib, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + zlibAfterBufLen,
 
194
        + w * (cl->format.bitsPerPixel / 8) * h);
 
195
 
 
196
    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
 
197
        > UPDATE_BUF_SIZE)
 
198
    {
 
199
        if (!rfbSendUpdateBuf(cl))
 
200
            return FALSE;
 
201
    }
 
202
 
 
203
    rect.r.x = Swap16IfLE(x);
 
204
    rect.r.y = Swap16IfLE(y);
 
205
    rect.r.w = Swap16IfLE(w);
 
206
    rect.r.h = Swap16IfLE(h);
 
207
    rect.encoding = Swap32IfLE(rfbEncodingZlib);
 
208
 
 
209
    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
 
210
           sz_rfbFramebufferUpdateRectHeader);
 
211
    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
 
212
 
 
213
    hdr.nBytes = Swap32IfLE(zlibAfterBufLen);
 
214
 
 
215
    memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
 
216
    cl->ublen += sz_rfbZlibHeader;
 
217
 
 
218
    for (i = 0; i < zlibAfterBufLen;) {
 
219
 
 
220
        int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
 
221
 
 
222
        if (i + bytesToCopy > zlibAfterBufLen) {
 
223
            bytesToCopy = zlibAfterBufLen - i;
 
224
        }
 
225
 
 
226
        memcpy(&cl->updateBuf[cl->ublen], &zlibAfterBuf[i], bytesToCopy);
 
227
 
 
228
        cl->ublen += bytesToCopy;
 
229
        i += bytesToCopy;
 
230
 
 
231
        if (cl->ublen == UPDATE_BUF_SIZE) {
 
232
            if (!rfbSendUpdateBuf(cl))
 
233
                return FALSE;
 
234
        }
 
235
    }
 
236
 
 
237
    return TRUE;
 
238
 
 
239
}
 
240
 
 
241
 
 
242
/*
 
243
 * rfbSendRectEncodingZlib - send a given rectangle using one or more
 
244
 *                           Zlib encoding rectangles.
 
245
 */
 
246
 
 
247
rfbBool
 
248
rfbSendRectEncodingZlib(rfbClientPtr cl,
 
249
                        int x,
 
250
                        int y,
 
251
                        int w,
 
252
                        int h)
 
253
{
 
254
    int  maxLines;
 
255
    int  linesRemaining;
 
256
    rfbRectangle partialRect;
 
257
 
 
258
    partialRect.x = x;
 
259
    partialRect.y = y;
 
260
    partialRect.w = w;
 
261
    partialRect.h = h;
 
262
 
 
263
    /* Determine maximum pixel/scan lines allowed per rectangle. */
 
264
    maxLines = ( ZLIB_MAX_SIZE(w) / w );
 
265
 
 
266
    /* Initialize number of scan lines left to do. */
 
267
    linesRemaining = h;
 
268
 
 
269
    /* Loop until all work is done. */
 
270
    while ( linesRemaining > 0 ) {
 
271
 
 
272
        int linesToComp;
 
273
 
 
274
        if ( maxLines < linesRemaining )
 
275
            linesToComp = maxLines;
 
276
        else
 
277
            linesToComp = linesRemaining;
 
278
 
 
279
        partialRect.h = linesToComp;
 
280
 
 
281
        /* Encode (compress) and send the next rectangle. */
 
282
        if ( ! rfbSendOneRectEncodingZlib( cl,
 
283
                                           partialRect.x,
 
284
                                           partialRect.y,
 
285
                                           partialRect.w,
 
286
                                           partialRect.h )) {
 
287
 
 
288
            return FALSE;
 
289
        }
 
290
 
 
291
        /* Technically, flushing the buffer here is not extrememly
 
292
         * efficient.  However, this improves the overall throughput
 
293
         * of the system over very slow networks.  By flushing
 
294
         * the buffer with every maximum size zlib rectangle, we
 
295
         * improve the pipelining usage of the server CPU, network,
 
296
         * and viewer CPU components.  Insuring that these components
 
297
         * are working in parallel actually improves the performance
 
298
         * seen by the user.
 
299
         * Since, zlib is most useful for slow networks, this flush
 
300
         * is appropriate for the desired behavior of the zlib encoding.
 
301
         */
 
302
        if (( cl->ublen > 0 ) &&
 
303
            ( linesToComp == maxLines )) {
 
304
            if (!rfbSendUpdateBuf(cl)) {
 
305
 
 
306
                return FALSE;
 
307
            }
 
308
        }
 
309
 
 
310
        /* Update remaining and incremental rectangle location. */
 
311
        linesRemaining -= linesToComp;
 
312
        partialRect.y += linesToComp;
 
313
 
 
314
    }
 
315
 
 
316
    return TRUE;
 
317
 
 
318
}
 
319