From 80b4209b547f030dad14b2ce9456b2a4220b9a65 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 10 Nov 2015 17:17:34 +0100 Subject: [PATCH] Split decoders into a read and decode step We need to split these steps up in preparation for multi-core support. Reading needs to be done in a serial manner, whilst decoding can be done in parallel. This also involved a rather large cleanup of the Tight decoder. --- common/rfb/CopyRectDecoder.cxx | 18 +- common/rfb/CopyRectDecoder.h | 5 +- common/rfb/DecodeManager.cxx | 11 +- common/rfb/DecodeManager.h | 3 + common/rfb/Decoder.h | 23 ++- common/rfb/HextileDecoder.cxx | 61 +++++- common/rfb/HextileDecoder.h | 5 +- common/rfb/RREDecoder.cxx | 25 ++- common/rfb/RREDecoder.h | 5 +- common/rfb/RawDecoder.cxx | 44 ++-- common/rfb/RawDecoder.h | 5 +- common/rfb/TightDecoder.cxx | 368 +++++++++++++++++++++++++++++++-- common/rfb/TightDecoder.h | 45 ++-- common/rfb/ZRLEDecoder.cxx | 28 ++- common/rfb/ZRLEDecoder.h | 5 +- common/rfb/hextileDecode.h | 20 +- common/rfb/tightDecode.h | 315 ++++++---------------------- 17 files changed, 622 insertions(+), 364 deletions(-) diff --git a/common/rfb/CopyRectDecoder.cxx b/common/rfb/CopyRectDecoder.cxx index 4690b5e3..52de8790 100644 --- a/common/rfb/CopyRectDecoder.cxx +++ b/common/rfb/CopyRectDecoder.cxx @@ -15,7 +15,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -#include +#include +#include #include #include @@ -30,10 +31,17 @@ CopyRectDecoder::~CopyRectDecoder() } void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, - ModifiablePixelBuffer* pb) + const ConnParams& cp, rdr::OutStream* os) { - int srcX = is->readU16(); - int srcY = is->readU16(); + os->copyBytes(is, 4); +} + +void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb) +{ + rdr::MemInStream is(buffer, buflen); + int srcX = is.readU16(); + int srcY = is.readU16(); pb->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY)); } diff --git a/common/rfb/CopyRectDecoder.h b/common/rfb/CopyRectDecoder.h index a7195ce3..998a5091 100644 --- a/common/rfb/CopyRectDecoder.h +++ b/common/rfb/CopyRectDecoder.h @@ -27,7 +27,10 @@ namespace rfb { CopyRectDecoder(); virtual ~CopyRectDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb); + const ConnParams& cp, rdr::OutStream* os); + virtual void decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb); }; } #endif diff --git a/common/rfb/DecodeManager.cxx b/common/rfb/DecodeManager.cxx index b82d31d2..ffae18b3 100644 --- a/common/rfb/DecodeManager.cxx +++ b/common/rfb/DecodeManager.cxx @@ -26,6 +26,7 @@ #include #include +#include using namespace rfb; @@ -35,12 +36,14 @@ DecodeManager::DecodeManager(CConnection *conn) : conn(conn) { memset(decoders, 0, sizeof(decoders)); + bufferStream = new rdr::MemOutStream(); } DecodeManager::~DecodeManager() { for (size_t i = 0; i < sizeof(decoders)/sizeof(decoders[0]); i++) delete decoders[i]; + delete bufferStream; } void DecodeManager::decodeRect(const Rect& r, int encoding, @@ -60,5 +63,11 @@ void DecodeManager::decodeRect(const Rect& r, int encoding, throw rdr::Exception("Unknown encoding"); } } - decoders[encoding]->readRect(r, conn->getInStream(), conn->cp, pb); + + bufferStream->clear(); + decoders[encoding]->readRect(r, conn->getInStream(), + conn->cp, bufferStream); + decoders[encoding]->decodeRect(r, bufferStream->data(), + bufferStream->length(), + conn->cp, pb); } diff --git a/common/rfb/DecodeManager.h b/common/rfb/DecodeManager.h index 445601d9..63a41206 100644 --- a/common/rfb/DecodeManager.h +++ b/common/rfb/DecodeManager.h @@ -21,6 +21,8 @@ #include +namespace rdr { class MemOutStream; } + namespace rfb { class CConnection; class Decoder; @@ -38,6 +40,7 @@ namespace rfb { private: CConnection *conn; Decoder *decoders[encodingMax+1]; + rdr::MemOutStream *bufferStream; }; } diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h index 9d929ea4..4195a80b 100644 --- a/common/rfb/Decoder.h +++ b/common/rfb/Decoder.h @@ -19,7 +19,10 @@ #ifndef __RFB_DECODER_H__ #define __RFB_DECODER_H__ -namespace rdr { class InStream; } +namespace rdr { + class InStream; + class OutStream; +} namespace rfb { class ConnParams; @@ -31,12 +34,20 @@ namespace rfb { Decoder(); virtual ~Decoder(); - // readRect() is the main interface that decodes the given rectangle - // with data from the given InStream, onto the ModifiablePixelBuffer. - // The PixelFormat of the PixelBuffer might not match the ConnParams - // and it is up to the decoder to do any necessary conversion. + // These functions are the main interface to an individual decoder + + // readRect() transfers data for the given rectangle from the + // InStream to the OutStream, possibly changing it along the way to + // make it easier to decode. virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb)=0; + const ConnParams& cp, rdr::OutStream* os)=0; + // decodeRect() decodes the given rectangle with data from the + // given buffer, onto the ModifiablePixelBuffer. The PixelFormat of + // the PixelBuffer might not match the ConnParams and it is up to + // the decoder to do any necessary conversion. + virtual void decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb)=0; static bool supported(int encoding); static Decoder* createDecoder(int encoding); diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx index 705ccf51..d1412d4a 100644 --- a/common/rfb/HextileDecoder.cxx +++ b/common/rfb/HextileDecoder.cxx @@ -15,7 +15,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ + #include +#include +#include + #include #include #include @@ -41,13 +45,60 @@ HextileDecoder::~HextileDecoder() } void HextileDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb) + const ConnParams& cp, rdr::OutStream* os) +{ + Rect t; + size_t bytesPerPixel; + + bytesPerPixel = cp.pf().bpp/8; + + for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { + + t.br.y = __rfbmin(r.br.y, t.tl.y + 16); + + for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) { + rdr::U8 tileType; + + t.br.x = __rfbmin(r.br.x, t.tl.x + 16); + + tileType = is->readU8(); + os->writeU8(tileType); + + if (tileType & hextileRaw) { + os->copyBytes(is, t.area() * bytesPerPixel); + continue; + } + + if (tileType & hextileBgSpecified) + os->copyBytes(is, bytesPerPixel); + + if (tileType & hextileFgSpecified) + os->copyBytes(is, bytesPerPixel); + + if (tileType & hextileAnySubrects) { + rdr::U8 nSubrects; + + nSubrects = is->readU8(); + os->writeU8(nSubrects); + + if (tileType & hextileSubrectsColoured) + os->copyBytes(is, nSubrects * (bytesPerPixel + 2)); + else + os->copyBytes(is, nSubrects * 2); + } + } + } +} + +void HextileDecoder::decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb) { + rdr::MemInStream is(buffer, buflen); const PixelFormat& pf = cp.pf(); - rdr::U8 buf[16 * 16 * 4 * pf.bpp/8]; switch (pf.bpp) { - case 8: hextileDecode8 (r, is, (rdr::U8*) buf, pf, pb); break; - case 16: hextileDecode16(r, is, (rdr::U16*)buf, pf, pb); break; - case 32: hextileDecode32(r, is, (rdr::U32*)buf, pf, pb); break; + case 8: hextileDecode8 (r, &is, pf, pb); break; + case 16: hextileDecode16(r, &is, pf, pb); break; + case 32: hextileDecode32(r, &is, pf, pb); break; } } diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h index 22eefba4..bdc76bcc 100644 --- a/common/rfb/HextileDecoder.h +++ b/common/rfb/HextileDecoder.h @@ -27,7 +27,10 @@ namespace rfb { HextileDecoder(); virtual ~HextileDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb); + const ConnParams& cp, rdr::OutStream* os); + virtual void decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb); }; } #endif diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx index b8026444..2dd47cc0 100644 --- a/common/rfb/RREDecoder.cxx +++ b/common/rfb/RREDecoder.cxx @@ -15,7 +15,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ + #include +#include +#include + #include #include #include @@ -41,12 +45,25 @@ RREDecoder::~RREDecoder() } void RREDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb) + const ConnParams& cp, rdr::OutStream* os) +{ + rdr::U32 numRects; + + numRects = is->readU32(); + os->writeU32(numRects); + + os->copyBytes(is, cp.pf().bpp/8 + numRects * (cp.pf().bpp/8 + 8)); +} + +void RREDecoder::decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb) { + rdr::MemInStream is(buffer, buflen); const PixelFormat& pf = cp.pf(); switch (pf.bpp) { - case 8: rreDecode8 (r, is, pf, pb); break; - case 16: rreDecode16(r, is, pf, pb); break; - case 32: rreDecode32(r, is, pf, pb); break; + case 8: rreDecode8 (r, &is, pf, pb); break; + case 16: rreDecode16(r, &is, pf, pb); break; + case 32: rreDecode32(r, &is, pf, pb); break; } } diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h index 3bed62bc..f89fef4a 100644 --- a/common/rfb/RREDecoder.h +++ b/common/rfb/RREDecoder.h @@ -27,7 +27,10 @@ namespace rfb { RREDecoder(); virtual ~RREDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb); + const ConnParams& cp, rdr::OutStream* os); + virtual void decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb); }; } #endif diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx index 292c3436..e349bda8 100644 --- a/common/rfb/RawDecoder.cxx +++ b/common/rfb/RawDecoder.cxx @@ -15,7 +15,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -#include + +#include + +#include #include #include #include @@ -31,36 +34,15 @@ RawDecoder::~RawDecoder() } void RawDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb) + const ConnParams& cp, rdr::OutStream* os) { - const PixelFormat& pf = cp.pf(); - - rdr::U8 imageBuf[16384]; - const int maxPixels = sizeof(imageBuf) / (pf.bpp/8); - - int x = r.tl.x; - int y = r.tl.y; - int w = r.width(); - int h = r.height(); - - while (h > 0) { - int dx; - - dx = 0; - while (dx < w) { - int dw; - - dw = maxPixels; - if (dx + dw > w) - dw = w - dx; - - is->readBytes(imageBuf, dw * pf.bpp/8); - pb->imageRect(pf, Rect(x+dx, y, x+dx+dw, y+1), imageBuf); - - dx += dw; - } + os->copyBytes(is, r.area() * cp.pf().bpp/8); +} - y++; - h--; - } +void RawDecoder::decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb) +{ + assert(buflen >= (size_t)r.area() * cp.pf().bpp/8); + pb->imageRect(cp.pf(), r, buffer); } diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h index 4caf175d..21ea738b 100644 --- a/common/rfb/RawDecoder.h +++ b/common/rfb/RawDecoder.h @@ -26,7 +26,10 @@ namespace rfb { RawDecoder(); virtual ~RawDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb); + const ConnParams& cp, rdr::OutStream* os); + virtual void decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb); }; } #endif diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx index 96749a9e..cab49fdf 100644 --- a/common/rfb/TightDecoder.cxx +++ b/common/rfb/TightDecoder.cxx @@ -1,5 +1,6 @@ /* 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 @@ -17,14 +18,23 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ + +#include + #include +#include +#include + #include +#include #include +#include #include using namespace rfb; -#define TIGHT_MAX_WIDTH 2048 +static const int TIGHT_MAX_WIDTH = 2048; +static const int TIGHT_MIN_TO_COMPRESS = 12; #define BPP 8 #include @@ -45,29 +55,355 @@ TightDecoder::~TightDecoder() } void TightDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb) + 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); + } +} + +void TightDecoder::decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb) { - this->is = is; - this->pb = pb; - clientpf = pb->getPF(); - serverpf = cp.pf(); + 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; + + // Flush 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; + + assert(buflen >= 4); - if (clientpf.equal(serverpf)) { - /* Decode directly into the framebuffer (fast path) */ + 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()) { + rdr::U8 tightPalette[palSize * 3]; + + assert(buflen >= sizeof(tightPalette)); + + memcpy(tightPalette, bufptr, sizeof(tightPalette)); + bufptr += sizeof(tightPalette); + buflen -= sizeof(tightPalette); + + pf.bufferFromRGB(palette, tightPalette, 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].reset(); + + 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 */ + // Decode into an intermediate buffer and use pixel translation directDecode = false; } - switch (serverpf.bpp) { - case 8: - tightDecode8 (r); break; - case 16: - tightDecode16(r); break; - case 32: - tightDecode32(r); break; + 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) diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h index 028514a5..18497d41 100644 --- a/common/rfb/TightDecoder.h +++ b/common/rfb/TightDecoder.h @@ -1,5 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2011 D. R. Commander. All Rights Reserved. + * Copyright 2009-2015 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,39 +32,35 @@ namespace rfb { TightDecoder(); virtual ~TightDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb); + const ConnParams& cp, rdr::OutStream* os); + virtual void decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb); private: rdr::U32 readCompact(rdr::InStream* is); - void tightDecode8(const Rect& r); - void tightDecode16(const Rect& r); - void tightDecode32(const Rect& r); + void FilterGradient24(const rdr::U8* inbuf, const PixelFormat& pf, + rdr::U32* outbuf, int stride, const Rect& r); - void DecompressJpegRect8(const Rect& r); - void DecompressJpegRect16(const Rect& r); - void DecompressJpegRect32(const Rect& r); + void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf, + rdr::U16* outbuf, int stride, const Rect& r); + void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf, + rdr::U32* outbuf, int stride, const Rect& r); - void FilterGradient8(rdr::U8 *netbuf, rdr::U8* buf, int stride, - const Rect& r); - void FilterGradient16(rdr::U8 *netbuf, rdr::U16* buf, int stride, - const Rect& r); - void FilterGradient24(rdr::U8 *netbuf, rdr::U32* buf, int stride, - const Rect& r); - void FilterGradient32(rdr::U8 *netbuf, rdr::U32* buf, int stride, - const Rect& r); + void FilterPalette(const rdr::U8* palette, int palSize, + const rdr::U8* inbuf, rdr::U8* outbuf, + int stride, const Rect& r); + void FilterPalette(const rdr::U16* palette, int palSize, + const rdr::U8* inbuf, rdr::U16* outbuf, + int stride, const Rect& r); + void FilterPalette(const rdr::U32* palette, int palSize, + const rdr::U8* inbuf, rdr::U32* outbuf, + int stride, const Rect& r); - void directFillRect8(const Rect& r, Pixel pix); - void directFillRect16(const Rect& r, Pixel pix); - void directFillRect32(const Rect& r, Pixel pix); - - ModifiablePixelBuffer* pb; - rdr::InStream* is; + private: rdr::ZlibInStream zis[4]; JpegDecompressor jd; - PixelFormat clientpf; - PixelFormat serverpf; - bool directDecode; }; } diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx index 1328012d..498152cf 100644 --- a/common/rfb/ZRLEDecoder.cxx +++ b/common/rfb/ZRLEDecoder.cxx @@ -15,7 +15,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ + #include +#include +#include + #include #include #include @@ -67,13 +71,25 @@ ZRLEDecoder::~ZRLEDecoder() } void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb) + const ConnParams& cp, rdr::OutStream* os) +{ + rdr::U32 len; + + len = is->readU32(); + os->writeU32(len); + os->copyBytes(is, len); +} + +void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb) { + rdr::MemInStream is(buffer, buflen); const rfb::PixelFormat& pf = cp.pf(); rdr::U8* buf[64 * 64 * 4 * pf.bpp/8]; switch (pf.bpp) { - case 8: zrleDecode8 (r, is, &zis, (rdr::U8*) buf, pf, pb); break; - case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, pf, pb); break; + case 8: zrleDecode8 (r, &is, &zis, (rdr::U8*) buf, pf, pb); break; + case 16: zrleDecode16(r, &is, &zis, (rdr::U16*)buf, pf, pb); break; case 32: { Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); @@ -83,16 +99,16 @@ void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is, if ((fitsInLS3Bytes && pf.isLittleEndian()) || (fitsInMS3Bytes && pf.isBigEndian())) { - zrleDecode24A(r, is, &zis, (rdr::U32*)buf, pf, pb); + zrleDecode24A(r, &is, &zis, (rdr::U32*)buf, pf, pb); } else if ((fitsInLS3Bytes && pf.isBigEndian()) || (fitsInMS3Bytes && pf.isLittleEndian())) { - zrleDecode24B(r, is, &zis, (rdr::U32*)buf, pf, pb); + zrleDecode24B(r, &is, &zis, (rdr::U32*)buf, pf, pb); } else { - zrleDecode32(r, is, &zis, (rdr::U32*)buf, pf, pb); + zrleDecode32(r, &is, &zis, (rdr::U32*)buf, pf, pb); } break; } diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h index 5ab80b48..1e338510 100644 --- a/common/rfb/ZRLEDecoder.h +++ b/common/rfb/ZRLEDecoder.h @@ -28,7 +28,10 @@ namespace rfb { ZRLEDecoder(); virtual ~ZRLEDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, ModifiablePixelBuffer* pb); + const ConnParams& cp, rdr::OutStream* os); + virtual void decodeRect(const Rect& r, const void* buffer, + size_t buflen, const ConnParams& cp, + ModifiablePixelBuffer* pb); private: rdr::ZlibInStream zis; }; diff --git a/common/rfb/hextileDecode.h b/common/rfb/hextileDecode.h index 56ba1181..7affa157 100644 --- a/common/rfb/hextileDecode.h +++ b/common/rfb/hextileDecode.h @@ -37,12 +37,14 @@ namespace rfb { #define READ_PIXEL CONCAT2E(readOpaque,BPP) #define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP) -void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, - const PixelFormat& pf, ModifiablePixelBuffer* pb) +static void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, + const PixelFormat& pf, + ModifiablePixelBuffer* pb) { Rect t; PIXEL_T bg = 0; PIXEL_T fg = 0; + PIXEL_T buf[16 * 16 * 4]; for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { @@ -55,20 +57,20 @@ void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, int tileType = is->readU8(); if (tileType & hextileRaw) { - is->readBytes(buf, t.area() * (BPP/8)); - pb->imageRect(pf, t, buf); - continue; + is->readBytes(buf, t.area() * (BPP/8)); + pb->imageRect(pf, t, buf); + continue; } if (tileType & hextileBgSpecified) - bg = is->READ_PIXEL(); + bg = is->READ_PIXEL(); int len = t.area(); - PIXEL_T* ptr = (PIXEL_T*)buf; + PIXEL_T* ptr = buf; while (len-- > 0) *ptr++ = bg; if (tileType & hextileFgSpecified) - fg = is->READ_PIXEL(); + fg = is->READ_PIXEL(); if (tileType & hextileAnySubrects) { int nSubrects = is->readU8(); @@ -85,7 +87,7 @@ void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, int y = (xy & 15); int w = ((wh >> 4) & 15) + 1; int h = (wh & 15) + 1; - PIXEL_T* ptr = (PIXEL_T*)buf + y * t.width() + x; + PIXEL_T* ptr = buf + y * t.width() + x; int rowAdd = t.width() - w; while (h-- > 0) { int len = w; diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h index 88fda73b..b6e86ed5 100644 --- a/common/rfb/tightDecode.h +++ b/common/rfb/tightDecode.h @@ -1,5 +1,6 @@ /* 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 @@ -24,11 +25,6 @@ // This file is #included after having set the following macro: // BPP - 8, 16 or 32 -#include -#include -#include -#include - namespace rfb { // CONCAT2E concatenates its arguments, expanding them if they are macros @@ -39,242 +35,17 @@ namespace rfb { #endif #define PIXEL_T rdr::CONCAT2E(U,BPP) -#define READ_PIXEL CONCAT2E(readOpaque,BPP) -#define TIGHT_DECODE TightDecoder::CONCAT2E(tightDecode,BPP) -#define DECOMPRESS_JPEG_RECT TightDecoder::CONCAT2E(DecompressJpegRect,BPP) -#define FILTER_GRADIENT TightDecoder::CONCAT2E(FilterGradient,BPP) - -#define TIGHT_MIN_TO_COMPRESS 12 - -// Main function implementing Tight decoder - -void TIGHT_DECODE (const Rect& r) -{ - bool cutZeros = false; -#if BPP == 32 - if (serverpf.is888()) { - cutZeros = true; - } -#endif - - rdr::U8 comp_ctl = is->readU8(); - - // Flush 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) { - PIXEL_T pix; - if (cutZeros) { - rdr::U8 bytebuf[3]; - is->readBytes(bytebuf, 3); - serverpf.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1); - } else { - pix = is->READ_PIXEL(); - } - pb->fillRect(serverpf, r, &pix); - return; - } - - // "JPEG" compression type. - if (comp_ctl == tightJpeg) { - DECOMPRESS_JPEG_RECT(r); - return; - } - - // Quit on unsupported compression type. - if (comp_ctl > tightMaxSubencoding) { - throw Exception("TightDecoder: bad subencoding value received"); - return; - } - - // "Basic" compression type. - int palSize = 0; - static PIXEL_T palette[256]; - bool useGradient = false; - - if ((comp_ctl & tightExplicitFilter) != 0) { - rdr::U8 filterId = is->readU8(); - - switch (filterId) { - case tightFilterPalette: - palSize = is->readU8() + 1; - if (cutZeros) { - rdr::U8 tightPalette[256 * 3]; - is->readBytes(tightPalette, palSize * 3); - serverpf.bufferFromRGB((rdr::U8*)palette, tightPalette, palSize); - } else { - is->readBytes(palette, palSize * sizeof(PIXEL_T)); - } - break; - case tightFilterGradient: - useGradient = true; - break; - case tightFilterCopy: - break; - default: - throw Exception("TightDecoder: unknown filter code received"); - return; - } - } - - int bppp = BPP; - if (palSize != 0) { - bppp = (palSize <= 2) ? 1 : 8; - } else if (cutZeros) { - bppp = 24; - } - - // Determine if the data should be decompressed or just copied. - int rowSize = (r.width() * bppp + 7) / 8; - int dataSize = r.height() * rowSize; - int streamId = -1; - rdr::InStream *input; - if (dataSize < TIGHT_MIN_TO_COMPRESS) { - input = is; - } else { - int length = readCompact(is); - streamId = comp_ctl & 0x03; - zis[streamId].setUnderlying(is, length); - input = &zis[streamId]; - } - - // Allocate netbuf and read in data - rdr::U8 *netbuf = new rdr::U8[dataSize]; - if (!netbuf) { - throw Exception("rfb::TightDecoder::tightDecode unable to allocate buffer"); - } - input->readBytes(netbuf, dataSize); - - PIXEL_T *buf; - int stride = r.width(); - if (directDecode) - buf = (PIXEL_T *)pb->getBufferRW(r, &stride); - else - buf = new PIXEL_T[r.area()]; - - if (palSize == 0) { - // Truecolor data - if (useGradient) { -#if BPP == 32 - if (cutZeros) { - FilterGradient24(netbuf, buf, stride, r); - } else -#endif - { - FILTER_GRADIENT(netbuf, buf, stride, r); - } - } else { - // Copy - int h = r.height(); - PIXEL_T *ptr = buf; - rdr::U8 *srcPtr = netbuf; - int w = r.width(); - if (cutZeros) { - while (h > 0) { - serverpf.bufferFromRGB((rdr::U8*)ptr, srcPtr, w); - ptr += stride; - srcPtr += w * 3; - h--; - } - } else { - while (h > 0) { - memcpy(ptr, srcPtr, w * sizeof(PIXEL_T)); - ptr += stride; - srcPtr += w * sizeof(PIXEL_T); - h--; - } - } - } - } else { - // Indexed color - int x, h = r.height(), w = r.width(), b, pad = stride - w; - PIXEL_T *ptr = buf; - rdr::U8 bits, *srcPtr = netbuf; - if (palSize <= 2) { - // 2-color palette - while (h > 0) { - for (x = 0; x < w / 8; x++) { - bits = *srcPtr++; - for (b = 7; b >= 0; b--) { - *ptr++ = palette[bits >> b & 1]; - } - } - if (w % 8 != 0) { - bits = *srcPtr++; - for (b = 7; b >= 8 - w % 8; b--) { - *ptr++ = palette[bits >> b & 1]; - } - } - ptr += pad; - h--; - } - } else { - // 256-color palette - while (h > 0) { - PIXEL_T *endOfRow = ptr + w; - while (ptr < endOfRow) { - *ptr++ = palette[*srcPtr++]; - } - ptr += pad; - h--; - } - } - } - - if (directDecode) - pb->commitBufferRW(r); - else { - pb->imageRect(serverpf, r, buf); - delete [] buf; - } - - delete [] netbuf; - - if (streamId != -1) { - zis[streamId].reset(); - } -} - -void -DECOMPRESS_JPEG_RECT(const Rect& r) -{ - // Read length - int compressedLen = readCompact(is); - if (compressedLen <= 0) { - throw Exception("Incorrect data received from the server.\n"); - } - - // Allocate netbuf and read in data - rdr::U8* netbuf = new rdr::U8[compressedLen]; - if (!netbuf) { - throw Exception("rfb::TightDecoder::DecompressJpegRect unable to allocate buffer"); - } - is->readBytes(netbuf, compressedLen); - - // We always use direct decoding with JPEG images - int stride; - rdr::U8 *buf = pb->getBufferRW(r, &stride); - jd.decompress(netbuf, compressedLen, buf, stride, r, clientpf); - pb->commitBufferRW(r); - - delete [] netbuf; -} #if BPP == 32 void -TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, - const Rect& r) +TightDecoder::FilterGradient24(const rdr::U8 *inbuf, + const PixelFormat& pf, PIXEL_T* outbuf, + int stride, const Rect& r) { int x, y, c; - static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; - static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; + rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; + rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; rdr::U8 pix[3]; int est[3]; @@ -287,10 +58,10 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, for (y = 0; y < rectHeight; y++) { /* First pixel in a row */ for (c = 0; c < 3; c++) { - pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c]; + pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c]; thisRow[c] = pix[c]; } - serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1); + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); /* Remaining pixels of a row */ for (x = 1; x < rectWidth; x++) { @@ -301,10 +72,10 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, } else if (est[c] < 0) { est[c] = 0; } - pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c]; + pix[c] = inbuf[(y*rectWidth+x)*3+c] + est[c]; thisRow[x*3+c] = pix[c]; } - serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1); + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1); } memcpy(prevRow, thisRow, sizeof(prevRow)); @@ -313,12 +84,15 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, #endif -void -FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r) +#if BPP != 8 + +void TightDecoder::FilterGradient(const rdr::U8* inbuf, + const PixelFormat& pf, PIXEL_T* outbuf, + int stride, const Rect& r) { int x, y, c; - static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)]; - static rdr::U8 thisRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)]; + static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3]; + static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3]; rdr::U8 pix[3]; int est[3]; @@ -330,13 +104,13 @@ FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r) for (y = 0; y < rectHeight; y++) { /* First pixel in a row */ - serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth], 1); + pf.rgbFromBuffer(pix, &inbuf[y*rectWidth], 1); for (c = 0; c < 3; c++) pix[c] += prevRow[c]; memcpy(thisRow, pix, sizeof(pix)); - serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1); + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1); /* Remaining pixels of a row */ for (x = 1; x < rectWidth; x++) { @@ -349,23 +123,60 @@ FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r) } } - serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1); + pf.rgbFromBuffer(pix, &inbuf[y*rectWidth+x], 1); for (c = 0; c < 3; c++) pix[c] += est[c]; memcpy(&thisRow[x*3], pix, sizeof(pix)); - serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1); + pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1); } memcpy(prevRow, thisRow, sizeof(prevRow)); } } -#undef TIGHT_MIN_TO_COMPRESS -#undef FILTER_GRADIENT -#undef DECOMPRESS_JPEG_RECT -#undef TIGHT_DECODE -#undef READ_PIXEL +#endif + +void TightDecoder::FilterPalette(const PIXEL_T* palette, int palSize, + const rdr::U8* inbuf, PIXEL_T* outbuf, + int stride, const Rect& r) +{ + // Indexed color + int x, h = r.height(), w = r.width(), b, pad = stride - w; + PIXEL_T* ptr = outbuf; + rdr::U8 bits; + const rdr::U8* srcPtr = inbuf; + if (palSize <= 2) { + // 2-color palette + while (h > 0) { + for (x = 0; x < w / 8; x++) { + bits = *srcPtr++; + for (b = 7; b >= 0; b--) { + *ptr++ = palette[bits >> b & 1]; + } + } + if (w % 8 != 0) { + bits = *srcPtr++; + for (b = 7; b >= 8 - w % 8; b--) { + *ptr++ = palette[bits >> b & 1]; + } + } + ptr += pad; + h--; + } + } else { + // 256-color palette + while (h > 0) { + PIXEL_T *endOfRow = ptr + w; + while (ptr < endOfRow) { + *ptr++ = palette[*srcPtr++]; + } + ptr += pad; + h--; + } + } +} + #undef PIXEL_T } -- 2.39.5