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