Windows NT 4.0 source code leak
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.

621 lines
15 KiB

4 years ago
  1. /*
  2. * Microsoft YUV Codec -yuv411 -> rgb conversion functions
  3. *
  4. * Copyright (c) Microsoft Corporation 1993
  5. * All Rights Reserved
  6. *
  7. */
  8. #include <windows.h>
  9. #include <windowsx.h>
  10. #include <mmsystem.h>
  11. #include <compddk.h>
  12. #include "msyuv.h"
  13. /*
  14. * This module provides translation from YUV into RGB. It translates
  15. * from 8-bit YUV 4:2:2 (as provided by the Spigot video capture driver)
  16. * or 7-bit YUV 4:1:1 (as provided by the Bravado driver) into 16-bit RGB555
  17. * or RGB565. All versions use a look-up table built using YUVToRGB555
  18. * or YUVToRGB565
  19. */
  20. #define RANGE(x, lo, hi) max(lo, min(hi, x))
  21. /*
  22. * Convert a YUV colour into a 15-bit RGB colour.
  23. *
  24. * The input Y is in the range 16..235; the input U and V components
  25. * are in the range -128..+127. The conversion equations for this are
  26. * (according to CCIR 601):
  27. *
  28. * R = Y + 1.371 V
  29. * G = Y - 0.698 V - 0.336 U
  30. * B = Y + 1.732 U
  31. *
  32. * To avoid floating point, we scale all values by 1024.
  33. *
  34. * The resulting RGB values are in the range 16..235: we truncate these to
  35. * 5 bits each. and return a WORD containing 5-bits each for R, G and B
  36. * with bit 15 set to 0.
  37. */
  38. WORD
  39. YUVToRGB555(int y, int u, int v)
  40. {
  41. int ScaledY = RANGE(y, 16, 235) * 1024;
  42. int red, green, blue;
  43. red = RANGE((ScaledY + (1404 * v)) / 1024, 0, 255);
  44. green = RANGE( (ScaledY - (715 * v) - (344 * u)) / 1024, 0, 255);
  45. blue = RANGE( (ScaledY + (1774 * u)) / 1024, 0, 255);
  46. return (WORD) (((red & 0xf8) << 7) | ((green & 0xf8) << 2) | ((blue & 0xf8) >>3) );
  47. }
  48. // same as above but converts to RGB565 instead
  49. WORD
  50. YUVToRGB565(int y, int u, int v)
  51. {
  52. int ScaledY = RANGE(y, 16, 235) * 1024;
  53. int red, green, blue;
  54. red = RANGE((ScaledY + (1404 * v)) / 1024, 0, 255);
  55. green = RANGE( (ScaledY - (715 * v) - (344 * u)) / 1024, 0, 255);
  56. blue = RANGE( (ScaledY + (1774 * u)) / 1024, 0, 255);
  57. return (WORD) (((red & 0xf8) << 8) | ((green & 0xfc) << 3) | ((blue & 0xf8) >>3) );
  58. }
  59. /* --- YUV 4:1:1 support ------------------------------------------ */
  60. /*
  61. * the input data is in YUV411 format. There is one 7 bit Luma sample
  62. * per pixel, and 1 each 7-bit U and V sample averaged over 4 pixels,
  63. * in the following layout:
  64. *
  65. * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  66. * Word 0 u6 u5 v6 v5 y6 y5 y4 y3 y2 y1 y0
  67. *
  68. * Word 1 u4 u3 v4 v3 y6 y5 y4 y3 y2 y1 y0
  69. *
  70. * Word 2 u2 u1 v2 v1 y6 y5 y4 y3 y2 y1 y0
  71. *
  72. * Word 3 u0 v0 y6 y5 y4 y3 y2 y1 y0
  73. *
  74. * The 7-bit y values are unsigned (0..127), whereas the 7-bit
  75. * u and V values are signed (-64..+63).
  76. *
  77. *
  78. * For RGB: we truncate the YUV into a 15-bit format and use a prepared
  79. * lookup table to convert the 15-bit YUV into a 15- or 16-bit RGB value.
  80. *
  81. * The (64 kbyte) rgb555 lookup table is built by BuildYUVToRGB555.
  82. *
  83. */
  84. /*
  85. * the YUV xlate tables use 5-bits per component with y in the ms bits, and
  86. * v in the ls bits. To convert from the above layout, look up the nibbles
  87. * containing the chroma bits in these tables and or together the result to
  88. * get a word with a 5-bit V component in bits 0..4, and a 5-bit
  89. * U component in bits 5..9. Note you only need three lookups since
  90. * we discard chroma bits 0 and 1.
  91. */
  92. WORD ChromaBits65[] = {
  93. 0x000, 0x008, 0x010, 0x018,
  94. 0x100, 0x108, 0x110, 0x118,
  95. 0x200, 0x208, 0x210, 0x218,
  96. 0x300, 0x308, 0x310, 0x318
  97. };
  98. WORD ChromaBits43[] = {
  99. 0x000, 0x002, 0x004, 0x006,
  100. 0x040, 0x042, 0x044, 0x046,
  101. 0x080, 0x082, 0x084, 0x086,
  102. 0x0c0, 0x0c2, 0x0c4, 0x0c6
  103. };
  104. WORD ChromaBits2[] = {
  105. 0x000, 0x000, 0x001, 0x001,
  106. 0x000, 0x000, 0x001, 0x001,
  107. 0x020, 0x020, 0x021, 0x021,
  108. 0x020, 0x020, 0x021, 0x021
  109. };
  110. /*
  111. * build yuv411->RGB555 xlate table
  112. */
  113. LPVOID BuildYUVToRGB555(PINSTINFO pinst)
  114. {
  115. LPVOID pXlate;
  116. LPWORD pRGB555;
  117. WORD w;
  118. if (pinst->pXlate != NULL) {
  119. return(pinst->pXlate);
  120. }
  121. /*
  122. * allocate a table big enough for 32k 2-byte entries
  123. */
  124. pXlate = GlobalLock(GlobalAlloc(GPTR, 2 * 32 * 1024));
  125. pRGB555 = (LPWORD)pXlate;
  126. /*
  127. * build a 15-bit yuv lookup table by stepping through each entry,
  128. * converting the yuv index to rgb and storing at that index. The index
  129. * to this table is a 15-bit value with the y component in bits 14..10,
  130. * u in bits 9..5 and v in bits 4..0. Note that the y component is unsigned,
  131. * whereas the u and v components are signed.
  132. */
  133. for (w = 0; w < 32*1024; w++) {
  134. /*
  135. * the YUVtoRGB55 conversion function takes values 0..255 for y,
  136. * and -128..+127 for u and v. Pick out the relevant bits of the
  137. * index for this cell, and shift to get values in this range.
  138. * Remember the cast to ensure sign-extension of these (8-bit) values -
  139. * and don't assume that chars are signed (they're not on MIPS).
  140. */
  141. *pRGB555++ = YUVToRGB555(
  142. (w & 0x7c00) >> 7,
  143. (signed char) ((w & 0x3e0) >> 2),
  144. (signed char) ((w & 0x1f) << 3)
  145. );
  146. }
  147. return(pXlate);
  148. }
  149. /*
  150. * build yuv411->RGB565 xlate table
  151. */
  152. LPVOID BuildYUVToRGB565(PINSTINFO pinst)
  153. {
  154. LPVOID pXlate;
  155. LPWORD pRGB;
  156. WORD w;
  157. if (pinst->pXlate != NULL) {
  158. return(pinst->pXlate);
  159. }
  160. /*
  161. * allocate a table big enough for 32k 2-byte entries
  162. */
  163. pXlate = GlobalLock(GlobalAlloc(GPTR, 2 * 32 * 1024));
  164. pRGB = (LPWORD)pXlate;
  165. /*
  166. * build a 15-bit yuv lookup table by stepping through each entry,
  167. * converting the yuv index to rgb and storing at that index. The index
  168. * to this table is a 15-bit value with the y component in bits 14..10,
  169. * u in bits 9..5 and v in bits 4..0. Note that the y component is unsigned,
  170. * whereas the u and v components are signed.
  171. */
  172. for (w = 0; w < 32*1024; w++) {
  173. /*
  174. * the YUVtoRGB conversion function takes values 0..255 for y,
  175. * and -128..+127 for u and v. Pick out the relevant bits of the
  176. * index for this cell, and shift to get values in this range.
  177. * Remember the cast to ensure sign-extension of these (8-bit) values -
  178. * and don't assume that chars are signed (they're not on MIPS).
  179. */
  180. *pRGB++ = YUVToRGB565(
  181. (w & 0x7c00) >> 7,
  182. (signed char) ((w & 0x3e0) >> 2),
  183. (signed char) ((w & 0x1f) << 3)
  184. );
  185. }
  186. return(pXlate);
  187. }
  188. /*
  189. * translate one frame from yuv411 to 15/16 bit rgb.
  190. *
  191. * The YUV data is spread over 4 16-bit pixels in the format described
  192. * above. Pick out 4 pixels at a time, truncate them to 15-bit yuv,
  193. * lookup to translate to 15 or 16-bit rgb (depending on the lookup table
  194. * and write out.
  195. *
  196. * Flip vertically into correct dib format during conversion.
  197. */
  198. VOID
  199. YUV411ToRGB(
  200. PINSTINFO pinst,
  201. LPBITMAPINFOHEADER lpbiInput,
  202. LPVOID lpInput,
  203. LPBITMAPINFOHEADER lpbiOutput,
  204. LPVOID lpOutput
  205. )
  206. {
  207. int RowInc;
  208. int i, j;
  209. DWORD Luma01, Luma23;
  210. DWORD Chroma;
  211. int Height, Width;
  212. int WidthBytes;
  213. PWORD pXlate;
  214. PWORD pDst;
  215. PDWORD pSrc;
  216. Height = lpbiInput->biHeight;
  217. Width = lpbiInput->biWidth;
  218. WidthBytes = Width*2; // size of (input and output) line
  219. pXlate = pinst->pXlate;
  220. /*
  221. * adjust the source to point to the start of the last line,
  222. * and work upwards (to flip vertically into DIB format)
  223. */
  224. pSrc = (PDWORD) ( (PUCHAR) lpInput + ((Height - 1) * WidthBytes));
  225. pDst = (PWORD) lpOutput;
  226. /*
  227. * calculate the amount to adjust source by at the end of one line
  228. * of copying. At this point we are at the end of line N. We need
  229. * to move to the start of line N-1.
  230. */
  231. RowInc = (WidthBytes * 2) / sizeof(DWORD);
  232. /* loop copying each scanline */
  233. for (i = 0; i < Height; i++) {
  234. /* loop copying four pixels at a time */
  235. for (j = 0; j < Width; j += 4) {
  236. /*
  237. * get four pixels and convert to 15-bpp YUV
  238. */
  239. /* get luma for first 2 pixels + higher chroma bits */
  240. Luma01 = *pSrc++;
  241. /* pick out u,v components using lookup table.
  242. * u and v will be the bottom 10 bits of each pixel, so
  243. * convert to this layout
  244. */
  245. Chroma = ChromaBits65[(Luma01 >> 12) & 0xf] |
  246. ChromaBits43[ (Luma01 >> 28) & 0xf ];
  247. /* next two pixels + lower chroma bits */
  248. Luma23 = *pSrc++;
  249. /* pickup u and v bits 2 - ignore bits 1, 0 since
  250. * we only use 5-bits per component for conversion
  251. */
  252. Chroma |= ChromaBits2[ ( Luma23 >> 12) & 0xf];
  253. /*
  254. * combine luma for pix 0 with common chroma bits to
  255. * get 15-bit yuv, then lookup to convert to
  256. * rgb and store.
  257. */
  258. *pDst++ = pXlate[ ((Luma01 & 0xf8) << 7) | Chroma];
  259. *pDst++ = pXlate[ ((Luma01 & 0xf80000) >> 9) | Chroma];
  260. *pDst++ = pXlate[ ((Luma23 & 0xf8) << 7) | Chroma];
  261. *pDst++ = pXlate[ ((Luma23 & 0xf80000) >> 9) | Chroma];
  262. } // loop per 4 pixels
  263. /* move source pointer back to next line */
  264. pSrc -= RowInc;
  265. } // loop per row
  266. }
  267. /* YUV 4:2:2 support ------------------------------------------ */
  268. /*
  269. * The captured data is in YUV 4:2:2, 8-bits per sample.
  270. * The data is laid out in alternating Y-U-Y-V-Y-U-Y-V format. Thus
  271. * every DWORD contains two complete pixels, in the
  272. * form (msb..lsb) V..Y1..U..Y0
  273. * All 3 components (y, u and v) are all unsigned 8-bit values in the range
  274. * 16..235.
  275. *
  276. * We have to double scan lines for >= 480 line formats since
  277. * the hardware only captured one field maximum.
  278. *
  279. */
  280. /*
  281. * build a translation table to translate between YUV and RGB555.
  282. *
  283. * This builds a lookup table with 32k 1-word entries: truncate the YUV
  284. * to 15bits (5-5-5) and look-up in this xlate table to produce the
  285. * 15-bit rgb value.
  286. */
  287. LPVOID BuildYUV422ToRGB555(PINSTINFO pinst)
  288. {
  289. LPVOID pXlate;
  290. LPWORD pRGB555;
  291. WORD w;
  292. if (pinst->pXlate != NULL) {
  293. return(pinst->pXlate);
  294. }
  295. /*
  296. * allocate a table big enough for 32k 2-byte entries
  297. */
  298. pXlate = GlobalLock(GlobalAlloc(GPTR, 2 * 32 * 1024));
  299. pRGB555 = (LPWORD)pXlate;
  300. /*
  301. * build a 15-bit yuv lookup table by stepping through each entry,
  302. * converting the yuv index to rgb and storing at that index. The index
  303. * to this table is a 15-bit value with the y component in bits 14..10,
  304. * u in bits 9..5 and v in bits 4..0. Note that the y component is unsigned,
  305. * whereas the u and v components are signed.
  306. */
  307. for (w = 0; w < 32*1024; w++) {
  308. /*
  309. * the YUVtoRGB55 conversion function takes values 0..255 for y,
  310. * and -128..+127 for u and v. Pick out the relevant bits of the
  311. * index for this cell, and shift to get values in this range.
  312. * Subtract 128 from u and v to shift from 0..255 to -128..+127
  313. */
  314. *pRGB555++ = YUVToRGB555(
  315. (w & 0x7c00) >> 7,
  316. ((w & 0x3e0) >> 2) - 128,
  317. ((w & 0x1f) << 3) - 128
  318. );
  319. }
  320. return(pXlate);
  321. }
  322. /*
  323. * build a translation table to translate between YUV and RGB 5-6-5
  324. *
  325. * This builds a lookup table with 32k 1-word entries: truncate the YUV
  326. * to 15bits (5-5-5) and look-up in this xlate table to produce the
  327. * 16-bit rgb value.
  328. */
  329. LPVOID BuildYUV422ToRGB565(PINSTINFO pinst)
  330. {
  331. LPVOID pXlate;
  332. LPWORD pRGB;
  333. WORD w;
  334. if (pinst->pXlate != NULL) {
  335. return(pinst->pXlate);
  336. }
  337. /*
  338. * allocate a table big enough for 32k 2-byte entries
  339. */
  340. pXlate = GlobalLock(GlobalAlloc(GPTR, 2 * 32 * 1024));
  341. pRGB = (LPWORD)pXlate;
  342. /*
  343. * build a 15-bit yuv lookup table by stepping through each entry,
  344. * converting the yuv index to rgb and storing at that index. The index
  345. * to this table is a 15-bit value with the y component in bits 14..10,
  346. * u in bits 9..5 and v in bits 4..0. Note that the y component is unsigned,
  347. * whereas the u and v components are signed.
  348. */
  349. for (w = 0; w < 32*1024; w++) {
  350. /*
  351. * the YUVtoRGB conversion function takes values 0..255 for y,
  352. * and -128..+127 for u and v. Pick out the relevant bits of the
  353. * index for this cell, and shift to get values in this range.
  354. * Subtract 128 from u and v to shift from 0..255 to -128..+127
  355. */
  356. *pRGB++ = YUVToRGB565(
  357. (w & 0x7c00) >> 7,
  358. ((w & 0x3e0) >> 2) - 128,
  359. ((w & 0x1f) << 3) - 128
  360. );
  361. }
  362. return(pXlate);
  363. }
  364. /*
  365. * translate YUV 4:2:2 into 16-bit RGB using a lookup table. Flip vertically
  366. * into DIB format during processing. Double scanlines for formats of
  367. * 480 lines or greater. Produces 565 or 555 format RGB depending on the
  368. * xlate table.
  369. */
  370. VOID
  371. YUV422ToRGB(
  372. PINSTINFO pinst,
  373. LPBITMAPINFOHEADER lpbiInput,
  374. LPVOID lpInput,
  375. LPBITMAPINFOHEADER lpbiOutput,
  376. LPVOID lpOutput
  377. )
  378. {
  379. int RowInc;
  380. int i, j;
  381. DWORD uv55, dwPixel;
  382. int WidthBytes; // width of one line in BYTES
  383. BOOL bDuplicate = FALSE;
  384. PDWORD pSrc, pDst;
  385. int Height, Width;
  386. PWORD pXlate;
  387. int InputHeight;
  388. Height = lpbiInput->biHeight;
  389. InputHeight = Height;
  390. Width = lpbiInput->biWidth;
  391. WidthBytes = Width*2; // size of (input and output) line
  392. pXlate = pinst->pXlate;
  393. /*
  394. * adjust the destination to point to the start of the last line,
  395. * and work upwards (to flip vertically into DIB format)
  396. */
  397. pDst = (PDWORD) ( (LPBYTE)lpOutput + (Height - 1) * WidthBytes );
  398. pSrc = (PDWORD) lpInput;
  399. /*
  400. * do we need to duplicate scans to fill the destination ?
  401. */
  402. if (Height >= 480) {
  403. bDuplicate = TRUE;
  404. /*
  405. * we need to skip one line each time we copy a line
  406. */
  407. RowInc = WidthBytes * 2 + (Width * 2);
  408. InputHeight = Height/2;
  409. } else {
  410. /*
  411. * calculate the amount to adjust pDst by at the end of one line
  412. * of copying. At this point we are at the end of line N. We need
  413. * to move to the start of line N-1.
  414. */
  415. RowInc = WidthBytes + (Width * 2);
  416. }
  417. /* remember we are adding to a DWORD pointer */
  418. RowInc /= sizeof(DWORD);
  419. /* loop copying each scanline */
  420. for (i = InputHeight; i > 0; i--) {
  421. /* loop copying two pixels at a time */
  422. for (j = Width ; j > 0; j -= 2) {
  423. /*
  424. * get two pixels and convert to 15-bpp YUV
  425. */
  426. dwPixel = *pSrc++;
  427. /*
  428. * dwPixel now has two pixels, in this layout (MSB..LSB):
  429. *
  430. * V Y1 U Y0
  431. *
  432. * convert to 2 yuv555 words and lookup in xlate table
  433. */
  434. /* get common u and v components to lower 10 bits */
  435. uv55 = ((dwPixel & 0xf8000000) >> 27) |
  436. ((dwPixel & 0x0000f800) >> 6);
  437. /* build each yuv-655 value by truncating
  438. * y to 5 bits and adding the common u and v bits,
  439. * look up to convert to rgb, and combine two pixels
  440. * into one dword
  441. */
  442. dwPixel = pXlate[ ((dwPixel & 0xf8) << 7) | uv55 ] |
  443. (pXlate[((dwPixel & 0xf80000) >> 9) | uv55 ] << 16);
  444. /* write two pixels to destination */
  445. *pDst++ = dwPixel;
  446. } // loop per 2 pixels
  447. /* move dest pointer back to next line */
  448. pDst -= RowInc;
  449. } // loop per row
  450. if (bDuplicate) {
  451. PBYTE pbDst;
  452. /*
  453. * Note that since we started at the last line, and didn't duplicate,
  454. * we placed data in lines 1, 3, 5 etc that needs to be copied
  455. * to lines 0, 2, 4 etc.
  456. */
  457. for (i = 0, pbDst = lpOutput; i < (int) Height; i+= 2) {
  458. /*
  459. * duplicate the scan line. We point at the first of the
  460. * two lines - the data is in the second of the
  461. * two lines.
  462. */
  463. RtlCopyMemory(pbDst, pbDst + WidthBytes, WidthBytes);
  464. /* skip this pair to get to the next line to be converted */
  465. pbDst += WidthBytes * 2;
  466. }
  467. }
  468. }
  469. VOID FreeXlate(PINSTINFO pinst)
  470. {
  471. GlobalFree(GlobalHandle(pinst->pXlate));
  472. pinst->pXlate = NULL;
  473. }