视频显示之Directdraw

日期:2014-09-25点击次数:8667

       在监控平台中流的接收,传输,显示,存储这几大功能都缺一不可,由于最近工作中完成的是显示部分的接口功能,于是总结一下与大家分享,主要介绍其中的一种显示方法,即windows下的2D显示之Directdraw。
        DirectDraw是DirectX中提供直接操纵显存、执行硬件映射、硬件覆盖及切换显示页等功能的组件。它不但兼容已有的Windows应用程序和驱动程序,而且还兼容许多显示卡:从简单的SVGA到支持图像剪裁、拉伸和非RGB格式图像的高档显示卡。DirectDrawHAL(hardware-abstraction layer)抽象了显示卡的硬件功能,以设备无关的方式提供了一些以前是设备相关的功能,如多显示页技术、访问并控制显示卡映射寄存器、支持3DZ-Buffer、支持Z-order硬件覆盖、访问图像拉伸硬件,以及同时访问标准显存和控制显存。正因为DirectDraw有这些优点,现在许多基于Windows95/98/NT的游戏程序都使用了DirectDraw;而它的设备无关性使开发者摆脱了繁重的显示卡接口工作,集中精力实现程序的主要功能。DirectX中的DDraw.dll实现了DirectDraw 所需要的函数、对象及其接口。
       下图所示的是Directdraw的整个框架及大致的开发流程,后面部分是具体接口的调用:
 
 
按照上面的流程图,我整理出如下的调用步骤:
1. 在程序中添加ddraw.lib的库
2. 创建DirectDraw对象
LPDIRECTDRAW            m_lpDD; // DirectDraw 对象指针
DirectDrawCreate(NULL, //代表显卡驱动程序的GUID,为NULL表示采样系统默认的驱动程序
&m_lpDD, //IDirectDraw接口对象
NULL);
3. 设置DirectDraw的工作模式
m_lpDD->SetCooperativeLevel(m_hWnd, //与DirectDraw对象关联的窗口句柄
DDSCL_NORMAL);//普通模式DDSCL_NORMAL,独占模式DDSCL_EXCLUSIVE
4. 创建物理屏幕(主表面)
简单的说DirectDraw表面是一个用于存储图像数据的线性内存区域,表面的大小是以象素为单位,用宽和高来定义,所以可以认为表面是一个用来画图的矩形区域。
    主表面:每个DirectDraw都有一个主表面,主表面相当于用户的显示器,它的内容是可见的,是根据显示器的显示模式设定宽和高。
LPDIRECTDRAWSURFACE     m_lpDDSPrimary; // DirectDraw 物理表面指针
DDSURFACEDESC   ddsd;
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS ;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
ddsd.dwBackBufferCount = 1;
if (m_lpDD->CreateSurface(&ddsd, &m_lpDDSPrimary, NULL) != DD_OK) {
return FALSE;
}
5. 创建Clipper
IDirectDrawClipper* lpClipper = NULL;
HRESULT hRet = m_lpDD->CreateClipper(0, &lpClipper, NULL);   
if (hRet != DD_OK) {        
    return FALSE;
}
 
 hRet = lpClipper->SetHWnd(0, m_hWnd);
 if (hRet != DD_OK) {       
     return FALSE;
 }    
 
  hRet = m_lpDDSPrimary->SetClipper(lpClipper);
  if (hRet != DD_OK) {       
      return FALSE;
  }
6. 创建逻辑屏幕(离表面,从表面)
离表面:类似后缓冲区,不是紧挨着主表面,经常被用来存储位图。
DDSURFACEDESC   ddsd;
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;//DDSCAPS_OVERLAY;
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
ddsd.dwWidth = width;
ddsd.dwHeight = 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;
 
HRESULT  hRet;
LPDIRECTDRAWSURFACE     m_lpDDSOverlay; // DirectDraw 离表面指针
  if (FAILED(hRet = m_lpDD->CreateSurface(&ddsd, &m_lpDDSOverlay, NULL))) {
    return FALSE;      
}
7. 显示
HRESULT     hRet;   // DirectDraw 函¡¥数ºy返¤¦Ì回?值¦Ì
DDSURFACEDESC   ddsd;   // DirectDraw 表À¨ª面?描¨¨述º?
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
 
EnterCriticalSection(&m_cs);
// Lock down the surface so we can modify it's contents.
if (m_lpDDSOverlay) {
//将解码得到的YUV数据拷贝到YUV表面
hRet = m_lpDDSOverlay->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (FAILED(hRet))
return ;

int width = m_rcSrcFrame.right;
int height = m_rcSrcFrame.bottom;

LPBYTE lpSurf = (LPBYTE)ddsd.lpSurface;
LPBYTE lpY = buf;   //Y数据位置
LPBYTE lpU = buf + width*height;  //U数据位置
LPBYTE lpV = lpU + width*height/4; //V数据位置

//填充逻辑表面
if(lpSurf) {
int i;
for (i=0; i<height; i++){ // fill Y data
memcpy(lpSurf, lpY, ddsd.dwWidth);
lpY += width;
lpSurf += ddsd.lPitch;
}

for (i=0; i<height/2; i++){ // fill V data
memcpy(lpSurf, lpV, ddsd.dwWidth/2);
lpV += width/2; 
lpSurf += ddsd.lPitch/2;
}

for (i=0; i<height/2; i++){ // fill U data
memcpy(lpSurf, lpU, ddsd.dwWidth/2);
lpU += width/2; 
lpSurf += ddsd.lPitch/2;
}
}
m_lpDDSOverlay->Unlock(NULL);

GetClientRect(m_hWnd, &m_rcDst);
ClientToScreen(m_hWnd, (LPPOINT)&m_rcDst.left);
ClientToScreen(m_hWnd, (LPPOINT)&m_rcDst.right);

if (m_lpDDSPrimary) {
hRet = m_lpDDSPrimary->Blt(&m_rcDst, m_lpDDSOverlay, &m_rcSrcFrame, DDBLT_WAIT, NULL);
if (DDERR_SURFACELOST == hRet) {
DDrawDispReinit(m_hWnd, width, height);
}
m_lpDDSPrimary->Flip(NULL,0); //切换物理屏幕和逻辑屏幕
}
}
LeaveCriticalSection(&m_cs);
8.释放
释放所创建的DirectDraw对象,调用Release方法
 
Directdraw在显示视频的时候用的是双缓冲,及离表面和主表面(有的地方也称为物理表面和逻辑表面),双缓冲交替刷新,加速了这个过程的效率。

 

研发部    陈娟

 

姓名:
性别:
电话:
E-mail
问题:
问题描述: