Chinaunix首页 | 论坛 | 博客
  • 博客访问: 270431
  • 博文数量: 47
  • 博客积分: 1415
  • 博客等级: 上尉
  • 技术积分: 648
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-01 17:20
文章存档

2011年(1)

2009年(46)

我的朋友

分类:

2009-04-02 14:07:14

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占用率降低了一半。

 

注:

表面分为 主表面、后备缓冲区、离屏表面。此处的yuv表面理解为离屏表面。

阅读(5426) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~