Home | History | Annotate | Download | only in windows
      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(-1),
    298     _availableMemory(-1)
    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