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

« back to all changes in this revision

Viewing changes to common/ivs/libvncserver/zlib.c

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mto: This revision was merged to the branch mainline in revision 5.
  • Revision ID: james.westby@ubuntu.com-20080617134654-2y5m7ki93r5c1ysf
Tags: upstream-1.0.9~rc3
ImportĀ upstreamĀ versionĀ 1.0.9~rc3

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
 
/*
51
 
 * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
52
 
 *                              rectangle encoding.
53
 
 */
54
 
 
55
 
rfbBool
56
 
rfbSendOneRectEncodingZlib(cl, x, y, w, h)
57
 
    rfbClientPtr cl;
58
 
    int x, y, w, h;
59
 
{
60
 
    rfbFramebufferUpdateRectHeader rect;
61
 
    rfbZlibHeader hdr;
62
 
    int deflateResult;
63
 
    int previousOut;
64
 
    int i;
65
 
    char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
66
 
           + (x * (cl->screen->bitsPerPixel / 8)));
67
 
 
68
 
    int maxRawSize;
69
 
    int maxCompSize;
70
 
 
71
 
    maxRawSize = (cl->screen->width * cl->screen->height
72
 
                  * (cl->format.bitsPerPixel / 8));
73
 
 
74
 
    if (zlibBeforeBufSize < maxRawSize) {
75
 
        zlibBeforeBufSize = maxRawSize;
76
 
        if (zlibBeforeBuf == NULL)
77
 
            zlibBeforeBuf = (char *)malloc(zlibBeforeBufSize);
78
 
        else
79
 
            zlibBeforeBuf = (char *)realloc(zlibBeforeBuf, zlibBeforeBufSize);
80
 
    }
81
 
 
82
 
    /* zlib compression is not useful for very small data sets.
83
 
     * So, we just send these raw without any compression.
84
 
     */
85
 
    if (( w * h * (cl->screen->bitsPerPixel / 8)) <
86
 
          VNC_ENCODE_ZLIB_MIN_COMP_SIZE ) {
87
 
 
88
 
        int result;
89
 
 
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...
95
 
         */
96
 
        if (( cl->format.bitsPerPixel > 8 ) &&
97
 
            ( cl->ublen % ( cl->format.bitsPerPixel / 8 )) != 0 ) {
98
 
            if (!rfbSendUpdateBuf(cl))
99
 
                return FALSE;
100
 
        }
101
 
 
102
 
        result = rfbSendRectEncodingRaw(cl, x, y, w, h);
103
 
 
104
 
        return result;
105
 
 
106
 
    }
107
 
 
108
 
    /*
109
 
     * zlib requires output buffer to be slightly larger than the input
110
 
     * buffer, in the worst case.
111
 
     */
112
 
    maxCompSize = maxRawSize + (( maxRawSize + 99 ) / 100 ) + 12;
113
 
 
114
 
    if (zlibAfterBufSize < maxCompSize) {
115
 
        zlibAfterBufSize = maxCompSize;
116
 
        if (zlibAfterBuf == NULL)
117
 
            zlibAfterBuf = (char *)malloc(zlibAfterBufSize);
118
 
        else
119
 
            zlibAfterBuf = (char *)realloc(zlibAfterBuf, zlibAfterBufSize);
120
 
    }
121
 
 
122
 
    /* 
123
 
     * Convert pixel data to client format.
124
 
     */
125
 
    (*cl->translateFn)(cl->translateLookupTable, &cl->screen->rfbServerFormat,
126
 
                       &cl->format, fbptr, zlibBeforeBuf,
127
 
                       cl->screen->paddedWidthInBytes, w, h);
128
 
 
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;
134
 
 
135
 
    /* Initialize the deflation state. */
136
 
    if ( cl->compStreamInited == FALSE ) {
137
 
 
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;
143
 
 
144
 
        deflateInit2( &(cl->compStream),
145
 
                        cl->zlibCompressLevel,
146
 
                        Z_DEFLATED,
147
 
                        MAX_WBITS,
148
 
                        MAX_MEM_LEVEL,
149
 
                        Z_DEFAULT_STRATEGY );
150
 
        /* deflateInit( &(cl->compStream), Z_BEST_COMPRESSION ); */
151
 
        /* deflateInit( &(cl->compStream), Z_BEST_SPEED ); */
152
 
        cl->compStreamInited = TRUE;
153
 
 
154
 
    }
155
 
 
156
 
    previousOut = cl->compStream.total_out;
157
 
 
158
 
    /* Perform the compression here. */
159
 
    deflateResult = deflate( &(cl->compStream), Z_SYNC_FLUSH );
160
 
 
161
 
    /* Find the total size of the resulting compressed data. */
162
 
    zlibAfterBufLen = cl->compStream.total_out - previousOut;
163
 
 
164
 
    if ( deflateResult != Z_OK ) {
165
 
        rfbErr("zlib deflation error: %s\n", cl->compStream.msg);
166
 
        return FALSE;
167
 
    }
168
 
 
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.
174
 
     */
175
 
 
176
 
    /* Update statics */
177
 
    cl->rfbRectanglesSent[rfbEncodingZlib]++;
178
 
    cl->rfbBytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader
179
 
                                         + sz_rfbZlibHeader + zlibAfterBufLen);
180
 
 
181
 
    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
182
 
        > UPDATE_BUF_SIZE)
183
 
    {
184
 
        if (!rfbSendUpdateBuf(cl))
185
 
            return FALSE;
186
 
    }
187
 
 
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);
193
 
 
194
 
    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
195
 
           sz_rfbFramebufferUpdateRectHeader);
196
 
    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
197
 
 
198
 
    hdr.nBytes = Swap32IfLE(zlibAfterBufLen);
199
 
 
200
 
    memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
201
 
    cl->ublen += sz_rfbZlibHeader;
202
 
 
203
 
    for (i = 0; i < zlibAfterBufLen;) {
204
 
 
205
 
        int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
206
 
 
207
 
        if (i + bytesToCopy > zlibAfterBufLen) {
208
 
            bytesToCopy = zlibAfterBufLen - i;
209
 
        }
210
 
 
211
 
        memcpy(&cl->updateBuf[cl->ublen], &zlibAfterBuf[i], bytesToCopy);
212
 
 
213
 
        cl->ublen += bytesToCopy;
214
 
        i += bytesToCopy;
215
 
 
216
 
        if (cl->ublen == UPDATE_BUF_SIZE) {
217
 
            if (!rfbSendUpdateBuf(cl))
218
 
                return FALSE;
219
 
        }
220
 
    }
221
 
 
222
 
    return TRUE;
223
 
 
224
 
}
225
 
 
226
 
 
227
 
/*
228
 
 * rfbSendRectEncodingZlib - send a given rectangle using one or more
229
 
 *                           Zlib encoding rectangles.
230
 
 */
231
 
 
232
 
rfbBool
233
 
rfbSendRectEncodingZlib(cl, x, y, w, h)
234
 
    rfbClientPtr cl;
235
 
    int x, y, w, h;
236
 
{
237
 
    int  maxLines;
238
 
    int  linesRemaining;
239
 
    rfbRectangle partialRect;
240
 
 
241
 
    partialRect.x = x;
242
 
    partialRect.y = y;
243
 
    partialRect.w = w;
244
 
    partialRect.h = h;
245
 
 
246
 
    /* Determine maximum pixel/scan lines allowed per rectangle. */
247
 
    maxLines = ( ZLIB_MAX_SIZE(w) / w );
248
 
 
249
 
    /* Initialize number of scan lines left to do. */
250
 
    linesRemaining = h;
251
 
 
252
 
    /* Loop until all work is done. */
253
 
    while ( linesRemaining > 0 ) {
254
 
 
255
 
        int linesToComp;
256
 
 
257
 
        if ( maxLines < linesRemaining )
258
 
            linesToComp = maxLines;
259
 
        else
260
 
            linesToComp = linesRemaining;
261
 
 
262
 
        partialRect.h = linesToComp;
263
 
 
264
 
        /* Encode (compress) and send the next rectangle. */
265
 
        if ( ! rfbSendOneRectEncodingZlib( cl,
266
 
                                           partialRect.x,
267
 
                                           partialRect.y,
268
 
                                           partialRect.w,
269
 
                                           partialRect.h )) {
270
 
 
271
 
            return FALSE;
272
 
        }
273
 
 
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
281
 
         * seen by the user.
282
 
         * Since, zlib is most useful for slow networks, this flush
283
 
         * is appropriate for the desired behavior of the zlib encoding.
284
 
         */
285
 
        if (( cl->ublen > 0 ) &&
286
 
            ( linesToComp == maxLines )) {
287
 
            if (!rfbSendUpdateBuf(cl)) {
288
 
 
289
 
                return FALSE;
290
 
            }
291
 
        }
292
 
 
293
 
        /* Update remaining and incremental rectangle location. */
294
 
        linesRemaining -= linesToComp;
295
 
        partialRect.y += linesToComp;
296
 
 
297
 
    }
298
 
 
299
 
    return TRUE;
300
 
 
301
 
}
302