windows-nt/Source/XPSP1/NT/drivers/wdm/capture/codec/msyuv/xlate.c
2020-09-26 16:20:57 +08:00

1467 lines
46 KiB
C

/*
* Microsoft YUV Codec UyVy -> rgb conversion functions
*
* Copyright (c) Microsoft Corporation 1993
* All Rights Reserved
*
*/
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include "msyuv.h"
#include "rgb8lut.h" // can only be included once
/*
* This module provides translation from YUV into RGB. It translates
* from 8-bit YUV 4:2:2 (as provided by the Spigot video capture driver)
* or 7-bit YUV 4:1:1 (as provided by the Bravado driver) into 16-bit RGB555
* or RGB565. All versions use a look-up table built using YUVToRGB555
* or YUVToRGB565
*/
#define RANGE(x, lo, hi) max(lo, min(hi, x))
/*
* Convert a YUV colour into a 15-bit RGB colour.
*
* The input Y is in the range 16..235; the input U and V components
* are in the range -128..+127. The conversion equations for this are
* (according to CCIR 601):
*
* R = Y + 1.371 V
* G = Y - 0.698 V - 0.336 U
* B = Y + 1.732 U
*
* To avoid floating point, we scale all values by 1024.
*
* The resulting RGB values are in the range 16..235: we truncate these to
* 5 bits each. and return a WORD containing 5-bits each for R, G and B
* with bit 15 set to 0.
*/
WORD
YUVToRGB555(int y, int u, int v)
{
int ScaledY = RANGE(y, 16, 235) * 1024;
int red, green, blue;
red = RANGE((ScaledY + (1404 * v)) / 1024, 0, 255);
green = RANGE((ScaledY - ( 715 * v) - (344 * u)) / 1024, 0, 255);
blue = RANGE((ScaledY + (1774 * u)) / 1024, 0, 255);
return (WORD) (((red & 0xf8) << 7) | ((green & 0xf8) << 2) | ((blue & 0xf8) >>3) );
}
// same as above but converts to RGB565 instead
WORD
YUVToRGB565(int y, int u, int v)
{
int ScaledY = RANGE(y, 16, 235) * 1024;
int red, green, blue;
red = RANGE((ScaledY + (1404 * v)) / 1024, 0, 255);
green = RANGE((ScaledY - ( 715 * v) - (344 * u)) / 1024, 0, 255);
blue = RANGE((ScaledY + (1774 * u)) / 1024, 0, 255);
return (WORD) (((red & 0xf8) << 8) | ((green & 0xfc) << 3) | ((blue & 0xf8) >>3) );
}
/* YUV 4:2:2 support ------------------------------------------ */
/*
* The captured data is in YUV 4:2:2, 8-bits per sample.
* The data is laid out in alternating Y-U-Y-V-Y-U-Y-V format. Thus
* every DWORD contains two complete pixels, in the
* form (msb..lsb) V..Y1..U..Y0
* All 3 components (y, u and v) are all unsigned 8-bit values in the range
* 16..235.
*
* We have to double scan lines for >= 480 line formats since
* the hardware only captured one field maximum.
*
*/
LPVOID BuildUYVYToRGB32( PINSTINFO pinst )
{
LPVOID pXlate;
long y, u, v;
// need 5 lookup tables to do the conversions, each is 256 entries long,
// and each contains short words.
//
short * yip; // Y impact
short * vrip; // red's V impact
short * vgip; // green's V impact
short * ugip; // green's U impact
short * ubip; // blue's U impact
dprintf2((TEXT("In BuildUYVYToRGB32\n")));
if (pinst->pXlate != NULL) {
return(pinst->pXlate);
}
dprintf1((TEXT("Allocate memory and building table for BuildUYVYToRGB32\n")));
/*
* allocate a table big enough for 5 256-byte arrays
*/
pXlate = VirtualAlloc (NULL, 5 * 256 * sizeof( short ), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if(!pXlate)
return pXlate;
// set the table offsets
//
yip = pXlate;
vrip = yip + 256;
vgip = vrip + 256;
ugip = vgip + 256;
ubip = ugip + 256;
// setup Y impact, etc
//
for( y = 0 ; y < 256 ; y++ )
{
yip[y] = (short)( ( 1.164 * ( y - 16L ) / 1.0 ) + 0 );
}
for( v = 0 ; v < 256 ; v++ )
{
vrip[v] = (short)( 1.596 * ( v - 128L ) / 1.0 );
vgip[v] = (short)( -0.813 * ( v - 128L ) / 1.0 );
}
for( u = 0 ; u < 256 ; u++ )
{
ugip[u] = (short)( -0.391 * ( u - 128L ) / 1.0 );
ubip[u] = (short)( 2.018 * ( u - 128L ) / 1.0 );
}
return(pXlate);
}
/*
* build a translation table to translate between YUV and RGB555.
*
* This builds a lookup table with 32k 1-word entries: truncate the YUV
* to 15bits (5-5-5) and look-up in this xlate table to produce the
* 15-bit rgb value.
*/
LPVOID BuildUYVYToRGB555(PINSTINFO pinst)
{
LPVOID pXlate;
LPWORD pRGB555;
WORD w;
dprintf2((TEXT("In BuildUYVYToRGB555\n")));
if (pinst->pXlate != NULL) {
return(pinst->pXlate);
}
dprintf2((TEXT("Allocate memory and building table for BuildUYVYToRGB555\n")));
/*
* allocate a table big enough for 32k 2-byte entries
*/
pXlate = VirtualAlloc (NULL, 2 * 32 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if(!pXlate)
return pXlate;
pRGB555 = (LPWORD)pXlate;
/*
* build a 15-bit yuv lookup table by stepping through each entry,
* converting the yuv index to rgb and storing at that index. The index
* to this table is a 15-bit value with the y component in bits 14..10,
* u in bits 9..5 and v in bits 4..0. Note that the y component is unsigned,
* whereas the u and v components are signed.
*/
for (w = 0; w < 32*1024; w++) {
/*
* the YUVtoRGB55 conversion function takes values 0..255 for y,
* and -128..+127 for u and v. Pick out the relevant bits of the
* index for this cell, and shift to get values in this range.
* Subtract 128 from u and v to shift from 0..255 to -128..+127
*/
*pRGB555++ = YUVToRGB555(
(w & 0x7c00) >> 7,
((w & 0x3e0) >> 2) - 128,
((w & 0x1f) << 3) - 128
);
}
return(pXlate);
}
/*
* build a translation table to translate between YUV and RGB 5-6-5
*
* This builds a lookup table with 32k 1-word entries: truncate the YUV
* to 15bits (5-5-5) and look-up in this xlate table to produce the
* 16-bit rgb value.
*/
LPVOID BuildUYVYToRGB565(PINSTINFO pinst)
{
LPVOID pXlate;
LPWORD pRGB;
WORD w;
dprintf2((TEXT("In BuildUYVYToRGB565\n")));
if (pinst->pXlate != NULL) {
return(pinst->pXlate);
}
dprintf2((TEXT("Allocate memory and building table for BuildUYVYToRGB565\n")));
/*
* allocate a table big enough for 32k 2-byte entries
*/
pXlate = VirtualAlloc (NULL, 2 * 32 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if(!pXlate)
return pXlate;
pRGB = (LPWORD)pXlate;
/*
* build a 15-bit yuv lookup table by stepping through each entry,
* converting the yuv index to rgb and storing at that index. The index
* to this table is a 15-bit value with the y component in bits 14..10,
* u in bits 9..5 and v in bits 4..0. Note that the y component is unsigned,
* whereas the u and v components are signed.
*/
for (w = 0; w < 32*1024; w++) {
/*
* the YUVtoRGB conversion function takes values 0..255 for y,
* and -128..+127 for u and v. Pick out the relevant bits of the
* index for this cell, and shift to get values in this range.
* Subtract 128 from u and v to shift from 0..255 to -128..+127
*/
*pRGB++ = YUVToRGB565(
(w & 0x7c00) >> 7,
((w & 0x3e0) >> 2) - 128,
((w & 0x1f) << 3) - 128
);
}
return(pXlate);
}
/*
* build a translation table to translate between YUV and RGB8
*
*/
LPVOID BuildUYVYToRGB8(PINSTINFO pinst)
{
dprintf2((TEXT("In BuildUYVYToRGB8: no dynamically built table. Return NULL;\n")));
return(0);
}
/*
* translate YUV 4:2:2 into 16-bit RGB using a lookup table. Flip vertically
* into DIB format during processing. Double scanlines for formats of
* 480 lines or greater. Produces 565 or 555 format RGB depending on the
* xlate table.
*/
VOID
UYVYToRGB16(
PINSTINFO pinst,
LPBITMAPINFOHEADER lpbiInput,
LPVOID lpInput,
LPBITMAPINFOHEADER lpbiOutput,
LPVOID lpOutput
)
{
int RowInc;
int i, j;
DWORD uv55, dwPixel;
int WidthBytes; // width of one line in BYTES
BOOL bDuplicate = FALSE;
PDWORD pSrc, pDst;
int Height, Width;
PWORD pXlate;
int InputHeight;
Height = abs(lpbiInput->biHeight);
InputHeight = Height;
Width = lpbiInput->biWidth;
WidthBytes = Width * 2 ;
ASSERT(lpbiInput->biBitCount / 8 == 2);
pXlate = pinst->pXlate;
pSrc = (PDWORD) lpInput;
dprintf3(("UYVYToRGB: %s %dx%d; %s %dx%dx%d=%d; %s %dx%dx%d=%d\n",
pinst->bRGB565?"RGB565" : "RGB555",
Width, Height,
(PCHAR) &lpbiInput->biCompression,
lpbiInput->biWidth, lpbiInput->biHeight, lpbiInput->biBitCount, lpbiInput->biSizeImage,
lpbiOutput->biCompression == 0 ? "RGB": lpbiOutput->biCompression == BI_BITFIELDS ? "BITF" : (PCHAR) &lpbiOutput->biCompression,
lpbiOutput->biWidth, lpbiOutput->biHeight, lpbiOutput->biBitCount, lpbiOutput->biSizeImage));
ASSERT((lpbiOutput->biWidth == lpbiInput->biWidth) && abs(lpbiOutput->biHeight) == abs(lpbiInput->biHeight));
/*
* calculate the amount to adjust pDst by at the end of one line
* of copying. At this point we are at the end of line N. We need
* to move to the start of line N-1.
*/
RowInc = WidthBytes * 2; // two lines!!
/* remember we are adding to a DWORD pointer */
RowInc /= sizeof(DWORD);
if(lpbiOutput->biCompression == FOURCC_UYVY ||
lpbiOutput->biCompression == FOURCC_YUY2 ||
lpbiOutput->biCompression == FOURCC_YVYU ) {
pDst = (PDWORD) lpOutput;
memcpy(pDst, pSrc, Width * Height * lpbiInput->biBitCount / 8); // Top down
} else {
// Output BI_RGB or BI_BITFIELD
// UVYV->RGB; +RGB->Flip
if(lpbiOutput->biHeight >= 0)
pDst = (PDWORD) ( (LPBYTE)lpOutput + (Height - 1) * WidthBytes );
else
pDst = (PDWORD) lpOutput;
//
// UyVy
//
if(pinst->dwFormat == FOURCC_UYVY) {
/* loop copying each scanline */
for (i = InputHeight; i > 0; i--) {
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2) {
/*
* get two pixels and convert to 15-bpp YUV
*/
dwPixel = *pSrc++;
/*
* Convert UYVY (0x y1 V y0 U) to YUYV (0x V y1 U y0) in which the translation table is built for.
*/
#if defined(_X86_)
_asm {
// FourCC
// dwPixel 0x y1 V y0 U U0 Y0 V0 Y1
mov eax, dwPixel // 0x y1 V y0 U U0 Y0 V0 Y1
bswap eax // 0x U y0 V y1 Y1 V0 Y0 U0
rol eax, 16 // 0x V y1 U y0 Y0 U0 Y1 V0
mov dwPixel, eax
}
#else
dwPixel = (((dwPixel & 0xff00ff00) >> 8) | ((dwPixel & 0x00ff00ff) << 8));
#endif
/*
* dwPixel now has two pixels, in this layout (MSB..LSB):
*
* V Y1 U Y0
*
* convert to 2 yuv555 words and lookup in xlate table
*/
/* get common u and v components to lower 10 bits */ // 9 8 7 6 5 4 3 2 1 0
uv55 = ((dwPixel & 0xf8000000) >> 27) | ((dwPixel & 0x0000f800) >> 6); // U7U6:U5U4U3 V7:V6V5V4V3
/* build each yuv-655 value by truncating
* y to 5 bits and adding the common u and v bits,
* look up to convert to rgb, and combine two pixels
* into one dword
*/ // f e d c b a 9 8 7 6 5 4 3 2 1 0
dwPixel = pXlate[((dwPixel & 0x000000f8) << 7) | uv55 ] | // 0Y7Y6Y5:Y4Y3 U7U6:U5U4U3 V7:V6V5V4V3
(pXlate[((dwPixel & 0x00f80000) >> 9) | uv55 ] << 16); // 0Y7Y6Y5:Y4Y3 U7U6:U5U4U3 V7:V6V5V4V3
/* write two pixels to destination */
*pDst++ = dwPixel;
} // loop per 2 pixels
/*
* bottom up need re-adjust its pointer by
* moving dest pointer back to next line
*/
if(lpbiOutput->biHeight >= 0) {
pDst -= RowInc;
}
}
//
// yUyV
//
} else if(pinst->dwFormat == FOURCC_YUY2) {
/* loop copying each scanline */
for (i = InputHeight; i > 0; i--) {
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2) {
/*
* get two pixels and convert to 15-bpp YUV
*/
dwPixel = *pSrc++;
// We are already in YUYV (0x V y1 U y0) format.
/* get common u and v components to lower 10 bits */ // 9 8 7 6 5 4 3 2 1 0
uv55 = ((dwPixel & 0xf8000000) >> 27) | ((dwPixel & 0x0000f800) >> 6); // U7U6:U5U4U3 V7:V6V5V4V3
/* build each yuv-655 value by truncating
* y to 5 bits and adding the common u and v bits,
* look up to convert to rgb, and combine two pixels
* into one dword
*/ // f e d c b a 9 8 7 6 5 4 3 2 1 0
dwPixel = pXlate[((dwPixel & 0x000000f8) << 7) | uv55 ] | // 0Y7Y6Y5:Y4Y3 U7U6:U5U4U3 V7:V6V5V4V3
(pXlate[((dwPixel & 0x00f80000) >> 9) | uv55 ] << 16); // 0Y7Y6Y5:Y4Y3 U7U6:U5U4U3 V7:V6V5V4V3
/* write two pixels to destination */
*pDst++ = dwPixel;
} // loop per 2 pixels
/*
* bottom up need re-adjust its pointer by
* moving dest pointer back to next line
*/
if(lpbiOutput->biHeight >= 0) {
pDst -= RowInc;
}
}
//
// yVyU
//
} else if(pinst->dwFormat == FOURCC_YVYU) {
/* loop copying each scanline */
for (i = InputHeight; i > 0; i--) {
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2) {
/*
* get two pixels and convert to 15-bpp YUV
*/
dwPixel = *pSrc++;
/*
* Convert yVyU (0x U y1 V y0) to YUYV (0x V y1 U y0) in which the translation table is built for.
*/
#if defined(_X86_)
_asm {
// FourCC
// dwPixel 0x U y1 V y0
mov eax, dwPixel // 0x U y1 V y0
bswap eax // 0x y0 V y1 U
rol eax, 8 // 0x V y1 U y0
mov dwPixel, eax
}
#else
// y0 and y1 stay and swap U and V
dwPixel = (dwPixel & 0x00ff00ff) | ((dwPixel & 0x0000ff00) << 16) | ((dwPixel & 0xff000000) >> 16);
#endif
/* get common u and v components to lower 10 bits */ // 9 8 7 6 5 4 3 2 1 0
uv55 = ((dwPixel & 0xf8000000) >> 27) | ((dwPixel & 0x0000f800) >> 6); // U7U6:U5U4U3 V7:V6V5V4V3
/* build each yuv-655 value by truncating
* y to 5 bits and adding the common u and v bits,
* look up to convert to rgb, and combine two pixels
* into one dword
*/ // f e d c b a 9 8 7 6 5 4 3 2 1 0
dwPixel = pXlate[((dwPixel & 0x000000f8) << 7) | uv55 ] | // 0Y7Y6Y5:Y4Y3 U7U6:U5U4U3 V7:V6V5V4V3
(pXlate[((dwPixel & 0x00f80000) >> 9) | uv55 ] << 16); // 0Y7Y6Y5:Y4Y3 U7U6:U5U4U3 V7:V6V5V4V3
/* write two pixels to destination */
*pDst++ = dwPixel;
} // loop per 2 pixels
/*
* bottom up need re-adjust its pointer by
* moving dest pointer back to next line
*/
if(lpbiOutput->biHeight >= 0) {
pDst -= RowInc;
}
}
}
}
}
/*
* translate YUV 4:2:2 into 8-bit RGB using a lookup table.
* i.e. 0x Y1:V:Y0:U -> ox index1;index0
*/
VOID
UYVYToRGB8(
PINSTINFO pinst,
LPBITMAPINFOHEADER lpbiInput,
LPVOID lpInput,
LPBITMAPINFOHEADER lpbiOutput,
LPVOID lpOutput
)
{
register dwPixel;
int i, j;
int SrcRawInc, DstRawInc, Dst3RawInc;
PDWORD pSrc, pSrc1; // Every 32bit UYVY
PWORD pDst, pDst1; // Convert to two 8bit RGB8
int Height, Width;
int InputHeight;
unsigned char y0, y1, y2, y3,
u0, u1,
v0, v1;
unsigned long yuv0, yuv1;
Height = abs(lpbiInput->biHeight);
InputHeight = Height;
Width = lpbiInput->biWidth;
dprintf3(("UYVYToRGB8: %dx%d; %s %dx%dx%d=%d; %s %dx%dx%d=%d\n",
Width, Height,
(PCHAR) &lpbiInput->biCompression,
lpbiInput->biWidth, lpbiInput->biHeight, lpbiInput->biBitCount, lpbiInput->biSizeImage,
lpbiOutput->biCompression == 0 ? "RGB": lpbiOutput->biCompression == BI_BITFIELDS ? "BITF" : (PCHAR) &lpbiOutput->biCompression,
lpbiOutput->biWidth, lpbiOutput->biHeight, lpbiOutput->biBitCount, lpbiOutput->biSizeImage));
ASSERT(lpbiInput->biBitCount == 16 && lpbiOutput->biBitCount == 8);
ASSERT((lpbiOutput->biWidth == lpbiInput->biWidth) && abs(lpbiOutput->biHeight) == abs(lpbiInput->biHeight));
ASSERT(( lpbiOutput->biWidth % 8 == 0 )); // Align with pairs of UYVY:UYVY
ASSERT(( lpbiOutput->biHeight % 2 == 0 )); // Even number of lines
/*
* calculate the amount to adjust pDst by at the end of one line of copying.
*/
// 2bytes per pixel; pSrc is PDWORD
SrcRawInc = Width * 2 / sizeof(DWORD);
// 1 byte per pixel; pDst is PWORD
DstRawInc = Width * 1 / sizeof(WORD);
Dst3RawInc = 3 * DstRawInc;
pSrc = (PDWORD) lpInput;
pSrc1 = pSrc + SrcRawInc;
// UVYV->RGB8; same sign:flip.
if(lpbiOutput->biHeight >= 0) {
pDst = (PWORD) ( (LPBYTE)lpOutput + (Height - 1) * Width/sizeof(BYTE) );
pDst1 = (PWORD) ( (LPBYTE)lpOutput + (Height - 2) * Width/sizeof(BYTE) );
} else {
pDst = (PWORD) lpOutput;
pDst1 = (PWORD) ((LPBYTE)lpOutput+Width/sizeof(BYTE));
}
if(pinst->dwFormat == FOURCC_UYVY) {
// loop copying two scanline
for (i = InputHeight; i > 0; i -= 2) {
// loop copying four (% 8) pixels at a time
for (j = Width ; j > 0; j -= 4) {
//
// Translate TopLeft, TopRight
//
dwPixel = *pSrc++;
// Pixel is in this format: Y1:V:Y0:U
y0 = (dwPixel & 0x0000ff00) >> 8;
y1 = (dwPixel & 0xff000000) >> 24;
u0 = (dwPixel & 0x000000ff);
v0 = (dwPixel & 0x00ff0000) >> 16;
dwPixel = *pSrc++;
y2 = (dwPixel & 0x0000ff00) >> 8;
y3 = (dwPixel & 0xff000000) >> 24;
u1 = (dwPixel & 0x000000ff);
v1 = (dwPixel & 0x00ff0000) >> 16;
yuv0 = yLUT_1[y1+2] | yLUT_0[y0+10] | cLUT_B0[u0] | cLUT_R0[v0];
yuv1 = yLUT_1[y3+0] | yLUT_0[y2+8] | cLUT_B0[u1+4] | cLUT_R0[v1+4];
*pDst++ = (WORD) yuv0;
*pDst++ = (WORD) yuv1;
//
// Translate BottomLeft, BottomRight
//
dwPixel = *pSrc1++;
// Pixel is in this format: Y1:V:Y0:U
y0 = (dwPixel & 0x0000ff00) >> 8;
y1 = (dwPixel & 0xff000000) >> 24;
u0 = (dwPixel & 0x000000ff);
v0 = (dwPixel & 0x00ff0000) >> 16;
dwPixel = *pSrc1++;
y2 = (dwPixel & 0x0000ff00) >> 8;
y3 = (dwPixel & 0xff000000) >> 24;
u1 = (dwPixel & 0x000000ff);
v1 = (dwPixel & 0x00ff0000) >> 16;
yuv0 = yLUT_1[y1+0] | yLUT_0[y0+8] | cLUT_B0[u0+4] | cLUT_R0[v0+4];
yuv1 = yLUT_1[y3+2] | yLUT_0[y2+10] | cLUT_B0[u1+0] | cLUT_R0[v1+0];
*pDst1++ = (WORD) yuv0;
*pDst1++ = (WORD) yuv1;
} // 2 * 4 pixel per loops
/*
* bottom up need re-adjust its pointer by
* moving dest pointer back to next line
*/
if (lpbiOutput->biHeight >= 0) {
pDst -= Dst3RawInc;
pDst1 -= Dst3RawInc;
} else {
pDst += DstRawInc;
pDst1 += DstRawInc;
}
pSrc += SrcRawInc;
pSrc1 += SrcRawInc;
} // 2 lines per loop
} else if(pinst->dwFormat == FOURCC_YUY2) { // YUY2
// loop copying two scanline
for (i = InputHeight; i > 0; i -= 2) {
// loop copying four (% 8) pixels at a time
for (j = Width ; j > 0; j -= 4) {
//
// Translate TopLeft, TopRight
//
dwPixel = *pSrc++;
// Pixel is in this format: V:Y1:U:Y0
u0 = (dwPixel & 0x0000ff00) >> 8;
v0 = (dwPixel & 0xff000000) >> 24;
y0 = (dwPixel & 0x000000ff);
y1 = (dwPixel & 0x00ff0000) >> 16;
dwPixel = *pSrc++;
u1 = (dwPixel & 0x0000ff00) >> 8;
v1 = (dwPixel & 0xff000000) >> 24;
y2 = (dwPixel & 0x000000ff);
y3 = (dwPixel & 0x00ff0000) >> 16;
yuv0 = yLUT_1[y1+2] | yLUT_0[y0+10] | cLUT_B0[u0] | cLUT_R0[v0];
yuv1 = yLUT_1[y3+0] | yLUT_0[y2+8] | cLUT_B0[u1+4] | cLUT_R0[v1+4];
*pDst++ = (WORD) yuv0;
*pDst++ = (WORD) yuv1;
//
// Translate BottomLeft, BottomRight
//
dwPixel = *pSrc1++;
// Pixel is in this format: V:Y1:U:Y0
u0 = (dwPixel & 0x0000ff00) >> 8;
v0 = (dwPixel & 0xff000000) >> 24;
y0 = (dwPixel & 0x000000ff);
y1 = (dwPixel & 0x00ff0000) >> 16;
dwPixel = *pSrc1++;
u1 = (dwPixel & 0x0000ff00) >> 8;
v1 = (dwPixel & 0xff000000) >> 24;
y2 = (dwPixel & 0x000000ff);
y3 = (dwPixel & 0x00ff0000) >> 16;
yuv0 = yLUT_1[y1+0] | yLUT_0[y0+8] | cLUT_B0[u0+4] | cLUT_R0[v0+4];
yuv1 = yLUT_1[y3+2] | yLUT_0[y2+10] | cLUT_B0[u1+0] | cLUT_R0[v1+0];
*pDst1++ = (WORD) yuv0;
*pDst1++ = (WORD) yuv1;
} // 2 * 4 pixel per loops
/*
* bottom up need re-adjust its pointer by
* moving dest pointer back to next line
*/
if (lpbiOutput->biHeight >= 0) {
pDst -= Dst3RawInc;
pDst1 -= Dst3RawInc;
} else {
pDst += DstRawInc;
pDst1 += DstRawInc;
}
pSrc += SrcRawInc;
pSrc1 += SrcRawInc;
} // 2 lines per loop
} else if(pinst->dwFormat == FOURCC_YVYU) {
// loop copying two scanline
for (i = InputHeight; i > 0; i -= 2) {
// loop copying four (% 8) pixels at a time
for (j = Width ; j > 0; j -= 4) {
//
// Translate TopLeft, TopRight
//
dwPixel = *pSrc++;
// Pixel is in this format: U:Y1:V:Y0
v0 = (dwPixel & 0x0000ff00) >> 8;
u0 = (dwPixel & 0xff000000) >> 24;
y0 = (dwPixel & 0x000000ff);
y1 = (dwPixel & 0x00ff0000) >> 16;
dwPixel = *pSrc++;
v1 = (dwPixel & 0x0000ff00) >> 8;
u1 = (dwPixel & 0xff000000) >> 24;
y2 = (dwPixel & 0x000000ff);
y3 = (dwPixel & 0x00ff0000) >> 16;
yuv0 = yLUT_1[y1+2] | yLUT_0[y0+10] | cLUT_B0[u0] | cLUT_R0[v0];
yuv1 = yLUT_1[y3+0] | yLUT_0[y2+8] | cLUT_B0[u1+4] | cLUT_R0[v1+4];
*pDst++ = (WORD) yuv0;
*pDst++ = (WORD) yuv1;
//
// Translate BottomLeft, BottomRight
//
dwPixel = *pSrc1++;
// Pixel is in this format: U:Y1:V:Y0
v0 = (dwPixel & 0x0000ff00) >> 8;
u0 = (dwPixel & 0xff000000) >> 24;
y0 = (dwPixel & 0x000000ff);
y1 = (dwPixel & 0x00ff0000) >> 16;
dwPixel = *pSrc1++;
v1 = (dwPixel & 0x0000ff00) >> 8;
u1 = (dwPixel & 0xff000000) >> 24;
y2 = (dwPixel & 0x000000ff);
y3 = (dwPixel & 0x00ff0000) >> 16;
yuv0 = yLUT_1[y1+0] | yLUT_0[y0+8] | cLUT_B0[u0+4] | cLUT_R0[v0+4];
yuv1 = yLUT_1[y3+2] | yLUT_0[y2+10] | cLUT_B0[u1+0] | cLUT_R0[v1+0];
*pDst1++ = (WORD) yuv0;
*pDst1++ = (WORD) yuv1;
} // 2 * 4 pixel per loops
/*
* bottom up need re-adjust its pointer by
* moving dest pointer back to next line
*/
if (lpbiOutput->biHeight >= 0) {
pDst -= Dst3RawInc;
pDst1 -= Dst3RawInc;
} else {
pDst += DstRawInc;
pDst1 += DstRawInc;
}
pSrc += SrcRawInc;
pSrc1 += SrcRawInc;
} // 2 lines per loop
}
}
VOID
UYVYToRGB32(
PINSTINFO pinst,
LPBITMAPINFOHEADER lpbiInput,
LPVOID lpInput,
LPBITMAPINFOHEADER lpbiOutput,
LPVOID lpOutput
)
{
int Height = abs( lpbiInput->biHeight );
int Width = lpbiInput->biWidth;
short U;
short V;
short y0, y1;
short d;
DWORD * pSrc = lpInput;
BYTE * pDst = lpOutput;
long WidthBytes = Width * 4; // ARGB = 4 bytes
int i, j;
DWORD dwYUV;
long l;
// set up the lookup table arrays
//
short * yip = pinst->pXlate;
short * vrip = yip + 256;
short * vgip = vrip + 256;
short * ugip = vgip + 256;
short * ubip = ugip + 256;
// if just a straight copy
//
if(lpbiOutput->biCompression == FOURCC_UYVY ||
lpbiOutput->biCompression == FOURCC_YUY2 ||
lpbiOutput->biCompression == FOURCC_YVYU )
{
memcpy( pDst, pSrc, WidthBytes * Height ); // Top down
return;
}
// flip around if necessary
//
if(lpbiOutput->biHeight >= 0)
{
pDst += (Height - 1) * WidthBytes;
}
if( pinst->dwFormat == FOURCC_UYVY ) // U0 Y0 V0 Y1 U2 Y2 V2 Y3
{
for (i = Height; i > 0; i--)
{
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2)
{
// get two YUV pixels at a time
//
dwYUV = *pSrc++; // U0 Y0 V0 Y1
U = (short) ( dwYUV & 0xFF );
dwYUV = dwYUV >> 8;
y0 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
V = (short) ( dwYUV & 0xFF );
dwYUV = dwYUV >> 8;
y1 = yip[( dwYUV & 0xFF )];
d = y0 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
pDst++;
d = y1 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
pDst++;
} // for j
// back up two rows to get to the next scanline
//
if(lpbiOutput->biHeight >= 0)
{
pDst -= WidthBytes * 2;
}
} // for i
} // UYVY
else if( pinst->dwFormat == FOURCC_YUY2 ) // Y0 U0 Y1 V0...
{
for (i = Height; i > 0; i--)
{
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2)
{
// We are already in YUYV (0x V y1 U y0) format.
#if 0 // straight computation
// get two YUV pixels at a time
//
dwYUV = *pSrc++; // Y0 U0 Y1 V0
y0 = (short) ( dwYUV & 0xFF ) - 16;
dwYUV = dwYUV >> 8;
U = (short) ( dwYUV & 0xFF ) - 128;
dwYUV = dwYUV >> 8;
y1 = (short) ( dwYUV & 0xFF ) - 16;
dwYUV = dwYUV >> 8;
V = (short) ( dwYUV & 0xFF ) - 128;
l = ( ( y0 * 298L ) + ( 517L * U ) ) / 256; // blue
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // blue
l = ( ( y0 * 298L ) - ( 100L * U ) - ( 208L * V ) ) / 256; // green
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // green
l = ( ( y0 * 298L ) + ( 409L * V ) ) / 256; // red
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // red
pDst++;
l = ( ( y1 * 298L ) + ( 517L * U ) ) / 256; // blue
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // blue
l = ( ( y1 * 298L ) - ( 100L * U ) - ( 208L * V ) ) / 256; // green
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // green
l = ( ( y1 * 298L ) + ( 409L * V ) ) / 256; // red
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // red
pDst++;
#else // table lookup
// get two YUV pixels at a time
//
dwYUV = *pSrc++; // Y0 U0 Y1 V0
y0 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
U = (short) ( dwYUV & 0xFF );
dwYUV = dwYUV >> 8;
y1 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
V = (short) ( dwYUV & 0xFF );
d = y0 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
pDst++;
d = y1 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
pDst++;
#endif
} // for j
// back up two rows to get to the next scanline
//
if(lpbiOutput->biHeight >= 0)
{
pDst -= WidthBytes * 2;
}
} // for i
}
else if( pinst->dwFormat == FOURCC_YVYU ) // Y0 V0 Y1 U0...
{
for (i = Height; i > 0; i--)
{
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2)
{
// get two YUV pixels at a time
//
dwYUV = *pSrc++; // Y0 U0 Y1 V0
y0 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
V = (short) ( dwYUV & 0xFF );
dwYUV = dwYUV >> 8;
y1 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
U = (short) ( dwYUV & 0xFF );
d = y0 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
pDst++;
d = y1 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
pDst++;
} // for j
// back up two rows to get to the next scanline
//
if(lpbiOutput->biHeight >= 0)
{
pDst -= WidthBytes * 2;
}
} // for i
}
}
VOID
UYVYToRGB24(
PINSTINFO pinst,
LPBITMAPINFOHEADER lpbiInput,
LPVOID lpInput,
LPBITMAPINFOHEADER lpbiOutput,
LPVOID lpOutput
)
{
int Height = abs( lpbiInput->biHeight );
int Width = lpbiInput->biWidth;
short U;
short V;
short y0, y1;
short d;
DWORD * pSrc = lpInput;
BYTE * pDst = lpOutput;
long WidthBytes = Width * 3; // RGB = 3 bytes
int i, j;
DWORD dwYUV;
long l;
short maxd = 0;
short mind = 255;
// set up the lookup table arrays
//
short * yip = pinst->pXlate;
short * vrip = yip + 256;
short * vgip = vrip + 256;
short * ugip = vgip + 256;
short * ubip = ugip + 256;
// if just a straight copy
//
if(lpbiOutput->biCompression == FOURCC_UYVY ||
lpbiOutput->biCompression == FOURCC_YUY2 ||
lpbiOutput->biCompression == FOURCC_YVYU )
{
memcpy( pDst, pSrc, WidthBytes * Height ); // Top down
return;
}
// flip around if necessary
//
if(lpbiOutput->biHeight >= 0)
{
pDst += (Height - 1) * WidthBytes;
}
if( pinst->dwFormat == FOURCC_UYVY ) // U0 Y0 V0 Y1 U2 Y2 V2 Y3
{
for (i = Height; i > 0; i--)
{
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2)
{
// get two YUV pixels at a time
//
dwYUV = *pSrc++; // U0 Y0 V0 Y1
U = (short) ( dwYUV & 0xFF );
dwYUV = dwYUV >> 8;
y0 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
V = (short) ( dwYUV & 0xFF );
dwYUV = dwYUV >> 8;
y1 = yip[( dwYUV & 0xFF )];
d = y0 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
} // for j
// back up two rows to get to the next scanline
//
if(lpbiOutput->biHeight >= 0)
{
pDst -= WidthBytes * 2;
}
} // for i
} // UYVY
else if( pinst->dwFormat == FOURCC_YUY2 ) // Y0 U0 Y1 V0...
{
for (i = Height; i > 0; i--)
{
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2)
{
// We are already in YUYV (0x V y1 U y0) format.
#if 0 // straight computation
// get two YUV pixels at a time
//
dwYUV = *pSrc++; // Y0 U0 Y1 V0
y0 = (short) ( dwYUV & 0xFF ) - 16;
dwYUV = dwYUV >> 8;
U = (short) ( dwYUV & 0xFF ) - 128;
dwYUV = dwYUV >> 8;
y1 = (short) ( dwYUV & 0xFF ) - 16;
dwYUV = dwYUV >> 8;
V = (short) ( dwYUV & 0xFF ) - 128;
l = ( ( y0 * 298L ) + ( 517L * U ) ) / 256; // blue
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // blue
l = ( ( y0 * 298L ) - ( 100L * U ) - ( 208L * V ) ) / 256; // green
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // green
l = ( ( y0 * 298L ) + ( 409L * V ) ) / 256; // red
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // red
l = ( ( y1 * 298L ) + ( 517L * U ) ) / 256; // blue
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // blue
l = ( ( y1 * 298L ) - ( 100L * U ) - ( 208L * V ) ) / 256; // green
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // green
l = ( ( y1 * 298L ) + ( 409L * V ) ) / 256; // red
if( l < 0 ) l = 0;
if( l > 255 ) l = 255;
*pDst++ = (BYTE) l; // red
#else // table lookup
// get two YUV pixels at a time
//
dwYUV = *pSrc++; // Y0 U0 Y1 V0
y0 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
U = (short) ( dwYUV & 0xFF );
dwYUV = dwYUV >> 8;
y1 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
V = (short) ( dwYUV & 0xFF );
d = y0 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
#endif
} // for j
// back up two rows to get to the next scanline
//
if(lpbiOutput->biHeight >= 0)
{
pDst -= WidthBytes * 2;
}
} // for i
}
else if( pinst->dwFormat == FOURCC_YVYU ) // Y0 V0 Y1 U0...
{
for (i = Height; i > 0; i--)
{
/* loop copying two pixels at a time */
for (j = Width ; j > 0; j -= 2)
{
// get two YUV pixels at a time
//
dwYUV = *pSrc++; // Y0 U0 Y1 V0
y0 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
V = (short) ( dwYUV & 0xFF );
dwYUV = dwYUV >> 8;
y1 = yip[( dwYUV & 0xFF )];
dwYUV = dwYUV >> 8;
U = (short) ( dwYUV & 0xFF );
d = y0 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y0 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ubip[U]; // blue
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + ugip[U] + vgip[V]; // green
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
d = y1 + vrip[V]; // red
if( d < 0 ) d = 0;
if( d > 255 ) d = 255;
*pDst++ = (BYTE) d;
} // for j
// back up two rows to get to the next scanline
//
if(lpbiOutput->biHeight >= 0)
{
pDst -= WidthBytes * 2;
}
} // for i
}
}
#define OFFSET 10
#define STDPALCOLOURS 256
/*****************************************************************************
*
* DecompressGetPalette() implements ICM_GET_PALETTE
*
* This function has no Compress...() equivalent
*
* It is used to pull the palette from a frame in order to possibly do
* a palette change.
*
****************************************************************************/
DWORD NEAR PASCAL DecompressGetPalette(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
DWORD dw;
unsigned char * lpPalArea;
long Index, cntEntries;
HDC hDC;
PALETTEENTRY apeSystem[STDPALCOLOURS]; // OFFSET];
dprintf2((TEXT("DecompressGetPalette()\n")));
if (dw = DecompressQuery(pinst, lpbiIn, NULL))
return dw;
if (lpbiOut->biBitCount != 8) { /* 8-bit only for palettes */
dprintf1(("DecompressGetPalette: Unsupported lpbiOut->biBitCount=%d\n", lpbiOut->biBitCount));
return (DWORD)ICERR_ERROR;
}
// Initialise the palette entries in the header
dprintf1(("DecompressGetPalette(): in->biSize=%d, out->biSize=%d\n", lpbiIn->biSize, lpbiOut->biSize));
// Get the standard system colours
if ( hDC = GetDC(GetDesktopWindow()) )
{
cntEntries = GetSystemPaletteEntries(hDC,0,STDPALCOLOURS,apeSystem);
ReleaseDC(GetDesktopWindow(),hDC);
}
if (cntEntries == 0) {
dprintf2(("DecompressGetPalette:cntEntries is 0; GetSystemPaletteEntries failed.\n"));
lpbiOut->biClrUsed = 0;
lpbiOut->biClrImportant = 0;
return (DWORD) ICERR_OK;
}
lpbiOut->biClrUsed = STDPALCOLOURS;
lpbiOut->biClrImportant = 0;
// Adding system device colours to be dithered
lpPalArea = (unsigned char *)lpbiOut + (int)lpbiOut->biSize;
// Copy the first ten VGA system colours
for (Index = 0;Index < OFFSET;Index++) {
lpPalArea[Index*4+0] = apeSystem[Index].peRed;
lpPalArea[Index*4+1] = apeSystem[Index].peGreen;
lpPalArea[Index*4+2] = apeSystem[Index].peBlue;
lpPalArea[Index*4+3] = 0;
}
// Copy the palette we dither to one colour at a time
for (Index = OFFSET;Index < STDPALCOLOURS-OFFSET;Index++) {
lpPalArea[Index*4+0] = PalTable[Index*4+2];
lpPalArea[Index*4+1] = PalTable[Index*4+1];
lpPalArea[Index*4+2] = PalTable[Index*4+0];
lpPalArea[Index*4+3] = 0;
}
// Copy the last ten VGA system colours
for (Index = STDPALCOLOURS-OFFSET;Index < STDPALCOLOURS;Index++) {
lpPalArea[Index*4+0] = apeSystem[Index].peRed;
lpPalArea[Index*4+1] = apeSystem[Index].peGreen;
lpPalArea[Index*4+2] = apeSystem[Index].peBlue;
lpPalArea[Index*4+3] = 0;
}
return (DWORD)ICERR_OK;
}
VOID FreeXlate(PINSTINFO pinst)
{
ASSERT(pinst != NULL);
if (pinst && pinst->pXlate != NULL) {
VirtualFree(pinst->pXlate, 0, MEM_RELEASE);
pinst->pXlate = NULL;
}
}