blob: 91a9f9deb06b854e25530455d809ea518b153e58 [file] [log] [blame]
Adam Tkacf53e62a2009-03-13 13:20:26 +00001package com.tigervnc.decoder;
enikey27a239d2008-12-19 07:32:05 +00002
Adam Tkacf53e62a2009-03-13 13:20:26 +00003import com.tigervnc.vncviewer.InStream;
4import com.tigervnc.vncviewer.RfbInputStream;
5import com.tigervnc.vncviewer.ZlibInStream;
enikey27a239d2008-12-19 07:32:05 +00006import java.awt.Graphics;
Adam Tkacf53e62a2009-03-13 13:20:26 +00007import com.tigervnc.vncviewer.MemInStream;
enikey4f3dac92008-12-19 07:45:53 +00008import java.awt.Color;
9import java.awt.Toolkit;
10import java.awt.image.MemoryImageSource;
11import java.io.IOException;
enikey27a239d2008-12-19 07:32:05 +000012
13//
14// Class that used for decoding ZRLE encoded data.
15//
16
enikey6aa2dbc2008-12-19 07:38:11 +000017public class ZRLEDecoder extends RawDecoder {
enikey27a239d2008-12-19 07:32:05 +000018
enikey6558a302008-12-24 05:14:30 +000019 final static int EncodingZRLE = 16;
20
enikey27a239d2008-12-19 07:32:05 +000021 public ZRLEDecoder(Graphics g, RfbInputStream is) {
22 super(g, is);
23 }
24
25 public ZRLEDecoder(Graphics g, RfbInputStream is, int frameBufferW,
26 int frameBufferH) {
27 super(g, is, frameBufferW, frameBufferH);
28 }
29
enikey6aa2dbc2008-12-19 07:38:11 +000030 //
enikey4f3dac92008-12-19 07:45:53 +000031 // Handle a ZRLE-encoded rectangle.
32 //
33 // FIXME: Currently, session recording is not fully supported for ZRLE.
34 //
35
36 public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
enikey2f0294e2008-12-24 08:18:54 +000037
38 //
39 // Write encoding ID to record output stream
40 //
41
42 if (dos != null) {
43 dos.writeInt(ZRLEDecoder.EncodingZRLE);
44 }
45
enikey4f3dac92008-12-19 07:45:53 +000046 if (zrleInStream == null)
47 zrleInStream = new ZlibInStream();
48
49 int nBytes = rfbis.readU32();
50 if (nBytes > 64 * 1024 * 1024)
51 throw new Exception("ZRLE decoder: illegal compressed data size");
52
53 if (zrleBuf == null || zrleBufLen < nBytes) {
54 zrleBufLen = nBytes + 4096;
55 zrleBuf = new byte[zrleBufLen];
56 }
57
58 // FIXME: Do not wait for all the data before decompression.
59 rfbis.readFully(zrleBuf, 0, nBytes);
60
61 //
62 // Override handleRect method to decode RRE encoded data insted of
63 // raw pixel data.
64 //
65
enikey5fac7082008-12-25 10:26:40 +000066 if (dos != null) {
67 if (!zrleRecWarningShown) {
enikey4f3dac92008-12-19 07:45:53 +000068 System.out.println("Warning: ZRLE session can be recorded" +
69 " only from the beginning");
70 System.out.println("Warning: Recorded file may be corrupted");
71 zrleRecWarningShown = true;
72 }
73 }
74
75 zrleInStream.setUnderlying(new MemInStream(zrleBuf, 0, nBytes), nBytes);
76
77 for (int ty = y; ty < y+h; ty += 64) {
78
79 int th = Math.min(y+h-ty, 64);
80
81 for (int tx = x; tx < x+w; tx += 64) {
82
83 int tw = Math.min(x+w-tx, 64);
84
85 int mode = zrleInStream.readU8();
86 boolean rle = (mode & 128) != 0;
87 int palSize = mode & 127;
88 int[] palette = new int[128];
89
90 readZrlePalette(palette, palSize);
91
92 if (palSize == 1) {
93 int pix = palette[0];
94 Color c = (bytesPerPixel == 1) ?
95 getColor256()[pix] : new Color(0xFF000000 | pix);
96 graphics.setColor(c);
97 graphics.fillRect(tx, ty, tw, th);
98 continue;
99 }
100
101 if (!rle) {
102 if (palSize == 0) {
103 readZrleRawPixels(tw, th);
104 } else {
105 readZrlePackedPixels(tw, th, palette, palSize);
106 }
107 } else {
108 if (palSize == 0) {
109 readZrlePlainRLEPixels(tw, th);
110 } else {
111 readZrlePackedRLEPixels(tw, th, palette);
112 }
113 }
114 handleUpdatedZrleTile(tx, ty, tw, th);
115 }
116 }
117 zrleInStream.reset();
118 }
119
120 //
121 // Override update() method cause we have own data that
122 // must be updated when framebuffer is resized or BPP is changed
123 //
124
125 public void update() {
126 // Images with raw pixels should be re-allocated on every change
127 // of geometry or pixel format.
128 int fbWidth = framebufferWidth;
129 int fbHeight = framebufferHeight;
130
131 if (bytesPerPixel == 1) {
132 RawDecoder.pixels24 = null;
133 RawDecoder.pixels8 = new byte[fbWidth * fbHeight];
134 RawDecoder.pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(), pixels8, 0, fbWidth);
135 zrleTilePixels24 = null;
136 zrleTilePixels8 = new byte[64 * 64];
137 } else {
138 RawDecoder.pixels8 = null;
139 RawDecoder.pixels24 = new int[fbWidth * fbHeight];
140 RawDecoder.pixelsSource =
141 new MemoryImageSource(fbWidth, fbHeight, getColorModel24(), pixels24, 0, fbWidth);
142 zrleTilePixels8 = null;
143 zrleTilePixels24 = new int[64 * 64];
144 }
145 RawDecoder.pixelsSource.setAnimated(true);
146 RawDecoder.rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
147 }
148
149 //
150 // Copy pixels from zrleTilePixels8 or zrleTilePixels24, then update.
151 //
152
153 private void handleUpdatedZrleTile(int x, int y, int w, int h) {
154 Object src, dst;
155 if (bytesPerPixel == 1) {
156 src = zrleTilePixels8; dst = pixels8;
157 } else {
158 src = zrleTilePixels24; dst = pixels24;
159 }
160 int offsetSrc = 0;
161 int offsetDst = (y * framebufferWidth + x);
162 for (int j = 0; j < h; j++) {
163 System.arraycopy(src, offsetSrc, dst, offsetDst, w);
164 offsetSrc += w;
165 offsetDst += framebufferWidth;
166 }
167 handleUpdatedPixels(x, y, w, h);
168 }
169
170 //
enikey6aa2dbc2008-12-19 07:38:11 +0000171 // Private methods for reading ZRLE data
172 //
173
174 private int readPixel(InStream is) throws Exception {
175 int pix;
176 if (bytesPerPixel == 1) {
177 pix = is.readU8();
178 } else {
179 int p1 = is.readU8();
180 int p2 = is.readU8();
181 int p3 = is.readU8();
182 pix = (p3 & 0xFF) << 16 | (p2 & 0xFF) << 8 | (p1 & 0xFF);
183 }
184 return pix;
185 }
186
187 private void readPixels(InStream is, int[] dst, int count) throws Exception {
188 if (bytesPerPixel == 1) {
189 byte[] buf = new byte[count];
190 is.readBytes(buf, 0, count);
191 for (int i = 0; i < count; i++) {
192 dst[i] = (int)buf[i] & 0xFF;
193 }
194 } else {
195 byte[] buf = new byte[count * 3];
196 is.readBytes(buf, 0, count * 3);
197 for (int i = 0; i < count; i++) {
198 dst[i] = ((buf[i*3+2] & 0xFF) << 16 |
199 (buf[i*3+1] & 0xFF) << 8 |
200 (buf[i*3] & 0xFF));
201 }
202 }
203 }
204
205 private void readZrlePalette(int[] palette, int palSize) throws Exception {
206 readPixels(zrleInStream, palette, palSize);
207 }
208
209 private void readZrleRawPixels(int tw, int th) throws Exception {
210 if (bytesPerPixel == 1) {
211 zrleInStream.readBytes(zrleTilePixels8, 0, tw * th);
212 } else {
213 readPixels(zrleInStream, zrleTilePixels24, tw * th); ///
214 }
215 }
216
217 private void readZrlePackedPixels(int tw, int th, int[] palette, int palSize)
218 throws Exception {
219
220 int bppp = ((palSize > 16) ? 8 :
221 ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
222 int ptr = 0;
223
224 for (int i = 0; i < th; i++) {
225 int eol = ptr + tw;
226 int b = 0;
227 int nbits = 0;
228
229 while (ptr < eol) {
230 if (nbits == 0) {
231 b = zrleInStream.readU8();
232 nbits = 8;
233 }
234 nbits -= bppp;
235 int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
236 if (bytesPerPixel == 1) {
237 zrleTilePixels8[ptr++] = (byte)palette[index];
238 } else {
239 zrleTilePixels24[ptr++] = palette[index];
240 }
241 }
242 }
243 }
244
245 private void readZrlePlainRLEPixels(int tw, int th) throws Exception {
246 int ptr = 0;
247 int end = ptr + tw * th;
248 while (ptr < end) {
249 int pix = readPixel(zrleInStream);
250 int len = 1;
251 int b;
252 do {
253 b = zrleInStream.readU8();
254 len += b;
255 } while (b == 255);
256
257 if (!(len <= end - ptr))
258 throw new Exception("ZRLE decoder: assertion failed" +
259 " (len <= end-ptr)");
260
261 if (bytesPerPixel == 1) {
262 while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
263 } else {
264 while (len-- > 0) zrleTilePixels24[ptr++] = pix;
265 }
266 }
267 }
268
269 private void readZrlePackedRLEPixels(int tw, int th, int[] palette)
270 throws Exception {
271
272 int ptr = 0;
273 int end = ptr + tw * th;
274 while (ptr < end) {
275 int index = zrleInStream.readU8();
276 int len = 1;
277 if ((index & 128) != 0) {
278 int b;
279 do {
280 b = zrleInStream.readU8();
281 len += b;
282 } while (b == 255);
283
284 if (!(len <= end - ptr))
285 throw new Exception("ZRLE decoder: assertion failed" +
286 " (len <= end - ptr)");
287 }
288
289 index &= 127;
290 int pix = palette[index];
291
292 if (bytesPerPixel == 1) {
293 while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
294 } else {
295 while (len-- > 0) zrleTilePixels24[ptr++] = pix;
296 }
297 }
298 }
299
300 //
301 // ZRLE encoder's data.
302 //
303
304 private byte[] zrleBuf;
305 private int zrleBufLen = 0;
306 private byte[] zrleTilePixels8;
307 private int[] zrleTilePixels24;
308 private ZlibInStream zrleInStream;
309 private boolean zrleRecWarningShown = false;
enikey27a239d2008-12-19 07:32:05 +0000310}