mirror of https://github.com/lianthony/NT4.0
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.
1243 lines
31 KiB
1243 lines
31 KiB
/*
|
|
|
|
* xlate.c
|
|
*
|
|
* 32-bit Video Capture driver
|
|
* format translation code (YUV->RGB 8, 16, 24)
|
|
*
|
|
*
|
|
*
|
|
* Geraint Davies, Feb 93
|
|
*/
|
|
|
|
#include <vckernel.h>
|
|
#include <spigot.h>
|
|
#include "hardware.h"
|
|
#include "hwstruct.h"
|
|
|
|
#include "profile.h"
|
|
#if DBG
|
|
extern profiling lineprof; // in stream.c
|
|
#endif
|
|
|
|
/*
|
|
* The captured data is read in from the fifo 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 read from the fifo 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 convert on copying to 8-bit palettised, RGB555 or RGB-24, using
|
|
* translation tables in all cases. We have to double scan lines for >= 480
|
|
* lines since we only capture one field. We do that on a second pass (to
|
|
* ensure we get the data out of the fifo quickly): in fact, in order to go
|
|
* fast enough to avoid overrun, we write the data unconverted, and
|
|
* convert yuv->rgb/pal at the same time as duping the scan lines in pass 2.
|
|
*
|
|
* When the number of scans remaining falls below a given threshold, we trigger the
|
|
* next capture. We check this every 20 scanlines rather than every line
|
|
* since it must be interlocked with the interrupt routine.
|
|
*
|
|
*
|
|
* The (128 kbyte) rgb555 lookup table is built by BuildYUVToRGB555 whenever
|
|
* the destination format is set to RGB555. This translates from YUV655 (6-bits of
|
|
* Y) to RGB555 for better colour resolution at the cost of doubling the
|
|
* table size.
|
|
*
|
|
* The (32 kbyte) palette lookup table is built whenever the format is set to
|
|
* FmtPal8 or the palette is changed. We are not given a palette here - we are
|
|
* given a rgb555-to-palette lookup table, and we build from it
|
|
* a yuv-to-palette lookup. This translates from YUV555.
|
|
*
|
|
* The (128kbyte) rgb24 lookup table is built by BuildYUVToRGB24 whenever the
|
|
* destination format is set to RGB24. This translates from YUV555 into 4-byte
|
|
* RGBQUAD values.
|
|
*
|
|
* Since the translation tables are allocated from non-paged memory, we
|
|
* only hold one at once (in pHw->pXlate).
|
|
*/
|
|
|
|
|
|
/*
|
|
* we assign junk data from the fifo here in the hope that the
|
|
* optimiser will leave it alone
|
|
*/
|
|
DWORD FifoDiscardData;
|
|
|
|
|
|
/*
|
|
* force x to be in the range lo to hi
|
|
*/
|
|
#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
|
|
YUVToRGB15(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) );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Convert a YUV colour into 24-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 return these in a
|
|
* DWORD with 8 bits each for red, green and blue, and 8 bits free at
|
|
* the top.
|
|
*/
|
|
DWORD
|
|
YUVToRGBQUAD(int y, int u, int v)
|
|
{
|
|
int ScaledY = RANGE(y, 16, 235) * 1024;
|
|
int red, green, blue;
|
|
DWORD dwResult;
|
|
|
|
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);
|
|
|
|
|
|
dwResult = ((red & 0xff) << 16) | ((green & 0xff) << 8) | (blue & 0xff);
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* build a translation table to translate between YUV and RGB555.
|
|
*
|
|
* This builds a lookup table with 64k 1-word entries: truncate the YUV
|
|
* to 16bits (6-5-5) and look-up in this xlate table to produce the
|
|
* 15-bit rgb value.
|
|
*/
|
|
BOOLEAN
|
|
HW_BuildYUVToRGB555(PDEVICE_INFO pDevInfo, PHWINFO pHw)
|
|
{
|
|
LPWORD pWord;
|
|
UINT w;
|
|
|
|
/* check that there is not already some form of translation */
|
|
if (pHw->pXlate != NULL) {
|
|
dprintf(("xlate table contention"));
|
|
return(FALSE);
|
|
}
|
|
|
|
pHw->ulSizeXlate = sizeof(WORD) * 64 * 1024; /* enough for 64k 16-bit values */
|
|
|
|
pHw->pXlate = VC_AllocMem(pDevInfo, pHw->ulSizeXlate);
|
|
if (pHw->pXlate == NULL) {
|
|
dprintf(("failed to alloc xlate memory"));
|
|
return(FALSE);
|
|
}
|
|
|
|
pWord = (LPWORD) pHw->pXlate;
|
|
|
|
/*
|
|
* build a 16-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 16-bit value with the (6-bit) y in bits 15..10,
|
|
* u in bits 9..5 and v in bits 4..0. All three components are unsigned.
|
|
*/
|
|
for (w = 0; w < 64*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
|
|
*/
|
|
*pWord++ = YUVToRGB15(
|
|
(w & 0xfc00) >> 8,
|
|
((w & 0x3e0) >> 2) - 128,
|
|
((w & 0x1f) << 3) - 128
|
|
);
|
|
}
|
|
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* build a palette translation table.
|
|
*
|
|
* User-level code has already converted the palette into a translation
|
|
* table with one entry for each 15-bit RGB value, giving the relevant
|
|
* 8-bit palette entry. We are passed a pointer to this table (protected
|
|
* by VC_AccessData, so we need not worry about access violations).
|
|
*
|
|
* Indices into this table are 15-bit yuv (5:5:5) colours. We step through
|
|
* each possible index, separate out the y, u and v components and convert
|
|
* that into an RGB (5:5:5) colour. We then use the passed translation table
|
|
* to convert the rgb colour to a palette index, and store that pal index
|
|
* as the translation for the yuv colour used as index.
|
|
*
|
|
* The palette table we are passed in is user-mode memory: we create
|
|
* our yuv->pal lookup in non-paged memory so we can use it at interrupt time.
|
|
*
|
|
* We are called via VC_AccessData: this passes us a PVOID context pointer that
|
|
* is not used. VC_AccessData handles invalid data exceptions for us, so we
|
|
* don't need to worry about bad user data.
|
|
*/
|
|
|
|
BOOLEAN
|
|
HW_BuildYuvToPal(
|
|
PDEVICE_INFO pDevInfo,
|
|
PUCHAR pBuffer,
|
|
ULONG Length,
|
|
PVOID pContext
|
|
)
|
|
{
|
|
PHWINFO pHw = VC_GetHWInfo(pDevInfo);
|
|
int wRGB;
|
|
UINT w;
|
|
PUCHAR pXlate;
|
|
|
|
/* check that the length of the palette xlate table is good */
|
|
if (Length < (32 * 1024)) {
|
|
dprintf(("bad palette xlate table length"));
|
|
return (FALSE);
|
|
}
|
|
|
|
/* check there is not already some form of xlate table */
|
|
if (pHw->pXlate != NULL) {
|
|
dprintf(("xlate table contention"));
|
|
return(FALSE);
|
|
}
|
|
|
|
/* allocate our non-paged xlate table */
|
|
pHw->ulSizeXlate = 32 * 1024; /* enough for 32k 1-byte entries */
|
|
|
|
pHw->pXlate = VC_AllocMem(pDevInfo, pHw->ulSizeXlate);
|
|
if (pHw->pXlate == NULL) {
|
|
dprintf(("failed to allocate xlate table memory"));
|
|
return(FALSE);
|
|
} else {
|
|
pXlate = pHw->pXlate;
|
|
}
|
|
|
|
|
|
/*
|
|
* build a 15-bit yuv lookup table by stepping through each entry,
|
|
* converting the yuv index to rgb and then to a palette 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. All three components are unsigned.
|
|
*/
|
|
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
|
|
*/
|
|
wRGB = YUVToRGB15(
|
|
(w & 0x7c00) >> 7,
|
|
((w & 0x3e0) >> 2) - 128,
|
|
((w & 0x1f) << 3) - 128
|
|
);
|
|
/*
|
|
* having got the RGB555 value for this YUV index value, we can
|
|
* use the passed-in table to convert rgb555 to pal-index and
|
|
* store that as the conversion for this yuv value
|
|
*/
|
|
|
|
*pXlate++ = pBuffer[wRGB];
|
|
|
|
}
|
|
|
|
|
|
dprintf2(("xlate table copied"));
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
/*
|
|
* build a translation table from YUV to a default palette
|
|
* containing 64 grey levels only.
|
|
*/
|
|
BOOLEAN
|
|
HW_BuildDefaultXlate(PDEVICE_INFO pDevInfo, PHWINFO pHw)
|
|
{
|
|
PUCHAR pXlate;
|
|
UINT w;
|
|
|
|
/* allocate our non-paged xlate table */
|
|
pHw->ulSizeXlate = 32 * 1024; /* enough for 32k 1-byte entries */
|
|
|
|
pHw->pXlate = VC_AllocMem(pDevInfo, pHw->ulSizeXlate);
|
|
if (pHw->pXlate == NULL) {
|
|
dprintf(("failed to allocate xlate table memory"));
|
|
return(FALSE);
|
|
} else {
|
|
pXlate = pHw->pXlate;
|
|
}
|
|
|
|
/*
|
|
* each entry in the table contains the palette entry for a given
|
|
* YUV value. The palette grey levels are 64 levels in order of
|
|
* increasing luminance, thus making the mapping straightforward.
|
|
*/
|
|
for (w = 0; w < 0x8000; w++) {
|
|
*pXlate++ = (BYTE) (UINT) ( (UINT) w / ((UINT) 0x8000 / 64));
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* build a translation table from yuv-555 to rgb-24. The table contains
|
|
* 32k entries, each of which is a DWORD containing an RGBQUAD.
|
|
*/
|
|
BOOLEAN
|
|
HW_BuildYUVToRGB24(PDEVICE_INFO pDevInfo, PHWINFO pHw)
|
|
{
|
|
UINT w;
|
|
LPDWORD pDWord;
|
|
|
|
/* check that there is not already some form of translation */
|
|
if (pHw->pXlate != NULL) {
|
|
dprintf(("xlate table contention"));
|
|
return(FALSE);
|
|
}
|
|
|
|
pHw->ulSizeXlate = sizeof(DWORD) * 32 * 1024; /* enough for 32k 32-bit values */
|
|
|
|
pHw->pXlate = VC_AllocMem(pDevInfo, pHw->ulSizeXlate);
|
|
if (pHw->pXlate == NULL) {
|
|
dprintf(("failed to alloc xlate memory"));
|
|
return(FALSE);
|
|
}
|
|
|
|
pDWord = (LPDWORD) pHw->pXlate;
|
|
|
|
|
|
/*
|
|
* build a 15-bit yuv lookup table by stepping through each entry,
|
|
* converting the yuv index to rgb and store the rgb value. 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. All three components are unsigned.
|
|
*/
|
|
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
|
|
*/
|
|
*pDWord++ = YUVToRGBQUAD(
|
|
(w & 0x7c00) >> 7,
|
|
((w & 0x3e0) >> 2) - 128,
|
|
((w & 0x1f) << 3) - 128
|
|
);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* translate YUV into RGB555 copying from FIFO at pSrc to pDst.
|
|
*
|
|
* Since pSrc points to a window onto the fifo, any read from this will
|
|
* fetch from the fifo. So we dont increment the pointer.
|
|
*
|
|
* Width and Height are the dimensions of the destination rectangle in
|
|
* pixels.
|
|
*
|
|
* pXlate is a pointer to an array of words, one for each
|
|
* 16-bit YUV-655 value, giving the corresponding RGB555 value.
|
|
*
|
|
* This routine also flips the image vertically into a DIB format
|
|
*
|
|
* The fifo only contains one field. So if we are capturing
|
|
* 480 lines or more, we need to duplicate scanlines. In order to
|
|
* get stuff out of the fifo quickly, we copy them unconverted and
|
|
* convert yuv->rgb and duplicate scan lines during a second pass.
|
|
*/
|
|
VOID
|
|
CopyYUVToRGB555(
|
|
PDEVICE_INFO pDevInfo,
|
|
PUCHAR pDstStart, /* destination pixels */
|
|
PUCHAR pSrc, /* source pixels */
|
|
LPWORD pXlate, /* translation table yuv-655 to rgb-555 */
|
|
DWORD Width, /* width of copy rect in pixels */
|
|
DWORD Height, /* height of copy rect in lines */
|
|
DWORD FifoWidth /* length in pixels of one source line */
|
|
)
|
|
{
|
|
int RowInc;
|
|
int i, j;
|
|
DWORD uv55, dwPixel;
|
|
int WidthBytes = Width * 2; // dest pixel size is two bytes
|
|
BOOL bDuplicate = FALSE;
|
|
PUCHAR pDst = pDstStart;
|
|
int excess = 0;
|
|
int lines_to_dec = 0;
|
|
|
|
/* force the copy width to 4-pixel alignment */
|
|
if (Width & 3) {
|
|
dprintf(("non-4 aligned copy "));
|
|
Width &= ~3;
|
|
}
|
|
|
|
/*
|
|
* do we need to duplicate scans to fill the destination ?
|
|
*/
|
|
if (Height >= TWO_FIELD_SIZE) {
|
|
bDuplicate = TRUE;
|
|
}
|
|
|
|
/*
|
|
* adjust the destination to point to the start of the last line,
|
|
* and work upwards (to flip vertically into DIB format)
|
|
*/
|
|
pDst += (Height - 1) * WidthBytes;
|
|
|
|
/*
|
|
* adjust the width to reflect the actual fifo size
|
|
*/
|
|
if (Width > FifoWidth) {
|
|
Width = FifoWidth;
|
|
} else if (FifoWidth > Width) {
|
|
excess = FifoWidth - Width;
|
|
}
|
|
|
|
if (bDuplicate) {
|
|
for (i = Height /2; i > 0; i--) {
|
|
|
|
VC_ReadIOMemoryBlock(pDst,
|
|
pSrc,
|
|
Width * 2 // two bytes per pixel
|
|
);
|
|
|
|
|
|
/* move pDst back two lines */
|
|
pDst -= (WidthBytes * 2);
|
|
|
|
if (++lines_to_dec >= 20) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
lines_to_dec = 0;
|
|
}
|
|
|
|
|
|
/* discard unwanted data */
|
|
if (excess) {
|
|
for (j = excess; j > 0; j -= 2) {
|
|
FifoDiscardData = VC_ReadIOMemoryULONG(pSrc);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* 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 + (Width * 2);
|
|
|
|
|
|
|
|
/* loop copying each scanline */
|
|
for (i = Height; i > 0; i--) {
|
|
|
|
/* loop copying two pixels at a time */
|
|
for (j = Width ; j > 0; j -= 2) {
|
|
|
|
/*
|
|
* get two pixels and convert to 16-bpp YUV
|
|
*/
|
|
|
|
dwPixel = VC_ReadIOMemoryULONG(pSrc);
|
|
|
|
/* don't increment pSrc since this is the fifo */
|
|
|
|
/*
|
|
* dwPixel now has two pixels, in this layout (MSB..LSB):
|
|
*
|
|
* V Y1 U Y0
|
|
*
|
|
* convert to 2 yuv655 words and lookup in xlate table
|
|
*/
|
|
|
|
/* get common u and v components to lower 10 bits */
|
|
uv55 = ((dwPixel & 0xf8000000) >> 27) |
|
|
((dwPixel & 0x0000f800) >> 6);
|
|
|
|
|
|
/* build each yuv-655 value by truncating
|
|
* y to 6 bits and adding the common u and v bits,
|
|
* look up to convert to rgb555, and combine two pixels
|
|
* into one dword
|
|
*/
|
|
dwPixel = pXlate[ ((dwPixel & 0xfc) << 8) | uv55 ] |
|
|
(pXlate[((dwPixel & 0xfc0000) >> 8) | uv55 ] << 16);
|
|
|
|
/* write two pixels to destination */
|
|
* (DWORD *)pDst = dwPixel;
|
|
pDst += sizeof(DWORD);
|
|
|
|
|
|
} // loop per 2 pixels
|
|
|
|
/*
|
|
* if the fifo line is longer, empty unwanted data
|
|
*/
|
|
if (excess) {
|
|
for (j = excess; j > 0; j -= 2) {
|
|
FifoDiscardData = VC_ReadIOMemoryULONG(pSrc);
|
|
}
|
|
}
|
|
|
|
|
|
/* move dest pointer back to next line */
|
|
pDst -= RowInc;
|
|
|
|
/* count one scanline out of the fifo, and see
|
|
* if it is time to start the next acquisition
|
|
*/
|
|
if (++lines_to_dec >= 20) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
lines_to_dec = 0;
|
|
}
|
|
|
|
} // loop per row
|
|
}
|
|
|
|
|
|
if (lines_to_dec > 0) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
}
|
|
|
|
if (bDuplicate) {
|
|
|
|
/*
|
|
* having emptied the fifo, we now convert and duplicate
|
|
* the scan lines. We could add interpolation here later...
|
|
*
|
|
* Note that since we started at the last line, and didn't duplicate,
|
|
* there is yuv data in lines 1, 3, 5 etc that needs to be converted
|
|
* (in place) and copied to lines 0, 2, 4 etc.
|
|
*/
|
|
for (i = 0, pDst = pDstStart + WidthBytes; i < (int) Height; i+= 2) {
|
|
|
|
for (j = Width; j > 0; j -= 2) {
|
|
|
|
|
|
/*
|
|
* get two pixels and convert to 16-bpp YUV
|
|
*/
|
|
|
|
dwPixel = *(DWORD *) pDst;
|
|
|
|
|
|
/*
|
|
* dwPixel now has two pixels, in this layout (MSB..LSB):
|
|
*
|
|
* V Y1 U Y0
|
|
*
|
|
* convert to 2 yuv655 words and lookup in xlate table
|
|
*/
|
|
|
|
/* get common u and v components to lower 10 bits */
|
|
uv55 = ((dwPixel & 0xf8000000) >> 27) |
|
|
((dwPixel & 0x0000f800) >> 6);
|
|
|
|
|
|
/* build each yuv-655 value by truncating
|
|
* y to 6 bits and adding the common u and v bits,
|
|
* look up to convert to rgb555, and combine two pixels
|
|
* into one dword
|
|
*/
|
|
dwPixel = pXlate[ ((dwPixel & 0xfc) << 8) | uv55 ] |
|
|
(pXlate[((dwPixel & 0xfc0000) >> 8) | uv55 ] << 16);
|
|
|
|
/* write two pixels back to same place in dest bitmap */
|
|
* (DWORD *)pDst = dwPixel;
|
|
pDst += sizeof(DWORD);
|
|
}
|
|
|
|
/* skip any unfilled area */
|
|
pDst += WidthBytes - (Width * sizeof(WORD));
|
|
|
|
/* duplicate the scan line - we point at the end of the
|
|
* scan line containing data, which is the line after the
|
|
* one to be filled
|
|
*/
|
|
RtlCopyMemory(pDst - (WidthBytes*2), pDst - WidthBytes, WidthBytes);
|
|
|
|
/* skip one (empty) line to the next line to be converted */
|
|
pDst += WidthBytes;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* translate YUV from pSrc into 8-bit palettised data in pDst.
|
|
*
|
|
* pSrc is a pointer to the memory window for the fifo. We don't
|
|
* need to increment this pointer.
|
|
*
|
|
* pXlate is an array of bytes, one for each 15-bit YUV555 value, giving
|
|
* the corresponding palette entry.
|
|
*
|
|
* dwWidth and dwHeight give the size of the destination rectangle in pixels.
|
|
*
|
|
* Also flip the image vertically into a DIB format.
|
|
*
|
|
* The fifo only contains one field (240 lines on NTSC), so we need
|
|
* to duplicate (or potentially interpolate) scanlines if the destination
|
|
* is 480 lines. We do this on a second pass after capture so we get the
|
|
* data out of the fifo quickly.
|
|
*
|
|
*/
|
|
VOID
|
|
CopyYUVToPal8(
|
|
PDEVICE_INFO pDevInfo,
|
|
PUCHAR pDstStart, /* destination pixels */
|
|
PUCHAR pSrc, /* source pixels */
|
|
PUCHAR pXlate, /* translation table yuv-15 to palette entry */
|
|
DWORD Width, /* width of copy rect in pixels */
|
|
DWORD Height, /* height of copy rect in lines */
|
|
DWORD FifoWidth /* width of one line in fifo, in pixels */
|
|
)
|
|
{
|
|
int RowInc;
|
|
int i, j;
|
|
DWORD uv55, dwPixel;
|
|
BOOL bDuplicate = FALSE;
|
|
PUCHAR pDst = pDstStart;
|
|
int excess = 0;
|
|
int WidthBytes = Width;
|
|
int lines_to_dec = 0;
|
|
|
|
/* force the copy width to 4-pixel alignment */
|
|
if (Width & 3) {
|
|
dprintf(("non-4 aligned copy "));
|
|
Width &= ~3;
|
|
}
|
|
|
|
/*
|
|
* do we need to duplicate scans to fill the destination ?
|
|
*/
|
|
if (Height >= TWO_FIELD_SIZE) {
|
|
bDuplicate = TRUE;
|
|
}
|
|
|
|
/*
|
|
* adjust the destination to point to the start of the last line,
|
|
* and work upwards (to flip vertically into DIB format)
|
|
* if duplicating, remember we fill 2 lines worth
|
|
*/
|
|
pDst += (Height - (bDuplicate ? 2 : 1)) * Width;
|
|
|
|
/*
|
|
* adjust the width to reflect the actual fifo size
|
|
*/
|
|
if (Width > FifoWidth) {
|
|
Width = FifoWidth;
|
|
} else if (FifoWidth > Width) {
|
|
excess = FifoWidth - Width;
|
|
}
|
|
|
|
if (bDuplicate) {
|
|
|
|
/*
|
|
* if we are in 480 line mode, then not only do we have to
|
|
* duplicate scanlines, but we also have to get the data out of
|
|
* the fifo quickly as one field is larger than the fifo.
|
|
*
|
|
* copy unconverted data into the buffer (although 16bpp is
|
|
* larger than the dest pixel size, we can fill two lines for
|
|
* each source line since we are going to dup scans later.
|
|
*/
|
|
for(i = Height/2; i > 0; i--) {
|
|
|
|
VC_ReadIOMemoryBlock(pDst,
|
|
pSrc,
|
|
Width * 2 // two bytes per pixel
|
|
);
|
|
|
|
|
|
/* skip to start of next dest line (source is fifo - no incr necy */
|
|
pDst -= WidthBytes * 2;
|
|
|
|
if (++lines_to_dec >= 20) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
lines_to_dec = 0;
|
|
}
|
|
|
|
|
|
/* discard unwanted data */
|
|
if (excess) {
|
|
for (j = excess; j > 0; j -= 2) {
|
|
FifoDiscardData = VC_ReadIOMemoryULONG(pSrc);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
/*
|
|
* 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 + Width;
|
|
|
|
|
|
|
|
/* loop copying each scanline */
|
|
for (i = Height; i > 0; i--) {
|
|
|
|
START_PROFILING(&lineprof);
|
|
|
|
|
|
|
|
/* loop copying four pixels at a time */
|
|
for (j = Width; j > 0; j -= 4) {
|
|
|
|
DWORD dw1, dw2, destpix;
|
|
|
|
/*
|
|
* get two pixels and convert to 15-bpp YUV-555
|
|
*/
|
|
dw1 = VC_ReadIOMemoryULONG((DWORD *) pSrc);
|
|
dw2 = VC_ReadIOMemoryULONG((DWORD *) pSrc);
|
|
|
|
/* don't increment pSrc since this is the fifo */
|
|
|
|
/*
|
|
* 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 */
|
|
uv55 = ((dw1) >> 27) |
|
|
((dw1 & 0x0000f800) >> 6);
|
|
|
|
|
|
/* build each yuv-555 value by truncating
|
|
* y to 5 bits and adding the common u and v bits,
|
|
* look up to convert to palindex, and combine two pixels
|
|
* into one word.
|
|
*/
|
|
destpix = pXlate[ ((dw1 & 0xf8) << 7) | uv55 ] |
|
|
(pXlate[((dw1 & 0xf80000) >> 9) | uv55 ] << 8);
|
|
|
|
// common u and v for second pixel pair
|
|
uv55 = ((dw2) >> 27) |
|
|
((dw2 & 0x0000f800) >> 6);
|
|
|
|
|
|
// build second pixel pair and write all 4 pixels
|
|
destpix = pXlate[ ((dw1 & 0xf8) << 7) | uv55 ] |
|
|
(pXlate[((dw1 & 0xf80000) >> 9) | uv55 ] << 8);
|
|
|
|
* (DWORD *) pDst =
|
|
(
|
|
pXlate[ ((dw2 & 0xf8) << 7) | uv55 ] |
|
|
(pXlate[((dw2 & 0xf80000) >> 9) | uv55 ] << 8)
|
|
) << 16 | destpix;
|
|
|
|
pDst += sizeof(DWORD);
|
|
}
|
|
|
|
STOP_PROFILING(&lineprof);
|
|
|
|
/*
|
|
* if the fifo line is longer, empty unwanted data
|
|
*/
|
|
if (excess) {
|
|
for (j = excess; j > 0; j -= 2) {
|
|
FifoDiscardData = VC_ReadIOMemoryULONG(pSrc);
|
|
}
|
|
}
|
|
|
|
|
|
/* move dest pointer back to next line */
|
|
pDst -= RowInc;
|
|
|
|
/* count one scanline out of the fifo, and see
|
|
* if it is time to start the next acquisition
|
|
*/
|
|
if (++lines_to_dec >= 20) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
lines_to_dec = 0;
|
|
}
|
|
|
|
} // loop per row
|
|
}
|
|
|
|
if (lines_to_dec > 0) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
}
|
|
|
|
if (bDuplicate) {
|
|
|
|
/*
|
|
* having emptied the fifo, we now need to convert the pixels
|
|
* and duplicate the scanlines. Two lines of the
|
|
* destination contain one line worth of 16 bit pixels, to be
|
|
* converted and written back, and then duplicated.
|
|
*/
|
|
|
|
for (i = 0, pDst = pDstStart; i < (int)Height; i+= 2) {
|
|
|
|
/* convert the 16-bit data at pDst into 8 bit data in place */
|
|
pSrc = pDst;
|
|
|
|
for (j = Width; j > 0; j -= 2) {
|
|
|
|
/*
|
|
* get two pixels and convert to 15-bpp YUV-555
|
|
*/
|
|
|
|
dwPixel = *(DWORD *) pSrc;
|
|
|
|
pSrc += sizeof(DWORD);
|
|
|
|
/*
|
|
* 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 */
|
|
uv55 = ((dwPixel & 0xf8000000) >> 27) |
|
|
((dwPixel & 0x0000f800) >> 6);
|
|
|
|
|
|
/* build each yuv-555 value by truncating
|
|
* y to 5 bits and adding the common u and v bits,
|
|
* look up to convert to palindex, and combine two pixels
|
|
* into one word, then write both to dest.
|
|
*/
|
|
* (WORD *) pDst = pXlate[ ((dwPixel & 0xf8) << 7) | uv55 ] |
|
|
(pXlate[((dwPixel & 0xf80000) >> 9) | uv55 ] << 8);
|
|
|
|
pDst += sizeof(WORD);
|
|
}
|
|
|
|
/*
|
|
* skip past any unwritten data - eg if fifo line length
|
|
* is shorter than destination
|
|
*/
|
|
pDst += (WidthBytes - Width);
|
|
|
|
/* now only one of the two lines contains data: duplicate
|
|
* the scan lines down to the second line. pDst now points
|
|
* to the beginning of the second line (to be copied into).
|
|
*/
|
|
|
|
RtlCopyMemory(pDst, pDst - WidthBytes, WidthBytes);
|
|
|
|
/* move pDst one more line, to the start of next double line */
|
|
pDst += WidthBytes;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* translate YUV from pSrc into 24-bit RGB in pDst.
|
|
*
|
|
* pSrc points to a window onto the fifo: we don't need to increment
|
|
* this pointer.
|
|
*
|
|
* pXlate points to a yuv555 to rgb conversion table. This contains 32k entries
|
|
* of one dword, each entry having (msb..lsb) 00RRGGBB for that yuv555 value.
|
|
*
|
|
* dwWidth and dwHeight give the size of the copy rectangle in pixels.
|
|
* WidthBytes is the width of one source line in bytes.
|
|
*
|
|
* Also flip the image vertically into a DIB format.
|
|
*
|
|
* The fifo contains one field only. If the destination is larger than
|
|
* one field high, we need to duplicate scans. We do this after
|
|
* capture as a second pass, to ensure that we get stuff out of the
|
|
* fifo quickly. We also leave yuv->rgb conversion to the second pass in
|
|
* this case.
|
|
*/
|
|
VOID
|
|
CopyYUVToRGB24(
|
|
PDEVICE_INFO pDevInfo,
|
|
PUCHAR pDstStart, /* destination pixels */
|
|
PUCHAR pSrc, /* source pixels */
|
|
PDWORD pXlate, /* yuv555 to rgbquad translation table */
|
|
DWORD Width, /* width of destination rect in pixels */
|
|
DWORD Height, /* height of destination rect in lines */
|
|
DWORD FifoWidth /* width in pixels of one fifo line */
|
|
)
|
|
{
|
|
int RowInc;
|
|
int i, j;
|
|
DWORD uv55, dwPixel, dwRGB;
|
|
int WidthBytes = Width * 3; // dest pixel size is three bytes
|
|
BOOL bDuplicate = FALSE;
|
|
PUCHAR pDst = pDstStart;
|
|
int excess = 0;
|
|
int lines_to_dec = 0;
|
|
|
|
/* force the copy width to 4-pixel alignment */
|
|
if (Width & 3) {
|
|
dprintf(("non-4 aligned copy "));
|
|
Width &= ~3;
|
|
}
|
|
|
|
/*
|
|
* do we need to duplicate scans to fill the destination ?
|
|
*/
|
|
if (Height >= TWO_FIELD_SIZE) {
|
|
bDuplicate = TRUE;
|
|
}
|
|
|
|
/*
|
|
* adjust the destination to point to the start of the last line,
|
|
* and work upwards (to flip vertically into DIB format)
|
|
*/
|
|
pDst += (Height - 1) * WidthBytes;
|
|
|
|
/*
|
|
* adjust the width to reflect the actual fifo size
|
|
*/
|
|
if (Width > FifoWidth) {
|
|
Width = FifoWidth;
|
|
} else if (FifoWidth > Width) {
|
|
excess = FifoWidth - Width;
|
|
}
|
|
|
|
if (bDuplicate) {
|
|
|
|
/* copy the scan lines unconverted into every other line */
|
|
for (i = Height/2; i > 0; i--) {
|
|
|
|
/* copy one line */
|
|
VC_ReadIOMemoryBlock(pDst,
|
|
pSrc,
|
|
Width * 2 // two bytes per pixel
|
|
);
|
|
|
|
/*
|
|
* move back two lines
|
|
*/
|
|
pDst -= WidthBytes * 2;
|
|
|
|
if (++lines_to_dec >= 20) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
lines_to_dec = 0;
|
|
}
|
|
|
|
|
|
/* discard unwanted data */
|
|
if (excess) {
|
|
for (j = excess; j > 0; j -= 2) {
|
|
FifoDiscardData = VC_ReadIOMemoryULONG( pSrc);
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* 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 + (Width * 3);
|
|
|
|
|
|
|
|
/* loop copying each scanline */
|
|
for (i = (bDuplicate ? Height/2 : Height); i>0; i--) {
|
|
|
|
/* loop copying two pixels at a time */
|
|
for (j = Width ; j > 0; j -= 2) {
|
|
|
|
/*
|
|
* get two pixels and convert to YUV-555
|
|
*/
|
|
|
|
dwPixel = VC_ReadIOMemoryULONG(pSrc);
|
|
|
|
/* don't increment pSrc since this is the fifo */
|
|
|
|
/*
|
|
* 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 */
|
|
uv55 = ((dwPixel & 0xf8000000) >> 27) |
|
|
((dwPixel & 0x0000f800) >> 6);
|
|
|
|
|
|
/*
|
|
* truncate y to 5 bits and add in common u, v bits. then
|
|
* lookup to convert to rgb dword.
|
|
*/
|
|
dwRGB = pXlate[ ((dwPixel & 0xf8) << 7) | uv55 ];
|
|
|
|
/* write the red, green and blue bytes to destination */
|
|
*(WORD UNALIGNED *) pDst = LOWORD(dwRGB);
|
|
pDst += sizeof(WORD);
|
|
*pDst = LOBYTE(HIWORD(dwRGB));
|
|
pDst += sizeof(BYTE);
|
|
|
|
/*
|
|
* same again for second pixel
|
|
*/
|
|
dwRGB = pXlate[((dwPixel & 0xf80000) >> 9) | uv55 ];
|
|
|
|
/* write the red, green and blue bytes to destination */
|
|
*(WORD UNALIGNED *) pDst = LOWORD(dwRGB);
|
|
pDst += sizeof(WORD);
|
|
*pDst = LOBYTE(HIWORD(dwRGB));
|
|
pDst += sizeof(BYTE);
|
|
|
|
|
|
} // loop per 2 pixels
|
|
|
|
/*
|
|
* if the fifo line is longer, empty unwanted data
|
|
*/
|
|
if (excess) {
|
|
for (j = excess; j > 0; j -= 2) {
|
|
FifoDiscardData = VC_ReadIOMemoryULONG(pSrc);
|
|
}
|
|
}
|
|
|
|
/* move dest pointer back to next line */
|
|
pDst -= RowInc;
|
|
|
|
/* count one scanline out of the fifo, and see
|
|
* if it is time to start the next acquisition
|
|
*/
|
|
if (++lines_to_dec >= 20) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
lines_to_dec = 0;
|
|
}
|
|
|
|
|
|
} // loop per row
|
|
}
|
|
|
|
if (lines_to_dec > 0) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
}
|
|
|
|
if (bDuplicate) {
|
|
|
|
/*
|
|
* having emptied the fifo, we now convert and duplicate
|
|
* the scan lines. We could add interpolation here later...
|
|
*
|
|
* We wrote the data into lines 1,3, 5 etc. This needs to be converted
|
|
* and also written to lines 0, 2, 4 etc. Since the dest pixel
|
|
* size is larger, we can't convert in place, so we convert to
|
|
* the even line and then copy this back to the odd line.
|
|
*
|
|
*/
|
|
for (i = 0, pDst = pDstStart; i < (int) Height; i+= 2) {
|
|
|
|
pSrc = pDst + WidthBytes;
|
|
|
|
for (j = Width; j>0; j -= 2) {
|
|
/*
|
|
* get two pixels and convert to YUV-555
|
|
*/
|
|
|
|
dwPixel = *(DWORD *) pSrc;
|
|
pSrc += sizeof(DWORD);
|
|
|
|
|
|
/*
|
|
* 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 */
|
|
uv55 = ((dwPixel & 0xf8000000) >> 27) |
|
|
((dwPixel & 0x0000f800) >> 6);
|
|
|
|
|
|
/*
|
|
* truncate y to 5 bits and add in common u, v bits. then
|
|
* lookup to convert to rgb dword.
|
|
*/
|
|
dwRGB = pXlate[ ((dwPixel & 0xf8) << 7) | uv55 ];
|
|
|
|
/* write the red, green and blue bytes to destination */
|
|
*(WORD UNALIGNED *) pDst = LOWORD(dwRGB);
|
|
pDst += sizeof(WORD);
|
|
*pDst = LOBYTE(HIWORD(dwRGB));
|
|
pDst += sizeof(BYTE);
|
|
|
|
/*
|
|
* same again for second pixel
|
|
*/
|
|
dwRGB = pXlate[((dwPixel & 0xf80000) >> 9) | uv55 ];
|
|
|
|
/* write the red, green and blue bytes to destination */
|
|
*(WORD UNALIGNED *) pDst = LOWORD(dwRGB);
|
|
pDst += sizeof(WORD);
|
|
*pDst = LOBYTE(HIWORD(dwRGB));
|
|
pDst += sizeof(BYTE);
|
|
|
|
}
|
|
|
|
/*
|
|
* skip any unwritten area (eg if fifo line is shorter)
|
|
*/
|
|
pDst += WidthBytes - (Width * 3);
|
|
|
|
/*
|
|
* pDst points to the start of the odd line: we need to
|
|
* copy from the previous line to here.
|
|
*/
|
|
|
|
RtlCopyMemory(pDst, pDst - WidthBytes, WidthBytes);
|
|
|
|
/* move one more line to the next even line */
|
|
pDst += WidthBytes;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* copy a rectangle from pSrc to pDst without any conversion: no scan
|
|
* doubling, no yuv -> rgb conversion and no vertical flip.
|
|
*
|
|
* Width x Height is the size of the destination rectangle in pixels.
|
|
*
|
|
* pSrc points to a memory window onto the fifo, so we dont need to increment it.
|
|
*/
|
|
VOID
|
|
CopyFifoRect(
|
|
PDEVICE_INFO pDevInfo,
|
|
PUCHAR pDst,
|
|
PUCHAR pSrc,
|
|
DWORD Width,
|
|
DWORD Height,
|
|
DWORD FifoWidth
|
|
)
|
|
{
|
|
int i, j;
|
|
int excess = 0;
|
|
int lines_to_dec = 0;
|
|
|
|
/*
|
|
* check for difference between real width and requested
|
|
*/
|
|
if (FifoWidth > Width) {
|
|
excess = FifoWidth - Width;
|
|
} else if (Width > FifoWidth) {
|
|
Width = FifoWidth;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* only one field in the fifo - so only copy one. The codec can
|
|
* duplicate on playback
|
|
*/
|
|
if (Height >= TWO_FIELD_SIZE) {
|
|
Height /= 2;
|
|
}
|
|
|
|
|
|
for (i = 0; i < (int)Height; i++) {
|
|
|
|
START_PROFILING(&lineprof);
|
|
|
|
VC_ReadIOMemoryBlock(pDst,
|
|
pSrc,
|
|
Width * 2);
|
|
|
|
pDst += Width*2;
|
|
|
|
STOP_PROFILING(&lineprof);
|
|
|
|
|
|
if (++lines_to_dec >= 20) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
lines_to_dec = 0;
|
|
}
|
|
|
|
|
|
/* discard unwanted data */
|
|
if (excess) {
|
|
for (j = excess; j > 0; j -= 2) {
|
|
FifoDiscardData = VC_ReadIOMemoryULONG(pSrc);
|
|
}
|
|
}
|
|
|
|
}
|
|
if (lines_to_dec > 0) {
|
|
HW_DecScansAndArm(pDevInfo, lines_to_dec);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|