我们如果是在在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到主表面,这样画的图形就不会闪烁了。

直接上源码吧,注意,我没有对画图的部分进行封装,感兴趣的朋友可以自己封装;

  1. #ifndef _DIRECTDRAW_H_
  2. #define _DIRECTDRAW_H_
  3. #pragma once
  4. #include "ddraw.h"
  5. #define   FOURCC_YUYV   0x32595559   //   MAKEFOURCC( 'Y ', 'U ', 'Y ', '2 ')
  6. #define   FOURCC_UYVY   0x59565955   //   MAKEFOURCC( 'U ', 'Y ', 'V ', 'Y ')
  7. #define  YUV_UYVY 1
  8. #define  YUV_YUYV 2
  9. class __declspec(dllexport) CDirectDraw
  10. {
  11. public:
  12. CDirectDraw(void);
  13. ~CDirectDraw(void);
  14. bool DirectDrawInit(HWND hWnd, int width, int height,DWORD dwYuvFourCC);
  15. bool DisPlayYUVData(byte *pYUVData,int bYuvType,RECT rect);
  1. void DirectDrawDeInit(void);
  1. protected:
  2. LPDIRECTDRAW7           lpDD;                                           // DirectDraw 对象指针
  3. LPDIRECTDRAWSURFACE7    lpDDSPrimary;   // DirectDraw 主表面指针
  4. LPDIRECTDRAWSURFACE7    lpDDSOffScr;        // DirectDraw 离屏表面指针
  5. DDSURFACEDESC2          ddsd;   // DirectDraw 表面描述
  6. LPDIRECTDRAWSURFACE7 m_pOsdSurface;     //画图表面
  7. };
  8. #endif

