📄 vconvert.cxx
字号:
return PTrue;
}
#define LIMIT(x) (unsigned char) ((x > 255) ? 255 : ((x < 0) ? 0 : x ))
static inline int clip(int a, int limit) {
return a<limit?a:limit;
}
PBoolean PStandardColourConverter::SBGGR8toYUV420P(const BYTE * src, BYTE * dst, PINDEX * bytesReturned) const
{
#define USE_SBGGR8_NATIVE 1 // set to 0 to use the double conversion algorithm (Bayer->RGB->YUV420P)
#if USE_SBGGR8_NATIVE
// kernels for Y conversion, normalised by 2^16
const int kR[]={1802,9667,1802,9667,19661,9667,1802,9667,1802};
const int kG1[]={7733,9830,7733,3604,7733,3604,7733,9830,7733};
const int kG2[]={7733,3604,7733,9830,7733,9830,7733,3604,7733};
const int kB[]={4915,9667,4915,9667,7209,9667,4915,9667,4915};
// const int kID[]={0,0,0,0,65536,0,0,0,0}; identity kernel, use to test
int B, G, G1, G2, R;
const int stride = srcFrameWidth;
unsigned const int hSize =srcFrameHeight/2;
unsigned const int vSize =srcFrameWidth/2;
unsigned const int lastRow=srcFrameHeight-1;
unsigned const int lastCol=srcFrameWidth-1;
unsigned int i,j;
const BYTE *sBayer = src;
// Y = round( 0.256788 * R + 0.504129 * G + 0.097906 * B) + 16;
// Y = round( 0.30 * R + 0.59 * G + 0.11 * B ) use this!
// U = round(-0.148223 * R - 0.290993 * G + 0.439216 * B) + 128;
// V = round( 0.439216 * R - 0.367788 * G - 0.071427 * B) + 128;
// Compute U and V planes using EXACT values, reading 2x2 pixels at a time
BYTE *dU = dst+srcFrameHeight*srcFrameWidth;
BYTE *dV = dU+hSize*vSize;
for (i=0; i<hSize; i++) {
for (j=0; j<vSize; j++) {
B=sBayer[0];
G1=sBayer[1];
G2=sBayer[stride];
R=sBayer[stride+1];
G=G1+G2;
*dU = (BYTE)( ( (-19428 * R -19071*G +57569 * B) >> 17) + 128 );
*dV = (BYTE)( ( ( 57569 * R -24103*G -9362 * B) >> 17) + 128 );
sBayer+=2;
dU++;
dV++;
}
sBayer+=stride; // skip odd lines
}
// Compute Y plane
BYTE *dY = dst;
sBayer=src;
const int * k; // kernel pointer
int dxLeft, dxRight; // precalculated offsets, needed for first and last column
const BYTE *sBayerTop, *sBayerBottom;
for (i=0; i<srcFrameHeight; i++) {
// Pointer to previous row, to the next if we are on the first one
sBayerTop=sBayer+(i?(-stride):stride);
// Pointer to next row, to the previous one if we are on the last
sBayerBottom=sBayer+((i<lastRow)?stride:(-stride));
// offset to previous column, to the next if we are on the first col
dxLeft=1;
for (j=0; j<srcFrameWidth; j++) {
// offset to next column, to previous if we are on the last one
dxRight=j<lastCol?1:(-1);
// find the proper kernel according to the current pixel color
if ( (i ^ j) & 1) k=(j&1)?kG1:kG2; // green 1 or green 2
else if (!(i & 1)) k=kB; // blue
else /* if (!(j & 1)) */ k=kR; // red
// apply the proper kernel to this pixel and surrounding ones
*dY= (BYTE)(clip( (k[0])*(int)sBayerTop[dxLeft]+
(k[1])*(int)(*sBayerTop)+
(k[2])*(int)sBayerTop[dxRight]+
(k[3])*(int)sBayer[dxLeft]+
(k[4])*(int)(*sBayer)+
(k[5])*(int)sBayer[dxRight]+
(k[6])*(int)sBayerBottom[dxLeft]+
(k[7])*(int)(*sBayerBottom)+
(k[8])*(int)sBayerBottom[dxRight], (1<<24)) >> 16);
dY++;
sBayer++;
sBayerTop++;
sBayerBottom++;
dxLeft=-1;
}
}
if (bytesReturned)
*bytesReturned = srcFrameHeight*srcFrameWidth+2*hSize*vSize;
return true;
#else //USE_SBGGR8_NATIVE
// shortest but less efficient (one malloc per conversion!)
BYTE * tempDest=(BYTE*)malloc(3*srcFrameWidth*srcFrameHeight);
SBGGR8toRGB(src, tempDest, NULL);
PBoolean r = RGBtoYUV420P(tempDest, dst, bytesReturned, 3, 2, 0);
free(tempDest);
return r;
#endif //USE_SBGGR8_NATIVE
}
PBoolean PStandardColourConverter::SBGGR8toRGB(const BYTE * src,
BYTE * dst,
PINDEX * bytesReturned) const
{
if (src == dst || verticalFlip)
return PFalse;
long int i;
const BYTE *rawpt;
BYTE *scanpt;
long int size;
rawpt = src;
scanpt = dst;
long int WIDTH = srcFrameWidth, HEIGHT = srcFrameHeight;
size = WIDTH*HEIGHT;
for ( i = 0; i < size; i++ ) {
if ( (i/WIDTH) % 2 == 0 ) {
if ( (i % 2) == 0 ) {
/* B */
if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
*scanpt++ = (BYTE) ((*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4); /* R */
*scanpt++ = (BYTE) ((*(rawpt-1)+*(rawpt+1)+ *(rawpt+WIDTH)+*(rawpt-WIDTH))/4); /* G */
*scanpt++ = *rawpt; /* B */
} else {
/* first line or left column */
*scanpt++ = *(rawpt+WIDTH+1); /* R */
*scanpt++ = (BYTE) ((*(rawpt+1)+*(rawpt+WIDTH))/2); /* G */
*scanpt++ = *rawpt; /* B */
}
} else {
/* (B)G */
if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
*scanpt++ = (BYTE) ((*(rawpt+WIDTH)+*(rawpt-WIDTH))/2); /* R */
*scanpt++ = *rawpt; /* G */
*scanpt++ = (BYTE) ((*(rawpt-1)+*(rawpt+1))/2); /* B */
} else {
/* first line or right column */
*scanpt++ = *(rawpt+WIDTH); /* R */
*scanpt++ = *rawpt; /* G */
*scanpt++ = *(rawpt-1); /* B */
}
}
} else {
if ( (i % 2) == 0 ) {
/* G(R) */
if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
*scanpt++ = (BYTE) ((*(rawpt-1)+*(rawpt+1))/2); /* R */
*scanpt++ = *rawpt; /* G */
*scanpt++ = (BYTE) ((*(rawpt+WIDTH)+*(rawpt-WIDTH))/2); /* B */
} else {
/* bottom line or left column */
*scanpt++ = *(rawpt+1); /* R */
*scanpt++ = *rawpt; /* G */
*scanpt++ = *(rawpt-WIDTH); /* B */
}
} else {
/* R */
if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
*scanpt++ = *rawpt; /* R */
*scanpt++ = (BYTE) ((*(rawpt-1)+*(rawpt+1)+*(rawpt-WIDTH)+*(rawpt+WIDTH))/4); /* G */
*scanpt++ = (BYTE) ((*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+*(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4); /* B */
} else {
/* bottom line or right column */
*scanpt++ = *rawpt; /* R */
*scanpt++ = (BYTE) ((*(rawpt-1)+*(rawpt-WIDTH))/2); /* G */
*scanpt++ = *(rawpt-WIDTH-1); /* B */
}
}
}
rawpt++;
}
if (bytesReturned)
*bytesReturned = scanpt - dst;
return PTrue;
}
#define SCALEBITS 12
#define ONE_HALF (1UL << (SCALEBITS - 1))
#define FIX(x) ((int) ((x) * (1UL<<SCALEBITS) + 0.5))
/*
* Please note when converting colorspace from YUV to RGB.
* Not all YUV have the same colorspace.
*
* For instance Jpeg use this formula
* YCbCr is defined per CCIR 601-1, except that Cb and Cr are
* normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
* The conversion equations to be implemented are therefore
* Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
* Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
* Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
* (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
* So
* R = Y + 1.402 (Cr-128)
* G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
* B = Y + 1.772 (Cb-128)
*
*/
PBoolean PStandardColourConverter::YUV420PtoRGB(const BYTE * srcFrameBuffer,
BYTE * dstFrameBuffer,
PINDEX * bytesReturned,
unsigned rgbIncrement,
unsigned redOffset,
unsigned blueOffset) const
{
if (srcFrameBuffer == dstFrameBuffer)
return PFalse; // Cannot do in-place conversion
static const unsigned greenOffset = 1;
unsigned height = PMIN(srcFrameHeight, dstFrameHeight)&(UINT_MAX-1); // Must be even
unsigned width = PMIN(srcFrameWidth, dstFrameWidth)&(UINT_MAX-1);
unsigned yplanesize = srcFrameWidth*srcFrameHeight;
const BYTE *yplane = srcFrameBuffer; // 1 byte Y (luminance) for each pixel
const BYTE *uplane = yplane+yplanesize; // 1 byte U for a block of 4 pixels
const BYTE *vplane = uplane+(yplanesize/4); // 1 byte V for a block of 4 pixels
BYTE * dstScanLine = dstFrameBuffer;
#ifdef P_MEDIALIB
const BYTE *y0;
const BYTE *y1;
const BYTE *cb;
const BYTE *cr;
unsigned int x,p;
for(int i = 0; i < srcFrameHeight; i += 2) {
p = i*srcFrameWidth;
x = p/4;
y0 = yplane + p;
y1 = y0 + srcFrameWidth;
cb = uplane + x;
cr = vplane + x;
mlib_VideoColorJFIFYCC2RGB420_Nearest(dstFrameBuffer,
dstFrameBuffer+3*dstFrameWidth,
y0, y1, cb, cr,
srcFrameWidth);
dstFrameBuffer += 6*dstFrameWidth;
}
#else
unsigned int srcPixpos[4] = { 0, 1, srcFrameWidth, srcFrameWidth + 1 };
unsigned int dstPixpos[4] = { 0, rgbIncrement, dstFrameWidth*rgbIncrement, (dstFrameWidth+1)*rgbIncrement };
if (verticalFlip) {
dstScanLine += (dstFrameHeight - 2) * dstFrameWidth * rgbIncrement;
dstPixpos[0] = dstFrameWidth;
dstPixpos[1] = dstFrameWidth +1;
dstPixpos[2] = 0;
dstPixpos[3] = 1;
}
for (unsigned y = 0; y < height; y += 2)
{
BYTE * dstPixelGroup = dstScanLine;
for (unsigned x = 0; x < width; x += 2)
{
// The RGB value without luminance
long cb = *uplane-128;
long cr = *vplane-128;
long rd = FIX(1.40200) * cr + ONE_HALF;
long gd = -FIX(0.34414) * cb -FIX(0.71414) * cr + ONE_HALF;
long bd = FIX(1.77200) * cb + ONE_HALF;
// Add luminance to each of the 4 pixels
for (unsigned p = 0; p < 4; p++)
{
int yvalue = *(yplane + srcPixpos[p]);
int l = yvalue << SCALEBITS;
int r = (l+rd)>>SCALEBITS;
int g = (l+gd)>>SCALEBITS;
int b = (l+bd)>>SCALEBITS;
BYTE * rgpPtr = dstPixelGroup + dstPixpos[p];
rgpPtr[redOffset] = LIMIT(r);
rgpPtr[greenOffset] = LIMIT(g);
rgpPtr[blueOffset] = LIMIT(b);
if (rgbIncrement == 4)
rgpPtr[3] = 0;
}
yplane += 2;
dstPixelGroup += rgbIncrement*2;
uplane++;
vplane++;
}
yplane += srcFrameWidth;
dstScanLine += (verticalFlip?-2:2)*rgbIncrement*dstFrameWidth;
}
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
#endif
return PTrue;
}
PSTANDARD_COLOUR_CONVERTER(SBGGR8,RGB24)
{
return SBGGR8toRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned);
}
PSTANDARD_COLOUR_CONVERTER(SBGGR8,YUV420P)
{
return SBGGR8toYUV420P(srcFrameBuffer, dstFrameBuffer, bytesReturned);
}
PSTANDARD_COLOUR_CONVERTER(YUV420P,RGB24)
{
return YUV420PtoRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, 0, 2);
}
PSTANDARD_COLOUR_CONVERTER(YUV420P,BGR24)
{
return YUV420PtoRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, 2, 0);
}
PSTANDARD_COLOUR_CONVERTER(YUV420P,RGB32)
{
return YUV420PtoRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned, 4, 0, 2);
}
PSTANDARD_COLOUR_CONVERTER(YUV420P,BGR32)
{
return YUV420PtoRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned, 4, 2, 0);
}
static void SwapRedAndBlueRow(const BYTE * srcRowPtr,
BYTE * dstRowPtr,
unsigned width,
unsigned srcIncrement,
unsigned dstIncrement)
{
for (unsigned x = 0; x < width; x++) {
BYTE temp = srcRowPtr[0]; // Do it this way in case src and dst are same buffer
dstRowPtr[0] = srcRowPtr[2];
dstRowPtr[1] = srcRowPtr[1];
dstRowPtr[2] = temp;
srcRowPtr += srcIncrement;
dstRowPtr += dstIncrement;
}
}
PBoolean PStandardColourConverter::SwapRedAndBlue(const BYTE * srcFrameBuffer,
BYTE * dstFrameBuffer,
PINDEX * bytesReturned,
unsigned srcIncrement,
unsigned dstIncrement) const
{
if ((dstFrameWidth != srcFrameWidth) || (dstFrameHeight != srcFrameHeight))
return PFalse;
unsigned srcRowSize = srcFrameBytes/srcFrameHeight;
const BYTE * srcRowPtr = srcFrameBuffer;
unsigned dstRowSize = dstFrameBytes/dstFrameHeight;
BYTE * dstRowPtr = dstFrameBuffer;
if (verticalFlip) {
dstRowPtr += dstFrameHeight*dstRowSize;
if (srcFrameBuffer == dstFrameBuffer) {
PBYTEArray tempRow(PMAX(srcRowSize, dstRowSize));
unsigned halfHeight = (srcFrameHeight+1)/2;
for (unsigned y = 0; y < halfHeight; y++) {
dstRowPtr -= dstRowSize;
SwapRedAndBlueRow(dstRowPtr, tempRow.GetPointer(), dstFrameWidth, srcIncrement, dstIncrement);
SwapRedAndBlueRow(srcRowPtr, dstRowPtr, srcFrameWidth, srcIncrement, dstIncrement);
memcpy((BYTE *)srcRowPtr, tempRow, srcRowSize);
srcRowPtr += srcRowSize;
}
}
else {
for (unsigned y = 0; y < srcFrameHeight; y++) {
dstRowPtr -= dstRowSize;
SwapRedAndBlueRow(srcRowPtr, dstRowPtr, srcFrameWidth, srcIncrement, dstIncrement);
srcRowPtr += srcRowSize;
}
}
}
else {
for (unsigned y = 0; y < srcFrameHeight; y++) {
SwapRedAndBlueRow(srcRowPtr, dstRowPtr, srcFrameWidth, srcIncrement, dstIncrement);
srcRowPtr += srcRowSize;
dstRowPtr += dstRowSize;
}
}
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
return PTrue;
}
PSTANDARD_COLOUR_CONVERTER(RGB24,BGR24)
{
return SwapRedAndBlue(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, 3);
}
PSTANDARD_COLOUR_CONVERTER(BGR24,RGB24)
{
return SwapRedAndBlue(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, 3);
}
PSTANDARD_COLOUR_CONVERTER(RGB24,BGR32)
{
return SwapRedAndBlue(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, 4);
}
PSTANDARD_COLOUR_CONVERTER(BGR24,RGB32)
{
return SwapRedAndBlue(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, 4);
}
PSTANDARD_COLOUR_CONVERTER(RGB32,BGR24)
{
return SwapRedAndBlue(srcFrameBuffer, dstFrameBuffer, bytesReturned, 4, 3);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -