/src/main/java/com/wet/wired/jrc/frame/compression/RunLengthThenGZCompressor.java
Java | 410 lines | 340 code | 63 blank | 7 comment | 65 complexity | e2351a06f00b003307c42a746e860251 MD5 | raw file
1package com.wet.wired.jrc.frame.compression; 2 3import java.io.ByteArrayInputStream; 4import java.io.IOException; 5import java.io.InputStream; 6import java.io.OutputStream; 7import java.util.zip.GZIPInputStream; 8import java.util.zip.GZIPOutputStream; 9 10import com.wet.wired.jrc.frame.Frame; 11 12public class RunLengthThenGZCompressor implements Compressor,Decompressor{ 13 private static final int ALPHA = 0xFF000000; 14 private static final int READ_BLOCK_SIZE = 10000; 15 16 private class OutputStreamMonitor extends OutputStream { 17 private OutputStream delegate; 18 private int writeCount = 0; 19 20 public OutputStreamMonitor(OutputStream out) { 21 delegate = out; 22 } 23 24 public void close() throws IOException { 25 delegate.close(); 26 } 27 28 public boolean equals(Object obj) { 29 return delegate.equals(obj); 30 } 31 32 public void flush() throws IOException { 33 delegate.flush(); 34 } 35 36 public int hashCode() { 37 return delegate.hashCode(); 38 } 39 40 public String toString() { 41 return delegate.toString(); 42 } 43 44 public void write(byte[] b, int off, int len) throws IOException { 45 delegate.write(b, off, len); 46 writeCount+=len; 47 } 48 49 public void write(byte[] b) throws IOException { 50 delegate.write(b); 51 writeCount+=b.length; 52 } 53 54 public void write(int b) throws IOException { 55 delegate.write(b); 56 writeCount++; 57 } 58 59 private int getWriteCount() { 60 return writeCount; 61 } 62 } 63 64 @Override 65 public int compressFrame(Frame lastFrame,Frame currentFrame, OutputStream out) throws IOException { 66 int inCursor = 0; 67 int outCursor = 0; 68 int blocks = 0; 69 70 boolean inBlock = true; 71 int blockSize = 0; 72 byte blockRed = 0; 73 byte blockGreen = 0; 74 byte blockBlue = 0; 75 76 int blankBlocks = 0; 77 78 int uncompressedCursor = -1; 79 80 byte red; 81 byte green; 82 byte blue; 83 84 boolean hasChanges = false; 85 boolean lastEntry = false; 86 87 int[] currFrame = currentFrame.getData(); 88 int[] prevFrame = lastFrame.getData(); 89 byte[] compFrame = new byte[lastFrame.getData().length]; 90 91 int dataSize = lastFrame.getData().length; 92 93 OutputStreamMonitor outMonitor = new OutputStreamMonitor(out); 94 95 while(inCursor < dataSize) 96 { 97 if(inCursor == dataSize - 1) 98 { 99 lastEntry = true; 100 } 101 102 if(currFrame[inCursor] == prevFrame[inCursor]) 103 { 104 red=0; 105 green=0; 106 blue=0; 107 } 108 else 109 { 110 red = (byte) ((currFrame[inCursor] & 0x00FF0000) >>> 16); 111 green = (byte) ((currFrame[inCursor] & 0x0000FF00) >>> 8); 112 blue = (byte) ((currFrame[inCursor] & 0x000000FF)); 113 114 if(red==0 && green==0 && blue==0) 115 { 116 blue = 1; 117 } 118 } 119 120 if( 121 blockRed == red && 122 blockGreen == green && 123 blockBlue == blue 124 ) 125 { 126 if(inBlock == false) 127 { 128 if(uncompressedCursor > -1) 129 { 130 blocks++; 131 hasChanges = true; 132 compFrame[uncompressedCursor] = (byte)(blockSize + 0x80); 133 } 134 inBlock = true; 135 blockSize = 0; 136 blankBlocks = 0; 137 } 138 else if(blockSize == 126 || lastEntry == true) 139 { 140 if ( 141 blockRed == 0 && 142 blockGreen == 0 && 143 blockBlue == 0 144 ) 145 { 146 if (blankBlocks > 0) 147 { 148 blankBlocks++; 149 compFrame[outCursor-1] = (byte) blankBlocks; 150 } 151 else 152 { 153 blocks++; 154 blankBlocks++; 155 compFrame[outCursor] = (byte)0xFF; 156 outCursor++; 157 compFrame[outCursor] = (byte)blankBlocks; 158 outCursor++; 159 } 160 if(blankBlocks == 255) 161 { 162 blankBlocks = 0; 163 } 164 } 165 else 166 { 167 blocks++; 168 hasChanges = true; 169 compFrame[outCursor] = (byte)blockSize; 170 outCursor++; 171 compFrame[outCursor] = blockRed; 172 outCursor++; 173 compFrame[outCursor] = blockGreen; 174 outCursor++; 175 compFrame[outCursor] = blockBlue; 176 outCursor++; 177 178 blankBlocks = 0; 179 } 180 inBlock = true; 181 blockSize = 0; 182 } 183 } 184 else 185 { 186 if(inBlock == true) 187 { 188 if(blockSize > 0) 189 { 190 blocks++; 191 hasChanges = true; 192 compFrame[outCursor] = (byte) blockSize; 193 outCursor++; 194 compFrame[outCursor] = blockRed; 195 outCursor++; 196 compFrame[outCursor] = blockGreen; 197 outCursor++; 198 compFrame[outCursor] = blockBlue; 199 outCursor++; 200 } 201 202 uncompressedCursor = -1; 203 inBlock = false; 204 blockSize = 0; 205 206 blankBlocks = 0; 207 } 208 else if(blockSize == 126 || lastEntry == true) 209 { 210 if(uncompressedCursor>-1) 211 { 212 blocks++; 213 hasChanges = true; 214 compFrame[uncompressedCursor] = (byte)(blockSize + 0x80); 215 } 216 217 uncompressedCursor = -1; 218 inBlock = false; 219 blockSize = 0; 220 221 blankBlocks = 0; 222 } 223 224 225 if(uncompressedCursor == -1) 226 { 227 uncompressedCursor = outCursor; 228 outCursor++; 229 } 230 231 compFrame[outCursor] = red; 232 outCursor++; 233 compFrame[outCursor] = green; 234 outCursor++; 235 compFrame[outCursor] = blue; 236 outCursor++; 237 238 blockRed = red; 239 blockGreen = green; 240 blockBlue = blue; 241 } 242 inCursor++; 243 blockSize++; 244 } 245 246 if(hasChanges==false) { 247 return -1; 248 } 249 250 GZIPOutputStream zO = new GZIPOutputStream(outMonitor); 251 zO.write(compFrame,0,outCursor); 252 zO.close(); 253 254 return outMonitor.getWriteCount(); 255 } 256 257 public void decompressFrame(InputStream in,int framePacketSize,Frame lastFrame,Frame currentFrame) throws IOException { 258 259 int[] prevFrame = lastFrame.getData(); 260 int[] currFrame = currentFrame.getData(); 261 int currFrameSize = currFrame.length; 262 263 byte[] compFrame = new byte[currFrameSize*4]; 264 int compFrameSize = 0; 265 266 byte[] zData = new byte[framePacketSize]; 267 268 int maxBlockSize = READ_BLOCK_SIZE; 269 if(maxBlockSize>framePacketSize) { 270 maxBlockSize = framePacketSize; 271 } 272 int sizeRead=in.read(zData,0,maxBlockSize); 273 int cursor=sizeRead; 274 while(sizeRead!=-1 && cursor<framePacketSize) { 275 if(maxBlockSize+cursor>framePacketSize) { 276 maxBlockSize = framePacketSize-cursor; 277 } 278 sizeRead=in.read(zData,cursor,maxBlockSize); 279 if(sizeRead>0) { 280 cursor+=sizeRead; 281 } 282 } 283 284 ByteArrayInputStream biStream = new ByteArrayInputStream( zData,0,zData.length ); 285 GZIPInputStream gzipInputStream = new GZIPInputStream( biStream ); 286 287 sizeRead = gzipInputStream.read(compFrame,0,READ_BLOCK_SIZE); 288 if(sizeRead>0) { 289 cursor+=sizeRead; 290 } 291 cursor=sizeRead; 292 293 while(sizeRead>-1) 294 { 295 sizeRead = gzipInputStream.read(compFrame,cursor,READ_BLOCK_SIZE); 296 if(sizeRead>0) { 297 cursor += sizeRead; 298 } 299 } 300 301 compFrameSize = cursor; 302 303 int inCursor = 0; 304 int outCursor = 0; 305 306 int blockSize = 0; 307 308 int rgb = 0xFF000000; 309 310 //System.out.println("Combining old:"+frame.previousData+" with new:"+frame.newData); 311 312 while(inCursor < compFrameSize && outCursor < currFrameSize) 313 { 314 if(compFrame[inCursor] == -1) 315 { 316 inCursor++; 317 318 int count = (compFrame[inCursor] & 0xFF); 319 inCursor++; 320 321 int size = count*126; 322 if( size > currFrameSize) 323 { 324 size = currFrameSize; 325 } 326 //System.arraycopy(frame.previousData,0,frame.newData,0,size); 327 //outCursor+=size; 328 329 for(int loop=0; loop < (126 * count); loop++) 330 { 331 //frame.newData[outCursor]=blue;//frame.previousData[outCursor]; 332 currFrame[outCursor] = prevFrame[outCursor]; 333 //newRawData[outCursor]=blue; 334 outCursor++; 335 if(outCursor == currFrameSize) 336 { 337 break; 338 } 339 } 340 341 } 342 else if (compFrame[inCursor] < 0) // uncomp 343 { 344 blockSize = compFrame[inCursor] & 0x7F;//(128+packed[inCursor]); 345 inCursor++; 346 347 for(int loop=0; loop < blockSize; loop++) 348 { 349 rgb = ((compFrame[inCursor] & 0xFF)<<16) 350 | ((compFrame[inCursor+1] & 0xFF) << 8) 351 | (compFrame[inCursor+2] & 0xFF) 352 | ALPHA; 353 354 if(rgb == ALPHA) 355 { 356 rgb = prevFrame[outCursor]; 357 } 358 //rgb = green; 359 inCursor += 3; 360 currFrame[outCursor] = rgb; 361 outCursor++; 362 if (outCursor == currFrame.length) 363 { 364 break; 365 } 366 } 367 } 368 else 369 { 370 blockSize = compFrame[inCursor]; 371 inCursor++; 372 rgb = ((compFrame[inCursor] & 0xFF) << 16) 373 | ((compFrame[inCursor+1] & 0xFF) << 8) 374 | (compFrame[inCursor+2] & 0xFF) 375 | ALPHA; 376 377 boolean transparent = false; 378 if(rgb == ALPHA) 379 { 380 transparent = true; 381 } 382 //rgb = red; 383 inCursor += 3; 384 385 for (int loop = 0; loop < blockSize; loop++) 386 { 387 if (transparent) 388 { 389 currFrame[outCursor] = prevFrame[outCursor]; 390 } 391 else 392 { 393 currFrame[outCursor] = rgb; 394 } 395 outCursor++; 396 if (outCursor == currFrameSize) 397 { 398 break; 399 } 400 } 401 } 402 } 403 if(outCursor<currFrameSize) { 404 currFrame[outCursor]=rgb; 405 } 406 407 currentFrame.setData(currFrame); 408 } 409 410}