最近在编写一个进行视频播放的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占用率降低了一半。

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

  1. 使用D3D渲染YUV视频数据

    源代码下载 在PC机上,对于YUV格式的视频如YV12,YUY2等的显示方法,一般是采用DIRECTDRAW,使用显卡的OVERLAY表面显示.OVERLAY技术主要是为了解决在PC上播放VCD而在显 ...

  2. 使用D3D渲染YUV视频数据<转>

    源代码下载 转载地址:http://blog.csdn.net/dengzikun/article/details/5824874 源码地址:http://download.csdn.net/down ...

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

    #include "draw.h"void CTest100Dlg::OnButton1() { // TODO: Add your control notification ha ...

  4. directdraw显示yuv视频,出现屏保时,yuv显示不出来,表面丢失

    原因是: DDrawSurface 丢失, DDraw表面在很多情况下都会丢失(如:启动其他全屏独占程序,屏保,或锁屏时), 表面丢失其实就是表面所使用的内存或显存被DirectDraw系统释放, 分 ...

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

    from:http://blog.csdn.net/dengzikun/article/details/5807694 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打 ...

  6. JavaCV 采集摄像头及桌面视频数据

    javacv 封装了javacpp-presets库很多native API,简化了开发,对java程序员来说比较友好. 之前使用JavaCV库都是使用ffmpeg native API开发,这种方式 ...

  7. Android上使用OpenGLES2.0显示YUV数据

    在Android上用OpenGLES来显示YUV图像,之所以这样做,是因为: 1.Android本身也不能直接显示YUV图像,YUV转成RGB还是必要的: 2.YUV手动转RGB会占用大量的CPU资源 ...

  8. Android用surface直接显示yuv数据(三)

    本文用Java创建UI并联合JNI层操作surface来直接显示yuv数据(yv12),开发环境为Android 4.4,全志A23平台. package com.example.myyuvviewe ...

  9. Android用surface直接显示yuv数据(二)

    上一篇文章主要是參照AwesomePlayer直接用SoftwareRenderer类来显示yuv,为了能用到这个类,不惜依赖了libstagefright.libstagefright_color_ ...

随机推荐

  1. 在UITableView顶部制作简单的UISegmentControl实例方法

    // http://www.tuicool.com/articles/yUfURj 使用方法 如上图: 分两步: 一.创建320长度背景,高不超过40最好 //segment背景图 UIImageVi ...

  2. 从零开始学习前端JAVASCRIPT — 10、JavaScript基础ES6(ECMAScript6.0)

    ECMAScript 6.0(简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发 ...

  3. css层叠样式初学

    一.css简介 1.层叠样式表:叠加效果,不同css对同一html修饰,冲突部分,优先级高作用,不冲突部分,共同作用 2.css作用 (1)修饰html (2)替代了标签自身的颜色,字号等属性,提高复 ...

  4. ansible playbook实践(四)-如何调试写好的playbook文件

    有时,我们写了一个长长,功能很强悍的yaml文件,但是,我们有可能会担心,写的yaml文件是否正确,是否有漏洞危机,毕竟是要修改线上的机器,那么,有可能我们可以从以下几个检查维度来进行,确保在大规模应 ...

  5. python学习交流 - 匿名函数

    匿名函数 匿名函数是一个很有特色的定义函数的功能.在实际使用的过程,用户有时不得不为一些一行代码即可实现的功能来定义一个函数,例如像map, max, filter等内置函数的key参数只能接收可调用 ...

  6. HBase Filter及对应Shell--转

    http://www.cnblogs.com/skyl/p/4807793.html 比较运算符 CompareFilter.CompareOp比较运算符用于定义比较关系,可以有以下几类值供选择: E ...

  7. 再看Java基本类型

    Java中的基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte.short.int.long.float.double. 数值类型又可以分为整数类型byte.short ...

  8. BZOJ 3876: [Ahoi2014]支线剧情 [上下界费用流]

    3876: [Ahoi2014]支线剧情 题意:每次只能从1开始,每条边至少经过一次,有边权,求最小花费 裸上下界费用流...每条边下界为1就行了 注意要加上下界*边权 #include <io ...

  9. BZOJ 3994: [SDOI2015]约数个数和 [莫比乌斯反演 转化]

    2015 题意:\(d(i)\)为i的约数个数,求\(\sum\limits_{i=1}^n \sum\limits_{j=1}^m d(ij)\) \(ij\)都爆int了.... 一开始想容斥一下 ...

  10. JSP基础使用

    一.JSP简介 JSP(Java Sever Pages):是为了能让 Java 在 Web 页面运行的一种语言. 在JSP中包括两种主要内容: 1. HTML.JS语言(静态内容).由客户端浏览器负 ...