<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    ddraw 視頻下畫圖 不閃爍的方法

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    我們如果是在在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在CODE上查看代碼片派生到我的代碼片  
    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在CODE上查看代碼片派生到我的代碼片  
    1. void DirectDrawDeInit(void);                                          
    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    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在CODE上查看代碼片派生到我的代碼片  
    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在CODE上查看代碼片派生到我的代碼片  
    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. }  


     

    測試結果如下:

    RFID設備管理軟件

     

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

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全