add libvncserver
[presencevnc] / libvnc / libvncserver / zrleencodetemplate.c
1 /*
2  * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
3  * Copyright (C) 2003 Sun Microsystems, Inc.
4  *
5  * This is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This software is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this software; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
18  * USA.
19  */
20
21 /*
22  * Before including this file, you must define a number of CPP macros.
23  *
24  * BPP should be 8, 16 or 32 depending on the bits per pixel.
25  * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data
26  * into the given buffer.  EXTRA_ARGS can be defined to pass any other
27  * arguments needed by GET_IMAGE_INTO_BUF.
28  *
29  * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
30  * bigger than the largest tile of pixel data, since the ZRLE encoding
31  * algorithm writes to the position one past the end of the pixel data.
32  */
33
34 #include "zrleoutstream.h"
35 #include "zrlepalettehelper.h"
36 #include <assert.h>
37
38 /* __RFB_CONCAT2 concatenates its two arguments.  __RFB_CONCAT2E does the same
39    but also expands its arguments if they are macros */
40
41 #ifndef __RFB_CONCAT2E
42 #define __RFB_CONCAT2(a,b) a##b
43 #define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b)
44 #endif
45
46 #ifndef __RFB_CONCAT3E
47 #define __RFB_CONCAT3(a,b,c) a##b##c
48 #define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c)
49 #endif
50
51 #undef END_FIX
52 #if ZYWRLE_ENDIAN == ENDIAN_LITTLE
53 #  define END_FIX LE
54 #elif ZYWRLE_ENDIAN == ENDIAN_BIG
55 #  define END_FIX BE
56 #else
57 #  define END_FIX NE
58 #endif
59
60 #ifdef CPIXEL
61 #define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
62 #define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL)
63 #define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX)
64 #define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX)
65 #define BPPOUT 24
66 #elif BPP==15
67 #define PIXEL_T __RFB_CONCAT2E(zrle_U,16)
68 #define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16)
69 #define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
70 #define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
71 #define BPPOUT 16
72 #else
73 #define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP)
74 #define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP)
75 #define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX)
76 #define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX)
77 #define BPPOUT BPP
78 #endif
79
80 #ifndef ZRLE_ONCE
81 #define ZRLE_ONCE
82
83 static const int bitsPerPackedPixel[] = {
84   0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
85 };
86
87 static zrlePaletteHelper paletteHelper;
88
89 #endif /* ZRLE_ONCE */
90
91 void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os,
92                 int zywrle_level, int *zywrleBuf);
93
94 #if BPP!=8
95 #define ZYWRLE_ENCODE
96 #include "zywrletemplate.c"
97 #endif
98
99 static void ZRLE_ENCODE (int x, int y, int w, int h,
100                   zrleOutStream* os, void* buf
101                   EXTRA_ARGS
102                   )
103 {
104   int ty;
105   for (ty = y; ty < y+h; ty += rfbZRLETileHeight) {
106     int tx, th = rfbZRLETileHeight;
107     if (th > y+h-ty) th = y+h-ty;
108     for (tx = x; tx < x+w; tx += rfbZRLETileWidth) {
109       int tw = rfbZRLETileWidth;
110       if (tw > x+w-tx) tw = x+w-tx;
111
112       GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
113
114       ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os,
115                       cl->zywrleLevel, cl->zywrleBuf);
116     }
117   }
118   zrleOutStreamFlush(os);
119 }
120
121
122 void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
123         int zywrle_level, int *zywrleBuf)
124 {
125   /* First find the palette and the number of runs */
126
127   zrlePaletteHelper *ph;
128
129   int runs = 0;
130   int singlePixels = 0;
131
132   rfbBool useRle;
133   rfbBool usePalette;
134
135   int estimatedBytes;
136   int plainRleBytes;
137   int i;
138
139   PIXEL_T* ptr = data;
140   PIXEL_T* end = ptr + h * w;
141   *end = ~*(end-1); /* one past the end is different so the while loop ends */
142
143   ph = &paletteHelper;
144   zrlePaletteHelperInit(ph);
145
146   while (ptr < end) {
147     PIXEL_T pix = *ptr;
148     if (*++ptr != pix) {
149       singlePixels++;
150     } else {
151       while (*++ptr == pix) ;
152       runs++;
153     }
154     zrlePaletteHelperInsert(ph, pix);
155   }
156
157   /* Solid tile is a special case */
158
159   if (ph->size == 1) {
160     zrleOutStreamWriteU8(os, 1);
161     zrleOutStreamWRITE_PIXEL(os, ph->palette[0]);
162     return;
163   }
164
165   /* Try to work out whether to use RLE and/or a palette.  We do this by
166      estimating the number of bytes which will be generated and picking the
167      method which results in the fewest bytes.  Of course this may not result
168      in the fewest bytes after compression... */
169
170   useRle = FALSE;
171   usePalette = FALSE;
172
173   estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */
174
175 #if BPP!=8
176   if (zywrle_level > 0 && !(zywrle_level & 0x80))
177           estimatedBytes >>= zywrle_level;
178 #endif
179
180   plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
181
182   if (plainRleBytes < estimatedBytes) {
183     useRle = TRUE;
184     estimatedBytes = plainRleBytes;
185   }
186
187   if (ph->size < 128) {
188     int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels;
189
190     if (paletteRleBytes < estimatedBytes) {
191       useRle = TRUE;
192       usePalette = TRUE;
193       estimatedBytes = paletteRleBytes;
194     }
195
196     if (ph->size < 17) {
197       int packedBytes = ((BPPOUT/8) * ph->size +
198                          w * h * bitsPerPackedPixel[ph->size-1] / 8);
199
200       if (packedBytes < estimatedBytes) {
201         useRle = FALSE;
202         usePalette = TRUE;
203         estimatedBytes = packedBytes;
204       }
205     }
206   }
207
208   if (!usePalette) ph->size = 0;
209
210   zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size);
211
212   for (i = 0; i < ph->size; i++) {
213     zrleOutStreamWRITE_PIXEL(os, ph->palette[i]);
214   }
215
216   if (useRle) {
217
218     PIXEL_T* ptr = data;
219     PIXEL_T* end = ptr + w * h;
220     PIXEL_T* runStart;
221     PIXEL_T pix;
222     while (ptr < end) {
223       int len;
224       runStart = ptr;
225       pix = *ptr++;
226       while (*ptr == pix && ptr < end)
227         ptr++;
228       len = ptr - runStart;
229       if (len <= 2 && usePalette) {
230         int index = zrlePaletteHelperLookup(ph, pix);
231         if (len == 2)
232           zrleOutStreamWriteU8(os, index);
233         zrleOutStreamWriteU8(os, index);
234         continue;
235       }
236       if (usePalette) {
237         int index = zrlePaletteHelperLookup(ph, pix);
238         zrleOutStreamWriteU8(os, index | 128);
239       } else {
240         zrleOutStreamWRITE_PIXEL(os, pix);
241       }
242       len -= 1;
243       while (len >= 255) {
244         zrleOutStreamWriteU8(os, 255);
245         len -= 255;
246       }
247       zrleOutStreamWriteU8(os, len);
248     }
249
250   } else {
251
252     /* no RLE */
253
254     if (usePalette) {
255       int bppp;
256       PIXEL_T* ptr = data;
257
258       /* packed pixels */
259
260       assert (ph->size < 17);
261
262       bppp = bitsPerPackedPixel[ph->size-1];
263
264       for (i = 0; i < h; i++) {
265         zrle_U8 nbits = 0;
266         zrle_U8 byte = 0;
267
268         PIXEL_T* eol = ptr + w;
269
270         while (ptr < eol) {
271           PIXEL_T pix = *ptr++;
272           zrle_U8 index = zrlePaletteHelperLookup(ph, pix);
273           byte = (byte << bppp) | index;
274           nbits += bppp;
275           if (nbits >= 8) {
276             zrleOutStreamWriteU8(os, byte);
277             nbits = 0;
278           }
279         }
280         if (nbits > 0) {
281           byte <<= 8 - nbits;
282           zrleOutStreamWriteU8(os, byte);
283         }
284       }
285     } else {
286
287       /* raw */
288
289 #if BPP!=8
290       if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
291         ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf);
292         ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf);
293       }
294       else
295 #endif
296       {
297 #ifdef CPIXEL
298         PIXEL_T *ptr;
299         for (ptr = data; ptr < data+w*h; ptr++)
300           zrleOutStreamWRITE_PIXEL(os, *ptr);
301 #else
302         zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8));
303 #endif
304       }
305     }
306   }
307 }
308
309 #undef PIXEL_T
310 #undef zrleOutStreamWRITE_PIXEL
311 #undef ZRLE_ENCODE
312 #undef ZRLE_ENCODE_TILE
313 #undef ZYWRLE_ENCODE_TILE
314 #undef BPPOUT