DirectDraw.cpp 源文件如下:

  1. #include "StdAfx.h"
  2. #include "DirectDraw.h"
  3. #include <string>
  4. using namespace std;
  5. CDirectDraw::CDirectDraw(void)
  6. {
  7. lpDD=NULL;            // DirectDraw 对象指针
  8. lpDDSPrimary=NULL;   // DirectDraw 主表面指针
  9. lpDDSOffScr=NULL;   // DirectDraw 离屏表面指针
  10. m_pOsdSurface=NULL;
  11. }
  12. CDirectDraw::~CDirectDraw(void)
  13. {
  14. DirectDrawDeInit();
  15. }
  16. //yuv_type控件不同的yuv格式
  1. bool CDirectDraw::DirectDrawInit(HWND hWnd, int width, int height,DWORD dwYuvFourCC)
  2. {
  3. HRESULT hr;
  4. // 创建DirectCraw对象
  5. if (DirectDrawCreateEx(NULL, (VOID**)&lpDD, IID_IDirectDraw7, NULL) != DD_OK)
  6. {
  7. return false;
  8. }
  9. // 设置协作层
  10. if (lpDD->SetCooperativeLevel(hWnd,
  11. DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES) != DD_OK)
  12. {
  13. return false;
  14. }
  15. // 创建主表面
  16. LPVOID  lpSurface  = NULL;
  17. ZeroMemory(&ddsd, sizeof(ddsd));
  18. ZeroMemory(&ddsd.ddpfPixelFormat, sizeof(DDPIXELFORMAT));
  19. ddsd.dwSize = sizeof(ddsd);
  20. ddsd.dwFlags = DDSD_CAPS;
  21. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  22. if (lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL) != DD_OK)
  23. {
  24. return false;
  25. }
  26. LPDIRECTDRAWCLIPPER   pcClipper;    // Cliper
  27. if( lpDD->CreateClipper( 0, &pcClipper, NULL ) != DD_OK )
  28. return false;
  29. if( pcClipper->SetHWnd( 0, hWnd ) != DD_OK )
  30. {
  31. pcClipper->Release();
  32. return false;
  33. }
  34. if( lpDDSPrimary->SetClipper( pcClipper ) != DD_OK )
  35. {
  36. pcClipper->Release();
  37. return false;
  38. }
  39. // Done with clipper
  40. pcClipper->Release();
  41. // 创建YUV表面
  42. ddsd.ddsCaps.dwCaps =  DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY ;
  43. ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT ;
  44. ddsd.dwWidth = width;
  45. ddsd.dwHeight =height;
  46. ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
  47. ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC | DDPF_YUV ;
  48. ddsd.ddpfPixelFormat.dwYUVBitCount = 8;
  49. ddsd.ddpfPixelFormat.dwFourCC =dwYuvFourCC;
  50. hr=lpDD->CreateSurface(&ddsd, &lpDDSOffScr, NULL);
  51. if ( hr!= DD_OK)
  52. {
  53. return false;
  54. }
  55. #if 1
  56. //创建OSD画图离屏表面
  57. //
  58. ZeroMemory(&ddsd, sizeof(ddsd));
  59. ddsd.dwSize = sizeof(ddsd);
  60. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  61. ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
  62. ddsd.dwWidth = width;
  63. ddsd.dwHeight = height;
  64. hr = lpDD->CreateSurface(&ddsd, &m_pOsdSurface, NULL);
  65. if ( hr != DD_OK)
  66. {
  67. //lpDD->Release();
  68. //lpDDSPrimary = NULL;
  69. //lpDD = NULL;
  70. return false;
  71. }
  72. #endif
  73. return true;
  74. }
  75. //add rect参数,将图像缩放到rect内
  76. bool CDirectDraw::DisPlayYUVData(byte *pYUVdata,int bYuvType,RECT rect)
  77. {
  78. byte *pSurf;
  79. int yuv_type=bYuvType;
  80. HRESULT hr;
  81. hr=lpDDSOffScr->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT,NULL);
  82. //2012-02-24
  83. if (hr==DDERR_SURFACELOST)
  84. {
  85. TRACE("off surface lost,restore offscr\n");
  86. hr=lpDDSOffScr->Restore();
  87. hr=lpDDSOffScr->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT,NULL);
  88. }
  89. if (FAILED(hr))
  90. {
  91. return DD_FALSE;
  92. }
  93. //2012-02-11
  94. if (yuv_type==YUV_UYVY)
  95. {
  96. ddsd.ddpfPixelFormat.dwFourCC =FOURCC_UYVY;
  97. }else
  98. {
  99. ddsd.ddpfPixelFormat.dwFourCC =FOURCC_YUYV;
  100. }
  101. pSurf=(LPBYTE)ddsd.lpSurface;
  102. if (pSurf)
  103. {
  104. for(unsigned int i=0; i < ddsd.dwHeight; i++)
  105. {
  106. memcpy(pSurf,pYUVdata,ddsd.dwWidth*2);
  107. pYUVdata+=ddsd.dwWidth*2;
  108. pSurf+=ddsd.lPitch;
  109. }
  110. }
  111. lpDDSOffScr->Unlock(NULL);
  112. #if 1
  113. //加入Osd离屏表面内容
  114. HRESULT ddrval;
  115. ddrval = m_pOsdSurface->Blt(&rect, lpDDSOffScr, NULL, DDBLT_WAIT, NULL);
  116. if (ddrval != DD_OK)
  117. {
  118. ddrval = lpDDSPrimary->Blt(&rect, lpDDSOffScr, &rect, DDBLT_WAIT, NULL);
  119. }
  120. else
  121. {
  122. HDC hDC = NULL;
  123. ddrval = m_pOsdSurface->GetDC(&hDC);
  124. if ((ddrval == DD_OK)&&(hDC != NULL))
  125. {
  126. //叠加文字
  127. SetTextColor(hDC,RGB(255,0,0));
  128. SetBkColor(hDC,RGB(0,255,0));
  129. CString m_sOsdMsg=_T("hello world");
  130. TextOut(hDC, rect.left+100,rect.top+200 , m_sOsdMsg, m_sOsdMsg.GetLength());
  131. //画实心矩形
  132. HPEN hpen = CreatePen (PS_SOLID, 1, RGB(255, 0, 0));
  133. SelectObject (hDC, hpen);
  134. HBRUSH hbrush = CreateSolidBrush (RGB(0, 255, 0)); //创建刷子
  135. SelectObject (hDC, hbrush);                        //使用刷子
  136. Rectangle(hDC, rect.left+100, rect.top+100, rect.left+200, rect.top+200); //画矩形
  137. //画空心矩形
  138. RECT rect1;
  139. rect1.left=rect.left+200;
  140. rect1.top=rect.top+200;
  141. rect1.right=rect.left+300;
  142. rect1.bottom=rect.top+300;
  143. FrameRect(hDC,&rect1,CreateSolidBrush(RGB(255,0,0)));
  144. //画直线
  145. MoveToEx(hDC,rect.left+50,rect.top+50,NULL);
  146. LineTo(hDC,rect.left+350,rect.top+350);
  147. m_pOsdSurface->ReleaseDC(hDC);
  148. lpDDSPrimary->Blt(&rect, m_pOsdSurface, &rect, DDBLT_WAIT, NULL);
  149. }
  150. }
  151. #else
  152. //只有主表面和离屏表面
  153. HRESULT ddrval;
  154. ddrval=lpDDSPrimary->Blt(&rect, lpDDSOffScr, NULL, DDBLT_WAIT, NULL);
  155. if (ddrval==DDERR_SURFACELOST)
  156. {
  157. TRACE("primary surface lost,restore all surfaces\n");
  158. lpDDSPrimary->Restore();
  159. }
  160. #endif
  161. return DD_OK;
  162. }
  163. //ddraw deInit
  164. void CDirectDraw::DirectDrawDeInit(void)
  165. {
  166. if (lpDDSOffScr != NULL)
  167. {
  168. lpDDSOffScr->Release();
  169. lpDDSOffScr = NULL;
  170. }
  171. if (lpDDSPrimary != NULL)
  172. {
  173. lpDDSPrimary->Release();
  174. lpDDSPrimary = NULL;
  175. }
  176. if (lpDD != NULL)
  177. {
  178. lpDD->Release();
  179. lpDD = NULL;
  180. }
  181. if (m_pOsdSurface!=NULL)
  182. {
  183. m_pOsdSurface->Release();
  184. m_pOsdSurface=NULL;
  185. }
  186. }

