enum EncoderClass solid, bitmap, bitmapRLE;
enum EncoderClass indexed, indexedRLE, fullColour;
+ bool allowJPEG;
+
rdr::S32 preferred;
std::vector<int>::iterator iter;
solid = bitmap = bitmapRLE = encoderRaw;
indexed = indexedRLE = fullColour = encoderRaw;
+ allowJPEG = conn->cp.pf().bpp >= 16;
+ if (!allowLossy) {
+ if (encoders[encoderTightJPEG]->losslessQuality == -1)
+ allowJPEG = false;
+ }
+
// Try to respect the client's wishes
preferred = conn->getPreferredEncoding();
switch (preferred) {
bitmapRLE = indexedRLE = fullColour = encoderHextile;
break;
case encodingTight:
- if (encoders[encoderTightJPEG]->isSupported() &&
- (conn->cp.pf().bpp >= 16) && allowLossy)
+ if (encoders[encoderTightJPEG]->isSupported() && allowJPEG)
fullColour = encoderTightJPEG;
else
fullColour = encoderTight;
// Any encoders still unassigned?
if (fullColour == encoderRaw) {
- if (encoders[encoderTightJPEG]->isSupported() &&
- (conn->cp.pf().bpp >= 16) && allowLossy)
+ if (encoders[encoderTightJPEG]->isSupported() && allowJPEG)
fullColour = encoderTightJPEG;
else if (encoders[encoderZRLE]->isSupported())
fullColour = encoderZRLE;
encoder = encoders[*iter];
encoder->setCompressLevel(conn->cp.compressLevel);
- encoder->setQualityLevel(conn->cp.qualityLevel);
- encoder->setFineQualityLevel(conn->cp.fineQualityLevel,
- conn->cp.subsampling);
+
+ if (allowLossy) {
+ encoder->setQualityLevel(conn->cp.qualityLevel);
+ encoder->setFineQualityLevel(conn->cp.fineQualityLevel,
+ conn->cp.subsampling);
+ } else {
+ int level = __rfbmax(conn->cp.qualityLevel,
+ encoder->losslessQuality);
+ encoder->setQualityLevel(level);
+ encoder->setFineQualityLevel(-1, subsampleUndefined);
+ }
}
}
encoder = encoders[klass];
conn->writer()->startRect(rect, encoder->encoding);
- if (encoder->flags & EncoderLossy)
+ if ((encoder->flags & EncoderLossy) &&
+ ((encoder->losslessQuality == -1) ||
+ (encoder->getQualityLevel() < encoder->losslessQuality)))
lossyRegion.assign_union(Region(rect));
else
lossyRegion.assign_subtract(Region(rect));
using namespace rfb;
Encoder::Encoder(SConnection *conn_, int encoding_,
- enum EncoderFlags flags_, unsigned int maxPaletteSize_) :
+ enum EncoderFlags flags_,
+ unsigned int maxPaletteSize_, int losslessQuality_) :
encoding(encoding_), flags(flags_),
- maxPaletteSize(maxPaletteSize_), conn(conn_)
+ maxPaletteSize(maxPaletteSize_), losslessQuality(losslessQuality_),
+ conn(conn_)
{
}
class Encoder {
public:
Encoder(SConnection* conn, int encoding,
- enum EncoderFlags flags, unsigned int maxPaletteSize=-1);
+ enum EncoderFlags flags, unsigned int maxPaletteSize=-1,
+ int losslessQuality=-1);
virtual ~Encoder();
// isSupported() should return a boolean indicating if this encoder
// Maximum size of the palette per rect
const unsigned int maxPaletteSize;
+ // Minimum level where the quality loss will not be noticed by
+ // most users (only relevant with EncoderLossy flag)
+ const int losslessQuality;
+
protected:
SConnection* conn;
};
TightJPEGEncoder::TightJPEGEncoder(SConnection* conn) :
- Encoder(conn, encodingTight, (EncoderFlags)(EncoderUseNativePF | EncoderLossy)),
+ Encoder(conn, encodingTight,
+ (EncoderFlags)(EncoderUseNativePF | EncoderLossy), -1, 9),
qualityLevel(-1), fineQuality(-1), fineSubsampling(subsampleUndefined)
{
}