]> source.dussan.org Git - tigervnc.git/commitdiff
Push encoder and decoder handling down into the connection objects
authorPierre Ossman <ossman@cendio.se>
Fri, 31 Jan 2014 12:12:18 +0000 (13:12 +0100)
committerPierre Ossman <ossman@cendio.se>
Mon, 7 Jul 2014 12:50:28 +0000 (14:50 +0200)
This keeps the reader and writer objects clean and simple protocol
decoders/encoders.

common/rfb/CMsgHandler.h
common/rfb/CMsgReader.cxx
common/rfb/CMsgReader.h
common/rfb/RREEncoder.cxx
common/rfb/RREEncoder.h
common/rfb/SMsgWriter.cxx
common/rfb/SMsgWriter.h
common/rfb/VNCSConnectionST.cxx
common/rfb/VNCSConnectionST.h
vncviewer/CConn.cxx
vncviewer/CConn.h

index d7ffd65b66b32700ed74a71f8b225cf9a77a8be1..8b58e0e59cec5a40eeae7b8765b8a9ec5e529229 100644 (file)
@@ -59,8 +59,7 @@ namespace rfb {
 
     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;
index b39fd09963a159812c27fa6efab8c545dc4c42fb..37612ea33f6129b02f6dd4f9243d49bdcfb630d1 100644 (file)
@@ -31,16 +31,10 @@ CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
   : 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;
 }
 
@@ -196,23 +190,7 @@ void CMsgReader::readRect(const Rect& r, int encoding)
   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)
index 12846678f0abcd173a824d5fca389890f3fc6f72..97b57ce7d7b5a45e4d37417878579508c24183c9 100644 (file)
@@ -33,7 +33,6 @@ namespace rdr { class InStream; }
 
 namespace rfb {
   class CMsgHandler;
-  class Decoder;
   struct Rect;
 
   class CMsgReader {
@@ -69,7 +68,6 @@ namespace rfb {
 
     CMsgHandler* handler;
     rdr::InStream* is;
-    Decoder* decoders[encodingMax+1];
     rdr::U8* imageBuf;
     int imageBufSize;
     int nUpdateRectsLeft;
index b37b7588d01cb815ade14cd6da1d84ed49a328b7..dc2d74ed1377ca5e72b5242786bce7dd54d335f4 100644 (file)
@@ -33,7 +33,7 @@ using namespace rfb;
 #include <rfb/rreEncode.h>
 #undef BPP
 
-RREEncoder::RREEncoder(SMsgWriter* writer) : Encoder(writer)
+RREEncoder::RREEncoder(SMsgWriter* writer) : RawEncoder(writer)
 {
 }
 
@@ -58,7 +58,7 @@ void RREEncoder::writeRect(const Rect& r, TransImageGetter* ig)
   }
   
   if (nSubrects < 0) {
-    writer->writeRect(r, encodingRaw, ig);
+    RawEncoder::writeRect(r, ig);
     return;
   }
 
index c5e655695e83826740d90ca5ee0cf31ca212d581..b263967e05e6fca5555172e79654bc9ecbffacba 100644 (file)
 #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();
index 5dc7c22f04d942a56952ae306f84a3f49287b0be..67590fe65df745095043302c56fc176beba8d1e4 100644 (file)
@@ -42,7 +42,6 @@ SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
     imageBuf(0), imageBufSize(0)
 {
   for (int i = 0; i <= encodingMax; i++) {
-    encoders[i] = 0;
     bytesSent[i] = 0;
     rectsSent[i] = 0;
   }
@@ -53,7 +52,6 @@ SMsgWriter::~SMsgWriter()
   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])
@@ -135,32 +133,6 @@ void SMsgWriter::writeEndOfContinuousUpdates()
   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;
@@ -290,20 +262,6 @@ void SMsgWriter::writeNoDataUpdate()
   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);
@@ -346,20 +304,6 @@ void SMsgWriter::writeFramebufferUpdateEnd()
   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);