测试结果如下:

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 视频下画图 不闪烁的方法的更多相关文章

  1. ddraw 视频下绘图 不闪烁的方法

    我们假设是在在RGB视频上绘图(直线,矩形等),一般採用双缓冲区继续,使用内存MemoryDC,来实现画的图形在视频上显示不闪烁的功能,可是我们知道用RGB显示视频都是使用GDI进行渲染,这样非常耗C ...

  2. IE6-7下margin-bottom不兼容解决方法(非原创,视频中看到的)

    在IE低版本下有很多不兼容,现在将看到的   IE6-7下margin-bottom不兼容解决方法   演示一下,方便日后自己查阅. <!DOCTYPE html> <html la ...

  3. 【Visual C++】Windows GDI贴图闪烁解决方法

    一般的windows 复杂的界面需要使用多层窗口而且要用贴图来美化,所以不可避免在窗口移动或者改变大小的时候出现闪烁. 先来谈谈闪烁产生的原因 原因一:如果熟悉显卡原理的话,调用GDI函数向屏幕输出的 ...

  4. 腾讯视频QLV格式转换mp4的方法

    腾讯视频QLV格式转换mp4的方法不知道大家知不知道用?喜欢用腾讯视频的朋友应该都知道腾讯视频单独搞出了个QLV格式文件,只能用腾讯独有的腾讯视频软件才能播放,就算用格式工厂转换也不行,那么腾讯视频的 ...

  5. 在Ubuntu下搭建FTP服务器的方法

    由于整个学校相当于一个大型局域网,相互之间传送数据非常快,比如要共享个电影,传点资料什么的. 所以我们可以选择搭建一个FTP服务器来共享文件. 那么问题来了,有的同学会问,我们既然在一个局域网内,直接 ...

  6. [转载]Linux下终端字体颜色设置方法

    原文地址:Linux下终端字体颜色设置方法作者:router 网上类似的文章有很多,但是都是转来转去的,没有经过测试,按照很多文章的方法会造成你设置之后的终端在换行和删除输入字符时终端显示会乱七八糟, ...

  7. C# Winform频繁刷新导致界面闪烁解决方法

    C#Winform频繁刷新导致界面闪烁解决方法 一.通过对窗体和控件使用双缓冲来减少图形闪烁(当绘制图片时出现闪烁时,使用双缓冲) 对于大多数应用程序,.NET Framework 提供的默认双缓冲将 ...

  8. Angular.js中处理页面闪烁的方法详解

    Angular.js中处理页面闪烁的方法详解 前言 大家在使用{{}}绑定数据的时候,页面加载会出现满屏尽是{{xxx}}的情况.数据还没响应,但页面已经渲染了.这是因为浏览器和angularjs渲染 ...

  9. winform频繁刷新导致界面闪烁解决方法

    转自龙心文 原文 winform频繁刷新导致界面闪烁解决方法 一.通过对窗体和控件使用双缓冲来减少图形闪烁(当绘制图片时出现闪烁时,使用双缓冲) 对于大多数应用程序,.NET Framework 提供 ...

