123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
- * Copyright 2004-2005 Cendio AB.
- * Copyright 2009-2015 Pierre Ossman for Cendio AB
- * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
- #include <assert.h>
-
- #include <rdr/InStream.h>
- #include <rdr/MemInStream.h>
- #include <rdr/OutStream.h>
-
- #include <rfb/ConnParams.h>
- #include <rfb/Exception.h>
- #include <rfb/PixelBuffer.h>
- #include <rfb/TightConstants.h>
- #include <rfb/TightDecoder.h>
-
- using namespace rfb;
-
- static const int TIGHT_MAX_WIDTH = 2048;
- static const int TIGHT_MIN_TO_COMPRESS = 12;
-
- #define BPP 8
- #include <rfb/tightDecode.h>
- #undef BPP
- #define BPP 16
- #include <rfb/tightDecode.h>
- #undef BPP
- #define BPP 32
- #include <rfb/tightDecode.h>
- #undef BPP
-
- TightDecoder::TightDecoder() : Decoder(DecoderPartiallyOrdered)
- {
- }
-
- TightDecoder::~TightDecoder()
- {
- }
-
- void TightDecoder::readRect(const Rect& r, rdr::InStream* is,
- const ConnParams& cp, rdr::OutStream* os)
- {
- rdr::U8 comp_ctl;
-
- comp_ctl = is->readU8();
- os->writeU8(comp_ctl);
-
- comp_ctl >>= 4;
-
- // "Fill" compression type.
- if (comp_ctl == tightFill) {
- if (cp.pf().is888())
- os->copyBytes(is, 3);
- else
- os->copyBytes(is, cp.pf().bpp/8);
- return;
- }
-
- // "JPEG" compression type.
- if (comp_ctl == tightJpeg) {
- rdr::U32 len;
-
- len = readCompact(is);
- os->writeOpaque32(len);
- os->copyBytes(is, len);
- return;
- }
-
- // Quit on unsupported compression type.
- if (comp_ctl > tightMaxSubencoding)
- throw Exception("TightDecoder: bad subencoding value received");
-
- // "Basic" compression type.
-
- int palSize = 0;
-
- if (r.width() > TIGHT_MAX_WIDTH)
- throw Exception("TightDecoder: too large rectangle (%d pixels)", r.width());
-
- // Possible palette
- if ((comp_ctl & tightExplicitFilter) != 0) {
- rdr::U8 filterId;
-
- filterId = is->readU8();
- os->writeU8(filterId);
-
- switch (filterId) {
- case tightFilterPalette:
- palSize = is->readU8() + 1;
- os->writeU8(palSize - 1);
-
- if (cp.pf().is888())
- os->copyBytes(is, palSize * 3);
- else
- os->copyBytes(is, palSize * cp.pf().bpp/8);
- break;
- case tightFilterGradient:
- if (cp.pf().bpp == 8)
- throw Exception("TightDecoder: invalid BPP for gradient filter");
- break;
- case tightFilterCopy:
- break;
- default:
- throw Exception("TightDecoder: unknown filter code received");
- }
- }
-
- size_t rowSize, dataSize;
-
- if (palSize != 0) {
- if (palSize <= 2)
- rowSize = (r.width() + 7) / 8;
- else
- rowSize = r.width();
- } else if (cp.pf().is888()) {
- rowSize = r.width() * 3;
- } else {
- rowSize = r.width() * cp.pf().bpp/8;
- }
-
- dataSize = r.height() * rowSize;
-
- if (dataSize < TIGHT_MIN_TO_COMPRESS)
- os->copyBytes(is, dataSize);
- else {
- rdr::U32 len;
-
- len = readCompact(is);
- os->writeOpaque32(len);
- os->copyBytes(is, len);
- }
- }
-
- bool TightDecoder::doRectsConflict(const Rect& rectA,
- const void* bufferA,
- size_t buflenA,
- const Rect& rectB,
- const void* bufferB,
- size_t buflenB,
- const ConnParams& cp)
- {
- rdr::U8 comp_ctl_a, comp_ctl_b;
-
- assert(buflenA >= 1);
- assert(buflenB >= 1);
-
- comp_ctl_a = *(const rdr::U8*)bufferA;
- comp_ctl_b = *(const rdr::U8*)bufferB;
-
- // Resets or use of zlib pose the same problem, so merge them
- if ((comp_ctl_a & 0x80) == 0x00)
- comp_ctl_a |= 1 << ((comp_ctl_a >> 4) & 0x03);
- if ((comp_ctl_b & 0x80) == 0x00)
- comp_ctl_b |= 1 << ((comp_ctl_b >> 4) & 0x03);
-
- if (((comp_ctl_a & 0x0f) & (comp_ctl_b & 0x0f)) != 0)
- return true;
-
- return false;
- }
-
- void TightDecoder::decodeRect(const Rect& r, const void* buffer,
- size_t buflen, const ConnParams& cp,
- ModifiablePixelBuffer* pb)
- {
- const rdr::U8* bufptr;
- const PixelFormat& pf = cp.pf();
-
- rdr::U8 comp_ctl;
-
- bufptr = (const rdr::U8*)buffer;
-
- assert(buflen >= 1);
-
- comp_ctl = *bufptr;
- bufptr += 1;
- buflen -= 1;
-
- // Reset zlib streams if we are told by the server to do so.
- for (int i = 0; i < 4; i++) {
- if (comp_ctl & 1) {
- zis[i].reset();
- }
- comp_ctl >>= 1;
- }
-
- // "Fill" compression type.
- if (comp_ctl == tightFill) {
- if (pf.is888()) {
- rdr::U8 pix[4];
-
- assert(buflen >= 3);
-
- pf.bufferFromRGB(pix, bufptr, 1);
- pb->fillRect(pf, r, pix);
- } else {
- assert(buflen >= (size_t)pf.bpp/8);
- pb->fillRect(pf, r, bufptr);
- }
- return;
- }
-
- // "JPEG" compression type.
- if (comp_ctl == tightJpeg) {
- rdr::U32 len;
-
- int stride;
- rdr::U8 *buf;
-
- JpegDecompressor jd;
-
- assert(buflen >= 4);
-
- memcpy(&len, bufptr, 4);
- bufptr += 4;
- buflen -= 4;
-
- // We always use direct decoding with JPEG images
- buf = pb->getBufferRW(r, &stride);
- jd.decompress(bufptr, len, buf, stride, r, pb->getPF());
- pb->commitBufferRW(r);
- return;
- }
-
- // Quit on unsupported compression type.
- assert(comp_ctl <= tightMaxSubencoding);
-
- // "Basic" compression type.
-
- int palSize = 0;
- rdr::U8 palette[256 * 4];
- bool useGradient = false;
-
- if ((comp_ctl & tightExplicitFilter) != 0) {
- rdr::U8 filterId;
-
- assert(buflen >= 1);
-
- filterId = *bufptr;
- bufptr += 1;
- buflen -= 1;
-
- switch (filterId) {
- case tightFilterPalette:
- assert(buflen >= 1);
-
- palSize = *bufptr + 1;
- bufptr += 1;
- buflen -= 1;
-
- if (pf.is888()) {
- size_t len = palSize * 3;
- rdr::U8Array tightPalette(len);
-
- assert(buflen >= len);
-
- memcpy(tightPalette.buf, bufptr, len);
- bufptr += len;
- buflen -= len;
-
- pf.bufferFromRGB(palette, tightPalette.buf, palSize);
- } else {
- size_t len;
-
- len = palSize * pf.bpp/8;
-
- assert(buflen >= len);
-
- memcpy(palette, bufptr, len);
- bufptr += len;
- buflen -= len;
- }
- break;
- case tightFilterGradient:
- useGradient = true;
- break;
- case tightFilterCopy:
- break;
- default:
- assert(false);
- }
- }
-
- // Determine if the data should be decompressed or just copied.
- size_t rowSize, dataSize;
- rdr::U8* netbuf;
-
- netbuf = NULL;
-
- if (palSize != 0) {
- if (palSize <= 2)
- rowSize = (r.width() + 7) / 8;
- else
- rowSize = r.width();
- } else if (pf.is888()) {
- rowSize = r.width() * 3;
- } else {
- rowSize = r.width() * pf.bpp/8;
- }
-
- dataSize = r.height() * rowSize;
-
- if (dataSize < TIGHT_MIN_TO_COMPRESS)
- assert(buflen >= dataSize);
- else {
- rdr::U32 len;
- int streamId;
- rdr::MemInStream* ms;
-
- assert(buflen >= 4);
-
- memcpy(&len, bufptr, 4);
- bufptr += 4;
- buflen -= 4;
-
- assert(buflen >= len);
-
- streamId = comp_ctl & 0x03;
- ms = new rdr::MemInStream(bufptr, len);
- zis[streamId].setUnderlying(ms, len);
-
- // Allocate buffer and decompress the data
- netbuf = new rdr::U8[dataSize];
-
- zis[streamId].readBytes(netbuf, dataSize);
-
- zis[streamId].removeUnderlying();
- delete ms;
-
- bufptr = netbuf;
- buflen = dataSize;
- }
-
- // Time to decode the actual data
- bool directDecode;
-
- rdr::U8* outbuf;
- int stride;
-
- if (pb->getPF().equal(pf)) {
- // Decode directly into the framebuffer (fast path)
- directDecode = true;
- } else {
- // Decode into an intermediate buffer and use pixel translation
- directDecode = false;
- }
-
- if (directDecode)
- outbuf = pb->getBufferRW(r, &stride);
- else {
- outbuf = new rdr::U8[r.area() * (pf.bpp/8)];
- stride = r.width();
- }
-
- if (palSize == 0) {
- // Truecolor data
- if (useGradient) {
- if (pf.is888())
- FilterGradient24(bufptr, pf, (rdr::U32*)outbuf, stride, r);
- else {
- switch (pf.bpp) {
- case 8:
- assert(false);
- break;
- case 16:
- FilterGradient(bufptr, pf, (rdr::U16*)outbuf, stride, r);
- break;
- case 32:
- FilterGradient(bufptr, pf, (rdr::U32*)outbuf, stride, r);
- break;
- }
- }
- } else {
- // Copy
- rdr::U8* ptr = outbuf;
- const rdr::U8* srcPtr = bufptr;
- int w = r.width();
- int h = r.height();
- if (pf.is888()) {
- while (h > 0) {
- pf.bufferFromRGB(ptr, srcPtr, w);
- ptr += stride * pf.bpp/8;
- srcPtr += w * 3;
- h--;
- }
- } else {
- while (h > 0) {
- memcpy(ptr, srcPtr, w * pf.bpp/8);
- ptr += stride * pf.bpp/8;
- srcPtr += w * pf.bpp/8;
- h--;
- }
- }
- }
- } else {
- // Indexed color
- switch (pf.bpp) {
- case 8:
- FilterPalette((const rdr::U8*)palette, palSize,
- bufptr, (rdr::U8*)outbuf, stride, r);
- break;
- case 16:
- FilterPalette((const rdr::U16*)palette, palSize,
- bufptr, (rdr::U16*)outbuf, stride, r);
- break;
- case 32:
- FilterPalette((const rdr::U32*)palette, palSize,
- bufptr, (rdr::U32*)outbuf, stride, r);
- break;
- }
- }
-
- if (directDecode)
- pb->commitBufferRW(r);
- else {
- pb->imageRect(pf, r, outbuf);
- delete [] outbuf;
- }
-
- delete [] netbuf;
- }
-
- rdr::U32 TightDecoder::readCompact(rdr::InStream* is)
- {
- rdr::U8 b;
- rdr::U32 result;
-
- b = is->readU8();
- result = (int)b & 0x7F;
- if (b & 0x80) {
- b = is->readU8();
- result |= ((int)b & 0x7F) << 7;
- if (b & 0x80) {
- b = is->readU8();
- result |= ((int)b & 0xFF) << 14;
- }
- }
-
- return result;
- }
|