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 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /* Copyright (C) 2002-2005 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 macro:
  22. // BPP - 8, 16 or 32
  23. //
  24. // Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel
  25. // bigger than the largest tile of pixel data, since the ZRLE encoding
  26. // algorithm writes to the position one past the end of the pixel data.
  27. //
  28. #include <rdr/OutStream.h>
  29. #include <rdr/ZlibOutStream.h>
  30. #include <rfb/Palette.h>
  31. #include <rfb/PixelBuffer.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(os, u) CONCAT2E(writeOpaque,CPIXEL)(os, u)
  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(os, u) os->CONCAT2E(writeOpaque,BPP)(u)
  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. #endif
  58. void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os);
  59. void ZRLE_ENCODE (const Rect& r, rdr::OutStream* os,
  60. rdr::ZlibOutStream* zos, void* buf,
  61. const PixelFormat& pf, PixelBuffer* pb)
  62. {
  63. zos->setUnderlying(os);
  64. // RLE overhead is at worst 1 byte per 64x64 (4Kpixel) block
  65. int worstCaseLine = r.width() * 64 * (BPPOUT/8) + 1 + r.width() / 64;
  66. // Zlib overhead is at worst 6 bytes plus 5 bytes per 32Kbyte block.
  67. worstCaseLine += 11 + 5 * (worstCaseLine >> 15);
  68. Rect t;
  69. for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
  70. t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
  71. for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
  72. t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
  73. pb->getImage(pf, buf, t);
  74. ZRLE_ENCODE_TILE((PIXEL_T*)buf, t.width(), t.height(), zos);
  75. }
  76. zos->flush();
  77. }
  78. }
  79. void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os)
  80. {
  81. // First find the palette and the number of runs
  82. Palette palette;
  83. int runs = 0;
  84. int singlePixels = 0;
  85. PIXEL_T* ptr = data;
  86. PIXEL_T* end = ptr + h * w;
  87. *end = ~*(end-1); // one past the end is different so the while loop ends
  88. while (ptr < end) {
  89. PIXEL_T pix = *ptr;
  90. if (*++ptr != pix) {
  91. singlePixels++;
  92. } else {
  93. while (*++ptr == pix) ;
  94. runs++;
  95. }
  96. palette.insert(pix, 1);
  97. }
  98. //fprintf(stderr,"runs %d, single pixels %d, paletteSize %d\n",
  99. // runs, singlePixels, ph.size);
  100. // Solid tile is a special case
  101. if (palette.size() == 1) {
  102. os->writeU8(1);
  103. WRITE_PIXEL(os, palette.getColour(0));
  104. return;
  105. }
  106. // Try to work out whether to use RLE and/or a palette. We do this by
  107. // estimating the number of bytes which will be generated and picking the
  108. // method which results in the fewest bytes. Of course this may not result
  109. // in the fewest bytes after compression...
  110. bool useRle = false;
  111. bool usePalette = false;
  112. int estimatedBytes = w * h * (BPPOUT/8); // start assuming raw
  113. int plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels);
  114. if (plainRleBytes < estimatedBytes) {
  115. useRle = true;
  116. estimatedBytes = plainRleBytes;
  117. }
  118. if (palette.size() < 128) {
  119. int paletteRleBytes = (BPPOUT/8) * palette.size() + 2 * runs + singlePixels;
  120. if (paletteRleBytes < estimatedBytes) {
  121. useRle = true;
  122. usePalette = true;
  123. estimatedBytes = paletteRleBytes;
  124. }
  125. if (palette.size() < 17) {
  126. int packedBytes = ((BPPOUT/8) * palette.size() +
  127. w * h * bitsPerPackedPixel[palette.size()-1] / 8);
  128. if (packedBytes < estimatedBytes) {
  129. useRle = false;
  130. usePalette = true;
  131. estimatedBytes = packedBytes;
  132. }
  133. }
  134. }
  135. if (!usePalette) palette.clear();
  136. os->writeU8((useRle ? 128 : 0) | palette.size());
  137. for (int i = 0; i < palette.size(); i++) {
  138. WRITE_PIXEL(os, palette.getColour(i));
  139. }
  140. if (useRle) {
  141. PIXEL_T* ptr = data;
  142. PIXEL_T* end = ptr + w * h;
  143. PIXEL_T* runStart;
  144. PIXEL_T pix;
  145. while (ptr < end) {
  146. runStart = ptr;
  147. pix = *ptr++;
  148. while (*ptr == pix && ptr < end)
  149. ptr++;
  150. int len = ptr - runStart;
  151. if (len <= 2 && usePalette) {
  152. int index = palette.lookup(pix);
  153. if (len == 2)
  154. os->writeU8(index);
  155. os->writeU8(index);
  156. continue;
  157. }
  158. if (usePalette) {
  159. int index = palette.lookup(pix);
  160. os->writeU8(index | 128);
  161. } else {
  162. WRITE_PIXEL(os, pix);
  163. }
  164. len -= 1;
  165. while (len >= 255) {
  166. os->writeU8(255);
  167. len -= 255;
  168. }
  169. os->writeU8(len);
  170. }
  171. } else {
  172. // no RLE
  173. if (usePalette) {
  174. // packed pixels
  175. assert (palette.size() < 17);
  176. int bppp = bitsPerPackedPixel[palette.size()-1];
  177. PIXEL_T* ptr = data;
  178. for (int i = 0; i < h; i++) {
  179. rdr::U8 nbits = 0;
  180. rdr::U8 byte = 0;
  181. PIXEL_T* eol = ptr + w;
  182. while (ptr < eol) {
  183. PIXEL_T pix = *ptr++;
  184. rdr::U8 index = palette.lookup(pix);
  185. byte = (byte << bppp) | index;
  186. nbits += bppp;
  187. if (nbits >= 8) {
  188. os->writeU8(byte);
  189. nbits = 0;
  190. }
  191. }
  192. if (nbits > 0) {
  193. byte <<= 8 - nbits;
  194. os->writeU8(byte);
  195. }
  196. }
  197. } else {
  198. // raw
  199. #ifdef CPIXEL
  200. for (PIXEL_T* ptr = data; ptr < data+w*h; ptr++) {
  201. WRITE_PIXEL(os, *ptr);
  202. }
  203. #else
  204. os->writeBytes(data, w*h*(BPP/8));
  205. #endif
  206. }
  207. }
  208. }
  209. #undef PIXEL_T
  210. #undef WRITE_PIXEL
  211. #undef ZRLE_ENCODE
  212. #undef ZRLE_ENCODE_TILE
  213. #undef BPPOUT
  214. }