系統架構(暫時不處理語音通話部分):
擷取網路攝影機資料-->編碼-->傳輸->解碼->播放
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,