全部博文(584)
分类: WINDOWS
2012-04-18 14:02:08
1.在DirectDraw中创建YUV表面
与一般表面不同的是,创建YUV表面时需要指定象素格式,并指定YUV数据的FourCC码,关于FourCC码可以参考微软MSDN站点上的说明,下面是具体的创建方法:(以YUV4:2:0格式为例,其中drawwidth和drawheight是欲显示图像的宽度和高度,以象素为单位)
LPDIRECTDRAW7
lpDD; //
DirectDraw 对象指针
LPDIRECTDRAWSURFACE7
lpDDSPrimary; // DirectDraw
主表面指针
LPDIRECTDRAWSURFACE7
lpDDSOffScr; // DirectDraw
离屏表面指针
DDSURFACEDESC2 ddsd; //
DirectDraw 表面描述
// 创建DirectCraw对象
if (DirectDrawCreateEx(NULL,
(VOID**)&lpDD, IID_IDirectDraw7, NULL) !=
DD_OK)
{
//MessageBox("Error Create
DDraw.");
return FALSE;
}
// 设置协作层
if
(lpDD->SetCooperativeLevel(hWnd,
DDSCL_NORMAL
| DDSCL_NOWINDOWCHANGES) != DD_OK)
{
//MessageBox("Error Create
Level.", s);
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)
{
//MessageBox("Error Create
Primary Surface.", s);
return FALSE;
}
LPDIRECTDRAWCLIPPER pcClipper; //
Cliper
if( lpDD->CreateClipper( 0,
&pcClipper, NULL ) != DD_OK )
return FALSE;
if(
pcClipper->SetHWnd( 0, hWnd ) != DD_OK )
{
pcClipper->Release();
return FALSE;
}
if(
lpDDSPrimary->SetClipper( pcClipper ) != DD_OK
)
{
pcClipper->Release();
return FALSE;
}
// Done with
clipper
pcClipper->Release();
// 创建YUV表面
ZeroMemory(&ddsd,
sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.ddsCaps.dwCaps =
DDSCAPS_OFFSCREENPLAIN;
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |
DDSD_WIDTH | DDSD_PIXELFORMAT;
ddsd.dwWidth = drawwidth;
ddsd.dwHeight = drawheight;
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)
{
//MessageBox("Error Create Off
Surface.", s);
return FALSE;
}
2.将解码得到的YUV数据拷贝到YUV表面
设解码得到的YUV数据的指针分别是Y,U,V, 每行数据长度为BPS,具体拷贝代码如下,这里需要特别注意每拷一行都要对写指针加ddsd.lPitch(对于Y)或ddsd.lPitch/2(对于UV):
LPBYTE lpSurf = (LPBYTE)ddsd.lpSurface;
LPBYTE PtrY = Y;
LPBYTE PtrU = U;
LPBYTE PtrV = V;
do {
ddRval =
lpDDSOffScr->Lock(NULL,&ddsd,DDLOCK_WAIT
| DDLOCK_WRITEONLY,NULL);
} while(ddRval == DDERR_WASSTILLDRAWING);
if(ddRval != DD_OK)
return 1;
// 填充离屏表面
if(lpSurf)
{
for (int
i=0;i Height;i++)
{
memcpy(lpSurf,
PtrY, ddsd.dwWidth);
PtrY +=
BpS;
lpSurf +=
ddsd.lPitch;
}
for (int
i=0;i Height/2;i++)
{
memcpy(lpSurf,
PtrV, ddsd.dwWidth/2);
PtrV +=
BpS;
lpSurf +=
ddsd.lPitch/2;
}
for (int
i=0;i Height/2;i++)
{
memcpy(lpSurf,
PtrU, ddsd.dwWidth/2);
PtrU +=
BpS;
lpSurf +=
ddsd.lPitch/2;
}
}
lpDDSOffScr->Unlock(NULL);
3.YUV表面的显示
现在就可以直接将YUV表面Blt到主表面或后备表面进行显示了:(设lpDDSBack为后备表面)
ddRval = lpDDSBack->Blt(NULL, lpDDSOffScr, NULL, DDBLT_WAIT, NULL);
这样就实现了YUV数据的显示,对比发现使用DirectDraw直接进行YUV数据显示,CPU占用率降低了一半。