使用DirectDraw直接显示YUV视频数据

最近在编写一个进行视频播放的ActiveX控件,工作已经接近尾声,现将其中显示YUV数据的使用DirectDraw的一些经验总结如下:(解码部分不是我编写的,我负责从网络接收数据,将数据传给解码器,并将解码得到的YUV数据进行显示,最初在显示部分我是先将YUV数据转换为RGB数据,再以位图的形式显示到屏幕上,但发现CPU占用率比较高,后来改用DirectDraw直接显示YUV数据)

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;iHeight;i++)
  {
   memcpy(lpSurf, PtrY, ddsd.dwWidth);
   PtrY += BpS;
   lpSurf += ddsd.lPitch;
  }

  for (int i=0;iHeight/2;i++)
  {
   memcpy(lpSurf, PtrV, ddsd.dwWidth/2);
   PtrV += BpS;
   lpSurf += ddsd.lPitch/2;
  }
  for (int i=0;iHeight/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占用率降低了一半。

时间: 2024-10-29 19:00:06

使用DirectDraw直接显示YUV视频数据的相关文章

使用D3D渲染YUV视频数据

源代码下载 在PC机上,对于YUV格式的视频如YV12,YUY2等的显示方法,一般是采用DIRECTDRAW,使用显卡的OVERLAY表面显示.OVERLAY技术主要是为了解决在PC上播放VCD而在显卡上实现的一个基于硬件的技术.OVERLAY的出现,很好的解决了在PC上播放VCD所遇到的困难.早期PC处理能力有限,播放VCD时,不但要做视频解码工作,还需要做YUV到RGB的颜色空间转换,软件实现非常耗费资源,于是,YUV OVERLAY表面出现了,颜色空间转换被转移到显卡上去实现,显卡做这些工

如何使用DirectDraw直接显示RGB、YUV视频数据(播放yuv)

#include "draw.h" void CTest100Dlg::OnButton1() { // TODO: Add your control notification handler code here CloseShowBMP(); InitDrawBMP(m_screen.GetSafeHwnd(),m_sel.GetCurSel());} void CTest100Dlg::OnButton2() { CString strFilename,str; CFileDial

yuv-关于OpenGL ES20显示YUV数据在不同手机要使用不同坐标系的问题,求教各位大虾

问题描述 关于OpenGL ES20显示YUV数据在不同手机要使用不同坐标系的问题,求教各位大虾 现在做OpenGL ES20在JNI层直接显示H264解码出来的YUV视频数据.参考的是这个链接,里面的坐标系问题至今也还没能解决掉,在不同手机上一定要用不同坐标系才能在正确的位置显示完整图像,如下: #if 0 // 红米.台电pad.kindle pad 等 GLfloat squareVertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,

基于RTP的H264视频数据打包解包类

from:http://blog.csdn.net/dengzikun/article/details/5807694 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包.解包的文档和代码.功夫不负有心人,找到不少有价值的文档和代码.参考这些资料,写了H264 RTP打包类.解包类,实现了单个NAL单元包和FU_A分片单元包.对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧.测试效果还不错,代码贴上来,若能为同道中人借鉴一二,足矣.两个类的使用说

web网页实时显示网络传来的视频数据

问题描述 web网页实时显示网络传来的视频数据 网络传输摄像头采集的视频数据,然后做一个web服务器,接受视频数据,并且实时显示,现在的问题是接受视频数据是一帧一阵传输?一帧是不是是就是一幅图像?怎么将传输过来的一帧视频数据显示大网页中? 解决方案 页面上放windowsmediaplayer或者flash控件,直接连你的流媒体数据源就可以了.

视频数据解析显示在surface上(android平台)

问题描述 视频数据解析显示在surface上(android平台) 12-18 20:07:30.426: E/Surface(2159): dequeueBuffer failed (Unknown error 2147483646) 12-18 20:07:30.436: E/ViewRootImpl(2159): Could not lock surface 12-18 20:07:30.436: E/ViewRootImpl(2159): java.lang.IllegalArgumen

如何在service中获取camera中的视频数据

问题描述 如何在service中获取camera中的视频数据 小弟是Android新手,最近遇到一点困难,困难具体如下,请各位大哥赐教: 我想在service中获取camera组件,然后把从camera中获取的数据通过 socket发送到电脑端. 现在主要的问题是不知道怎么获取camera中的数据,surfaceView貌似行不通 解决方案 用void onPreviewFrame(byte[] data, Camera camera),data就是预览图像的数据一般情况下是YUV格式. 解决方

视频数据智能结构化 引领安防进入SDT时代

当下,大数据快速积累.大规模并行计算的实现以及新算法不断涌现成为了深度学习爆发的催化剂,这也直接推动了人工智能在很多传统领域中的进展.在安防行业中,人工智能也从概念逐步落地,人脸识别.图像识别等技术与视频监控系统的深度结合使得智能安防有了实质性的发展. 对数据的理解是安防大数据的入口 随着平安城市建设的不断推进,监控点位剧增,视频监控系统成为社会立体化防控的重要组成部分.据数据统计,2016年的高清摄像头每天产生的数据比2015年产生多337PB.而目前在城市数据中,视频监控也成为所有数据中占比

jni-安卓怎样通过JNI获取手机摄像头视频数据?

问题描述 安卓怎样通过JNI获取手机摄像头视频数据? 不通过camera接口,通过jni获取,如果是USB摄像头的可以在/dev找到对应的文件,但是手机自带的摄像头怎样处理?求高人指点! 解决方案 http://blog.csdn.net/stephen_yu/article/details/7891424