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.

450 lines
15 KiB

  1. /*--------------------------------------------------------------------------*\
  2. | RLEC.C - MS-CRUNCH |
  3. |//@@BEGIN_MSINTERNAL |
  4. | History: |
  5. | 01/01/88 toddla Created |
  6. | 10/30/90 davidmay Reorganized, rewritten somewhat. |
  7. | 07/11/91 dannymi Un-hacked |
  8. | 09/15/91 ToddLa Re-hacked |
  9. |//@@END_MSINTERNAL |
  10. | |
  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 "msrle.h"
  25. #ifdef _WIN32
  26. #define _huge
  27. #endif
  28. //
  29. // make a copy of a DIB that is not packed.
  30. //
  31. __inline static LPVOID CopyDib(LPBITMAPINFOHEADER lpbi, LPVOID lpS)
  32. {
  33. LPVOID lpD;
  34. BYTE _huge *s;
  35. BYTE _huge *d;
  36. long lImageHeader, lImageData, lImageSize;
  37. if (!lpbi || !lpS)
  38. return NULL;
  39. FixBitmapInfo(lpbi);
  40. lpD = GlobalAllocPtr(GHND, lImageSize = DibSize(lpbi));
  41. if (lpD)
  42. {
  43. // Copy the bitmapinfoheader and colours
  44. s = (LPVOID)lpbi;
  45. d = (LPVOID)lpD;
  46. lImageData = DibSizeImageX(lpbi); // grab the number of data bytes
  47. lImageHeader = lImageSize - lImageData; // save header+colortable size
  48. #if 0
  49. while (lImageHeader-- > 0)
  50. *d++ = *s++;
  51. #else
  52. memcpy(d, s, lImageHeader); // copy the header+colortable to new Dib
  53. d += lImageHeader; // step pointer to Data piece
  54. #endif
  55. // Copy the image
  56. s = (LPVOID)lpS;
  57. #if 0
  58. while (lImageData-- > 0)
  59. *d++ = *s++;
  60. #else
  61. memcpy(d, s, lImageData); // copy data bytes to new Dib
  62. #endif
  63. }
  64. return lpD;
  65. }
  66. //
  67. // CrunchDib() - make a DIB fit into a specific size.
  68. //
  69. BOOL FAR PASCAL CrunchDib(PRLEINST pri,
  70. LPBITMAPINFOHEADER lpbiRle, LPBYTE lpRle,
  71. LPBITMAPINFOHEADER lpbiFrom,LPBYTE lpFrom,
  72. LPBITMAPINFOHEADER lpbiTo, LPBYTE lpTo)
  73. {
  74. long dwSize = 0L, dwLastSize = 0L;
  75. long lCurParm = 0L;
  76. long lTempMax; // highest value before halving
  77. long tolMax;
  78. long lTempMin = 0L;
  79. BOOL fInterlaceNow = FALSE; // time to try interlacing?
  80. long lBumpUp = 2048L; // bump the parameter up by this amount
  81. int iStart, iLen;
  82. BOOL fSpatialAdaptive;
  83. BOOL fTemporalAdaptive;
  84. long tolTemporal;
  85. long tolSpatial;
  86. int minJump;
  87. int maxRun;
  88. int FIRSTTRY = 1024; // use this parameter value as a first guess
  89. int CWND = 250; // Give up searching for the perfect parameter
  90. // when the window is smaller than this
  91. lTempMax = pri->RleState.tolMax; // highest value before halving
  92. // No Previous DIB -- we want a full frame, so no interlacing allowed
  93. // (infinite tolerance allowed before frame halving)
  94. if (lpbiFrom == NULL)
  95. lTempMax = MAXTOL;
  96. // In case we were passed a bogus value -- don't allow frame halving at all
  97. if (lTempMax < 0)
  98. lTempMax = MAXTOL;
  99. tolMax = lTempMax;
  100. tolTemporal = pri->RleState.tolTemporal;
  101. tolSpatial = pri->RleState.tolSpatial;
  102. fSpatialAdaptive = (pri->RleState.tolSpatial == ADAPTIVE);
  103. fTemporalAdaptive = (pri->RleState.tolTemporal == ADAPTIVE);
  104. maxRun = pri->RleState.iMaxRunLen;
  105. minJump = 4;
  106. // No Previous DIB - we should do a full frame, so no interlacing and
  107. // allow spatial compression to be adaptive to do the compression since
  108. // we can't do temporal compression.
  109. if (lpbiFrom == NULL) {
  110. pri->iStart = 0;
  111. fSpatialAdaptive = TRUE;
  112. }
  113. iStart = pri->iStart;
  114. iLen = -1;
  115. if (!lpbiTo) {
  116. DPF(("Crunch Error - Invalid DIB or HPAL"));
  117. goto return_failure;
  118. }
  119. //
  120. // In the previous frame, we did the bottom only,
  121. // so now we need to do the top
  122. //
  123. // If lpbiFrom is NULL, we don't want to do this--we want to make
  124. // a full frame, even though the last one was a first half.
  125. //
  126. if (iStart > 0 && pri->lpbiPrev) {
  127. fInterlaceNow = TRUE; // Only do half of the frame.
  128. lpbiTo = pri->lpbiPrev;
  129. lpTo = DibPtr(lpbiTo); // This will be a packed DIB
  130. lTempMin = 0L;
  131. lTempMax = MAXTOL; // no limit to how fuzzy you can get before
  132. tolMax = MAXTOL; // interlacing since we already are doing it
  133. DPF(("SECOND HALF OF INTERLACE"));
  134. //
  135. // copy over the color table from the last DIB to the empty RLE
  136. // to delay any palette change....
  137. //
  138. hmemcpy(lpbiRle,lpbiTo,lpbiTo->biSize+(int)lpbiTo->biClrUsed*sizeof(RGBQUAD));
  139. } else {
  140. iStart = 0;
  141. }
  142. // OK. Here's where we work on getting the frame down in size!
  143. // First, try an EXACT RLE with no fuzziness. If that works, no need to degrade
  144. // the image quality at all!
  145. if (!RleDeltaFrame(lpbiRle,lpRle,lpbiFrom,lpFrom,lpbiTo,lpTo,iStart,iLen,0L,0L,0,0)) {
  146. DPF(("Crunch Error - Lossless RleDeltaFrame failed"));
  147. goto return_failure;
  148. }
  149. dwSize = lpbiRle->biSizeImage;
  150. DPF(("tolTemporal = 0, tolSpatial = 0, Size = %ld", dwSize));
  151. // Exact RLE worked!
  152. if (dwSize < pri->RleState.lMaxFrameSize) {
  153. if (fInterlaceNow)
  154. pri->iStart = 0; // we did 2nd half, so next time do full dib
  155. goto return_success;
  156. }
  157. if (pri->lLastParm) // this value worked last time, so try it now!
  158. // unless of course, it's too big.
  159. lCurParm = min(pri->lLastParm, lTempMax);
  160. else if (lTempMax == MAXTOL) // no limit to what parameter can be
  161. lCurParm = FIRSTTRY; // so make the 1st value reasonable
  162. else
  163. lCurParm = lTempMax; // There is a limit on how big the parm can be.
  164. // Start as big as possible, so that if that
  165. // doesn't fit, we can give up right away
  166. goto skip_if; // skip the big IF
  167. noskip_if:
  168. // This first condition tests to see if the current attempt yielded a frame
  169. // that was still too big, and we have just tried the largest parameter
  170. // possible. It looks like we will never get the frame small enough!
  171. // Our only hope is to interlace the frames, if we're allowed to.
  172. if (dwSize > pri->RleState.lMaxFrameSize && lCurParm > tolMax-1)
  173. {
  174. // It looks like either we're a keyframe and can't interlace, or
  175. // we've been trying interlacing and we're STILL not small enough.
  176. // There is nothing else we can do. Give up.
  177. // NOTE: this shouldn't happen if the parameter is allowed to grow
  178. // arbitrarily!
  179. if (fInterlaceNow || !lpbiFrom) {
  180. if (!lpbiFrom)
  181. goto return_success;
  182. if (iStart > 0) { // This was 2nd frame of a pair (top)
  183. pri->iStart = 0;
  184. lCurParm = 0L; // don't remember this value because
  185. // this frame halving value won't help
  186. // us next frame when we aren't using
  187. // frame halving any more.
  188. } else { // This was the first frame of a pair (bottom).
  189. // Remember to do the 2nd frame next time
  190. pri->iStart += iLen;
  191. }
  192. goto return_success;
  193. // We are allowed to interlace, so we can prepare to.
  194. // Gee, I hope this isn't the last frame in the movie
  195. // (there will be no frame to do the 2nd half of!! )
  196. } else {
  197. fInterlaceNow = TRUE;
  198. DPF(("FIRST HALF OF INTERLACE"));
  199. iStart = 0;
  200. iLen = (int)lpbiTo->biHeight/2;
  201. lCurParm = 0L; // start with no fuzziness
  202. lTempMin = 0L;
  203. lTempMax = MAXTOL; // no limit to fuzziness
  204. tolMax = MAXTOL;
  205. }
  206. // This condition tests to see if the size is still too big after this attempt,
  207. // and the window of parameter values that we can try is still large enough
  208. // to try some more values. If so, we shrink the window a bit (the new lowest
  209. // value worth trying is the current value, and we bump the current value up by
  210. // half of the window size, but not TOO much. You see, if our parameter is too
  211. // high, then we binary search smaller values between 0 and this value. But if
  212. // the parameter is too small, how do we binary search through here and
  213. // infinity? (actually 195,075) So, we just increase the parameter by 2048.
  214. // Next time we need to increase it, we will increase by 4096, 8192, etc.
  215. // This way, we will quickly get to the limit of 195,075. Perhaps the frame
  216. // cannot possibly be crunched as small as it needs to be. The program
  217. // shouldn't take forever to realize this and get to 195,075. But we shouldn't
  218. // binary search between 0 and 195,075 because it will waste time getting down
  219. // to the small values like 1000 that most movies will need. This is the
  220. // best compromise. Hope that wasn't too long winded! :-)
  221. } else if ((dwSize > pri->RleState.lMaxFrameSize) &&
  222. ((lTempMax - lTempMin) > CWND))
  223. {
  224. lTempMin = lCurParm;
  225. if (lTempMax == MAXTOL){ // upper limit is still unbounded so
  226. // leap way higher to our next try
  227. if (MAXTOL - lCurParm < lBumpUp)
  228. lCurParm = MAXTOL;
  229. else
  230. lCurParm += lBumpUp;
  231. lBumpUp *= 2;
  232. } else
  233. lCurParm += (lTempMax - lCurParm) >> 1;
  234. // For this condition, we are still too big, but the window is getting so small
  235. // that we fear we will never find a value that works! Let's say we know that
  236. // 200 gives a frame that is too big, and 210 gives a frame that is too small.
  237. // Should we bother searching any more? NO!!! That would waste time. Let's
  238. // just give up and take the 210 value (too small is better than too large)
  239. // and continue. The next time through this loop, it will give up when it sees
  240. // that the window is too small and the current attempt produced a frame that
  241. // was small enough, even though it was a little smaller than we wanted.
  242. } else if (dwSize > pri->RleState.lMaxFrameSize) {
  243. lCurParm = lTempMax;
  244. // This condtion says that the size is too small to accept, and the window
  245. // of values to try is still large enough to warrant trying again. So, we
  246. // close the window a bit by setting the new highest value worth trying to
  247. // the current value, and dropping the current value by half.
  248. } else if ((dwSize < pri->RleState.lMinFrameSize) && ((lTempMax - lTempMin) > CWND)) {
  249. lTempMax = lCurParm;
  250. lCurParm -= (lCurParm - lTempMin) >> 1;
  251. // Here is the catch all last else of the if. If it gets here, then the frame
  252. // is either just the perfect size and we can quit, or it's too small, but
  253. // we've determined that we can't be bothered to search any more, so we're going
  254. // to quit anyway.
  255. } else {
  256. if (fInterlaceNow) { // we were interlacing
  257. if (iStart > 0) { // this was 2nd half of a pair (top)
  258. pri->iStart = 0;
  259. lCurParm = 0L; // don't remember this value because
  260. // this frame halving value won't help
  261. // us next frame when we aren't using
  262. // frame halving any more.
  263. } else { // This was 1st half of a pair (bottom)
  264. pri->iStart = iLen; // next time, do 2nd half
  265. }
  266. }
  267. goto return_success;
  268. }
  269. skip_if:
  270. // We know that the previous attempt to RLE didn't work, so try again with
  271. // the new values.
  272. Yield();
  273. // Set the TEMPORAL and SPATIAL values.
  274. // NOTE: if we are only working with a single DIB, (no lpbiFrom),
  275. // TEMPORAL compression won't work, so we enabled SPATIAL adaptive.
  276. // The TEMPORAL value will be ignored in that case.
  277. if (fSpatialAdaptive && fTemporalAdaptive) {
  278. tolSpatial = lCurParm>>3; // lCurParm/8;
  279. tolTemporal = lCurParm;
  280. } else if (fTemporalAdaptive)
  281. tolTemporal = lCurParm;
  282. else if (fSpatialAdaptive)
  283. tolSpatial = lCurParm;
  284. if (!RleDeltaFrame(lpbiRle,lpRle,lpbiFrom,lpFrom,lpbiTo,lpTo,iStart,iLen,tolTemporal,tolSpatial,maxRun,minJump)) {
  285. DPF(("Crunch Error - Rle Delta Frame failed"));
  286. goto return_failure;
  287. }
  288. // Remember the size of the last attempt, and take size of this attempt
  289. dwLastSize = dwSize;
  290. dwSize = lpbiRle->biSizeImage;
  291. DPF(("tolTemporal=%ld, tolSpatial=%ld, Size=%ld", tolTemporal, tolSpatial, dwSize));
  292. goto noskip_if; // Go back and see how we did!
  293. return_failure:
  294. pri->lLastParm = 0L;
  295. return FALSE;
  296. return_success:
  297. // if (lCurParm) // putting this line in won't let frame halving
  298. // threshold value get tried first. But it will
  299. // avoid trashing old values that worked. If you
  300. // understand this comment, you probably didn't need
  301. // to read it!!
  302. pri->lLastParm = lCurParm;
  303. if (pri->lpbiPrev)
  304. {
  305. GlobalFreePtr(pri->lpbiPrev);
  306. pri->lpbiPrev = NULL;
  307. }
  308. if (lpbiRle)
  309. {
  310. if (pri->iStart)
  311. {
  312. lpbiRle->biCompression = BI_DIBX; // 1st part of DIB. Not
  313. pri->lpbiPrev = CopyDib(lpbiTo, lpTo);// complete until next
  314. } // BI_RLE8 is seen.
  315. else
  316. {
  317. lpbiRle->biCompression = BI_RLE8;
  318. }
  319. }
  320. return TRUE;
  321. }
  322. BOOL FAR PASCAL SplitDib(PRLEINST pri,
  323. LPBITMAPINFOHEADER lpbiRle, LPBYTE pbRle,
  324. LPBITMAPINFOHEADER lpbiPrev,LPBYTE pbPrev,
  325. LPBITMAPINFOHEADER lpbiDib, LPBYTE pbDib)
  326. {
  327. int iStart, iLen, iMin, iMax;
  328. DWORD dwSize;
  329. BOOL f;
  330. iStart = iMin = 0;
  331. iLen = iMax = (int)lpbiDib->biHeight - iStart;
  332. for(;;)
  333. {
  334. f = RleDeltaFrame(
  335. lpbiRle, pbRle,
  336. lpbiPrev,pbPrev,
  337. lpbiDib, pbDib,
  338. iStart,iLen,
  339. pri->RleState.tolTemporal,
  340. pri->RleState.tolSpatial,
  341. pri->RleState.iMaxRunLen,4);
  342. if (!f)
  343. return FALSE;
  344. dwSize = lpbiRle->biSizeImage;
  345. DPF(("iStart=%d, iLen=%d, Size=%ld, Max=%ld", iStart, iLen, dwSize, pri->RleState.lMaxFrameSize));
  346. if (dwSize < (DWORD)pri->RleState.lMaxFrameSize)
  347. {
  348. iMin = iLen;
  349. if (iMax-iMin <= 1)
  350. {
  351. pri->iStart += iLen;
  352. if (pri->iStart >= (int)lpbiDib->biHeight)
  353. pri->iStart = 0;
  354. return TRUE;
  355. }
  356. }
  357. else
  358. iMax = iLen - 1;
  359. if (iStart != pri->iStart)
  360. {
  361. iStart = pri->iStart;
  362. iLen = iMax = (int)lpbiDib->biHeight - iStart;
  363. }
  364. else
  365. {
  366. iLen = (iMin + iMax) / 2;
  367. }
  368. }
  369. }