343 lines
8.2 KiB
C++
343 lines
8.2 KiB
C++
/* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
|
|
*
|
|
* This file is part of Open Source Doubango Framework.
|
|
*
|
|
* DOUBANGO is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* DOUBANGO is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with DOUBANGO.
|
|
*/
|
|
#include "internals/DSUtils.h"
|
|
|
|
#include <atlbase.h>
|
|
#include <atlstr.h>
|
|
#include <d3d9.h>
|
|
|
|
#include "tsk_debug.h"
|
|
|
|
HWND GetMainWindow()
|
|
{
|
|
HWND hWnd;
|
|
if(!(hWnd = GetActiveWindow())){
|
|
if(!(hWnd = GetForegroundWindow())){
|
|
if(!(hWnd = GetConsoleWindow())){
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return hWnd;
|
|
}
|
|
|
|
bool IsMainThread()
|
|
{
|
|
HWND hWnd = GetMainWindow();
|
|
if(hWnd){
|
|
DWORD mainTid = GetWindowThreadProcessId(hWnd, NULL);
|
|
DWORD currentTid = GetCurrentThreadId();
|
|
return (mainTid == currentTid);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsD3D9Supported()
|
|
{
|
|
static bool g_bChecked = false;
|
|
static bool g_bSupported = false;
|
|
|
|
if (g_bChecked) {
|
|
return g_bSupported;
|
|
}
|
|
g_bChecked = true;
|
|
HRESULT hr = S_OK;
|
|
IDirect3D9* pD3D = NULL;
|
|
D3DDISPLAYMODE mode = { 0 };
|
|
D3DPRESENT_PARAMETERS pp = {0};
|
|
IDirect3DDevice9* pDevice = NULL;
|
|
|
|
if (!(pD3D = Direct3DCreate9(D3D_SDK_VERSION))) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto bail;
|
|
}
|
|
|
|
hr = pD3D->GetAdapterDisplayMode(
|
|
D3DADAPTER_DEFAULT,
|
|
&mode
|
|
);
|
|
if (FAILED(hr)) {
|
|
goto bail;
|
|
}
|
|
|
|
hr = pD3D->CheckDeviceType(
|
|
D3DADAPTER_DEFAULT,
|
|
D3DDEVTYPE_HAL,
|
|
mode.Format,
|
|
D3DFMT_X8R8G8B8,
|
|
TRUE // windowed
|
|
);
|
|
if (FAILED(hr)) {
|
|
goto bail;
|
|
}
|
|
pp.BackBufferFormat = D3DFMT_X8R8G8B8;
|
|
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
pp.Windowed = TRUE;
|
|
pp.hDeviceWindow = GetDesktopWindow();
|
|
hr = pD3D->CreateDevice(
|
|
D3DADAPTER_DEFAULT,
|
|
D3DDEVTYPE_HAL,
|
|
pp.hDeviceWindow,
|
|
D3DCREATE_HARDWARE_VERTEXPROCESSING,
|
|
&pp,
|
|
&pDevice
|
|
);
|
|
if (FAILED(hr)) {
|
|
goto bail;
|
|
}
|
|
|
|
// Everythings is OK
|
|
g_bSupported = TRUE;
|
|
TSK_DEBUG_INFO("D3D9 supported");
|
|
|
|
bail:
|
|
if (!g_bSupported) {
|
|
TSK_DEBUG_WARN("D3D9 not supported");
|
|
}
|
|
SAFE_RELEASE(pDevice);
|
|
SAFE_RELEASE(pD3D);
|
|
return g_bSupported;
|
|
}
|
|
|
|
IPin *GetPin(IBaseFilter *filter, PIN_DIRECTION direction)
|
|
{
|
|
IEnumPins *enumPins = NULL;
|
|
IPin *pin = NULL;
|
|
|
|
HRESULT hr = filter->EnumPins(&enumPins);
|
|
if(!enumPins){
|
|
return NULL;
|
|
}
|
|
|
|
for(;;){
|
|
ULONG fetched = 0;
|
|
PIN_DIRECTION pinDir = PIN_DIRECTION(-1);
|
|
pin = NULL;
|
|
|
|
if (FAILED(enumPins->Next(1, &pin, &fetched))){
|
|
enumPins->Release();
|
|
return NULL;
|
|
}
|
|
|
|
if (fetched == 1 && pin){
|
|
pin->QueryDirection(&pinDir);
|
|
if(pinDir == direction){
|
|
break;
|
|
}
|
|
pin->Release();
|
|
}
|
|
}
|
|
|
|
enumPins->Release();
|
|
return pin;
|
|
}
|
|
|
|
HRESULT ConnectFilters(IGraphBuilder *graphBuilder, IBaseFilter *source, IBaseFilter *destination, AM_MEDIA_TYPE *mediaType)
|
|
{
|
|
HRESULT hr;
|
|
|
|
IPin *outPin = GetPin(source, PINDIR_OUTPUT);
|
|
IPin *inPin = GetPin(destination, PINDIR_INPUT);
|
|
|
|
if (mediaType != NULL){
|
|
hr = graphBuilder->ConnectDirect(outPin, inPin, mediaType);
|
|
}
|
|
else{
|
|
hr = graphBuilder->Connect(outPin, inPin);
|
|
}
|
|
|
|
SAFE_RELEASE(outPin);
|
|
SAFE_RELEASE(inPin);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DisconnectFilters(IGraphBuilder *graphBuilder, IBaseFilter *source, IBaseFilter *destination)
|
|
{
|
|
HRESULT hr;
|
|
|
|
IPin *outPin = GetPin(source, PINDIR_OUTPUT);
|
|
IPin *inPin = GetPin(destination, PINDIR_INPUT);
|
|
|
|
if (inPin){
|
|
hr = graphBuilder->Disconnect(inPin);
|
|
}
|
|
|
|
if (outPin){
|
|
hr = graphBuilder->Disconnect(outPin);
|
|
}
|
|
|
|
SAFE_RELEASE(outPin);
|
|
SAFE_RELEASE(inPin);
|
|
|
|
return hr;
|
|
}
|
|
|
|
bool DisconnectAllFilters(IGraphBuilder *graphBuilder)
|
|
{
|
|
CComPtr<IEnumFilters> filterEnum = NULL;
|
|
CComPtr<IBaseFilter> currentFilter = NULL;
|
|
ULONG fetched;
|
|
HRESULT hr;
|
|
|
|
hr = graphBuilder->EnumFilters(&filterEnum);
|
|
if (FAILED(hr)) return false;
|
|
|
|
while(filterEnum->Next(1, ¤tFilter, &fetched) == S_OK){
|
|
hr = DisconnectFilters(graphBuilder, currentFilter, currentFilter);
|
|
}
|
|
|
|
filterEnum.Release();
|
|
return true;
|
|
}
|
|
|
|
bool RemoveAllFilters(IGraphBuilder *graphBuilder)
|
|
{
|
|
CComPtr<IEnumFilters> filterEnum = NULL;
|
|
CComPtr<IBaseFilter> currentFilter = NULL;
|
|
ULONG fetched;
|
|
HRESULT hr;
|
|
|
|
hr = graphBuilder->EnumFilters(&filterEnum);
|
|
if (FAILED(hr)) return false;
|
|
|
|
while(filterEnum->Next(1, ¤tFilter, &fetched) == S_OK){
|
|
hr = graphBuilder->RemoveFilter(currentFilter);
|
|
if (FAILED(hr)){
|
|
filterEnum.Release();
|
|
return false;
|
|
}
|
|
currentFilter.Release();
|
|
filterEnum->Reset();
|
|
}
|
|
|
|
filterEnum.Release();
|
|
return true;
|
|
}
|
|
|
|
|
|
#include "internals/DSDisplay.h"
|
|
#include "internals/DSGrabber.h"
|
|
|
|
#define WM_CREATE_DISPLAY_ON_UI_THREAD (WM_USER + 101)
|
|
#define WM_CREATE_GRABBER_ON_UI_THREAD (WM_CREATE_DISPLAY_ON_UI_THREAD + 1)
|
|
#define WM_CREATE_ON_UI_THREAD_TIMEOUT 1000
|
|
|
|
// C Callback that dispatch event to create display on UI thread
|
|
static LRESULT CALLBACK __create__WndProcWindow(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HANDLE* event = reinterpret_cast<HANDLE*>(wParam);
|
|
BOOL* isScreenCast = reinterpret_cast<BOOL*>(GetPropA(hWnd, "screnCast"));
|
|
|
|
if(event && lParam){
|
|
switch(uMsg){
|
|
case WM_CREATE_DISPLAY_ON_UI_THREAD:
|
|
{
|
|
HRESULT hr;
|
|
DSDisplay** ppDisplay = reinterpret_cast<DSDisplay**>(lParam);
|
|
*ppDisplay = new DSDisplay(&hr);
|
|
SetEvent(event);
|
|
break;
|
|
}
|
|
case WM_CREATE_GRABBER_ON_UI_THREAD:
|
|
{
|
|
HRESULT hr;
|
|
DSGrabber** ppGrabber = reinterpret_cast<DSGrabber**>(lParam);
|
|
*ppGrabber = new DSGrabber(&hr, *isScreenCast);
|
|
SetEvent(event);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
int createOnCurrentThead(HWND hWnd, void** ppRet, BOOL display, BOOL screnCast)
|
|
{
|
|
HRESULT hr;
|
|
if(display) *ppRet = new DSDisplay(&hr);
|
|
else *ppRet = new DSGrabber(&hr, screnCast);
|
|
if(FAILED(hr)){
|
|
TSK_DEBUG_ERROR("Failed to created DirectShow %s", display ? "Display" : "Grabber");
|
|
SAFE_DELETE_PTR(*ppRet);
|
|
return -2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int createOnUIThead(HWND hWnd, void** ppRet, BOOL display, BOOL screnCast)
|
|
{
|
|
static BOOL __isScreenCastFalse = FALSE;
|
|
static BOOL __isScreenCastTrue = TRUE;
|
|
if(!ppRet){
|
|
TSK_DEBUG_ERROR("Invalid parameter");
|
|
return -1;
|
|
}
|
|
|
|
if (IsMainThread()) {
|
|
return createOnCurrentThead(hWnd, ppRet, display, screnCast);
|
|
}
|
|
else{
|
|
TSK_DEBUG_INFO("Create DirectShow element on worker thread");
|
|
HANDLE event = NULL;
|
|
int ret = 0;
|
|
DWORD retWait, retryCount = 3;
|
|
|
|
if(!hWnd){
|
|
if(!(hWnd = FindWindowA(NULL, "Boghe - IMS/RCS Client"))){
|
|
if(!(hWnd = GetMainWindow())){
|
|
TSK_DEBUG_ERROR("No Window handle could be used");
|
|
return -2;
|
|
}
|
|
}
|
|
}
|
|
|
|
WNDPROC wndProc = (WNDPROC) SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG) __create__WndProcWindow);
|
|
if (!wndProc) {
|
|
TSK_DEBUG_ERROR("SetWindowLongPtr() failed with errcode=%d", GetLastError());
|
|
return createOnCurrentThead(hWnd, ppRet, display, screnCast);
|
|
}
|
|
|
|
if (!(event = CreateEvent(NULL, TRUE, FALSE, NULL))) {
|
|
TSK_DEBUG_ERROR("Failed to create new event");
|
|
ret = -4; goto bail;
|
|
}
|
|
SetPropA(hWnd, "screnCast", screnCast ? &__isScreenCastTrue : &__isScreenCastFalse);
|
|
if (!PostMessageA(hWnd, display ? WM_CREATE_DISPLAY_ON_UI_THREAD : WM_CREATE_GRABBER_ON_UI_THREAD, reinterpret_cast<WPARAM>(event), reinterpret_cast<LPARAM>(ppRet))) {
|
|
TSK_DEBUG_ERROR("PostMessageA() failed");
|
|
ret = -5; goto bail;
|
|
}
|
|
|
|
do {
|
|
retWait = WaitForSingleObject(event, WM_CREATE_ON_UI_THREAD_TIMEOUT);
|
|
}
|
|
while (retryCount-- > 0 && (retWait == WAIT_TIMEOUT));
|
|
|
|
bail:
|
|
// restore
|
|
if (hWnd && wndProc) {
|
|
SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG)wndProc);
|
|
}
|
|
if (event) {
|
|
CloseHandle(event);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
} |