index ee59eb367c0adb732485af850014b885627b9564..ccc8f803a6edfe1af363ba1007fdb92cfad93eb5 100644 (file)
@@ -32,10 +32,6 @@ namespace rdr { class OutStream; }
 namespace rfb {
 
   class ConnParams;
-  class TransImageGetter;
-  class Region;
-  class UpdateInfo;
-  class Encoder;
   class ScreenSet;
 
   class WriteSetCursorCallback {
@@ -72,14 +68,6 @@ namespace rfb {
     // 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();
@@ -118,26 +106,17 @@ namespace rfb {
     // 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();
 
@@ -169,7 +148,6 @@ namespace rfb {
     ConnParams* cp;
     rdr::OutStream* os;
 
-    Encoder* encoders[encodingMax+1];
     int currentEncoding;
 
     int nRectsInUpdate;
index 452f7246fc2259ffed349103ac9838998e37d7e5..0000c1ea4bed3ecb28c8b14c56b4156b68303230 100644 (file)
@@ -37,6 +37,7 @@
 #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>
@@ -81,6 +82,8 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
   peerEndpoint.buf = sock->getPeerEndpoint();
   VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf);
 
+  memset(encoders, 0, sizeof(encoders));
+
   // Configure the socket
   setSocketTimeouts();
   lastEventTime = time(0);
@@ -106,6 +109,9 @@ VNCSConnectionST::~VNCSConnectionST()
   // Remove this client from the server
   server->clients.remove(this);
 
+  for (int i = 0; i <= encodingMax; i++)
+    delete encoders[i];
+
   delete [] fenceData;
 }
 
@@ -1060,18 +1066,30 @@ void VNCSConnectionST::writeFramebufferUpdate()
   }
 
   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
@@ -1088,17 +1106,33 @@ void VNCSConnectionST::writeFramebufferUpdate()
     
     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:
@@ -1106,22 +1140,6 @@ 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())
index 3c7672f44a060ac2786378582e462e6a2b6c723e..ca5c4f015b8902d9aafbd6e09e0851a0bbd2e08e 100644 (file)
@@ -37,6 +37,8 @@
 struct RTTInfo;
 
 namespace rfb {
+  class Encoder;
+
   class VNCSConnectionST : public SConnection,
                            public WriteSetCursorCallback,
                            public Timer::Callback {
@@ -169,7 +171,6 @@ namespace rfb {
 
     void writeFramebufferUpdate();
 
-    void writeRenderedCursorRect();
     void screenLayoutChange(rdr::U16 reason);
     void setCursor();
     void setDesktopName(const char *name);
@@ -202,6 +203,7 @@ namespace rfb {
     Rect renderedCursorRect;
     bool continuousUpdates;
     Region cuRegion;
+    Encoder* encoders[encodingMax+1];
 
     Timer updateTimer;
 
index d7f57b5f8f54c169344ea37991ecbf519e34d642..f5420629ef79f26c66a7cb71844579b596c7c3bc 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
@@ -29,6 +29,7 @@
 
 #include <rfb/CMsgWriter.h>
 #include <rfb/encodings.h>
+#include <rfb/Decoder.h>
 #include <rfb/Hostname.h>
 #include <rfb/LogWriter.h>
 #include <rfb/util.h>
@@ -80,6 +81,8 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL)
   setShared(::shared);
   sock = socket;
 
+  memset(decoders, 0, sizeof(decoders));
+
   int encNum = encodingNum(preferredEncoding);
   if (encNum != -1)
     currentEncoding = encNum;
@@ -131,6 +134,9 @@ CConn::~CConn()
 {
   OptionsDialog::removeCallback(handleOptions);
 
+  for (int i = 0; i < sizeof(decoders)/sizeof(decoders[0]); i++)
+    delete decoders[i];
+
   if (desktop)
     delete desktop;
 
@@ -380,19 +386,27 @@ void CConn::serverCutText(const char* str, rdr::U32 len)
   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();
 }
 
index 286a09eda04041a9f435e665cc5fdc829b29a206..f7f560bcc2924a1f224e86accaab2df5c122a8d4 100644 (file)
@@ -1,5 +1,5 @@
 /* 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,
@@ -62,8 +65,7 @@ public:
   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);
@@ -102,6 +104,8 @@ private:
   bool pendingPFChange;
   rfb::PixelFormat pendingPF;
 
+  rfb::Decoder *decoders[rfb::encodingMax+1];
+
   int currentEncoding, lastServerEncoding;
 
   bool formatChange;