Przeglądaj źródła

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.
tags/v1.6.90
Pierre Ossman 8 lat temu
rodzic
commit
80b4209b54

+ 13
- 5
common/rfb/CopyRectDecoder.cxx Wyświetl plik

@@ -15,7 +15,8 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rdr/InStream.h>
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>
#include <rfb/PixelBuffer.h>
#include <rfb/CopyRectDecoder.h>

@@ -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));
}

+ 4
- 1
common/rfb/CopyRectDecoder.h Wyświetl plik

@@ -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

+ 10
- 1
common/rfb/DecodeManager.cxx Wyświetl plik

@@ -26,6 +26,7 @@
#include <rfb/LogWriter.h>

#include <rdr/Exception.h>
#include <rdr/MemOutStream.h>

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);
}

+ 3
- 0
common/rfb/DecodeManager.h Wyświetl plik

@@ -21,6 +21,8 @@

#include <rfb/encodings.h>

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;
};
}


+ 17
- 6
common/rfb/Decoder.h Wyświetl plik

@@ -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);

+ 56
- 5
common/rfb/HextileDecoder.cxx Wyświetl plik

@@ -15,7 +15,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/

#include <rdr/InStream.h>
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>

#include <rfb/ConnParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/HextileDecoder.h>
@@ -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;
}
}

+ 4
- 1
common/rfb/HextileDecoder.h Wyświetl plik

@@ -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

+ 21
- 4
common/rfb/RREDecoder.cxx Wyświetl plik

@@ -15,7 +15,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/

#include <rdr/InStream.h>
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>

#include <rfb/ConnParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/RREDecoder.h>
@@ -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;
}
}

+ 4
- 1
common/rfb/RREDecoder.h Wyświetl plik

@@ -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

+ 13
- 31
common/rfb/RawDecoder.cxx Wyświetl plik

@@ -15,7 +15,10 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <rdr/InStream.h>

#include <assert.h>

#include <rdr/OutStream.h>
#include <rfb/ConnParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/RawDecoder.h>
@@ -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);
}

+ 4
- 1
common/rfb/RawDecoder.h Wyświetl plik

@@ -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

+ 352
- 16
common/rfb/TightDecoder.cxx Wyświetl plik

@@ -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 <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;

#define TIGHT_MAX_WIDTH 2048
static const int TIGHT_MAX_WIDTH = 2048;
static const int TIGHT_MIN_TO_COMPRESS = 12;

#define BPP 8
#include <rfb/tightDecode.h>
@@ -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)

+ 21
- 24
common/rfb/TightDecoder.h Wyświetl plik

@@ -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;
};
}


+ 22
- 6
common/rfb/ZRLEDecoder.cxx Wyświetl plik

@@ -15,7 +15,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/

#include <rdr/InStream.h>
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>

#include <rfb/ConnParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/ZRLEDecoder.h>
@@ -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;
}

+ 4
- 1
common/rfb/ZRLEDecoder.h Wyświetl plik

@@ -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;
};

+ 11
- 9
common/rfb/hextileDecode.h Wyświetl plik

@@ -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;

+ 63
- 252
common/rfb/tightDecode.h Wyświetl plik

@@ -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 <rdr/InStream.h>
#include <rdr/ZlibInStream.h>
#include <rfb/Exception.h>
#include <rfb/TightConstants.h>

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
}

Ładowanie…
Anuluj
Zapisz