📄 yuv.c
字号:
#include "yuv.h"
#include "mathutil.h"
// do NOT put +0.5 's in the ftoi's !
/**************************************************************/
static void RGB_to_YUVf(float Red,float Green,float Blue,float *Y,float *U,float *V)
{
*Y = 0.2989f*Red + 0.5867f*Green + 0.1144f*Blue;
*U = -0.1687f*Red - 0.3312f*Green + 0.5000f*Blue;
*V = 0.5000f*Red - 0.4183f*Green - 0.0816f*Blue;
}
static void YUV_to_RGBf(float Y,float U,float V,float *R,float *G,float *B)
{
*R = Y + 1.4022f*V;
*G = Y - 0.3456f*U - 0.7145f*V;
*B = Y + 1.7710f*U ;
}
void BGRb_to_YUVf(ubyte *BGRptr,float *Y,float *U,float *V)
{
int R,G,B;
B = BGRptr[0];
G = BGRptr[1];
R = BGRptr[2];
RGB_to_YUVf(R,G,B,Y,U,V);
}
static void Yf_to_BGRb(float y,float ruv,float guv,float buv,ubyte * bgr)
{
int z;
z = ftoi(y+buv); bgr[0] = clamp255(z);
z = ftoi(y+guv); bgr[1] = clamp255(z);
z = ftoi(y+ruv); bgr[2] = clamp255(z);
}
void YUV_122toBGRbytes(float *Yptr0,float *Yptr1,float *Uptr,float *Vptr,ubyte *BGRptr,int width)
{
ubyte *BGRptr2;
int x;
BGRptr2 = BGRptr + (width*3);
for(x=(width>>1);x--;)
{
float u,v;
float ruv,guv,buv;
u = *Uptr++; v = *Vptr++;
ruv = + 1.4022f*v;
guv = - 0.3456f*u - 0.7145f*v;
buv = + 1.7710f*u;
Yf_to_BGRb(*Yptr0++,ruv,guv,buv,BGRptr ); BGRptr += 3;
Yf_to_BGRb(*Yptr0++,ruv,guv,buv,BGRptr ); BGRptr += 3;
Yf_to_BGRb(*Yptr1++,ruv,guv,buv,BGRptr2); BGRptr2 += 3;
Yf_to_BGRb(*Yptr1++,ruv,guv,buv,BGRptr2); BGRptr2 += 3;
}
}
static uword rtablebase[512],gtablebase[512],btablebase[512];
static uword *rtable = rtablebase+128,*gtable=gtablebase+128,*btable=btablebase+128;
uword INLINE packyrgb(int y,int r,int g,int b)
{
return rtable[y+r] | gtable[y+g] | btable[y+b];
}
static bool havetables = false;
static void maketables(int Mode)
{
int p,q,r,g,b;
for(p=0;p<512;p++)
{
q = clamp255(p-128);
r = b = q>>3;
switch(Mode)
{
case DRIVER_MODE_565:
g = q>>2;
r<<=11;
break;
case DRIVER_MODE_555:
g = q>>3;
r<<=10;
break;
}
g<<=5;
rtablebase[p] = r;
gtablebase[p] = g;
btablebase[p] = b;
}
havetables = true;
}
void YUV_122toDriver(float *Yptr0,float *Yptr1,float *Uptr,float *Vptr,Driver_Window * Driver,int width)
{
uword *p0,*p1;
int x;
if ( Driver->UserY >= Driver->Height )
return;
if ( ! havetables )
maketables(Driver->Mode);
assert( (int)Driver->Width >= width );
p0 = (uword *)(Driver->Buffer + Driver->Stride * Driver->UserY);
p1 = p0 + (Driver->Stride>>1);
Driver->UserY += 2;
/**
should do this all in assembly
the biggest hurt is in the ftoi's
----
@@
one method would be to do the YUV in 755 in which case we
could do a direct lookup to get the 555 RGB result. Doing 755
does hurt psnr a bit (26.9 instead of 27.2).
The path then is like :
u = clamp31[ftoi(*Uptr++)];
v = clamp31[ftoi(*Vptr++)];
uv = (u<<5) | v;
y = ftoi(*Yptr0++); *p0++ = maintable[ clamp128[y] | uv ]
y = ftoi(*Yptr0++); *p0++ = maintable[ clamp128[y] | uv ]
y = ftoi(*Yptr1++); *p1++ = maintable[ clamp128[y] | uv ]
y = ftoi(*Yptr1++); *p1++ = maintable[ clamp128[y] | uv ]
we would do:
6 ftoi's
6 small table lookups
4 big table lookups
as opposed to the current:
7 ftoi's
12 small table lookups
4 fmuls
actually that's very tasty, and doesn't cost any visual
quality, since 755 YUV is way better than 555 RGB
In the end, the ftoi's are by far the biggest problem,
at about 100 clocks each (on my K6)
**/
for(x=(width>>1);x--;)
{
float u,v;
int y,r,g,b;
uword *rptr,*gptr,*bptr;
u = *Uptr++;
v = *Vptr++;
r = ftoi(1.4022f*v);
g =-ftoi(0.3456f*u + 0.7145f*v);
b = ftoi(1.7710f*u);
rptr = rtable + r;
gptr = gtable + g;
bptr = btable + b;
y = ftoi(*Yptr0++); *p0++ = rptr[y] | gptr[y] | bptr[y];
y = ftoi(*Yptr0++); *p0++ = rptr[y] | gptr[y] | bptr[y];
y = ftoi(*Yptr1++); *p1++ = rptr[y] | gptr[y] | bptr[y];
y = ftoi(*Yptr1++); *p1++ = rptr[y] | gptr[y] | bptr[y];
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -