diff options
-rw-r--r-- | common/rfb/Encoder.h | 4 | ||||
-rw-r--r-- | common/rfb/HextileEncoder.cxx | 3 | ||||
-rw-r--r-- | common/rfb/HextileEncoder.h | 2 | ||||
-rw-r--r-- | common/rfb/JpegCompressor.cxx | 9 | ||||
-rw-r--r-- | common/rfb/JpegCompressor.h | 2 | ||||
-rw-r--r-- | common/rfb/PixelBuffer.h | 3 | ||||
-rw-r--r-- | common/rfb/PixelFormat.cxx | 46 | ||||
-rw-r--r-- | common/rfb/PixelFormat.h | 3 | ||||
-rw-r--r-- | common/rfb/PixelTransformer.cxx | 6 | ||||
-rw-r--r-- | common/rfb/PixelTransformer.h | 4 | ||||
-rw-r--r-- | common/rfb/RREEncoder.cxx | 2 | ||||
-rw-r--r-- | common/rfb/RREEncoder.h | 2 | ||||
-rw-r--r-- | common/rfb/RawEncoder.cxx | 2 | ||||
-rw-r--r-- | common/rfb/RawEncoder.h | 2 | ||||
-rw-r--r-- | common/rfb/SMsgWriter.cxx | 6 | ||||
-rw-r--r-- | common/rfb/SMsgWriter.h | 6 | ||||
-rw-r--r-- | common/rfb/TightEncoder.cxx | 95 | ||||
-rw-r--r-- | common/rfb/TightEncoder.h | 89 | ||||
-rw-r--r-- | common/rfb/TransImageGetter.cxx | 10 | ||||
-rw-r--r-- | common/rfb/TransImageGetter.h | 5 | ||||
-rw-r--r-- | common/rfb/ZRLEEncoder.cxx | 2 | ||||
-rw-r--r-- | common/rfb/ZRLEEncoder.h | 2 | ||||
-rw-r--r-- | common/rfb/tightEncode.h | 428 |
23 files changed, 460 insertions, 273 deletions
diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h index 2a6e2f6b..893c0138 100644 --- a/common/rfb/Encoder.h +++ b/common/rfb/Encoder.h @@ -20,6 +20,7 @@ #include <rfb/Rect.h> #include <rfb/encodings.h> +#include <rfb/TransImageGetter.h> namespace rfb { class SMsgWriter; @@ -38,7 +39,8 @@ namespace rfb { // writeRect() tries to write the given rectangle. If it is unable to // write the whole rectangle it returns false and sets actual to the actual // rectangle which was updated. - virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual)=0; + virtual bool writeRect(const Rect& r, TransImageGetter* ig, + Rect* actual)=0; static bool supported(int encoding); static Encoder* createEncoder(int encoding, SMsgWriter* writer); diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx index ba71d56d..73f1f575 100644 --- a/common/rfb/HextileEncoder.cxx +++ b/common/rfb/HextileEncoder.cxx @@ -58,7 +58,8 @@ HextileEncoder::~HextileEncoder() { } -bool HextileEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual) +bool HextileEncoder::writeRect(const Rect& r, TransImageGetter* ig, + Rect* actual) { writer->startRect(r, encodingHextile); rdr::OutStream* os = writer->getOutStream(); diff --git a/common/rfb/HextileEncoder.h b/common/rfb/HextileEncoder.h index c78107a4..6b89643d 100644 --- a/common/rfb/HextileEncoder.h +++ b/common/rfb/HextileEncoder.h @@ -25,7 +25,7 @@ namespace rfb { class HextileEncoder : public Encoder { public: static Encoder* create(SMsgWriter* writer); - virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual); + virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); virtual ~HextileEncoder(); private: HextileEncoder(SMsgWriter* writer); diff --git a/common/rfb/JpegCompressor.cxx b/common/rfb/JpegCompressor.cxx index e203560a..a55fee7e 100644 --- a/common/rfb/JpegCompressor.cxx +++ b/common/rfb/JpegCompressor.cxx @@ -114,7 +114,7 @@ JpegCompressor::~JpegCompressor(void) jpeg_destroy_compress(&cinfo); } -void JpegCompressor::compress(rdr::U8 *buf, const Rect& r, +void JpegCompressor::compress(rdr::U8 *buf, int pitch, const Rect& r, const PixelFormat& pf, int quality, JPEG_SUBSAMP subsamp) { int w = r.width(); @@ -168,10 +168,13 @@ void JpegCompressor::compress(rdr::U8 *buf, const Rect& r, } #endif + if (pitch == 0) pitch = w * pixelsize; + if (cinfo.in_color_space == JCS_RGB) { srcBuf = new rdr::U8[w * h * pixelsize]; srcBufIsTemp = true; - pf.rgbFromBuffer(srcBuf, (const rdr::U8 *)buf, w * h); + pf.rgbFromBuffer(srcBuf, (const rdr::U8 *)buf, w, pitch, h); + pitch = w * pixelsize; } cinfo.input_components = pixelsize; @@ -197,7 +200,7 @@ void JpegCompressor::compress(rdr::U8 *buf, const Rect& r, rowPointer = new JSAMPROW[h]; for (int dy = 0; dy < h; dy++) - rowPointer[dy] = (JSAMPROW)(&srcBuf[dy * w * pixelsize]); + rowPointer[dy] = (JSAMPROW)(&srcBuf[dy * pitch]); jpeg_start_compress(&cinfo, TRUE); while (cinfo.next_scanline < cinfo.image_height) diff --git a/common/rfb/JpegCompressor.h b/common/rfb/JpegCompressor.h index 5a9c2fd5..6860b415 100644 --- a/common/rfb/JpegCompressor.h +++ b/common/rfb/JpegCompressor.h @@ -63,7 +63,7 @@ namespace rfb { JpegCompressor(int bufferLen = 128*1024); virtual ~JpegCompressor(); - void compress(rdr::U8 *, const Rect&, const PixelFormat&, int, + void compress(rdr::U8 *, int, const Rect&, const PixelFormat&, int, JPEG_SUBSAMP); void writeBytes(const void*, int); diff --git a/common/rfb/PixelBuffer.h b/common/rfb/PixelBuffer.h index 4a13923c..fc35a7d7 100644 --- a/common/rfb/PixelBuffer.h +++ b/common/rfb/PixelBuffer.h @@ -68,6 +68,7 @@ namespace rfb { // The pointer is to the top-left pixel of the specified Rect. // The buffer stride (in pixels) is returned. virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) = 0; + virtual rdr::U8* getPixelsRW(const Rect& r, int* stride) = 0; // Get pixel data for a given part of the buffer // Data is copied into the supplied buffer, with the specified @@ -107,7 +108,7 @@ namespace rfb { virtual int getStride() const; // Get a pointer to specified pixel data - virtual rdr::U8* getPixelsRW(const Rect& r, int* stride); + rdr::U8* getPixelsRW(const Rect& r, int* stride); virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) { return getPixelsRW(r, stride); } diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index 11c2d7ab..013cceb2 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -1,5 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2009 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 @@ -295,6 +296,51 @@ void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels, Co } +void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, + int w, int pitch, int h, ColourMap* cm) const +{ + rdr::U8 *rowptr, *colptr; + + if (is888()) { + // Optimised common case + int rindex, gindex, bindex; + + if (bigEndian) { + rindex = (24 - redShift)/8; + gindex = (24 - greenShift)/8; + bindex = (24 - blueShift)/8; + } else { + rindex = redShift/8; + gindex = greenShift/8; + bindex = blueShift/8; + } + + for(rowptr = (rdr::U8 *)src; rowptr < &src[pitch * h]; rowptr += pitch) { + for(colptr = rowptr; colptr < &rowptr[w * 4]; colptr += 4) { + *(dst++) = colptr[rindex]; + *(dst++) = colptr[gindex]; + *(dst++) = colptr[bindex]; + } + } + } else { + // Generic code + Pixel p; + rdr::U8 r, g, b; + + for(rowptr = (rdr::U8 *)src; rowptr < &src[pitch * h]; rowptr += pitch) { + for(colptr = rowptr; colptr < &rowptr[w * bpp/8]; colptr += bpp/8) { + p = pixelFromBuffer(colptr); + + rgbFromPixel(p, cm, &r, &g, &b); + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + } + } + } +} + + void PixelFormat::print(char* str, int len) const { // Unfortunately snprintf is not widely available so we build the string up diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h index c1de09a9..6566e38b 100644 --- a/common/rfb/PixelFormat.h +++ b/common/rfb/PixelFormat.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * 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 @@ -59,6 +60,8 @@ namespace rfb { void rgbFromBuffer(rdr::U16* dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const; void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const; + void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int w, int pitch, + int h, ColourMap* cm=0) const; void print(char* str, int len) const; bool parse(const char* str); diff --git a/common/rfb/PixelTransformer.cxx b/common/rfb/PixelTransformer.cxx index ea43d9c7..c737f4d9 100644 --- a/common/rfb/PixelTransformer.cxx +++ b/common/rfb/PixelTransformer.cxx @@ -1,5 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2011 Pierre Ossman <ossman@cendio.se> 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 @@ -320,3 +321,8 @@ void PixelTransformer::translateRect(void* inPtr, int inStride, outPF, out, outStride, inRect.width(), inRect.height()); } + +bool PixelTransformer::willTransform(void) +{ + return transFn != NULL && transFn != noTransFn; +} diff --git a/common/rfb/PixelTransformer.h b/common/rfb/PixelTransformer.h index 54b05a5b..a368b63a 100644 --- a/common/rfb/PixelTransformer.h +++ b/common/rfb/PixelTransformer.h @@ -1,5 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2011 Pierre Ossman <ossman@cendio.se> 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 @@ -20,6 +21,7 @@ #ifndef __RFB_PIXELTRANSFORMER_H__ #define __RFB_PIXELTRANSFORMER_H__ +#include <stdlib.h> #include <rfb/Rect.h> #include <rfb/PixelFormat.h> @@ -83,6 +85,8 @@ namespace rfb { void translateRect(void* inPtr, int inStride, Rect inRect, void* outPtr, int outStride, Point outCoord) const; + bool willTransform(void); + private: bool economic; diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx index b000e9d3..1b86986f 100644 --- a/common/rfb/RREEncoder.cxx +++ b/common/rfb/RREEncoder.cxx @@ -46,7 +46,7 @@ RREEncoder::~RREEncoder() { } -bool RREEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual) +bool RREEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) { int w = r.width(); int h = r.height(); diff --git a/common/rfb/RREEncoder.h b/common/rfb/RREEncoder.h index 1281410d..6178d57f 100644 --- a/common/rfb/RREEncoder.h +++ b/common/rfb/RREEncoder.h @@ -26,7 +26,7 @@ namespace rfb { class RREEncoder : public Encoder { public: static Encoder* create(SMsgWriter* writer); - virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual); + virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); virtual ~RREEncoder(); private: RREEncoder(SMsgWriter* writer); diff --git a/common/rfb/RawEncoder.cxx b/common/rfb/RawEncoder.cxx index a2545b61..5612cb8d 100644 --- a/common/rfb/RawEncoder.cxx +++ b/common/rfb/RawEncoder.cxx @@ -36,7 +36,7 @@ RawEncoder::~RawEncoder() { } -bool RawEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual) +bool RawEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) { int x = r.tl.x; int y = r.tl.y; diff --git a/common/rfb/RawEncoder.h b/common/rfb/RawEncoder.h index 1b9ad929..34dba0b5 100644 --- a/common/rfb/RawEncoder.h +++ b/common/rfb/RawEncoder.h @@ -25,7 +25,7 @@ namespace rfb { class RawEncoder : public Encoder { public: static Encoder* create(SMsgWriter* writer); - virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual); + virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); virtual ~RawEncoder(); private: RawEncoder(SMsgWriter* writer); diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 2262be09..f0a97c59 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -142,7 +142,7 @@ void SMsgWriter::writeNoDataUpdate() vlog.error("writeNoDataUpdate() called"); } -void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig, +void SMsgWriter::writeRects(const UpdateInfo& ui, TransImageGetter* ig, Region* updatedRegion) { std::vector<Rect> rects; @@ -164,13 +164,13 @@ void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig, } } -bool SMsgWriter::writeRect(const Rect& r, ImageGetter* ig, Rect* actual) +bool SMsgWriter::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) { return writeRect(r, cp->currentEncoding(), ig, actual); } bool SMsgWriter::writeRect(const Rect& r, int encoding, - ImageGetter* ig, Rect* actual) + TransImageGetter* ig, Rect* actual) { if (!encoders[encoding]) { encoders[encoding] = Encoder::createEncoder(encoding, this); diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index 007d7580..8112d010 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -129,7 +129,7 @@ namespace rfb { // before the first writeRects() call and writeFrameBufferUpdateEnd() after // the last one. It returns the actual region sent to the client, which // may be smaller than the update passed in. - virtual void writeRects(const UpdateInfo& update, ImageGetter* ig, + virtual void writeRects(const UpdateInfo& update, TransImageGetter* ig, Region* updatedRegion); // To construct a framebuffer update you can call @@ -144,9 +144,9 @@ namespace rfb { // writeRect() tries to write the given rectangle. If it is unable to // write the whole rectangle it returns false and sets actual to the actual // rectangle which was updated. - virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual); + virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); virtual bool writeRect(const Rect& r, int encoding, - ImageGetter* ig, Rect* actual); + TransImageGetter* ig, Rect* actual); virtual void writeCopyRect(const Rect& r, int srcX, int srcY); diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx index 52673a6d..fa7ee9a7 100644 --- a/common/rfb/TightEncoder.cxx +++ b/common/rfb/TightEncoder.cxx @@ -17,7 +17,6 @@ * USA. */ #include <rdr/OutStream.h> -#include <rfb/ImageGetter.h> #include <rfb/encodings.h> #include <rfb/ConnParams.h> #include <rfb/SMsgWriter.h> @@ -77,16 +76,10 @@ const TIGHT_CONF TightEncoder::conf[10] = { }; const int TightEncoder::defaultCompressLevel = 1; -// FIXME: Not good to mirror TightEncoder's members here. -static const TIGHT_CONF* s_pconf; -static const TIGHT_CONF* s_pjconf; - // // Including BPP-dependent implementation of the encoder. // -#define EXTRA_ARGS ImageGetter* ig -#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r); #define BPP 8 #include <rfb/tightEncode.h> #undef BPP @@ -130,21 +123,20 @@ void TightEncoder::setQualityLevel(int level) } } -bool TightEncoder::checkSolidTile(Rect& r, ImageGetter *ig, rdr::U32* colorPtr, +bool TightEncoder::checkSolidTile(Rect& r, rdr::U32* colorPtr, bool needSameColor) { - switch (writer->bpp()) { + switch (serverpf.bpp) { case 32: - return checkSolidTile32(r, ig, writer, colorPtr, needSameColor); + return checkSolidTile32(r, colorPtr, needSameColor); case 16: - return checkSolidTile16(r, ig, writer, colorPtr, needSameColor); + return checkSolidTile16(r, colorPtr, needSameColor); default: - return checkSolidTile8(r, ig, writer, colorPtr, needSameColor); + return checkSolidTile8(r, colorPtr, needSameColor); } } -void TightEncoder::findBestSolidArea(Rect& r, ImageGetter *ig, - rdr::U32 colorValue, Rect& bestr) +void TightEncoder::findBestSolidArea(Rect& r, rdr::U32 colorValue, Rect& bestr) { int dx, dy, dw, dh; int w_prev; @@ -164,16 +156,16 @@ void TightEncoder::findBestSolidArea(Rect& r, ImageGetter *ig, TIGHT_MAX_SPLIT_TILE_SIZE : w_prev; sr.setXYWH(r.tl.x, dy, dw, dh); - if (!checkSolidTile(sr, ig, &colorValue, true)) + if (!checkSolidTile(sr, &colorValue, true)) break; for (dx = r.tl.x + dw; dx < r.tl.x + w_prev;) { dw = (dx + TIGHT_MAX_SPLIT_TILE_SIZE <= r.tl.x + w_prev) ? TIGHT_MAX_SPLIT_TILE_SIZE : (r.tl.x + w_prev - dx); sr.setXYWH(dx, dy, dw, dh); - if (!checkSolidTile(sr, ig, &colorValue, true)) + if (!checkSolidTile(sr, &colorValue, true)) break; - dx += dw; + dx += dw; } w_prev = dx - r.tl.x; @@ -187,8 +179,8 @@ void TightEncoder::findBestSolidArea(Rect& r, ImageGetter *ig, bestr.br.y = bestr.tl.y + h_best; } -void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig, - rdr::U32 colorValue, Rect& er) +void TightEncoder::extendSolidArea(const Rect& r, rdr::U32 colorValue, + Rect& er) { int cx, cy; Rect sr; @@ -196,7 +188,7 @@ void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig, // Try to extend the area upwards. for (cy = er.tl.y - 1; ; cy--) { sr.setXYWH(er.tl.x, cy, er.width(), 1); - if (cy < r.tl.y || !checkSolidTile(sr, ig, &colorValue, true)) + if (cy < r.tl.y || !checkSolidTile(sr, &colorValue, true)) break; } er.tl.y = cy + 1; @@ -204,7 +196,7 @@ void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig, // ... downwards. for (cy = er.br.y; ; cy++) { sr.setXYWH(er.tl.x, cy, er.width(), 1); - if (cy >= r.br.y || !checkSolidTile(sr, ig, &colorValue, true)) + if (cy >= r.br.y || !checkSolidTile(sr, &colorValue, true)) break; } er.br.y = cy; @@ -212,7 +204,7 @@ void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig, // ... to the left. for (cx = er.tl.x - 1; ; cx--) { sr.setXYWH(cx, er.tl.y, 1, er.height()); - if (cx < r.tl.x || !checkSolidTile(sr, ig, &colorValue, true)) + if (cx < r.tl.x || !checkSolidTile(sr, &colorValue, true)) break; } er.tl.x = cx + 1; @@ -220,7 +212,7 @@ void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig, // ... to the right. for (cx = er.br.x; ; cx++) { sr.setXYWH(cx, er.tl.y, 1, er.height()); - if (cx >= r.br.x || !checkSolidTile(sr, ig, &colorValue, true)) + if (cx >= r.br.x || !checkSolidTile(sr, &colorValue, true)) break; } er.br.x = cx; @@ -254,7 +246,7 @@ int TightEncoder::getNumRects(const Rect &r) ((h - 1) / subrectMaxHeight + 1)); } -void TightEncoder::sendRectSimple(const Rect& r, ImageGetter* ig) +void TightEncoder::sendRectSimple(const Rect& r) { // Shortcuts to rectangle coordinates and dimensions. const int x = r.tl.x; @@ -265,7 +257,7 @@ void TightEncoder::sendRectSimple(const Rect& r, ImageGetter* ig) // Encode small rects as is. bool rectTooBig = w > pconf->maxRectWidth || w * h > pconf->maxRectSize; if (!rectTooBig) { - writeSubrect(r, ig); + writeSubrect(r); return; } @@ -283,14 +275,18 @@ void TightEncoder::sendRectSimple(const Rect& r, ImageGetter* ig) sw = (dx + pconf->maxRectWidth < w) ? pconf->maxRectWidth : w - dx; sh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy; sr.setXYWH(x + dx, y + dy, sw, sh); - writeSubrect(sr, ig); + writeSubrect(sr); } } } -bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual) +bool TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig, + Rect* actual) { + ig = _ig; + serverpf = ig->getPixelBuffer()->getPF(); ConnParams* cp = writer->getConnParams(); + clientpf = cp->pf(); // Shortcuts to rectangle coordinates and dimensions. Rect r = _r; @@ -299,13 +295,9 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual) unsigned int w = r.width(); unsigned int h = r.height(); - // Copy members of current TightEncoder instance to static variables. - s_pconf = pconf; - s_pjconf = pjconf; - // Encode small rects as is. if (!cp->supportsLastRect || w * h < TIGHT_MIN_SPLIT_RECT_SIZE) { - sendRectSimple(r, ig); + sendRectSimple(r); return true; } @@ -313,10 +305,10 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual) Rect sr, bestr; unsigned int dx, dy, dw, dh; rdr::U32 colorValue; - int maxRectSize = s_pconf->maxRectSize; - int maxRectWidth = s_pconf->maxRectWidth; + int maxRectSize = pconf->maxRectSize; + int maxRectWidth = pconf->maxRectWidth; int nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w; - int nMaxRows = s_pconf->maxRectSize / nMaxWidth; + int nMaxRows = pconf->maxRectSize / nMaxWidth; // Try to find large solid-color areas and send them separately. for (dy = y; dy < y + h; dy += TIGHT_MAX_SPLIT_TILE_SIZE) { @@ -324,7 +316,7 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual) // If a rectangle becomes too large, send its upper part now. if (dy - y >= nMaxRows) { sr.setXYWH(x, y, w, nMaxRows); - sendRectSimple(sr, ig); + sendRectSimple(sr); r.tl.y += nMaxRows; y = r.tl.y; h = r.height(); @@ -339,11 +331,11 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual) TIGHT_MAX_SPLIT_TILE_SIZE : (x + w - dx); sr.setXYWH(dx, dy, dw, dh); - if (checkSolidTile(sr, ig, &colorValue, false)) { + if (checkSolidTile(sr, &colorValue, false)) { // Get dimensions of solid-color area. sr.setXYWH(dx, dy, r.br.x - dx, r.br.y - dy); - findBestSolidArea(sr, ig, colorValue, bestr); + findBestSolidArea(sr, colorValue, bestr); // Make sure a solid rectangle is large enough // (or the whole rectangle is of the same color). @@ -352,30 +344,30 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual) continue; // Try to extend solid rectangle to maximum size. - extendSolidArea(r, ig, colorValue, bestr); + extendSolidArea(r, colorValue, bestr); // Send rectangles at top and left to solid-color area. if (bestr.tl.y != y) { sr.setXYWH(x, y, w, bestr.tl.y - y); - sendRectSimple(sr, ig); + sendRectSimple(sr); } if (bestr.tl.x != x) { sr.setXYWH(x, bestr.tl.y, bestr.tl.x - x, bestr.height()); - writeRect(sr, ig, NULL); + writeRect(sr, _ig, NULL); } // Send solid-color rectangle. - writeSubrect(bestr, ig, true); + writeSubrect(bestr, true); // Send remaining rectangles (at right and bottom). if (bestr.br.x != r.br.x) { sr.setXYWH(bestr.br.x, bestr.tl.y, r.br.x - bestr.br.x, bestr.height()); - writeRect(sr, ig, NULL); + writeRect(sr, _ig, NULL); } if (bestr.br.y != r.br.y) { sr.setXYWH(x, bestr.br.y, w, r.br.y - bestr.br.y); - writeRect(sr, ig, NULL); + writeRect(sr, _ig, NULL); } return true; @@ -384,24 +376,21 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual) } // No suitable solid-color rectangles found. - sendRectSimple(r, ig); + sendRectSimple(r); return true; } -void TightEncoder::writeSubrect(const Rect& r, ImageGetter* ig, - bool forceSolid) +void TightEncoder::writeSubrect(const Rect& r, bool forceSolid) { - rdr::U8* imageBuf = writer->getImageBuf(r.area()); - ConnParams* cp = writer->getConnParams(); mos.clear(); - switch (writer->bpp()) { + switch (clientpf.bpp) { case 8: - tightEncode8(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid); break; + tightEncode8(r, &mos, forceSolid); break; case 16: - tightEncode16(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid); break; + tightEncode16(r, &mos, forceSolid); break; case 32: - tightEncode32(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid); break; + tightEncode32(r, &mos, forceSolid); break; } writer->startRect(r, encodingTight); diff --git a/common/rfb/TightEncoder.h b/common/rfb/TightEncoder.h index 064a8343..ae9672c0 100644 --- a/common/rfb/TightEncoder.h +++ b/common/rfb/TightEncoder.h @@ -22,6 +22,7 @@ #include <rdr/MemOutStream.h> #include <rdr/ZlibOutStream.h> #include <rfb/JpegCompressor.h> +#include <rfb/TransImageGetter.h> #include <rfb/Encoder.h> // FIXME: Check if specifying extern "C" is really necessary. @@ -43,6 +44,28 @@ namespace rfb { }; // + // C-style structures to store palette entries and compression paramentes. + // Such code probably should be converted into C++ classes. + // + + struct TIGHT_COLOR_LIST { + TIGHT_COLOR_LIST *next; + int idx; + rdr::U32 rgb; + }; + + struct TIGHT_PALETTE_ENTRY { + TIGHT_COLOR_LIST *listNode; + int numPixels; + }; + + struct TIGHT_PALETTE { + TIGHT_PALETTE_ENTRY entry[256]; + TIGHT_COLOR_LIST *hash[256]; + TIGHT_COLOR_LIST list[256]; + }; + + // // Compression level stuff. The following array contains various // encoder parameters for each of 10 compression levels (0..9). // Last three parameters correspond to JPEG quality levels (0..9). @@ -59,24 +82,72 @@ namespace rfb { virtual void setCompressLevel(int level); virtual void setQualityLevel(int level); virtual int getNumRects(const Rect &r); - virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual); + virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); virtual ~TightEncoder(); private: TightEncoder(SMsgWriter* writer); - bool checkSolidTile(Rect& r, ImageGetter *ig, rdr::U32* colorPtr, - bool needSameColor); - void extendSolidArea(const Rect& r, ImageGetter *ig, - rdr::U32 colorValue, Rect& er); - void findBestSolidArea(Rect& r, ImageGetter* ig, rdr::U32 colorValue, - Rect& bestr); - void sendRectSimple(const Rect& r, ImageGetter* ig); - void writeSubrect(const Rect& r, ImageGetter* ig, bool forceSolid = false); + bool checkSolidTile(Rect& r, rdr::U32* colorPtr, bool needSameColor); + void extendSolidArea(const Rect& r, rdr::U32 colorValue, Rect& er); + void findBestSolidArea(Rect& r, rdr::U32 colorValue, Rect& bestr); + void sendRectSimple(const Rect& r); + void writeSubrect(const Rect& r, bool forceSolid = false); + + void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos, + const void *buf, unsigned int length, int zlibLevel); + + int paletteInsert(rdr::U32 rgb, int numPixels, int bpp); + void paletteReset(void); + + void fastFillPalette8(const Rect &r, rdr::U8 *data, int stride); + void fastFillPalette16(const Rect &r, rdr::U16 *data, int stride); + void fastFillPalette32(const Rect &r, rdr::U32 *data, int stride); + + void fillPalette8(rdr::U8 *data, int count); + void fillPalette16(rdr::U16 *data, int count); + void fillPalette32(rdr::U32 *data, int count); + + unsigned int packPixels8(rdr::U8 *buf, unsigned int count); + unsigned int packPixels16(rdr::U16 *buf, unsigned int count); + unsigned int packPixels32(rdr::U32 *buf, unsigned int count); + + void tightEncode8(const Rect& r, rdr::OutStream *os, bool forceSolid); + void tightEncode16(const Rect& r, rdr::OutStream *os, bool forceSolid); + void tightEncode32(const Rect& r, rdr::OutStream *os, bool forceSolid); + + bool checkSolidTile8(Rect& r, rdr::U32 *colorPtr, bool needSameColor); + bool checkSolidTile16(Rect& r, rdr::U32 *colorPtr, bool needSameColor); + bool checkSolidTile32(Rect& r, rdr::U32 *colorPtr, bool needSameColor); + + void encodeSolidRect8(rdr::OutStream *os, rdr::U8 *buf); + void encodeSolidRect16(rdr::OutStream *os, rdr::U16 *buf); + void encodeSolidRect32(rdr::OutStream *os, rdr::U32 *buf); + + void encodeFullColorRect8(rdr::OutStream *os, rdr::U8 *buf, const Rect& r); + void encodeFullColorRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r); + void encodeFullColorRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r); + + void encodeMonoRect8(rdr::OutStream *os, rdr::U8 *buf, const Rect& r); + void encodeMonoRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r); + void encodeMonoRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r); + + void encodeIndexedRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r); + void encodeIndexedRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r); + + void encodeJpegRect16(rdr::OutStream *os, rdr::U16 *buf, int, const Rect& r); + void encodeJpegRect32(rdr::OutStream *os, rdr::U32 *buf, int, const Rect& r); SMsgWriter* writer; rdr::MemOutStream mos; rdr::ZlibOutStream zos[4]; JpegCompressor jc; + TransImageGetter *ig; + PixelFormat serverpf, clientpf; + + bool pack24; + int palMaxColors, palNumColors; + rdr::U32 monoBackground, monoForeground; + TIGHT_PALETTE palette; static const int defaultCompressLevel; static const TIGHT_CONF conf[]; diff --git a/common/rfb/TransImageGetter.cxx b/common/rfb/TransImageGetter.cxx index f4154554..e0c60a40 100644 --- a/common/rfb/TransImageGetter.cxx +++ b/common/rfb/TransImageGetter.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * 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 @@ -55,6 +56,14 @@ void TransImageGetter::setColourMapEntries(int firstCol, int nCols) PixelTransformer::setColourMapEntries(firstCol, nCols); } +rdr::U8 *TransImageGetter::getPixelsRW(const Rect &r, int *stride) +{ + if (!offset.equals(Point(0, 0))) + return pb->getPixelsRW(r.translate(offset.negate()), stride); + else + return pb->getPixelsRW(r, stride); +} + void TransImageGetter::getImage(void* outPtr, const Rect& r, int outStride) { int inStride; @@ -77,4 +86,3 @@ void TransImageGetter::cmCallback(int firstColour, int nColours, if (self->writer) self->writer->writeSetColourMapEntries(firstColour, nColours, cm); } - diff --git a/common/rfb/TransImageGetter.h b/common/rfb/TransImageGetter.h index 7942247a..8fde743b 100644 --- a/common/rfb/TransImageGetter.h +++ b/common/rfb/TransImageGetter.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * 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 @@ -71,11 +72,15 @@ namespace rfb { // padding will be outStride-r.width() pixels). void getImage(void* outPtr, const Rect& r, int outStride=0); + rdr::U8 *getPixelsRW(const Rect &r, int *stride); + // setPixelBuffer() changes the pixel buffer to be used. The new pixel // buffer MUST have the same pixel format as the old one - if not you // should call init() instead. void setPixelBuffer(PixelBuffer* pb_) { pb = pb_; } + PixelBuffer *getPixelBuffer(void) { return pb; } + // setOffset() sets an offset which is subtracted from the coordinates of // the rectangle given to getImage(). void setOffset(const Point& offset_) { offset = offset_; } diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx index ef0dd9f5..a83d79f3 100644 --- a/common/rfb/ZRLEEncoder.cxx +++ b/common/rfb/ZRLEEncoder.cxx @@ -69,7 +69,7 @@ ZRLEEncoder::~ZRLEEncoder() delete mos; } -bool ZRLEEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual) +bool ZRLEEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) { rdr::U8* imageBuf = writer->getImageBuf(64 * 64 * 4 + 4); mos->clear(); diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h index 7768917d..3a0f52a9 100644 --- a/common/rfb/ZRLEEncoder.h +++ b/common/rfb/ZRLEEncoder.h @@ -27,7 +27,7 @@ namespace rfb { class ZRLEEncoder : public Encoder { public: static Encoder* create(SMsgWriter* writer); - virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual); + virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); virtual ~ZRLEEncoder(); // setMaxLen() sets the maximum size in bytes of any ZRLE rectangle. This diff --git a/common/rfb/tightEncode.h b/common/rfb/tightEncode.h index d4c8f6e3..9b2b29d1 100644 --- a/common/rfb/tightEncode.h +++ b/common/rfb/tightEncode.h @@ -26,8 +26,6 @@ // GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer // -#include <rdr/OutStream.h> -#include <rdr/ZlibOutStream.h> #include <assert.h> namespace rfb { @@ -40,79 +38,35 @@ namespace rfb { #endif #define PIXEL_T rdr::CONCAT2E(U,BPP) -#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP) -#define TIGHT_ENCODE CONCAT2E(tightEncode,BPP) -#define SWAP_PIXEL CONCAT2E(SWAP,BPP) +#define TIGHT_ENCODE TightEncoder::CONCAT2E(tightEncode,BPP) #define HASH_FUNCTION CONCAT2E(HASH_FUNC,BPP) -#define PACK_PIXELS CONCAT2E(packPixels,BPP) -#define ENCODE_SOLID_RECT CONCAT2E(encodeSolidRect,BPP) -#define ENCODE_FULLCOLOR_RECT CONCAT2E(encodeFullColorRect,BPP) -#define ENCODE_MONO_RECT CONCAT2E(encodeMonoRect,BPP) -#define ENCODE_INDEXED_RECT CONCAT2E(encodeIndexedRect,BPP) -#define ENCODE_JPEG_RECT CONCAT2E(encodeJpegRect,BPP) -#define FILL_PALETTE CONCAT2E(fillPalette,BPP) -#define CHECK_SOLID_TILE CONCAT2E(checkSolidTile,BPP) +#define PACK_PIXELS TightEncoder::CONCAT2E(packPixels,BPP) +#define ENCODE_SOLID_RECT TightEncoder::CONCAT2E(encodeSolidRect,BPP) +#define ENCODE_FULLCOLOR_RECT TightEncoder::CONCAT2E(encodeFullColorRect,BPP) +#define ENCODE_MONO_RECT TightEncoder::CONCAT2E(encodeMonoRect,BPP) +#define ENCODE_INDEXED_RECT TightEncoder::CONCAT2E(encodeIndexedRect,BPP) +#define ENCODE_JPEG_RECT TightEncoder::CONCAT2E(encodeJpegRect,BPP) +#define FAST_FILL_PALETTE TightEncoder::CONCAT2E(fastFillPalette,BPP) +#define FILL_PALETTE TightEncoder::CONCAT2E(fillPalette,BPP) +#define CHECK_SOLID_TILE TightEncoder::CONCAT2E(checkSolidTile,BPP) #ifndef TIGHT_ONCE #define TIGHT_ONCE // -// C-style structures to store palette entries and compression paramentes. -// Such code probably should be converted into C++ classes. -// - -struct TIGHT_COLOR_LIST { - TIGHT_COLOR_LIST *next; - int idx; - rdr::U32 rgb; -}; - -struct TIGHT_PALETTE_ENTRY { - TIGHT_COLOR_LIST *listNode; - int numPixels; -}; - -struct TIGHT_PALETTE { - TIGHT_PALETTE_ENTRY entry[256]; - TIGHT_COLOR_LIST *hash[256]; - TIGHT_COLOR_LIST list[256]; -}; - -// FIXME: Is it really a good idea to use static variables for this? -static bool s_pack24; // use 24-bit packing for 32-bit pixels - -// FIXME: Make a separate class for palette operations. -static int s_palMaxColors, s_palNumColors; -static rdr::U32 s_monoBackground, s_monoForeground; -static TIGHT_PALETTE s_palette; - -// -// Swapping bytes in pixels. -// FIXME: Use a sort of ImageGetter that does not convert pixel format? -// - -#ifndef SWAP16 -#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff)) -#endif -#ifndef SWAP32 -#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \ - (((n) & 0x0000ff00) << 8) | ((n) << 24)) -#endif - -// // Functions to operate on palette structures. // #define HASH_FUNC16(rgb) ((int)(((rgb >> 8) + rgb) & 0xFF)) #define HASH_FUNC32(rgb) ((int)(((rgb >> 16) + (rgb >> 8)) & 0xFF)) -static void paletteReset(void) +void TightEncoder::paletteReset(void) { - s_palNumColors = 0; - memset(s_palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *)); + palNumColors = 0; + memset(palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *)); } -static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp) +int TightEncoder::paletteInsert(rdr::U32 rgb, int numPixels, int bpp) { TIGHT_COLOR_LIST *pnode; TIGHT_COLOR_LIST *prev_pnode = NULL; @@ -120,59 +74,59 @@ static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp) hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb); - pnode = s_palette.hash[hash_key]; + pnode = palette.hash[hash_key]; while (pnode != NULL) { if (pnode->rgb == rgb) { // Such palette entry already exists. new_idx = idx = pnode->idx; - count = s_palette.entry[idx].numPixels + numPixels; - if (new_idx && s_palette.entry[new_idx-1].numPixels < count) { + count = palette.entry[idx].numPixels + numPixels; + if (new_idx && palette.entry[new_idx-1].numPixels < count) { do { - s_palette.entry[new_idx] = s_palette.entry[new_idx-1]; - s_palette.entry[new_idx].listNode->idx = new_idx; + palette.entry[new_idx] = palette.entry[new_idx-1]; + palette.entry[new_idx].listNode->idx = new_idx; new_idx--; } while (new_idx && - s_palette.entry[new_idx-1].numPixels < count); - s_palette.entry[new_idx].listNode = pnode; + palette.entry[new_idx-1].numPixels < count); + palette.entry[new_idx].listNode = pnode; pnode->idx = new_idx; } - s_palette.entry[new_idx].numPixels = count; - return s_palNumColors; + palette.entry[new_idx].numPixels = count; + return palNumColors; } prev_pnode = pnode; pnode = pnode->next; } // Check if palette is full. - if ( s_palNumColors == 256 || s_palNumColors == s_palMaxColors ) { - s_palNumColors = 0; + if ( palNumColors == 256 || palNumColors == palMaxColors ) { + palNumColors = 0; return 0; } // Move palette entries with lesser pixel counts. - for ( idx = s_palNumColors; - idx > 0 && s_palette.entry[idx-1].numPixels < numPixels; + for ( idx = palNumColors; + idx > 0 && palette.entry[idx-1].numPixels < numPixels; idx-- ) { - s_palette.entry[idx] = s_palette.entry[idx-1]; - s_palette.entry[idx].listNode->idx = idx; + palette.entry[idx] = palette.entry[idx-1]; + palette.entry[idx].listNode->idx = idx; } // Add new palette entry into the freed slot. - pnode = &s_palette.list[s_palNumColors]; + pnode = &palette.list[palNumColors]; if (prev_pnode != NULL) { prev_pnode->next = pnode; } else { - s_palette.hash[hash_key] = pnode; + palette.hash[hash_key] = pnode; } pnode->next = NULL; pnode->idx = idx; pnode->rgb = rgb; - s_palette.entry[idx].listNode = pnode; - s_palette.entry[idx].numPixels = numPixels; + palette.entry[idx].listNode = pnode; + palette.entry[idx].numPixels = numPixels; - return (++s_palNumColors); + return (++palNumColors); } // @@ -180,16 +134,16 @@ static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp) // size is less than TIGHT_MIN_TO_COMPRESS bytes. // -static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos, - const void *buf, const PixelFormat& pf, - unsigned int length, int zlibLevel) +void TightEncoder::compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos, + const void *buf, unsigned int length, + int zlibLevel) { if (length < TIGHT_MIN_TO_COMPRESS) { os->writeBytes(buf, length); } else { // FIXME: Using a temporary MemOutStream may be not efficient. // Maybe use the same static object used in the JPEG coder? - int maxBeforeSize = s_pconf->maxRectSize * (pf.bpp / 8); + int maxBeforeSize = pconf->maxRectSize * (clientpf.bpp / 8); int maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12; rdr::MemOutStream mem_os(maxAfterSize); zos->setUnderlying(&mem_os); @@ -204,41 +158,25 @@ static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos, #endif // #ifndef TIGHT_ONCE -static void ENCODE_SOLID_RECT (rdr::OutStream *os, - PIXEL_T *buf, const PixelFormat& pf); -static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], - PIXEL_T *buf, const PixelFormat& pf, const Rect& r); -static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], - PIXEL_T *buf, const PixelFormat& pf, const Rect& r); -#if (BPP != 8) -static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], - PIXEL_T *buf, const PixelFormat& pf, const Rect& r); -static void ENCODE_JPEG_RECT (rdr::OutStream *os, JpegCompressor& jc, - PIXEL_T *buf, const PixelFormat& pf, const Rect& r); -#endif - -static void FILL_PALETTE (PIXEL_T *data, int count); - // // Convert 32-bit color samples into 24-bit colors, in place. // Performs packing only when redMax, greenMax and blueMax are all 255. // Color components are assumed to be byte-aligned. // -static inline unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count, - const PixelFormat& pf) +unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count) { #if (BPP != 32) return count * sizeof(PIXEL_T); #else - if (!s_pack24) + if (!pack24) return count * sizeof(PIXEL_T); rdr::U32 pix; rdr::U8 *dst = (rdr::U8 *)buf; for (unsigned int i = 0; i < count; i++) { pix = *buf++; - pf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1, NULL); + clientpf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1, NULL); dst += 3; } return count * 3; @@ -249,64 +187,67 @@ static inline unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count, // Main function of the Tight encoder // -void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os, - rdr::ZlibOutStream zos[4], JpegCompressor &jc, void* buf, - ConnParams* cp -#ifdef EXTRA_ARGS - , EXTRA_ARGS, -#endif - bool forceSolid) +void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os, bool forceSolid) { - const PixelFormat& pf = cp->pf(); - if(forceSolid) { - GET_IMAGE_INTO_BUF(Rect(r.tl.x, r.tl.y, r.tl.x + 1, r.tl.y + 1), buf); - } - else { - GET_IMAGE_INTO_BUF(r, buf); - } - PIXEL_T* pixels = (PIXEL_T*)buf; + int stride = r.width(); + PIXEL_T *pixels = (PIXEL_T *)ig->getPixelsRW(r, &stride); #if (BPP == 32) // Check if it's necessary to pack 24-bit pixels, and // compute appropriate shift values if necessary. - s_pack24 = pf.is888(); + pack24 = clientpf.is888(); #endif if (forceSolid) - s_palNumColors = 1; + palNumColors = 1; else { - s_palMaxColors = r.area() / s_pconf->idxMaxColorsDivisor; - if (s_pjconf != NULL) s_palMaxColors = s_pconf->palMaxColorsWithJPEG; - if (s_palMaxColors < 2 && r.area() >= s_pconf->monoMinRectSize) { - s_palMaxColors = 2; + palMaxColors = r.area() / pconf->idxMaxColorsDivisor; + if (pjconf != NULL) palMaxColors = pconf->palMaxColorsWithJPEG; + if (palMaxColors < 2 && r.area() >= pconf->monoMinRectSize) { + palMaxColors = 2; } - FILL_PALETTE(pixels, r.area()); + if (clientpf.equal(serverpf) && clientpf.bpp >= 16) { + // This is so we can avoid translating the pixels when compressing + // with JPEG, since it is unnecessary + FAST_FILL_PALETTE(r, pixels, stride); + if(palNumColors != 0 || pjconf == NULL) { + pixels = (PIXEL_T *)writer->getImageBuf(r.area()); + stride = r.width(); + ig->getImage(pixels, r); + } + } + else { + pixels = (PIXEL_T *)writer->getImageBuf(r.area()); + stride = r.width(); + ig->getImage(pixels, r); + FILL_PALETTE(pixels, r.area()); + } } - switch (s_palNumColors) { + switch (palNumColors) { case 0: // Truecolor image #if (BPP != 8) - if (s_pjconf != NULL) { - ENCODE_JPEG_RECT(os, jc, pixels, pf, r); + if (pjconf != NULL) { + ENCODE_JPEG_RECT(os, pixels, stride, r); break; } #endif - ENCODE_FULLCOLOR_RECT(os, zos, pixels, pf, r); + ENCODE_FULLCOLOR_RECT(os, pixels, r); break; case 1: // Solid rectangle - ENCODE_SOLID_RECT(os, pixels, pf); + ENCODE_SOLID_RECT(os, pixels); break; case 2: // Two-color rectangle - ENCODE_MONO_RECT(os, zos, pixels, pf, r); + ENCODE_MONO_RECT(os, pixels, r); break; #if (BPP != 8) default: // Up to 256 different colors - ENCODE_INDEXED_RECT(os, zos, pixels, pf, r); + ENCODE_INDEXED_RECT(os, pixels, r); #endif } } @@ -315,35 +256,33 @@ void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os, // Subencoding implementations. // -static void ENCODE_SOLID_RECT (rdr::OutStream *os, PIXEL_T *buf, const PixelFormat& pf) +void ENCODE_SOLID_RECT (rdr::OutStream *os, PIXEL_T *buf) { os->writeU8(0x08 << 4); - int length = PACK_PIXELS(buf, 1, pf); + int length = PACK_PIXELS(buf, 1); os->writeBytes(buf, length); } -static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], - PIXEL_T *buf, const PixelFormat& pf, const Rect& r) +void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r) { const int streamId = 0; os->writeU8(streamId << 4); - int length = PACK_PIXELS(buf, r.area(), pf); - compressData(os, &zos[streamId], buf, pf, length, s_pconf->rawZlibLevel); + int length = PACK_PIXELS(buf, r.area()); + compressData(os, &zos[streamId], buf, length, pconf->rawZlibLevel); } -static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], - PIXEL_T *buf, const PixelFormat& pf, const Rect& r) +void ENCODE_MONO_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r) { const int streamId = 1; os->writeU8((streamId | 0x04) << 4); os->writeU8(0x01); // Write the palette - PIXEL_T pal[2] = { (PIXEL_T)s_monoBackground, (PIXEL_T)s_monoForeground }; + PIXEL_T pal[2] = { (PIXEL_T)monoBackground, (PIXEL_T)monoForeground }; os->writeU8(1); - os->writeBytes(pal, PACK_PIXELS(pal, 2, pf)); + os->writeBytes(pal, PACK_PIXELS(pal, 2)); // Encode the data in-place PIXEL_T *src = buf; @@ -355,7 +294,7 @@ static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], int aligned_width; int x, y, bg_bits; - bg = (PIXEL_T) s_monoBackground; + bg = (PIXEL_T) monoBackground; aligned_width = w - w % 8; for (y = 0; y < h; y++) { @@ -396,12 +335,11 @@ static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], // Write the data int length = (w + 7) / 8; length *= h; - compressData(os, &zos[streamId], buf, pf, length, s_pconf->monoZlibLevel); + compressData(os, &zos[streamId], buf, length, pconf->monoZlibLevel); } #if (BPP != 8) -static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], - PIXEL_T *buf, const PixelFormat& pf, const Rect& r) +void ENCODE_INDEXED_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r) { const int streamId = 2; os->writeU8((streamId | 0x04) << 4); @@ -410,10 +348,10 @@ static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], // Write the palette { PIXEL_T pal[256]; - for (int i = 0; i < s_palNumColors; i++) - pal[i] = (PIXEL_T)s_palette.entry[i].listNode->rgb; - os->writeU8((rdr::U8)(s_palNumColors - 1)); - os->writeBytes(pal, PACK_PIXELS(pal, s_palNumColors, pf)); + for (int i = 0; i < palNumColors; i++) + pal[i] = (PIXEL_T)palette.entry[i].listNode->rgb; + os->writeU8((rdr::U8)(palNumColors - 1)); + os->writeBytes(pal, PACK_PIXELS(pal, palNumColors)); } // Encode data in-place @@ -429,7 +367,7 @@ static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], while (count && *src == rgb) { rep++, src++, count--; } - pnode = s_palette.hash[HASH_FUNCTION(rgb)]; + pnode = palette.hash[HASH_FUNCTION(rgb)]; while (pnode != NULL) { if ((PIXEL_T)pnode->rgb == rgb) { *dst++ = (rdr::U8)pnode->idx; @@ -444,7 +382,7 @@ static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], } // Write the data - compressData(os, &zos[streamId], buf, pf, r.area(), s_pconf->idxZlibLevel); + compressData(os, &zos[streamId], buf, r.area(), pconf->idxZlibLevel); } #endif // #if (BPP != 8) @@ -453,13 +391,12 @@ static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4], // #if (BPP != 8) -static void ENCODE_JPEG_RECT (rdr::OutStream *os, JpegCompressor& jc, - PIXEL_T *buf, const PixelFormat& pf, - const Rect& r) +void ENCODE_JPEG_RECT (rdr::OutStream *os, PIXEL_T *buf, int stride, + const Rect& r) { jc.clear(); - jc.compress((rdr::U8 *)buf, r, pf, s_pjconf->jpegQuality, - s_pjconf->jpegSubSample); + jc.compress((rdr::U8 *)buf, stride * serverpf.bpp / 8, r, serverpf, + pjconf->jpegQuality, pjconf->jpegSubSample); os->writeU8(0x09 << 4); os->writeCompactLength(jc.length()); os->writeBytes(jc.data(), jc.length()); @@ -471,21 +408,22 @@ static void ENCODE_JPEG_RECT (rdr::OutStream *os, JpegCompressor& jc, // #if (BPP == 8) -static void FILL_PALETTE (PIXEL_T *data, int count) + +void FILL_PALETTE (PIXEL_T *data, int count) { PIXEL_T c0, c1; int i, n0, n1; - s_palNumColors = 0; + palNumColors = 0; c0 = data[0]; for (i = 1; i < count && data[i] == c0; i++); if (i == count) { - s_palNumColors = 1; + palNumColors = 1; return; // Solid rectangle } - if (s_palMaxColors < 2) + if (palMaxColors < 2) return; n0 = i; @@ -501,17 +439,23 @@ static void FILL_PALETTE (PIXEL_T *data, int count) } if (i == count) { if (n0 > n1) { - s_monoBackground = (rdr::U32)c0; - s_monoForeground = (rdr::U32)c1; + monoBackground = (rdr::U32)c0; + monoForeground = (rdr::U32)c1; } else { - s_monoBackground = (rdr::U32)c1; - s_monoForeground = (rdr::U32)c0; + monoBackground = (rdr::U32)c1; + monoForeground = (rdr::U32)c0; } - s_palNumColors = 2; // Two colors + palNumColors = 2; // Two colors } } + +void FAST_FILL_PALETTE (const Rect& r, PIXEL_T *data, int stride) +{ +} + #else // (BPP != 8) -static void FILL_PALETTE (PIXEL_T *data, int count) + +void FILL_PALETTE (PIXEL_T *data, int count) { PIXEL_T c0, c1, ci = 0; int i, n0, n1, ni; @@ -519,12 +463,12 @@ static void FILL_PALETTE (PIXEL_T *data, int count) c0 = data[0]; for (i = 1; i < count && data[i] == c0; i++); if (i >= count) { - s_palNumColors = 1; // Solid rectangle + palNumColors = 1; // Solid rectangle return; } - if (s_palMaxColors < 2) { - s_palNumColors = 0; // Full-color format preferred + if (palMaxColors < 2) { + palNumColors = 0; // Full-color format preferred return; } @@ -542,13 +486,13 @@ static void FILL_PALETTE (PIXEL_T *data, int count) } if (i >= count) { if (n0 > n1) { - s_monoBackground = (rdr::U32)c0; - s_monoForeground = (rdr::U32)c1; + monoBackground = (rdr::U32)c0; + monoForeground = (rdr::U32)c1; } else { - s_monoBackground = (rdr::U32)c1; - s_monoForeground = (rdr::U32)c0; + monoBackground = (rdr::U32)c1; + monoForeground = (rdr::U32)c0; } - s_palNumColors = 2; // Two colors + palNumColors = 2; // Two colors return; } @@ -569,32 +513,137 @@ static void FILL_PALETTE (PIXEL_T *data, int count) } paletteInsert (ci, (rdr::U32)ni, BPP); } + +void FAST_FILL_PALETTE (const Rect& r, PIXEL_T *data, int stride) +{ + PIXEL_T c0, c1, ci = 0, mask, c0t, c1t, cit; + int n0, n1, ni; + int w = r.width(), h = r.height(); + PIXEL_T *rowptr, *colptr, *rowptr2, *colptr2, *dataend = &data[stride * h]; + bool willTransform = ig->willTransform(); + + if (willTransform) { + mask = serverpf.redMax << serverpf.redShift; + mask |= serverpf.greenMax << serverpf.greenShift; + mask |= serverpf.blueMax << serverpf.blueShift; + } + else mask = ~0; + + c0 = data[0] & mask; + n0 = 0; + for (rowptr = data; rowptr < dataend; rowptr += stride) { + for (colptr = rowptr; colptr < &rowptr[w]; colptr++) { + if (((*colptr) & mask) != c0) + goto soliddone; + n0++; + } + } + + soliddone: + if (rowptr >= dataend) { + palNumColors = 1; // Solid rectangle + return; + } + if (palMaxColors < 2) { + palNumColors = 0; // Full-color format preferred + return; + } + + c1 = *colptr & mask; + n1 = 0; + colptr++; + if (colptr >= &rowptr[w]) { + rowptr += stride; colptr = rowptr; + } + colptr2 = colptr; + for (rowptr2 = rowptr; rowptr2 < dataend;) { + for (; colptr2 < &rowptr2[w]; colptr2++) { + ci = (*colptr2) & mask; + if (ci == c0) { + n0++; + } else if (ci == c1) { + n1++; + } else + goto monodone; + } + rowptr2 += stride; + colptr2 = rowptr2; + } + + monodone: + if (willTransform) { + ig->translateRect(&c0, 1, Rect(0, 0, 1, 1), &c0t, 1, Point(0, 0)); + ig->translateRect(&c1, 1, Rect(0, 0, 1, 1), &c1t, 1, Point(0, 0)); + } + else { + c0t = c0; c1t = c1; + } + + if (colptr2 >= dataend) { + if (n0 > n1) { + monoBackground = (rdr::U32)c0t; + monoForeground = (rdr::U32)c1t; + } else { + monoBackground = (rdr::U32)c1t; + monoForeground = (rdr::U32)c0t; + } + palNumColors = 2; // Two colors + return; + } + + paletteReset(); + paletteInsert (c0t, (rdr::U32)n0, BPP); + paletteInsert (c1t, (rdr::U32)n1, BPP); + + ni = 1; + colptr2++; + if (colptr2 >= &rowptr2[w]) { + rowptr2 += stride; colptr2 = rowptr2; + } + colptr = colptr2; + for (rowptr = rowptr2; rowptr < dataend;) { + for (; colptr < &rowptr[w]; colptr++) { + if (((*colptr) & mask) == ci) { + ni++; + } else { + if (willTransform) + ig->translateRect(&ci, 1, Rect(0, 0, 1, 1), &cit, 1, Point(0, 0)); + else + cit = ci; + if (!paletteInsert (cit, (rdr::U32)ni, BPP)) + return; + ci = (*colptr) & mask; + ni = 1; + } + } + rowptr += stride; + colptr = rowptr; + } + ig->translateRect(&ci, 1, Rect(0, 0, 1, 1), &cit, 1, Point(0, 0)); + paletteInsert (cit, (rdr::U32)ni, BPP); +} + #endif // #if (BPP == 8) -bool CHECK_SOLID_TILE(Rect& r, ImageGetter* ig, SMsgWriter* writer, - rdr::U32 *colorPtr, bool needSameColor) +bool CHECK_SOLID_TILE(Rect& r, rdr::U32 *colorPtr, bool needSameColor) { - PIXEL_T *buf; - PIXEL_T colorValue; + PIXEL_T *buf, colorValue; int dx, dy; - Rect sr; + int w = r.width(), h = r.height(); - buf = (PIXEL_T *)writer->getImageBuf(r.area()); - sr.setXYWH(r.tl.x, r.tl.y, 1, 1); - GET_IMAGE_INTO_BUF(sr, buf); + int stride = w; + buf = (PIXEL_T *)ig->getPixelsRW(r, &stride); colorValue = *buf; if (needSameColor && (rdr::U32)colorValue != *colorPtr) return false; - for (dy = 0; dy < r.height(); dy++) { - Rect sr; - sr.setXYWH(r.tl.x, r.tl.y + dy, r.width(), 1); - GET_IMAGE_INTO_BUF(sr, buf); - for (dx = 0; dx < r.width(); dx++) { + for (dy = 0; dy < h; dy++) { + for (dx = 0; dx < w; dx++) { if (colorValue != buf[dx]) return false; } + buf += stride; } *colorPtr = (rdr::U32)colorValue; @@ -602,9 +651,7 @@ bool CHECK_SOLID_TILE(Rect& r, ImageGetter* ig, SMsgWriter* writer, } #undef PIXEL_T -#undef WRITE_PIXEL #undef TIGHT_ENCODE -#undef SWAP_PIXEL #undef HASH_FUNCTION #undef PACK_PIXELS #undef ENCODE_SOLID_RECT @@ -612,6 +659,7 @@ bool CHECK_SOLID_TILE(Rect& r, ImageGetter* ig, SMsgWriter* writer, #undef ENCODE_MONO_RECT #undef ENCODE_INDEXED_RECT #undef ENCODE_JPEG_RECT +#undef FAST_FILL_PALETTE #undef FILL_PALETTE #undef CHECK_SOLID_TILE } |