Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(459)

Unified Diff: webrtc/modules/video_render/windows/video_render_direct3d9.cc

Issue 1923613003: Revert of Delete video_render module. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/video_render/windows/video_render_direct3d9.cc
diff --git a/webrtc/modules/video_render/windows/video_render_direct3d9.cc b/webrtc/modules/video_render/windows/video_render_direct3d9.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b59b944e483405818db95708c5793ac8cdc28ede
--- /dev/null
+++ b/webrtc/modules/video_render/windows/video_render_direct3d9.cc
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// Own include file
+#include "webrtc/modules/video_render/windows/video_render_direct3d9.h"
+
+// System include files
+#include <windows.h>
+
+// WebRtc include files
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/include/event_wrapper.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+
+// A structure for our custom vertex type
+struct CUSTOMVERTEX
+{
+ FLOAT x, y, z;
+ DWORD color; // The vertex color
+ FLOAT u, v;
+};
+
+// Our custom FVF, which describes our custom vertex structure
+#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
+
+/*
+ *
+ * D3D9Channel
+ *
+ */
+D3D9Channel::D3D9Channel(LPDIRECT3DDEVICE9 pd3DDevice,
+ CriticalSectionWrapper* critSect,
+ Trace* trace) :
+ _width(0),
+ _height(0),
+ _pd3dDevice(pd3DDevice),
+ _pTexture(NULL),
+ _bufferIsUpdated(false),
+ _critSect(critSect),
+ _streamId(0),
+ _zOrder(0),
+ _startWidth(0),
+ _startHeight(0),
+ _stopWidth(0),
+ _stopHeight(0)
+{
+
+}
+
+D3D9Channel::~D3D9Channel()
+{
+ //release the texture
+ if (_pTexture != NULL)
+ {
+ _pTexture->Release();
+ _pTexture = NULL;
+ }
+}
+
+void D3D9Channel::SetStreamSettings(uint16_t streamId,
+ uint32_t zOrder,
+ float startWidth,
+ float startHeight,
+ float stopWidth,
+ float stopHeight)
+{
+ _streamId = streamId;
+ _zOrder = zOrder;
+ _startWidth = startWidth;
+ _startHeight = startHeight;
+ _stopWidth = stopWidth;
+ _stopHeight = stopHeight;
+}
+
+int D3D9Channel::GetStreamSettings(uint16_t streamId,
+ uint32_t& zOrder,
+ float& startWidth,
+ float& startHeight,
+ float& stopWidth,
+ float& stopHeight)
+{
+ streamId = _streamId;
+ zOrder = _zOrder;
+ startWidth = _startWidth;
+ startHeight = _startHeight;
+ stopWidth = _stopWidth;
+ stopHeight = _stopHeight;
+ return 0;
+}
+
+int D3D9Channel::GetTextureWidth()
+{
+ return _width;
+}
+
+int D3D9Channel::GetTextureHeight()
+{
+ return _height;
+}
+
+// Called from video engine when a the frame size changed
+int D3D9Channel::FrameSizeChange(int width, int height, int numberOfStreams)
+{
+ WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1,
+ "FrameSizeChange, wifth: %d, height: %d, streams: %d", width,
+ height, numberOfStreams);
+
+ CriticalSectionScoped cs(_critSect);
+ _width = width;
+ _height = height;
+
+ //clean the previous texture
+ if (_pTexture != NULL)
+ {
+ _pTexture->Release();
+ _pTexture = NULL;
+ }
+
+ HRESULT ret = E_POINTER;
+
+ if (_pd3dDevice)
+ ret = _pd3dDevice->CreateTexture(_width, _height, 1, 0, D3DFMT_A8R8G8B8,
+ D3DPOOL_MANAGED, &_pTexture, NULL);
+
+ if (FAILED(ret))
+ {
+ _pTexture = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int32_t D3D9Channel::RenderFrame(const uint32_t streamId,
+ const VideoFrame& videoFrame) {
+ CriticalSectionScoped cs(_critSect);
+ if (_width != videoFrame.width() || _height != videoFrame.height())
+ {
+ if (FrameSizeChange(videoFrame.width(), videoFrame.height(), 1) == -1)
+ {
+ return -1;
+ }
+ }
+ return DeliverFrame(videoFrame);
+}
+
+// Called from video engine when a new frame should be rendered.
+int D3D9Channel::DeliverFrame(const VideoFrame& videoFrame) {
+ WEBRTC_TRACE(kTraceStream, kTraceVideo, -1,
+ "DeliverFrame to D3D9Channel");
+
+ CriticalSectionScoped cs(_critSect);
+
+ // FIXME if _bufferIsUpdated is still true (not be renderred), do we want to
+ // update the texture? probably not
+ if (_bufferIsUpdated) {
+ WEBRTC_TRACE(kTraceStream, kTraceVideo, -1,
+ "Last frame hasn't been rendered yet. Drop this frame.");
+ return -1;
+ }
+
+ if (!_pd3dDevice) {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "D3D for rendering not initialized.");
+ return -1;
+ }
+
+ if (!_pTexture) {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Texture for rendering not initialized.");
+ return -1;
+ }
+
+ D3DLOCKED_RECT lr;
+
+ if (FAILED(_pTexture->LockRect(0, &lr, NULL, 0))) {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Failed to lock a texture in D3D9 Channel.");
+ return -1;
+ }
+ UCHAR* pRect = (UCHAR*) lr.pBits;
+
+ ConvertFromI420(videoFrame, kARGB, 0, pRect);
+
+ if (FAILED(_pTexture->UnlockRect(0))) {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Failed to unlock a texture in D3D9 Channel.");
+ return -1;
+ }
+
+ _bufferIsUpdated = true;
+ return 0;
+}
+
+// Called by d3d channel owner to indicate the frame/texture has been rendered off
+int D3D9Channel::RenderOffFrame()
+{
+ WEBRTC_TRACE(kTraceStream, kTraceVideo, -1,
+ "Frame has been rendered to the screen.");
+ CriticalSectionScoped cs(_critSect);
+ _bufferIsUpdated = false;
+ return 0;
+}
+
+// Called by d3d channel owner to check if the texture is updated
+int D3D9Channel::IsUpdated(bool& isUpdated)
+{
+ CriticalSectionScoped cs(_critSect);
+ isUpdated = _bufferIsUpdated;
+ return 0;
+}
+
+// Called by d3d channel owner to get the texture
+LPDIRECT3DTEXTURE9 D3D9Channel::GetTexture()
+{
+ CriticalSectionScoped cs(_critSect);
+ return _pTexture;
+}
+
+int D3D9Channel::ReleaseTexture()
+{
+ CriticalSectionScoped cs(_critSect);
+
+ //release the texture
+ if (_pTexture != NULL)
+ {
+ _pTexture->Release();
+ _pTexture = NULL;
+ }
+ _pd3dDevice = NULL;
+ return 0;
+}
+
+int D3D9Channel::RecreateTexture(LPDIRECT3DDEVICE9 pd3DDevice)
+{
+ CriticalSectionScoped cs(_critSect);
+
+ _pd3dDevice = pd3DDevice;
+
+ if (_pTexture != NULL)
+ {
+ _pTexture->Release();
+ _pTexture = NULL;
+ }
+
+ HRESULT ret;
+
+ ret = _pd3dDevice->CreateTexture(_width, _height, 1, 0, D3DFMT_A8R8G8B8,
+ D3DPOOL_MANAGED, &_pTexture, NULL);
+
+ if (FAILED(ret))
+ {
+ _pTexture = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * VideoRenderDirect3D9
+ *
+ */
+VideoRenderDirect3D9::VideoRenderDirect3D9(Trace* trace,
+ HWND hWnd,
+ bool fullScreen) :
+ _refD3DCritsect(*CriticalSectionWrapper::CreateCriticalSection()),
+ _trace(trace),
+ _hWnd(hWnd),
+ _fullScreen(fullScreen),
+ _pTextureLogo(NULL),
+ _pVB(NULL),
+ _pd3dDevice(NULL),
+ _pD3D(NULL),
+ _d3dChannels(),
+ _d3dZorder(),
+ _screenUpdateEvent(NULL),
+ _logoLeft(0),
+ _logoTop(0),
+ _logoRight(0),
+ _logoBottom(0),
+ _pd3dSurface(NULL),
+ _totalMemory(0),
+ _availableMemory(0)
+{
+ _screenUpdateThread.reset(new rtc::PlatformThread(
+ ScreenUpdateThreadProc, this, "ScreenUpdateThread"));
+ _screenUpdateEvent = EventTimerWrapper::Create();
+ SetRect(&_originalHwndRect, 0, 0, 0, 0);
+}
+
+VideoRenderDirect3D9::~VideoRenderDirect3D9()
+{
+ //NOTE: we should not enter CriticalSection in here!
+
+ // Signal event to exit thread, then delete it
+ rtc::PlatformThread* tmpPtr = _screenUpdateThread.release();
+ if (tmpPtr)
+ {
+ _screenUpdateEvent->Set();
+ _screenUpdateEvent->StopTimer();
+
+ tmpPtr->Stop();
+ delete tmpPtr;
+ }
+ delete _screenUpdateEvent;
+
+ //close d3d device
+ CloseDevice();
+
+ // Delete all channels
+ std::map<int, D3D9Channel*>::iterator it = _d3dChannels.begin();
+ while (it != _d3dChannels.end())
+ {
+ delete it->second;
+ it = _d3dChannels.erase(it);
+ }
+ // Clean the zOrder map
+ _d3dZorder.clear();
+
+ if (_fullScreen)
+ {
+ // restore hwnd to original size and position
+ ::SetWindowPos(_hWnd, HWND_NOTOPMOST, _originalHwndRect.left,
+ _originalHwndRect.top, _originalHwndRect.right
+ - _originalHwndRect.left,
+ _originalHwndRect.bottom - _originalHwndRect.top,
+ SWP_FRAMECHANGED);
+ ::RedrawWindow(_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW
+ | RDW_ERASE);
+ ::RedrawWindow(NULL, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW
+ | RDW_ERASE);
+ }
+
+ delete &_refD3DCritsect;
+}
+
+DWORD VideoRenderDirect3D9::GetVertexProcessingCaps()
+{
+ D3DCAPS9 caps;
+ DWORD dwVertexProcessing = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+ if (SUCCEEDED(_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
+ &caps)))
+ {
+ if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
+ == D3DDEVCAPS_HWTRANSFORMANDLIGHT)
+ {
+ dwVertexProcessing = D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ }
+ }
+ return dwVertexProcessing;
+}
+
+int VideoRenderDirect3D9::InitializeD3D(HWND hWnd,
+ D3DPRESENT_PARAMETERS* pd3dpp)
+{
+ // initialize Direct3D
+ if (NULL == (_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
+ {
+ return -1;
+ }
+
+ // determine what type of vertex processing to use based on the device capabilities
+ DWORD dwVertexProcessing = GetVertexProcessingCaps();
+
+ // get the display mode
+ D3DDISPLAYMODE d3ddm;
+ _pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
+ pd3dpp->BackBufferFormat = d3ddm.Format;
+
+ // create the D3D device
+ if (FAILED(_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
+ dwVertexProcessing | D3DCREATE_MULTITHREADED
+ | D3DCREATE_FPU_PRESERVE, pd3dpp,
+ &_pd3dDevice)))
+ {
+ //try the ref device
+ if (FAILED(_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF,
+ hWnd, dwVertexProcessing
+ | D3DCREATE_MULTITHREADED
+ | D3DCREATE_FPU_PRESERVE,
+ pd3dpp, &_pd3dDevice)))
+ {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int VideoRenderDirect3D9::ResetDevice()
+{
+ WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1,
+ "VideoRenderDirect3D9::ResetDevice");
+
+ CriticalSectionScoped cs(&_refD3DCritsect);
+
+ //release the channel texture
+ std::map<int, D3D9Channel*>::iterator it;
+ it = _d3dChannels.begin();
+ while (it != _d3dChannels.end())
+ {
+ if (it->second)
+ {
+ it->second->ReleaseTexture();
+ }
+ it++;
+ }
+
+ //close d3d device
+ if (CloseDevice() != 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "VideoRenderDirect3D9::ResetDevice failed to CloseDevice");
+ return -1;
+ }
+
+ //reinit d3d device
+ if (InitDevice() != 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "VideoRenderDirect3D9::ResetDevice failed to InitDevice");
+ return -1;
+ }
+
+ //recreate channel texture
+ it = _d3dChannels.begin();
+ while (it != _d3dChannels.end())
+ {
+ if (it->second)
+ {
+ it->second->RecreateTexture(_pd3dDevice);
+ }
+ it++;
+ }
+
+ return 0;
+}
+
+int VideoRenderDirect3D9::InitDevice()
+{
+ // Set up the structure used to create the D3DDevice
+ ZeroMemory(&_d3dpp, sizeof(_d3dpp));
+ _d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ _d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
+ if (GetWindowRect(_hWnd, &_originalHwndRect) == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "VideoRenderDirect3D9::InitDevice Could not get window size");
+ return -1;
+ }
+ if (!_fullScreen)
+ {
+ _winWidth = _originalHwndRect.right - _originalHwndRect.left;
+ _winHeight = _originalHwndRect.bottom - _originalHwndRect.top;
+ _d3dpp.Windowed = TRUE;
+ _d3dpp.BackBufferHeight = 0;
+ _d3dpp.BackBufferWidth = 0;
+ }
+ else
+ {
+ _winWidth = (LONG) ::GetSystemMetrics(SM_CXSCREEN);
+ _winHeight = (LONG) ::GetSystemMetrics(SM_CYSCREEN);
+ _d3dpp.Windowed = FALSE;
+ _d3dpp.BackBufferWidth = _winWidth;
+ _d3dpp.BackBufferHeight = _winHeight;
+ _d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ }
+
+ if (InitializeD3D(_hWnd, &_d3dpp) == -1)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "VideoRenderDirect3D9::InitDevice failed in InitializeD3D");
+ return -1;
+ }
+
+ // Turn off culling, so we see the front and back of the triangle
+ _pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+
+ // Turn off D3D lighting, since we are providing our own vertex colors
+ _pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
+
+ // Settings for alpha blending
+ _pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+ _pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+ _pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+
+ _pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
+ _pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
+ _pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR );
+
+ // Initialize Vertices
+ CUSTOMVERTEX Vertices[] = {
+ //front
+ { -1.0f, -1.0f, 0.0f, 0xffffffff, 0, 1 }, { -1.0f, 1.0f, 0.0f,
+ 0xffffffff, 0, 0 },
+ { 1.0f, -1.0f, 0.0f, 0xffffffff, 1, 1 }, { 1.0f, 1.0f, 0.0f,
+ 0xffffffff, 1, 0 } };
+
+ // Create the vertex buffer.
+ if (FAILED(_pd3dDevice->CreateVertexBuffer(sizeof(Vertices), 0,
+ D3DFVF_CUSTOMVERTEX,
+ D3DPOOL_DEFAULT, &_pVB, NULL )))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Failed to create the vertex buffer.");
+ return -1;
+ }
+
+ // Now we fill the vertex buffer.
+ VOID* pVertices;
+ if (FAILED(_pVB->Lock(0, sizeof(Vertices), (void**) &pVertices, 0)))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Failed to lock the vertex buffer.");
+ return -1;
+ }
+ memcpy(pVertices, Vertices, sizeof(Vertices));
+ _pVB->Unlock();
+
+ return 0;
+}
+
+int32_t VideoRenderDirect3D9::Init()
+{
+ WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1,
+ "VideoRenderDirect3D9::Init");
+
+ CriticalSectionScoped cs(&_refD3DCritsect);
+
+ // Start rendering thread...
+ if (!_screenUpdateThread)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Thread not created");
+ return -1;
+ }
+ _screenUpdateThread->Start();
+ _screenUpdateThread->SetPriority(rtc::kRealtimePriority);
+
+ // Start the event triggering the render process
+ unsigned int monitorFreq = 60;
+ DEVMODE dm;
+ // initialize the DEVMODE structure
+ ZeroMemory(&dm, sizeof(dm));
+ dm.dmSize = sizeof(dm);
+ if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
+ {
+ monitorFreq = dm.dmDisplayFrequency;
+ }
+ _screenUpdateEvent->StartTimer(true, 1000 / monitorFreq);
+
+ return InitDevice();
+}
+
+int32_t VideoRenderDirect3D9::ChangeWindow(void* window)
+{
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
+ return -1;
+}
+
+int VideoRenderDirect3D9::UpdateRenderSurface()
+{
+ CriticalSectionScoped cs(&_refD3DCritsect);
+
+ // Check if there are any updated buffers
+ bool updated = false;
+ std::map<int, D3D9Channel*>::iterator it;
+ it = _d3dChannels.begin();
+ while (it != _d3dChannels.end())
+ {
+
+ D3D9Channel* channel = it->second;
+ channel->IsUpdated(updated);
+ if (updated)
+ {
+ break;
+ }
+ it++;
+ }
+ //nothing is updated, continue
+ if (!updated)
+ return -1;
+
+ // Clear the backbuffer to a black color
+ _pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f,
+ 0);
+
+ // Begin the scene
+ if (SUCCEEDED(_pd3dDevice->BeginScene()))
+ {
+ _pd3dDevice->SetStreamSource(0, _pVB, 0, sizeof(CUSTOMVERTEX));
+ _pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
+
+ //draw all the channels
+ //get texture from the channels
+ LPDIRECT3DTEXTURE9 textureFromChannel = NULL;
+ DWORD textureWidth, textureHeight;
+
+ std::multimap<int, unsigned int>::reverse_iterator it;
+ it = _d3dZorder.rbegin();
+ while (it != _d3dZorder.rend())
+ {
+ // loop through all channels and streams in Z order
+ int channel = it->second & 0x0000ffff;
+
+ std::map<int, D3D9Channel*>::iterator ddIt;
+ ddIt = _d3dChannels.find(channel);
+ if (ddIt != _d3dChannels.end())
+ {
+ // found the channel
+ D3D9Channel* channelObj = ddIt->second;
+ if (channelObj)
+ {
+ textureFromChannel = channelObj->GetTexture();
+ textureWidth = channelObj->GetTextureWidth();
+ textureHeight = channelObj->GetTextureHeight();
+
+ uint32_t zOrder;
+ float startWidth, startHeight, stopWidth, stopHeight;
+ channelObj->GetStreamSettings(0, zOrder, startWidth,
+ startHeight, stopWidth,
+ stopHeight);
+
+ //draw the video stream
+ UpdateVerticeBuffer(_pVB, 0, startWidth, startHeight,
+ stopWidth, stopHeight);
+ _pd3dDevice->SetTexture(0, textureFromChannel);
+ _pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+
+ //Notice channel that this frame as been rendered
+ channelObj->RenderOffFrame();
+ }
+ }
+ it++;
+ }
+
+ //draw the logo
+ if (_pTextureLogo)
+ {
+ UpdateVerticeBuffer(_pVB, 0, _logoLeft, _logoTop, _logoRight,
+ _logoBottom);
+ _pd3dDevice->SetTexture(0, _pTextureLogo);
+ _pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+ }
+
+ // End the scene
+ _pd3dDevice->EndScene();
+ }
+
+ // Present the backbuffer contents to the display
+ _pd3dDevice->Present(NULL, NULL, NULL, NULL );
+
+ return 0;
+}
+
+//set the alpha value of the pixal with a particular colorkey as 0
+int VideoRenderDirect3D9::SetTransparentColor(LPDIRECT3DTEXTURE9 pTexture,
+ DDCOLORKEY* transparentColorKey,
+ DWORD width,
+ DWORD height)
+{
+ D3DLOCKED_RECT lr;
+ if (!pTexture)
+ return -1;
+
+ CriticalSectionScoped cs(&_refD3DCritsect);
+ if (SUCCEEDED(pTexture->LockRect(0, &lr, NULL, D3DLOCK_DISCARD)))
+ {
+ for (DWORD y = 0; y < height; y++)
+ {
+ DWORD dwOffset = y * width;
+
+ for (DWORD x = 0; x < width; x)
+ {
+ DWORD temp = ((DWORD*) lr.pBits)[dwOffset + x];
+ if ((temp & 0x00FFFFFF)
+ == transparentColorKey->dwColorSpaceLowValue)
+ {
+ temp &= 0x00FFFFFF;
+ }
+ else
+ {
+ temp |= 0xFF000000;
+ }
+ ((DWORD*) lr.pBits)[dwOffset + x] = temp;
+ x++;
+ }
+ }
+ pTexture->UnlockRect(0);
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ *
+ * Rendering process
+ *
+ */
+bool VideoRenderDirect3D9::ScreenUpdateThreadProc(void* obj)
+{
+ return static_cast<VideoRenderDirect3D9*> (obj)->ScreenUpdateProcess();
+}
+
+bool VideoRenderDirect3D9::ScreenUpdateProcess()
+{
+ _screenUpdateEvent->Wait(100);
+
+ if (!_screenUpdateThread)
+ {
+ //stop the thread
+ return false;
+ }
+ if (!_pd3dDevice)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "d3dDevice not created.");
+ return true;
+ }
+
+ HRESULT hr = _pd3dDevice->TestCooperativeLevel();
+
+ if (SUCCEEDED(hr))
+ {
+ UpdateRenderSurface();
+ }
+
+ if (hr == D3DERR_DEVICELOST)
+ {
+ //Device is lost and cannot be reset yet
+
+ }
+ else if (hr == D3DERR_DEVICENOTRESET)
+ {
+ //Lost but we can reset it now
+ //Note: the standard way is to call Reset, however for some reason doesn't work here.
+ //so we will release the device and create it again.
+ ResetDevice();
+ }
+
+ return true;
+}
+
+int VideoRenderDirect3D9::CloseDevice()
+{
+ CriticalSectionScoped cs(&_refD3DCritsect);
+ WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1,
+ "VideoRenderDirect3D9::CloseDevice");
+
+ if (_pTextureLogo != NULL)
+ {
+ _pTextureLogo->Release();
+ _pTextureLogo = NULL;
+ }
+
+ if (_pVB != NULL)
+ {
+ _pVB->Release();
+ _pVB = NULL;
+ }
+
+ if (_pd3dDevice != NULL)
+ {
+ _pd3dDevice->Release();
+ _pd3dDevice = NULL;
+ }
+
+ if (_pD3D != NULL)
+ {
+ _pD3D->Release();
+ _pD3D = NULL;
+ }
+
+ if (_pd3dSurface != NULL)
+ _pd3dSurface->Release();
+ return 0;
+}
+
+D3D9Channel* VideoRenderDirect3D9::GetD3DChannel(int channel)
+{
+ std::map<int, D3D9Channel*>::iterator ddIt;
+ ddIt = _d3dChannels.find(channel & 0x0000ffff);
+ D3D9Channel* ddobj = NULL;
+ if (ddIt != _d3dChannels.end())
+ {
+ ddobj = ddIt->second;
+ }
+ if (ddobj == NULL)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Direct3D render failed to find channel");
+ return NULL;
+ }
+ return ddobj;
+}
+
+int32_t VideoRenderDirect3D9::DeleteChannel(const uint32_t streamId)
+{
+ CriticalSectionScoped cs(&_refD3DCritsect);
+
+
+ std::multimap<int, unsigned int>::iterator it;
+ it = _d3dZorder.begin();
+ while (it != _d3dZorder.end())
+ {
+ if ((streamId & 0x0000ffff) == (it->second & 0x0000ffff))
+ {
+ it = _d3dZorder.erase(it);
+ break;
+ }
+ it++;
+ }
+
+ std::map<int, D3D9Channel*>::iterator ddIt;
+ ddIt = _d3dChannels.find(streamId & 0x0000ffff);
+ if (ddIt != _d3dChannels.end())
+ {
+ delete ddIt->second;
+ _d3dChannels.erase(ddIt);
+ return 0;
+ }
+ return -1;
+}
+
+VideoRenderCallback* VideoRenderDirect3D9::CreateChannel(const uint32_t channel,
+ const uint32_t zOrder,
+ const float left,
+ const float top,
+ const float right,
+ const float bottom)
+{
+ CriticalSectionScoped cs(&_refD3DCritsect);
+
+ //FIXME this should be done in VideoAPIWindows? stop the frame deliver first
+ //remove the old channel
+ DeleteChannel(channel);
+
+ D3D9Channel* d3dChannel = new D3D9Channel(_pd3dDevice,
+ &_refD3DCritsect, _trace);
+ d3dChannel->SetStreamSettings(0, zOrder, left, top, right, bottom);
+
+ // store channel
+ _d3dChannels[channel & 0x0000ffff] = d3dChannel;
+
+ // store Z order
+ // default streamID is 0
+ _d3dZorder.insert(
+ std::pair<int, unsigned int>(zOrder, channel & 0x0000ffff));
+
+ return d3dChannel;
+}
+
+int32_t VideoRenderDirect3D9::GetStreamSettings(const uint32_t channel,
+ const uint16_t streamId,
+ uint32_t& zOrder,
+ float& left, float& top,
+ float& right, float& bottom)
+{
+ std::map<int, D3D9Channel*>::iterator ddIt;
+ ddIt = _d3dChannels.find(channel & 0x0000ffff);
+ D3D9Channel* ddobj = NULL;
+ if (ddIt != _d3dChannels.end())
+ {
+ ddobj = ddIt->second;
+ }
+ if (ddobj == NULL)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Direct3D render failed to find channel");
+ return -1;
+ }
+ // Only allow one stream per channel, demuxing is
+ return ddobj->GetStreamSettings(0, zOrder, left, top, right, bottom);
+}
+
+int VideoRenderDirect3D9::UpdateVerticeBuffer(LPDIRECT3DVERTEXBUFFER9 pVB,
+ int offset,
+ float startWidth,
+ float startHeight,
+ float stopWidth,
+ float stopHeight)
+{
+ if (pVB == NULL)
+ return -1;
+
+ float left, right, top, bottom;
+
+ //update the vertice buffer
+ //0,1 => -1,1
+ left = startWidth * 2 - 1;
+ right = stopWidth * 2 - 1;
+
+ //0,1 => 1,-1
+ top = 1 - startHeight * 2;
+ bottom = 1 - stopHeight * 2;
+
+ CUSTOMVERTEX newVertices[] = {
+ //logo
+ { left, bottom, 0.0f, 0xffffffff, 0, 1 }, { left, top, 0.0f,
+ 0xffffffff, 0, 0 },
+ { right, bottom, 0.0f, 0xffffffff, 1, 1 }, { right, top, 0.0f,
+ 0xffffffff, 1, 0 }, };
+ // Now we fill the vertex buffer.
+ VOID* pVertices;
+ if (FAILED(pVB->Lock(sizeof(CUSTOMVERTEX) * offset, sizeof(newVertices),
+ (void**) &pVertices, 0)))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Failed to lock the vertex buffer.");
+ return -1;
+ }
+ memcpy(pVertices, newVertices, sizeof(newVertices));
+ pVB->Unlock();
+
+ return 0;
+}
+
+int32_t VideoRenderDirect3D9::StartRender()
+{
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
+ return 0;
+}
+
+int32_t VideoRenderDirect3D9::StopRender()
+{
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
+ return 0;
+}
+
+bool VideoRenderDirect3D9::IsFullScreen()
+{
+ return _fullScreen;
+}
+
+int32_t VideoRenderDirect3D9::SetCropping(const uint32_t channel,
+ const uint16_t streamId,
+ const float left, const float top,
+ const float right, const float bottom)
+{
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
+ return 0;
+}
+
+int32_t VideoRenderDirect3D9::SetTransparentBackground(
+ const bool enable)
+{
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
+ return 0;
+}
+
+int32_t VideoRenderDirect3D9::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)
+{
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1, "Not supported.");
+ return 0;
+}
+
+int32_t VideoRenderDirect3D9::SetBitmap(const void* bitMap,
+ const uint8_t pictureId,
+ const void* colorKey,
+ const float left, const float top,
+ const float right, const float bottom)
+{
+ if (!bitMap)
+ {
+ if (_pTextureLogo != NULL)
+ {
+ _pTextureLogo->Release();
+ _pTextureLogo = NULL;
+ }
+ WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1, "Remove bitmap.");
+ return 0;
+ }
+
+ // sanity
+ if (left > 1.0f || left < 0.0f ||
+ top > 1.0f || top < 0.0f ||
+ right > 1.0f || right < 0.0f ||
+ bottom > 1.0f || bottom < 0.0f)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Direct3D SetBitmap invalid parameter");
+ return -1;
+ }
+
+ if ((bottom <= top) || (right <= left))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Direct3D SetBitmap invalid parameter");
+ return -1;
+ }
+
+ CriticalSectionScoped cs(&_refD3DCritsect);
+
+ unsigned char* srcPtr;
+ HGDIOBJ oldhand;
+ BITMAPINFO pbi;
+ BITMAP bmap;
+ HDC hdcNew;
+ hdcNew = CreateCompatibleDC(0);
+ // Fill out the BITMAP structure.
+ GetObject((HBITMAP)bitMap, sizeof(bmap), &bmap);
+ //Select the bitmap handle into the new device context.
+ oldhand = SelectObject(hdcNew, (HGDIOBJ) bitMap);
+ // we are done with this object
+ DeleteObject(oldhand);
+ pbi.bmiHeader.biSize = 40;
+ pbi.bmiHeader.biWidth = bmap.bmWidth;
+ pbi.bmiHeader.biHeight = bmap.bmHeight;
+ pbi.bmiHeader.biPlanes = 1;
+ pbi.bmiHeader.biBitCount = bmap.bmBitsPixel;
+ pbi.bmiHeader.biCompression = BI_RGB;
+ pbi.bmiHeader.biSizeImage = bmap.bmWidth * bmap.bmHeight * 3;
+ srcPtr = new unsigned char[bmap.bmWidth * bmap.bmHeight * 4];
+ // the original un-stretched image in RGB24
+ int pixelHeight = GetDIBits(hdcNew, (HBITMAP)bitMap, 0, bmap.bmHeight, srcPtr, &pbi,
+ DIB_RGB_COLORS);
+ if (pixelHeight == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Direct3D failed to GetDIBits in SetBitmap");
+ delete[] srcPtr;
+ return -1;
+ }
+ DeleteDC(hdcNew);
+ if (pbi.bmiHeader.biBitCount != 24 && pbi.bmiHeader.biBitCount != 32)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Direct3D failed to SetBitmap invalid bit depth");
+ delete[] srcPtr;
+ return -1;
+ }
+
+ HRESULT ret;
+ //release the previous logo texture
+ if (_pTextureLogo != NULL)
+ {
+ _pTextureLogo->Release();
+ _pTextureLogo = NULL;
+ }
+ ret = _pd3dDevice->CreateTexture(bmap.bmWidth, bmap.bmHeight, 1, 0,
+ D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
+ &_pTextureLogo, NULL);
+ if (FAILED(ret))
+ {
+ _pTextureLogo = NULL;
+ delete[] srcPtr;
+ return -1;
+ }
+ if (!_pTextureLogo)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Texture for rendering not initialized.");
+ delete[] srcPtr;
+ return -1;
+ }
+
+ D3DLOCKED_RECT lr;
+ if (FAILED(_pTextureLogo->LockRect(0, &lr, NULL, 0)))
+ {
+ delete[] srcPtr;
+ return -1;
+ }
+ unsigned char* dstPtr = (UCHAR*) lr.pBits;
+ int pitch = bmap.bmWidth * 4;
+
+ if (pbi.bmiHeader.biBitCount == 24)
+ {
+ ConvertRGB24ToARGB(srcPtr, dstPtr, bmap.bmWidth, bmap.bmHeight, 0);
+ }
+ else
+ {
+ unsigned char* srcTmp = srcPtr + (bmap.bmWidth * 4) * (bmap.bmHeight - 1);
+ for (int i = 0; i < bmap.bmHeight; ++i)
+ {
+ memcpy(dstPtr, srcTmp, bmap.bmWidth * 4);
+ srcTmp -= bmap.bmWidth * 4;
+ dstPtr += pitch;
+ }
+ }
+
+ delete[] srcPtr;
+ if (FAILED(_pTextureLogo->UnlockRect(0)))
+ {
+ return -1;
+ }
+
+ if (colorKey)
+ {
+ DDCOLORKEY* ddColorKey =
+ static_cast<DDCOLORKEY*> (const_cast<void*> (colorKey));
+ SetTransparentColor(_pTextureLogo, ddColorKey, bmap.bmWidth,
+ bmap.bmHeight);
+ }
+
+ //update the vertice buffer
+ //0,1 => -1,1
+ _logoLeft = left;
+ _logoRight = right;
+
+ //0,1 => 1,-1
+ _logoTop = top;
+ _logoBottom = bottom;
+
+ return 0;
+
+}
+
+int32_t VideoRenderDirect3D9::GetGraphicsMemory(uint64_t& totalMemory,
+ uint64_t& availableMemory)
+{
+ totalMemory = _totalMemory;
+ availableMemory = _availableMemory;
+ return 0;
+}
+
+int32_t VideoRenderDirect3D9::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)
+{
+ std::map<int, D3D9Channel*>::iterator ddIt;
+ ddIt = _d3dChannels.find(channel & 0x0000ffff);
+ D3D9Channel* ddobj = NULL;
+ if (ddIt != _d3dChannels.end())
+ {
+ ddobj = ddIt->second;
+ }
+ if (ddobj == NULL)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
+ "Direct3D render failed to find channel");
+ return -1;
+ }
+ // Only allow one stream per channel, demuxing is
+ ddobj->SetStreamSettings(0, zOrder, left, top, right, bottom);
+
+ return 0;
+}
+
+} // namespace webrtc

Powered by Google App Engine
This is Rietveld 408576698