系统架构(暂时不处理音频通话部分):
获取摄像头数据-->编码-->传输->解码->播放
1.获取摄像头数据
通过DShow已经可以得到16RGB或者24RGB(略)
2.转化数据到YUV420
// Conversion from RGB to YUV420
int RGB2YUV_YR[256], RGB2YUV_YG[256], RGB2YUV_YB[256];
int RGB2YUV_UR[256], RGB2YUV_UG[256], RGB2YUV_UBVR[256];
int RGB2YUV_VG[256], RGB2YUV_VB[256];
void InitLookupTable()
{
int i;
for (i = 0; i < 256; i++) RGB2YUV_YR[i] = (float)65.481 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_YG[i] = (float)128.553 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_YB[i] = (float)24.966 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_UR[i] = (float)37.797 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_UG[i] = (float)74.203 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_VG[i] = (float)93.786 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_VB[i] = (float)18.214 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_UBVR[i] = (float)112 * (i<<8);
}
//
// Convert from RGB24 to YUV420
//
int ConvertRGB2YUV(int w,int h,unsigned char *bmp,unsigned int *yuv)
{
unsigned int *u,*v,*y,*uu,*vv;
unsigned int *pu1,*pu2,*pu3,*pu4;
unsigned int *pv1,*pv2,*pv3,*pv4;
unsigned char *r,*g,*b;
int i,j;
uu=new unsigned int[w*h];
vv=new unsigned int[w*h];
if(uu==NULL || vv==NULL)
return 0;
y=yuv;
u=uu;
v=vv;
// Get r,g,b pointers from bmp image data....
r=bmp;
g=bmp+1;
b=bmp+2;
//Get YUV values for rgb values...
for(i=0;i<h;i++)
{
for(j=0;j<w;j++)
{
*y++=( RGB2YUV_YR[*r] +RGB2YUV_YG[*g]+RGB2YUV_YB[*b]+1048576)>>16;
*u++=(-RGB2YUV_UR[*r] -RGB2YUV_UG[*g]+RGB2YUV_UBVR[*b]+8388608)>>16;
*v++=( RGB2YUV_UBVR[*r]-RGB2YUV_VG[*g]-RGB2YUV_VB[*b]+8388608)>>16;
r+=3;
g+=3;
b+=3;
}
}
这是网上流传的经典的转换代码,按理应该没错,但是起初用的时候根本无法正确转换,后来将unsigned int全部改为unsigned char,可以转换,但是图像是倒立的,并且颜色偏绿,之所以说经典是效率高。
下面看另一种转换:
void ReadBmp(unsigned char *RGB,FILE *fp)//便于调试用本地图片载入数据
{
int i,j;
unsigned char temp;
fseek(fp,54, SEEK_SET);
fread(RGB+WIDTH*HEIGHT*3, 1, WIDTH*HEIGHT*3, fp);//读取
for(i=HEIGHT-1,j=0; i>=0; i--,j++)//调整顺序
{
memcpy(RGB+j*WIDTH*3,RGB+WIDTH*HEIGHT*3+i*WIDTH*3,WIDTH*3);
}
//这里做了顺序调整,所以出来的图片是正常的方向,可见第一种方法没有进行数据顺序转换
//顺序调整
for(i=0; (unsigned int)i < WIDTH*HEIGHT*3; i+=3)
{
temp = RGB[i];
RGB[i] = RGB[i+2];
RGB[i+2] = temp;
}
}
void Convert(unsigned char *RGB, unsigned char *YUV)
{
//变量声明
unsigned int i,x,y,j;
unsigned char *Y = NULL;
unsigned char *U = NULL;
unsigned char *V = NULL;
Y = YUV;
U = YUV + WIDTH*HEIGHT;
V = U + ((WIDTH*HEIGHT)>>2);
for(y=0; y < HEIGHT; y++)
for(x=0; x < WIDTH; x++)
{
j = y*WIDTH + x;
i = j*3;
Y[j] = (unsigned char)(DY(RGB[i], RGB[i+1], RGB[i+2]));
if(x%2 == 1 && y%2 == 1)
{
j = (WIDTH>>1) * (y>>1) + (x>>1);
//上面i仍有效
U[j] = (unsigned char)
((DU(RGB[i ], RGB[i+1], RGB[i+2]) +
DU(RGB[i-3], RGB[i-2], RGB[i-1]) +
DU(RGB[i -WIDTH*3], RGB[i+1-WIDTH*3], RGB[i+2-WIDTH*3]) +
DU(RGB[i-3-WIDTH*3], RGB[i-2-WIDTH*3], RGB[i-1-WIDTH*3]))/4);
V[j] = (unsigned char)
((DV(RGB[i ], RGB[i+1], RGB[i+2]) +
DV(RGB[i-3], RGB[i-2], RGB[i-1]) +
DV(RGB[i -WIDTH*3], RGB[i+1-WIDTH*3], RGB[i+2-WIDTH*3]) +
DV(RGB[i-3-WIDTH*3], RGB[i-2-WIDTH*3], RGB[i-1-WIDTH*3]))/4);
}
}
}
第二种方法OK,转换成YUV420以后和原先的BMP对照,肉眼几乎分辨不出有什么失真。但是……效率太低下了。两种转换在相同的模拟器上跑,第一种大约是320--350ms,而第二种竟然达到了惊人的6000Ms.
效果对比图:
第二种(不失真,效率低) 第一种(失真,效率高)
接下来的时间,尽快解决第一种转换方法的偏差。
OK~没想到就用了几分钟调整了顺序,第一种方法就搞定,貌似显示的效果比第二种佳。
看图:
11.13
预览和视频捕获能支持144X176 120X160 240X320
图片拍摄就只能240X320 480X640
then,截图