Home | History | Annotate | Download | only in directx
      1 /*
      2 // Sample demonstrating interoperability of OpenCV UMat with Direct X surface
      3 // At first, the data obtained from video file or camera and
      4 // placed onto Direct X surface,
      5 // following mapping of this Direct X surface to OpenCV UMat and call cv::Blur
      6 // function. The result is mapped back to Direct X surface and rendered through
      7 // Direct X API.
      8 */
      9 #define WIN32_LEAN_AND_MEAN
     10 #include <windows.h>
     11 #include <d3d9.h>
     12 
     13 #include "opencv2/core.hpp"
     14 #include "opencv2/core/directx.hpp"
     15 #include "opencv2/core/ocl.hpp"
     16 #include "opencv2/imgproc.hpp"
     17 #include "opencv2/videoio.hpp"
     18 
     19 #include "d3dsample.hpp"
     20 
     21 #pragma comment (lib, "d3d9.lib")
     22 
     23 
     24 using namespace std;
     25 using namespace cv;
     26 
     27 class D3D9ExWinApp : public D3DSample
     28 {
     29 public:
     30     D3D9ExWinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
     31         D3DSample(width, height, window_name, cap) {}
     32 
     33     ~D3D9ExWinApp() {}
     34 
     35     int create(void)
     36     {
     37         // base initialization
     38         D3DSample::create();
     39 
     40         // initialize DirectX
     41         HRESULT r;
     42 
     43         r = ::Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9Ex);
     44         if (FAILED(r))
     45         {
     46             return -1;
     47         }
     48 
     49         DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING |
     50                       D3DCREATE_PUREDEVICE |
     51                       D3DCREATE_NOWINDOWCHANGES |
     52                       D3DCREATE_MULTITHREADED |
     53                       D3DCREATE_FPU_PRESERVE;
     54 
     55         D3DPRESENT_PARAMETERS d3dpp;
     56         ::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
     57 
     58         d3dpp.Windowed                   = true;
     59         d3dpp.Flags                      = 0;
     60         d3dpp.BackBufferCount            = 0;
     61         d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
     62         d3dpp.BackBufferHeight           = m_height;
     63         d3dpp.BackBufferWidth            = m_width;
     64         d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
     65         d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD;
     66         d3dpp.hDeviceWindow              = m_hWnd;
     67         d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
     68         d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
     69 
     70         r = m_pD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, NULL, &m_pD3D9DevEx);
     71         if (FAILED(r))
     72         {
     73             return -1;
     74         }
     75 
     76         r = m_pD3D9DevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
     77         if (FAILED(r))
     78         {
     79             return -1;
     80         }
     81 
     82         r = m_pD3D9DevEx->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL);
     83         if (FAILED(r))
     84         {
     85             std::cerr << "Can't create surface for result" << std::endl;
     86             return -1;
     87         }
     88 
     89         // initialize OpenCL context of OpenCV lib from DirectX
     90         if (cv::ocl::haveOpenCL())
     91         {
     92             m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9DevEx);
     93         }
     94 
     95         m_oclDevName = cv::ocl::useOpenCL() ?
     96             cv::ocl::Context::getDefault().device(0).name() :
     97             "No OpenCL device";
     98 
     99         return 0;
    100     } // create()
    101 
    102 
    103     // get media data on DX surface for further processing
    104     int get_surface(LPDIRECT3DSURFACE9* ppSurface)
    105     {
    106         HRESULT r;
    107 
    108         if (!m_cap.read(m_frame_bgr))
    109             return -1;
    110 
    111         cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA);
    112 
    113         D3DLOCKED_RECT memDesc = { 0, NULL };
    114         RECT rc = { 0, 0, m_width, m_height };
    115 
    116         r = m_pSurface->LockRect(&memDesc, &rc, 0);
    117         if (FAILED(r))
    118         {
    119             return r;
    120         }
    121 
    122         cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
    123         // copy video frame data to surface
    124         m_frame_rgba.copyTo(m);
    125 
    126         r = m_pSurface->UnlockRect();
    127         if (FAILED(r))
    128         {
    129             return r;
    130         }
    131 
    132         *ppSurface = m_pSurface;
    133 
    134         return 0;
    135     } // get_surface()
    136 
    137 
    138     // process and render media data
    139     int render()
    140     {
    141         try
    142         {
    143             if (m_shutdown)
    144                 return 0;
    145 
    146             HRESULT r;
    147             LPDIRECT3DSURFACE9 pSurface;
    148 
    149             r = get_surface(&pSurface);
    150             if (FAILED(r))
    151             {
    152                 return -1;
    153             }
    154 
    155             switch (m_mode)
    156             {
    157                 case MODE_NOP:
    158                     // no processing
    159                     break;
    160 
    161                 case MODE_CPU:
    162                 {
    163                     // process video frame on CPU
    164                     D3DLOCKED_RECT memDesc = { 0, NULL };
    165                     RECT rc = { 0, 0, m_width, m_height };
    166 
    167                     r = pSurface->LockRect(&memDesc, &rc, 0);
    168                     if (FAILED(r))
    169                     {
    170                         return -1;
    171                     }
    172 
    173                     cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch);
    174 
    175                     if (!m_disableProcessing)
    176                     {
    177                         // blur D3D9 surface with OpenCV on CPU
    178                         cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7));
    179                     }
    180 
    181                     r = pSurface->UnlockRect();
    182                     if (FAILED(r))
    183                     {
    184                         return -1;
    185                     }
    186 
    187                     break;
    188                 }
    189 
    190                 case MODE_GPU:
    191                 {
    192                     // process video frame on GPU
    193                     cv::UMat u;
    194 
    195                     cv::directx::convertFromDirect3DSurface9(pSurface, u);
    196 
    197                     if (!m_disableProcessing)
    198                     {
    199                         // blur D3D9 surface with OpenCV on GPU with OpenCL
    200                         cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7));
    201                     }
    202 
    203                     cv::directx::convertToDirect3DSurface9(u, pSurface);
    204 
    205                     break;
    206                 }
    207 
    208             } // switch
    209 
    210             print_info(pSurface, m_mode, getFps(), m_oclDevName);
    211 
    212             // traditional DX render pipeline:
    213             //   BitBlt surface to backBuffer and flip backBuffer to frontBuffer
    214             r = m_pD3D9DevEx->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE);
    215             if (FAILED(r))
    216             {
    217                 return -1;
    218             }
    219 
    220             // present the back buffer contents to the display
    221             r = m_pD3D9DevEx->Present(NULL, NULL, NULL, NULL);
    222             if (FAILED(r))
    223             {
    224                 return -1;
    225             }
    226 
    227         } // try
    228 
    229         catch (cv::Exception& e)
    230         {
    231             std::cerr << "Exception: " << e.what() << std::endl;
    232             return 10;
    233         }
    234 
    235         return 0;
    236     } // render()
    237 
    238 
    239     void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName)
    240     {
    241         HDC hDC;
    242 
    243         HRESULT r = pSurface->GetDC(&hDC);
    244         if (FAILED(r))
    245         {
    246             return;
    247         }
    248 
    249         HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
    250 
    251         HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont);
    252 
    253         if (hOldFont)
    254         {
    255             TEXTMETRIC tm;
    256             ::GetTextMetrics(hDC, &tm);
    257 
    258             char buf[256];
    259             int  y = 0;
    260 
    261             buf[0] = 0;
    262             sprintf(buf, "Mode: %s", m_modeStr[mode].c_str());
    263             ::TextOut(hDC, 0, y, buf, (int)strlen(buf));
    264 
    265             y += tm.tmHeight;
    266             buf[0] = 0;
    267             sprintf(buf, "FPS: %2.1f", fps);
    268             ::TextOut(hDC, 0, y, buf, (int)strlen(buf));
    269 
    270             y += tm.tmHeight;
    271             buf[0] = 0;
    272             sprintf(buf, "OpenCL device: %s", oclDevName.c_str());
    273             ::TextOut(hDC, 0, y, buf, (int)strlen(buf));
    274 
    275             ::SelectObject(hDC, hOldFont);
    276         }
    277 
    278         r = pSurface->ReleaseDC(hDC);
    279 
    280         return;
    281     } // print_info()
    282 
    283 
    284     int cleanup(void)
    285     {
    286         SAFE_RELEASE(m_pSurface);
    287         SAFE_RELEASE(m_pBackBuffer);
    288         SAFE_RELEASE(m_pD3D9DevEx);
    289         SAFE_RELEASE(m_pD3D9Ex);
    290         D3DSample::cleanup();
    291         return 0;
    292     } // cleanup()
    293 
    294 private:
    295     LPDIRECT3D9EX        m_pD3D9Ex;
    296     LPDIRECT3DDEVICE9EX  m_pD3D9DevEx;
    297     LPDIRECT3DSURFACE9   m_pBackBuffer;
    298     LPDIRECT3DSURFACE9   m_pSurface;
    299     cv::ocl::Context     m_oclCtx;
    300     cv::String           m_oclPlatformName;
    301     cv::String           m_oclDevName;
    302 };
    303 
    304 
    305 // main func
    306 int main(int argc, char** argv)
    307 {
    308     std::string title = "D3D9Ex interop sample";
    309     return d3d_app<D3D9ExWinApp>(argc, argv, title);
    310 }
    311