obs/DShowPlugin/DShowPlugin.cpp
paibox d7645a016f Add option to preserve DirectShow source size
For when you want to make sure that your DirectShow capture source stays
in place and the same size even if you change the input resolution.
2013-11-26 23:27:50 +01:00

2211 lines
93 KiB
C++

/********************************************************************************
Copyright (C) 2012 Hugh Bailey <obs.jim@gmail.com>
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************/
#include "DShowPlugin.h"
//todo: super long file. this is another one of those abominations.
//fix it jim
extern "C" __declspec(dllexport) bool LoadPlugin();
extern "C" __declspec(dllexport) void UnloadPlugin();
extern "C" __declspec(dllexport) CTSTR GetPluginName();
extern "C" __declspec(dllexport) CTSTR GetPluginDescription();
LocaleStringLookup *pluginLocale = NULL;
HINSTANCE hinstMain = NULL;
extern DeinterlacerConfig deinterlacerConfigs[DEINTERLACING_TYPE_LAST];
CTSTR deinterlacerLocalizations[DEINTERLACING_TYPE_LAST] = {
TEXT("DeinterlacingType.None"),
TEXT("DeinterlacingType.Discard"),
TEXT("DeinterlacingType.Retro"),
TEXT("DeinterlacingType.Blend"),
TEXT("DeinterlacingType.Blend2x"),
TEXT("DeinterlacingType.Linear"),
TEXT("DeinterlacingType.Linear2x"),
TEXT("DeinterlacingType.Yadif"),
TEXT("DeinterlacingType.Yadif2x"),
TEXT("DeinterlacingType.Debug")
};
#define DSHOW_CLASSNAME TEXT("DeviceCapture")
//CTSTR lpRoxioVideoCaptureGUID = TEXT("{6994AD05-93EF-11D0-A3-CC-00-A0-C9-22-31-96}");
const GUID PIN_CATEGORY_ROXIOCAPTURE = {0x6994AD05, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
bool SourceListHasDevice(CTSTR lpDevice, XElement *sourceList)
{
UINT numSources = sourceList->NumElements();
for(UINT i=0; i<numSources; i++)
{
XElement *sourceElement = sourceList->GetElementByID(i);
if(scmpi(sourceElement->GetString(TEXT("class")), DSHOW_CLASSNAME) == 0)
{
XElement *data = sourceElement->GetElement(TEXT("data"));
if(scmpi(data->GetString(TEXT("device")), lpDevice) == 0)
return true;
if(scmpi(data->GetString(TEXT("audioDevice")), lpDevice) == 0)
return true;
}
}
return false;
}
bool CurrentDeviceExists(CTSTR lpDevice, bool bGlobal, bool &isGlobal)
{
isGlobal = false;
XElement *globalSources = API->GetGlobalSourceListElement();
if(globalSources)
{
if(SourceListHasDevice(lpDevice, globalSources))
{
isGlobal = true;
return true;
}
}
if(bGlobal)
{
XElement *sceneListElement = API->GetSceneListElement();
if(sceneListElement)
{
UINT numScenes = sceneListElement->NumElements();
for(UINT i=0; i<numScenes; i++)
{
XElement *sceneElement = sceneListElement->GetElementByID(i);
if(sceneElement)
{
XElement *sourceListElement = sceneElement->GetElement(TEXT("sources"));
if(sourceListElement)
{
if(SourceListHasDevice(lpDevice, sourceListElement))
return true;
}
}
}
}
}
else
{
XElement *sceneElement = API->GetSceneElement();
if(sceneElement)
{
XElement *sourceListElement = sceneElement->GetElement(TEXT("sources"));
if(sourceListElement)
{
if(SourceListHasDevice(lpDevice, sourceListElement))
return true;
}
}
}
return false;
}
bool GetGUIDFromString(CTSTR lpGUID, GUID &targetGUID)
{
String strGUID = lpGUID;
if(strGUID.Length() != 38)
return false;
strGUID = strGUID.Mid(1, strGUID.Length()-1);
StringList GUIDData;
strGUID.GetTokenList(GUIDData, '-', FALSE);
if (GUIDData.Num() != 5)
return false;
if (GUIDData[0].Length() != 8 ||
GUIDData[1].Length() != 4 ||
GUIDData[2].Length() != 4 ||
GUIDData[3].Length() != 4 ||
GUIDData[4].Length() != 12 )
{
return false;
}
targetGUID.Data1 = (UINT)tstring_base_to_uint(GUIDData[0], NULL, 16);
targetGUID.Data2 = (WORD)tstring_base_to_uint(GUIDData[1], NULL, 16);
targetGUID.Data3 = (WORD)tstring_base_to_uint(GUIDData[2], NULL, 16);
targetGUID.Data4[0] = (BYTE)tstring_base_to_uint(GUIDData[3].Left(2), NULL, 16);
targetGUID.Data4[1] = (BYTE)tstring_base_to_uint(GUIDData[3].Right(2), NULL, 16);
targetGUID.Data4[2] = (BYTE)tstring_base_to_uint(GUIDData[4].Left(2), NULL, 16);
targetGUID.Data4[3] = (BYTE)tstring_base_to_uint(GUIDData[4].Mid(2, 4), NULL, 16);
targetGUID.Data4[4] = (BYTE)tstring_base_to_uint(GUIDData[4].Mid(4, 6), NULL, 16);
targetGUID.Data4[5] = (BYTE)tstring_base_to_uint(GUIDData[4].Mid(6, 8), NULL, 16);
targetGUID.Data4[6] = (BYTE)tstring_base_to_uint(GUIDData[4].Mid(8, 10), NULL, 16);
targetGUID.Data4[7] = (BYTE)tstring_base_to_uint(GUIDData[4].Right(2), NULL, 16);
return true;
}
IBaseFilter* GetExceptionDevice(CTSTR lpGUID)
{
GUID targetGUID;
if (!GetGUIDFromString(lpGUID, targetGUID))
return NULL;
IBaseFilter *filter;
if(SUCCEEDED(CoCreateInstance(targetGUID, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&filter)))
return filter;
return NULL;
}
IBaseFilter* GetDeviceByValue(const IID &enumType, WSTR lpType, CTSTR lpName, WSTR lpType2, CTSTR lpName2)
{
//---------------------------------
// exception devices
if(scmpi(lpType2, L"DevicePath") == 0 && lpName2 && *lpName2 == '{')
return GetExceptionDevice(lpName2);
//---------------------------------
ICreateDevEnum *deviceEnum;
IEnumMoniker *videoDeviceEnum;
HRESULT err;
err = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&deviceEnum);
if(FAILED(err))
{
AppWarning(TEXT("GetDeviceByValue: CoCreateInstance for the device enum failed, result = %08lX"), err);
return NULL;
}
err = deviceEnum->CreateClassEnumerator(enumType, &videoDeviceEnum, 0);
if(FAILED(err))
{
AppWarning(TEXT("GetDeviceByValue: deviceEnum->CreateClassEnumerator failed, result = %08lX"), err);
deviceEnum->Release();
return NULL;
}
SafeRelease(deviceEnum);
if(err == S_FALSE) //no devices, so NO ENUM FO U
return NULL;
//---------------------------------
IBaseFilter *bestFilter = NULL;
IMoniker *deviceInfo;
DWORD count;
while(videoDeviceEnum->Next(1, &deviceInfo, &count) == S_OK)
{
IPropertyBag *propertyData;
err = deviceInfo->BindToStorage(0, 0, IID_IPropertyBag, (void**)&propertyData);
if(SUCCEEDED(err))
{
VARIANT valueThingy;
VARIANT valueThingy2;
VariantInit(&valueThingy);
VariantInit(&valueThingy2);
/*valueThingy.vt = VT_BSTR;
valueThingy.pbstrVal = NULL;
valueThingy2.vt = VT_BSTR;
valueThingy2.bstrVal = NULL;*/
if(SUCCEEDED(propertyData->Read(lpType, &valueThingy, NULL)))
{
if(lpType2 && lpName2)
{
if(FAILED(propertyData->Read(lpType2, &valueThingy2, NULL)))
nop();
}
SafeRelease(propertyData);
String strVal1 = (CWSTR)valueThingy.bstrVal;
if(strVal1 == lpName)
{
IBaseFilter *filter;
err = deviceInfo->BindToObject(NULL, 0, IID_IBaseFilter, (void**)&filter);
if(FAILED(err))
{
AppWarning(TEXT("GetDeviceByValue: deviceInfo->BindToObject failed, result = %08lX"), err);
continue;
}
if(!bestFilter)
{
bestFilter = filter;
if(!lpType2 || !lpName2)
{
SafeRelease(deviceInfo);
SafeRelease(videoDeviceEnum);
return bestFilter;
}
}
else if(lpType2 && lpName2)
{
String strVal2 = (CWSTR)valueThingy2.bstrVal;
if(strVal2 == lpName2)
{
bestFilter->Release();
bestFilter = filter;
SafeRelease(deviceInfo);
SafeRelease(videoDeviceEnum);
return bestFilter;
}
}
else
filter->Release();
}
}
}
SafeRelease(deviceInfo);
}
SafeRelease(videoDeviceEnum);
return bestFilter;
}
IPin* GetOutputPin(IBaseFilter *filter, const GUID *majorType)
{
IPin *foundPin = NULL;
IEnumPins *pins;
if(!filter) return NULL;
if(FAILED(filter->EnumPins(&pins))) return NULL;
IPin *curPin;
ULONG num;
while(pins->Next(1, &curPin, &num) == S_OK)
{
if(majorType)
{
AM_MEDIA_TYPE *pinMediaType;
IEnumMediaTypes *mediaTypesEnum;
if(FAILED(curPin->EnumMediaTypes(&mediaTypesEnum)))
{
SafeRelease(curPin);
continue;
}
ULONG curVal = 0;
HRESULT hRes = mediaTypesEnum->Next(1, &pinMediaType, &curVal);
mediaTypesEnum->Release();
if(hRes != S_OK)
{
SafeRelease(curPin);
continue;
}
BOOL bDesiredMediaType = (pinMediaType->majortype == *majorType);
DeleteMediaType(pinMediaType);
if(!bDesiredMediaType)
{
SafeRelease(curPin);
continue;
}
}
//------------------------------
PIN_DIRECTION pinDir;
if(SUCCEEDED(curPin->QueryDirection(&pinDir)))
{
if(pinDir == PINDIR_OUTPUT)
{
IKsPropertySet *propertySet;
if(SUCCEEDED(curPin->QueryInterface(IID_IKsPropertySet, (void**)&propertySet)))
{
GUID pinCategory;
DWORD retSize;
PIN_INFO chi;
curPin->QueryPinInfo(&chi);
if(chi.pFilter)
chi.pFilter->Release();
if(SUCCEEDED(propertySet->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, &pinCategory, sizeof(GUID), &retSize)))
{
if(pinCategory == PIN_CATEGORY_CAPTURE || pinCategory == PIN_CATEGORY_ROXIOCAPTURE)
{
SafeRelease(propertySet);
SafeRelease(pins);
return curPin;
}
}
SafeRelease(propertySet);
}
}
}
SafeRelease(curPin);
}
SafeRelease(pins);
return foundPin;
}
void AddOutput(AM_MEDIA_TYPE *pMT, BYTE *capsData, bool bAllowV2, List<MediaOutputInfo> &outputInfoList)
{
VideoOutputType type = GetVideoOutputType(*pMT);
if(pMT->formattype == FORMAT_VideoInfo || (bAllowV2 && pMT->formattype == FORMAT_VideoInfo2))
{
VIDEO_STREAM_CONFIG_CAPS *pVSCC = reinterpret_cast<VIDEO_STREAM_CONFIG_CAPS*>(capsData);
VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER*>(pMT->pbFormat);
BITMAPINFOHEADER *bmiHeader = GetVideoBMIHeader(pMT);
bool bUsingFourCC = false;
if(type == VideoOutputType_None)
{
type = GetVideoOutputTypeFromFourCC(bmiHeader->biCompression);
bUsingFourCC = true;
}
if(type != VideoOutputType_None)
{
MediaOutputInfo *outputInfo = outputInfoList.CreateNew();
if(pVSCC)
{
outputInfo->minFrameInterval = pVSCC->MinFrameInterval;
outputInfo->maxFrameInterval = pVSCC->MaxFrameInterval;
outputInfo->minCX = pVSCC->MinOutputSize.cx;
outputInfo->maxCX = pVSCC->MaxOutputSize.cx;
outputInfo->minCY = pVSCC->MinOutputSize.cy;
outputInfo->maxCY = pVSCC->MaxOutputSize.cy;
if (!outputInfo->minCX || !outputInfo->minCY || !outputInfo->maxCX || !outputInfo->maxCY) {
outputInfo->minCX = outputInfo->maxCX = bmiHeader->biWidth;
outputInfo->minCY = outputInfo->maxCY = bmiHeader->biHeight;
}
//actually due to the other code in GetResolutionFPSInfo, we can have this granularity
// back to the way it was. now, even if it's corrupted, it will always work
outputInfo->xGranularity = max(pVSCC->OutputGranularityX, 1);
outputInfo->yGranularity = max(pVSCC->OutputGranularityY, 1);
}
else
{
outputInfo->minCX = outputInfo->maxCX = bmiHeader->biWidth;
outputInfo->minCY = outputInfo->maxCY = bmiHeader->biHeight;
if(pVih->AvgTimePerFrame != 0)
outputInfo->minFrameInterval = outputInfo->maxFrameInterval = pVih->AvgTimePerFrame;
else
outputInfo->minFrameInterval = outputInfo->maxFrameInterval = 10000000/30; //elgato hack
outputInfo->xGranularity = outputInfo->yGranularity = 1;
}
outputInfo->mediaType = pMT;
outputInfo->videoType = type;
outputInfo->bUsingFourCC = bUsingFourCC;
return;
}
}
DeleteMediaType(pMT);
}
void GetOutputList(IPin *curPin, List<MediaOutputInfo> &outputInfoList)
{
HRESULT hRes;
IAMStreamConfig *config;
if(SUCCEEDED(curPin->QueryInterface(IID_IAMStreamConfig, (void**)&config)))
{
int count, size;
if(SUCCEEDED(hRes = config->GetNumberOfCapabilities(&count, &size)))
{
BYTE *capsData = (BYTE*)Allocate(size);
int priority = -1;
for(int i=0; i<count; i++)
{
AM_MEDIA_TYPE *pMT;
if(SUCCEEDED(config->GetStreamCaps(i, &pMT, capsData)))
AddOutput(pMT, capsData, false, outputInfoList);
}
Free(capsData);
}
else if(hRes == E_NOTIMPL) //...usually elgato.
{
IEnumMediaTypes *mediaTypes;
if(SUCCEEDED(curPin->EnumMediaTypes(&mediaTypes)))
{
ULONG i;
AM_MEDIA_TYPE *pMT;
if(mediaTypes->Next(1, &pMT, &i) == S_OK)
AddOutput(pMT, NULL, true, outputInfoList);
mediaTypes->Release();
}
}
SafeRelease(config);
}
}
inline bool ResolutionListHasValue(const List<SIZE> &resolutions, SIZE &size)
{
bool bHasResolution = false;
for(UINT i=0; i<resolutions.Num(); i++)
{
SIZE &testSize = resolutions[i];
if(size.cx == testSize.cx && size.cy == testSize.cy)
{
bHasResolution = true;
break;
}
}
return bHasResolution;
}
struct FPSInterval
{
inline FPSInterval(UINT64 minVal, UINT64 maxVal) : minFrameInterval(minVal), maxFrameInterval(maxVal) {}
UINT64 minFrameInterval, maxFrameInterval;
};
struct FPSInfo
{
List<FPSInterval> supportedIntervals;
};
static inline UINT64 GetFrameIntervalDist(UINT64 minInterval, UINT64 maxInterval, UINT64 desiredInterval)
{
INT64 minDist = INT64(minInterval)-INT64(desiredInterval);
INT64 maxDist = INT64(desiredInterval)-INT64(maxInterval);
if (minDist < 0) minDist = 0;
if (maxDist < 0) maxDist = 0;
return UINT64(MAX(minDist, maxDist));
}
bool GetClosestResolutionFPS(List<MediaOutputInfo> &outputList, SIZE &resolution, UINT64 &frameInterval, bool bPrioritizeFPS)
{
LONG width, height;
UINT64 internalFrameInterval = 10000000/UINT64(API->GetMaxFPS());
API->GetBaseSize((UINT&)width, (UINT&)height);
LONG bestDistance = 0x7FFFFFFF;
SIZE bestSize;
UINT64 maxFrameInterval = 0;
UINT64 minFrameInterval = 0;
UINT64 bestFrameIntervalDist = 0xFFFFFFFFFFFFFFFFLL;
for(UINT i=0; i<outputList.Num(); i++)
{
MediaOutputInfo &outputInfo = outputList[i];
LONG outputWidth = outputInfo.minCX;
do
{
LONG distWidth = width-outputWidth;
if(distWidth < 0)
break;
if(distWidth > bestDistance)
{
outputWidth += outputInfo.xGranularity;
continue;
}
LONG outputHeight = outputInfo.minCY;
do
{
LONG distHeight = height-outputHeight;
if(distHeight < 0)
break;
LONG totalDist = distHeight+distWidth;
UINT64 frameIntervalDist = GetFrameIntervalDist(outputInfo.minFrameInterval,
outputInfo.maxFrameInterval, internalFrameInterval);
bool bBetter;
if (bPrioritizeFPS)
bBetter = (frameIntervalDist != bestFrameIntervalDist) ?
(frameIntervalDist < bestFrameIntervalDist) :
(totalDist < bestDistance);
else
bBetter = (totalDist != bestDistance) ?
(totalDist < bestDistance) :
(frameIntervalDist < bestFrameIntervalDist);
if (bBetter) {
bestDistance = totalDist;
bestSize.cx = outputWidth;
bestSize.cy = outputHeight;
maxFrameInterval = outputInfo.maxFrameInterval;
minFrameInterval = outputInfo.minFrameInterval;
bestFrameIntervalDist = frameIntervalDist;
}
outputHeight += outputInfo.yGranularity;
}while((UINT)outputHeight <= outputInfo.maxCY);
outputWidth += outputInfo.xGranularity;
}while((UINT)outputWidth <= outputInfo.maxCX);
}
if(bestDistance != 0x7FFFFFFF)
{
resolution.cx = bestSize.cx;
resolution.cy = bestSize.cy;
if(internalFrameInterval > maxFrameInterval)
frameInterval = maxFrameInterval;
else if(internalFrameInterval < minFrameInterval)
frameInterval = minFrameInterval;
else
frameInterval = internalFrameInterval;
return true;
}
return false;
}
struct ConfigDialogData
{
CTSTR lpName;
XElement *data;
List<MediaOutputInfo> outputList;
List<SIZE> resolutions;
StringList deviceNameList;
StringList deviceIDList;
StringList audioNameList;
StringList audioIDList;
bool bGlobalSource;
bool bCreating;
bool bDeviceHasAudio;
~ConfigDialogData()
{
ClearOutputList();
}
void ClearOutputList()
{
for(UINT i=0; i<outputList.Num(); i++)
outputList[i].FreeData();
outputList.Clear();
}
void GetResolutions(List<SIZE> &resolutions)
{
resolutions.Clear();
for(UINT i=0; i<outputList.Num(); i++)
{
MediaOutputInfo &outputInfo = outputList[i];
SIZE size;
size.cx = outputInfo.minCX;
size.cy = outputInfo.minCY;
if(!ResolutionListHasValue(resolutions, size))
resolutions << size;
size.cx = outputInfo.maxCX;
size.cy = outputInfo.maxCY;
if(!ResolutionListHasValue(resolutions, size))
resolutions << size;
}
//sort
for(UINT i=0; i<resolutions.Num(); i++)
{
SIZE &rez = resolutions[i];
for(UINT j=i+1; j<resolutions.Num(); j++)
{
SIZE &testRez = resolutions[j];
if(testRez.cy < rez.cy)
{
resolutions.SwapValues(i, j);
j = i;
}
}
}
}
bool GetResolutionFPSInfo(SIZE &resolution, FPSInfo &fpsInfo)
{
fpsInfo.supportedIntervals.Clear();
for(UINT i=0; i<outputList.Num(); i++)
{
MediaOutputInfo &outputInfo = outputList[i];
if( UINT(resolution.cx) >= outputInfo.minCX && UINT(resolution.cx) <= outputInfo.maxCX &&
UINT(resolution.cy) >= outputInfo.minCY && UINT(resolution.cy) <= outputInfo.maxCY )
{
if((resolution.cx-outputInfo.minCX) % outputInfo.xGranularity || (resolution.cy-outputInfo.minCY) % outputInfo.yGranularity)
return false;
fpsInfo.supportedIntervals << FPSInterval(outputInfo.minFrameInterval, outputInfo.maxFrameInterval);
}
}
return fpsInfo.supportedIntervals.Num() != 0;
}
};
#define DEV_EXCEPTION_COUNT 1
CTSTR lpExceptionNames[DEV_EXCEPTION_COUNT] = {TEXT("Elgato Game Capture HD")};
CTSTR lpExceptionGUIDs[DEV_EXCEPTION_COUNT] = {TEXT("{39F50F4C-99E1-464a-B6F9-D605B4FB5918}")};
bool FillOutListOfDevices(HWND hwndCombo, GUID matchGUID, StringList *deviceList, StringList *deviceIDList)
{
deviceIDList->Clear();
deviceList->Clear();
if(hwndCombo != NULL) SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
//------------------------------------------
for(int i=0; i<DEV_EXCEPTION_COUNT; i++)
{
IBaseFilter *exceptionFilter = GetExceptionDevice(lpExceptionGUIDs[i]);
if(exceptionFilter)
{
deviceList->Add(lpExceptionNames[i]);
deviceIDList->Add(lpExceptionGUIDs[i]);
if(hwndCombo != NULL) SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)lpExceptionNames[i]);
exceptionFilter->Release();
}
}
//------------------------------------------
ICreateDevEnum *deviceEnum;
IEnumMoniker *videoDeviceEnum;
HRESULT err;
err = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&deviceEnum);
if(FAILED(err))
{
AppWarning(TEXT("FillOutListDevices: CoCreateInstance for the device enum failed, result = %08lX"), err);
return false;
}
err = deviceEnum->CreateClassEnumerator(matchGUID, &videoDeviceEnum, 0);
if(FAILED(err))
{
AppWarning(TEXT("FillOutListDevices: deviceEnum->CreateClassEnumerator failed, result = %08lX"), err);
deviceEnum->Release();
return false;
}
SafeRelease(deviceEnum);
if(err == S_FALSE) //no devices
return false;
//------------------------------------------
IMoniker *deviceInfo;
DWORD count;
while(videoDeviceEnum->Next(1, &deviceInfo, &count) == S_OK)
{
IPropertyBag *propertyData;
err = deviceInfo->BindToStorage(0, 0, IID_IPropertyBag, (void**)&propertyData);
if(SUCCEEDED(err))
{
VARIANT friendlyNameValue, devicePathValue;
friendlyNameValue.vt = VT_BSTR;
friendlyNameValue.bstrVal = NULL;
devicePathValue.vt = VT_BSTR;
devicePathValue.bstrVal = NULL;
err = propertyData->Read(L"FriendlyName", &friendlyNameValue, NULL);
propertyData->Read(L"DevicePath", &devicePathValue, NULL);
if(SUCCEEDED(err))
{
IBaseFilter *filter;
err = deviceInfo->BindToObject(NULL, 0, IID_IBaseFilter, (void**)&filter);
if(SUCCEEDED(err))
{
String strDeviceName = (CWSTR)friendlyNameValue.bstrVal;
deviceList->Add(strDeviceName);
UINT count2 = 0;
UINT id = INVALID;
while((id = deviceList->FindNextValueIndexI(strDeviceName, id)) != INVALID) count2++;
if(count2 > 1)
strDeviceName << TEXT(" (") << UIntString(count2) << TEXT(")");
String strDeviceID = (CWSTR)devicePathValue.bstrVal;
if(hwndCombo != NULL) SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)strDeviceName.Array());
deviceIDList->Add(strDeviceID);
SafeRelease(filter);
}
}
SafeRelease(propertyData);
}
SafeRelease(deviceInfo);
}
SafeRelease(videoDeviceEnum);
return true;
}
bool GetResolution(HWND hwndResolution, SIZE &resolution, BOOL bSelChange)
{
String strResolution;
if(bSelChange)
strResolution = GetCBText(hwndResolution);
else
strResolution = GetEditText(hwndResolution);
if(strResolution.NumTokens('x') != 2)
return false;
String strCX = strResolution.GetToken(0, 'x');
String strCY = strResolution.GetToken(1, 'x');
if(strCX.IsEmpty() || strCY.IsEmpty() || !ValidIntString(strCX) || !ValidIntString(strCY))
return false;
UINT cx = strCX.ToInt();
UINT cy = strCY.ToInt();
if(cx < 32 || cy < 32 || cx > 8192 || cy > 8192)
return false;
resolution.cx = cx;
resolution.cy = cy;
return true;
}
struct ColorSelectionData
{
HDC hdcDesktop;
HDC hdcDestination;
HBITMAP hBitmap;
bool bValid;
inline ColorSelectionData() : hdcDesktop(NULL), hdcDestination(NULL), hBitmap(NULL), bValid(false) {}
inline ~ColorSelectionData() {Clear();}
inline bool Init()
{
hdcDesktop = GetDC(NULL);
if(!hdcDesktop)
return false;
hdcDestination = CreateCompatibleDC(hdcDesktop);
if(!hdcDestination)
return false;
hBitmap = CreateCompatibleBitmap(hdcDesktop, 1, 1);
if(!hBitmap)
return false;
SelectObject(hdcDestination, hBitmap);
bValid = true;
return true;
}
inline void Clear()
{
if(hdcDesktop)
{
ReleaseDC(NULL, hdcDesktop);
hdcDesktop = NULL;
}
if(hdcDestination)
{
DeleteDC(hdcDestination);
hdcDestination = NULL;
}
if(hBitmap)
{
DeleteObject(hBitmap);
hBitmap = NULL;
}
bValid = false;
}
inline DWORD GetColor()
{
POINT p;
if(GetCursorPos(&p))
{
BITMAPINFO data;
zero(&data, sizeof(data));
data.bmiHeader.biSize = sizeof(data.bmiHeader);
data.bmiHeader.biWidth = 1;
data.bmiHeader.biHeight = 1;
data.bmiHeader.biPlanes = 1;
data.bmiHeader.biBitCount = 24;
data.bmiHeader.biCompression = BI_RGB;
data.bmiHeader.biSizeImage = 4;
if(BitBlt(hdcDestination, 0, 0, 1, 1, hdcDesktop, p.x, p.y, SRCCOPY|CAPTUREBLT))
{
DWORD buffer;
if(GetDIBits(hdcDestination, hBitmap, 0, 1, &buffer, &data, DIB_RGB_COLORS))
return 0xFF000000|buffer;
}
else
{
int err = GetLastError();
nop();
}
}
return 0xFF000000;
}
};
static void OpenPropertyPages(HWND hwnd, IUnknown *propObject)
{
if(!propObject)
return;
ISpecifyPropertyPages *propPages;
CAUUID cauuid;
if(SUCCEEDED(propObject->QueryInterface(IID_ISpecifyPropertyPages, (void**)&propPages)))
{
if(SUCCEEDED(propPages->GetPages(&cauuid)))
{
if(cauuid.cElems)
{
OleCreatePropertyFrame(hwnd, 0, 0, NULL, 1, (LPUNKNOWN*)&propObject, cauuid.cElems, cauuid.pElems, 0, 0, NULL);
CoTaskMemFree(cauuid.pElems);
}
}
propPages->Release();
}
}
static void OpenPropertyPagesByName(HWND hwnd, String devicename, String deviceid, GUID matchGUID)
{
IBaseFilter *filter = GetDeviceByValue(matchGUID,
L"FriendlyName", devicename,
L"DevicePath", deviceid);
if(filter)
{
OpenPropertyPages(hwnd, filter);
filter->Release();
}
}
int SetSliderText(HWND hwndParent, int controlSlider, int controlText)
{
HWND hwndSlider = GetDlgItem(hwndParent, controlSlider);
HWND hwndText = GetDlgItem(hwndParent, controlText);
int sliderVal = (int)SendMessage(hwndSlider, TBM_GETPOS, 0, 0);
float floatVal = float(sliderVal)*0.01f;
SetWindowText(hwndText, FormattedString(TEXT("%.02f"), floatVal));
return sliderVal;
}
static IAMCrossbar *GetFilterCrossbar(IBaseFilter *filter)
{
IAMCrossbar *crossbar = NULL;
IGraphBuilder *graph = NULL;
ICaptureGraphBuilder2 *capture = NULL;
IAMStreamConfig *configVideo = NULL;
if (FAILED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, (REFIID)IID_IFilterGraph, (void**)&graph)))
goto crossbar_exit;
if (FAILED(CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, (REFIID)IID_ICaptureGraphBuilder2, (void**)&capture)))
goto crossbar_exit;
if (FAILED(capture->SetFiltergraph(graph)))
goto crossbar_exit;
if (FAILED(graph->AddFilter(filter, L"Capture device")))
goto crossbar_exit;
capture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, filter, IID_IAMStreamConfig, (void**)&configVideo);
capture->FindInterface(NULL, NULL, filter, IID_IAMCrossbar, (void**)&crossbar);
graph->RemoveFilter(filter);
crossbar_exit:
SafeRelease(configVideo);
SafeRelease(capture);
SafeRelease(graph);
return crossbar;
}
INT_PTR CALLBACK ConfigureDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static bool bSelectingColor = false;
static bool bMouseDown = false, bAudioDevicesPresent = true;
static ColorSelectionData colorData;
static DeinterlacerConfig deinterlacingConfig;
switch(message)
{
case WM_INITDIALOG:
{
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)lParam);
ConfigDialogData *configData = (ConfigDialogData*)lParam;
HWND hwndDeviceList = GetDlgItem(hwnd, IDC_DEVICELIST);
HWND hwndAudioList = GetDlgItem(hwnd, IDC_AUDIOLIST);
HWND hwndResolutionList = GetDlgItem(hwnd, IDC_RESOLUTION);
HWND hwndFPS = GetDlgItem(hwnd, IDC_FPS);
HWND hwndFlip = GetDlgItem(hwnd, IDC_FLIPIMAGE);
HWND hwndFlipHorizontal = GetDlgItem(hwnd, IDC_FLIPIMAGEH);
//------------------------------------------
bool bFlipVertical = configData->data->GetInt(TEXT("flipImage")) != 0;
bool bFlipHorizontal = configData->data->GetInt(TEXT("flipImageHorizontal")) != 0;
SendMessage(hwndFlip, BM_SETCHECK, bFlipVertical ? BST_CHECKED : BST_UNCHECKED, 0);
SendMessage(hwndFlipHorizontal, BM_SETCHECK, bFlipHorizontal ? BST_CHECKED : BST_UNCHECKED, 0);
//------------------------------------------
UINT opacity = configData->data->GetInt(TEXT("opacity"), 100);
SendMessage(GetDlgItem(hwnd, IDC_OPACITY), UDM_SETRANGE32, 0, 100);
SendMessage(GetDlgItem(hwnd, IDC_OPACITY), UDM_SETPOS32, 0, opacity);
int gammaVal = configData->data->GetInt(TEXT("gamma"), 100);
HWND hwndTemp = GetDlgItem(hwnd, IDC_GAMMA);
SendMessage(hwndTemp, TBM_CLEARTICS, FALSE, 0);
SendMessage(hwndTemp, TBM_SETRANGE, FALSE, MAKELPARAM(50, 175));
SendMessage(hwndTemp, TBM_SETTIC, 0, 100);
SendMessage(hwndTemp, TBM_SETPOS, TRUE, gammaVal);
SetSliderText(hwnd, IDC_GAMMA, IDC_GAMMAVAL);
//------------------------------------------
String strDevice = configData->data->GetString(TEXT("device"));
String strAudioDevice = configData->data->GetString(TEXT("audioDevice"));
UINT cx = configData->data->GetInt(TEXT("resolutionWidth"));
UINT cy = configData->data->GetInt(TEXT("resolutionHeight"));
UINT64 frameInterval = configData->data->GetInt(TEXT("frameInterval"));
//------------------------------------------
deinterlacingConfig.type = configData->data->GetInt(TEXT("deinterlacingType"));
deinterlacingConfig.fieldOrder = configData->data->GetInt(TEXT("deinterlacingFieldOrder"));
deinterlacingConfig.processor = configData->data->GetInt(TEXT("deinterlacingProcessor"));
if(deinterlacingConfig.type >= DEINTERLACING_TYPE_LAST)
deinterlacingConfig.type = DEINTERLACING_NONE;
hwndTemp = GetDlgItem(hwnd, IDC_DEINTERLACELIST);
// Populate deinterlacing type list
for(size_t i = 0; i < DEINTERLACING_TYPE_LAST; i++)
{
#ifndef _DEBUG
if(i == DEINTERLACING__DEBUG)
continue;
#endif
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)pluginLocale->LookupString(deinterlacerLocalizations[i]));
DeinterlacerConfig& config = deinterlacerConfigs[i];
if(deinterlacingConfig.type != config.type)
continue;
const int deintProcBoth = (DEINTERLACING_PROCESSOR_CPU | DEINTERLACING_PROCESSOR_GPU);
HWND checkbox = GetDlgItem(hwnd, IDC_GPUDEINT);
EnableWindow(checkbox, config.processor == deintProcBoth);
if(config.processor != deintProcBoth && deinterlacingConfig.processor != config.processor)
{
configData->data->SetInt(TEXT("deinterlacingGPU"), config.processor);
deinterlacingConfig.processor = config.processor;
}
Button_SetCheck(checkbox, deinterlacingConfig.processor == DEINTERLACING_PROCESSOR_GPU);
const int deintFieldsBoth = (FIELD_ORDER_TFF | FIELD_ORDER_BFF);
HWND tff = GetDlgItem(hwnd, IDC_TFF),
bff = GetDlgItem(hwnd, IDC_BFF);
if(config.fieldOrder != deintFieldsBoth && deinterlacingConfig.fieldOrder != config.fieldOrder)
{
configData->data->SetInt(TEXT("deinterlacingFieldOrder"), config.fieldOrder);
deinterlacingConfig.fieldOrder = config.fieldOrder;
}
Button_SetCheck(tff, deinterlacingConfig.fieldOrder == FIELD_ORDER_TFF);
Button_SetCheck(bff, deinterlacingConfig.fieldOrder == FIELD_ORDER_BFF);
EnableWindow(tff, config.fieldOrder & FIELD_ORDER_TFF);
EnableWindow(bff, config.fieldOrder & FIELD_ORDER_BFF);
}
SendMessage(hwndTemp, CB_SETCURSEL, deinterlacingConfig.type, 0);
//------------------------------------------
BOOL bCustomResolution = configData->data->GetInt(TEXT("customResolution"));
SendMessage(GetDlgItem(hwnd, IDC_CUSTOMRESOLUTION), BM_SETCHECK, bCustomResolution ? BST_CHECKED : BST_UNCHECKED, 0);
LocalizeWindow(hwnd, pluginLocale);
FillOutListOfDevices(hwndDeviceList, CLSID_VideoInputDeviceCategory, &configData->deviceNameList, &configData->deviceIDList);
UINT deviceID = CB_ERR;
if(strDevice.IsValid() && cx > 0 && cy > 0 && frameInterval > 0)
deviceID = (UINT)SendMessage(hwndDeviceList, CB_FINDSTRINGEXACT, -1, (LPARAM)strDevice.Array());
if(deviceID == CB_ERR)
{
SendMessage(hwndDeviceList, CB_SETCURSEL, 0, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_DEVICELIST, CBN_SELCHANGE), (LPARAM)hwndDeviceList);
}
else
{
SendMessage(hwndDeviceList, CB_SETCURSEL, deviceID, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_DEVICELIST, CBN_SELCHANGE), (LPARAM)hwndDeviceList);
if(bCustomResolution)
{
String strResolution;
strResolution << UIntString(cx) << TEXT("x") << UIntString(cy);
SendMessage(hwndResolutionList, WM_SETTEXT, 0, (LPARAM)strResolution.Array());
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_RESOLUTION, CBN_EDITCHANGE), (LPARAM)hwndResolutionList);
SetWindowText(hwndFPS, FloatString(10000000.0/double(frameInterval)));
}
}
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_CUSTOMRESOLUTION, BN_CLICKED), (LPARAM)GetDlgItem(hwnd, IDC_CUSTOMRESOLUTION));
HWND hwndPreferredList = GetDlgItem(hwnd, IDC_PREFERREDOUTPUT);
BOOL bUsePreferredOutput = configData->data->GetInt(TEXT("usePreferredType"));
EnableWindow(hwndPreferredList, bUsePreferredOutput);
SendMessage(GetDlgItem(hwnd, IDC_USEPREFERREDOUTPUT), BM_SETCHECK, bUsePreferredOutput ? BST_CHECKED : BST_UNCHECKED, 0);
//------------------------------------------
bool bDefaultUseBuffering = strDevice.IsValid() && (sstri(strDevice, TEXT("Elgato")) != NULL);
bool bUseBuffering = configData->data->GetInt(TEXT("useBuffering"), bDefaultUseBuffering) != 0;
EnableWindow(GetDlgItem(hwnd, IDC_DELAY_EDIT), bUseBuffering);
EnableWindow(GetDlgItem(hwnd, IDC_DELAY), bUseBuffering);
SendMessage(GetDlgItem(hwnd, IDC_USEBUFFERING), BM_SETCHECK, bUseBuffering ? BST_CHECKED : BST_UNCHECKED, 0);
DWORD bufferTime = configData->data->GetInt(TEXT("bufferTime"));
SendMessage(GetDlgItem(hwnd, IDC_DELAY), UDM_SETRANGE32, 0, 8000);
SendMessage(GetDlgItem(hwnd, IDC_DELAY), UDM_SETPOS32, 0, bufferTime);
//------------------------------------------
UINT audioDeviceID = CB_ERR;
if(strAudioDevice.IsValid())
audioDeviceID = (UINT)SendMessage(hwndAudioList, CB_FINDSTRINGEXACT, -1, (LPARAM)strAudioDevice.Array());
if(audioDeviceID == CB_ERR)
SendMessage(hwndAudioList, CB_SETCURSEL, configData->bDeviceHasAudio ? 1 : 0, 0); //yes, I know, but the output is not a bool
else
SendMessage(hwndAudioList, CB_SETCURSEL, audioDeviceID, 0);
//------------------------------------------
int soundOutputType = configData->data->GetInt(TEXT("soundOutputType"), 1);
switch(soundOutputType) {
case 0:
case 1: hwndTemp = GetDlgItem(hwnd, IDC_OUTPUTSOUND); break;
case 2: hwndTemp = GetDlgItem(hwnd, IDC_PLAYDESKTOPSOUND); break;
}
SendMessage(hwndTemp, BM_SETCHECK, BST_CHECKED, 0);
EnableWindow(GetDlgItem(hwnd, IDC_TIMEOFFSET), soundOutputType == 1);
EnableWindow(GetDlgItem(hwnd, IDC_TIMEOFFSET_EDIT), soundOutputType == 1);
EnableWindow(GetDlgItem(hwnd, IDC_VOLUME), soundOutputType != 0);
if (soundOutputType == 0)
SendMessage(hwndAudioList, CB_SETCURSEL, 0, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_AUDIOLIST, CBN_SELCHANGE), (LPARAM)hwndAudioList);
//------------------------------------------
float fVol = configData->data->GetFloat(TEXT("volume"), 1.0f);
SetVolumeControlValue(GetDlgItem(hwnd, IDC_VOLUME), fVol);
//------------------------------------------
int pos = configData->data->GetInt(TEXT("soundTimeOffset"));
SendMessage(GetDlgItem(hwnd, IDC_TIMEOFFSET), UDM_SETRANGE32, -3000, 20000);
SendMessage(GetDlgItem(hwnd, IDC_TIMEOFFSET), UDM_SETPOS32, 0, pos);
//------------------------------------------
BOOL bUseChromaKey = configData->data->GetInt(TEXT("useChromaKey"), 0);
BOOL bUsePointFiltering = configData->data->GetInt(TEXT("usePointFiltering"), 0);
BOOL bPreserveSourceSize = configData->data->GetInt(TEXT("preserveSourceSize"), 0);
DWORD keyColor = configData->data->GetInt(TEXT("keyColor"), 0xFFFFFFFF);
UINT similarity = configData->data->GetInt(TEXT("keySimilarity"), 0);
UINT blend = configData->data->GetInt(TEXT("keyBlend"), 80);
UINT gamma = configData->data->GetInt(TEXT("keySpillReduction"), 50);
SendMessage(GetDlgItem(hwnd, IDC_POINTFILTERING), BM_SETCHECK, bUsePointFiltering ? BST_CHECKED : BST_UNCHECKED, 0);
SendMessage(GetDlgItem(hwnd, IDC_PRESERVESIZE), BM_SETCHECK, bPreserveSourceSize ? BST_CHECKED : BST_UNCHECKED, 0);
SendMessage(GetDlgItem(hwnd, IDC_USECHROMAKEY), BM_SETCHECK, bUseChromaKey ? BST_CHECKED : BST_UNCHECKED, 0);
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), keyColor);
SendMessage(GetDlgItem(hwnd, IDC_BASETHRESHOLD), UDM_SETRANGE32, 0, 1000);
SendMessage(GetDlgItem(hwnd, IDC_BASETHRESHOLD), UDM_SETPOS32, 0, similarity);
SendMessage(GetDlgItem(hwnd, IDC_BLEND), UDM_SETRANGE32, 0, 1000);
SendMessage(GetDlgItem(hwnd, IDC_BLEND), UDM_SETPOS32, 0, blend);
SendMessage(GetDlgItem(hwnd, IDC_SPILLREDUCTION), UDM_SETRANGE32, 0, 1000);
SendMessage(GetDlgItem(hwnd, IDC_SPILLREDUCTION), UDM_SETPOS32, 0, gamma);
EnableWindow(GetDlgItem(hwnd, IDC_COLOR), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_SELECTCOLOR), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_BASETHRESHOLD_EDIT), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_BASETHRESHOLD), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_BLEND_EDIT), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_BLEND), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_SPILLREDUCTION_EDIT), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_SPILLREDUCTION), bUseChromaKey);
//------------------------------------------
return TRUE;
}
case WM_DESTROY:
if(colorData.bValid)
{
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), colorData.GetColor());
colorData.Clear();
}
break;
case WM_LBUTTONDOWN:
if(bSelectingColor)
{
bMouseDown = true;
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), colorData.GetColor());
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_COLOR, CCN_CHANGED), (LPARAM)GetDlgItem(hwnd, IDC_COLOR));
}
break;
case WM_MOUSEMOVE:
if(bSelectingColor && bMouseDown)
{
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), colorData.GetColor());
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_COLOR, CCN_CHANGED), (LPARAM)GetDlgItem(hwnd, IDC_COLOR));
}
break;
case WM_LBUTTONUP:
if(bSelectingColor)
{
colorData.Clear();
ReleaseCapture();
bMouseDown = false;
bSelectingColor = false;
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
source->SetInt(TEXT("useChromaKey"), true);
}
break;
case WM_CAPTURECHANGED:
if(bSelectingColor)
{
if(colorData.bValid)
{
CCSetColor(GetDlgItem(hwnd, IDC_COLOR), colorData.GetColor());
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_COLOR, CCN_CHANGED), (LPARAM)GetDlgItem(hwnd, IDC_COLOR));
colorData.Clear();
}
ReleaseCapture();
bMouseDown = false;
bSelectingColor = false;
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
source->SetInt(TEXT("useChromaKey"), true);
}
break;
case WM_HSCROLL:
{
if(GetDlgCtrlID((HWND)lParam) == IDC_GAMMA)
{
int gamma = SetSliderText(hwnd, IDC_GAMMA, IDC_GAMMAVAL);
ConfigDialogData *info = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(info->lpName);
if(source)
source->SetInt(TEXT("gamma"), gamma);
}
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_CUSTOMRESOLUTION:
{
HWND hwndUseCustomResolution = (HWND)lParam;
BOOL bCustomResolution = SendMessage(hwndUseCustomResolution, BM_GETCHECK, 0, 0) == BST_CHECKED;
EnableWindow(GetDlgItem(hwnd, IDC_RESOLUTION), bCustomResolution);
EnableWindow(GetDlgItem(hwnd, IDC_FPS), bCustomResolution);
break;
}
case IDC_USEBUFFERING:
if (HIWORD(wParam) == BN_CLICKED) {
bool bUseBuffering = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
EnableWindow(GetDlgItem(hwnd, IDC_DELAY_EDIT), bUseBuffering);
EnableWindow(GetDlgItem(hwnd, IDC_DELAY), bUseBuffering);
}
break;
case IDC_VOLUME:
if(HIWORD(wParam) == VOLN_ADJUSTING || HIWORD(wParam) == VOLN_FINALVALUE)
{
if(IsWindowEnabled((HWND)lParam))
{
float fVol = GetVolumeControlValue((HWND)lParam);
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
source->SetFloat(TEXT("volume"), fVol);
}
}
break;
case IDC_USECHROMAKEY:
{
HWND hwndUseColorKey = (HWND)lParam;
BOOL bUseChromaKey = SendMessage(hwndUseColorKey, BM_GETCHECK, 0, 0) == BST_CHECKED;
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
source->SetInt(TEXT("useChromaKey"), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_COLOR), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_SELECTCOLOR), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_BASETHRESHOLD_EDIT), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_BASETHRESHOLD), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_BLEND_EDIT), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_BLEND), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_SPILLREDUCTION_EDIT), bUseChromaKey);
EnableWindow(GetDlgItem(hwnd, IDC_SPILLREDUCTION), bUseChromaKey);
break;
}
case IDC_SELECTCOLOR:
{
if(!bSelectingColor)
{
if(colorData.Init())
{
bMouseDown = false;
bSelectingColor = true;
SetCapture(hwnd);
HCURSOR hCursor = (HCURSOR)LoadImage(hinstMain, MAKEINTRESOURCE(IDC_COLORPICKER), IMAGE_CURSOR, 32, 32, 0);
SetCursor(hCursor);
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
source->SetInt(TEXT("useChromaKey"), false);
}
else
colorData.Clear();
}
break;
}
case IDC_COLOR:
{
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
{
DWORD color = CCGetColor((HWND)lParam);
source->SetInt(TEXT("keyColor"), color);
}
break;
}
case IDC_FLIPIMAGE:
case IDC_FLIPIMAGEH:
if(HIWORD(wParam) == BN_CLICKED)
{
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
{
HWND hwndFlip = (HWND)lParam;
BOOL bFlipImage = SendMessage(hwndFlip, BM_GETCHECK, 0, 0) == BST_CHECKED;
switch(LOWORD(wParam))
{
case IDC_FLIPIMAGE: source->SetInt(TEXT("flipImage"), bFlipImage); break;
case IDC_FLIPIMAGEH: source->SetInt(TEXT("flipImageHorizontal"), bFlipImage); break;
}
}
}
break;
case IDC_DELAY_EDIT:
case IDC_TIMEOFFSET_EDIT:
case IDC_OPACITY_EDIT:
case IDC_BASETHRESHOLD_EDIT:
case IDC_BLEND_EDIT:
case IDC_SPILLREDUCTION_EDIT:
if(HIWORD(wParam) == EN_CHANGE)
{
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
if(configData)
{
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
{
HWND hwndVal = NULL;
switch(LOWORD(wParam))
{
case IDC_DELAY_EDIT: hwndVal = GetDlgItem(hwnd, IDC_DELAY); break;
case IDC_TIMEOFFSET_EDIT: hwndVal = GetDlgItem(hwnd, IDC_TIMEOFFSET); break;
case IDC_OPACITY_EDIT: hwndVal = GetDlgItem(hwnd, IDC_OPACITY); break;
case IDC_BASETHRESHOLD_EDIT: hwndVal = GetDlgItem(hwnd, IDC_BASETHRESHOLD); break;
case IDC_BLEND_EDIT: hwndVal = GetDlgItem(hwnd, IDC_BLEND); break;
case IDC_SPILLREDUCTION_EDIT: hwndVal = GetDlgItem(hwnd, IDC_SPILLREDUCTION); break;
}
int val = (int)SendMessage(hwndVal, UDM_GETPOS32, 0, 0);
switch(LOWORD(wParam))
{
case IDC_DELAY_EDIT: source->SetInt(TEXT("bufferTime"), val); break;
case IDC_TIMEOFFSET_EDIT: source->SetInt(TEXT("timeOffset"), val); break;
case IDC_OPACITY_EDIT: source->SetInt(TEXT("opacity"), val); break;
case IDC_BASETHRESHOLD_EDIT: source->SetInt(TEXT("keySimilarity"), val); break;
case IDC_BLEND_EDIT: source->SetInt(TEXT("keyBlend"), val); break;
case IDC_SPILLREDUCTION_EDIT: source->SetInt(TEXT("keySpillReduction"), val); break;
}
}
}
}
break;
case IDC_USEPREFERREDOUTPUT:
{
BOOL bUsePreferredOutput = SendMessage(GetDlgItem(hwnd, IDC_USEPREFERREDOUTPUT), BM_GETCHECK, 0, 0) == BST_CHECKED;
EnableWindow(GetDlgItem(hwnd, IDC_PREFERREDOUTPUT), bUsePreferredOutput);
break;
}
case IDC_REFRESH:
{
HWND hwndDeviceList = GetDlgItem(hwnd, IDC_DEVICELIST);
HWND hwndAudioDeviceList = GetDlgItem(hwnd, IDC_AUDIOLIST);
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
FillOutListOfDevices(hwndDeviceList, CLSID_VideoInputDeviceCategory, &configData->deviceNameList, &configData->deviceIDList);
bAudioDevicesPresent = FillOutListOfDevices(hwndAudioDeviceList, CLSID_AudioInputDeviceCategory, &configData->audioNameList, &configData->audioIDList);
SendMessage(hwndDeviceList, CB_SETCURSEL, 0, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_DEVICELIST, CBN_SELCHANGE), (LPARAM)hwndDeviceList);
if(bAudioDevicesPresent)
{
SendMessage(hwndAudioDeviceList, CB_SETCURSEL, 0, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_AUDIOLIST, CBN_SELCHANGE), (LPARAM)hwndAudioDeviceList);
}
EnableWindow(hwndAudioDeviceList, bAudioDevicesPresent);
EnableWindow(GetDlgItem(hwnd, IDC_CONFIGAUDIO), bAudioDevicesPresent);
break;
}
case IDC_DEINTERLACELIST:
if(HIWORD(wParam) == CBN_SELCHANGE)
{
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);;
int confId = (int)SendMessage(GetDlgItem(hwnd, IDC_DEINTERLACELIST), CB_GETCURSEL, 0, 0);
deinterlacingConfig.type = configData->data->GetInt(TEXT("deinterlacingType"));
deinterlacingConfig.fieldOrder = configData->data->GetInt(TEXT("deinterlacingFieldOrder"));
deinterlacingConfig.processor = configData->data->GetInt(TEXT("deinterlacingGPU"));
if(deinterlacingConfig.type >= DEINTERLACING_TYPE_LAST)
deinterlacingConfig.type = DEINTERLACING_NONE;
DeinterlacerConfig& config = deinterlacerConfigs[confId];
const int deintProcBoth = (DEINTERLACING_PROCESSOR_CPU | DEINTERLACING_PROCESSOR_GPU);
HWND checkbox = GetDlgItem(hwnd, IDC_GPUDEINT);
EnableWindow(checkbox, config.processor == deintProcBoth);
if(config.processor != deintProcBoth && deinterlacingConfig.processor != config.processor)
deinterlacingConfig.processor = config.processor;
Button_SetCheck(checkbox, deinterlacingConfig.processor == DEINTERLACING_PROCESSOR_GPU);
const int deintFieldsBoth = (FIELD_ORDER_TFF | FIELD_ORDER_BFF);
HWND tff = GetDlgItem(hwnd, IDC_TFF),
bff = GetDlgItem(hwnd, IDC_BFF);
if(config.fieldOrder != deintFieldsBoth && deinterlacingConfig.fieldOrder != config.fieldOrder)
deinterlacingConfig.fieldOrder = config.fieldOrder;
else if(deinterlacingConfig.fieldOrder != config.fieldOrder && (config.fieldOrder & deinterlacingConfig.fieldOrder) == 0)
deinterlacingConfig.fieldOrder = config.fieldOrder & FIELD_ORDER_TFF ? FIELD_ORDER_TFF : FIELD_ORDER_BFF;
Button_SetCheck(tff, deinterlacingConfig.fieldOrder == FIELD_ORDER_TFF);
Button_SetCheck(bff, deinterlacingConfig.fieldOrder == FIELD_ORDER_BFF);
EnableWindow(tff, config.fieldOrder & FIELD_ORDER_TFF);
EnableWindow(bff, config.fieldOrder & FIELD_ORDER_BFF);
}
break;
case IDC_DEVICELIST:
if(HIWORD(wParam) == CBN_SELCHANGE)
{
HWND hwndResolutions = GetDlgItem(hwnd, IDC_RESOLUTION);
SendMessage(hwndResolutions, CB_RESETCONTENT, 0, 0);
HWND hwndDevices = (HWND)lParam;
UINT id = (UINT)SendMessage(hwndDevices, CB_GETCURSEL, 0, 0);
if(id == CB_ERR)
{
EnableWindow(GetDlgItem(hwnd, IDC_RESOLUTION), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_FPS), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_CONFIG), FALSE);
EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
}
else
{
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
HWND hwndAudioList = GetDlgItem(hwnd, IDC_AUDIOLIST);
BOOL bCustomResolution = SendMessage(GetDlgItem(hwnd, IDC_CUSTOMRESOLUTION) , BM_GETCHECK, 0, 0) == BST_CHECKED;
EnableWindow(GetDlgItem(hwnd, IDC_RESOLUTION), bCustomResolution);
EnableWindow(GetDlgItem(hwnd, IDC_FPS), bCustomResolution);
EnableWindow(GetDlgItem(hwnd, IDC_CONFIG), TRUE);
EnableWindow(GetDlgItem(hwnd, IDOK), TRUE);
IBaseFilter *filter = GetDeviceByValue(CLSID_VideoInputDeviceCategory,
L"FriendlyName", configData->deviceNameList[id],
L"DevicePath", configData->deviceIDList[id]);
if(filter)
{
//--------------------------------
// get video info
IPin *outputPin = GetOutputPin(filter, &MEDIATYPE_Video);
if(outputPin)
{
configData->ClearOutputList();
GetOutputList(outputPin, configData->outputList);
configData->GetResolutions(configData->resolutions);
for(UINT i=0; i<configData->resolutions.Num(); i++)
{
SIZE &resolution = configData->resolutions[i];
String strResolution;
strResolution << IntString(resolution.cx) << TEXT("x") << IntString(resolution.cy);
SendMessage(hwndResolutions, CB_ADDSTRING, 0, (LPARAM)strResolution.Array());
}
outputPin->Release();
outputPin = NULL;
}
String strDeviceName = configData->deviceNameList[id];
bool bIsElworkaroundo = sstri(strDeviceName, TEXT("elgato")) != NULL; //HAHAHAHAHAHAHA HOW F***ING WONDERFUL. 自殺したい
IAMCrossbar *crossbar = bIsElworkaroundo ? NULL : GetFilterCrossbar(filter);
EnableWindow(GetDlgItem(hwnd, IDC_CROSSBAR), crossbar != NULL);
SafeRelease(crossbar);
outputPin = GetOutputPin(filter, &MEDIATYPE_Audio);
configData->bDeviceHasAudio = (outputPin != NULL);
SafeRelease(outputPin);
filter->Release();
}
HWND hwndUseBuffering = GetDlgItem(hwnd, IDC_USEBUFFERING);
if (sstri(configData->deviceNameList[id], TEXT("Elgato")) != NULL) {
SendMessage(hwndUseBuffering, BM_SETCHECK, BST_CHECKED, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_USEBUFFERING, BN_CLICKED), (LPARAM)hwndUseBuffering);
} else {
SendMessage(hwndUseBuffering, BM_SETCHECK, BST_UNCHECKED, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_USEBUFFERING, BN_CLICKED), (LPARAM)hwndUseBuffering);
}
//-------------------------------------------------
SIZE size;
UINT64 frameInterval;
if(GetClosestResolutionFPS(configData->outputList, size, frameInterval, true))
{
String strResolution;
strResolution << UIntString(size.cx) << TEXT("x") << UIntString(size.cy);
SendMessage(hwndResolutions, WM_SETTEXT, 0, (LPARAM)strResolution.Array());
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_RESOLUTION, CBN_EDITCHANGE), (LPARAM)hwndResolutions);
HWND hwndFPS = GetDlgItem(hwnd, IDC_FPS);
SetWindowText(hwndFPS, FloatString(10000000.0/double(frameInterval)));
}
else
{
SendMessage(hwndResolutions, CB_SETCURSEL, 0, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_RESOLUTION, CBN_SELCHANGE), (LPARAM)hwndResolutions);
}
//-------------------------------------------------
// get audio devices
bAudioDevicesPresent = FillOutListOfDevices(hwndAudioList, CLSID_AudioInputDeviceCategory, &configData->audioNameList, &configData->audioIDList);
if (configData->bDeviceHasAudio) {
CTSTR lpName = PluginStr("DeviceSelection.UseDeviceAudio");
SendMessage(hwndAudioList, CB_INSERTSTRING, 0, (LPARAM)lpName);
configData->audioNameList.Insert(0, lpName);
configData->audioIDList.Insert(0, NULL);
}
CTSTR pDisabled = Str("Disable");
SendMessage(hwndAudioList, CB_INSERTSTRING, 0, (LPARAM)pDisabled);
configData->audioNameList.Insert(0, pDisabled);
configData->audioIDList.Insert(0, TEXT("Disabled"));
EnableWindow(hwndAudioList, bAudioDevicesPresent);
if (!bAudioDevicesPresent)
EnableWindow(GetDlgItem(hwnd, IDC_CONFIGAUDIO), FALSE);
bool bHasAudio = configData->bDeviceHasAudio;
EnableWindow(GetDlgItem(hwnd, IDC_PLAYDESKTOPSOUND), bHasAudio);
EnableWindow(GetDlgItem(hwnd, IDC_OUTPUTSOUND), bHasAudio);
EnableWindow(GetDlgItem(hwnd, IDC_TIMEOFFSET), bHasAudio);
EnableWindow(GetDlgItem(hwnd, IDC_TIMEOFFSET_EDIT), bHasAudio);
if (bHasAudio)
SendMessage(hwndAudioList, CB_SETCURSEL, 1, 0);
else
SendMessage(hwndAudioList, CB_SETCURSEL, 0, 0);
ConfigureDialogProc(hwnd, WM_COMMAND, MAKEWPARAM(IDC_AUDIOLIST, CBN_SELCHANGE), (LPARAM)hwndAudioList);
}
}
break;
case IDC_AUDIOLIST:
if(HIWORD(wParam) == CBN_SELCHANGE)
{
HWND hwndDevices = (HWND)lParam;
UINT id = (UINT)SendMessage(hwndDevices, CB_GETCURSEL, 0, 0);
if (id == CB_ERR || id == 0) {
EnableWindow(GetDlgItem(hwnd, IDC_CONFIGAUDIO), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_PLAYDESKTOPSOUND), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_OUTPUTSOUND), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_TIMEOFFSET), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_TIMEOFFSET_EDIT), FALSE);
} else {
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
IBaseFilter *filter = GetDeviceByValue(CLSID_AudioInputDeviceCategory,
L"FriendlyName", configData->audioNameList[id],
L"DevicePath", configData->audioIDList[id]);
if (filter) {
EnableWindow(GetDlgItem(hwnd, IDC_CONFIGAUDIO), TRUE);
filter->Release();
} else {
EnableWindow(GetDlgItem(hwnd, IDC_CONFIGAUDIO), FALSE);
}
EnableWindow(GetDlgItem(hwnd, IDC_PLAYDESKTOPSOUND), TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_OUTPUTSOUND), TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_TIMEOFFSET), TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_TIMEOFFSET_EDIT), TRUE);
}
}
break;
case IDC_RESOLUTION:
if(HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam) == CBN_SELCHANGE)
{
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
HWND hwndResolution = (HWND)lParam;
HWND hwndFPS = GetDlgItem(hwnd, IDC_FPS);
SIZE resolution;
FPSInfo fpsInfo;
SendMessage(hwndFPS, CB_RESETCONTENT, 0, 0);
if(!GetResolution(hwndResolution, resolution, HIWORD(wParam) == CBN_SELCHANGE) || !configData->GetResolutionFPSInfo(resolution, fpsInfo))
{
SetWindowText(hwndFPS, TEXT("0"));
break;
}
//-------------------------------------------------------
double bestFPS = 0.0f;
UINT64 bestInterval = 0;
for(UINT i=0; i<fpsInfo.supportedIntervals.Num(); i++)
{
double minFPS = 10000000.0/double(fpsInfo.supportedIntervals[i].maxFrameInterval);
double maxFPS = 10000000.0/double(fpsInfo.supportedIntervals[i].minFrameInterval);
String strFPS;
if(CloseDouble(minFPS, maxFPS))
strFPS << FloatString(float(minFPS));
else
strFPS << FloatString(float(minFPS)) << TEXT("-") << FloatString(float(maxFPS));
int id = (int)SendMessage(hwndFPS, CB_FINDSTRINGEXACT, -1, (LPARAM)strFPS.Array());
if(id == CB_ERR)
SendMessage(hwndFPS, CB_ADDSTRING, 0, (LPARAM)strFPS.Array());
if(bestFPS < minFPS)
{
bestFPS = minFPS;
bestInterval = fpsInfo.supportedIntervals[i].maxFrameInterval;
}
if(bestFPS < maxFPS)
{
bestFPS = maxFPS;
bestInterval = fpsInfo.supportedIntervals[i].minFrameInterval;
}
}
SetWindowText(hwndFPS, FloatString(float(bestFPS)));
//-------------------------------------------------------
PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_FPS, CBN_EDITCHANGE), (LPARAM)GetDlgItem(hwnd, IDC_FPS));
}
break;
case IDC_FPS:
if(HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE)
{
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
SIZE resolution;
if(!GetResolution(GetDlgItem(hwnd, IDC_RESOLUTION), resolution, FALSE))
break;
FPSInfo fpsInfo;
if(!configData->GetResolutionFPSInfo(resolution, fpsInfo))
break;
//--------------------------------------------
String strFPSVal = GetEditText((HWND)lParam);
if(schr(strFPSVal, '-'))
{
StringList tokens;
strFPSVal.GetTokenList(tokens, '-', FALSE);
if(tokens.Num())
strFPSVal = tokens.Last();
else
break;
}
if(!ValidFloatString(strFPSVal))
break;
float fps = strFPSVal.ToFloat();
INT64 interval = INT64(10000000.0/double(fps));
UINT64 bestInterval;
UINT64 bestDist = 0xFFFFFFFFFFFFFFFFLL;
for(UINT i=0; i<fpsInfo.supportedIntervals.Num(); i++)
{
UINT64 maxDist = (UINT64)_abs64(INT64(fpsInfo.supportedIntervals[i].maxFrameInterval)-interval);
UINT64 minDist = (UINT64)_abs64(INT64(fpsInfo.supportedIntervals[i].minFrameInterval)-interval);
if(maxDist < bestDist)
{
bestDist = maxDist;
bestInterval = fpsInfo.supportedIntervals[i].maxFrameInterval;
}
if(minDist < bestDist)
{
bestDist = minDist;
bestInterval = fpsInfo.supportedIntervals[i].minFrameInterval;
}
}
//--------------------------------------------
HWND hwndPreferredList = GetDlgItem(hwnd, IDC_PREFERREDOUTPUT);
SendMessage(hwndPreferredList, CB_RESETCONTENT, 0, 0);
UINT preferredType = (UINT)configData->data->GetInt(TEXT("preferredType"), -1);
List<VideoOutputType> types;
if(GetVideoOutputTypes(configData->outputList, resolution.cx, resolution.cy, bestInterval, types))
{
int preferredID = -1;
for(UINT i=0; i<types.Num(); i++)
{
CTSTR lpName = EnumToName[(UINT)types[i]];
int id = (int)SendMessage(hwndPreferredList, CB_ADDSTRING, 0, (LPARAM)lpName);
SendMessage(hwndPreferredList, CB_SETITEMDATA, id, (LPARAM)types[i]);
if((UINT)types[i] == preferredType)
{
SendMessage(hwndPreferredList, CB_SETCURSEL, id, 0);
preferredID = id;
}
}
if(preferredID == -1)
SendMessage(hwndPreferredList, CB_SETCURSEL, 0, 0);
}
}
break;
case IDC_CONFIG:
case IDC_CONFIGAUDIO:
case IDC_CROSSBAR:
{
UINT id;
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
IBaseFilter *filter;
switch(LOWORD(wParam))
{
case IDC_CONFIG:
id = (UINT)SendMessage(GetDlgItem(hwnd, IDC_DEVICELIST), CB_GETCURSEL, 0, 0);
if(id != CB_ERR) OpenPropertyPagesByName(hwnd, configData->deviceNameList[id], configData->deviceIDList[id], CLSID_VideoInputDeviceCategory);
break;
case IDC_CONFIGAUDIO:
id = (UINT)SendMessage(GetDlgItem(hwnd, IDC_AUDIOLIST), CB_GETCURSEL, 0, 0);
if(id != CB_ERR) OpenPropertyPagesByName(hwnd, configData->audioNameList[id], configData->audioIDList[id], CLSID_AudioInputDeviceCategory);
break;
case IDC_CROSSBAR:
id = (UINT)SendMessage(GetDlgItem(hwnd, IDC_DEVICELIST), CB_GETCURSEL, 0, 0);
if (id == CB_ERR)
break;
filter = GetDeviceByValue(CLSID_VideoInputDeviceCategory,
L"FriendlyName", configData->deviceNameList[id],
L"DevicePath", configData->deviceIDList[id]);
if (filter) {
String strDeviceName = configData->deviceNameList[id];
bool bIsElworkaroundo = sstri(strDeviceName, TEXT("elgato")) != NULL; //HAHAHAHAHAHAHA HOW F***ING WONDERFUL. 自殺したい
IAMCrossbar *crossbar = bIsElworkaroundo ? NULL : GetFilterCrossbar(filter);
if (crossbar) {
OpenPropertyPages(hwnd, crossbar);
crossbar->Release();
}
filter->Release();
}
break;
}
break;
}
case IDOK:
{
UINT deviceID = (UINT)SendMessage(GetDlgItem(hwnd, IDC_DEVICELIST), CB_GETCURSEL, 0, 0);
if(deviceID == CB_ERR)
break;
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
SIZE resolution;
if(!GetResolution(GetDlgItem(hwnd, IDC_RESOLUTION), resolution, FALSE))
{
MessageBox(hwnd, PluginStr("DeviceSelection.InvalidResolution"), NULL, 0);
break;
}
String strDevice = GetCBText(GetDlgItem(hwnd, IDC_DEVICELIST), deviceID);
String strFPS = GetEditText(GetDlgItem(hwnd, IDC_FPS));
if(schr(strFPS, '-'))
{
StringList tokens;
strFPS.GetTokenList(tokens, '-', FALSE);
if(tokens.Num())
strFPS = tokens.Last();
else
break;
}
float fpsVal = 120.0f;
if(ValidFloatString(strFPS))
fpsVal = strFPS.ToFloat();
UINT64 frameInterval = UINT64(10000000.0/double(fpsVal));
if(strFPS == TEXT("0") || fpsVal == 0.0)
{
MessageBox(hwnd, PluginStr("DeviceSelection.UnsupportedResolution"), NULL, 0);
break;
}
if(configData->bCreating)
{
bool bFoundGlobal;
if(CurrentDeviceExists(strDevice, configData->bGlobalSource, bFoundGlobal))
{
if(bFoundGlobal)
MessageBox(hwnd, PluginStr("DeviceSelection.GlobalExists"), NULL, 0);
else
{
if(configData->bGlobalSource)
MessageBox(hwnd, PluginStr("DeviceSelection.ExistsSomewhere"), NULL, 0);
else
MessageBox(hwnd, PluginStr("DeviceSelection.ExistsInScene"), NULL, 0);
}
break;
}
}
//------------------------------------------
BOOL bFlip = SendMessage(GetDlgItem(hwnd, IDC_FLIPIMAGE), BM_GETCHECK, 0, 0) == BST_CHECKED;
BOOL bFlipHorizontal = SendMessage(GetDlgItem(hwnd, IDC_FLIPIMAGEH), BM_GETCHECK, 0, 0) == BST_CHECKED;
BOOL bCustomResolution = SendMessage(GetDlgItem(hwnd, IDC_CUSTOMRESOLUTION), BM_GETCHECK, 0, 0) == BST_CHECKED;
BOOL bUsePointFiltering = SendMessage(GetDlgItem(hwnd, IDC_POINTFILTERING), BM_GETCHECK, 0, 0) == BST_CHECKED;
BOOL bPreserveSourceSize = SendMessage(GetDlgItem(hwnd, IDC_PRESERVESIZE), BM_GETCHECK, 0, 0) == BST_CHECKED;
int deintId = (int)SendMessage(GetDlgItem(hwnd, IDC_DEINTERLACELIST), CB_GETCURSEL, 0, 0);
deinterlacingConfig = deinterlacerConfigs[deintId];
bool tff = SendMessage(GetDlgItem(hwnd, IDC_TFF), BM_GETCHECK, 0, 0) == BST_CHECKED,
bff = SendMessage(GetDlgItem(hwnd, IDC_BFF), BM_GETCHECK, 0, 0) == BST_CHECKED;
deinterlacingConfig.fieldOrder = tff ? FIELD_ORDER_TFF : (bff ? FIELD_ORDER_BFF : FIELD_ORDER_NONE);
deinterlacingConfig.processor = SendMessage(GetDlgItem(hwnd, IDC_GPUDEINT), BM_GETCHECK, 0, 0) == BST_CHECKED ? DEINTERLACING_PROCESSOR_GPU : DEINTERLACING_PROCESSOR_CPU;
configData->data->SetString(TEXT("device"), strDevice);
configData->data->SetString(TEXT("deviceName"), configData->deviceNameList[deviceID]);
configData->data->SetString(TEXT("deviceID"), configData->deviceIDList[deviceID]);
configData->data->SetInt(TEXT("customResolution"), bCustomResolution);
configData->data->SetFloat(TEXT("scaleFactor_x"), (float)resolution.cx / configData->data->GetFloat(TEXT("resolutionWidth"), 1.0f));
configData->data->SetFloat(TEXT("scaleFactor_y"), (float)resolution.cy / configData->data->GetFloat(TEXT("resolutionHeight"), 1.0f));
configData->data->SetInt(TEXT("resolutionWidth"), resolution.cx);
configData->data->SetInt(TEXT("resolutionHeight"), resolution.cy);
configData->data->SetInt(TEXT("frameInterval"), UINT(frameInterval));
configData->data->SetInt(TEXT("flipImage"), bFlip);
configData->data->SetInt(TEXT("flipImageHorizontal"), bFlipHorizontal);
configData->data->SetInt(TEXT("usePointFiltering"), bUsePointFiltering);
configData->data->SetInt(TEXT("gamma"), (int)SendMessage(GetDlgItem(hwnd, IDC_GAMMA), TBM_GETPOS, 0, 0));
configData->data->SetInt(TEXT("preserveSourceSize"), bPreserveSourceSize);
configData->data->SetFloat(TEXT("scaleRatio"), (float)resolution.cx / configData->data->GetFloat(TEXT("resolutionWidth"), 1.0f));
configData->data->SetInt(TEXT("deinterlacingType"), deinterlacingConfig.type);
configData->data->SetInt(TEXT("deinterlacingFieldOrder"), deinterlacingConfig.fieldOrder);
configData->data->SetInt(TEXT("deinterlacingProcessor"), deinterlacingConfig.processor);
configData->data->SetInt(TEXT("deinterlacingDoublesFramerate"), deinterlacingConfig.doublesFramerate);
//------------------------------------------
BOOL bUDMError;
UINT opacity = (UINT)SendMessage(GetDlgItem(hwnd, IDC_OPACITY), UDM_GETPOS32, 0, (LPARAM)&bUDMError);
if(bUDMError) opacity = 100;
configData->data->SetInt(TEXT("opacity"), opacity);
//------------------------------------------
UINT preferredType = -1;
int id = (int)SendMessage(GetDlgItem(hwnd, IDC_PREFERREDOUTPUT), CB_GETCURSEL, 0, 0);
if(id != -1)
preferredType = (UINT)SendMessage(GetDlgItem(hwnd, IDC_PREFERREDOUTPUT), CB_GETITEMDATA, id, 0);
BOOL bUsePreferredType = preferredType != -1 && SendMessage(GetDlgItem(hwnd, IDC_USEPREFERREDOUTPUT), BM_GETCHECK, 0, 0) == BST_CHECKED;
configData->data->SetInt(TEXT("usePreferredType"), bUsePreferredType);
configData->data->SetInt(TEXT("preferredType"), preferredType);
bool bUseBuffering = SendMessage(GetDlgItem(hwnd, IDC_USEBUFFERING), BM_GETCHECK, 0, 0) == BST_CHECKED;
configData->data->SetInt(TEXT("useBuffering"), bUseBuffering);
DWORD bufferTime = (DWORD)SendMessage(GetDlgItem(hwnd, IDC_DELAY), UDM_GETPOS32, 0, 0);
configData->data->SetInt(TEXT("bufferTime"), bufferTime);
//------------------------------------------
int soundOutputType = 0;
UINT audioDeviceID = (UINT)SendMessage(GetDlgItem(hwnd, IDC_AUDIOLIST), CB_GETCURSEL, 0, 0);
if (audioDeviceID != CB_ERR) {
if (bAudioDevicesPresent) {
String strAudioDevice = GetCBText(GetDlgItem(hwnd, IDC_AUDIOLIST), audioDeviceID);
configData->data->SetString(TEXT("audioDevice"), strAudioDevice);
configData->data->SetString(TEXT("audioDeviceName"), configData->audioNameList[audioDeviceID]);
configData->data->SetString(TEXT("audioDeviceID"), configData->audioIDList[audioDeviceID]);
}
configData->data->SetInt(TEXT("forceCustomAudioDevice"), (!configData->bDeviceHasAudio || audioDeviceID > 1));
if(SendMessage(GetDlgItem(hwnd, IDC_OUTPUTSOUND), BM_GETCHECK, 0, 0) == BST_CHECKED)
soundOutputType = 1;
else if(SendMessage(GetDlgItem(hwnd, IDC_PLAYDESKTOPSOUND), BM_GETCHECK, 0, 0) == BST_CHECKED)
soundOutputType = 2;
}
configData->data->SetInt(TEXT("soundOutputType"), soundOutputType);
int soundTimeOffset = (int)SendMessage(GetDlgItem(hwnd, IDC_TIMEOFFSET), UDM_GETPOS32, 0, 0);
configData->data->SetInt(TEXT("soundTimeOffset"), soundTimeOffset);
float fVol = GetVolumeControlValue(GetDlgItem(hwnd, IDC_VOLUME));
configData->data->SetFloat(TEXT("volume"), fVol);
//------------------------------------------
BOOL bUseChromaKey = SendMessage(GetDlgItem(hwnd, IDC_USECHROMAKEY), BM_GETCHECK, 0, 0) == BST_CHECKED;
DWORD color = CCGetColor(GetDlgItem(hwnd, IDC_COLOR));
UINT keySimilarity = (UINT)SendMessage(GetDlgItem(hwnd, IDC_BASETHRESHOLD), UDM_GETPOS32, 0, (LPARAM)&bUDMError);
if(bUDMError) keySimilarity = 0;
UINT keyBlend = (UINT)SendMessage(GetDlgItem(hwnd, IDC_BLEND), UDM_GETPOS32, 0, (LPARAM)&bUDMError);
if(bUDMError) keyBlend = 10;
int keySpillReduction = (int)SendMessage(GetDlgItem(hwnd, IDC_SPILLREDUCTION), UDM_GETPOS32, 0, (LPARAM)&bUDMError);
if(bUDMError) keySpillReduction = 0;
configData->data->SetInt(TEXT("useChromaKey"), bUseChromaKey);
configData->data->SetInt(TEXT("keyColor"), color);
configData->data->SetInt(TEXT("keySimilarity"), keySimilarity);
configData->data->SetInt(TEXT("keyBlend"), keyBlend);
configData->data->SetInt(TEXT("keySpillReduction"), keySpillReduction);
}
case IDCANCEL:
if(LOWORD(wParam) == IDCANCEL)
{
ConfigDialogData *configData = (ConfigDialogData*)GetWindowLongPtr(hwnd, DWLP_USER);
ImageSource *source = API->GetSceneImageSource(configData->lpName);
if(source)
{
source->SetInt(TEXT("bufferTime"), configData->data->GetInt(TEXT("bufferTime"), 0));
source->SetInt(TEXT("timeOffset"), configData->data->GetInt(TEXT("soundTimeOffset"), 0));
source->SetFloat(TEXT("volume"), configData->data->GetFloat(TEXT("volume"), 1.0f));
source->SetInt(TEXT("flipImage"), configData->data->GetInt(TEXT("flipImage"), 0));
source->SetInt(TEXT("flipImageHorizontal"), configData->data->GetInt(TEXT("flipImageHorizontal"), 0));
source->SetInt(TEXT("usePointFiltering"), configData->data->GetInt(TEXT("usePointFiltering"), 0));
source->SetInt(TEXT("opacity"), configData->data->GetInt(TEXT("opacity"), 100));
source->SetInt(TEXT("useChromaKey"), configData->data->GetInt(TEXT("useChromaKey"), 0));
source->SetInt(TEXT("keyColor"), configData->data->GetInt(TEXT("keyColor"), 0xFFFFFFFF));
source->SetInt(TEXT("keySimilarity"), configData->data->GetInt(TEXT("keySimilarity"), 0));
source->SetInt(TEXT("keyBlend"), configData->data->GetInt(TEXT("keyBlend"), 80));
source->SetInt(TEXT("keySpillReduction"), configData->data->GetInt(TEXT("keySpillReduction"), 50));
source->SetInt(TEXT("gamma"), configData->data->GetInt(TEXT("gamma"), 100));
source->SetInt(TEXT("deinterlacingType"), configData->data->GetInt(TEXT("deinterlacingType"), 0));
source->SetInt(TEXT("deinterlacingFieldOrder"), configData->data->GetInt(TEXT("deinterlacingFieldOrder"), 0));
source->SetInt(TEXT("deinterlacingProcessor"), configData->data->GetInt(TEXT("deinterlacingProcessor"), 0));
source->SetInt(TEXT("deinterlacingDoublesFramerate"), configData->data->GetInt(TEXT("deinterlacingDoublesFramerate"), 0));
source->SetInt(TEXT("preserveSourceSize"), configData->data->GetInt(TEXT("preserveSourceSize"), 0));
}
}
EndDialog(hwnd, LOWORD(wParam));
}
}
return FALSE;
}
bool STDCALL ConfigureDShowSource(XElement *element, bool bCreating)
{
if(!element)
{
AppWarning(TEXT("ConfigureDShowSource: NULL element"));
return false;
}
XElement *data = element->GetElement(TEXT("data"));
if(!data)
data = element->CreateElement(TEXT("data"));
ConfigDialogData configData;
configData.lpName = element->GetName();
configData.data = data;
configData.bGlobalSource = (scmpi(element->GetParent()->GetName(), TEXT("global sources")) == 0);
configData.bCreating = bCreating;
if(DialogBoxParam(hinstMain, MAKEINTRESOURCE(IDD_CONFIG), API->GetMainWindow(), ConfigureDialogProc, (LPARAM)&configData) == IDOK)
{
bool bPreserveSourceSize = data->GetInt(TEXT("preserveSourceSize")) != 0;
float scaleFactor_x = 1.0f, scaleFactor_y = 1.0f;
if(bPreserveSourceSize) {
scaleFactor_x = data->GetFloat(TEXT("scaleFactor_x"), 1.0f);
scaleFactor_y = data->GetFloat(TEXT("scaleFactor_y"), 1.0f);
}
element->SetFloat(TEXT("cx"), data->GetFloat(TEXT("resolutionWidth")) / scaleFactor_x);
element->SetFloat(TEXT("cy"), data->GetFloat(TEXT("resolutionHeight")) / scaleFactor_y);
return true;
}
return false;
}
ImageSource* STDCALL CreateDShowSource(XElement *data)
{
DeviceSource *source = new DeviceSource;
if(!source->Init(data))
{
delete source;
return NULL;
}
return source;
}
bool LoadPlugin()
{
InitColorControl(hinstMain);
InitVolumeControl(hinstMain);
InitVolumeMeter(hinstMain);
pluginLocale = new LocaleStringLookup;
if(!pluginLocale->LoadStringFile(TEXT("plugins/DShowPlugin/locale/en.txt")))
AppWarning(TEXT("Could not open locale string file '%s'"), TEXT("plugins/DShowPlugin/locale/en.txt"));
if(scmpi(API->GetLanguage(), TEXT("en")) != 0)
{
String pluginStringFile;
pluginStringFile << TEXT("plugins/DShowPlugin/locale/") << API->GetLanguage() << TEXT(".txt");
if(!pluginLocale->LoadStringFile(pluginStringFile))
AppWarning(TEXT("Could not open locale string file '%s'"), pluginStringFile.Array());
}
API->RegisterImageSourceClass(DSHOW_CLASSNAME, PluginStr("ClassName"), (OBSCREATEPROC)CreateDShowSource, (OBSCONFIGPROC)ConfigureDShowSource);
return true;
}
void UnloadPlugin()
{
delete pluginLocale;
}
CTSTR GetPluginName()
{
return PluginStr("Plugin.Name");
}
CTSTR GetPluginDescription()
{
return PluginStr("Plugin.Description");
}
BOOL CALLBACK DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpBla)
{
if(dwReason == DLL_PROCESS_ATTACH)
hinstMain = hInst;
return TRUE;
}