vncEncodeCoRRE.cpp
上传用户:sbftbdw
上传日期:2007-01-03
资源大小:379k
文件大小:15k
源码类别:

远程控制编程

开发平台:

Visual C++

  1. //  Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory
  2. //
  3. //  This file is part of the VNC system.
  4. //
  5. //  The VNC system 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 program 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 program; if not, write to the Free Software
  17. //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  18. //  USA.
  19. //
  20. // If the source code for the VNC system is not available from the place 
  21. // whence you received this file, check http://www.orl.co.uk/vnc or contact
  22. // the authors on vnc@orl.co.uk for information on obtaining it.
  23. // vncEncodeCoRRE
  24. // This file implements the vncEncoder-derived vncEncodeCoRRE class.
  25. // This class overrides some vncEncoder functions to produce a
  26. // Compact RRE encoder.  Compact RRE (CoRRE) uses fewer bytes to
  27. // encode each subrect, which makes it faster in general.  It also
  28. // splits large rectangles up into ones of at most 256 pixels width
  29. // & height.  This results in better granularity to use for deciding
  30. // whether to send RAW or CoRRE/RRE. 
  31. #include "vncEncodeCoRRE.h"
  32. #include "rfb.h"
  33. #include "MinMax.h"
  34. #include <stdlib.h>
  35. #include <time.h>
  36. vncEncodeCoRRE::vncEncodeCoRRE()
  37. {
  38. m_buffer = NULL;
  39. m_bufflen = 0;
  40. // Set some sensible defaults
  41. m_maxwidth = 24;
  42. m_maxheight = 24;
  43. m_maxadjust = 1;
  44. // Set the threshold up/down probability
  45. m_threshold = 50;
  46. // Seed the random number generator
  47. srand((unsigned)time(NULL));
  48. m_statsready = FALSE;
  49. m_encodedbytes = 0;
  50. m_rectbytes = 0;
  51. }
  52. vncEncodeCoRRE::~vncEncodeCoRRE()
  53. {
  54. if (m_buffer != NULL)
  55. {
  56. delete [] m_buffer;
  57. m_buffer = NULL;
  58. }
  59. }
  60. void vncEncodeCoRRE::Init()
  61. {
  62. vncEncoder::Init();
  63. }
  64. UINT vncEncodeCoRRE::RequiredBuffSize(UINT width, UINT height)
  65. {
  66. RECT fullscreen;
  67. UINT codedrects;
  68. // Work out how many rectangles the entire screen would
  69. // be re-encoded to...
  70. fullscreen.left = 0;
  71. fullscreen.top = 0;
  72. fullscreen.right = width;
  73. fullscreen.bottom = height;
  74. codedrects = NumCodedRects(fullscreen);
  75. // The buffer size required is the size of raw data for the whole
  76. // screen plus enough space for the required number of rectangle
  77. // headers.
  78. // This is inherently always greater than the RAW encoded size of
  79. // the whole screen!
  80. return (codedrects * sz_rfbFramebufferUpdateRectHeader) +
  81. (width * height * m_remoteformat.bitsPerPixel)/8;
  82. }
  83. UINT
  84. vncEncodeCoRRE::NumCodedRects(RECT &rect)
  85. {
  86. // If we have any statistical data handy then adjust the CoRRE sizes
  87. if (m_statsready)
  88. {
  89. m_statsready = FALSE;
  90. UINT newscore = m_encodedbytes * m_lastrectbytes;
  91. UINT oldscore = m_lastencodedbytes * m_rectbytes;
  92. if (newscore <= oldscore)
  93. {
  94. // The change was a good one, so adjust the threshold accordingly!
  95. m_threshold = Max(5, Min(95, m_threshold + m_maxadjust));
  96. m_maxwidth = Max(8, Min(255, m_maxwidth + m_maxadjust));
  97. m_maxheight = Max(8, Min(255, m_maxheight + m_maxadjust));
  98. }
  99. else
  100. {
  101. // The change was a bad one, so adjust the threshold accordingly!
  102. // m_threshold = Max(5, Min(95, m_threshold - m_maxadjust));
  103. }
  104. // Now calculate a new adjustment and apply it
  105. m_maxadjust = ((rand() % 99)<m_threshold) ? 1 : -1;
  106. // Prepare the stats data for next time...
  107. m_lastencodedbytes = m_encodedbytes;
  108. m_lastrectbytes = m_rectbytes;
  109. m_encodedbytes = 0;
  110. m_rectbytes = 0;
  111. }
  112. // Now return the number of rects that this one would encode to
  113.     if ((rect.bottom-rect.top) > m_maxheight)
  114. {
  115. RECT subrect1, subrect2;
  116. // Find how many rects the two subrects would take
  117. subrect1.left = rect.left;
  118. subrect1.right = rect.right;
  119. subrect1.top = rect.top;
  120. subrect1.bottom = rect.top + m_maxheight;
  121. subrect2.left = rect.left;
  122. subrect2.right = rect.right;
  123. subrect2.top = rect.top + m_maxheight;
  124. subrect2.bottom = rect.bottom;
  125. return NumCodedRects(subrect1) + NumCodedRects(subrect2);
  126. }
  127.     if ((rect.right-rect.left) > m_maxwidth)
  128. {
  129. RECT subrect1, subrect2;
  130. // Find how many rects the two subrects would take
  131. subrect1.left = rect.left;
  132. subrect1.right = rect.left + m_maxwidth;
  133. subrect1.top = rect.top;
  134. subrect1.bottom = rect.bottom;
  135. subrect2.left = rect.left + m_maxwidth;
  136. subrect2.right = rect.right;
  137. subrect2.top = rect.top;
  138. subrect2.bottom = rect.bottom;
  139. return NumCodedRects(subrect1) + NumCodedRects(subrect2);
  140. }
  141. // This rectangle is small enough not to require splitting
  142. return 1;
  143. }
  144. /*
  145.  * corre.c
  146.  *
  147.  * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE).  This
  148.  * code is based on krw's original javatel rfbserver.
  149.  */
  150. /*
  151.  * This version modified for WinVNC by jnw.
  152.  */
  153. static int rreAfterBufLen;
  154. static int subrectEncode8 (CARD8 *source, CARD8 *dest, int w, int h, int max);
  155. static int subrectEncode16 (CARD16 *source, CARD8 *dest, int w, int h, int max);
  156. static int subrectEncode32 (CARD32 *source, CARD8 *dest, int w, int h, int max);
  157. static CARD32 getBgColour (char *data, int size, int bpp);
  158. /*
  159.  * vncEncodeCoRRE::EncodeRect - send an arbitrary size rectangle using CoRRE
  160.  * encoding.
  161.  */
  162. UINT
  163. vncEncodeCoRRE::EncodeRect(BYTE *source, BYTE *dest, const RECT &rect)
  164. {
  165. // Do the encoding
  166. UINT size = InternalEncodeRect(source, dest, rect);
  167. const rectW = rect.right - rect.left;
  168. const rectH = rect.bottom - rect.top;
  169. // Will this rectangle have been split for encoding?
  170. if ((rectW>m_maxwidth) || (rectH>m_maxheight))
  171. {
  172. // Yes : Once we return, the stats will be valid!
  173. m_statsready = TRUE;
  174. // Update the stats
  175. m_encodedbytes += size;
  176. m_rectbytes += sz_rfbFramebufferUpdateRectHeader +
  177. (rectW*rectH*m_remoteformat.bitsPerPixel/8);
  178. }
  179. return size;
  180. }
  181. UINT
  182. vncEncodeCoRRE::InternalEncodeRect(BYTE *source, BYTE *dest, const RECT &rect)
  183. {
  184. int size = 0;
  185.     if ((rect.bottom-rect.top) > m_maxheight)
  186. {
  187. RECT subrect;
  188. // Rectangle is too high - split it into two subrects to send
  189. subrect.left = rect.left;
  190. subrect.right = rect.right;
  191. subrect.top = rect.top;
  192. subrect.bottom = rect.top + m_maxheight;
  193. size += InternalEncodeRect(source, dest + size, subrect);
  194. subrect.left = rect.left;
  195. subrect.right = rect.right;
  196. subrect.top = rect.top + m_maxheight;
  197. subrect.bottom = rect.bottom;
  198. size += InternalEncodeRect(source, dest + size, subrect);
  199. return size;
  200.     }
  201.     if ((rect.right-rect.left) > m_maxwidth)
  202. {
  203. RECT subrect;
  204. // Rectangle is too high - split it into two subrects to send
  205. subrect.left = rect.left;
  206. subrect.right = rect.left + m_maxwidth;
  207. subrect.top = rect.top;
  208. subrect.bottom = rect.bottom;
  209. size += InternalEncodeRect(source, dest + size, subrect);
  210. subrect.left = rect.left + m_maxwidth;
  211. subrect.right = rect.right;
  212. subrect.top = rect.top;
  213. subrect.bottom = rect.bottom;
  214. size += InternalEncodeRect(source, dest + size, subrect);
  215. return size;
  216. }
  217.     return EncodeSmallRect(source, dest, rect);
  218. }
  219. void
  220. vncEncodeCoRRE::SetCoRREMax(BYTE width, BYTE height)
  221. {
  222. m_maxwidth = width;
  223. m_maxheight = height;
  224. }
  225. /*
  226.  * EncodeSmallRect - send a small (guaranteed < 256x256)
  227.  * rectangle using CoRRE encoding.
  228.  */
  229. UINT
  230. vncEncodeCoRRE::EncodeSmallRect(BYTE *source, BYTE *dest, const RECT &rect)
  231. {
  232. int subrects = -1;
  233. const rectW = rect.right - rect.left;
  234. const rectH = rect.bottom - rect.top;
  235. // Create the rectangle header
  236. rfbFramebufferUpdateRectHeader *surh=(rfbFramebufferUpdateRectHeader *)dest;
  237. surh->r.x = (CARD16) rect.left;
  238. surh->r.y = (CARD16) rect.top;
  239. surh->r.w = (CARD16) (rectW);
  240. surh->r.h = (CARD16) (rectH);
  241. surh->r.x = Swap16IfLE(surh->r.x);
  242. surh->r.y = Swap16IfLE(surh->r.y);
  243. surh->r.w = Swap16IfLE(surh->r.w);
  244. surh->r.h = Swap16IfLE(surh->r.h);
  245. surh->encoding = Swap32IfLE(rfbEncodingCoRRE);
  246. // create a space big enough for the CoRRE encoded pixels
  247. if (m_bufflen < (rectW*rectH*m_remoteformat.bitsPerPixel / 8))
  248. {
  249. if (m_buffer != NULL)
  250. {
  251. delete [] m_buffer;
  252. m_buffer = NULL;
  253. }
  254. m_buffer = new BYTE [rectW*rectH*m_remoteformat.bitsPerPixel/8+1];
  255. if (m_buffer == NULL)
  256. return vncEncoder::EncodeRect(source, dest, rect);
  257. m_bufflen = rectW*rectH*m_remoteformat.bitsPerPixel/8;
  258. }
  259. // Translate the data into our new buffer
  260. Translate(source, m_buffer, rect);
  261. // The Buffer object will have ensured that the destination buffer is
  262. // big enough using RequiredBuffSize
  263. // Choose the appropriate encoding routine (for speed...)
  264. switch(m_remoteformat.bitsPerPixel)
  265. {
  266. case 8:
  267. subrects = subrectEncode8(
  268. m_buffer,
  269. dest+sz_rfbFramebufferUpdateRectHeader+sz_rfbRREHeader,
  270. rectW,
  271. rectH,
  272. m_bufflen-sz_rfbFramebufferUpdateRectHeader-sz_rfbRREHeader
  273. );
  274. break;
  275. case 16:
  276. subrects = subrectEncode16(
  277. (CARD16 *)m_buffer,
  278. (CARD8 *)(dest+sz_rfbFramebufferUpdateRectHeader+sz_rfbRREHeader),
  279. rectW,
  280. rectH,
  281. m_bufflen-sz_rfbFramebufferUpdateRectHeader-sz_rfbRREHeader
  282. );
  283. break;
  284. case 32:
  285. subrects = subrectEncode32(
  286. (CARD32 *)m_buffer,
  287. (CARD8 *)(dest+sz_rfbFramebufferUpdateRectHeader+sz_rfbRREHeader),
  288. rectW,
  289. rectH,
  290. m_bufflen-sz_rfbFramebufferUpdateRectHeader-sz_rfbRREHeader
  291. );
  292. break;
  293. }
  294. // If we couldn't encode the rectangles then just send the data raw
  295. if (subrects < 0)
  296. return vncEncoder::EncodeRect(source, dest, rect);
  297. // Send the RREHeader
  298. rfbRREHeader *rreh=(rfbRREHeader *)(dest+sz_rfbFramebufferUpdateRectHeader);
  299. rreh->nSubrects = Swap32IfLE(subrects);
  300. // Calculate the size of the buffer produced
  301. return sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + rreAfterBufLen;
  302. }
  303. /*
  304.  * subrectEncode() encodes the given multicoloured rectangle as a background 
  305.  * colour overwritten by single-coloured rectangles.  It returns the number 
  306.  * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
  307.  * fit in the buffer.  It puts the encoded rectangles in rreAfterBuf.  The
  308.  * single-colour rectangle partition is not optimal, but does find the biggest
  309.  * horizontal or vertical rectangle top-left anchored to each consecutive 
  310.  * coordinate position.
  311.  *
  312.  * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each 
  313.  * <subrect> is [<colour><x><y><w><h>].
  314.  */
  315. #define DEFINE_SUBRECT_ENCODE(bpp)
  316. static int
  317. subrectEncode##bpp(
  318. CARD##bpp *source,
  319.     CARD8 *dest,
  320. int w,
  321. int h,
  322. int maxbytes)
  323. {
  324.     CARD##bpp cl;
  325.     rfbCoRRERectangle subrect;
  326.     int x,y;
  327.     int i,j;
  328.     int hx=0,hy,vx=0,vy;
  329.     int hyflag;
  330.     CARD##bpp *seg;
  331.     CARD##bpp *line;
  332.     int hw,hh,vw,vh;
  333.     int thex,they,thew,theh;
  334.     int numsubs = 0;
  335.     int newLen;
  336.     CARD##bpp bg = (CARD##bpp)getBgColour((char*)source,w*h,bpp);
  337.     *((CARD##bpp*)dest) = bg;
  338.     rreAfterBufLen = (bpp/8);
  339.     for (y=0; y<h; y++) {
  340.       line = source+(y*w);
  341.       for (x=0; x<w; x++) {
  342.         if (line[x] != bg) {
  343.           cl = line[x];
  344.           hy = y-1;
  345.           hyflag = 1;
  346.           for (j=y; j<h; j++) {
  347.             seg = source+(j*w);
  348.             if (seg[x] != cl) {break;}     
  349.             i = x;
  350.             while ((seg[i] == cl) && (i < w)) i += 1;
  351.             i -= 1;
  352.             if (j == y) vx = hx = i;     
  353.             if (i < vx) vx = i;
  354.             if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;}      
  355.           }
  356.           vy = j-1;
  357.           /*  We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy)  
  358.            *  We'll choose the bigger of the two.
  359.            */
  360.           hw = hx-x+1;
  361.           hh = hy-y+1;
  362.           vw = vx-x+1;
  363.           vh = vy-y+1;
  364.           thex = x;
  365.           they = y;
  366.           if ((hw*hh) > (vw*vh)) {
  367.             thew = hw;
  368.             theh = hh;
  369.           } else {
  370.             thew = vw;
  371.             theh = vh;
  372.           }
  373.           subrect.x = thex;
  374.           subrect.y = they;
  375.           subrect.w = thew;
  376.           subrect.h = theh;
  377.   newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle;
  378.           if ((newLen > (w * h * (bpp/8))) || (newLen > maxbytes))
  379.     return -1;
  380.   numsubs += 1;
  381.   *((CARD##bpp*)(dest + rreAfterBufLen)) = cl;
  382.   rreAfterBufLen += (bpp/8);
  383.   memcpy(&dest[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle);
  384.   rreAfterBufLen += sz_rfbCoRRERectangle;     
  385.   /*
  386.            * Now mark the subrect as done.     
  387.            */
  388.           for (j=they; j < (they+theh); j++) {
  389.             for (i=thex; i < (thex+thew); i++) {
  390.               source[j*w+i] = bg;
  391.             }
  392.           }
  393.         }
  394.       }
  395.     }
  396.     return numsubs;
  397. }
  398. DEFINE_SUBRECT_ENCODE(8)
  399. DEFINE_SUBRECT_ENCODE(16)
  400. DEFINE_SUBRECT_ENCODE(32)
  401. /*
  402.  * getBgColour() gets the most prevalent colour in a byte array.
  403.  */
  404. static CARD32
  405. getBgColour(
  406. char *data,
  407. int size,
  408. int bpp)
  409. {
  410.     
  411. #define NUMCLRS 256
  412.   
  413.   static int counts[NUMCLRS];
  414.   int i,j,k;
  415.   int maxcount = 0;
  416.   CARD8 maxclr = 0;
  417.   if (bpp != 8) {
  418.     if (bpp == 16) {
  419.       return ((CARD16 *)data)[0];
  420.     } else if (bpp == 32) {
  421.       return ((CARD32 *)data)[0];
  422.     } else {
  423.       fprintf(stderr,"getBgColour: bpp %d?n",bpp);
  424.       exit(1);
  425.     }
  426.   }
  427.   for (i=0; i<NUMCLRS; i++) {
  428.     counts[i] = 0;
  429.   }
  430.   for (j=0; j<size; j++) {
  431.     k = (int)(((CARD8 *)data)[j]);
  432.     if (k >= NUMCLRS) {
  433.       fprintf(stderr, "%s: unusual colour = %dn", "getBgColour",k);
  434.       exit(1);
  435.     }
  436.     counts[k] += 1;
  437.     if (counts[k] > maxcount) {
  438.       maxcount = counts[k];
  439.       maxclr = ((CARD8 *)data)[j];
  440.     }
  441.   }
  442.   
  443.   return maxclr;
  444. }