OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 // Own include file | |
12 #include "webrtc/modules/video_render/windows/video_render_direct3d9.h" | |
13 | |
14 // System include files | |
15 #include <windows.h> | |
16 | |
17 // WebRtc include files | |
18 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | |
19 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
20 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
21 #include "webrtc/system_wrappers/include/trace.h" | |
22 | |
23 namespace webrtc { | |
24 | |
25 // A structure for our custom vertex type | |
26 struct CUSTOMVERTEX | |
27 { | |
28 FLOAT x, y, z; | |
29 DWORD color; // The vertex color | |
30 FLOAT u, v; | |
31 }; | |
32 | |
33 // Our custom FVF, which describes our custom vertex structure | |
34 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) | |
35 | |
36 /* | |
37 * | |
38 * D3D9Channel | |
39 * | |
40 */ | |
41 D3D9Channel::D3D9Channel(LPDIRECT3DDEVICE9 pd3DDevice, | |
42 CriticalSectionWrapper* critSect, | |
43 Trace* trace) : | |
44 _width(0), | |
45 _height(0), | |
46 _pd3dDevice(pd3DDevice), | |
47 _pTexture(NULL), | |
48 _bufferIsUpdated(false), | |
49 _critSect(critSect), | |
50 _streamId(0), | |
51 _zOrder(0), | |
52 _startWidth(0), | |
53 _startHeight(0), | |
54 _stopWidth(0), | |
55 _stopHeight(0) | |
56 { | |
57 | |
58 } | |
59 | |
60 D3D9Channel::~D3D9Channel() | |
61 { | |
62 //release the texture | |
63 if (_pTexture != NULL) | |
64 { | |
65 _pTexture->Release(); | |
66 _pTexture = NULL; | |
67 } | |
68 } | |
69 | |
70 void D3D9Channel::SetStreamSettings(uint16_t streamId, | |
71 uint32_t zOrder, | |
72 float startWidth, | |
73 float startHeight, | |
74 float stopWidth, | |
75 float stopHeight) | |
76 { | |
77 _streamId = streamId; | |
78 _zOrder = zOrder; | |
79 _startWidth = startWidth; | |
80 _startHeight = startHeight; | |
81 _stopWidth = stopWidth; | |
82 _stopHeight = stopHeight; | |
83 } | |
84 | |
85 int D3D9Channel::GetStreamSettings(uint16_t streamId, | |
86 uint32_t& zOrder, | |
87 float& startWidth, | |
88 float& startHeight, | |
89 float& stopWidth, | |
90 float& stopHeight) | |
91 { | |
92 streamId = _streamId; | |
93 zOrder = _zOrder; | |
94 startWidth = _startWidth; | |
95 startHeight = _startHeight; | |
96 stopWidth = _stopWidth; | |
97 stopHeight = _stopHeight; | |
98 return 0; | |
99 } | |
100 | |
101 int D3D9Channel::GetTextureWidth() | |
102 { | |
103 return _width; | |
104 } | |
105 | |
106 int D3D9Channel::GetTextureHeight() | |
107 { | |
108 return _height; | |
109 } | |
110 | |
111 // Called from video engine when a the frame size changed | |
112 int D3D9Channel::FrameSizeChange(int width, int height, int numberOfStreams) | |
113 { | |
114 WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1, | |
115 "FrameSizeChange, wifth: %d, height: %d, streams: %d", width, | |
116 height, numberOfStreams); | |
117 | |
118 CriticalSectionScoped cs(_critSect); | |
119 _width = width; | |
120 _height = height; | |
121 | |
122 //clean the previous texture | |
123 if (_pTexture != NULL) | |
124 { | |
125 _pTexture->Release(); | |
126 _pTexture = NULL; | |
127 } | |
128 | |
129 HRESULT ret = E_POINTER; | |
130 | |
131 if (_pd3dDevice) | |
132 ret = _pd3dDevice->CreateTexture(_width, _height, 1, 0, D3DFMT_A8R8G8B8, | |
133 D3DPOOL_MANAGED, &_pTexture, NULL); | |
134 | |
135 if (FAILED(ret)) | |
136 { | |
137 _pTexture = NULL; | |
138 return -1; | |
139 } | |
140 | |
141 return 0; | |
142 } | |
143 | |
144 int32_t D3D9Channel::RenderFrame(const uint32_t streamId, | |
145 const VideoFrame& videoFrame) { | |
146 CriticalSectionScoped cs(_critSect); | |
147 if (_width != videoFrame.width() || _height != videoFrame.height()) | |
148 { | |
149 if (FrameSizeChange(videoFrame.width(), videoFrame.height(), 1) == -1) | |
150 { | |
151 return -1; | |
152 } | |
153 } | |
154 return DeliverFrame(videoFrame); | |
155 } | |
156 | |
157 // Called from video engine when a new frame should be rendered. | |
158 int D3D9Channel::DeliverFrame(const VideoFrame& videoFrame) { | |
159 WEBRTC_TRACE(kTraceStream, kTraceVideo, -1, | |
160 "DeliverFrame to D3D9Channel"); | |
161 | |
162 CriticalSectionScoped cs(_critSect); | |
163 | |
164 // FIXME if _bufferIsUpdated is still true (not be renderred), do we want to | |
165 // update the texture? probably not | |
166 if (_bufferIsUpdated) { | |
167 WEBRTC_TRACE(kTraceStream, kTraceVideo, -1, | |
168 "Last frame hasn't been rendered yet. Drop this frame."); | |
169 return -1; | |
170 } | |
171 | |
172 if (!_pd3dDevice) { | |
173 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
174 "D3D for rendering not initialized."); | |
175 return -1; | |
176 } | |
177 | |
178 if (!_pTexture) { | |
179 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
180 "Texture for rendering not initialized."); | |
181 return -1; | |
182 } | |
183 | |
184 D3DLOCKED_RECT lr; | |
185 | |
186 if (FAILED(_pTexture->LockRect(0, &lr, NULL, 0))) { | |
187 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
188 "Failed to lock a texture in D3D9 Channel."); | |
189 return -1; | |
190 } | |
191 UCHAR* pRect = (UCHAR*) lr.pBits; | |
192 | |
193 ConvertFromI420(videoFrame, kARGB, 0, pRect); | |
194 | |
195 if (FAILED(_pTexture->UnlockRect(0))) { | |
196 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
197 "Failed to unlock a texture in D3D9 Channel."); | |
198 return -1; | |
199 } | |
200 | |
201 _bufferIsUpdated = true; | |
202 return 0; | |
203 } | |
204 | |
205 // Called by d3d channel owner to indicate the frame/texture has been rendered o
ff | |
206 int D3D9Channel::RenderOffFrame() | |
207 { | |
208 WEBRTC_TRACE(kTraceStream, kTraceVideo, -1, | |
209 "Frame has been rendered to the screen."); | |
210 CriticalSectionScoped cs(_critSect); | |
211 _bufferIsUpdated = false; | |
212 return 0; | |
213 } | |
214 | |
215 // Called by d3d channel owner to check if the texture is updated | |
216 int D3D9Channel::IsUpdated(bool& isUpdated) | |
217 { | |
218 CriticalSectionScoped cs(_critSect); | |
219 isUpdated = _bufferIsUpdated; | |
220 return 0; | |
221 } | |
222 | |
223 // Called by d3d channel owner to get the texture | |
224 LPDIRECT3DTEXTURE9 D3D9Channel::GetTexture() | |
225 { | |
226 CriticalSectionScoped cs(_critSect); | |
227 return _pTexture; | |
228 } | |
229 | |
230 int D3D9Channel::ReleaseTexture() | |
231 { | |
232 CriticalSectionScoped cs(_critSect); | |
233 | |
234 //release the texture | |
235 if (_pTexture != NULL) | |
236 { | |
237 _pTexture->Release(); | |
238 _pTexture = NULL; | |
239 } | |
240 _pd3dDevice = NULL; | |
241 return 0; | |
242 } | |
243 | |
244 int D3D9Channel::RecreateTexture(LPDIRECT3DDEVICE9 pd3DDevice) | |
245 { | |
246 CriticalSectionScoped cs(_critSect); | |
247 | |
248 _pd3dDevice = pd3DDevice; | |
249 | |
250 if (_pTexture != NULL) | |
251 { | |
252 _pTexture->Release(); | |
253 _pTexture = NULL; | |
254 } | |
255 | |
256 HRESULT ret; | |
257 | |
258 ret = _pd3dDevice->CreateTexture(_width, _height, 1, 0, D3DFMT_A8R8G8B8, | |
259 D3DPOOL_MANAGED, &_pTexture, NULL); | |
260 | |
261 if (FAILED(ret)) | |
262 { | |
263 _pTexture = NULL; | |
264 return -1; | |
265 } | |
266 | |
267 return 0; | |
268 } | |
269 | |
270 /* | |
271 * | |
272 * VideoRenderDirect3D9 | |
273 * | |
274 */ | |
275 VideoRenderDirect3D9::VideoRenderDirect3D9(Trace* trace, | |
276 HWND hWnd, | |
277 bool fullScreen) : | |
278 _refD3DCritsect(*CriticalSectionWrapper::CreateCriticalSection()), | |
279 _trace(trace), | |
280 _hWnd(hWnd), | |
281 _fullScreen(fullScreen), | |
282 _pTextureLogo(NULL), | |
283 _pVB(NULL), | |
284 _pd3dDevice(NULL), | |
285 _pD3D(NULL), | |
286 _d3dChannels(), | |
287 _d3dZorder(), | |
288 _screenUpdateEvent(NULL), | |
289 _logoLeft(0), | |
290 _logoTop(0), | |
291 _logoRight(0), | |
292 _logoBottom(0), | |
293 _pd3dSurface(NULL), | |
294 _totalMemory(0), | |
295 _availableMemory(0) | |
296 { | |
297 _screenUpdateThread.reset(new rtc::PlatformThread( | |
298 ScreenUpdateThreadProc, this, "ScreenUpdateThread")); | |
299 _screenUpdateEvent = EventTimerWrapper::Create(); | |
300 SetRect(&_originalHwndRect, 0, 0, 0, 0); | |
301 } | |
302 | |
303 VideoRenderDirect3D9::~VideoRenderDirect3D9() | |
304 { | |
305 //NOTE: we should not enter CriticalSection in here! | |
306 | |
307 // Signal event to exit thread, then delete it | |
308 rtc::PlatformThread* tmpPtr = _screenUpdateThread.release(); | |
309 if (tmpPtr) | |
310 { | |
311 _screenUpdateEvent->Set(); | |
312 _screenUpdateEvent->StopTimer(); | |
313 | |
314 tmpPtr->Stop(); | |
315 delete tmpPtr; | |
316 } | |
317 delete _screenUpdateEvent; | |
318 | |
319 //close d3d device | |
320 CloseDevice(); | |
321 | |
322 // Delete all channels | |
323 std::map<int, D3D9Channel*>::iterator it = _d3dChannels.begin(); | |
324 while (it != _d3dChannels.end()) | |
325 { | |
326 delete it->second; | |
327 it = _d3dChannels.erase(it); | |
328 } | |
329 // Clean the zOrder map | |
330 _d3dZorder.clear(); | |
331 | |
332 if (_fullScreen) | |
333 { | |
334 // restore hwnd to original size and position | |
335 ::SetWindowPos(_hWnd, HWND_NOTOPMOST, _originalHwndRect.left, | |
336 _originalHwndRect.top, _originalHwndRect.right | |
337 - _originalHwndRect.left, | |
338 _originalHwndRect.bottom - _originalHwndRect.top, | |
339 SWP_FRAMECHANGED); | |
340 ::RedrawWindow(_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | |
341 | RDW_ERASE); | |
342 ::RedrawWindow(NULL, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | |
343 | RDW_ERASE); | |
344 } | |
345 | |
346 delete &_refD3DCritsect; | |
347 } | |
348 | |
349 DWORD VideoRenderDirect3D9::GetVertexProcessingCaps() | |
350 { | |
351 D3DCAPS9 caps; | |
352 DWORD dwVertexProcessing = D3DCREATE_SOFTWARE_VERTEXPROCESSING; | |
353 if (SUCCEEDED(_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, | |
354 &caps))) | |
355 { | |
356 if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) | |
357 == D3DDEVCAPS_HWTRANSFORMANDLIGHT) | |
358 { | |
359 dwVertexProcessing = D3DCREATE_HARDWARE_VERTEXPROCESSING; | |
360 } | |
361 } | |
362 return dwVertexProcessing; | |
363 } | |
364 | |
365 int VideoRenderDirect3D9::InitializeD3D(HWND hWnd, | |
366 D3DPRESENT_PARAMETERS* pd3dpp) | |
367 { | |
368 // initialize Direct3D | |
369 if (NULL == (_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) | |
370 { | |
371 return -1; | |
372 } | |
373 | |
374 // determine what type of vertex processing to use based on the device capab
ilities | |
375 DWORD dwVertexProcessing = GetVertexProcessingCaps(); | |
376 | |
377 // get the display mode | |
378 D3DDISPLAYMODE d3ddm; | |
379 _pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); | |
380 pd3dpp->BackBufferFormat = d3ddm.Format; | |
381 | |
382 // create the D3D device | |
383 if (FAILED(_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, | |
384 dwVertexProcessing | D3DCREATE_MULTITHREADED | |
385 | D3DCREATE_FPU_PRESERVE, pd3dpp, | |
386 &_pd3dDevice))) | |
387 { | |
388 //try the ref device | |
389 if (FAILED(_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, | |
390 hWnd, dwVertexProcessing | |
391 | D3DCREATE_MULTITHREADED | |
392 | D3DCREATE_FPU_PRESERVE, | |
393 pd3dpp, &_pd3dDevice))) | |
394 { | |
395 return -1; | |
396 } | |
397 } | |
398 | |
399 return 0; | |
400 } | |
401 | |
402 int VideoRenderDirect3D9::ResetDevice() | |
403 { | |
404 WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1, | |
405 "VideoRenderDirect3D9::ResetDevice"); | |
406 | |
407 CriticalSectionScoped cs(&_refD3DCritsect); | |
408 | |
409 //release the channel texture | |
410 std::map<int, D3D9Channel*>::iterator it; | |
411 it = _d3dChannels.begin(); | |
412 while (it != _d3dChannels.end()) | |
413 { | |
414 if (it->second) | |
415 { | |
416 it->second->ReleaseTexture(); | |
417 } | |
418 it++; | |
419 } | |
420 | |
421 //close d3d device | |
422 if (CloseDevice() != 0) | |
423 { | |
424 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
425 "VideoRenderDirect3D9::ResetDevice failed to CloseDevice"); | |
426 return -1; | |
427 } | |
428 | |
429 //reinit d3d device | |
430 if (InitDevice() != 0) | |
431 { | |
432 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
433 "VideoRenderDirect3D9::ResetDevice failed to InitDevice"); | |
434 return -1; | |
435 } | |
436 | |
437 //recreate channel texture | |
438 it = _d3dChannels.begin(); | |
439 while (it != _d3dChannels.end()) | |
440 { | |
441 if (it->second) | |
442 { | |
443 it->second->RecreateTexture(_pd3dDevice); | |
444 } | |
445 it++; | |
446 } | |
447 | |
448 return 0; | |
449 } | |
450 | |
451 int VideoRenderDirect3D9::InitDevice() | |
452 { | |
453 // Set up the structure used to create the D3DDevice | |
454 ZeroMemory(&_d3dpp, sizeof(_d3dpp)); | |
455 _d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; | |
456 _d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; | |
457 if (GetWindowRect(_hWnd, &_originalHwndRect) == 0) | |
458 { | |
459 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
460 "VideoRenderDirect3D9::InitDevice Could not get window size
"); | |
461 return -1; | |
462 } | |
463 if (!_fullScreen) | |
464 { | |
465 _winWidth = _originalHwndRect.right - _originalHwndRect.left; | |
466 _winHeight = _originalHwndRect.bottom - _originalHwndRect.top; | |
467 _d3dpp.Windowed = TRUE; | |
468 _d3dpp.BackBufferHeight = 0; | |
469 _d3dpp.BackBufferWidth = 0; | |
470 } | |
471 else | |
472 { | |
473 _winWidth = (LONG) ::GetSystemMetrics(SM_CXSCREEN); | |
474 _winHeight = (LONG) ::GetSystemMetrics(SM_CYSCREEN); | |
475 _d3dpp.Windowed = FALSE; | |
476 _d3dpp.BackBufferWidth = _winWidth; | |
477 _d3dpp.BackBufferHeight = _winHeight; | |
478 _d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; | |
479 } | |
480 | |
481 if (InitializeD3D(_hWnd, &_d3dpp) == -1) | |
482 { | |
483 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
484 "VideoRenderDirect3D9::InitDevice failed in InitializeD3D")
; | |
485 return -1; | |
486 } | |
487 | |
488 // Turn off culling, so we see the front and back of the triangle | |
489 _pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); | |
490 | |
491 // Turn off D3D lighting, since we are providing our own vertex colors | |
492 _pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); | |
493 | |
494 // Settings for alpha blending | |
495 _pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); | |
496 _pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); | |
497 _pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); | |
498 | |
499 _pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); | |
500 _pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); | |
501 _pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR ); | |
502 | |
503 // Initialize Vertices | |
504 CUSTOMVERTEX Vertices[] = { | |
505 //front | |
506 { -1.0f, -1.0f, 0.0f, 0xffffffff, 0, 1 }, { -1.0f, 1.0f, 0.0f, | |
507 0xffffffff, 0, 0 }, | |
508 { 1.0f, -1.0f, 0.0f, 0xffffffff, 1, 1 }, { 1.0f, 1.0f, 0.0f, | |
509 0xffffffff, 1, 0 } }; | |
510 | |
511 // Create the vertex buffer. | |
512 if (FAILED(_pd3dDevice->CreateVertexBuffer(sizeof(Vertices), 0, | |
513 D3DFVF_CUSTOMVERTEX, | |
514 D3DPOOL_DEFAULT, &_pVB, NULL ))) | |
515 { | |
516 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
517 "Failed to create the vertex buffer."); | |
518 return -1; | |
519 } | |
520 | |
521 // Now we fill the vertex buffer. | |
522 VOID* pVertices; | |
523 if (FAILED(_pVB->Lock(0, sizeof(Vertices), (void**) &pVertices, 0))) | |
524 { | |
525 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
526 "Failed to lock the vertex buffer."); | |
527 return -1; | |
528 } | |
529 memcpy(pVertices, Vertices, sizeof(Vertices)); | |
530 _pVB->Unlock(); | |
531 | |
532 return 0; | |
533 } | |
534 | |
535 int32_t VideoRenderDirect3D9::Init() | |
536 { | |
537 WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1, | |
538 "VideoRenderDirect3D9::Init"); | |
539 | |
540 CriticalSectionScoped cs(&_refD3DCritsect); | |
541 | |
542 // Start rendering thread... | |
543 if (!_screenUpdateThread) | |
544 { | |
545 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Thread not created"); | |
546 return -1; | |
547 } | |
548 _screenUpdateThread->Start(); | |
549 _screenUpdateThread->SetPriority(rtc::kRealtimePriority); | |
550 | |
551 // Start the event triggering the render process | |
552 unsigned int monitorFreq = 60; | |
553 DEVMODE dm; | |
554 // initialize the DEVMODE structure | |
555 ZeroMemory(&dm, sizeof(dm)); | |
556 dm.dmSize = sizeof(dm); | |
557 if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) | |
558 { | |
559 monitorFreq = dm.dmDisplayFrequency; | |
560 } | |
561 _screenUpdateEvent->StartTimer(true, 1000 / monitorFreq); | |
562 | |
563 return InitDevice(); | |
564 } | |
565 | |
566 int32_t VideoRenderDirect3D9::ChangeWindow(void* window) | |
567 { | |
568 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); | |
569 return -1; | |
570 } | |
571 | |
572 int VideoRenderDirect3D9::UpdateRenderSurface() | |
573 { | |
574 CriticalSectionScoped cs(&_refD3DCritsect); | |
575 | |
576 // Check if there are any updated buffers | |
577 bool updated = false; | |
578 std::map<int, D3D9Channel*>::iterator it; | |
579 it = _d3dChannels.begin(); | |
580 while (it != _d3dChannels.end()) | |
581 { | |
582 | |
583 D3D9Channel* channel = it->second; | |
584 channel->IsUpdated(updated); | |
585 if (updated) | |
586 { | |
587 break; | |
588 } | |
589 it++; | |
590 } | |
591 //nothing is updated, continue | |
592 if (!updated) | |
593 return -1; | |
594 | |
595 // Clear the backbuffer to a black color | |
596 _pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, | |
597 0); | |
598 | |
599 // Begin the scene | |
600 if (SUCCEEDED(_pd3dDevice->BeginScene())) | |
601 { | |
602 _pd3dDevice->SetStreamSource(0, _pVB, 0, sizeof(CUSTOMVERTEX)); | |
603 _pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); | |
604 | |
605 //draw all the channels | |
606 //get texture from the channels | |
607 LPDIRECT3DTEXTURE9 textureFromChannel = NULL; | |
608 DWORD textureWidth, textureHeight; | |
609 | |
610 std::multimap<int, unsigned int>::reverse_iterator it; | |
611 it = _d3dZorder.rbegin(); | |
612 while (it != _d3dZorder.rend()) | |
613 { | |
614 // loop through all channels and streams in Z order | |
615 int channel = it->second & 0x0000ffff; | |
616 | |
617 std::map<int, D3D9Channel*>::iterator ddIt; | |
618 ddIt = _d3dChannels.find(channel); | |
619 if (ddIt != _d3dChannels.end()) | |
620 { | |
621 // found the channel | |
622 D3D9Channel* channelObj = ddIt->second; | |
623 if (channelObj) | |
624 { | |
625 textureFromChannel = channelObj->GetTexture(); | |
626 textureWidth = channelObj->GetTextureWidth(); | |
627 textureHeight = channelObj->GetTextureHeight(); | |
628 | |
629 uint32_t zOrder; | |
630 float startWidth, startHeight, stopWidth, stopHeight; | |
631 channelObj->GetStreamSettings(0, zOrder, startWidth, | |
632 startHeight, stopWidth, | |
633 stopHeight); | |
634 | |
635 //draw the video stream | |
636 UpdateVerticeBuffer(_pVB, 0, startWidth, startHeight, | |
637 stopWidth, stopHeight); | |
638 _pd3dDevice->SetTexture(0, textureFromChannel); | |
639 _pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); | |
640 | |
641 //Notice channel that this frame as been rendered | |
642 channelObj->RenderOffFrame(); | |
643 } | |
644 } | |
645 it++; | |
646 } | |
647 | |
648 //draw the logo | |
649 if (_pTextureLogo) | |
650 { | |
651 UpdateVerticeBuffer(_pVB, 0, _logoLeft, _logoTop, _logoRight, | |
652 _logoBottom); | |
653 _pd3dDevice->SetTexture(0, _pTextureLogo); | |
654 _pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); | |
655 } | |
656 | |
657 // End the scene | |
658 _pd3dDevice->EndScene(); | |
659 } | |
660 | |
661 // Present the backbuffer contents to the display | |
662 _pd3dDevice->Present(NULL, NULL, NULL, NULL ); | |
663 | |
664 return 0; | |
665 } | |
666 | |
667 //set the alpha value of the pixal with a particular colorkey as 0 | |
668 int VideoRenderDirect3D9::SetTransparentColor(LPDIRECT3DTEXTURE9 pTexture, | |
669 DDCOLORKEY* transparentColorKe
y, | |
670 DWORD width, | |
671 DWORD height) | |
672 { | |
673 D3DLOCKED_RECT lr; | |
674 if (!pTexture) | |
675 return -1; | |
676 | |
677 CriticalSectionScoped cs(&_refD3DCritsect); | |
678 if (SUCCEEDED(pTexture->LockRect(0, &lr, NULL, D3DLOCK_DISCARD))) | |
679 { | |
680 for (DWORD y = 0; y < height; y++) | |
681 { | |
682 DWORD dwOffset = y * width; | |
683 | |
684 for (DWORD x = 0; x < width; x) | |
685 { | |
686 DWORD temp = ((DWORD*) lr.pBits)[dwOffset + x]; | |
687 if ((temp & 0x00FFFFFF) | |
688 == transparentColorKey->dwColorSpaceLowValue) | |
689 { | |
690 temp &= 0x00FFFFFF; | |
691 } | |
692 else | |
693 { | |
694 temp |= 0xFF000000; | |
695 } | |
696 ((DWORD*) lr.pBits)[dwOffset + x] = temp; | |
697 x++; | |
698 } | |
699 } | |
700 pTexture->UnlockRect(0); | |
701 return 0; | |
702 } | |
703 return -1; | |
704 } | |
705 | |
706 /* | |
707 * | |
708 * Rendering process | |
709 * | |
710 */ | |
711 bool VideoRenderDirect3D9::ScreenUpdateThreadProc(void* obj) | |
712 { | |
713 return static_cast<VideoRenderDirect3D9*> (obj)->ScreenUpdateProcess(); | |
714 } | |
715 | |
716 bool VideoRenderDirect3D9::ScreenUpdateProcess() | |
717 { | |
718 _screenUpdateEvent->Wait(100); | |
719 | |
720 if (!_screenUpdateThread) | |
721 { | |
722 //stop the thread | |
723 return false; | |
724 } | |
725 if (!_pd3dDevice) | |
726 { | |
727 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
728 "d3dDevice not created."); | |
729 return true; | |
730 } | |
731 | |
732 HRESULT hr = _pd3dDevice->TestCooperativeLevel(); | |
733 | |
734 if (SUCCEEDED(hr)) | |
735 { | |
736 UpdateRenderSurface(); | |
737 } | |
738 | |
739 if (hr == D3DERR_DEVICELOST) | |
740 { | |
741 //Device is lost and cannot be reset yet | |
742 | |
743 } | |
744 else if (hr == D3DERR_DEVICENOTRESET) | |
745 { | |
746 //Lost but we can reset it now | |
747 //Note: the standard way is to call Reset, however for some reason doesn
't work here. | |
748 //so we will release the device and create it again. | |
749 ResetDevice(); | |
750 } | |
751 | |
752 return true; | |
753 } | |
754 | |
755 int VideoRenderDirect3D9::CloseDevice() | |
756 { | |
757 CriticalSectionScoped cs(&_refD3DCritsect); | |
758 WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1, | |
759 "VideoRenderDirect3D9::CloseDevice"); | |
760 | |
761 if (_pTextureLogo != NULL) | |
762 { | |
763 _pTextureLogo->Release(); | |
764 _pTextureLogo = NULL; | |
765 } | |
766 | |
767 if (_pVB != NULL) | |
768 { | |
769 _pVB->Release(); | |
770 _pVB = NULL; | |
771 } | |
772 | |
773 if (_pd3dDevice != NULL) | |
774 { | |
775 _pd3dDevice->Release(); | |
776 _pd3dDevice = NULL; | |
777 } | |
778 | |
779 if (_pD3D != NULL) | |
780 { | |
781 _pD3D->Release(); | |
782 _pD3D = NULL; | |
783 } | |
784 | |
785 if (_pd3dSurface != NULL) | |
786 _pd3dSurface->Release(); | |
787 return 0; | |
788 } | |
789 | |
790 D3D9Channel* VideoRenderDirect3D9::GetD3DChannel(int channel) | |
791 { | |
792 std::map<int, D3D9Channel*>::iterator ddIt; | |
793 ddIt = _d3dChannels.find(channel & 0x0000ffff); | |
794 D3D9Channel* ddobj = NULL; | |
795 if (ddIt != _d3dChannels.end()) | |
796 { | |
797 ddobj = ddIt->second; | |
798 } | |
799 if (ddobj == NULL) | |
800 { | |
801 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
802 "Direct3D render failed to find channel"); | |
803 return NULL; | |
804 } | |
805 return ddobj; | |
806 } | |
807 | |
808 int32_t VideoRenderDirect3D9::DeleteChannel(const uint32_t streamId) | |
809 { | |
810 CriticalSectionScoped cs(&_refD3DCritsect); | |
811 | |
812 | |
813 std::multimap<int, unsigned int>::iterator it; | |
814 it = _d3dZorder.begin(); | |
815 while (it != _d3dZorder.end()) | |
816 { | |
817 if ((streamId & 0x0000ffff) == (it->second & 0x0000ffff)) | |
818 { | |
819 it = _d3dZorder.erase(it); | |
820 break; | |
821 } | |
822 it++; | |
823 } | |
824 | |
825 std::map<int, D3D9Channel*>::iterator ddIt; | |
826 ddIt = _d3dChannels.find(streamId & 0x0000ffff); | |
827 if (ddIt != _d3dChannels.end()) | |
828 { | |
829 delete ddIt->second; | |
830 _d3dChannels.erase(ddIt); | |
831 return 0; | |
832 } | |
833 return -1; | |
834 } | |
835 | |
836 VideoRenderCallback* VideoRenderDirect3D9::CreateChannel(const uint32_t channel, | |
837 const uint32_t
zOrder, | |
838 const float lef
t, | |
839 const float top
, | |
840 const float rig
ht, | |
841 const float bot
tom) | |
842 { | |
843 CriticalSectionScoped cs(&_refD3DCritsect); | |
844 | |
845 //FIXME this should be done in VideoAPIWindows? stop the frame deliver first | |
846 //remove the old channel | |
847 DeleteChannel(channel); | |
848 | |
849 D3D9Channel* d3dChannel = new D3D9Channel(_pd3dDevice, | |
850 &_refD3DCritsect, _trace); | |
851 d3dChannel->SetStreamSettings(0, zOrder, left, top, right, bottom); | |
852 | |
853 // store channel | |
854 _d3dChannels[channel & 0x0000ffff] = d3dChannel; | |
855 | |
856 // store Z order | |
857 // default streamID is 0 | |
858 _d3dZorder.insert( | |
859 std::pair<int, unsigned int>(zOrder, channel & 0x0000ffff)
); | |
860 | |
861 return d3dChannel; | |
862 } | |
863 | |
864 int32_t VideoRenderDirect3D9::GetStreamSettings(const uint32_t channel, | |
865 const uint16_t streamId, | |
866 uint32_t& zOrder, | |
867 float& left, float& top, | |
868 float& right, float& bottom) | |
869 { | |
870 std::map<int, D3D9Channel*>::iterator ddIt; | |
871 ddIt = _d3dChannels.find(channel & 0x0000ffff); | |
872 D3D9Channel* ddobj = NULL; | |
873 if (ddIt != _d3dChannels.end()) | |
874 { | |
875 ddobj = ddIt->second; | |
876 } | |
877 if (ddobj == NULL) | |
878 { | |
879 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
880 "Direct3D render failed to find channel"); | |
881 return -1; | |
882 } | |
883 // Only allow one stream per channel, demuxing is | |
884 return ddobj->GetStreamSettings(0, zOrder, left, top, right, bottom); | |
885 } | |
886 | |
887 int VideoRenderDirect3D9::UpdateVerticeBuffer(LPDIRECT3DVERTEXBUFFER9 pVB, | |
888 int offset, | |
889 float startWidth, | |
890 float startHeight, | |
891 float stopWidth, | |
892 float stopHeight) | |
893 { | |
894 if (pVB == NULL) | |
895 return -1; | |
896 | |
897 float left, right, top, bottom; | |
898 | |
899 //update the vertice buffer | |
900 //0,1 => -1,1 | |
901 left = startWidth * 2 - 1; | |
902 right = stopWidth * 2 - 1; | |
903 | |
904 //0,1 => 1,-1 | |
905 top = 1 - startHeight * 2; | |
906 bottom = 1 - stopHeight * 2; | |
907 | |
908 CUSTOMVERTEX newVertices[] = { | |
909 //logo | |
910 { left, bottom, 0.0f, 0xffffffff, 0, 1 }, { left, top, 0.0f, | |
911 0xffffffff, 0, 0 }, | |
912 { right, bottom, 0.0f, 0xffffffff, 1, 1 }, { right, top, 0.0f, | |
913 0xffffffff, 1, 0 }, }; | |
914 // Now we fill the vertex buffer. | |
915 VOID* pVertices; | |
916 if (FAILED(pVB->Lock(sizeof(CUSTOMVERTEX) * offset, sizeof(newVertices), | |
917 (void**) &pVertices, 0))) | |
918 { | |
919 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
920 "Failed to lock the vertex buffer."); | |
921 return -1; | |
922 } | |
923 memcpy(pVertices, newVertices, sizeof(newVertices)); | |
924 pVB->Unlock(); | |
925 | |
926 return 0; | |
927 } | |
928 | |
929 int32_t VideoRenderDirect3D9::StartRender() | |
930 { | |
931 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); | |
932 return 0; | |
933 } | |
934 | |
935 int32_t VideoRenderDirect3D9::StopRender() | |
936 { | |
937 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); | |
938 return 0; | |
939 } | |
940 | |
941 bool VideoRenderDirect3D9::IsFullScreen() | |
942 { | |
943 return _fullScreen; | |
944 } | |
945 | |
946 int32_t VideoRenderDirect3D9::SetCropping(const uint32_t channel, | |
947 const uint16_t streamId, | |
948 const float left, const float top, | |
949 const float right, const float bottom) | |
950 { | |
951 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); | |
952 return 0; | |
953 } | |
954 | |
955 int32_t VideoRenderDirect3D9::SetTransparentBackground( | |
956 const bool enab
le) | |
957 { | |
958 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); | |
959 return 0; | |
960 } | |
961 | |
962 int32_t VideoRenderDirect3D9::SetText(const uint8_t textId, | |
963 const uint8_t* text, | |
964 const int32_t textLength, | |
965 const uint32_t colorText, | |
966 const uint32_t colorBg, | |
967 const float left, const float top, | |
968 const float rigth, const float bottom) | |
969 { | |
970 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); | |
971 return 0; | |
972 } | |
973 | |
974 int32_t VideoRenderDirect3D9::SetBitmap(const void* bitMap, | |
975 const uint8_t pictureId, | |
976 const void* colorKey, | |
977 const float left, const float top, | |
978 const float right, const float bottom) | |
979 { | |
980 if (!bitMap) | |
981 { | |
982 if (_pTextureLogo != NULL) | |
983 { | |
984 _pTextureLogo->Release(); | |
985 _pTextureLogo = NULL; | |
986 } | |
987 WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1, "Remove bitmap."); | |
988 return 0; | |
989 } | |
990 | |
991 // sanity | |
992 if (left > 1.0f || left < 0.0f || | |
993 top > 1.0f || top < 0.0f || | |
994 right > 1.0f || right < 0.0f || | |
995 bottom > 1.0f || bottom < 0.0f) | |
996 { | |
997 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
998 "Direct3D SetBitmap invalid parameter"); | |
999 return -1; | |
1000 } | |
1001 | |
1002 if ((bottom <= top) || (right <= left)) | |
1003 { | |
1004 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
1005 "Direct3D SetBitmap invalid parameter"); | |
1006 return -1; | |
1007 } | |
1008 | |
1009 CriticalSectionScoped cs(&_refD3DCritsect); | |
1010 | |
1011 unsigned char* srcPtr; | |
1012 HGDIOBJ oldhand; | |
1013 BITMAPINFO pbi; | |
1014 BITMAP bmap; | |
1015 HDC hdcNew; | |
1016 hdcNew = CreateCompatibleDC(0); | |
1017 // Fill out the BITMAP structure. | |
1018 GetObject((HBITMAP)bitMap, sizeof(bmap), &bmap); | |
1019 //Select the bitmap handle into the new device context. | |
1020 oldhand = SelectObject(hdcNew, (HGDIOBJ) bitMap); | |
1021 // we are done with this object | |
1022 DeleteObject(oldhand); | |
1023 pbi.bmiHeader.biSize = 40; | |
1024 pbi.bmiHeader.biWidth = bmap.bmWidth; | |
1025 pbi.bmiHeader.biHeight = bmap.bmHeight; | |
1026 pbi.bmiHeader.biPlanes = 1; | |
1027 pbi.bmiHeader.biBitCount = bmap.bmBitsPixel; | |
1028 pbi.bmiHeader.biCompression = BI_RGB; | |
1029 pbi.bmiHeader.biSizeImage = bmap.bmWidth * bmap.bmHeight * 3; | |
1030 srcPtr = new unsigned char[bmap.bmWidth * bmap.bmHeight * 4]; | |
1031 // the original un-stretched image in RGB24 | |
1032 int pixelHeight = GetDIBits(hdcNew, (HBITMAP)bitMap, 0, bmap.bmHeight, srcPt
r, &pbi, | |
1033 DIB_RGB_COLORS); | |
1034 if (pixelHeight == 0) | |
1035 { | |
1036 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
1037 "Direct3D failed to GetDIBits in SetBitmap"); | |
1038 delete[] srcPtr; | |
1039 return -1; | |
1040 } | |
1041 DeleteDC(hdcNew); | |
1042 if (pbi.bmiHeader.biBitCount != 24 && pbi.bmiHeader.biBitCount != 32) | |
1043 { | |
1044 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
1045 "Direct3D failed to SetBitmap invalid bit depth"); | |
1046 delete[] srcPtr; | |
1047 return -1; | |
1048 } | |
1049 | |
1050 HRESULT ret; | |
1051 //release the previous logo texture | |
1052 if (_pTextureLogo != NULL) | |
1053 { | |
1054 _pTextureLogo->Release(); | |
1055 _pTextureLogo = NULL; | |
1056 } | |
1057 ret = _pd3dDevice->CreateTexture(bmap.bmWidth, bmap.bmHeight, 1, 0, | |
1058 D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, | |
1059 &_pTextureLogo, NULL); | |
1060 if (FAILED(ret)) | |
1061 { | |
1062 _pTextureLogo = NULL; | |
1063 delete[] srcPtr; | |
1064 return -1; | |
1065 } | |
1066 if (!_pTextureLogo) | |
1067 { | |
1068 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
1069 "Texture for rendering not initialized."); | |
1070 delete[] srcPtr; | |
1071 return -1; | |
1072 } | |
1073 | |
1074 D3DLOCKED_RECT lr; | |
1075 if (FAILED(_pTextureLogo->LockRect(0, &lr, NULL, 0))) | |
1076 { | |
1077 delete[] srcPtr; | |
1078 return -1; | |
1079 } | |
1080 unsigned char* dstPtr = (UCHAR*) lr.pBits; | |
1081 int pitch = bmap.bmWidth * 4; | |
1082 | |
1083 if (pbi.bmiHeader.biBitCount == 24) | |
1084 { | |
1085 ConvertRGB24ToARGB(srcPtr, dstPtr, bmap.bmWidth, bmap.bmHeight, 0); | |
1086 } | |
1087 else | |
1088 { | |
1089 unsigned char* srcTmp = srcPtr + (bmap.bmWidth * 4) * (bmap.bmHeight - 1
); | |
1090 for (int i = 0; i < bmap.bmHeight; ++i) | |
1091 { | |
1092 memcpy(dstPtr, srcTmp, bmap.bmWidth * 4); | |
1093 srcTmp -= bmap.bmWidth * 4; | |
1094 dstPtr += pitch; | |
1095 } | |
1096 } | |
1097 | |
1098 delete[] srcPtr; | |
1099 if (FAILED(_pTextureLogo->UnlockRect(0))) | |
1100 { | |
1101 return -1; | |
1102 } | |
1103 | |
1104 if (colorKey) | |
1105 { | |
1106 DDCOLORKEY* ddColorKey = | |
1107 static_cast<DDCOLORKEY*> (const_cast<void*> (colorKey)); | |
1108 SetTransparentColor(_pTextureLogo, ddColorKey, bmap.bmWidth, | |
1109 bmap.bmHeight); | |
1110 } | |
1111 | |
1112 //update the vertice buffer | |
1113 //0,1 => -1,1 | |
1114 _logoLeft = left; | |
1115 _logoRight = right; | |
1116 | |
1117 //0,1 => 1,-1 | |
1118 _logoTop = top; | |
1119 _logoBottom = bottom; | |
1120 | |
1121 return 0; | |
1122 | |
1123 } | |
1124 | |
1125 int32_t VideoRenderDirect3D9::GetGraphicsMemory(uint64_t& totalMemory, | |
1126 uint64_t& availableMemory) | |
1127 { | |
1128 totalMemory = _totalMemory; | |
1129 availableMemory = _availableMemory; | |
1130 return 0; | |
1131 } | |
1132 | |
1133 int32_t VideoRenderDirect3D9::ConfigureRenderer(const uint32_t channel, | |
1134 const uint16_t streamId, | |
1135 const unsigned int zOrder, | |
1136 const float left, | |
1137 const float top, | |
1138 const float right, | |
1139 const float bottom) | |
1140 { | |
1141 std::map<int, D3D9Channel*>::iterator ddIt; | |
1142 ddIt = _d3dChannels.find(channel & 0x0000ffff); | |
1143 D3D9Channel* ddobj = NULL; | |
1144 if (ddIt != _d3dChannels.end()) | |
1145 { | |
1146 ddobj = ddIt->second; | |
1147 } | |
1148 if (ddobj == NULL) | |
1149 { | |
1150 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, | |
1151 "Direct3D render failed to find channel"); | |
1152 return -1; | |
1153 } | |
1154 // Only allow one stream per channel, demuxing is | |
1155 ddobj->SetStreamSettings(0, zOrder, left, top, right, bottom); | |
1156 | |
1157 return 0; | |
1158 } | |
1159 | |
1160 } // namespace webrtc | |
OLD | NEW |