使用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占用率降低了一半。
使用DirectDraw直接显示YUV视频数据的更多相关文章
- 使用D3D渲染YUV视频数据
源代码下载 在PC机上,对于YUV格式的视频如YV12,YUY2等的显示方法,一般是采用DIRECTDRAW,使用显卡的OVERLAY表面显示.OVERLAY技术主要是为了解决在PC上播放VCD而在显 ...
- 使用D3D渲染YUV视频数据<转>
源代码下载 转载地址:http://blog.csdn.net/dengzikun/article/details/5824874 源码地址:http://download.csdn.net/down ...
- 如何使用DirectDraw直接显示RGB、YUV视频数据(播放yuv)
#include "draw.h"void CTest100Dlg::OnButton1() { // TODO: Add your control notification ha ...
- directdraw显示yuv视频,出现屏保时,yuv显示不出来,表面丢失
原因是: DDrawSurface 丢失, DDraw表面在很多情况下都会丢失(如:启动其他全屏独占程序,屏保,或锁屏时), 表面丢失其实就是表面所使用的内存或显存被DirectDraw系统释放, 分 ...
- 基于RTP的H264视频数据打包解包类
from:http://blog.csdn.net/dengzikun/article/details/5807694 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打 ...
- JavaCV 采集摄像头及桌面视频数据
javacv 封装了javacpp-presets库很多native API,简化了开发,对java程序员来说比较友好. 之前使用JavaCV库都是使用ffmpeg native API开发,这种方式 ...
- Android上使用OpenGLES2.0显示YUV数据
在Android上用OpenGLES来显示YUV图像,之所以这样做,是因为: 1.Android本身也不能直接显示YUV图像,YUV转成RGB还是必要的: 2.YUV手动转RGB会占用大量的CPU资源 ...
- Android用surface直接显示yuv数据(三)
本文用Java创建UI并联合JNI层操作surface来直接显示yuv数据(yv12),开发环境为Android 4.4,全志A23平台. package com.example.myyuvviewe ...
- Android用surface直接显示yuv数据(二)
上一篇文章主要是參照AwesomePlayer直接用SoftwareRenderer类来显示yuv,为了能用到这个类,不惜依赖了libstagefright.libstagefright_color_ ...
随机推荐
- cache.config文件配置模板
# # cache.config # # The purpose of this file is to alter caching parameters of # specific objects o ...
- Codeforce B. Polycarp and Letters
B. Polycarp and Letters time limit per test 2 seconds memory limit per test 256 megabytes input stan ...
- 窗口缩小div内容隐藏看不到怎么解决?
div的宽度设置为100%,并设置其背景颜色,但当窗口发生变化出现横向滚动条,拉滚动条的时候发现右面是空白的. 解决方法:body{min-width:1024px},给body加上一个最小宽度.ie ...
- mui页面跳转(传值+接收)
<script type="text/javascript" charset="utf-8"> mui.init(); mui.plusReady( ...
- ABP官方文档翻译 6.4 导航
导航 创建菜单 注册导航提供者 显示菜单 每一个网络应用都会有一些菜单用来在pages/screens之间导航.ABP提供了通用的基础设施来创建并显示菜单. 创建菜单 应用可以由不同的模块组成,每一个 ...
- ZOJ 2314 Reactor Cooling [无源汇上下界网络流]
贴个板子 #include <iostream> #include <cstdio> #include <cstring> #include <algorit ...
- OI黑科技:读入优化
利用getchar()函数加速读入. Q:读入优化是什么? A :更加快速地读入一些较大的数字. Q:scanf不是已经够快了吗? A:Naive,scanf还是不!够!快! Q:那怎么办呢? A:我 ...
- uboot之ldr指令
刚开始接触uboot的时候,就一直对ldr指令很迷惑,因为这个指令有两层用法,一个是加载,一个是伪指令.今天闲着没事就来说一下这两个之间的区别. LDR伪指令的形式是"LDR Rn,=exp ...
- Spring Task定时任务Scheduled
Spring的任务调度,采用注解的形式 Spring中@Scheduled的用法. spring的配置文件如下,先扫描到任务的类,打开spirng任务的标签 <beans xmlns=" ...
- GitHub入门与实践
基本命令 git status 工作区状态 git add git commint 暂存区 git push gitHub客户端 下载网址:https://desktop.github.com/ 解决 ...