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 D3D9WinApp : public D3DSample
28 {
29 public:
D3D9WinApp(int width,int height,std::string & window_name,cv::VideoCapture & cap)30 D3D9WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
31 D3DSample(width, height, window_name, cap) {}
32
~D3D9WinApp()33 ~D3D9WinApp() {}
34
create(void)35 int create(void)
36 {
37 // base initialization
38 D3DSample::create();
39
40 // initialize DirectX
41 HRESULT r;
42
43 m_pD3D9 = ::Direct3DCreate9(D3D_SDK_VERSION);
44 if (NULL == m_pD3D9)
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_pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, &m_pD3D9Dev);
71 if (FAILED(r))
72 {
73 return -1;
74 }
75
76 r = m_pD3D9Dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
77 if (FAILED(r))
78 {
79 return -1;
80 }
81
82 r = m_pD3D9Dev->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_pD3D9Dev);
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
get_surface(LPDIRECT3DSURFACE9 * ppSurface)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
render()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_pD3D9Dev->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_pD3D9Dev->Present(NULL, NULL, NULL, NULL);
222 if (FAILED(r))
223 {
224 return -1;
225 }
226 } // try
227
228 catch (cv::Exception& e)
229 {
230 std::cerr << "Exception: " << e.what() << std::endl;
231 return 10;
232 }
233
234 return 0;
235 } // render()
236
237
print_info(LPDIRECT3DSURFACE9 pSurface,int mode,float fps,cv::String oclDevName)238 void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName)
239 {
240 HDC hDC;
241
242 HRESULT r = pSurface->GetDC(&hDC);
243 if (FAILED(r))
244 {
245 return;
246 }
247
248 HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
249
250 HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont);
251
252 if (hOldFont)
253 {
254 TEXTMETRIC tm;
255 ::GetTextMetrics(hDC, &tm);
256
257 char buf[256];
258 int y = 0;
259
260 buf[0] = 0;
261 sprintf(buf, "Mode: %s", m_modeStr[mode].c_str());
262 ::TextOut(hDC, 0, y, buf, (int)strlen(buf));
263
264 y += tm.tmHeight;
265 buf[0] = 0;
266 sprintf(buf, "FPS: %2.1f", fps);
267 ::TextOut(hDC, 0, y, buf, (int)strlen(buf));
268
269 y += tm.tmHeight;
270 buf[0] = 0;
271 sprintf(buf, "OpenCL device: %s", oclDevName.c_str());
272 ::TextOut(hDC, 0, y, buf, (int)strlen(buf));
273
274 ::SelectObject(hDC, hOldFont);
275 }
276
277 r = pSurface->ReleaseDC(hDC);
278
279 return;
280 } // print_info()
281
282
cleanup(void)283 int cleanup(void)
284 {
285 SAFE_RELEASE(m_pSurface);
286 SAFE_RELEASE(m_pBackBuffer);
287 SAFE_RELEASE(m_pD3D9Dev);
288 SAFE_RELEASE(m_pD3D9);
289 D3DSample::cleanup();
290 return 0;
291 } // cleanup()
292
293 private:
294 LPDIRECT3D9 m_pD3D9;
295 LPDIRECT3DDEVICE9 m_pD3D9Dev;
296 LPDIRECT3DSURFACE9 m_pBackBuffer;
297 LPDIRECT3DSURFACE9 m_pSurface;
298 cv::ocl::Context m_oclCtx;
299 cv::String m_oclPlatformName;
300 cv::String m_oclDevName;
301 };
302
303
304 // main func
main(int argc,char ** argv)305 int main(int argc, char** argv)
306 {
307 std::string title = "D3D9 interop sample";
308 return d3d_app<D3D9WinApp>(argc, argv, title);
309 }
310