随机推荐

  1. js 中的闭包

    /** *闭包就是在一个函数的外面访问函数内部的变量 **/ var name = "xiao A"; var obj = { name : "xiao B" ...

  2. HDU 5584 LCM Walk(数学题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5584 题意:(x, y)经过一次操作可以变成(x+z, y)或(x, y+z)现在给你个点(ex, e ...

  3. Hadoop学习之Hadoop案例分析

    一.日志数据分析1.背景1.1 ***论坛日志,数据分为两部分组成,原来是一个大文件,是56GB:以后每天生成一个文件,大约是150-200MB之间: 每行记录有5部分组成:1.访问ip:2.访问时间 ...

  4. HBase API详解

    一.Java API和HBase数据模型的关系 在Java中,与HBase数据库存储管理相关的类包括HBaseAdmin.HBaseConfiguration.HTable.HTableDescrip ...

  5. Django 探索(一) HelloWorld

    一.Django怎么读 酱狗 二.Django下载 安装 下载地址 安装: tar zxvf Django-1.5.4.tar.gz python setup.py install 三.建立一个Hel ...

  6. java新特性之可变参数

    public class NewDemo01 {     public static void main(String[] args) {         System.out.print(" ...

  7. Linux 网络编程基础(2)-- 获取主机信息

    前一篇已经介绍了最基本的网络数据结构.这篇介绍一下获取主机信息的函数 举个例子,想要通过代码的方式从百度获取当前的时间,怎么做?我们不知道百度的IP地址啊,这代码怎么写?还好,Linux提供了一些AP ...

  8. Mysql 笔记:

    1:可以查看information_schema.index_statistics 来查看索引的使用信息.还可以使用pt-index-usage 这个工具来分析日志再结合explain 来分析使用的索 ...

  9. 用extundelete恢复rm -rf删的文件

    “慎用rm -rf命令,除非你知道此命令带来的后果.”这是一条Linux用户守则,虽然大多数用户都明白这条语句的含义,但是我觉得还需要完善一下,为这条语句加 上一个使用前提:在你确认自己拥有清醒头脑, ...

  10. Codeforces 430B Balls Game(Two Pointers)

    [题目链接] http://codeforces.com/contest/430/problem/B [题目大意] 祖玛游戏,给出一个序列,表示祖玛球的颜色序列,三个或者以上的球碰在一起就会发生消除, ...