comparison src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java @ 534:a3d0ba67e8cf

try 512 tiles / 256 tiles flush
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 06 May 2019 16:59:25 +0900
parents 4be31e107121
children 17a2d0ea5c03
comparison
equal deleted inserted replaced
533:4be31e107121 534:a3d0ba67e8cf
29 import com.glavsoft.rfb.encoding.EncodingType; 29 import com.glavsoft.rfb.encoding.EncodingType;
30 import com.glavsoft.transport.Reader; 30 import com.glavsoft.transport.Reader;
31 import jp.ac.u_ryukyu.treevnc.CheckDelay; 31 import jp.ac.u_ryukyu.treevnc.CheckDelay;
32 import jp.ac.u_ryukyu.treevnc.TreeRFBProto; 32 import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
33 33
34 import java.io.ByteArrayInputStream;
35 import java.io.InputStream;
36 import java.io.UnsupportedEncodingException; 34 import java.io.UnsupportedEncodingException;
37 import java.nio.ByteBuffer; 35 import java.nio.ByteBuffer;
38 import java.util.LinkedList; 36 import java.util.LinkedList;
39 import java.util.zip.DataFormatException;
40 import java.util.zip.Deflater; 37 import java.util.zip.Deflater;
41 38
42 public class ZRLEDecoder extends ZlibDecoder { 39 public class ZRLEDecoder extends ZlibDecoder {
43 private static final int MAX_TILE_SIZE = 64; 40 private static final int MAX_TILE_SIZE = 64;
44 private int[] decodedBitmap; 41 private int[] decodedBitmap;
53 private int prevLineOffset; 50 private int prevLineOffset;
54 private int prevC1Offset; 51 private int prevC1Offset;
55 private int prevoffset; 52 private int prevoffset;
56 private Deflater deflater; 53 private Deflater deflater;
57 private int rectPos; 54 private int rectPos;
55 private int ztileInLine;
56 private int hwidth;
57 private int hc1width;
58 private int hoffset;
59 private int hc1offset;
58 60
59 /** 61 /**
60 * Multicast framebufferUpdate to children. 62 * Multicast framebufferUpdate to children.
61 * read FrameBuffferUpdate. If it is ZLE, make it ZLEE which is self contained compressed packet. 63 * read FrameBuffferUpdate. If it is ZLE, make it ZLEE which is self contained compressed packet.
62 * put the packet to the multicastqueue. Then normal rendering engine read the same stream using is.reset(). 64 * put the packet to the multicastqueue. Then normal rendering engine read the same stream using is.reset().
102 c1.putShort((short) 0); 104 c1.putShort((short) 0);
103 c1.position(c1.position()+16); 105 c1.position(c1.position()+16);
104 c1.putInt(0); // should be data length 106 c1.putInt(0); // should be data length
105 width = 0; 107 width = 0;
106 rectPos = 4; 108 rectPos = 4;
109 ztileInLine = 0;
107 } 110 }
108 111
109 int spanGap = 128; 112 int spanGap = 128;
110 /** 113 /**
111 * 114 *
115 * Series of tiles compose at most three rectangles. SYNC_FLUSH is necessary on
116 * rectangle boundaries.
117 *
112 * +----+ 118 * +----+
113 * | | phase 0 119 * | | | phase 0
114 * +---------------+ 120 * +---------------+
115 * | | phase 1 121 * | | | phase 1
116 * +----+----------+ 122 * +----+----------+
117 * | | phase 2 123 * | | | phase 2
118 * +----+ 124 * +----+
125 *
126 * Broadcast packet have to less than 64kbytes
127 * A tile 8x8x3 192byte, a packet can contain 340 raw tiles, when these are
128 * compressed 500 to 2000 tiles can be stored. It is impossible to predict the
129 * compression rate. To check the compressed capacity, Deflate.needsInputs() can
130 * be used. If needsInputs() is false on SYNC_FLUSH, smaller input is necessary.
131 *
132 * We'll try 512 tiles before SYNC_FLUSH in a phase, if it fails try 256.
133 * If it will failed again, flush the previous line and try again.
134 * If 256 tiles are failed in new packet, discard it.
119 * 135 *
120 * @param rfb 136 * @param rfb
121 * @param last 137 * @param last
122 * @param rect 138 * @param rect
123 * @param bytes 139 * @param bytes
124 * @param offset 140 * @param offset
125 * @param tileW 141 * @param tileW
126 * @param tileH 142 * @param tileH
127 */ 143 */
144
145 int MAX_ZTILE = 512;
146
128 public void multicastPut(TreeRFBProto rfb, boolean last, FramebufferUpdateRectangle rect, byte[] bytes, int offset, int tileW, int tileH) { 147 public void multicastPut(TreeRFBProto rfb, boolean last, FramebufferUpdateRectangle rect, byte[] bytes, int offset, int tileW, int tileH) {
129 int span = offset - prevoffset; 148 int span = offset - prevoffset;
130 deflater.setInput(bytes,prevoffset,span); 149 deflater.setInput(bytes,prevoffset,span);
131 prevoffset = offset; 150 prevoffset = offset;
132 c1rect.width += tileW; width += tileW; 151 c1rect.width += tileW; width += tileW;
133 if (c1rect.x > rect.x) { // phase 0 152 if (c1rect.x > rect.x) { // phase 0
134 if (c1rect.x+c1rect.width < rect.x+rect.width) { 153 if (c1rect.x+c1rect.width < rect.x+rect.width) {
135 if (c1.remaining() > spanGap ) { 154 compressAndCheckFlush(rfb, rect, bytes, offset,false, last);
136 deflater.deflate(c1, Deflater.NO_FLUSH);
137 if (!deflater.needsInput()) flushRectangle(rect);
138 return;
139 }
140 } else { 155 } else {
141 c1rect.width = rect.x+rect.width-c1rect.x ; 156 c1rect.width = rect.x+rect.width-c1rect.x ;
142 c1rect.height += tileH; 157 c1rect.height += tileH;
143 deflater.deflate(c1, Deflater.NO_FLUSH); 158 compressAndCheckFlush(rfb,rect,bytes,offset,true, last);
144 flushRectangle(rect); 159 }
145 } 160 } else if (!last && c1.remaining() > spanGap) { // phase 1
146 return;
147 }
148 if (!last && c1.remaining() > spanGap) { // phase 1
149 if (width >= rect.width) { 161 if (width >= rect.width) {
150 c1rect.width = rect.width; 162 c1rect.width = rect.width;
151 width = 0; 163 width = 0;
152 c1rect.height += tileH; 164 c1rect.height += tileH;
153 prevLineOffset = offset; 165 prevLineOffset = offset;
154 prevC1Offset = c1.position(); 166 prevC1Offset = c1.position();
155 deflater.deflate(c1, Deflater.SYNC_FLUSH); 167 compressAndCheckFlush(rfb,rect,bytes,offset,true, last);
156 if (!deflater.needsInput()) flushRectangle(rect);
157 } else { 168 } else {
158 deflater.deflate(c1, Deflater.NO_FLUSH); 169 compressAndCheckFlush(rfb,rect,bytes,offset,false, last);
159 if (!deflater.needsInput()) flushRectangle(rect); 170 }
160 }
161 return;
162 } else { // phase2 171 } else { // phase2
163 // rewind to the last line finish phase 1 172 // rewind to the last line finish phase 1
164 int savew = width; 173 int savew = width;
165 c1.position(prevC1Offset); 174 c1.position(prevC1Offset);
166 flushRectangle(rect); 175 flushRectangle(rect);
167 if (savew>0) { 176 if (savew>0) {
168 // recompress overrun and flush phase 2 177 // recompress overrun and flush phase 2
169 c1rect.width = savew; 178 c1rect.width = savew;
170 c1rect.height = tileH; 179 c1rect.height = tileH;
171 deflater.setInput(bytes, prevLineOffset, span); 180 compressAndCheckFlush(rfb,rect,bytes,offset,true, last);
181 }
182 }
183 }
184
185 private void compressAndCheckFlush(TreeRFBProto rfb, FramebufferUpdateRectangle rect, byte[] bytes, int offset, boolean flush, boolean last) {
186 if (!flush && ztileInLine++ < MAX_ZTILE) {
187 if (ztileInLine == MAX_ZTILE/2) {
188 hwidth = width; hc1width = c1rect.width; hoffset = offset; hc1offset = c1.position();
189 }
190 deflater.deflate(c1, Deflater.NO_FLUSH);
191 } else {
192 deflater.deflate(c1, Deflater.SYNC_FLUSH);
193 if (!deflater.needsInput()) {
194 // too large, try half line
195 width = hwidth;
196 c1rect.width = hc1width;
197 c1.position(hc1offset);
198 deflater.setInput(bytes, prevLineOffset, hoffset - prevC1Offset);
172 deflater.deflate(c1, Deflater.SYNC_FLUSH); 199 deflater.deflate(c1, Deflater.SYNC_FLUSH);
173 flushRectangle(rect); 200 int from, len;
174 } 201 if (!deflater.needsInput()) {
175 flushMuticast(rfb); 202 // flush previous line and start new packet
176 if (!last) newMulticastPacket(rfb,rect); 203 c1.position(prevC1Offset);
204 unputrectangle();
205 flushMuticast(rfb);
206 newMulticastPacket(rfb, rect);
207 nextRectangle(rect);
208 // we already reached MIX_ZTILE do half of them, do compress right now
209 from = prevC1Offset;
210 len = offset - prevLineOffset;
211 deflater.setInput(bytes, from, len);
212 deflater.deflate(c1, Deflater.SYNC_FLUSH);
213 if (deflater.needsInput()) {
214 flushRectangle(rect); // we are the flushed last line
215 return;
216 }
217 // half size should always succeed
218 from = prevC1Offset;
219 len = hoffset - prevLineOffset;
220 deflater.setInput(bytes, from, len);
221 deflater.deflate(c1, Deflater.SYNC_FLUSH);
222 if (!deflater.needsInput()) { /* fatal error discard this line */
223 if (!last) {
224 newMulticastPacket(rfb, rect);
225 nextRectangle(rect);
226 }
227 return;
228 } else
229 flushRectangle(rect); // normal case
230 // later half is remain continue
231 } else {
232 flushMuticast(rfb);
233 newMulticastPacket(rfb,rect);
234 nextRectangle(rect);
235 }
236 // do later half in new Packet
237 from = hoffset ; len = offset - hoffset;
238 deflater.setInput(bytes, from, len);
239 deflater.deflate(c1, Deflater.NO_FLUSH);
240 hwidth = width;
241 hoffset = offset;
242 hc1offset = c1.position();
243 ztileInLine = MAX_ZTILE/2;
244 }
177 } 245 }
178 } 246 }
179 247
180 /** 248 /**
181 * fix rectangle header 249 * fix rectangle header
191 c1.putInt(rectPos + 8,EncodingType.ZRLEE.getId()); 259 c1.putInt(rectPos + 8,EncodingType.ZRLEE.getId());
192 c1.putInt(rectPos + 12, c1.position()-rectPos-12); // data length 260 c1.putInt(rectPos + 12, c1.position()-rectPos-12); // data length
193 rectPos = c1.position(); 261 rectPos = c1.position();
194 c1.putShort(2,(short)(c1.getShort(2)+1)); // increment rectangle count 262 c1.putShort(2,(short)(c1.getShort(2)+1)); // increment rectangle count
195 nextRectangle(rect); 263 nextRectangle(rect);
264 ztileInLine = 0;
265 }
266
267 private void unputrectangle() {
268 c1.putShort(2,(short)(c1.getShort(2)-1)); // last rectangle is canceled
196 } 269 }
197 270
198 private void nextRectangle(FramebufferUpdateRectangle rect) { 271 private void nextRectangle(FramebufferUpdateRectangle rect) {
199 if (c1rect.x+c1rect.width < rect.x+rect.width) { 272 if (c1rect.x+c1rect.width < rect.x+rect.width) {
200 c1rect.x = c1rect.width; // next rectangle is phase 1 273 c1rect.x = c1rect.width; // next rectangle is phase 1
206 c1rect.width = 0; 279 c1rect.width = 0;
207 c1rect.height = 0; 280 c1rect.height = 0;
208 } 281 }
209 282
210 private void flushMuticast(TreeRFBProto rfb) { 283 private void flushMuticast(TreeRFBProto rfb) {
211 deflater.deflate(c1, Deflater.FULL_FLUSH);
212 deflater.finish();
213 c1.flip(); 284 c1.flip();
214 //System.out.println("multicastPut: " + c1rect + " length: " + (c1.remaining()-c1headerPos-header.limit())); 285 //System.out.println("multicastPut: " + c1rect + " length: " + (c1.remaining()-c1headerPos-header.limit()));
215 try { 286 try {
216 deflater.reset(); 287 deflater.reset();
217 288