changeset 582:f01eef88010f

new blocking scheme
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 08 Feb 2020 10:34:46 +0900
parents aef7d24b430d
children 2fe1be5476a6 ef5033b06019
files src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java
diffstat 2 files changed, 68 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java	Sat Feb 08 06:24:26 2020 +0900
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java	Sat Feb 08 10:34:46 2020 +0900
@@ -27,9 +27,12 @@
 import com.glavsoft.drawing.Renderer;
 import com.glavsoft.exceptions.TransportException;
 import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.rfb.protocol.ReceiverTask;
 import com.glavsoft.transport.Reader;
 import jp.ac.u_ryukyu.treevnc.CheckDelay;
 import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
+
+import java.awt.*;
 import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
 import java.util.LinkedList;
@@ -46,7 +49,7 @@
 		final int deflate_size = 60000-MARGIN;
 		private ByteBuffer c1;
 		private int width; // phase2 length
-		private FramebufferUpdateRectangle c1rect;
+		private FramebufferUpdateRectangle c0rect,c1rect,rect;
 		private int prevLineOffset;
 		private int prevC1Offset;
 		private int prevC1LineOffset;
@@ -88,8 +91,10 @@
 		private void zrleeBlocking(TreeRFBProto rfb, ByteBuffer header, FramebufferUpdateRectangle rect, byte bytes[]) {
 			// dump32(inputs);
 			deflater = rfb.deflater;
+			this.rect = rect;
+			c0rect = null;
 			c1rect = new FramebufferUpdateRectangle(rect.x, rect.y, 0, 0);
-			newMulticastPacket(rfb, rect);
+			newMulticastPacket(rfb);
 			//c1.put(header.get(0));
 			if (!blocking) {
 				deflater.setInput(bytes, 0,(int) prevoffset);
@@ -99,7 +104,7 @@
 			return;
 		}
 
-		private void newMulticastPacket(TreeRFBProto rfb, FramebufferUpdateRectangle rect) {
+		private void newMulticastPacket(TreeRFBProto rfb) {
 			c1 = rfb.multicastqueue.allocate(deflate_size + MARGIN);
 			c1.limit(deflate_size);
 			if (rfb.addSerialNum)
@@ -113,15 +118,15 @@
 			c1.putInt(0);     // should be data length
 			prevC1Offset = c1.position();
 			prevC1LineOffset = prevC1Offset;
-			width = 0;
 			c1rect.width = c1rect.height = 0;
+			c0rect = null;
 		}
 
 		int spanGap = 128;
 		/**
 		 * Series of tiles compose at most three rectangles. SYNC_FLUSH is necessary on
 		 * rectangle boundaries.
-		 * <p>
+		 *
 		 *               +----+
 		 *               |    |   phase 0
 		 *    +---------------+
@@ -129,73 +134,97 @@
 		 *    +----+----------+
 		 *    |    |              phase 2
 		 *    +----+
-		 * <p>
-		 * Broadcast packet have to less than 64kbytes
-		 * A tile 64x64x3 11288byte, a packet can contain 5 raw tiles, when these are
-		 * compressed 10 to 100 tiles can be stored. It is impossible to predict the
-		 * compression rate. To check the compressed capacity, Deflate.needsInputs() can
-		 * be used. If needsInputs() is false on SYNC_FLUSH, smaller input is necessary.
-		 * <p>
-		 * We'll try 512 tiles before SYNC_FLUSH in a phase, if it fails try flush former 256 tiles.
-		 * If it will failed again, flush the previous line and do flush 512 tiles in new Packet.
-		 * If it failed again try former 256 tiles flushed, if this failes again dicard the former half.
-		 * The last case cannot happen but former 256 tiles have to be flushed, because the next 256 lines
-		 * may failed again and restart the from this point.
-		 * The next packet start with later 256 tiles filled and unflushed.
+		 *
+		 * Broadcast packet have to be less than 64kbytes
+		 * A tile 64x64x4 166384byte
+		 *
+		 * we cannot rewind zlib stream, zlib stream have to be flushed at the end of rectangles
+		 * if we leave 16kbytes space margin, zlib stream can be flushed safely
+		 *
+		 * keep completed previous rectangle in c0rect, which is possibly none.
+		 * at the last or packet full, flush c0rect first, then flush c1rect if it exists
 		 *
 		 * @param rfb
 		 * @param last
-		 * @param rect
 		 * @param bytes
 		 * @param offset
 		 * @param tileW
 		 * @param tileH
 		 */
 
-		public void multicastPut(TreeRFBProto rfb, boolean last, FramebufferUpdateRectangle rect, byte[] bytes, int offset, int tileW, int tileH) {
+		public void multicastPut(TreeRFBProto rfb, boolean last, byte[] bytes, int offset, int tileW, int tileH) {
 			if (!blocking) return;
 			int span = offset - prevoffset;
 			deflater.setInput(bytes, prevoffset, span);
 			do {
 				deflater.deflate(c1, Deflater. SYNC_FLUSH);
 				if (!deflater.needsInput()) {
-					// compression failed
+					// packet full
 					flushDeflator();
 					prevoffset = flushOffset+(int)deflater.getBytesRead();
 					assert(prevoffset==offset);
 					System.out.println("od prevOffset = "+prevoffset+" span = "+(prevoffset-flushOffset));
-					flushRectangle(rect);
+					if (c0rect!=null) { flushRectangle(c0rect); moveNext(); } // finish pahse 1
+					flushRectangle(c1rect); // phase 2
 					flushMuticast(rfb, bytes);
 					if (last) {
 						return;
 					} else {
-						newMulticastPacket(rfb, rect);
+						newMulticastPacket(rfb);
+						if (width<rect.width) { // phase 0
+							c1rect.x = rect.x + width;
+						} else {
+							c1rect.x = 0; // phase 1
+							c1rect.y += tileH;
+						}
+						return;
 					}
 				}
 			} while (! deflater.needsInput());
 			prevoffset = offset;
 			if (last) {
 				flushDeflator();
-				flushRectangle(rect);
+				if (c0rect!=null) { flushRectangle(c0rect); moveNext(); }
+				flushRectangle(c1rect);
 				flushMuticast(rfb, bytes);
+				return;
 			}
 			width += tileW;
+			if (c1rect.height==0) c1rect.height = tileH;
 			if (c1rect.x > rect.x) {  // phase 0
+				assert(c0rect==null);
 				if (c1rect.x + c1rect.width < rect.x + rect.width) {
+					c1rect.x += tileW;
 				} else {   // end of phase 0
-					c1rect.width = rect.x + rect.width - c1rect.x;
-					prevC1LineOffset = c1.position();
+					flushRectangle(c1rect);
+					c1.position((c1.position()+16)); // make next header space
+					c1rect = new FramebufferUpdateRectangle(rect.x,c1rect.y+tileH,0,0);
 				}
 			} else {  // phase 1
 				if (width >= rect.width) { // next line
+					deflater.deflate(c1,Deflater.FULL_FLUSH);
+					prevC1LineOffset = c1.position();
 					c1rect.width = rect.width;
+					if (c0rect!=null) { // extend phase 1
+						c0rect.height += tileH;
+						c1rect = new FramebufferUpdateRectangle(rect.x, c0rect.y+c0rect.height,0,0);
+					} else { // first phase 1 case
+						c1rect.height = tileH;
+						c0rect = c1rect;
+						c1rect = new FramebufferUpdateRectangle(rect.x, c1rect.y+c1rect.height,0,0);
+					}
 					width = 0;
 					prevLineOffset = offset;
-					prevC1LineOffset = c1.position();
 				}
 			}
 		}
 
+		public void moveNext() {
+			// previous rectangle is finished, make next header space and copy already compressed part
+			c1.limit(c1.limit()+16);
+			System.arraycopy(c1.array(),prevC1LineOffset,16,prevC1LineOffset+16,c1.position()-prevC1LineOffset);
+		}
+
 		private void flushDeflator() {
 			c1.limit(c1.limit() + MARGIN);
 			deflater.deflate(c1, Deflater.FULL_FLUSH);
@@ -204,6 +233,10 @@
 			}
 		}
 
+		private void bufdump(byte[] bytes,int beigin, int end) {
+			ReceiverTask.dump("in  ",bytes,beigin,8); ReceiverTask.dump("... ",bytes,end,8);
+			System.out.println();
+		}
 
 		/**
 		 * fix rectangle header
@@ -212,25 +245,14 @@
 		 * send muticast pacate if nessesally
 		 */
 		private void flushRectangle(FramebufferUpdateRectangle rect) {
-			c1.putShort(prevC1Offset - 16, (short) c1rect.x);
-			c1.putShort(prevC1Offset - 14, (short) c1rect.y);
-			c1.putShort(prevC1Offset - 12, (short) c1rect.width);
-			c1.putShort(prevC1Offset - 10, (short) c1rect.height);
+			c1.putShort(prevC1Offset - 16, (short) rect.x);
+			c1.putShort(prevC1Offset - 14, (short) rect.y);
+			c1.putShort(prevC1Offset - 12, (short) rect.width);
+			c1.putShort(prevC1Offset - 10, (short) rect.height);
 			c1.putInt(prevC1Offset - 8, EncodingType.ZRLEE.getId());
 			c1.putInt(prevC1Offset  - 4, c1.position() - prevC1Offset - 12); // data length
 			c1.putShort(2, (short) (c1.getShort(2) + 1));    // increment rectangle count
 			prevC1Offset = c1.position();
-			nextPhase(rect);
-		}
-
-		private void nextPhase(FramebufferUpdateRectangle rect) {
-			if (c1rect.x + c1rect.width < rect.x + rect.width) {
-				c1rect.x = c1rect.width;   // next rectangle is phase 1
-			} else {
-				c1rect.x = rect.x;
-				c1rect.y += c1rect.height;
-			}
-			width = 0;
 		}
 
 		private void flushMuticast(TreeRFBProto rfb, byte[] bytes) {
@@ -324,15 +346,15 @@
 						}
 					}
 					if (rfbProto != null && rfbProto.multicastBlocking)
-						tileloop.multicastPut(rfbProto, false, rect, bytes, offset, tileWidth, tileHeight);
+						tileloop.multicastPut(rfbProto, false, bytes, offset, tileWidth, tileHeight);
 				}
 			}
 			if (rfbProto != null && rfbProto.multicastBlocking)
-				tileloop.multicastPut(rfbProto, true, rect, bytes, offset, 0, 0);
+				tileloop.multicastPut(rfbProto, true, bytes, offset, 0, 0);
 		} catch (Exception e) {
 			e.printStackTrace();
 			if (rfbProto != null && rfbProto.multicastBlocking)
-				tileloop.multicastPut(rfbProto, true, rect, bytes, offset, 0, 0);
+				tileloop.multicastPut(rfbProto, true, bytes, offset, 0, 0);
 			throw e;
 		}
 	}
--- a/src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java	Sat Feb 08 06:24:26 2020 +0900
+++ b/src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java	Sat Feb 08 10:34:46 2020 +0900
@@ -422,7 +422,7 @@
         System.out.println();
     }
 
-    private void dump(String s, byte[] bytes, int begin, int len) {
+    public static void dump(String s, byte[] bytes, int begin, int len) {
         System.out.print(s);
         while(len > 0 && begin < bytes.length) {
             System.out.print(bytes[begin] + " ");