virtual void framebufferUpdateStart() = 0;
virtual void framebufferUpdateEnd() = 0;
- virtual void beginRect(const Rect& r, int encoding) = 0;
- virtual void endRect(const Rect& r, int encoding) = 0;
+ virtual void dataRect(const Rect& r, int encoding) = 0;
virtual void setColourMapEntries(int firstColour, int nColours,
rdr::U16* rgbs) = 0;
: imageBufIdealSize(0), handler(handler_), is(is_),
imageBuf(0), imageBufSize(0), nUpdateRectsLeft(0)
{
- for (int i = 0; i <= encodingMax; i++) {
- decoders[i] = 0;
- }
}
CMsgReader::~CMsgReader()
{
- for (int i = 0; i <= encodingMax; i++) {
- delete decoders[i];
- }
delete [] imageBuf;
}
if (r.is_empty())
fprintf(stderr, "Warning: zero size rect\n");
- handler->beginRect(r, encoding);
-
- if (!Decoder::supported(encoding)) {
- fprintf(stderr, "Unknown rect encoding %d\n", encoding);
- throw Exception("Unknown rect encoding");
- }
-
- if (!decoders[encoding]) {
- decoders[encoding] = Decoder::createDecoder(encoding, this);
- if (!decoders[encoding]) {
- fprintf(stderr, "Unknown rect encoding %d\n", encoding);
- throw Exception("Unknown rect encoding");
- }
- }
- decoders[encoding]->readRect(r, handler);
-
- handler->endRect(r, encoding);
+ handler->dataRect(r, encoding);
}
void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
namespace rfb {
class CMsgHandler;
- class Decoder;
struct Rect;
class CMsgReader {
CMsgHandler* handler;
rdr::InStream* is;
- Decoder* decoders[encodingMax+1];
rdr::U8* imageBuf;
int imageBufSize;
int nUpdateRectsLeft;
#include <rfb/rreEncode.h>
#undef BPP
-RREEncoder::RREEncoder(SMsgWriter* writer) : Encoder(writer)
+RREEncoder::RREEncoder(SMsgWriter* writer) : RawEncoder(writer)
{
}
}
if (nSubrects < 0) {
- writer->writeRect(r, encodingRaw, ig);
+ RawEncoder::writeRect(r, ig);
return;
}
#define __RFB_RREENCODER_H__
#include <rdr/MemOutStream.h>
-#include <rfb/Encoder.h>
+#include <rfb/RawEncoder.h>
namespace rfb {
- class RREEncoder : public Encoder {
+ class RREEncoder : public RawEncoder {
public:
RREEncoder(SMsgWriter* writer);
virtual ~RREEncoder();
imageBuf(0), imageBufSize(0)
{
for (int i = 0; i <= encodingMax; i++) {
- encoders[i] = 0;
bytesSent[i] = 0;
rectsSent[i] = 0;
}
vlog.info("framebuffer updates %d",updatesSent);
int bytes = 0;
for (int i = 0; i <= encodingMax; i++) {
- delete encoders[i];
if (i != encodingCopyRect)
bytes += bytesSent[i];
if (rectsSent[i])
endMsg();
}
-void SMsgWriter::setupCurrentEncoder()
-{
- int encoding = cp->currentEncoding();
-
- // FIXME: Code duplication, see writeRect().
- if (!encoders[encoding]) {
- encoders[encoding] = Encoder::createEncoder(encoding, this);
- assert(encoders[encoding]);
- }
-
- encoders[encoding]->setCompressLevel(cp->compressLevel);
- encoders[encoding]->setQualityLevel(cp->qualityLevel);
- encoders[encoding]->setFineQualityLevel(cp->fineQualityLevel,
- cp->subsampling);
-}
-
-int SMsgWriter::getNumRects(const Rect &r)
-{
- int encoding = cp->currentEncoding();
-
- if (!encoders[encoding])
- setupCurrentEncoder();
-
- return encoders[encoding]->getNumRects(r);
-}
-
bool SMsgWriter::writeSetDesktopSize() {
if (!cp->supportsDesktopResize)
return false;
writeFramebufferUpdateEnd();
}
-void SMsgWriter::writeRects(const UpdateInfo& ui, TransImageGetter* ig)
-{
- std::vector<Rect> rects;
- std::vector<Rect>::const_iterator i;
-
- ui.copied.get_rects(&rects, ui.copy_delta.x <= 0, ui.copy_delta.y <= 0);
- for (i = rects.begin(); i != rects.end(); i++)
- writeCopyRect(*i, i->tl.x - ui.copy_delta.x, i->tl.y - ui.copy_delta.y);
-
- ui.changed.get_rects(&rects);
- for (i = rects.begin(); i != rects.end(); i++)
- writeRect(*i, ig);
-}
-
void SMsgWriter::writeFramebufferUpdateStart(int nRects)
{
startMsg(msgTypeFramebufferUpdate);
endMsg();
}
-void SMsgWriter::writeRect(const Rect& r, TransImageGetter* ig)
-{
- writeRect(r, cp->currentEncoding(), ig);
-}
-
-void SMsgWriter::writeRect(const Rect& r, int encoding, TransImageGetter* ig)
-{
- if (!encoders[encoding]) {
- encoders[encoding] = Encoder::createEncoder(encoding, this);
- assert(encoders[encoding]);
- }
- encoders[encoding]->writeRect(r, ig);
-}
-
void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY)
{
startRect(r,encodingCopyRect);
namespace rfb {
class ConnParams;
- class TransImageGetter;
- class Region;
- class UpdateInfo;
- class Encoder;
class ScreenSet;
class WriteSetCursorCallback {
// updates mode.
void writeEndOfContinuousUpdates();
- // setupCurrentEncoder() should be called before each framebuffer update,
- // prior to calling getNumRects() or writeFramebufferUpdateStart().
- void setupCurrentEncoder();
-
- // getNumRects() computes the number of sub-rectangles that will compose a
- // given rectangle, for current encoder.
- int getNumRects(const Rect &r);
-
// writeSetDesktopSize() won't actually write immediately, but will
// write the relevant pseudo-rectangle as part of the next update.
bool writeSetDesktopSize();
// pseudo-rectangles.
void writeNoDataUpdate();
- // writeRects() accepts an UpdateInfo (changed & copied regions) and an
- // ImageGetter to fetch pixels from. It then calls writeCopyRect() and
- // writeRect() as appropriate. writeFramebufferUpdateStart() must be used
- // before the first writeRects() call and writeFrameBufferUpdateEnd() after
- // the last one.
- void writeRects(const UpdateInfo& update, TransImageGetter* ig);
-
- // To construct a framebuffer update you can call
- // writeFramebufferUpdateStart(), followed by a number of writeCopyRect()s
- // and writeRect()s, finishing with writeFramebufferUpdateEnd().
+ // writeFramebufferUpdateStart() initiates an update which you can fill
+ // in using writeCopyRect() and encoders. Finishing the update by calling
+ // writeFramebufferUpdateEnd().
void writeFramebufferUpdateStart(int nRects);
void writeFramebufferUpdateEnd();
- // writeRect() writers the given rectangle using either the preferred
- // encoder, or the one explicitly given.
- void writeRect(const Rect& r, TransImageGetter* ig);
- void writeRect(const Rect& r, int encoding, TransImageGetter* ig);
-
+ // There is no explicit encoder for CopyRect rects.
void writeCopyRect(const Rect& r, int srcX, int srcY);
+ // Encoders should call these to mark the start and stop of individual
+ // rects.
void startRect(const Rect& r, int enc);
void endRect();
ConnParams* cp;
rdr::OutStream* os;
- Encoder* encoders[encodingMax+1];
int currentEncoding;
int nRectsInUpdate;
#include <rfb/ServerCore.h>
#include <rfb/ComparingUpdateTracker.h>
#include <rfb/KeyRemapper.h>
+#include <rfb/Encoder.h>
#define XK_MISCELLANY
#define XK_XKB_KEYS
#include <rfb/keysymdef.h>
peerEndpoint.buf = sock->getPeerEndpoint();
VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
+ memset(encoders, 0, sizeof(encoders));
+
// Configure the socket
setSocketTimeouts();
lastEventTime = time(0);
// Remove this client from the server
server->clients.remove(this);
+ for (int i = 0; i <= encodingMax; i++)
+ delete encoders[i];
+
delete [] fenceData;
}
}
if (!ui.is_empty() || writer()->needFakeUpdate() || drawRenderedCursor) {
+ std::vector<Rect> rects;
+ std::vector<Rect>::const_iterator i;
+ int encoding;
+
+ // Make sure the encoder has the latest settings
+ encoding = cp.currentEncoding();
+
+ if (!encoders[encoding])
+ encoders[encoding] = Encoder::createEncoder(encoding, writer());
+
+ encoders[encoding]->setCompressLevel(cp.compressLevel);
+ encoders[encoding]->setQualityLevel(cp.qualityLevel);
+ encoders[encoding]->setFineQualityLevel(cp.fineQualityLevel,
+ cp.subsampling);
+
// Compute the number of rectangles. Tight encoder makes the things more
// complicated as compared to the original VNC4.
- writer()->setupCurrentEncoder();
int nRects = (ui.copied.numRects() +
(drawRenderedCursor ? 1 : 0));
- std::vector<Rect> rects;
- std::vector<Rect>::const_iterator i;
ui.changed.get_rects(&rects);
for (i = rects.begin(); i != rects.end(); i++) {
if (i->width() && i->height()) {
- int nUpdateRects = writer()->getNumRects(*i);
+ int nUpdateRects = encoders[encoding]->getNumRects(*i);
if (nUpdateRects == 0 && cp.currentEncoding() == encodingTight) {
// With Tight encoding and LastRect support, the client does not
// care about the number of rectangles in the update - it will
writer()->writeFramebufferUpdateStart(nRects);
- writer()->writeRects(ui, &image_getter);
- updates.clear();
+ ui.copied.get_rects(&rects);
+ for (i = rects.begin(); i != rects.end(); i++)
+ writer()->writeCopyRect(*i, i->tl.x - ui.copy_delta.x,
+ i->tl.y - ui.copy_delta.y);
+
+ ui.changed.get_rects(&rects);
+ for (i = rects.begin(); i != rects.end(); i++)
+ encoders[encoding]->writeRect(*i, &image_getter);
- if (drawRenderedCursor)
- writeRenderedCursorRect();
+ if (drawRenderedCursor) {
+ image_getter.setPixelBuffer(&server->renderedCursor);
+ image_getter.setOffset(server->renderedCursorTL);
+
+ encoders[encoding]->writeRect(renderedCursorRect, &image_getter);
+
+ image_getter.setPixelBuffer(server->pb);
+ image_getter.setOffset(Point(0,0));
+
+ drawRenderedCursor = false;
+ }
writer()->writeFramebufferUpdateEnd();
writeRTTPing();
requested.clear();
+ updates.clear();
}
out:
}
-// writeRenderedCursorRect() writes a single rectangle drawing the rendered
-// cursor on the client.
-
-void VNCSConnectionST::writeRenderedCursorRect()
-{
- image_getter.setPixelBuffer(&server->renderedCursor);
- image_getter.setOffset(server->renderedCursorTL);
-
- writer()->writeRect(renderedCursorRect, &image_getter);
-
- image_getter.setPixelBuffer(server->pb);
- image_getter.setOffset(Point(0,0));
-
- drawRenderedCursor = false;
-}
-
void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
{
if (!authenticated())
struct RTTInfo;
namespace rfb {
+ class Encoder;
+
class VNCSConnectionST : public SConnection,
public WriteSetCursorCallback,
public Timer::Callback {
void writeFramebufferUpdate();
- void writeRenderedCursorRect();
void screenLayoutChange(rdr::U16 reason);
void setCursor();
void setDesktopName(const char *name);
Rect renderedCursorRect;
bool continuousUpdates;
Region cuRegion;
+ Encoder* encoders[encodingMax+1];
Timer updateTimer;
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
+ * Copyright 2009-2014 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
#include <rfb/CMsgWriter.h>
#include <rfb/encodings.h>
+#include <rfb/Decoder.h>
#include <rfb/Hostname.h>
#include <rfb/LogWriter.h>
#include <rfb/util.h>
setShared(::shared);
sock = socket;
+ memset(decoders, 0, sizeof(decoders));
+
int encNum = encodingNum(preferredEncoding);
if (encNum != -1)
currentEncoding = encNum;
{
OptionsDialog::removeCallback(handleOptions);
+ for (int i = 0; i < sizeof(decoders)/sizeof(decoders[0]); i++)
+ delete decoders[i];
+
if (desktop)
delete desktop;
delete [] buffer;
}
-// We start timing on beginRect and stop timing on endRect, to
-// avoid skewing the bandwidth estimation as a result of the server
-// being slow or the network having high latency
-void CConn::beginRect(const Rect& r, int encoding)
+void CConn::dataRect(const Rect& r, int encoding)
{
sock->inStream().startTiming();
- if (encoding != encodingCopyRect) {
+
+ if (encoding != encodingCopyRect)
lastServerEncoding = encoding;
+
+ if (!Decoder::supported(encoding)) {
+ fprintf(stderr, "Unknown rect encoding %d\n", encoding);
+ throw Exception("Unknown rect encoding");
}
-}
-void CConn::endRect(const Rect& r, int encoding)
-{
+ if (!decoders[encoding]) {
+ decoders[encoding] = Decoder::createDecoder(encoding, reader());
+ if (!decoders[encoding]) {
+ fprintf(stderr, "Unknown rect encoding %d\n", encoding);
+ throw Exception("Unknown rect encoding");
+ }
+ }
+ decoders[encoding]->readRect(r, this);
+
sock->inStream().stopTiming();
}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright 2009-2014 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
#include <FL/Fl.H>
#include <rfb/CConnection.h>
+#include <rfb/encodings.h>
#include <network/Socket.h>
+namespace rfb { class Decoder; }
+
class DesktopWindow;
class CConn : public rfb::CConnection,
void framebufferUpdateStart();
void framebufferUpdateEnd();
- void beginRect(const rfb::Rect& r, int encoding);
- void endRect(const rfb::Rect& r, int encoding);
+ void dataRect(const rfb::Rect& r, int encoding);
void fillRect(const rfb::Rect& r, rfb::Pixel p);
void imageRect(const rfb::Rect& r, void* p);
bool pendingPFChange;
rfb::PixelFormat pendingPF;
+ rfb::Decoder *decoders[rfb::encodingMax+1];
+
int currentEncoding, lastServerEncoding;
bool formatChange;