ddraw 视频下画图 不闪烁的方法
我们如果是在在RGB视频上画图(直线,矩形等),一般采用双缓冲区继续,使用内存MemoryDC,来实现画的图形在视频上显示不闪烁的功能,但是我们知道用RGB显示视频都是使用GDI进行渲染,这样很耗CPU,那么我们能不能在YUV上进行视频渲染呢,答案是肯定的,使用ddraw直接显示yuv就ok了,可以支持yuv422和yuv420的直接使用显卡显示,不耗CPU,但是我们在使用ddraw显示时,然后在配合GDI画图(直线或矩形等),画的图形是闪烁的,原因是我们在ddraw直接显示yuv视频时,使用的是离屏表面的方法,将yuv数据拷贝到离屏表面,然后在blt到主表面,这样用gdi画图时,和视频刷新不同步,造成闪烁,那么我们怎么解决该问题呢?方法如下:
新增加一个离屏表面,我们定义成osd离屏表面吧,我们将yuv数据拷贝到离屏表面后,在将该离屏表面blt到osd离屏表面,然后在osd离屏表面上画直线或矩形,画完后在blt到主表面,这样画的图形就不会闪烁了。
直接上源码吧,注意,我没有对画图的部分进行封装,感兴趣的朋友可以自己封装;
- #ifndef _DIRECTDRAW_H_
- #define _DIRECTDRAW_H_
- #pragma once
- #include "ddraw.h"
- #define FOURCC_YUYV 0x32595559 // MAKEFOURCC( 'Y ', 'U ', 'Y ', '2 ')
- #define FOURCC_UYVY 0x59565955 // MAKEFOURCC( 'U ', 'Y ', 'V ', 'Y ')
- #define YUV_UYVY 1
- #define YUV_YUYV 2
- class __declspec(dllexport) CDirectDraw
- {
- public:
- CDirectDraw(void);
- ~CDirectDraw(void);
- bool DirectDrawInit(HWND hWnd, int width, int height,DWORD dwYuvFourCC);
- bool DisPlayYUVData(byte *pYUVData,int bYuvType,RECT rect);
- void DirectDrawDeInit(void);
- protected:
- LPDIRECTDRAW7 lpDD; // DirectDraw 对象指针
- LPDIRECTDRAWSURFACE7 lpDDSPrimary; // DirectDraw 主表面指针
- LPDIRECTDRAWSURFACE7 lpDDSOffScr; // DirectDraw 离屏表面指针
- DDSURFACEDESC2 ddsd; // DirectDraw 表面描述
- LPDIRECTDRAWSURFACE7 m_pOsdSurface; //画图表面
- };
- #endif
DirectDraw.cpp 源文件如下:
- #include "StdAfx.h"
- #include "DirectDraw.h"
- #include <string>
- using namespace std;
- CDirectDraw::CDirectDraw(void)
- {
- lpDD=NULL; // DirectDraw 对象指针
- lpDDSPrimary=NULL; // DirectDraw 主表面指针
- lpDDSOffScr=NULL; // DirectDraw 离屏表面指针
- m_pOsdSurface=NULL;
- }
- CDirectDraw::~CDirectDraw(void)
- {
- DirectDrawDeInit();
- }
- //yuv_type控件不同的yuv格式
- bool CDirectDraw::DirectDrawInit(HWND hWnd, int width, int height,DWORD dwYuvFourCC)
- {
- HRESULT hr;
- // 创建DirectCraw对象
- if (DirectDrawCreateEx(NULL, (VOID**)&lpDD, IID_IDirectDraw7, NULL) != DD_OK)
- {
- return false;
- }
- // 设置协作层
- if (lpDD->SetCooperativeLevel(hWnd,
- DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES) != DD_OK)
- {
- return false;
- }
- // 创建主表面
- LPVOID lpSurface = NULL;
- ZeroMemory(&ddsd, sizeof(ddsd));
- ZeroMemory(&ddsd.ddpfPixelFormat, sizeof(DDPIXELFORMAT));
- ddsd.dwSize = sizeof(ddsd);
- ddsd.dwFlags = DDSD_CAPS;
- ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
- if (lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL) != DD_OK)
- {
- 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表面
- ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY ;
- 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.dwYUVBitCount = 8;
- ddsd.ddpfPixelFormat.dwFourCC =dwYuvFourCC;
- hr=lpDD->CreateSurface(&ddsd, &lpDDSOffScr, NULL);
- if ( hr!= DD_OK)
- {
- return false;
- }
- #if 1
- //创建OSD画图离屏表面
- //
- ZeroMemory(&ddsd, sizeof(ddsd));
- ddsd.dwSize = sizeof(ddsd);
- ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
- ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
- ddsd.dwWidth = width;
- ddsd.dwHeight = height;
- hr = lpDD->CreateSurface(&ddsd, &m_pOsdSurface, NULL);
- if ( hr != DD_OK)
- {
- //lpDD->Release();
- //lpDDSPrimary = NULL;
- //lpDD = NULL;
- return false;
- }
- #endif
- return true;
- }
- //add rect参数,将图像缩放到rect内
- bool CDirectDraw::DisPlayYUVData(byte *pYUVdata,int bYuvType,RECT rect)
- {
- byte *pSurf;
- int yuv_type=bYuvType;
- HRESULT hr;
- hr=lpDDSOffScr->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT,NULL);
- //2012-02-24
- if (hr==DDERR_SURFACELOST)
- {
- TRACE("off surface lost,restore offscr\n");
- hr=lpDDSOffScr->Restore();
- hr=lpDDSOffScr->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT,NULL);
- }
- if (FAILED(hr))
- {
- return DD_FALSE;
- }
- //2012-02-11
- if (yuv_type==YUV_UYVY)
- {
- ddsd.ddpfPixelFormat.dwFourCC =FOURCC_UYVY;
- }else
- {
- ddsd.ddpfPixelFormat.dwFourCC =FOURCC_YUYV;
- }
- pSurf=(LPBYTE)ddsd.lpSurface;
- if (pSurf)
- {
- for(unsigned int i=0; i < ddsd.dwHeight; i++)
- {
- memcpy(pSurf,pYUVdata,ddsd.dwWidth*2);
- pYUVdata+=ddsd.dwWidth*2;
- pSurf+=ddsd.lPitch;
- }
- }
- lpDDSOffScr->Unlock(NULL);
- #if 1
- //加入Osd离屏表面内容
- HRESULT ddrval;
- ddrval = m_pOsdSurface->Blt(&rect, lpDDSOffScr, NULL, DDBLT_WAIT, NULL);
- if (ddrval != DD_OK)
- {
- ddrval = lpDDSPrimary->Blt(&rect, lpDDSOffScr, &rect, DDBLT_WAIT, NULL);
- }
- else
- {
- HDC hDC = NULL;
- ddrval = m_pOsdSurface->GetDC(&hDC);
- if ((ddrval == DD_OK)&&(hDC != NULL))
- {
- //叠加文字
- SetTextColor(hDC,RGB(255,0,0));
- SetBkColor(hDC,RGB(0,255,0));
- CString m_sOsdMsg=_T("hello world");
- TextOut(hDC, rect.left+100,rect.top+200 , m_sOsdMsg, m_sOsdMsg.GetLength());
- //画实心矩形
- HPEN hpen = CreatePen (PS_SOLID, 1, RGB(255, 0, 0));
- SelectObject (hDC, hpen);
- HBRUSH hbrush = CreateSolidBrush (RGB(0, 255, 0)); //创建刷子
- SelectObject (hDC, hbrush); //使用刷子
- Rectangle(hDC, rect.left+100, rect.top+100, rect.left+200, rect.top+200); //画矩形
- //画空心矩形
- RECT rect1;
- rect1.left=rect.left+200;
- rect1.top=rect.top+200;
- rect1.right=rect.left+300;
- rect1.bottom=rect.top+300;
- FrameRect(hDC,&rect1,CreateSolidBrush(RGB(255,0,0)));
- //画直线
- MoveToEx(hDC,rect.left+50,rect.top+50,NULL);
- LineTo(hDC,rect.left+350,rect.top+350);
- m_pOsdSurface->ReleaseDC(hDC);
- lpDDSPrimary->Blt(&rect, m_pOsdSurface, &rect, DDBLT_WAIT, NULL);
- }
- }
- #else
- //只有主表面和离屏表面
- HRESULT ddrval;
- ddrval=lpDDSPrimary->Blt(&rect, lpDDSOffScr, NULL, DDBLT_WAIT, NULL);
- if (ddrval==DDERR_SURFACELOST)
- {
- TRACE("primary surface lost,restore all surfaces\n");
- lpDDSPrimary->Restore();
- }
- #endif
- return DD_OK;
- }
- //ddraw deInit
- void CDirectDraw::DirectDrawDeInit(void)
- {
- if (lpDDSOffScr != NULL)
- {
- lpDDSOffScr->Release();
- lpDDSOffScr = NULL;
- }
- if (lpDDSPrimary != NULL)
- {
- lpDDSPrimary->Release();
- lpDDSPrimary = NULL;
- }
- if (lpDD != NULL)
- {
- lpDD->Release();
- lpDD = NULL;
- }
- if (m_pOsdSurface!=NULL)
- {
- m_pOsdSurface->Release();
- m_pOsdSurface=NULL;
- }
- }
测试结果如下:
ddraw gdi 画图知识如下:
由于DirectDraw并没有提供画点、线,圆等的语句,所以我们要借助Windows GDI函数来完成这些工作。就像输出文字时一样,我们先要获得页面的HDC:
HDC hdc;
lpDDSXXX->GetDC(&hdc);
画点是最简单的,SetPixel (hdc, x, y, RGB(r, g, b)); 即可在屏幕的(x,y)坐标处画上一个指定颜色的点。
如果需要画线等,我们需要创建"画笔":
HPEN hpen = CreatePen (PS_SOLID, 5, RGB(r, g, b));
CreatePen的第一个参数意义为画笔样式,常用的有PS_SOLID(普通画笔)和PS_DOT(由间断点组成的画笔,需要设置画笔宽度为1)。第二个参数是画笔的宽度,第三个参数是画笔的颜色。
接着将画笔给HDC:
SelectObject (hdc, hpen);
移动画笔到(x1,y1):
MoveToEx (hdc, x1, y1, NULL);
从画图起始位置向(x2,y2)坐标处画线:
LineTo (hdc, x2, y2);
下面列出一些常用的画图语句,使用方法和画线差不多,设定完画笔即可使用:
Rectangle(hdc, x1, y1, x2, y2); //画矩形
Ellipse(hdc, x1, y1, x2, y2); //画椭圆
值得注意的是我们画的图形将由一个"刷子"来填充,使用最简单的单色刷子的方法是:
HBRUSH hbrush = CreateSolidBrush (RGB(r, g, b)); //创建刷子
SelectObject (hdc, hbrush); //使用刷子
画完后,我们要记住释放HDC:
lpDDSXXX->ReleaseDC(hdc);
ddraw 视频下画图 不闪烁的方法的更多相关文章
- ddraw 视频下绘图 不闪烁的方法
我们假设是在在RGB视频上绘图(直线,矩形等),一般採用双缓冲区继续,使用内存MemoryDC,来实现画的图形在视频上显示不闪烁的功能,可是我们知道用RGB显示视频都是使用GDI进行渲染,这样非常耗C ...
- IE6-7下margin-bottom不兼容解决方法(非原创,视频中看到的)
在IE低版本下有很多不兼容,现在将看到的 IE6-7下margin-bottom不兼容解决方法 演示一下,方便日后自己查阅. <!DOCTYPE html> <html la ...
- 【Visual C++】Windows GDI贴图闪烁解决方法
一般的windows 复杂的界面需要使用多层窗口而且要用贴图来美化,所以不可避免在窗口移动或者改变大小的时候出现闪烁. 先来谈谈闪烁产生的原因 原因一:如果熟悉显卡原理的话,调用GDI函数向屏幕输出的 ...
- 腾讯视频QLV格式转换mp4的方法
腾讯视频QLV格式转换mp4的方法不知道大家知不知道用?喜欢用腾讯视频的朋友应该都知道腾讯视频单独搞出了个QLV格式文件,只能用腾讯独有的腾讯视频软件才能播放,就算用格式工厂转换也不行,那么腾讯视频的 ...
- 在Ubuntu下搭建FTP服务器的方法
由于整个学校相当于一个大型局域网,相互之间传送数据非常快,比如要共享个电影,传点资料什么的. 所以我们可以选择搭建一个FTP服务器来共享文件. 那么问题来了,有的同学会问,我们既然在一个局域网内,直接 ...
- [转载]Linux下终端字体颜色设置方法
原文地址:Linux下终端字体颜色设置方法作者:router 网上类似的文章有很多,但是都是转来转去的,没有经过测试,按照很多文章的方法会造成你设置之后的终端在换行和删除输入字符时终端显示会乱七八糟, ...
- C# Winform频繁刷新导致界面闪烁解决方法
C#Winform频繁刷新导致界面闪烁解决方法 一.通过对窗体和控件使用双缓冲来减少图形闪烁(当绘制图片时出现闪烁时,使用双缓冲) 对于大多数应用程序,.NET Framework 提供的默认双缓冲将 ...
- Angular.js中处理页面闪烁的方法详解
Angular.js中处理页面闪烁的方法详解 前言 大家在使用{{}}绑定数据的时候,页面加载会出现满屏尽是{{xxx}}的情况.数据还没响应,但页面已经渲染了.这是因为浏览器和angularjs渲染 ...
- winform频繁刷新导致界面闪烁解决方法
转自龙心文 原文 winform频繁刷新导致界面闪烁解决方法 一.通过对窗体和控件使用双缓冲来减少图形闪烁(当绘制图片时出现闪烁时,使用双缓冲) 对于大多数应用程序,.NET Framework 提供 ...
随机推荐
- oracle归档日志
前几天因为导入大的东西,弄得很久都没动静,一看最后才发现是归档满了.但是很多的命令还是很是很不熟悉,所以看了下,百度了下.整理下这个. 1.查看归档日志大小及使用情况 select * from v$ ...
- Filemanager 的使用
filemanager的使用包括: 1.创建文件夹 2.删除文件夹 3.写入文件 4.复制文件 5.移动文件 6.删除文件 一.创建文件夹 首先宏的定义一个字符串作为地址的来获取当前的docum ...
- Unity5UGUI 官方教程学习笔记(二)Rect Transform
Rect Transform Posx Posy Posz : ui相对于父级的位置 Anchors :锚点 定义了与父体之间的位置关系 一个锚点由四个锚组成 四个锚分别代表了 ...
- C++_基础_C与C++的区别2
内容: (1)C++中的函数 (2)动态内存 (3)引用 (4)类型转换 (5)C++社区对C程序员的建议 1.C++中的函数1.1 函数的重载(1)重载的概念 在同一个作用域中,函数名相同,函数的参 ...
- Class类对象的三种实例化方法
class X { } public class GetClassDemo01 { public static void main(String[] args) { X x = ...
- css如此强大你知道吗
看个这个大神纯 CSS 绘制<辛普森一家>人物头像我惊呆了,css如此牛x <div id="wrap"> <div class="cont ...
- 一步一步Asp.Net MVC系列_权限管理总结(附MVC权限管理系统源码)
在上一节中我们总结了关于权限控制的方式,我们这一节讲解关于权限控制中角色权限的授予处理等等并做本系列的总结. 首先,我们来谈谈权限控制中角色权限的控制,上一节只是针对权限拦截中比较粗的控制,如果我们需 ...
- HDU 4366 Successor(树链剖分+zkw线段树+扫描线)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...
- UVA - 1103Ancient Messages(dfs)
UVA - 1103Ancient Messages In order to understand early civilizations, archaeologists often study te ...
- Summer Holiday(强联通入度最小点)
Summer Holiday Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...