我现在要做的事情是将摄像头传送过来的视频信息转成YUV420格式的输出。 现在用相机的API能得到每一帧图像的800*600的24位RGB值数据。
然后我用RGB->YUV的算法将RGB转成YV12,再显示出来,可是显示得图片显示出来总是跟原始的图片不符。
代码如下,请高手帮忙看看,感激不尽~
1---------------------从JPEG解码得到RGB值 , 解码函数是相机厂商提供的。
CYNET_JpegDecode((BYTE*)pImageData,pFh->len,(BYTE*)pRgbData,&jl,&jw,&jh,&jbit,&jpitch);
unsigned char * rgbdata = (unsigned char*)pRgbData; 
unsigned char *YUV = NULL;
rgb2yuv_convert(YUV, rgbdata,jw,jh);
2------------RGB->YUV解码 并存储一张YUV图片-----------------------
void rgb2yuv_convert(unsigned char *YUV, unsigned char *RGB, unsigned int width, unsigned int height)   
{
//声明变量
unsigned int i,x,y,j;
unsigned char *Y = NULL;
unsigned char *U = NULL;
unsigned char *V = NULL; int line_width = width * 3;
int lengthyuv =  width*height + ((width*height)>>1);
YUV = (unsigned char *)malloc(lengthyuv); i = j = 0;
Y = YUV;
V = YUV + width*height;
U = V + ((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仍然有效
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);
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);
}

}
存储一帧YUV图片
FILE *fp;
if ((fp = fopen("1.yuv","w")) == 0)
{
printf("open failed!");
exit(1);
}
fwrite(YUV, 1, lengthyuv, fp);
fclose(fp);
free(YUV);
}
3---------------------------------显示图片的代码----------------
#define FILE_HEIGHT            600
#define FILE_WIDTH            800#define DRAW_TOP            0
#define DRAW_LEFT            0
#define DRAW_HEIGHT            600
#define DRAW_WIDHT            800BOOL DrawYV12(HWND hWnd)
{
LPDIRECTDRAW            lpDD = NULL;                // DirectDraw 对象指针
LPDIRECTDRAWSURFACE     lpDDSPrimary = NULL;        // DirectDraw 主表面指针
LPDIRECTDRAWSURFACE     lpDDSOffScr = NULL;        // DirectDraw 离屏表面指针
DDSURFACEDESC            ddsd;                // DirectDraw 表面描述
RECT                    rctDest;            // 目标区域
RECT                    rctSour;            // 源区域
HRESULT                    ddRval;                // DirectDraw 函数返回值
LPDIRECTDRAWCLIPPER pMyClipper = NULL; 
// 创建DirectCraw对象
if (DirectDrawCreate(NULL, &lpDD, NULL) != DD_OK) 
return FALSE; // 设置协作层
if (lpDD->SetCooperativeLevel(hWnd,
DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES) != DD_OK)
return FALSE; // 创建主表面
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL) != DD_OK)
return FALSE; // 创建离屏表面对象
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; //DDSCAPS_OVERLAY DDSCAPS_OFFSCREENPLAIN;
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
ddsd.dwWidth = DRAW_WIDHT;
ddsd.dwHeight = DRAW_HEIGHT;
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
ddsd.ddpfPixelFormat.dwFlags  = DDPF_FOURCC | DDPF_YUV ;
ddsd.ddpfPixelFormat.dwFourCC = MAKEFOURCC('Y','V','1','2');
ddsd.ddpfPixelFormat.dwYUVBitCount = 8;
if (lpDD->CreateSurface(&ddsd, &lpDDSOffScr, NULL) != DD_OK)
return FALSE;
ddRval = lpDD->CreateClipper(0, &pMyClipper, NULL);

ddRval = pMyClipper->SetHWnd(0, hWnd);

// 把剪贴板加到窗口上去
ddRval = lpDDSPrimary->SetClipper(pMyClipper);
// 加载yv12图像文件
FILE * f = fopen("1.yuv","rb");
LPBYTE lpYV12 = new BYTE[FILE_WIDTH * FILE_HEIGHT * 3 / 2];
UINT iLen = fread(lpYV12, 1, FILE_WIDTH * FILE_HEIGHT * 3 / 2, f);
fclose(f);
LPBYTE lpY = lpYV12;
LPBYTE lpV = lpYV12 + FILE_WIDTH * FILE_HEIGHT;
LPBYTE lpU = lpYV12 + FILE_WIDTH * FILE_HEIGHT * 5 / 4; ddRval = lpDDSOffScr->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_WRITEONLY,NULL);
while(ddRval == DDERR_WASSTILLDRAWING);
if(ddRval != DD_OK)
return FALSE;
LPBYTE lpSurf = (LPBYTE)ddsd.lpSurface;
LPBYTE lpY1 = lpSurf;
LPBYTE lpV1 = lpSurf + ddsd.lPitch * FILE_HEIGHT;
LPBYTE lpU1 = lpV1 + ddsd.lPitch  * FILE_HEIGHT / 4;
int nOffset = DRAW_TOP*FILE_WIDTH+DRAW_LEFT; // 填充离屏表面
if(lpSurf)
{
int i = 0; // fill Y data
lpY += nOffset;
for(i=0; i<ddsd.dwHeight; i++)
{
memcpy(lpSurf, lpY, ddsd.dwWidth);
lpY += FILE_WIDTH;
lpSurf += ddsd.lPitch;
} // fill V data
lpV += DRAW_TOP * FILE_WIDTH / 4 + DRAW_LEFT / 2;
for(i=0; i<ddsd.dwHeight/2; i++)
{
memcpy(lpSurf, lpV, ddsd.dwWidth / 2);
lpV += FILE_WIDTH / 2;
lpSurf += ddsd.lPitch / 2;
} // fill U data
lpU += DRAW_TOP * FILE_WIDTH / 4 + DRAW_LEFT / 2;
for(i=0; i<ddsd.dwHeight/2; i++)
{
memcpy(lpSurf, lpU, ddsd.dwWidth / 2);
lpU += FILE_WIDTH / 2;
lpSurf += ddsd.lPitch / 2;
}
} lpDDSOffScr->Unlock(NULL); delete lpYV12; // Blt到主表面上
rctSour.left = 0;
rctSour.top = 0;
rctSour.right = ddsd.dwWidth;
rctSour.bottom = ddsd.dwHeight;
GetClientRect(hWnd,&rctDest);
ClientToScreen(hWnd, (LPPOINT)&rctDest.left);
ClientToScreen(hWnd, (LPPOINT)&rctDest.right); ddRval = lpDDSPrimary->Blt(&rctDest, lpDDSOffScr, &rctSour, DDBLT_WAIT, NULL);
while(ddRval == DDERR_WASSTILLDRAWING);
  if(ddRval != DD_OK)
{return FALSE;
}
MessageBox(hWnd,"Draw yv12 image ok","DDraw error", MB_OK);
// 释放DirectDraw对象
if(lpDD != NULL)
{
if(lpDDSPrimary != NULL)
{
lpDDSPrimary->Release();
lpDDSPrimary = NULL;
}
if(lpDDSOffScr != NULL)
{
lpDDSOffScr->Release();
lpDDSOffScr = NULL;
}
lpDD->Release();
lpDD = NULL;
}
return TRUE;
}