Skip to content

Instantly share code, notes, and snippets.

@wrongbranch
Last active January 17, 2021 08:32
Show Gist options
  • Save wrongbranch/500a6853a810258f754ab4eac080e324 to your computer and use it in GitHub Desktop.
Save wrongbranch/500a6853a810258f754ab4eac080e324 to your computer and use it in GitHub Desktop.
test_DXSDK_Filter.cpp
/*
test_DXSDK_Filter.cpp
advapi32.lib for RegSetValueExW Reg[Enum|Open|Close|Create|Delete]KeyExW
oleaut32.lib for SysFreeString SysAllocString
legacy_stdio_definitions.lib for _vsnwprintf_s
headers from https://github.com/ganboing/sdk71examples
download and extract sdk71examples-master_ganboing_6779974_20150120.zip
copy sdk71examples-master/multimedia/directshow/baseclasses
to ./baseclasses
needs test_DXSDK_Filter.def (not use __declspec(dllexport))
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
------------------------------------------------------------------------
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe" -source-charset:utf-8 -execution-charset:utf-8 -EHsc -LD -Fetest_DXSDK_Filter.dll test_DXSDK_Filter.cpp -I. -I.\baseclasses -link /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib\x64" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x64" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x64" oleaut32.lib advapi32.lib kernel32.lib user32.lib gdi32.lib winmm.lib ole32.lib strmbase.lib strmiids.lib legacy_stdio_definitions.lib
compile OK but link error (const wchar_t *) etc
------------------------------------------------------------------------
"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x64"
strmiids.lib strmbase.lib Ole32.Lib WinMM.Lib
"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x86"
strmiids.lib strmbase.lib Ole32.Lib WinMM.Lib
strmbase.lib is ANSI version ? (can't link with -DUNICODE -D_UNICODE obj)
------------------------------------------------------------------------
can ReBuild strmbase.lib ? (after convert sln and vcproj) UNICODE (not MBCS)
baseclasses>msbuild baseclasses.sln /t:ReBuild /p:Configuration=Release /p:Platform=x64
baseclasses>msbuild baseclasses.sln /t:ReBuild /p:Configuration=Release /p:Platform=Win32
error MSB8036: Windows SDK version 8.1 not found
install Windows SDK version 8.1 or re-select target on project property
(not use MSBuild for strmbase.lib) (use cl and lib baseclasses/*.cpp -> OK)
------------------------------------------------------------------------
baseclasses>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe" -source-charset:utf-8 -execution-charset:utf-8 -EHsc -DUNICODE -D_UNICODE -c *.cpp -I.
amextra.cpp amfilter.cpp amvideo.cpp arithutil.cpp
combase.cpp cprop.cpp ctlutil.cpp ddmm.cpp dllentry.cpp dllsetup.cpp
mtype.cpp outputq.cpp perflog.cpp pstream.cpp pullpin.cpp
refclock.cpp renbase.cpp
schedule.cpp seekpt.cpp source.cpp strmctl.cpp sysclock.cpp
transfrm.cpp transip.cpp videoctl.cpp vtrans.cpp
winctrl.cpp winutil.cpp wxdebug.cpp wxlist.cpp wxutil.cpp
OK *.obj (for Release UNICODE x64)
baseclasses>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\lib.exe" -machine:x64 -out:..\strmbase_u_x64.lib *.obj
OK ..\strmbase_u_x64.lib 2021-01-11 17:12 1,461,356
"...\Hostx86\x86\cl.exe" ...
OK *.obj (for Release UNICODE x86)
"...\Hostx86\x86\lib.exe" -machine:x86 ...
OK ..\strmbase_u_x86.lib 2021-01-11 17:31 975,236
------------------------------------------------------------------------
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe" -source-charset:utf-8 -execution-charset:utf-8 -EHsc -LD -Fetest_DXSDK_Filter.dll test_DXSDK_Filter.cpp -I. -I.\baseclasses -link /DEF:test_DXSDK_Filter.def /LIBPATH:. /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib\x64" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x64" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x64" oleaut32.lib advapi32.lib kernel32.lib user32.lib gdi32.lib winmm.lib ole32.lib strmbase_u_x64.lib strmiids.lib legacy_stdio_definitions.lib
OK test_DXSDK_Filter.dll 2021-01-13 15:42 236,544
test_DXSDK_Filter.exp 2021-01-13 15:42 1,206
test_DXSDK_Filter.lib 2021-01-11 18:21 1,728
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx86\x86\cl.exe" -source-charset:utf-8 -execution-charset:utf-8 -EHsc -LD -Fetest_DXSDK_Filter_x86.dll test_DXSDK_Filter.cpp -I. -I.\baseclasses -link /MACHINE:x86 /DEF:test_DXSDK_Filter.def /LIBPATH:. /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib\x86" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x86" /LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x86" oleaut32.lib advapi32.lib kernel32.lib user32.lib gdi32.lib winmm.lib ole32.lib strmbase_u_x86.lib strmiids.lib legacy_stdio_definitions.lib
OK test_DXSDK_Filter_x86.dll 2021-01-13 15:42 189,440
test_DXSDK_Filter_x86.exp 2021-01-13 15:42 1,239
test_DXSDK_Filter_x86.lib 2021-01-11 18:22 1,768
------------------------------------------------------------------------
run as administrator
"C:\Windows\System32\regsvr32.exe" [/u] "<path>\test_DXSDK_Filter.dll"
"C:\Windows\SysWOW64\regsvr32.exe" [/u] "<path>\test_DXSDK_Filter_x86.dll"
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\graphedt.exe"
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\graphedt.exe"
DirectShow Filters DirectShow Filters
DXSDK_Filter Output -> connect -> Video Renderer VMR Input 0
https://stackoverflow.com/questions/33693131/how-to-create-virtual-webcam-in-windows-10
https://qiita.com/tomoki0sanaki/items/fec5cb057b9872c0664c
* https://qiita.com/HexagramNM/items/2311f025f3af758c83a0
* https://github.com/HexagramNM/NMVCamFilter
* https://github.com/syu5-gh/mysourcefilter
* https://github.com/aricatamoy/svcam
* https://blog.firefly-vj.net/2007/10/08/push-model-source-filter.html
* https://blog.firefly-vj.net/2008/05/11/directshow-filter-development-project-setting.html
* https://github.com/ganboing/sdk71examples
https://docs.microsoft.com/ja-jp/windows/win32/directshow/building-directshow-filters
https://docs.microsoft.com/en-us/windows/win32/directshow/implementing-dllregisterserver
https://community.osr.com/discussion/245023/virtual-camera-source-filter-directshow
https://level69.net/archives/26918
https://github.com/CatxFish/obs-virtual-cam
*/
#include "test_DXSDK_Filter.h"
#define LOGING_LEVEL 5
#define FILTER_NAME L"DXSDK_Filter"
#define OUTPUT_PIN_NAME L"OutPIN"
#if 0
#define CAM_WIDTH 640
#define CAM_HEIGHT 480
#define CAM_BITS 32
#else
#define CAM_WIDTH 640
#define CAM_HEIGHT 480
#define CAM_BITS 24
#endif
#define EWP_TITLE_DB "e:\\virtual\\camera_memo_utf-8.txt"
// {44585F5F-5344-4B5F-5F5F-46696C746572}
DEFINE_GUID(CLSID_MySrc,
0x44585F5F, 0x5344, 0x4B5F, 0x5F, 0x5F, 0x46, 0x69, 0x6C, 0x74, 0x65, 0x72);
const AMOVIESETUP_MEDIATYPE sudPinTypes[] = {{
#if CAM_BITS == 32
&MEDIATYPE_Video, &MEDIASUBTYPE_RGB32}};
#else
&MEDIATYPE_Video, &MEDIASUBTYPE_RGB24}};
#endif
const AMOVIESETUP_PIN sudPins[] = {{
OUTPUT_PIN_NAME, FALSE, TRUE, FALSE, FALSE,
&CLSID_NULL, NULL, 1, sudPinTypes}};
const AMOVIESETUP_FILTER afFilterInfo = {
&CLSID_MySrc, FILTER_NAME,
#if 0
MERIT_DO_NOT_USE,
#else
MERIT_NORMAL,
#endif
#if 0
0, NULL // nop filter
#else
1, sudPins // make out PINs
#endif
};
REGFILTER2 rf2FilterReg = {
1,
#if 0
MERIT_DO_NOT_USE,
#else
MERIT_NORMAL,
#endif
#if 0
0, NULL // nop filter
#else
1, sudPins // make out PINs
#endif
};
CFactoryTemplate g_Templates[] = {
{FILTER_NAME, &CLSID_MySrc, CMySrc::CreateInstance, NULL, &afFilterInfo}};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
STDAPI DllRegisterServer()
{
#if 0
return AMovieDllRegisterServer2(TRUE);
#else
HRESULT hr = AMovieDllRegisterServer2(TRUE);
if(FAILED(hr)) return hr;
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if(FAILED(hr)) return hr;
if(pFM2){
IMoniker *pMoniker = NULL;
hr = pFM2->RegisterFilter(CLSID_MySrc, FILTER_NAME, &pMoniker,
&CLSID_VideoInputDeviceCategory, FILTER_NAME, &rf2FilterReg);
pFM2->Release();
}
return hr;
#endif
}
STDAPI DllUnregisterServer()
{
#if 0
return AMovieDllRegisterServer2(FALSE);
#else
HRESULT hr = AMovieDllRegisterServer2(FALSE);
if(FAILED(hr)) return hr;
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if(FAILED(hr)) return hr;
if(pFM2){
hr = pFM2->UnregisterFilter(
&CLSID_VideoInputDeviceCategory, FILTER_NAME, CLSID_MySrc);
pFM2->Release();
}
return hr;
#endif
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
DbgSetModuleLevel(LOG_TRACE, LOGING_LEVEL);
// DbgSetModuleLevel(LOG_ERROR, LOGING_LEVEL);
return DllEntryPoint((HINSTANCE)hModule, dwReason, lpReserved);
}
BOOL EnumWndTitle(EWPParams *pewp, char *fn)
{
FILE *fp = fopen(fn, "rb");
if(fp){
char tmp[_countof(EWPParams::title) * 4];
fgets(tmp, sizeof(tmp), fp);
fclose(fp);
int l = strlen(tmp);
if(l > 0 && tmp[l - 1] == 0x0A){ tmp[l - 1] = '\0'; --l; }
#if 0
for(int i = 0; i < l; ++i) pewp->title[i] = (wchar_t)tmp[i];
if(l >= 0) pewp->title[l] = L'\0';
#else
int len = MultiByteToWideChar(CP_UTF8, 0, tmp, -1, NULL, 0);
MultiByteToWideChar(CP_UTF8, 0, tmp, -1, pewp->title, len); // -1 add L'\0'
// MB_PRECOMPOSED MB_COMPOSITE MB_ERR_INVALID_CHARS MB_USEGLYPHCHARS
// if(GetLastError() == ERROR_NO_UNICODE_TRANSLATION) ...
#endif
}
return TRUE;
}
BOOL CALLBACK EnumWndProc(HWND hWnd, LPARAM lp)
{
EWPParams *pewp = (EWPParams *)lp;
wchar_t buf[_countof(EWPParams::title)] = L"";
SendMessageTimeoutW(hWnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf,
SMTO_BLOCK, 100, NULL);
if(!wcsncmp(buf, pewp->title, wcslen(pewp->title))){
pewp->hWnd = hWnd;
return FALSE;
}
return TRUE;
}
CUnknown *WINAPI CMySrc::CreateInstance(IUnknown *pUnk, HRESULT *phr)
{
CMySrc *pNewFilter = new CMySrc(pUnk, phr);
if(!pNewFilter) *phr = E_OUTOFMEMORY;
return dynamic_cast<CUnknown *>(pNewFilter);
}
CMySrc::CMySrc(IUnknown *pUnk, HRESULT *phr) :
CSource(FILTER_NAME, pUnk, CLSID_MySrc)
{
CPushPin *pPin = new CPushPin(phr, this); // will be deleted by BaseClasses
if(!pPin) *phr = E_OUTOFMEMORY;
}
CMySrc::~CMySrc()
{
}
HRESULT CMySrc::QueryInterface(REFIID riid, void **ppv)
{
if(riid == _uuidof(IAMStreamConfig) || riid == _uuidof(IKsPropertySet))
return m_paStreams[0]->QueryInterface(riid, ppv);
else
return CSource::QueryInterface(riid, ppv);
}
CPushPin::CPushPin(HRESULT *phr, CMySrc *pFilter) :
CSourceStream(NAME("CPushPin"), phr, pFilter, OUTPUT_PIN_NAME),
m_pFilter(pFilter), m_Count(0), m_rtFrameLength(666666), // 100 nanosec 15fps
m_BmpData(NULL), m_Bitmap(NULL), m_Hdc(NULL)
{
GetMediaType(&m_mt);
}
CPushPin::~CPushPin()
{
Dispose();
}
void CPushPin::Dispose()
{
if(m_Bitmap){ DeleteObject(m_Bitmap); m_Bitmap = NULL; }
if(m_Hdc){ DeleteDC(m_Hdc); m_Hdc = NULL; }
if(m_BmpData){ delete m_BmpData; m_BmpData = NULL; }
}
BITMAPINFOHEADER *CPushPin::PreSetupHDCandBMI(VIDEOINFO *pvi, BOOL flg)
{
Dispose();
BITMAPINFOHEADER *pBmi = &(pvi->bmiHeader);
if(flg){
pBmi->biSize = sizeof(BITMAPINFOHEADER);
pBmi->biWidth = CAM_WIDTH;
pBmi->biHeight = CAM_HEIGHT;
pBmi->biPlanes = 1;
pBmi->biBitCount = CAM_BITS;
pBmi->biCompression = BI_RGB;
pBmi->biSizeImage = DIBSIZE(pvi->bmiHeader);
// biXPelsPerMeter, biYPelsPerMeter, biClrUsed
pBmi->biClrImportant = 0;
}
return pBmi;
}
HRESULT CPushPin::SetupHDCandBMI(BITMAPINFOHEADER *pBmi, size_t sz)
{
m_BmpData = new DWORD[pBmi->biWidth * pBmi->biHeight];
memset(m_BmpData, 0, sz);
HDC dwhdc = GetDC(GetDesktopWindow());
m_Bitmap = CreateDIBitmap(dwhdc, pBmi, CBM_INIT, m_BmpData, (BITMAPINFO *)pBmi, DIB_RGB_COLORS);
m_Hdc = CreateCompatibleDC(dwhdc);
SelectObject(m_Hdc, m_Bitmap);
ReleaseDC(GetDesktopWindow(), dwhdc);
return NOERROR;
}
HRESULT CPushPin::CompleteConnect(IPin *pReceivePin)
{
VIDEOINFO *pvi = (VIDEOINFO *)m_mt.Format();
BITMAPINFOHEADER *pBmi = PreSetupHDCandBMI(pvi, FALSE);
SetupHDCandBMI(pBmi, m_mt.GetSampleSize());
return __super::CompleteConnect(pReceivePin);
}
STDMETHODIMP CPushPin::Disconnect()
{
Dispose();
return __super::Disconnect();
}
STDMETHODIMP CPushPin::Notify(IBaseFilter *pSelf, Quality q)
{
#if 1
return E_FAIL;
#else
return E_NOTIMPL;
#endif
}
HRESULT CPushPin::GetMediaType(CMediaType *pMediaType)
{
VIDEOINFO *pvi = (VIDEOINFO *)pMediaType->AllocFormatBuffer(sizeof(VIDEOINFO));
ZeroMemory(pvi, sizeof(VIDEOINFO));
pvi->AvgTimePerFrame = m_rtFrameLength;
// call before use pvi->bmiHeader after ZeroMemory
BITMAPINFOHEADER *pBmi = PreSetupHDCandBMI(pvi, TRUE);
SetRectEmpty(&(pvi->rcSource));
SetRectEmpty(&(pvi->rcTarget));
pMediaType->SetType(&MEDIATYPE_Video);
pMediaType->SetFormatType(&FORMAT_VideoInfo);
const GUID subtype = GetBitmapSubtype(&pvi->bmiHeader);
pMediaType->SetSubtype(&subtype);
pMediaType->SetTemporalCompression(FALSE);
pMediaType->SetSampleSize(DIBSIZE(*pBmi));
SetupHDCandBMI(pBmi, pMediaType->GetSampleSize());
return S_OK;
}
HRESULT CPushPin::CheckMediaType(const CMediaType *pMediaType)
{
HRESULT hr = S_OK;
CheckPointer(pMediaType, E_POINTER);
CMediaType mt;
GetMediaType(&mt);
if(mt != *pMediaType) hr = E_FAIL;
FreeMediaType(mt);
return hr;
}
HRESULT CPushPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest)
{
#if 1
VIDEOINFO *pvi = reinterpret_cast<VIDEOINFO *>(m_mt.Format());
#else
VIDEOINFO *pvi = (VIDEOINFO *)m_mt.Format();
#endif
ASSERT(pvi != NULL);
pRequest->cBuffers = 1;
if(pvi->bmiHeader.biSizeImage > (DWORD)pRequest->cbBuffer)
pRequest->cbBuffer = pvi->bmiHeader.biSizeImage;
ALLOCATOR_PROPERTIES Actual;
HRESULT hr = pAlloc->SetProperties(pRequest, &Actual);
if(FAILED(hr)) return hr;
if(Actual.cbBuffer < pRequest->cbBuffer) return E_FAIL;
return S_OK;
}
HRESULT CPushPin::FillBuffer(IMediaSample *pSample)
{
CheckPointer(pSample, E_POINTER);
// check format changed by downstreamfilter
ASSERT(m_mt.formattype == FORMAT_VideoInfo);
ASSERT(m_mt.cbFormat >= sizeof(VIDEOINFOHEADER));
LPBYTE pSampleData = NULL;
const long size = pSample->GetSize();
pSample->GetPointer(&pSampleData);
CRefTime ref;
m_pFilter->StreamTime(ref);
PatBlt(m_Hdc, 0, 0, CAM_WIDTH, CAM_HEIGHT, BLACKNESS);
HFONT fnt = CreateFont(44, 0, 3570, 3570, FW_BOLD, TRUE, TRUE, FALSE,
SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, VARIABLE_PITCH | FF_ROMAN , L"Migu 1M");
SelectObject(m_Hdc, fnt);
TCHAR buf[_countof(EWPParams::title)];
#if 1
IReferenceClock *clock;
m_pFilter->GetSyncSource(&clock);
REFERENCE_TIME stime;
clock->GetTime(&stime);
#endif
#if 1
EWPParams ewp = {NULL, L""};
EnumWndTitle(&ewp, EWP_TITLE_DB);
EnumWindows(EnumWndProc, (LPARAM)&ewp);
if(ewp.hWnd){
HDC wDC = GetDC(ewp.hWnd);
BitBlt(m_Hdc, 0, 0, CAM_WIDTH, CAM_HEIGHT, wDC, 0, 0, SRCCOPY);
ReleaseDC(ewp.hWnd, wDC);
}
_snwprintf_s(buf, _countof(buf), _TRUNCATE, TEXT("%s"), ewp.title);
#else
_snwprintf_s(buf, _countof(buf), _TRUNCATE, TEXT("%08x"), ref.Millisecs());
#endif
TextOut(m_Hdc, 0, 0, buf, lstrlen(buf));
#if 1
clock->Release();
#endif
SelectObject(m_Hdc, GetStockObject(SYSTEM_FONT));
DeleteObject(fnt);
VIDEOINFO *pvi = (VIDEOINFO *)m_mt.Format();
GetDIBits(m_Hdc, m_Bitmap, 0, CAM_HEIGHT,
pSampleData, (BITMAPINFO *)&pvi->bmiHeader, DIB_RGB_COLORS);
const REFERENCE_TIME delta = m_rtFrameLength;
REFERENCE_TIME start_time = ref;
FILTER_STATE state;
m_pFilter->GetState(0, &state);
if(state == State_Paused) start_time = 0;
REFERENCE_TIME end_time = start_time + delta;
pSample->SetTime(&start_time, &end_time);
pSample->SetActualDataLength(size);
pSample->SetSyncPoint(TRUE); // TRUE: key frame, FALSE: delta frame
// Sleep(CRefTime(m_rtFrameLength).Millisecs()); // wait
#if 1
++m_Count;
#endif
return S_OK;
}
HRESULT CPushPin::QueryInterface(REFIID riid, LPVOID *ppvObj)
{
if(riid == _uuidof(IAMStreamConfig)) *ppvObj = (IAMStreamConfig *)this;
else if(riid == _uuidof(IKsPropertySet)) *ppvObj = (IKsPropertySet *)this;
else return CSourceStream::QueryInterface(riid, ppvObj);
AddRef();
return S_OK;
}
ULONG CPushPin::AddRef()
{
return GetOwner()->AddRef();
}
ULONG CPushPin::Release()
{
return GetOwner()->Release();
}
HRESULT CPushPin::Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG *BytesReturned)
{
if(PropSet != AMPROPSETID_Pin) return E_PROP_SET_UNSUPPORTED;
if(Id != AMPROPERTY_PIN_CATEGORY) return E_PROP_ID_UNSUPPORTED;
if(PropertyData == NULL && BytesReturned == NULL) return E_POINTER;
if(BytesReturned) *BytesReturned = sizeof(GUID);
if(PropertyData == NULL) return S_OK; // Caller just wants to know the size.
if(DataLength < sizeof(GUID)) return E_UNEXPECTED; // The buffer is too small.
*(GUID *)PropertyData = PIN_CATEGORY_CAPTURE;
return S_OK;
}
HRESULT CPushPin::Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength)
{
return E_NOTIMPL;
}
HRESULT CPushPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG *TypeSupport)
{
if(PropSet != AMPROPSETID_Pin) return E_PROP_SET_UNSUPPORTED;
if(Id != AMPROPERTY_PIN_CATEGORY) return E_PROP_ID_UNSUPPORTED;
// We support getting this property, but not setting it.
if(TypeSupport) *TypeSupport = KSPROPERTY_SUPPORT_GET;
return S_OK;
}
HRESULT CPushPin::GetFormat(AM_MEDIA_TYPE **ppmt)
{
*ppmt = CreateMediaType(&m_mt);
return S_OK;
}
HRESULT CPushPin::GetNumberOfCapabilities(int *piCount, int *piSize)
{
*piCount = 1;
*piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS);
return S_OK;
}
HRESULT CPushPin::GetStreamCaps(int iIndex, AM_MEDIA_TYPE **ppmt, BYTE *pSCC)
{
*ppmt = CreateMediaType(&m_mt);
VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)(*ppmt)->pbFormat;
BITMAPINFOHEADER *pBmi = &(pvi->bmiHeader);
pBmi->biSize = sizeof(BITMAPINFOHEADER);
pBmi->biWidth = CAM_WIDTH;
pBmi->biHeight = CAM_HEIGHT;
pBmi->biPlanes = 1;
pBmi->biBitCount = CAM_BITS;
pBmi->biCompression = BI_RGB;
pBmi->biSizeImage = GetBitmapSize(&pvi->bmiHeader);
// biXPelsPerMeter, biYPelsPerMeter, biClrUsed
pBmi->biClrImportant = 0;
SetRectEmpty(&(pvi->rcSource));
SetRectEmpty(&(pvi->rcTarget));
(*ppmt)->majortype = (const GUID)(*sudPinTypes[0].clsMajorType);
(*ppmt)->subtype = (const GUID)(*sudPinTypes[0].clsMinorType);
(*ppmt)->formattype = FORMAT_VideoInfo;
(*ppmt)->bTemporalCompression = FALSE;
(*ppmt)->bFixedSizeSamples = TRUE;
(*ppmt)->lSampleSize = pBmi->biSizeImage;
(*ppmt)->cbFormat = sizeof(VIDEOINFOHEADER);
VIDEO_STREAM_CONFIG_CAPS *pvscc = (VIDEO_STREAM_CONFIG_CAPS *)pSCC;
pvscc->guid = FORMAT_VideoInfo;
pvscc->VideoStandard = AnalogVideo_None;
pvscc->InputSize.cx = CAM_WIDTH;
pvscc->InputSize.cy = CAM_HEIGHT;
pvscc->MinCroppingSize.cx = CAM_WIDTH;
pvscc->MinCroppingSize.cy = CAM_HEIGHT;
pvscc->MaxCroppingSize.cx = CAM_WIDTH;
pvscc->MaxCroppingSize.cy = CAM_HEIGHT;
pvscc->CropGranularityX = 80;
pvscc->CropGranularityY = 60;
pvscc->CropAlignX = 0;
pvscc->CropAlignY = 0;
pvscc->MinOutputSize.cx = CAM_WIDTH;
pvscc->MinOutputSize.cy = CAM_HEIGHT;
pvscc->MaxOutputSize.cx = CAM_WIDTH;
pvscc->MaxOutputSize.cy = CAM_HEIGHT;
pvscc->OutputGranularityX = 0;
pvscc->OutputGranularityY = 0;
pvscc->StretchTapsX = 0;
pvscc->StretchTapsY = 0;
pvscc->ShrinkTapsX = 0;
pvscc->ShrinkTapsY = 0;
pvscc->MinFrameInterval = 200000; // 50fps
pvscc->MaxFrameInterval = 50000000; // 0.2fps
pvscc->MinBitsPerSecond = (CAM_WIDTH * CAM_HEIGHT * CAM_BITS) / 5;
pvscc->MaxBitsPerSecond = (CAM_WIDTH * CAM_HEIGHT * CAM_BITS) * 50;
return S_OK;
}
HRESULT CPushPin::SetFormat(AM_MEDIA_TYPE *pmt)
{
VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)m_mt.pbFormat;
m_mt = *pmt;
IPin *pin;
ConnectedTo(&pin);
if(pin){
IFilterGraph *pGraph = m_pFilter->GetGraph();
pGraph->Reconnect(this);
}
return S_OK;
}
ULONG CPushPin::GetMiscFlags()
{
return AM_FILTER_MISC_FLAGS_IS_SOURCE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment