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

 

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

[cpp] view plaincopy

 

  1. #ifndef _DIRECTDRAW_H_  
  2. #define _DIRECTDRAW_H_  
  3. #pragma once  
  4. #include "ddraw.h"  
  5.   
  6. #define   FOURCC_YUYV   0x32595559   //   MAKEFOURCC( 'Y ', 'U ', 'Y ', '2 ')   
  7. #define   FOURCC_UYVY   0x59565955   //   MAKEFOURCC( 'U ', 'Y ', 'V ', 'Y ')   
  8.   
  9. #define  YUV_UYVY 1  
  10. #define  YUV_YUYV 2  
  11.   
  12. class __declspec(dllexport) CDirectDraw  
  13. {  
  14. public:  
  15.     CDirectDraw(void);  
  16.     ~CDirectDraw(void);  
  17.   
  18.     bool DirectDrawInit(HWND hWnd, int width, int height,DWORD dwYuvFourCC);  
  19.     bool DisPlayYUVData(byte *pYUVData,int bYuvType,RECT rect);               

[cpp] view plaincopy

 

  1. void DirectDrawDeInit(void);                                          

[cpp] view plaincopy

 

  1. protected:  
  2.     LPDIRECTDRAW7           lpDD;                                           // DirectDraw 对象指针  
  3.     LPDIRECTDRAWSURFACE7    lpDDSPrimary;   // DirectDraw 主表面指针  
  4.     LPDIRECTDRAWSURFACE7    lpDDSOffScr;        // DirectDraw 离屏表面指针  
  5.     DDSURFACEDESC2          ddsd;   // DirectDraw 表面描述  
  6.   
  7.     LPDIRECTDRAWSURFACE7 m_pOsdSurface;     //画图表面  
  8.   
  9. };  
  10.   
  11. #endif  

DirectDraw.cpp 源文件如下:

[cpp] view plaincopy

 

  1. #include "StdAfx.h"  
  2. #include "DirectDraw.h"  
  3. #include <string>  
  4. using namespace std;  
  5.   
  6. CDirectDraw::CDirectDraw(void)  
  7. {  
  8.   
  9.     lpDD=NULL;            // DirectDraw 对象指针  
  10.     lpDDSPrimary=NULL;   // DirectDraw 主表面指针  
  11.     lpDDSOffScr=NULL;   // DirectDraw 离屏表面指针  
  12.     m_pOsdSurface=NULL;  
  13.   
  14. }  
  15.   
  16. CDirectDraw::~CDirectDraw(void)  
  17. {  
  18.   
  19.     DirectDrawDeInit();  
  20. }  
  21.   
  22. //yuv_type控件不同的yuv格式   

[cpp] view plaincopy

 

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

 

测试结果如下:

 

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);

时间: 2024-08-31 02:26:50

ddraw 视频下画图 不闪烁的方法的相关文章

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

一般的windows 复杂的界面需要使用多层窗口而且要用贴图来美化,所以不可避免在窗口移动或者改变大小的时候出现闪烁. 先来谈谈闪烁产生的原因 原因一:如果熟悉显卡原理的话,调用GDI函数向屏幕输出的时候并不是立刻就显示在屏幕上只是写到了显存里,而显卡每隔一段时间把显存的内容输出到屏幕上,这就是刷新周期. 一般显卡的刷新周期是 1/80秒左右,具体数字可以自己设置的. 这样问题就来了,一般画图都是先画背景色,然后再把内容画上去,如果这两次操作不在同一个刷新周期内完成,那么给人的视觉感受就是,先看

让PPT中对象闪烁的方法

在使用PowerPoint时,有时为了强调某个对象,需要让其在屏幕上闪烁几下.记得以前,我们常常需要将该对象复制多个后重叠在一起,然后再分别设置动画效果才可以实现.在PowerPoint2003中,已经提供了两种让对象闪烁的方法: 方法1:选定对象,单击"自定义动画"窗格中"添加效果"/"进入"/"闪烁一次",即可为对象添加闪烁效果一次.但这种动画效果的缺点是动画效果演示完毕后,对象将会从屏幕上消失. 方法2:选定对象,单击&

php使用memcoder将视频转成mp4格式的方法

 这篇文章主要介绍了php使用memcoder将视频转成mp4格式的方法,涉及php操作视频文件的技巧,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了php使用memcoder将视频转成mp4格式的方法.分享给大家供大家参考.具体实现方法如下: 代码如下: <?php convertTo( "some-input-video.avi", "output.mp4" ); function convertTo( $input, $output

win8系统下载腾讯视频总是qlv文件的解决方法

  win8系统下载腾讯视频总是qlv文件的解决方法           解决方法1: 1.首先我们要找到自己要下的视频,比如这个视频 一小时50分, 或者从手机腾讯视频app上直接找到这个视频; 2.然后 在手机上 缓存这个视频 我这个是已经缓存好了; 3.然后 把手机 接入电脑..以我的小米4c为例.找到:::计算机Mi-4c内部存储设备Androiddatacom.tencent.qqlivefilesvideos ; 4.我们看到有好几个 奇怪文件名的文件夹,我们缓存的视频就在里面,但是

RM/RMVB视频文件损坏原因及解决方法

  最近有用户反映windows系统RM/RMVB视频文件损坏,用户下载的电影视频文件都无法观看.RMVB格式出色的画质和众多优秀软件(如Easy RealMedia Producer)的支持,在较低平均比特率下如400-500kbps下,XVID和DIVX画质几乎无法观看,画面中除了色块就是色阶,除非是极低的分辨率 或者高码率.此时RMVB编码能应付大多画面.RMVB的价值优势是低码率下尽可能能获得更好的画质,由于编码特性 高码率反而无法得到相对应的清晰度.在这样的明显优势下小编就为大家介绍w

在Linux下开发GUI程序的方法

在Linux下开发GUI程序的方法有很多,比如Gnome桌面使用GTK+作为默认的图形界面库,KDE桌面使用Qt作为默认的图形界面库,wxWidgets则是另一个使用广泛的图形库,此外使用Java中的Swing/AWT组件也可以用于开发Linux下的GUI应用. 本文将依次介绍GTK+.Qt.wxWidgets和Swing/AWT,对其进行对比分析. 1. GTK+ 平台支持 虽然GTK+最初是为X Window系统开发的,但是目前已经发展成为一个跨平台的图形界面API,其支持的平台包括: Li

《中国人工智能学会通讯》——11.25 单目视频下运动物体建模及分析

11.25 单目视频下运动物体建模及分析 特征点轨迹是刻画视频中不同图像帧匹配关系的一种常用表示,其首先提取图像中的特征点,例如Harris 特征点,然后利用 Lucas-Kanade 方法[3]对这些特征点进行跟踪得到.由于特征点具有显著性和稳定性的特点,特征点轨迹往往较精确而且可以持续较长时间,从而能准确刻画物体的长时间运动.如图3所示,本章主要研究基于特征点轨迹的运动视频分割,其关键在于对同一个物体上轨迹进行运动建模. 已有研究表明,在仿射摄像机下,同一个运动物体上的轨迹在一个低维线性子空

vuejs在解析时出现闪烁的原因及防止闪烁的方法_javascript技巧

原因: 在使用vuejs.angularjs开发时,经常会遇见在如Chrome这类能够快速解析的浏览器上出现表达式({{ express }} ),或者是模块(div)的闪烁.对于这个问题由于JavaScript去操作DOM,都会等待DOM加载完成(DOM ready).对于vuejs.angularjs这些会在DOM ready完会才回去解析html view Template,所以对于Chrome这类快速的浏览器你会看见有闪烁的情况出现.而对于IE7,8这类解析稍慢的浏览器大部分情况下是不会

C# 重写ComboBox实现下拉任意组件的方法_C#教程

一.需求 C#种的下拉框ComboBox不支持下拉复选框列表与下拉树形列表等,系统中需要用到的地方使用了第三方组件,现在需要将第三方组件替换掉. 二.设计 基本思路:重写ComboBox,将原生的下拉部分屏蔽,使用toolStripDropDown制作下拉弹出 三.问题解决 1. 问题:toolStripDropDown中放toolStripControlHost时会有边框产生,同时CheckedListBox的duck为full时底端会有很大空白 解决: toolStripControlHos