📄 vconvert.cxx
字号:
return RGBtoYUV420P(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, TRUE);
}
PSTANDARD_COLOUR_CONVERTER(RGB32F,YUV420P)
{
return RGBtoYUV420P(srcFrameBuffer, dstFrameBuffer, bytesReturned, 4, TRUE);
}
// Consider a YUV422P image of 8x2 pixels.
//
// A plane of Y values A B C D E F G H
// I J K L M N O P
//
// A plane of U values 1 . 2 . 3 . 4 .
// 5 . 6 . 7 . 8 .
//
// A plane of V values 1 . 2 . 3 . 4 .
// 5 . 6 . 7 . 8 .
//
// YUV422 is stored as Y U Y V
// thus, a 4x4 image requires 32 bytes of storage.
//
// Image has two possible transformations.
// padded (src smaller than dst)
// subsampled and padded (src bigger than dst)
void PStandardColourConverter::ResizeYUV422(const BYTE * src, BYTE * dest) const
{
DWORD *result = (DWORD *)dest;
DWORD black = (DWORD)(BLACK_U<<24) + (BLACK_Y<<16) + (BLACK_U<<8) + BLACK_Y;
unsigned maxIndex = dstFrameWidth*dstFrameHeight/2;
for (unsigned i = 0; i < maxIndex; i++)
*result++ = black;
if ( (dstFrameWidth*dstFrameHeight) > (srcFrameWidth*srcFrameHeight) ) {
//dest is bigger than the source. No subsampling.
//Place the src in the middle of the destination.
unsigned yOffset = dstFrameHeight - srcFrameHeight;
unsigned xOffset = dstFrameWidth - srcFrameWidth;
BYTE *s_ptr,*d_ptr;
d_ptr = (yOffset * dstFrameWidth) + xOffset + dest;
s_ptr = (BYTE *)src;
for (unsigned y = 0; y < srcFrameHeight; y++) {
memcpy(d_ptr,s_ptr, srcFrameWidth*2);
d_ptr += 2*dstFrameWidth;
s_ptr += 2*srcFrameWidth;
}
} else {
// source is bigger than the destination.
//
unsigned subSample = 1 + (srcFrameHeight/dstFrameHeight) ;
unsigned yOffset = dstFrameHeight - (srcFrameHeight/subSample);
unsigned xOffset = dstFrameWidth - (srcFrameWidth/subSample);
unsigned subSample2 = subSample*2;
DWORD *s_ptr = (DWORD * )src;
DWORD *d_ptr = (DWORD *) dest + ((yOffset * dstFrameWidth) + xOffset)/4 ;
DWORD *sl_ptr, *dl_ptr;
for (unsigned y = 0; y < srcFrameHeight; y+= subSample) {
sl_ptr = s_ptr;
dl_ptr = d_ptr;
for (unsigned x = 0; x < srcFrameWidth; x+= subSample2) {
*dl_ptr++ = *sl_ptr;
sl_ptr += subSample;
}
d_ptr += dstFrameWidth/2;
s_ptr += srcFrameWidth*subSample/2;
}
}
}
PSTANDARD_COLOUR_CONVERTER(YUV422,YUV422)
{
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
if (srcFrameBuffer == dstFrameBuffer)
return TRUE;
if ((srcFrameWidth == dstFrameWidth) && (srcFrameHeight == dstFrameHeight))
memcpy(dstFrameBuffer,srcFrameBuffer,srcFrameWidth*srcFrameHeight*2);
else
ResizeYUV422(srcFrameBuffer, dstFrameBuffer);
return TRUE;
}
///No resize here.
//Colour format change only, YUV422 is turned into YUV420P.
static void Yuv422ToYuv420P(unsigned dstFrameWidth, unsigned dstFrameHeight,
const BYTE * srcFrame, BYTE * dstFrame)
{
unsigned a,b;
BYTE *u,*v;
const BYTE * s = srcFrame;
BYTE * y = dstFrame;
u = y + (dstFrameWidth * dstFrameHeight);
v = u + (dstFrameWidth * dstFrameHeight / 4);
for (a = 0; a < dstFrameHeight; a+=2) {
for (b = 0; b < dstFrameWidth; b+=2) {
*(y++) = *(s++);
*(u++) = *(s++);
*(y++) = *(s++);
*(v++) = *(s++);
}
for (b = 0; b < dstFrameWidth; b+=2) {
*(y++) = *(s++);
s++;
*(y++) = *(s++);
s++;
}
}
}
PSTANDARD_COLOUR_CONVERTER(YUV422,YUV420P)
{
if (srcFrameBuffer == dstFrameBuffer)
return FALSE;
if ((srcFrameWidth==dstFrameWidth) && (srcFrameHeight==dstFrameHeight))
Yuv422ToYuv420P(srcFrameWidth, srcFrameHeight, srcFrameBuffer, dstFrameBuffer);
else {
//do a resize. then convert to yuv420p.
BYTE * intermed = intermediateFrameStore.GetPointer(dstFrameWidth*dstFrameHeight*2);
ResizeYUV422(srcFrameBuffer, intermed);
Yuv422ToYuv420P(dstFrameWidth, dstFrameHeight, intermed, dstFrameBuffer);
}
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
return TRUE;
}
#define LIMIT(x) (unsigned char) (((x > 0xffffff) ? 0xff0000 : ((x <= 0xffff) ? 0 : x & 0xff0000)) >> 16)
BOOL PStandardColourConverter::YUV420PtoRGB(const BYTE * srcFrameBuffer,
BYTE * dstFrameBuffer,
PINDEX * bytesReturned,
unsigned rgbIncrement,
BOOL flipVertical) const
{
if (srcFrameBuffer == dstFrameBuffer)
return FALSE;
BYTE *dstImageFrame;
unsigned int nbytes = srcFrameWidth*srcFrameHeight;
const BYTE *yplane = srcFrameBuffer; // 1 byte Y (luminance) for each pixel
const BYTE *uplane = yplane+nbytes; // 1 byte U for a block of 4 pixels
const BYTE *vplane = uplane+(nbytes >> 2); // 1 byte V for a block of 4 pixels
unsigned int pixpos[4] = { 0, 1, srcFrameWidth, srcFrameWidth+1 };
unsigned int x, y, p;
long int yvalue;
long int cr, cb, rd, gd, bd;
long int l, r, g, b;
if(flipVertical) {
dstImageFrame = dstFrameBuffer + ((srcFrameHeight-2) * srcFrameWidth * rgbIncrement);
pixpos[0] = srcFrameWidth;
pixpos[1] = srcFrameWidth +1;
pixpos[2] = 0;
pixpos[3] = 1;
}
else
dstImageFrame = dstFrameBuffer;
for (y = 0; y < srcFrameHeight; y += 2)
{
for (x = 0; x < srcFrameWidth; x += 2)
{
// The RGB value without luminance
cr = *uplane-128;
cb = *vplane-128;
rd = 104635*cb; // 106986*cb
gd = -25690*cr-53294*cb; // -26261*cr + -54496*cb
bd = 132278*cr; // 135221*cr
// Add luminance to each of the 4 pixels
for (p = 0; p < 4; p++)
{
yvalue = *(yplane+pixpos[p])-16;
if (yvalue < 0) yvalue = 0;
l = 76310*yvalue;
r = l+rd;
g = l+gd;
b = l+bd;
*(dstImageFrame + rgbIncrement*pixpos[p]) = LIMIT(b);
*(dstImageFrame + rgbIncrement*pixpos[p]+1) = LIMIT(g);
*(dstImageFrame + rgbIncrement*pixpos[p]+2) = LIMIT(r);
if (rgbIncrement == 4)
*(dstImageFrame + 4*pixpos[p]+3) = 0;
}
yplane += 2;
dstImageFrame += rgbIncrement*2;
uplane++;
vplane++;
}
yplane += srcFrameWidth;
if (flipVertical)
dstImageFrame -= 3*rgbIncrement*srcFrameWidth;
else
dstImageFrame += rgbIncrement*srcFrameWidth;
}
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
return TRUE;
}
PSTANDARD_COLOUR_CONVERTER(YUV420P,RGB24)
{
return YUV420PtoRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, FALSE);
}
PSTANDARD_COLOUR_CONVERTER(YUV420P,RGB32)
{
return YUV420PtoRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned, 4, FALSE);
}
PSTANDARD_COLOUR_CONVERTER(YUV420P,RGB24F)
{
return YUV420PtoRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned, 3, TRUE);
}
PSTANDARD_COLOUR_CONVERTER(YUV420P,RGB32F)
{
return YUV420PtoRGB(srcFrameBuffer, dstFrameBuffer, bytesReturned, 4, TRUE);
}
PSTANDARD_COLOUR_CONVERTER(RGB24,RGB32)
{
if ((dstFrameWidth != srcFrameWidth) || (dstFrameHeight != srcFrameHeight))
return FALSE;
// Go from bottom to top so can do in place conversion
const BYTE * src = srcFrameBuffer+srcFrameBytes-1;
BYTE * dst = dstFrameBuffer+dstFrameBytes-1;
for (unsigned x = 0; x < srcFrameWidth; x++) {
for (unsigned y = 0; y < srcFrameHeight; y++) {
*dst-- = 0;
for (unsigned p = 0; p < 3; p++)
*dst-- = *src--;
}
}
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
return TRUE;
}
PSTANDARD_COLOUR_CONVERTER(RGB32,RGB24)
{
if ((dstFrameWidth != srcFrameWidth) || (dstFrameHeight != srcFrameHeight))
return FALSE;
const BYTE * src = srcFrameBuffer;
BYTE * dst = dstFrameBuffer;
for (unsigned x = 0; x < srcFrameWidth; x++) {
for (unsigned y = 0; y < srcFrameHeight; y++) {
for (unsigned p = 0; p < 3; p++)
*dst++ = *src++;
src++;
}
}
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
return TRUE;
}
// Consider a YUV420P image of 8x2 pixels.
//
// A plane of Y values A B C D E F G H
// I J K L M N O P
//
// A plane of U values 1 2 3 4
// A plane of V values 1 2 3 4 ....
//
// The U1/V1 samples correspond to the ABIJ pixels.
// U2/V2 samples correspond to the CDKL pixels.
//
// Consider a YUV411P image of 8x2 pixels.
//
// A plane of Y values as before.
//
// A plane of U values 1 2
// 3 4
//
// A plane of V values 1 2
// 3 4
//
// The U1/V1 samples correspond to the ABCD pixels.
// U2/V2 samples correspond to the EFGH pixels.
//
// I choose to reoganize the U and V samples by using
// using U1 for ABCD, U3 for EFGH, U2 for IJKL, U4 for MNOP
//
// Possibly discarding U2/U4 completely, or using the
// average of U1 and U2 might be easier for compression
//
// TODO:
//
// - Inplace converter
// - Resizing / padding / scaling converter
//
PSTANDARD_COLOUR_CONVERTER(YUV420P,YUV411P)
{
if (srcFrameBuffer == dstFrameBuffer)
return FALSE;
if ((dstFrameWidth != srcFrameWidth) || (dstFrameHeight != srcFrameHeight))
return FALSE;
// Copy over the Y plane.
memcpy(dstFrameBuffer, srcFrameBuffer, srcFrameWidth*srcFrameHeight);
unsigned linewidth = dstFrameWidth / 4;
// Source data is the start of the U plane
const BYTE* src = srcFrameBuffer + srcFrameWidth * srcFrameHeight;
// Two output lines at a time
BYTE *dst0 = dstFrameBuffer + dstFrameWidth * dstFrameHeight;
BYTE *dst1 = dst0 + linewidth;
unsigned x, y;
// U plane
for (y = 0; y < dstFrameHeight; y += 2) {
for (x = 0; x < dstFrameWidth; x += 4) {
*dst0++ = *src++;
*dst1++ = *src++;
}
// Skip over the 2nd line we already did.
dst0 += linewidth;
dst1 = dst0 + linewidth;
}
// Source data is the start of the U plane
src = srcFrameBuffer + srcFrameWidth * srcFrameHeight * 5 / 4;
// Two output lines at a time
dst0 = dstFrameBuffer + dstFrameWidth * dstFrameHeight * 5 / 4;
dst1 = dst0 + linewidth;
// V plane
for (y = 0; y < dstFrameHeight; y += 2) {
for (x = 0; x < dstFrameWidth; x += 4) {
*dst0++ = *src++;
*dst1++ = *src++;
}
// Skip over the 2nd line we already did.
dst0 += linewidth;
dst1 = dst0 + linewidth;
}
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
return TRUE;
}
// YUV411P to YUV420P conversion
//
// Consider YUV411P U plane (. = pixel) :
//
// A... B... C... D...
// E... F... G... H...
// I... J... K... L...
// M... N... O... P...
//
// We map this to a YUV420P plane by
// discarding odd rows, and doubling up
// the even row samples:
//
// A.A. B.B. C.C. D.D.
// .... .... .... ....
// I.I. J.J. K.K. L.L.
// .... .... .... ....
//
// TODO:
//
// - Inplace converter
// - Resizing / padding / scaling converter
//
PSTANDARD_COLOUR_CONVERTER(YUV411P,YUV420P)
{
if (srcFrameBuffer == dstFrameBuffer)
return FALSE;
if ((dstFrameWidth != srcFrameWidth) || (dstFrameHeight != srcFrameHeight))
return FALSE;
// Copy over the Y plane.
memcpy(dstFrameBuffer, srcFrameBuffer, srcFrameWidth*srcFrameHeight);
unsigned linewidth = dstFrameWidth / 4;
// Source data is the start of the U plane
const BYTE* src = srcFrameBuffer + srcFrameWidth * srcFrameHeight;
// Output line
BYTE *dst0 = dstFrameBuffer + dstFrameWidth * dstFrameHeight;
unsigned x, y;
// U plane
for (y = 0; y < dstFrameHeight; y += 2) {
for (x = 0; x < dstFrameWidth; x += 4) {
// Double up the horizontal samples
*dst0++ = *src;
*dst0++ = *src++;
}
// Skip over the 2nd line we are decimating
src += linewidth;
}
// Source data is the start of the U plane
src = srcFrameBuffer + srcFrameWidth * srcFrameHeight * 5 / 4;
// Output line
dst0 = dstFrameBuffer + dstFrameWidth * dstFrameHeight * 5 / 4;
// V plane
for (y = 0; y < dstFrameHeight; y += 2) {
for (x = 0; x < dstFrameWidth; x += 4) {
// Double up the samples horizontal samples
*dst0++ = *src;
*dst0++ = *src++;
}
// Skip over the 2nd source line we already did.
src += linewidth;
}
if (bytesReturned != NULL)
*bytesReturned = dstFrameBytes;
return TRUE;
}
// End Of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -