source: trunk/src/testing/app/vnc/tight.cpp @ 4

Revision 4, 17.9 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1/************************************************************************
2 *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
3 *
4 *  This is free software; you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation; either version 2 of the License, or
7 *  (at your option) any later version.
8 *
9 *  This software is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *  GNU General Public License for more details.
13 *
14 *  You should have received a copy of the GNU General Public License
15 *  along with this software; if not, write to the Free Software
16 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
17 *  USA.
18 */
19
20/*
21 * tight.c - handle ``tight'' encoding.
22 *
23 * This file shouldn't be compiled directly. It is included multiple
24 * times by rfbproto.c, each time with a different definition of the
25 * macro BPP. For each value of BPP, this file defines a function
26 * which handles a tight-encoded rectangle with BPP bits per pixel.
27 *
28 */
29
30#define TIGHT_MIN_TO_COMPRESS 12
31
32#define CARDBPP CONCAT2E(CARD,BPP)
33#define filterPtrBPP CONCAT2E(filterPtr,BPP)
34
35#define HandleTightBPP CONCAT2E(HandleTight,BPP)
36#define ReceiveTightBPP CONCAT2E(ReceiveTight,BPP)
37#define flushTightBPP CONCAT2E(flushTight,BPP)
38#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
39#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
40#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
41#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
42#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
43#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
44
45#if BPP != 8
46#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
47#endif
48
49#ifndef RGB_TO_PIXEL
50
51#define RGB_TO_PIXEL(bpp,r,g,b)                                         \
52  (((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift |            \
53   ((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift |        \
54   ((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift)
55
56#define RGB24_TO_PIXEL(bpp,r,g,b)                                       \
57   ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255             \
58    << myFormat.redShift |                                              \
59    (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255           \
60    << myFormat.greenShift |                                            \
61    (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255            \
62    << myFormat.blueShift)
63
64#define RGB24_TO_PIXEL32(r,g,b)                                         \
65  (((CARD32)(r) & 0xFF) << myFormat.redShift |                          \
66   ((CARD32)(g) & 0xFF) << myFormat.greenShift |                        \
67   ((CARD32)(b) & 0xFF) << myFormat.blueShift)
68
69#endif
70
71/* Type declarations */
72
73typedef void (VNCViewer::*filterPtrBPP)(int, CARDBPP *);
74
75/* Prototypes */
76
77//  static int InitFilterCopyBPP (int rw, int rh);
78//  static int InitFilterPaletteBPP (int rw, int rh);
79//  static int InitFilterGradientBPP (int rw, int rh);
80//  static void FilterCopyBPP (int numRows, CARDBPP *destBuffer);
81//  static void FilterPaletteBPP (int numRows, CARDBPP *destBuffer);
82//  static void FilterGradientBPP (int numRows, CARDBPP *destBuffer);
83
84#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
85#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
86#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
87#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
88#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
89#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
90
91//static Bool DecompressJpegRectBPP(int x, int y, int w, int h);
92
93/* Definitions */
94
95Bool
96VNCViewer::HandleTightBPP (sgVNCViewer *ct, int rx, int ry, int rw, int rh)
97{
98    CARDBPP fill_colour;
99    CARD8 comp_ctl;
100    CARD8 filter_id;
101    filterPtrBPP filterFn;
102    z_streamp zs;
103    char *buffer2;
104    int err, stream_id, compressedLen, bitsPixel;
105    int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
106
107    if (!ReadFromRFBServer((char *)&comp_ctl, 1))
108        return False;
109
110        /* Flush zlib streams if we are told by the server to do so. */
111    for (stream_id = 0; stream_id < 4; stream_id++) {
112        if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
113            if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
114                zlibStream[stream_id].msg != NULL)
115                aLog("inflateEnd: %s\n", zlibStream[stream_id].msg);
116            zlibStreamActive[stream_id] = False;
117        }
118        comp_ctl >>= 1;
119    }
120
121        /* Handle solid rectangles. */
122    if (comp_ctl == rfbTightFill) {
123#if BPP == 32
124        if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
125            myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
126            if (!ReadFromRFBServer(buffer, 3))
127                return False;
128            fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]);
129        } else {
130            if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
131                return False;
132        }
133#else
134        if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
135            return False;
136#endif
137
138        ct->FillToScreen(fill_colour, rx, ry, rw, rh);
139
140        return True;
141    }
142
143#if BPP == 8
144    if (comp_ctl == rfbTightJpeg) {
145        aLog("Tight encoding: JPEG is not supported in 8 bpp mode.\n");
146        return False;
147    }
148#else
149    if (comp_ctl == rfbTightJpeg) {
150        return DecompressJpegRectBPP(ct,rx, ry, rw, rh);
151    }
152#endif
153
154        /* Quit on unsupported subencoding value. */
155    if (comp_ctl > rfbTightMaxSubencoding) {
156        aLog("Tight encoding: bad subencoding value received.\n");
157        return False;
158    }
159
160        /*
161         * Here primary compression mode handling begins.
162         * Data was processed with optional filter + zlib compression.
163         */
164
165        /* First, we should identify a filter to use. */
166    if ((comp_ctl & rfbTightExplicitFilter) != 0) {
167        if (!ReadFromRFBServer((char*)&filter_id, 1))
168            return False;
169
170        switch (filter_id) {
171            case rfbTightFilterCopy:
172                filterFn = &VNCViewer::FilterCopyBPP;
173                bitsPixel = InitFilterCopyBPP(rw, rh);
174                break;
175            case rfbTightFilterPalette:
176                filterFn = &VNCViewer::FilterPaletteBPP;
177                bitsPixel = InitFilterPaletteBPP(rw, rh);
178                break;
179            case rfbTightFilterGradient:
180                filterFn = &VNCViewer::FilterGradientBPP;
181                bitsPixel = InitFilterGradientBPP(rw, rh);
182                break;
183          default:
184                aLog("Tight encoding: unknown filter code received.\n");
185                return False;
186        }
187    } else {
188        filterFn = &VNCViewer::FilterCopyBPP;
189        bitsPixel = InitFilterCopyBPP(rw, rh);
190    }
191    if (bitsPixel == 0) {
192        aLog("Tight encoding: error receiving palette.\n");
193        return False;
194    }
195
196        /* Determine if the data should be decompressed or just copied. */
197    rowSize = (rw * bitsPixel + 7) / 8;
198    if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
199        if (!ReadFromRFBServer((char*)buffer, rh * rowSize))
200            return False;
201
202        buffer2 = &buffer[TIGHT_MIN_TO_COMPRESS * 4];
203        (this->*filterFn)(rh, (CARDBPP *)buffer2);
204        ct->CopyDataToScreen(buffer2, rx, ry, rw, rh);
205
206        return True;
207    }
208
209        /* Read the length (1..3 bytes) of compressed data following. */
210    compressedLen = (int)ReadCompactLen();
211    if (compressedLen <= 0) {
212        aLog("Incorrect data received from the server.\n");
213        return False;
214    }
215
216        /* Now let's initialize compression stream if needed. */
217    stream_id = comp_ctl & 0x03;
218    zs = &zlibStream[stream_id];
219    if (!zlibStreamActive[stream_id]) {
220        zs->zalloc = Z_NULL;
221        zs->zfree = Z_NULL;
222        zs->opaque = Z_NULL;
223        err = inflateInit(zs);
224        if (err != Z_OK) {
225            if (zs->msg != NULL)
226                aLog("InflateInit error: %s.\n", zs->msg);
227            return False;
228        }
229        zlibStreamActive[stream_id] = True;
230    }
231
232        /* Read, decode and draw actual pixel data in a loop. */
233
234    bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
235    buffer2 = &buffer[bufferSize];
236    if (rowSize > bufferSize) {
237            /* Should be impossible when BUFFER_SIZE >= 16384 */
238        aLog("Internal error: incorrect buffer size.\n");
239        return False;
240    }
241
242    rowsProcessed = 0;
243    extraBytes = 0;
244
245    while (compressedLen > 0) {
246        if (compressedLen > ZLIB_BUFFER_SIZE)
247            portionLen = ZLIB_BUFFER_SIZE;
248        else
249            portionLen = compressedLen;
250
251        if (!ReadFromRFBServer((char*)zlib_buffer, portionLen))
252            return False;
253
254        compressedLen -= portionLen;
255
256        zs->next_in = (Bytef *)zlib_buffer;
257        zs->avail_in = portionLen;
258
259        do {
260            zs->next_out = (Bytef *)&buffer[extraBytes];
261            zs->avail_out = bufferSize - extraBytes;
262
263            err = inflate(zs, Z_SYNC_FLUSH);
264            if (err == Z_BUF_ERROR)   /* Input exhausted -- no problem. */
265                break;
266            if (err != Z_OK && err != Z_STREAM_END) {
267                if (zs->msg != NULL) {
268                    aLog("Inflate error: %s.\n", zs->msg);
269                } else {
270                    aLog("Inflate error: %d.\n", err);
271                }
272                return False;
273            }
274
275            numRows = (bufferSize - zs->avail_out) / rowSize;
276
277            (this->*filterFn)(numRows, (CARDBPP *)buffer2);
278
279            extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
280            if (extraBytes > 0)
281                memcpy(buffer, &buffer[numRows * rowSize], extraBytes);
282
283            ct->CopyDataToScreen(buffer2, rx, ry + rowsProcessed, rw, numRows);
284            rowsProcessed += numRows;
285        }
286        while (zs->avail_out == 0);
287    }
288
289    if (rowsProcessed != rh) {
290        aLog("Incorrect number of scan lines after decompression.\n");
291        return False;
292    }
293
294    return True;
295}
296
297/*----------------------------------------------------------------------------
298 *
299 * Filter stuff.
300 *
301 */
302
303/*
304   The following variables are defined in rfbproto.c:
305     static Bool cutZeros;
306     static int rectWidth, rectColors;
307     static CARD8 tightPalette[256*4];
308     static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
309*/
310
311int
312VNCViewer::InitFilterCopyBPP (int rw, int rh)
313{
314    rectWidth = rw;
315
316#if BPP == 32
317    if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
318        myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
319        cutZeros = True;
320        return 24;
321    } else {
322        cutZeros = False;
323    }
324#endif
325
326    return BPP;
327}
328
329void
330VNCViewer::FilterCopyBPP (int numRows, CARDBPP *dst)
331{
332
333#if BPP == 32
334    int x, y;
335
336    if (cutZeros) {
337        for (y = 0; y < numRows; y++) {
338            for (x = 0; x < rectWidth; x++) {
339                dst[y*rectWidth+x] =
340                    RGB24_TO_PIXEL32(buffer[(y*rectWidth+x)*3],
341                                     buffer[(y*rectWidth+x)*3+1],
342                                     buffer[(y*rectWidth+x)*3+2]);
343            }
344        }
345        return;
346    }
347#endif
348
349    memcpy (dst, buffer, numRows * rectWidth * (BPP / 8));
350}
351
352int
353VNCViewer::InitFilterGradientBPP (int rw, int rh)
354{
355    int bits;
356
357    bits = InitFilterCopyBPP(rw, rh);
358    if (cutZeros)
359        memset(tightPrevRow, 0, rw * 3);
360    else
361        memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16));
362
363    return bits;
364}
365
366#if BPP == 32
367
368void
369VNCViewer::FilterGradient24 (int numRows, CARD32 *dst)
370{
371    int x, y, c;
372    CARD8 thisRow[2048*3];
373    CARD8 pix[3];
374    int est[3];
375
376    for (y = 0; y < numRows; y++) {
377
378            /* First pixel in a row */
379        for (c = 0; c < 3; c++) {
380            pix[c] = tightPrevRow[c] + buffer[y*rectWidth*3+c];
381            thisRow[c] = pix[c];
382        }
383        dst[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
384
385            /* Remaining pixels of a row */
386        for (x = 1; x < rectWidth; x++) {
387            for (c = 0; c < 3; c++) {
388                est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
389                    (int)tightPrevRow[(x-1)*3+c];
390                if (est[c] > 0xFF) {
391                    est[c] = 0xFF;
392                } else if (est[c] < 0x00) {
393                    est[c] = 0x00;
394                }
395                pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c];
396                thisRow[x*3+c] = pix[c];
397            }
398            dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
399        }
400
401        memcpy(tightPrevRow, thisRow, rectWidth * 3);
402    }
403}
404
405#endif
406
407void
408VNCViewer::FilterGradientBPP (int numRows, CARDBPP *dst)
409{
410    int x, y, c;
411    CARDBPP *src = (CARDBPP *)buffer;
412    CARD16 *thatRow = (CARD16 *)tightPrevRow;
413    CARD16 thisRow[2048*3];
414    CARD16 pix[3];
415    CARD16 max[3];
416    int shift[3];
417    int est[3];
418
419#if BPP == 32
420    if (cutZeros) {
421        FilterGradient24(numRows, dst);
422        return;
423    }
424#endif
425
426    max[0] = myFormat.redMax;
427    max[1] = myFormat.greenMax;
428    max[2] = myFormat.blueMax;
429
430    shift[0] = myFormat.redShift;
431    shift[1] = myFormat.greenShift;
432    shift[2] = myFormat.blueShift;
433
434    for (y = 0; y < numRows; y++) {
435
436            /* First pixel in a row */
437        for (c = 0; c < 3; c++) {
438            pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]);
439            thisRow[c] = pix[c];
440        }
441        dst[y*rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
442
443            /* Remaining pixels of a row */
444        for (x = 1; x < rectWidth; x++) {
445            for (c = 0; c < 3; c++) {
446                est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
447                if (est[c] > (int)max[c]) {
448                    est[c] = (int)max[c];
449                } else if (est[c] < 0) {
450                    est[c] = 0;
451                }
452                pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]);
453                thisRow[x*3+c] = pix[c];
454            }
455            dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
456        }
457        memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16));
458    }
459}
460
461int
462VNCViewer::InitFilterPaletteBPP (int rw, int rh)
463{
464    CARD8 numColors;
465    CARDBPP *palette = (CARDBPP *)tightPalette;
466
467    rectWidth = rw;
468
469    if (!ReadFromRFBServer((char*)&numColors, 1))
470        return 0;
471
472    rectColors = (int)numColors;
473    if (++rectColors < 2)
474        return 0;
475
476#if BPP == 32
477        int i;
478    if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
479        myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
480        if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3))
481            return 0;
482        for (i = rectColors - 1; i >= 0; i--) {
483            palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
484                                          tightPalette[i*3+1],
485                                          tightPalette[i*3+2]);
486        }
487        return (rectColors == 2) ? 1 : 8;
488    }
489#endif
490
491    if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8)))
492        return 0;
493
494    return (rectColors == 2) ? 1 : 8;
495}
496
497void
498VNCViewer::FilterPaletteBPP (int numRows, CARDBPP *dst)
499{
500    int x, y, b, w;
501    CARD8 *src = (CARD8 *)buffer;
502    CARDBPP *palette = (CARDBPP *)tightPalette;
503
504    if (rectColors == 2) {
505        w = (rectWidth + 7) / 8;
506        for (y = 0; y < numRows; y++) {
507            for (x = 0; x < rectWidth / 8; x++) {
508                for (b = 7; b >= 0; b--)
509                    dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
510            }
511            for (b = 7; b >= 8 - rectWidth % 8; b--) {
512                dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
513            }
514        }
515    } else {
516        for (y = 0; y < numRows; y++)
517            for (x = 0; x < rectWidth; x++)
518                dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]];
519    }
520}
521
522
523#if BPP != 8
524
525/*----------------------------------------------------------------------------
526 *
527 * JPEG decompression.
528 *
529 */
530
531/*
532   The following variables are defined in rfbproto.c:
533     static Bool jpegError;
534     static struct jpeg_source_mgr jpegSrcManager;
535     static JOCTET *jpegBufferPtr;
536     static size_t *jpegBufferLen;
537*/
538
539Bool
540VNCViewer::DecompressJpegRectBPP(sgVNCViewer *ct, int x, int y, int w, int h)
541{
542    struct jpeg_decompress_struct cinfo;
543    struct jpeg_error_mgr jerr;
544    int compressedLen;
545    CARD8 *compressedData;
546    CARDBPP *pixelPtr;
547    JSAMPROW rowPointer[1];
548    int dx, dy;
549
550    compressedLen = (int)ReadCompactLen();
551    if (compressedLen <= 0) {
552        aLog("Incorrect data received from the server.\n");
553        return False;
554    }
555
556    compressedData = (CARD8*)malloc(compressedLen);
557    if (compressedData == NULL) {
558        aLog("Memory allocation error.\n");
559        return False;
560    }
561
562    if (!ReadFromRFBServer((char*)compressedData, compressedLen)) {
563        free(compressedData);
564        return False;
565    }
566
567    cinfo.err = jpeg_std_error(&jerr);
568    jpeg_create_decompress(&cinfo);
569
570    JpegSetSrcManager(&cinfo, compressedData, compressedLen);
571
572    jpeg_read_header(&cinfo, TRUE);
573    cinfo.out_color_space = JCS_RGB;
574
575    jpeg_start_decompress(&cinfo);
576    if (cinfo.output_width != w || cinfo.output_height != h ||
577        cinfo.output_components != 3) {
578        aLog("Tight Encoding: Wrong JPEG data received.\n");
579        jpeg_destroy_decompress(&cinfo);
580        free(compressedData);
581        return False;
582    }
583
584    rowPointer[0] = (JSAMPROW)buffer;
585    dy = 0;
586    while (cinfo.output_scanline < cinfo.output_height) {
587        jpeg_read_scanlines(&cinfo, rowPointer, 1);
588        if (jpegError) {
589            break;
590        }
591        pixelPtr = (CARDBPP *)&buffer[BUFFER_SIZE / 2];
592        for (dx = 0; dx < w; dx++) {
593            *pixelPtr++ =
594                RGB24_TO_PIXEL(BPP, buffer[dx*3], buffer[dx*3+1], buffer[dx*3+2]);
595        }
596        ct->CopyDataToScreen(&buffer[BUFFER_SIZE / 2], x, y + dy, w, 1);
597        dy++;
598    }
599
600    if (!jpegError)
601        jpeg_finish_decompress(&cinfo);
602
603    jpeg_destroy_decompress(&cinfo);
604    free(compressedData);
605
606    return !jpegError;
607}
608
609#endif
610
Note: See TracBrowser for help on using the repository browser.