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 23namespace webrtc { 24 25// A structure for our custom vertex type 26struct 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 */ 41D3D9Channel::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 60D3D9Channel::~D3D9Channel() 61{ 62 //release the texture 63 if (_pTexture != NULL) 64 { 65 _pTexture->Release(); 66 _pTexture = NULL; 67 } 68} 69 70void 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 85int 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 101int D3D9Channel::GetTextureWidth() 102{ 103 return _width; 104} 105 106int D3D9Channel::GetTextureHeight() 107{ 108 return _height; 109} 110 111// Called from video engine when a the frame size changed 112int 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 144int32_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. 158int 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 off 206int 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 216int 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 224LPDIRECT3DTEXTURE9 D3D9Channel::GetTexture() 225{ 226 CriticalSectionScoped cs(_critSect); 227 return _pTexture; 228} 229 230int 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 244int 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 */ 275VideoRenderDirect3D9::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 303VideoRenderDirect3D9::~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 349DWORD 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 365int 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 capabilities 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 402int 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 451int 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 535int32_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 566int32_t VideoRenderDirect3D9::ChangeWindow(void* window) 567{ 568 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); 569 return -1; 570} 571 572int 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 668int VideoRenderDirect3D9::SetTransparentColor(LPDIRECT3DTEXTURE9 pTexture, 669 DDCOLORKEY* transparentColorKey, 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 */ 711bool VideoRenderDirect3D9::ScreenUpdateThreadProc(void* obj) 712{ 713 return static_cast<VideoRenderDirect3D9*> (obj)->ScreenUpdateProcess(); 714} 715 716bool 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 755int 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 790D3D9Channel* 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 808int32_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 836VideoRenderCallback* VideoRenderDirect3D9::CreateChannel(const uint32_t channel, 837 const uint32_t zOrder, 838 const float left, 839 const float top, 840 const float right, 841 const float bottom) 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 864int32_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 887int 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 929int32_t VideoRenderDirect3D9::StartRender() 930{ 931 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); 932 return 0; 933} 934 935int32_t VideoRenderDirect3D9::StopRender() 936{ 937 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); 938 return 0; 939} 940 941bool VideoRenderDirect3D9::IsFullScreen() 942{ 943 return _fullScreen; 944} 945 946int32_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 955int32_t VideoRenderDirect3D9::SetTransparentBackground( 956 const bool enable) 957{ 958 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported."); 959 return 0; 960} 961 962int32_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 974int32_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, srcPtr, &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 1125int32_t VideoRenderDirect3D9::GetGraphicsMemory(uint64_t& totalMemory, 1126 uint64_t& availableMemory) 1127{ 1128 if (_totalMemory == -1 || _availableMemory == -1) 1129 { 1130 totalMemory = 0; 1131 availableMemory = 0; 1132 return -1; 1133 } 1134 totalMemory = _totalMemory; 1135 availableMemory = _availableMemory; 1136 return 0; 1137} 1138 1139int32_t VideoRenderDirect3D9::ConfigureRenderer(const uint32_t channel, 1140 const uint16_t streamId, 1141 const unsigned int zOrder, 1142 const float left, 1143 const float top, 1144 const float right, 1145 const float bottom) 1146{ 1147 std::map<int, D3D9Channel*>::iterator ddIt; 1148 ddIt = _d3dChannels.find(channel & 0x0000ffff); 1149 D3D9Channel* ddobj = NULL; 1150 if (ddIt != _d3dChannels.end()) 1151 { 1152 ddobj = ddIt->second; 1153 } 1154 if (ddobj == NULL) 1155 { 1156 WEBRTC_TRACE(kTraceError, kTraceVideo, -1, 1157 "Direct3D render failed to find channel"); 1158 return -1; 1159 } 1160 // Only allow one stream per channel, demuxing is 1161 ddobj->SetStreamSettings(0, zOrder, left, top, right, bottom); 1162 1163 return 0; 1164} 1165 1166} // namespace webrtc 1167