Mercurial > hg > Members > riono > TreeVNC_ja_comment
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 |