• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
D3D9Channel(LPDIRECT3DDEVICE9 pd3DDevice,CriticalSectionWrapper * critSect,Trace * trace)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 
~D3D9Channel()61 D3D9Channel::~D3D9Channel()
62 {
63     //release the texture
64     if (_pTexture != NULL)
65     {
66         _pTexture->Release();
67         _pTexture = NULL;
68     }
69 }
70 
SetStreamSettings(uint16_t streamId,uint32_t zOrder,float startWidth,float startHeight,float stopWidth,float stopHeight)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 
GetStreamSettings(uint16_t streamId,uint32_t & zOrder,float & startWidth,float & startHeight,float & stopWidth,float & stopHeight)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 
GetTextureWidth()102 int D3D9Channel::GetTextureWidth()
103 {
104     return _width;
105 }
106 
GetTextureHeight()107 int D3D9Channel::GetTextureHeight()
108 {
109     return _height;
110 }
111 
112 // Called from video engine when a the frame size changed
FrameSizeChange(int width,int height,int numberOfStreams)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 
RenderFrame(const uint32_t streamId,I420VideoFrame & videoFrame)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.
DeliverFrame(const I420VideoFrame & videoFrame)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
RenderOffFrame()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
IsUpdated(bool & isUpdated)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
GetTexture()226 LPDIRECT3DTEXTURE9 D3D9Channel::GetTexture()
227 {
228     CriticalSectionScoped cs(_critSect);
229     return _pTexture;
230 }
231 
ReleaseTexture()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 
RecreateTexture(LPDIRECT3DDEVICE9 pd3DDevice)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  */
VideoRenderDirect3D9(Trace * trace,HWND hWnd,bool fullScreen)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 
~VideoRenderDirect3D9()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 
GetVertexProcessingCaps()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 
InitializeD3D(HWND hWnd,D3DPRESENT_PARAMETERS * pd3dpp)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 
ResetDevice()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 
InitDevice()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 
Init()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 
ChangeWindow(void * window)573 int32_t VideoRenderDirect3D9::ChangeWindow(void* window)
574 {
575     WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
576     return -1;
577 }
578 
UpdateRenderSurface()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
SetTransparentColor(LPDIRECT3DTEXTURE9 pTexture,DDCOLORKEY * transparentColorKey,DWORD width,DWORD height)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  */
ScreenUpdateThreadProc(void * obj)721 bool VideoRenderDirect3D9::ScreenUpdateThreadProc(void* obj)
722 {
723     return static_cast<VideoRenderDirect3D9*> (obj)->ScreenUpdateProcess();
724 }
725 
ScreenUpdateProcess()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 
CloseDevice()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 
GetD3DChannel(int channel)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 
DeleteChannel(const uint32_t streamId)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 
CreateChannel(const uint32_t channel,const uint32_t zOrder,const float left,const float top,const float right,const float bottom)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 
GetStreamSettings(const uint32_t channel,const uint16_t streamId,uint32_t & zOrder,float & left,float & top,float & right,float & bottom)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 
UpdateVerticeBuffer(LPDIRECT3DVERTEXBUFFER9 pVB,int offset,float startWidth,float startHeight,float stopWidth,float stopHeight)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 
StartRender()940 int32_t VideoRenderDirect3D9::StartRender()
941 {
942     WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
943     return 0;
944 }
945 
StopRender()946 int32_t VideoRenderDirect3D9::StopRender()
947 {
948     WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
949     return 0;
950 }
951 
IsFullScreen()952 bool VideoRenderDirect3D9::IsFullScreen()
953 {
954     return _fullScreen;
955 }
956 
SetCropping(const uint32_t channel,const uint16_t streamId,const float left,const float top,const float right,const float bottom)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 
SetTransparentBackground(const bool enable)966 int32_t VideoRenderDirect3D9::SetTransparentBackground(
967                                                                  const bool enable)
968 {
969     WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
970     return 0;
971 }
972 
SetText(const uint8_t textId,const uint8_t * text,const int32_t textLength,const uint32_t colorText,const uint32_t colorBg,const float left,const float top,const float rigth,const float bottom)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 
SetBitmap(const void * bitMap,const uint8_t pictureId,const void * colorKey,const float left,const float top,const float right,const float bottom)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 
GetGraphicsMemory(uint64_t & totalMemory,uint64_t & availableMemory)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 
ConfigureRenderer(const uint32_t channel,const uint16_t streamId,const unsigned int zOrder,const float left,const float top,const float right,const float bottom)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