rendered paste body#include "StdAfx.h"
#include "SmartCamFilter.h"
// COM global table of objects in this dll
CFactoryTemplate g_Templates[] = {
{
SMART_CAM_FILTER_NAME,
&CLSID_SmartCam,
CSmartCamFilter::CreateInstance,
NULL,
NULL
}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
// DllEntryPoint
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
LPVOID lpReserved)
{
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}
// Exported entry points for registration and unregistration
STDAPI DllRegisterServer()
{
REGPINTYPES pinMediaTypes[] = {
{ &MEDIATYPE_Video, &MEDIASUBTYPE_RGB24 }
};
REGFILTERPINS2 pinRegInfo = {
REG_PINFLAG_B_OUTPUT, // dwFlags
1, // cInstances
1, // nMediaTypes
pinMediaTypes, // lpMediaType
0, // nMediums
NULL, // lpMedium
&PIN_CATEGORY_CAPTURE // clsPinCategory
};
REGFILTER2 filterRegInfo = {
2, // Version 2 (pin mediums or pin category).
MERIT_NORMAL, // Merit.
{
1, // Number of pins.
(const REGFILTERPINS *)&pinRegInfo // Pointer to pin information.
}
};
HRESULT hr;
IFilterMapper2 *pFM2 = NULL;
hr = AMovieDllRegisterServer2(TRUE);
if (FAILED(hr))
return hr;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (FAILED(hr))
return hr;
hr = pFM2->RegisterFilter(
CLSID_SmartCam, // Filter CLSID.
SMART_CAM_FILTER_NAME, // Filter name.
NULL, // Device moniker.
&CLSID_VideoInputDeviceCategory, // Video capture category.
SMART_CAM_FILTER_NAME, // Instance data.
&filterRegInfo); // Pointer to filter information.
pFM2->Release();
return hr;
}
STDAPI DllUnregisterServer()
{
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 (SUCCEEDED(hr))
{
hr = pFM2->UnregisterFilter(&CLSID_VideoInputDeviceCategory,
SMART_CAM_FILTER_NAME, CLSID_SmartCam);
pFM2->Release();
}
return hr;
}
//
// ------------------ CSmartCamFilter ------------------
//
CUnknown * WINAPI CSmartCamFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
{
ASSERT(phr);
CUnknown *punk = new CSmartCamFilter(lpunk, phr);
if(punk == NULL)
{
if(phr)
*phr = E_OUTOFMEMORY;
}
return punk;
}
STDMETHODIMP CSmartCamFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_ISmartCamWriter)
{
return GetInterface(static_cast<ISmartCamWriter*>(this), ppv);
}
return CSource::NonDelegatingQueryInterface(riid,ppv);
}
CSmartCamFilter::CSmartCamFilter(LPUNKNOWN lpunk, HRESULT *phr)
:CSource(NAME("SMARTCAM"), lpunk, CLSID_SmartCam)
{
DbgOutString("CSmartCamFilter()\n");
ASSERT(phr);
CAutoLock cAutoLock(&m_cStateLock);
m_paStreams = (CSourceStream **) new CSmartCamCapturePin*[1];
if(m_paStreams == NULL)
{
if(phr)
*phr = E_OUTOFMEMORY;
return;
}
m_paStreams[0] = new CSmartCamCapturePin(phr, this, SMART_CAM_CAPTURE_PIN_NAME);
if(m_paStreams[0] == NULL)
{
if(phr)
*phr = E_OUTOFMEMORY;
}
}
// ISmartCamWriter methods
STDMETHODIMP CSmartCamFilter::WriteFrame(char* frameBuffer, int size)
{
return NOERROR;
}
STDMETHODIMP CSmartCamFilter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *State)
{
switch(m_State)
{
case State_Stopped:
{
DbgOutString("CSmartCamFilter::GetState() [crtState = State_Stopped]\n");
break;
}
case State_Paused:
{
DbgOutString("CSmartCamFilter::GetState() [crtState = State_Paused]\n");
break;
}
case State_Running:
{
DbgOutString("CSmartCamFilter::GetState() [crtState = State_Running]\n");
break;
}
}
CheckPointer(State, E_POINTER);
*State = m_State;
if (m_State == State_Paused)
return VFW_S_CANT_CUE;
else
return S_OK;
}
STDMETHODIMP CSmartCamFilter::SetSyncSource(IReferenceClock* pClock)
{
DbgOutString("SetSyncSource()\n");
return CBaseFilter::SetSyncSource(pClock);
}
CSmartCamFilter::~CSmartCamFilter(void)
{
DbgOutString("~CSmartCamFilter()\n");
}
//
// ------------------ CSmartCamCapturePin ------------------
//
CSmartCamCapturePin::CSmartCamCapturePin(HRESULT *phr, CSmartCamFilter *pParent, LPCWSTR pPinName):
CSourceStream(NAME("SMARTCAM_CAPTURE_PIN"), phr, pParent, pPinName),
hFileMapping(NULL),
pSharedMem(NULL),
//hNewFrameEvt(NULL),
isMaster(FALSE),
frameNumber(0),
sampleTime((LONG) 0)
{
DbgOutString("CSmartCamCapturePin()\n");
Initialize();
}
CSmartCamCapturePin::~CSmartCamCapturePin()
{
DbgOutString("~CSmartCamCapturePin()\n");
Cleanup();
}
STDMETHODIMP CSmartCamCapturePin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IAMPushSource)
{
return GetInterface(static_cast<IAMPushSource*>(this), ppv);
}
if(riid == IID_IAMStreamConfig)
{
return GetInterface(static_cast<IAMStreamConfig*>(this), ppv);
}
if(riid == IID_IKsPropertySet)
{
return GetInterface(static_cast<IKsPropertySet*>(this), ppv);
}
return CSourceStream::NonDelegatingQueryInterface(riid, ppv);
}
// IAMStreamConfig methods
STDMETHODIMP CSmartCamCapturePin::GetFormat(AM_MEDIA_TYPE **ppmt)
{
DbgOutString("CSmartCamCapturePin::GetFormat()\n");
VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
*pVih = SmartCamVideoInfoHeader;
AM_MEDIA_TYPE * pmt = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
*pmt = SmartCamMediaType;
pmt->pbFormat = (BYTE*) pVih;
pmt->cbFormat = sizeof(VIDEOINFOHEADER);
*ppmt = pmt;
return NOERROR;
}
STDMETHODIMP CSmartCamCapturePin::GetNumberOfCapabilities(int *piCount, int *piSize)
{
DbgOutString("CSmartCamCapturePin::GetNumberOfCapabilities()\n");
*piCount = 1;
*piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS);
return NOERROR;
}
STDMETHODIMP CSmartCamCapturePin::GetStreamCaps(int iIndex, AM_MEDIA_TYPE **ppmt, BYTE *pSCC)
{
DbgOutString("CSmartCamCapturePin::GetStreamCaps()\n");
if(iIndex < 0)
return E_INVALIDARG;
if(iIndex > 0)
return S_FALSE;
if(pSCC == NULL)
return E_POINTER;
VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
*pVih = SmartCamVideoInfoHeader;
AM_MEDIA_TYPE * pmt = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
*pmt = SmartCamMediaType;
pmt->pbFormat = (BYTE*) pVih;
pmt->cbFormat = sizeof(VIDEOINFOHEADER);
*ppmt = pmt;
VIDEO_STREAM_CONFIG_CAPS* pVidCap = (VIDEO_STREAM_CONFIG_CAPS*) pSCC;
*pVidCap = SmartCamVideoCfgCaps;
return S_OK;
}
STDMETHODIMP CSmartCamCapturePin::SetFormat(AM_MEDIA_TYPE *pmt)
{
DbgOutString("CSmartCamCapturePin::SetFormat()\n");
CAutoLock cAutoLock(m_pFilter->pStateLock());
if(pmt == NULL)
return E_POINTER;
// Pass the call up to the base class
CMediaType MediaType = *pmt;
return CSourceStream::SetMediaType(&MediaType);
}
// IKsPropertySet methods
STDMETHODIMP CSmartCamCapturePin::Set(
REFGUID guidPropSet,
DWORD dwPropID,
LPVOID pInstanceData,
DWORD cbInstanceData,
LPVOID pPropData,
DWORD cbPropData
)
{
DbgOutString("CSmartCamCapturePin::Set()\n");
return E_NOTIMPL;
}
STDMETHODIMP CSmartCamCapturePin::Get(
REFGUID guidPropSet,
DWORD dwPropID,
LPVOID pInstanceData,
DWORD cbInstanceData,
LPVOID pPropData,
DWORD cbPropData,
DWORD *pcbReturned
)
{
DbgOutString("CSmartCamCapturePin::Get()\n");
if (guidPropSet != AMPROPSETID_Pin)
return E_PROP_SET_UNSUPPORTED;
if (dwPropID != AMPROPERTY_PIN_CATEGORY)
return E_PROP_ID_UNSUPPORTED;
if (pPropData == NULL && pcbReturned == NULL)
return E_POINTER;
if (pcbReturned)
*pcbReturned = sizeof(GUID);
if (pPropData == NULL) // Caller just wants to know the size.
{
DbgOutString("CSmartCamCapturePin::Get() [ (SIZE QUERY) OK !!! ]\n");
return S_OK;
}
if (cbPropData < sizeof(GUID)) // The buffer is too small.
return E_UNEXPECTED;
*(GUID *)pPropData = PIN_CATEGORY_CAPTURE;
DbgOutString("CSmartCamCapturePin::Get() [ OK !!! ]\n");
return S_OK;
}
STDMETHODIMP CSmartCamCapturePin::QuerySupported(
REFGUID guidPropSet,
DWORD dwPropID,
DWORD *pTypeSupport
)
{
DbgOutString("CSmartCamCapturePin::QuerySupported()\n");
if (guidPropSet != AMPROPSETID_Pin)
return E_PROP_SET_UNSUPPORTED;
if (dwPropID != AMPROPERTY_PIN_CATEGORY)
return E_PROP_ID_UNSUPPORTED;
if (pTypeSupport)
// We support getting this property, but not setting it.
*pTypeSupport = KSPROPERTY_SUPPORT_GET;
return S_OK;
}
// IAMPushSource
STDMETHODIMP CSmartCamCapturePin::GetMaxStreamOffset(REFERENCE_TIME *prtMaxOffset)
{
DbgOutString("CSmartCamCapturePin::GetMaxStreamOffset()\n");
return E_NOTIMPL;
}
STDMETHODIMP CSmartCamCapturePin::GetPushSourceFlags(ULONG *pFlags)
{
DbgOutString("CSmartCamCapturePin::GetPushSourceFlags()\n");
*pFlags = AM_PUSHSOURCECAPS_INTERNAL_RM;
return E_NOTIMPL;
}
STDMETHODIMP CSmartCamCapturePin::GetStreamOffset(REFERENCE_TIME *prtOffset)
{
DbgOutString("CSmartCamCapturePin::GetStreamOffset()\n");
return E_NOTIMPL;
}
STDMETHODIMP CSmartCamCapturePin::SetMaxStreamOffset(REFERENCE_TIME rtMaxOffset)
{
DbgOutString("CSmartCamCapturePin::SetMaxStreamOffset()\n");
return E_NOTIMPL;
}
STDMETHODIMP CSmartCamCapturePin::SetPushSourceFlags(ULONG Flags)
{
DbgOutString("CSmartCamCapturePin::SetPushSourceFlags()\n");
return E_NOTIMPL;
}
STDMETHODIMP CSmartCamCapturePin::SetStreamOffset(REFERENCE_TIME rtOffset)
{
DbgOutString("CSmartCamCapturePin::SetStreamOffset()\n");
return E_NOTIMPL;
}
STDMETHODIMP CSmartCamCapturePin::GetLatency(REFERENCE_TIME *prtLatency)
{
DbgOutString("CSmartCamCapturePin::GetLatency()\n");
return E_NOTIMPL;
}
// CBasePin methods
HRESULT CSmartCamCapturePin::SetMediaType(const CMediaType *pMediaType)
{
DbgOutString("CSmartCamCapturePin::SetMediaType()\n");
CAutoLock cAutoLock(m_pFilter->pStateLock());
// Pass the call up to the base class
return CSourceStream::SetMediaType(pMediaType);
}
HRESULT CSmartCamCapturePin::GetMediaType(int iPosition, CMediaType* pMediaType)
{
DbgLog((LOG_ERROR, 0, TEXT("CSmartCamCapturePin::GetMediaType( iPosition = %d )\n"), iPosition));
CheckPointer(pMediaType,E_POINTER);
CAutoLock cAutoLock(m_pFilter->pStateLock());
if(iPosition < 0)
{
return E_INVALIDARG;
}
// Have we run off the end of types?
if(iPosition > 0)
{
return VFW_S_NO_MORE_ITEMS;
}
*pMediaType = SmartCamMediaType;
VIDEOINFOHEADER* pVih =
(VIDEOINFOHEADER*) pMediaType->AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
if(pVih == NULL)
{
DbgOutString("CSmartCamCapturePin::GetMediaType(iPosition) - Format allocation failed !\n");
return(E_OUTOFMEMORY);
}
*pVih = SmartCamVideoInfoHeader;
DbgOutString("CSmartCamCapturePin::GetMediaType(iPosition) - OK! -\n");
return NOERROR;
}
HRESULT CSmartCamCapturePin::GetMediaType(CMediaType *pMediaType)
{
DbgOutString("CSmartCamCapturePin::GetMediaType()\n");
return GetMediaType(0, pMediaType);
}
HRESULT CSmartCamCapturePin::CheckMediaType(const CMediaType *pMediaType)
{
DbgOutString("CSmartCamCapturePin::CheckMediaType()\n");
CheckPointer(pMediaType,E_POINTER);
const GUID* Type = pMediaType->Type();
if (Type == NULL)
return E_INVALIDARG;
if((*Type != MEDIATYPE_Video) || // we only output video
!(pMediaType->IsFixedSize())) // in fixed size samples
{
return E_INVALIDARG;
}
// Check for the RGB24 subtype we support
const GUID* SubType = pMediaType->Subtype();
if (SubType == NULL)
return E_INVALIDARG;
if(*SubType != MEDIASUBTYPE_RGB24)
{
return E_INVALIDARG;
}
// Get the format area of the media type
VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) pMediaType->Format();
if(pVih == NULL)
return E_INVALIDARG;
// Check the image size
if((pVih->bmiHeader.biWidth > FRAME_WIDTH) || (abs(pVih->bmiHeader.biHeight) > FRAME_HEIGHT) ||
(pVih->bmiHeader.biSizeImage != GetBitmapSize(&pVih->bmiHeader)))
{
return E_INVALIDARG;
}
// Check the color depth and compression
if((pVih->bmiHeader.biBitCount != 24) || (pVih->bmiHeader.biCompression != BI_RGB))
{
return E_INVALIDARG;
}
DbgOutString("CSmartCamCapturePin::CheckMediaType() - OK! -\n");
return S_OK; // This format is acceptable.
}
HRESULT CSmartCamCapturePin::FillBuffer(IMediaSample *pMediaSample)
{
DbgOutString("CSmartCamCapturePin::FillBuffer()\n");
CAutoLock cAutoLock(m_pFilter->pStateLock());
CheckPointer(pMediaSample, E_POINTER);
DWORD crtFrameNumber = *((DWORD*) pSharedMem);
if(crtFrameNumber == SC_END_OF_STREAM)
return S_FALSE;
BYTE* pData = NULL;
pMediaSample->GetPointer(&pData);
long lDataLen = pMediaSample->GetSize();
BYTE* pSharedFrame = (BYTE*) pSharedMem + FRAME_NUMBER_SIZE;
RtlCopyMemory(pData, pSharedFrame, lDataLen);
CRefTime rtStart = sampleTime;
sampleTime += CRefTime(MILLISECONDS_TO_100NS_UNITS(AVG_FRAME_TIME_MS));
pMediaSample->SetTime((REFERENCE_TIME *)&rtStart, (REFERENCE_TIME *)&sampleTime);
Sleep(AVG_FRAME_TIME_MS);
return S_OK;
}
HRESULT CSmartCamCapturePin::DecideBufferSize(
IMemAllocator *pIMemAlloc,
ALLOCATOR_PROPERTIES *pProperties)
{
DbgOutString("CSmartCamCapturePin::DecideBufferSize()\n");
CheckPointer(pIMemAlloc, E_POINTER);
CheckPointer(pProperties, E_POINTER);
CAutoLock cAutoLock(m_pFilter->pStateLock());
HRESULT hr = NOERROR;
VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) m_mt.Format();
pProperties->cBuffers = 1;
pProperties->cbBuffer = pVih->bmiHeader.biSizeImage;
ASSERT(pProperties->cbBuffer);
// Ask the allocator to reserve us some sample memory, NOTE the function
// can succeed (that is return NOERROR) but still not have allocated the
// memory that we requested, so we must check we got whatever we wanted
ALLOCATOR_PROPERTIES Actual;
hr = pIMemAlloc->SetProperties(pProperties,&Actual);
if(FAILED(hr))
{
return hr;
}
// Is this allocator unsuitable
if(Actual.cbBuffer < pProperties->cbBuffer)
{
return E_FAIL;
}
// Make sure that we have only 1 buffer (we erase the ball in the
// old buffer to save having to zero a 200k+ buffer every time
// we draw a frame)
ASSERT(Actual.cBuffers == 1);
DbgOutString("CSmartCamCapturePin::DecideBufferSize() - OK! -\n");
return NOERROR;
}
HRESULT CSmartCamCapturePin::OnThreadCreate()
{
DbgOutString("CSmartCamCapturePin::OnThreadCreate()\n");
return CSourceStream::OnThreadCreate();
}
HRESULT CSmartCamCapturePin::OnThreadDestroy()
{
DbgOutString("CSmartCamCapturePin::OnThreadDestroy()\n");
return NOERROR;
}
STDMETHODIMP CSmartCamCapturePin::Notify(IBaseFilter * pSelf , Quality q)
{
return E_NOTIMPL;
//return CSourceStream::Notify(pSelf, q);
}
STDMETHODIMP CSmartCamCapturePin::SetSink(IQualityControl * piqc)
{
return E_NOTIMPL;
//return CSourceStream::SetSink(piqc);
}
HRESULT CSmartCamCapturePin::Initialize()
{
Util::CreateSharedMem(&hFileMapping, &pSharedMem);
//Util::CreateOpenNewFrameEvt(&hNewFrameEvt);
char procFullFileName[MAX_PROC_FILE_NAME], dllFullFileName[MAX_PROC_FILE_NAME];
GetModuleFileName(GetModuleHandle(SMART_CAM_FILTER_FILE_NAME), dllFullFileName, MAX_PROC_FILE_NAME);
GetModuleFileName(NULL, procFullFileName, MAX_PROC_FILE_NAME);
string installDir, procDir, procFileName;
Util::ParseFileName(dllFullFileName, &installDir, NULL);
Util::ParseFileName(procFullFileName, &procDir, &procFileName);
isMaster = (procDir == installDir) && (procFileName == MASTER_APP_FILE_NAME);
if(!isMaster)
{
HWND hMasterWnd = FindWindow(SMARTCAM_CLASSNAME, SMARTCAM_CAPTION);
if(hMasterWnd == NULL)
{
string masterAppFullFileName = installDir + MASTER_APP_FILE_NAME;
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_MINIMIZE;
PROCESS_INFORMATION pi;
CreateProcess(masterAppFullFileName.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
}
}
return S_OK;
}
void CSmartCamCapturePin::Cleanup()
{
// Close the shared memory
// Unmap shared memory from the process's address space.
UnmapViewOfFile(pSharedMem);
// Close the process's handle to the file-mapping object.
CloseHandle(hFileMapping);
// Close the handle to the synchronization event object
//CloseHandle(hNewFrameEvt);
}
void CSmartCamCapturePin::GetVideoInfoParameters(
const VIDEOINFOHEADER *pvih, // Pointer to the format header
BYTE * const pbData, // Pointer to first address in buffer
DWORD *pdwWidth, // Returns the width in pixels
DWORD *pdwHeight, // Returns the height in pixels
LONG *plStrideInBytes, // Add this to a row to get the new row down
BYTE **ppbTop, // Pointer to first byte in top row of pixels
bool bYuv
)
{
LONG lStride;
// For 'normal' formats, biWidth is in pixels.
// Expand to bytes and round up to a multiple of 4.
if (pvih->bmiHeader.biBitCount != 0 &&
0 == (7 & pvih->bmiHeader.biBitCount))
{
lStride = (pvih->bmiHeader.biWidth *
(pvih->bmiHeader.biBitCount / 8) + 3) & ~3;
}
else // Otherwise, biWidth is in bytes.
{
lStride = pvih->bmiHeader.biWidth;
}
// If rcTarget is empty, use the whole image.
if (IsRectEmpty(&pvih->rcTarget))
{
*pdwWidth = (DWORD)pvih->bmiHeader.biWidth;
*pdwHeight = (DWORD)(abs(pvih->bmiHeader.biHeight));
if (pvih->bmiHeader.biHeight < 0 || bYuv) // Top-down bitmap
{
*plStrideInBytes = lStride; // Stride goes "down"
*ppbTop = pbData; // Top row is first
}
else // Bottom-up bitmap
{
*plStrideInBytes = -lStride; // Stride goes "up"
*ppbTop = pbData + lStride *
(*pdwHeight - 1); // Bottom row is first
}
}
else // rcTarget is NOT empty. Use a sub-rectangle in the image.
{
*pdwWidth = (DWORD)(pvih->rcTarget.right - pvih->rcTarget.left);
*pdwHeight = (DWORD)(pvih->rcTarget.bottom - pvih->rcTarget.top);
if (pvih->bmiHeader.biHeight < 0 || bYuv) // Top-down bitmap
{
// Same stride as above, but first pixel is modified down
// and over by the target rectangle.
*plStrideInBytes = lStride;
*ppbTop = pbData +
lStride * pvih->rcTarget.top +
(pvih->bmiHeader.biBitCount * pvih->rcTarget.left) / 8;
}
else // Bottom-up bitmap
{
*plStrideInBytes = -lStride;
*ppbTop = pbData +
lStride * (pvih->bmiHeader.biHeight -
pvih->rcTarget.top - 1) +
(pvih->bmiHeader.biBitCount * pvih->rcTarget.left) / 8;
}
}
}