Leaked source code of windows server 2003
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.

598 lines
15 KiB

  1. /*--------------------------------------------------------------------------*\
  2. | RLE.C - RLE Delta frame code |
  3. |@@BEGIN_MSINTERNAL |
  4. | |
  5. | History: |
  6. | 01/01/88 toddla Created |
  7. | 10/30/90 davidmay Reorganized, rewritten somewhat. |
  8. | 07/11/91 dannymi Un-hacked |
  9. | 09/15/91 ToddLa Re-hacked |
  10. |@@END_MSINTERNAL |
  11. \*--------------------------------------------------------------------------*/
  12. /**************************************************************************
  13. *
  14. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  15. * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  17. * PURPOSE.
  18. *
  19. * Copyright (c) 1991 - 1995 Microsoft Corporation. All Rights Reserved.
  20. *
  21. **************************************************************************/
  22. #include <windows.h>
  23. #include <windowsx.h>
  24. #include <memory.h> // for _fmemcmp()
  25. #include "msrle.h"
  26. #define RLE_ESCAPE 0
  27. #define RLE_EOL 0
  28. #define RLE_EOF 1
  29. #define RLE_JMP 2
  30. #define RLE_RUN 3
  31. typedef BYTE huge * HPRLE;
  32. typedef BYTE far * LPRLE;
  33. RGBTOL gRgbTol = {0, 0};
  34. //
  35. // RleDeltaFrame
  36. //
  37. // Calculate the RLE bits to go from hdib1 to hdib2
  38. //
  39. // hdibPrev - Previous DIB
  40. // hdib - DIB to RLE
  41. //
  42. // returns
  43. //
  44. // handle to a RLE DIB
  45. //
  46. BOOL FAR PASCAL RleDeltaFrame(
  47. LPBITMAPINFOHEADER lpbiRle, LPBYTE pbRle,
  48. LPBITMAPINFOHEADER lpbiPrev, LPBYTE pbPrev,
  49. LPBITMAPINFOHEADER lpbiDib, LPBYTE pbDib,
  50. int iStart,
  51. int iLen,
  52. long tolTemporal,
  53. long tolSpatial,
  54. int maxRun,
  55. int minJump)
  56. {
  57. LPBITMAPINFOHEADER lpbi;
  58. int biHeight;
  59. UINT cbJump=0;
  60. int dy;
  61. if (!lpbiDib)
  62. return FALSE;
  63. if (maxRun == 0)
  64. maxRun = -1;
  65. if (minJump == 0)
  66. minJump = 4;
  67. //
  68. // Get info on the source and dest dibs
  69. //
  70. lpbi = lpbiDib;
  71. biHeight = (int)lpbi->biHeight;
  72. if (iLen <= 0)
  73. iLen = biHeight;
  74. iLen = min(biHeight-iStart, iLen);
  75. //
  76. // Hey! we only work with 8bpp DIBs if we get otherwise barf.
  77. //
  78. if (lpbi->biBitCount != 8 || lpbi->biCompression != BI_RGB)
  79. return FALSE;
  80. #if 0 // CompressBegin does this..
  81. //
  82. // Set up the table for quick sum of squares calculation (see rle.h)
  83. //
  84. if (!MakeRgbTable(lpbi))
  85. return FALSE;
  86. #endif
  87. //
  88. // lock all the buffers, and start the delta framin'
  89. //
  90. lpbi = lpbiRle;
  91. if (iStart > 0)
  92. pbDib = DibXYN(lpbiDib, pbDib,0,iStart,8);
  93. if (iStart > 0 && lpbiPrev)
  94. pbPrev = DibXYN(lpbiPrev,pbPrev,0,iStart,8);
  95. if (lpbiPrev == NULL)
  96. pbPrev = NULL;
  97. while(iStart > 0)
  98. {
  99. dy = min(iStart,255);
  100. *pbRle++ = RLE_ESCAPE;
  101. *pbRle++ = RLE_JMP;
  102. *pbRle++ = 0;
  103. *pbRle++ = (BYTE)dy;
  104. iStart -= dy;
  105. cbJump += 4;
  106. }
  107. lpbi->biHeight = iLen;
  108. #ifdef _WIN32
  109. DeltaFrameC(
  110. #else
  111. DeltaFrame386(
  112. #endif
  113. lpbi, pbPrev, pbDib, pbRle, maxRun, minJump,
  114. gRgbTol.hpTable, tolTemporal, tolSpatial);
  115. lpbi->biHeight = biHeight;
  116. lpbi->biSizeImage += cbJump; // adjust size to include JUMP!
  117. return TRUE;
  118. }
  119. /* Next is a table that, for each pair of palette entries, helps determine
  120. if two colours are close enough to be merged to a single colour
  121. Let's say the first pixel of a frame is black, and the same pixel in the
  122. next frame is gray. Should you bother painting that gray pixel or let it
  123. stay black because it's close enough? With this table, you have 2 palettes
  124. (one for each of the two frames you are comparing, or possibly two identical
  125. palettes if you are filtering a single DIB) and a table associated with
  126. those palettes. You can index into the table with the colour number of the
  127. pixel in the first frame and the colour number of the pixel in the second
  128. frame. The table value will be a number representing how different those
  129. two colours are.
  130. |Red1 - Red2|^2 + |Green1 - Green2|^2 + |Blue1 - Blue2|^2
  131. is that value (sum of squares of differences). As soon as you start
  132. using this table with a pair of palettes, those hpals are put in this
  133. structure so that you know what pair of palettes the table is built with.
  134. If you change a palette, you need to recompute the table. BUT: you don't
  135. build the table at the beginning, you do it on demand. Initially, the
  136. table is filled with a value of UNCOMPUTED, and as the values are needed,
  137. they are put into the table, so a second call to the CloseEnough routine
  138. with the same colours will exit extremely quickly with no calculations!
  139. Prepare the table for looking up quickly the sum of squares of colours
  140. of two palette entries (possibly in different palettes) */
  141. DWORD NEAR _fastcall RgbCompare(RGBQUAD rgb1, RGBQUAD rgb2)
  142. {
  143. DWORD sum=0;
  144. //
  145. // lets do some magic so the compiler generates "good" code.
  146. //
  147. #define SUMSQ(a,b) \
  148. if (a > b) \
  149. sum += (WORD)(a-b) * (WORD)(a-b); \
  150. else \
  151. sum += (WORD)(b-a) * (WORD)(b-a);
  152. SUMSQ(rgb1.rgbRed, rgb2.rgbRed);
  153. SUMSQ(rgb1.rgbGreen, rgb2.rgbGreen);
  154. SUMSQ(rgb1.rgbBlue, rgb2.rgbBlue);
  155. return sum;
  156. }
  157. BOOL NEAR PASCAL MakeRgbTable(LPBITMAPINFOHEADER lpbi)
  158. {
  159. UINT i, j;
  160. int n=0;
  161. DWORD tol;
  162. if (!lpbi)
  163. return FALSE;
  164. if (lpbi->biClrUsed == 0)
  165. lpbi->biClrUsed = 1 << lpbi->biBitCount;
  166. /* If the palette passed in has a different number of colours than */
  167. /* the one in the table, we obviously need a new table */
  168. if (gRgbTol.hpTable == NULL ||
  169. (int)lpbi->biClrUsed != gRgbTol.ClrUsed ||
  170. _fmemcmp(lpbi+1, gRgbTol.argbq, gRgbTol.ClrUsed * sizeof(RGBQUAD)))
  171. {
  172. if (gRgbTol.hpTable == NULL)
  173. {
  174. gRgbTol.hpTable = (LPVOID)GlobalAllocPtr(GHND|GMEM_SHARE, 256L * 256L * sizeof(DWORD));
  175. if (gRgbTol.hpTable == NULL)
  176. return FALSE;
  177. }
  178. gRgbTol.ClrUsed = (int)lpbi->biClrUsed; // get the actual colours
  179. for (i = 0; i < (UINT)gRgbTol.ClrUsed; i++)
  180. gRgbTol.argbq[i] = ((LPRGBQUAD)(lpbi + 1))[i];
  181. for (i = 0; i < (UINT)gRgbTol.ClrUsed; i++)
  182. {
  183. for (j = 0; j <= i; j++)
  184. {
  185. tol = RgbCompare(gRgbTol.argbq[i], gRgbTol.argbq[j]);
  186. gRgbTol.hpTable[256 * i + j] = tol;
  187. gRgbTol.hpTable[256 * j + i] = tol;
  188. }
  189. }
  190. }
  191. return TRUE;
  192. }
  193. #ifdef _WIN32
  194. // ---- DeltaFrameC --------------------------------------------------------
  195. #define TolLookUp(p, a, b) ( ((LPDWORD)p)[a * 256 + b] )
  196. LPBYTE EncodeFragment(LPBYTE pIn, int len, LPBYTE pOut, LPDWORD pTol, DWORD tolerance, UINT maxrun);
  197. LPBYTE EncodeAbsolute(LPBYTE pbDib, int len, LPBYTE pbRle);
  198. int FindFragmentLength(LPBYTE pIn, LPBYTE pPrev, int len, UINT maxjmp, LPDWORD pTol, DWORD tol, PDWORD prunlen);
  199. // rle format:
  200. // byte 1: 0 - escape
  201. // byte 2: 0 - eol
  202. // byte 2: 1 - eof
  203. // byte 2: 2 - jump x, y (bytes 3, 4)
  204. // byte 2: >2 - absolute run of pixels - byte 2 is length
  205. // byte 1: >0 - repeat solid colour - byte 1 is length
  206. // byte 2 is solid pixel to repeat
  207. // compression - in df.asm for Win16
  208. extern void DeltaFrameC(
  209. LPBITMAPINFOHEADER lpbi,
  210. LPBYTE pbPrev,
  211. LPBYTE pbDib,
  212. LPBYTE pbRle,
  213. UINT MaxRunLength,
  214. UINT MinJumpLength,
  215. LPDWORD TolTable,
  216. DWORD tolTemporal,
  217. DWORD tolSpatial)
  218. {
  219. int WidthBytes = (lpbi->biWidth+3) & (~3);
  220. int x, y;
  221. LPBYTE pbRle_Orig = pbRle;
  222. if ((MaxRunLength == 0) || (MaxRunLength > 255)) {
  223. MaxRunLength = 255;
  224. }
  225. if (pbPrev == NULL) {
  226. // no previous frame, just encode each line spatially
  227. for (y = lpbi->biHeight; y > 0; y--) {
  228. pbRle = EncodeFragment(
  229. pbDib,
  230. lpbi->biWidth,
  231. pbRle,
  232. TolTable,
  233. tolSpatial,
  234. MaxRunLength);
  235. // don't bother to insert an EOL if we are about to insert EOF
  236. if (y > 0) {
  237. * (WORD FAR *)pbRle = RLE_ESCAPE | (RLE_EOL << 8);
  238. pbRle += sizeof(WORD);
  239. }
  240. pbDib += WidthBytes;
  241. }
  242. } else {
  243. int jumpX = 0;
  244. int jumpY = 0;
  245. int frag, runlen;
  246. for (y = 0; y < lpbi->biHeight; y++) {
  247. x = 0;
  248. while (x < lpbi->biWidth) {
  249. // see how much is not the same as the previous frame,
  250. // followed by how much is the same. frag is the length of
  251. // the not-similar fragment; runlen is the length of the
  252. // similar fragment.
  253. frag = FindFragmentLength(
  254. pbDib,
  255. pbPrev,
  256. lpbi->biWidth - x,
  257. MinJumpLength,
  258. TolTable,
  259. tolTemporal,
  260. &runlen
  261. );
  262. if (frag == 0) {
  263. // no fragment, just a jump over the similar pixels.
  264. //add up jumps until we need to output them
  265. jumpX += runlen;
  266. x += runlen;
  267. pbPrev += runlen;
  268. pbDib += runlen;
  269. } else {
  270. // output any saved jumps
  271. if (jumpX < 0) {
  272. // don't jump backwards - eol and jump forwards
  273. *(WORD FAR *)pbRle = RLE_ESCAPE | (RLE_EOL << 8);
  274. pbRle += sizeof(WORD);
  275. // jump is now across to current position,
  276. // and one fewer lines.
  277. jumpX = x;
  278. jumpY--;
  279. }
  280. while (jumpX + jumpY) {
  281. int delta;
  282. * (WORD FAR *)pbRle = RLE_ESCAPE | (RLE_JMP << 8);
  283. pbRle += sizeof(WORD);
  284. // max jump size is 255
  285. delta = min(255, jumpX);
  286. *pbRle++ = (BYTE) delta;
  287. jumpX -= delta;
  288. delta = min(255, jumpY);
  289. *pbRle++ = (BYTE) delta;
  290. jumpY -= delta;
  291. }
  292. // output the different fragment as a combination
  293. // of solid runs and absolute pixels
  294. pbRle = EncodeFragment(
  295. pbDib,
  296. frag,
  297. pbRle,
  298. TolTable,
  299. tolSpatial,
  300. MaxRunLength);
  301. x += frag;
  302. pbDib += frag;
  303. pbPrev += frag;
  304. }
  305. }
  306. // end-of-line
  307. jumpY++;
  308. // advance past DWORD-rounding bytes
  309. pbPrev += (WidthBytes - lpbi->biWidth);
  310. pbDib += (WidthBytes - lpbi->biWidth);
  311. //adjust jumpX
  312. jumpX -= x;
  313. }
  314. }
  315. // end-of-frame
  316. * (WORD FAR *)pbRle = RLE_ESCAPE | (RLE_EOF << 8);
  317. pbRle += sizeof(WORD);
  318. // update lpbi to correct size and format
  319. lpbi->biSizeImage = (DWORD) (pbRle - pbRle_Orig);
  320. lpbi->biCompression = BI_RLE8;
  321. }
  322. //
  323. // encode a sequence of pixels as a mixture of solid runs and absolute
  324. // pixels. write the rle data to pbRle and return pointer to the next
  325. // available rle buffer.
  326. LPBYTE
  327. EncodeFragment(
  328. LPBYTE pbDib,
  329. int width,
  330. LPBYTE pbRle,
  331. LPDWORD TolTable,
  332. DWORD tolerance,
  333. UINT MaxRunLength
  334. )
  335. {
  336. int maxrun, run;
  337. BYTE px;
  338. while (width > 0) {
  339. maxrun = min(255, width);
  340. MaxRunLength = min((int)MaxRunLength, maxrun);
  341. px = *pbDib;
  342. for (run = 0; run < maxrun; run++, pbDib++) {
  343. // the same or similar ? - use tolerance table to compare pixel
  344. // rgb values
  345. // We're allowed a run of 255 if they're exact, but only a run of
  346. // MaxRunLength if they're not exact, only close
  347. if (px == *pbDib)
  348. continue;
  349. if (TolLookUp(TolTable,px,*pbDib) <= tolerance &&
  350. run < (int)MaxRunLength)
  351. continue;
  352. // not close enough - end run
  353. break;
  354. }
  355. // we have found the end of a run of identical pixels
  356. // if the run is one pixel, then we switch into absolute mode.
  357. // however, we cannot encode absolute runs of less than RLE_RUN
  358. // pixels (the runlength code is an escape code and must not coincide
  359. // with RLE_JMP, RLE_EOL and RLE_EOF.
  360. if ((run > 1) || (width < RLE_RUN)) {
  361. // write out run length and colour
  362. * (WORD FAR *)pbRle = run | (px << 8);
  363. pbRle += sizeof(WORD);
  364. width -= run;
  365. } else {
  366. // we have a 'run' of one pixel - back up to point at this.
  367. pbDib--;
  368. // write out an absolute run. now we are in abs mode, we need
  369. // a solid run of at least 4 pixels for it to be worth leaving
  370. // and re-entering abs mode
  371. for (run = 0; run < maxrun; run++) {
  372. // at the end of the fragment ?
  373. if ((maxrun - run) < 4) {
  374. // yes - so no point in looking for a solid run -
  375. // just dump all the remainder as an absolute block
  376. pbRle = EncodeAbsolute(pbDib, maxrun, pbRle);
  377. pbDib += maxrun;
  378. width -= maxrun;
  379. break;
  380. }
  381. px = pbDib[run];
  382. if ( (TolLookUp(TolTable,px,pbDib[run + 1]) <= tolerance) &&
  383. (TolLookUp(TolTable,px,pbDib[run + 2]) <= tolerance) &&
  384. (TolLookUp(TolTable,px,pbDib[run + 3]) <= tolerance)) {
  385. // we have run bytes to encode followed by four
  386. // similar pixels
  387. pbRle = EncodeAbsolute(pbDib, run, pbRle);
  388. pbDib += run;
  389. width -= run;
  390. break;
  391. }
  392. }
  393. }
  394. }
  395. return pbRle;
  396. }
  397. LPBYTE
  398. EncodeAbsolute(LPBYTE pbDib, int runlen, LPBYTE pbRle)
  399. {
  400. if (runlen < RLE_RUN) {
  401. // cannot encode absolute runs of less than RLE_RUN as it
  402. // conflicts with other rle escapes - so encode each pixel
  403. // as a run of 1 of that pixel
  404. int i;
  405. for (i = 0; i < runlen; i++) {
  406. * (WORD FAR *) pbRle = 1 | ((*pbDib++) << 8);
  407. pbRle += sizeof(WORD);
  408. }
  409. return pbRle;
  410. }
  411. // absolute run of > RLE_RUN
  412. * (WORD FAR *)pbRle = RLE_ESCAPE | (runlen << 8);
  413. pbRle += sizeof(WORD);
  414. while (runlen >= 2) {
  415. * (WORD FAR *) pbRle = * (WORD UNALIGNED FAR *)pbDib;
  416. pbRle += sizeof(WORD);
  417. pbDib += sizeof(WORD);
  418. runlen -= 2;
  419. }
  420. // remember to keep word alignment
  421. if (runlen) {
  422. *pbRle++ = *pbDib++;
  423. *pbRle++ = 0;
  424. }
  425. return pbRle;
  426. }
  427. // count how many pixels are not the same as the previous frame, and how
  428. // long is the run of similar pixels after it. We must find at least minjump
  429. // similar pixels before we stop.
  430. int
  431. FindFragmentLength(
  432. LPBYTE pIn,
  433. LPBYTE pPrev,
  434. int len,
  435. UINT minjump,
  436. LPDWORD pTol,
  437. DWORD tol,
  438. PDWORD prunlen
  439. )
  440. {
  441. int x;
  442. int run = 0;
  443. for (x = 0; x < len; x++) {
  444. if ((*pIn == *pPrev) || (TolLookUp(pTol, *pIn, *pPrev) <= tol)) {
  445. run++;
  446. } else {
  447. // have we accumulated a run long enough to be worth
  448. // returning ?
  449. if (run >= (int)minjump) {
  450. *prunlen = run;
  451. return x - run;
  452. } else {
  453. run = 0;
  454. }
  455. }
  456. pIn++;
  457. pPrev++;
  458. }
  459. // end of line - did we find a run ?
  460. if (run < (int) minjump) {
  461. *prunlen = 0;
  462. return len;
  463. } else {
  464. *prunlen = run;
  465. return x - run;
  466. }
  467. }
  468. #endif