You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

zrleEncode.h 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. //
  19. // zrleEncode.h - zrle encoding function.
  20. //
  21. // This file is #included after having set the following macros:
  22. // BPP - 8, 16 or 32
  23. // EXTRA_ARGS - optional extra arguments
  24. // GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
  25. //
  26. // Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
  27. // bigger than the largest tile of pixel data, since the ZRLE encoding
  28. // algorithm writes to the position one past the end of the pixel data.
  29. //
  30. #include <rdr/OutStream.h>
  31. #include <rdr/ZlibOutStream.h>
  32. #include <assert.h>
  33. namespace rfb {
  34. // CONCAT2E concatenates its arguments, expanding them if they are macros
  35. #ifndef CONCAT2E
  36. #define CONCAT2(a,b) a##b
  37. #define CONCAT2E(a,b) CONCAT2(a,b)
  38. #endif
  39. #ifdef CPIXEL
  40. #define PIXEL_T rdr::CONCAT2E(U,BPP)
  41. #define WRITE_PIXEL CONCAT2E(writeOpaque,CPIXEL)
  42. #define ZRLE_ENCODE CONCAT2E(zrleEncode,CPIXEL)
  43. #define ZRLE_ENCODE_TILE CONCAT2E(zrleEncodeTile,CPIXEL)
  44. #define BPPOUT 24
  45. #else
  46. #define PIXEL_T rdr::CONCAT2E(U,BPP)
  47. #define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
  48. #define ZRLE_ENCODE CONCAT2E(zrleEncode,BPP)
  49. #define ZRLE_ENCODE_TILE CONCAT2E(zrleEncodeTile,BPP)
  50. #define BPPOUT BPP
  51. #endif
  52. #ifndef ZRLE_ONCE
  53. #define ZRLE_ONCE
  54. static const int bitsPerPackedPixel[] = {
  55. 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
  56. };
  57. // The PaletteHelper class helps us build up the palette from pixel data by
  58. // storing a reverse index using a simple hash-table
  59. class PaletteHelper {
  60. public:
  61. enum { MAX_SIZE = 127 };
  62. PaletteHelper()
  63. {
  64. memset(index, 255, sizeof(index));
  65. size = 0;
  66. }
  67. inline int hash(rdr::U32 pix)
  68. {
  69. return (pix ^ (pix >> 17)) & 4095;
  70. }
  71. inline void insert(rdr::U32 pix)
  72. {
  73. if (size < MAX_SIZE) {
  74. int i = hash(pix);
  75. while (index[i] != 255 && key[i] != pix)
  76. i++;
  77. if (index[i] != 255) return;
  78. index[i] = size;
  79. key[i] = pix;
  80. palette[size] = pix;
  81. }
  82. size++;
  83. }
  84. inline int lookup(rdr::U32 pix)
  85. {
  86. assert(size <= MAX_SIZE);
  87. int i = hash(pix);
  88. while (index[i] != 255 && key[i] != pix)
  89. i++;
  90. if (index[i] != 255) return index[i];
  91. return -1;
  92. }
  93. rdr::U32 palette[MAX_SIZE];
  94. rdr::U8 index[4096+MAX_SIZE];
  95. rdr::U32 key[4096+MAX_SIZE];
  96. int size;
  97. };
  98. #endif
  99. void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os);
  100. bool ZRLE_ENCODE (const Rect& r, rdr::OutStream* os,
  101. rdr::ZlibOutStream* zos, void* buf, int maxLen, Rect* actual
  102. #ifdef EXTRA_ARGS
  103. , EXTRA_ARGS
  104. #endif
  105. )
  106. {
  107. zos->setUnderlying(os);
  108. // RLE overhead is at worst 1 byte per 64x64 (4Kpixel) block
  109. int worstCaseLine = r.width() * 64 * (BPPOUT/8) + 1 + r.width() / 64;
  110. // Zlib overhead is at worst 6 bytes plus 5 bytes per 32Kbyte block.
  111. worstCaseLine += 11 + 5 * (worstCaseLine >> 15);
  112. Rect t;
  113. for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
  114. t.br.y = vncmin(r.br.y, t.tl.y + 64);
  115. if (os->length() + worstCaseLine > maxLen) {
  116. if (t.tl.y == r.tl.y)
  117. throw Exception("ZRLE: not enough space for first line?");
  118. actual->tl = r.tl;
  119. actual->br.x = r.br.x;
  120. actual->br.y = t.tl.y;
  121. return false;
  122. }
  123. for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
  124. t.br.x = vncmin(r.br.x, t.tl.x + 64);
  125. GET_IMAGE_INTO_BUF(t,buf);
  126. ZRLE_ENCODE_TILE((PIXEL_T*)buf, t.width(), t.height(), zos);
  127. }
  128. zos->flush();
  129. }
  130. return true;
  131. }
  132. void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os)
  133. {
  134. // First find the palette and the number of runs
  135. PaletteHelper ph;
  136. int runs = 0;
  137. int singlePixels = 0;
  138. PIXEL_T* ptr = data;
  139. PIXEL_T* end = ptr + h * w;
  140. *end = ~*(end-1); // one past the end is different so the while loop ends
  141. while (ptr < end) {
  142. PIXEL_T pix = *ptr;
  143. if (*++ptr != pix) {
  144. singlePixels++;
  145. } else {
  146. while (*++ptr == pix) ;
  147. runs++;
  148. }
  149. ph.insert(pix);
  150. }
  151. //fprintf(stderr,"runs %d, single pixels %d, paletteSize %d\n",
  152. // runs, singlePixels, ph.size);
  153. // Solid tile is a special case
  154. if (ph.size == 1) {
  155. os->writeU8(1);
  156. os->WRITE_PIXEL(ph.palette[0]);
  157. return;
  158. }
  159. // Try to work out whether to use RLE and/or a palette. We do this by
  160. // estimating the number of bytes which will be generated and picking the
  161. // method which results in the fewest bytes. Of course this may not result
  162. // in the fewest bytes after compression...
  163. bool useRle = false;
  164. bool usePalette = false;
  165. int estimatedBytes = w * h * (BPPOUT/8); // start assuming raw
  166. int plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
  167. if (plainRleBytes < estimatedBytes) {
  168. useRle = true;
  169. estimatedBytes = plainRleBytes;
  170. }
  171. if (ph.size < 128) {
  172. int paletteRleBytes = (BPPOUT/8) * ph.size + 2 * runs + singlePixels;
  173. if (paletteRleBytes < estimatedBytes) {
  174. useRle = true;
  175. usePalette = true;
  176. estimatedBytes = paletteRleBytes;
  177. }
  178. if (ph.size < 17) {
  179. int packedBytes = ((BPPOUT/8) * ph.size +
  180. w * h * bitsPerPackedPixel[ph.size-1] / 8);
  181. if (packedBytes < estimatedBytes) {
  182. useRle = false;
  183. usePalette = true;
  184. estimatedBytes = packedBytes;
  185. }
  186. }
  187. }
  188. if (!usePalette) ph.size = 0;
  189. os->writeU8((useRle ? 128 : 0) | ph.size);
  190. for (int i = 0; i < ph.size; i++) {
  191. os->WRITE_PIXEL(ph.palette[i]);
  192. }
  193. if (useRle) {
  194. PIXEL_T* ptr = data;
  195. PIXEL_T* end = ptr + w * h;
  196. PIXEL_T* runStart;
  197. PIXEL_T pix;
  198. while (ptr < end) {
  199. runStart = ptr;
  200. pix = *ptr++;
  201. while (*ptr == pix && ptr < end)
  202. ptr++;
  203. int len = ptr - runStart;
  204. if (len <= 2 && usePalette) {
  205. int index = ph.lookup(pix);
  206. if (len == 2)
  207. os->writeU8(index);
  208. os->writeU8(index);
  209. continue;
  210. }
  211. if (usePalette) {
  212. int index = ph.lookup(pix);
  213. os->writeU8(index | 128);
  214. } else {
  215. os->WRITE_PIXEL(pix);
  216. }
  217. len -= 1;
  218. while (len >= 255) {
  219. os->writeU8(255);
  220. len -= 255;
  221. }
  222. os->writeU8(len);
  223. }
  224. } else {
  225. // no RLE
  226. if (usePalette) {
  227. // packed pixels
  228. assert (ph.size < 17);
  229. int bppp = bitsPerPackedPixel[ph.size-1];
  230. PIXEL_T* ptr = data;
  231. for (int i = 0; i < h; i++) {
  232. rdr::U8 nbits = 0;
  233. rdr::U8 byte = 0;
  234. PIXEL_T* eol = ptr + w;
  235. while (ptr < eol) {
  236. PIXEL_T pix = *ptr++;
  237. rdr::U8 index = ph.lookup(pix);
  238. byte = (byte << bppp) | index;
  239. nbits += bppp;
  240. if (nbits >= 8) {
  241. os->writeU8(byte);
  242. nbits = 0;
  243. }
  244. }
  245. if (nbits > 0) {
  246. byte <<= 8 - nbits;
  247. os->writeU8(byte);
  248. }
  249. }
  250. } else {
  251. // raw
  252. #ifdef CPIXEL
  253. for (PIXEL_T* ptr = data; ptr < data+w*h; ptr++) {
  254. os->WRITE_PIXEL(*ptr);
  255. }
  256. #else
  257. os->writeBytes(data, w*h*(BPP/8));
  258. #endif
  259. }
  260. }
  261. }
  262. #undef PIXEL_T
  263. #undef WRITE_PIXEL
  264. #undef ZRLE_ENCODE
  265. #undef ZRLE_ENCODE_TILE
  266. #undef BPPOUT
  267. }