请大家分析一下为什么这个YUV420转RGB32的程序效率如此低下

时间:2022-04-02 17:33:41

#define RGB4Y 1.164
#define B4U 2.018
#define Y2ADD 16

#define G4U 0.391
#define G4V 0.813
#define U2ADD 128

#define R4V 1.596
#define V2ADD 128

#define SCALEBITS 13

#define FIX(x) ((WORD) ((x) * (1L << SCALEBITS) + 0.5))



int g_RGB4Y_Tab[256];

int g_B4U_Tab[256];
int g_G4U_Tab[256];
int g_G4V_Tab[256];
int g_R4V_Tab[256];



void InitColorSpace()
{
for (UINT i = 0; i < 256; i++)
{
g_RGB4Y_Tab[i] = FIX(RGB4Y) * (i - Y2ADD);
g_B4U_Tab[i] = FIX(B4U  ) * (i - U2ADD);
g_G4U_Tab[i] = FIX(G4U  ) * (i - U2ADD);
g_G4V_Tab[i] = FIX(G4V  ) * (i - V2ADD);
g_R4V_Tab[i] = FIX(R4V  ) * (i - V2ADD);
}
}


inline BYTE ClipColorValue(int x)
{
return x < 0 ? 0 : (x > 255 ? 255 : x);
}


inline void YUV420_RGB32_4Pixel(LPBYTE pRGB, LPBYTE pY, LPBYTE pU, LPBYTE pV, UINT Width)
{
int nRGB4Y = 0;
int nB4U   = g_B4U_Tab[pU[0]];
int nG4UV  = g_G4U_Tab[pU[0]] + g_G4V_Tab[pV[0]];
int nR4V   = g_R4V_Tab[pV[0]];


// (0, 0)

nRGB4Y = g_RGB4Y_Tab[pY[0]];

pRGB[0] = ClipColorValue((nRGB4Y + nB4U ) >> SCALEBITS);
pRGB[1] = ClipColorValue((nRGB4Y - nG4UV) >> SCALEBITS);
pRGB[2] = ClipColorValue((nRGB4Y + nR4V ) >> SCALEBITS);
pRGB[3] = 0;


// (0, 1)

nRGB4Y = g_RGB4Y_Tab[pY[1]];

pRGB[4] = ClipColorValue((nRGB4Y + nB4U ) >> SCALEBITS);
pRGB[5] = ClipColorValue((nRGB4Y - nG4UV) >> SCALEBITS);
pRGB[6] = ClipColorValue((nRGB4Y + nR4V ) >> SCALEBITS);
pRGB[7] = 0;


// (1, 0)

nRGB4Y = g_RGB4Y_Tab[pY[Width]];

pRGB[(Width<<2)+0] = ClipColorValue((nRGB4Y + nB4U ) >> SCALEBITS);
pRGB[(Width<<2)+1] = ClipColorValue((nRGB4Y - nG4UV) >> SCALEBITS);
pRGB[(Width<<2)+2] = ClipColorValue((nRGB4Y + nR4V ) >> SCALEBITS);
pRGB[(Width<<2)+3] = 0;


// (1, 1)

nRGB4Y = g_RGB4Y_Tab[pY[Width+1]];

pRGB[(Width<<2)+4] = ClipColorValue((nRGB4Y + nB4U ) >> SCALEBITS);
pRGB[(Width<<2)+5] = ClipColorValue((nRGB4Y - nG4UV) >> SCALEBITS);
pRGB[(Width<<2)+6] = ClipColorValue((nRGB4Y + nR4V ) >> SCALEBITS);
pRGB[(Width<<2)+7] = 0;
}


///////////////////////////////////////////////////////////////////////////////////
//

void YUV420_RGB32(LPBYTE pRGB, LPBYTE pYUV, DWORD Width, DWORD Height)
{
LPBYTE pY = pYUV,   pU = pY + Width * Height,   pV = pU + Width * Height/4;

UINT x, y;
for (y = 0; y < Height; y += 2)
{
for (x = 0; x < Width; x += 2)
{
YUV420_RGB32_4Pixel(pRGB, pY, pU, pV, Width);

pRGB += 8; pY += 2; pU += 1; pV += 1;
}

pRGB += Width<<2;
pY   += Width;
}
}

10 个解决方案

#1


光从算法的角度讲,不考虑汇编优化

#2


到一些开源的项目中去找找优化过的方法吧,比如ffmpeg, ffdshow。

#3


这是xvid中的改写的,只是把它的宏改为inline函数

#4


没人气啊 :(

#5


这个算法还可以,若不考虑汇编也只能这样了, 即使要优化,提高也不会太大。

我觉得有个可以优化的地方,如下:
YUV420_RGB32_4Pixel的调用一次可以处理两行RGB或y。因为yuv420的一行u或v用于两行的y或RGB。如果一次只处理两个pixel,函数调用次数过多,额外消耗就过多。

#6


Bill老兄,不瞒您说,该算法不是一般的慢,我处理CIF格式352x288,25FPS,2.4G CPU占到了35%,我用YUVViewer的cscc.lib中的转换函数转成RGB24,再赋值转成RGB32都不到1%(也就是说0%)。我好纳闷,怎么效率低了几百倍???

#7


顶顶!

#8


你不是说不用汇编优化吗?你怎么知道cscc.lib中也没有用汇编优化?不可比的。我只是说用C也只能做到这个样子了。
我这里有一段sse的优化代码,你需要的话发给你好了。

#9


好的谢谢,fz_fz@tom.com

cscc.lib应该没优化吧,MMX都要对齐的,它好象没要求对齐,况且我还额外做了RGB24转RGB32的赋值,CPU占用率还是特别小。

是不是查表访问内存次数多了?

不过我觉得即使是汇编优化,也不应该有这么大的优势,比方算SAD什么的,也就快个2倍,3倍的。

#10


可以用ipp库试试

#1


光从算法的角度讲,不考虑汇编优化

#2


到一些开源的项目中去找找优化过的方法吧,比如ffmpeg, ffdshow。

#3


这是xvid中的改写的,只是把它的宏改为inline函数

#4


没人气啊 :(

#5


这个算法还可以,若不考虑汇编也只能这样了, 即使要优化,提高也不会太大。

我觉得有个可以优化的地方,如下:
YUV420_RGB32_4Pixel的调用一次可以处理两行RGB或y。因为yuv420的一行u或v用于两行的y或RGB。如果一次只处理两个pixel,函数调用次数过多,额外消耗就过多。

#6


Bill老兄,不瞒您说,该算法不是一般的慢,我处理CIF格式352x288,25FPS,2.4G CPU占到了35%,我用YUVViewer的cscc.lib中的转换函数转成RGB24,再赋值转成RGB32都不到1%(也就是说0%)。我好纳闷,怎么效率低了几百倍???

#7


顶顶!

#8


你不是说不用汇编优化吗?你怎么知道cscc.lib中也没有用汇编优化?不可比的。我只是说用C也只能做到这个样子了。
我这里有一段sse的优化代码,你需要的话发给你好了。

#9


好的谢谢,fz_fz@tom.com

cscc.lib应该没优化吧,MMX都要对齐的,它好象没要求对齐,况且我还额外做了RGB24转RGB32的赋值,CPU占用率还是特别小。

是不是查表访问内存次数多了?

不过我觉得即使是汇编优化,也不应该有这么大的优势,比方算SAD什么的,也就快个2倍,3倍的。

#10


可以用ipp库试试