1166 lines
27 KiB
C++
1166 lines
27 KiB
C++
#define WIN32_LEAN_AND_MEAN
|
|
#include <atlbase.h>
|
|
#include <windows.h>
|
|
#include <dshow.h>
|
|
#include <ks.h>
|
|
#include <ksmedia.h>
|
|
#include <qedit.h>
|
|
#include "SCENE.h"
|
|
extern TCHAR CurrWebCam[256];
|
|
int GetWebCamByName(char *compressorsName, IBaseFilter **FilterPtr);
|
|
int CAMERA_SpecifyedW = 320;
|
|
#pragma optimize("",off)
|
|
#define MYDRV "YouUp"
|
|
#define NB_UNFRENDLY_CAMS 2
|
|
static char *unfrendlyCams[NB_UNFRENDLY_CAMS] = { MYDRV, "CamCam" };
|
|
|
|
//#define Draw_Histogram
|
|
#define CAM_ERROR 1
|
|
#define CAM_UNFRENDLY 2
|
|
#define CAM_IN_USE 3
|
|
#define CAM_USED 4
|
|
|
|
//#pragma optimize("",off)
|
|
struct DeviceInfo
|
|
{
|
|
DeviceInfo():next(NULL), deviceId(-1)
|
|
{
|
|
}
|
|
~DeviceInfo()
|
|
{
|
|
if (next)
|
|
delete next;
|
|
}
|
|
char friendlyName[2048];
|
|
int deviceId;
|
|
DeviceInfo* next;
|
|
};
|
|
|
|
class C2SampleGrabberCB : public ISampleGrabberCB
|
|
{
|
|
public:
|
|
u32 ImageCounter;
|
|
STDMETHODIMP_(ULONG) AddRef() { return 2; }
|
|
STDMETHODIMP_(ULONG) Release() { return 1; }
|
|
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)
|
|
{
|
|
if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown ) {
|
|
*ppv = (void *) static_cast<ISampleGrabberCB*> ( this );
|
|
return NOERROR;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample ){ImageCounter ++;return 0;}
|
|
STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize ){ImageCounter ++;return 0;}
|
|
};
|
|
|
|
|
|
class ARFrameGrabber
|
|
{
|
|
public:
|
|
HRESULT hrinit ;
|
|
VIDEOINFOHEADER Vih;
|
|
|
|
char str[2048];
|
|
long hardwareFlipAvailable;
|
|
long hardwareFlipSet;
|
|
|
|
C2SampleGrabberCB CB;
|
|
|
|
|
|
ARFrameGrabber();
|
|
virtual ~ARFrameGrabber();
|
|
|
|
int Init(int deviceId);
|
|
void BindFilter(int deviceId, IBaseFilter **pFilter);
|
|
int GrabFrame();
|
|
BOOL SetVideoControl(long mask, bool remove = 0);
|
|
|
|
long GetBufferSize() {return bufferSize;}
|
|
long* GetBuffer() {return pBuffer;}
|
|
|
|
void DisplayProperties();
|
|
|
|
protected:
|
|
CComPtr<IPin> pGrabberInput;
|
|
CComPtr<IPin> pGrabberOutput;
|
|
CComPtr<IPin> pCameraOutput;
|
|
CComPtr<IPin> pNullInputPin;
|
|
|
|
CComPtr<IGraphBuilder> pGraph;
|
|
CComPtr<IBaseFilter> pDeviceFilter;
|
|
CComPtr<IBaseFilter> pSampleGrabberFilter;
|
|
CComPtr<IBaseFilter> pNullFilter;
|
|
|
|
CComPtr<IMediaControl> pMediaControl;
|
|
CComPtr<ISampleGrabber> pSampleGrabber;
|
|
CComPtr<IMediaEvent> pMediaEvent;
|
|
|
|
|
|
private:
|
|
void ReportError(char *msg);
|
|
|
|
|
|
long bufferSize;
|
|
long *pBuffer;
|
|
};
|
|
|
|
|
|
|
|
ARFrameGrabber::ARFrameGrabber():pBuffer(NULL), bufferSize(0)
|
|
{
|
|
// memset(this,0,sizeof(*this));
|
|
}
|
|
|
|
ARFrameGrabber::~ARFrameGrabber()
|
|
{
|
|
if (pGrabberInput) pGrabberInput.Release();
|
|
if (pGrabberOutput) pGrabberOutput.Release();
|
|
if (pCameraOutput) pCameraOutput.Release();
|
|
if (pNullInputPin) pNullInputPin.Release();
|
|
|
|
if (pMediaControl) pMediaControl->Stop();
|
|
if (pMediaControl) pMediaControl.Release();
|
|
|
|
if (pMediaEvent) pMediaEvent.Release();
|
|
if (pSampleGrabber) pSampleGrabber.Release();
|
|
if (pSampleGrabberFilter) pSampleGrabberFilter.Release();
|
|
if (pNullFilter) pNullFilter.Release();
|
|
|
|
if (pDeviceFilter) pDeviceFilter.Release();
|
|
if (pGraph) pGraph.Release();
|
|
|
|
if (pBuffer) CC_free(pBuffer);
|
|
pBuffer = NULL;
|
|
bufferSize = 0;
|
|
}
|
|
void FAIL_TEST(HRESULT hr)
|
|
{
|
|
if (hr != S_OK)
|
|
hr = hr;
|
|
}
|
|
|
|
|
|
int ARFrameGrabber::Init(int deviceId)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
hrinit = S_OK;
|
|
|
|
// Bind Device Filter. We know the device because the id was passed in
|
|
str[0] = 0;
|
|
BindFilter(deviceId, &pDeviceFilter);
|
|
char SaveStr9;
|
|
SaveStr9 = str[9];
|
|
str[9] = 0;
|
|
for (int uf=0; uf < NB_UNFRENDLY_CAMS; uf++)
|
|
{
|
|
if (strnicmp(unfrendlyCams[uf],str, strlen(unfrendlyCams[uf])) == 0)
|
|
{
|
|
hrinit = E_FAIL ;
|
|
return CAM_UNFRENDLY;
|
|
}
|
|
}
|
|
str[9] = SaveStr9;
|
|
if (!pDeviceFilter)
|
|
{
|
|
hrinit = E_FAIL ;
|
|
return CAM_ERROR;
|
|
}
|
|
|
|
// Create the Filter Graph Manager.
|
|
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
|
|
IID_IGraphBuilder, (void **)&pGraph);
|
|
|
|
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IBaseFilter, (LPVOID *)&pSampleGrabberFilter);
|
|
|
|
hr = pGraph->QueryInterface(IID_IMediaControl, (void **) &pMediaControl);
|
|
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **) &pMediaEvent);
|
|
|
|
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IBaseFilter, (LPVOID*) &pNullFilter);
|
|
|
|
hr = pGraph->AddFilter(pNullFilter, L"NullRenderer");
|
|
|
|
hr = pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);
|
|
|
|
AM_MEDIA_TYPE mt;
|
|
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
|
|
mt.majortype = MEDIATYPE_Video;
|
|
mt.subtype = MEDIASUBTYPE_RGB32;
|
|
mt.formattype = FORMAT_VideoInfo;
|
|
hr = pSampleGrabber->SetMediaType(&mt);
|
|
|
|
pGraph->AddFilter(pSampleGrabberFilter, L"Grabber");
|
|
|
|
|
|
//hr = pGraph->AddSourceFilter(L"X:\\Bins\\je suis ton pere.avi", L"Source", &pDeviceFilter);
|
|
if (S_OK != pGraph->AddFilter(pDeviceFilter, NULL))
|
|
{
|
|
pDeviceFilter.Release();
|
|
pGraph.Release();
|
|
|
|
hrinit = E_FAIL ;
|
|
return CAM_ERROR;
|
|
}
|
|
|
|
/*
|
|
CComPtr<IAMVideoProcAmp> videoProp;
|
|
pDeviceFilter->QueryInterface(IID_IAMVideoProcAmp, (void **)&vidProp);
|
|
if (vidProp)
|
|
{
|
|
long Min, Max, SteppingDelta, Default, CapsFlag;
|
|
hr = vidProp->GetRange(VideoProcAmp_Brightness, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_Contrast, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_Hue, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_Saturation, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_Sharpness, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_Gamma, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_ColorEnable, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_WhiteBalance, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_BacklightCompensation, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
hr = vidProp->GetRange(VideoProcAmp_Gain, &Min, &Max, &SteppingDelta, &Default, &CapsFlag);
|
|
flags = 2;
|
|
vidProp->Get(VideoProcAmp_Gain, &value, &flags);
|
|
flags = 0;
|
|
}
|
|
*/
|
|
|
|
CComPtr<IEnumPins> pEnum;
|
|
if (S_OK != pDeviceFilter->EnumPins(&pEnum))
|
|
{
|
|
pDeviceFilter.Release();
|
|
pGraph.Release();
|
|
hrinit = E_FAIL ;
|
|
return CAM_ERROR;
|
|
}
|
|
|
|
|
|
if (S_OK != pEnum->Reset())
|
|
{
|
|
pDeviceFilter.Release();
|
|
pGraph.Release();
|
|
pEnum.Release();
|
|
hrinit = E_FAIL ;
|
|
return CAM_ERROR;
|
|
}
|
|
|
|
|
|
if (S_OK != pEnum->Next(1, &pCameraOutput, NULL))
|
|
{
|
|
pDeviceFilter.Release();
|
|
pGraph.Release();
|
|
hrinit = E_FAIL ;
|
|
return CAM_ERROR;
|
|
}
|
|
|
|
|
|
// get flip available
|
|
hardwareFlipAvailable = 0;
|
|
hardwareFlipSet = 0;
|
|
|
|
pEnum.Release();
|
|
pSampleGrabberFilter->EnumPins(&pEnum);
|
|
pEnum->Reset();
|
|
FAIL_TEST(pEnum->Next(1, &pGrabberInput, NULL));
|
|
|
|
pEnum.Release();
|
|
pSampleGrabberFilter->EnumPins(&pEnum);
|
|
pEnum->Reset();
|
|
pEnum->Skip(1);
|
|
FAIL_TEST(pEnum->Next(1, &pGrabberOutput, NULL));
|
|
|
|
|
|
pEnum.Release();
|
|
pNullFilter->EnumPins(&pEnum);
|
|
FAIL_TEST(pEnum->Reset());
|
|
FAIL_TEST(pEnum->Next(1, &pNullInputPin, NULL));
|
|
pEnum.Release();
|
|
|
|
DisplayProperties();
|
|
|
|
FAIL_TEST(pGraph->Connect(pCameraOutput, pGrabberInput));
|
|
FAIL_TEST(pGraph->Connect(pGrabberOutput, pNullInputPin));
|
|
if (deviceId == 2)
|
|
deviceId = deviceId;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
switch(hr)
|
|
{
|
|
case VFW_S_NOPREVIEWPIN :
|
|
break;
|
|
case E_FAIL :
|
|
break;
|
|
case E_INVALIDARG :
|
|
break;
|
|
case E_POINTER :
|
|
break;
|
|
}
|
|
hrinit = hr ;
|
|
return CAM_ERROR;
|
|
}
|
|
|
|
FAIL_TEST(pSampleGrabber->SetBufferSamples(TRUE));
|
|
FAIL_TEST(pSampleGrabber->SetOneShot(TRUE));
|
|
|
|
// AM_MEDIA_TYPE mt;
|
|
hrinit = pSampleGrabber->GetConnectedMediaType(&mt);
|
|
if (!FAILED(hrinit))
|
|
{
|
|
memcpy(&Vih,mt.pbFormat,sizeof(VIDEOINFOHEADER));
|
|
hrinit = pMediaControl->Run();
|
|
long evCode;
|
|
if (hrinit == S_FALSE)
|
|
hrinit = S_OK;
|
|
if (deviceId == 2)
|
|
deviceId = deviceId;
|
|
|
|
|
|
pSampleGrabber->SetCallback(&CB,1);
|
|
|
|
} else
|
|
{
|
|
return CAM_USED;
|
|
}
|
|
|
|
pMediaControl->Run();
|
|
/*
|
|
|
|
setting test
|
|
//IKsPropertySet *m_pKSProp;
|
|
CComPtr<IKsPropertySet> m_pKSProp;
|
|
hr = pDeviceFilter->QueryInterface(IID_IKsPropertySet, (void**)&m_pKSProp);
|
|
if (hr == S_OK)
|
|
{
|
|
DWORD dwSupported = 0;
|
|
hr = m_pKSProp->QuerySupported(PROPSETID_VIDCAP_VIDEOPROCAMP, KSPROPERTY_VIDEOPROCAMP_GAIN,
|
|
&dwSupported);
|
|
if(SUCCEEDED(hr) && dwSupported&KSPROPERTY_SUPPORT_SET)
|
|
{
|
|
KSPROPERTY_VIDEOPROCAMP_S ModeCaps;
|
|
memset(&ModeCaps,0,sizeof(KSPROPERTY_TUNER_MODE_CAPS_S));
|
|
DWORD cbBytes=0;
|
|
//ModeCaps.Property = KSPROPERTY_SUPPORT_SET;
|
|
ModeCaps.Value = 1;
|
|
ModeCaps.Flags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;
|
|
#define INSTANCEDATA_OF_PROPERTY_PTR(x) ((PKSPROPERTY((x))) + 1)
|
|
#define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
|
|
|
|
hr = m_pKSProp->Set(PROPSETID_VIDCAP_VIDEOPROCAMP,KSPROPERTY_VIDEOPROCAMP_COLORENABLE,
|
|
INSTANCEDATA_OF_PROPERTY_PTR(&ModeCaps),
|
|
INSTANCEDATA_OF_PROPERTY_SIZE(ModeCaps),
|
|
&ModeCaps, sizeof(ModeCaps));
|
|
}
|
|
|
|
}//*/
|
|
long evCode;
|
|
pMediaEvent->WaitForCompletion(2000, &evCode);
|
|
return 0;
|
|
}
|
|
#ifdef DRAW_FPS
|
|
u32 RRRRRR = 0;
|
|
#endif
|
|
int ARFrameGrabber::GrabFrame()
|
|
{
|
|
long evCode;
|
|
long size = 0;
|
|
pMediaControl->Run();
|
|
pMediaEvent->WaitForCompletion(INFINITE, &evCode);
|
|
|
|
//if (!CB.ImageCounter) return 0;
|
|
#ifdef DRAW_FPS
|
|
RRRRRR = 0;
|
|
if (CB.ImageCounter > 1 ) RRRRRR = CB.ImageCounter;
|
|
#endif
|
|
/*
|
|
u32 MAXWAIT = 100;
|
|
while ((!CB.ImageCounter) && MAXWAIT) {Sleep(1);MAXWAIT--;};
|
|
*/
|
|
if (!CB.ImageCounter ) return 0;
|
|
|
|
pSampleGrabber->GetCurrentBuffer(&size, NULL);
|
|
CB.ImageCounter = 0;
|
|
|
|
// if buffer is not the same size as before, create a new one
|
|
if (size && (size != bufferSize))
|
|
{
|
|
if (pBuffer)
|
|
CC_free(pBuffer);
|
|
bufferSize = size;
|
|
pBuffer = (long *)CC_malloc(bufferSize*sizeof(long));
|
|
}
|
|
|
|
pSampleGrabber->GetCurrentBuffer(&size, pBuffer);
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARFrameGrabber::BindFilter(int deviceId, IBaseFilter **pFilter)
|
|
{
|
|
if (deviceId < 0)
|
|
return;
|
|
|
|
*pFilter = NULL;
|
|
// enumerate all video capture devices
|
|
CComPtr<ICreateDevEnum> pCreateDevEnum;
|
|
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
|
|
if (hr != NOERROR)
|
|
{
|
|
// ErrMsg("Error Creating Device Enumerator");
|
|
return;
|
|
}
|
|
|
|
CComPtr<IEnumMoniker> pEm;
|
|
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
|
|
&pEm, 0);
|
|
if (hr != NOERROR)
|
|
{
|
|
// ErrMsg("Sorry, you have no video capture hardware");
|
|
return;
|
|
}
|
|
|
|
pEm->Reset();
|
|
ULONG cFetched;
|
|
IMoniker *pM;
|
|
int index = 0;
|
|
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK, index <= deviceId)
|
|
{
|
|
IPropertyBag *pBag;
|
|
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
VARIANT var;
|
|
var.vt = VT_BSTR;
|
|
hr = pBag->Read(L"FriendlyName", &var, NULL);
|
|
if (hr == NOERROR)
|
|
{
|
|
WideCharToMultiByte(CP_ACP,0,var.bstrVal, -1, str, 2048, NULL, NULL);
|
|
if (index == deviceId)
|
|
{
|
|
|
|
FILTER_STATE State;
|
|
hr = pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);
|
|
}
|
|
SysFreeString(var.bstrVal);
|
|
}
|
|
pBag->Release();
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
|
|
BOOL ARFrameGrabber::SetVideoControl(long mask, bool remove)
|
|
{
|
|
HRESULT hr;
|
|
return false; // ....
|
|
|
|
if ( hardwareFlipAvailable != 0 &&
|
|
!(hardwareFlipAvailable & mask))
|
|
return false;
|
|
|
|
if ((!remove && ( hardwareFlipSet & mask)) ||
|
|
( remove && !(hardwareFlipSet & mask)))
|
|
return true;
|
|
|
|
|
|
CComPtr<IAMVideoControl> videoControl;
|
|
CComPtr<IEnumPins> pEnum;
|
|
CComPtr<IPin> oPin;
|
|
|
|
if (S_OK == pDeviceFilter->QueryInterface(IID_IAMVideoControl, (void **)&videoControl) &&
|
|
S_OK == pDeviceFilter->EnumPins(&pEnum) &&
|
|
S_OK == pEnum->Reset() &&
|
|
S_OK == pEnum->Next(1, &oPin, NULL))
|
|
{
|
|
if (hardwareFlipAvailable == 0)
|
|
{
|
|
videoControl->GetCaps(oPin, &hardwareFlipAvailable);
|
|
hardwareFlipAvailable |= 0x80;
|
|
}
|
|
|
|
if (hardwareFlipAvailable & mask)
|
|
{
|
|
long mode = 0;
|
|
hr = videoControl->GetMode(oPin, &mode);
|
|
if (remove)
|
|
{
|
|
mode &= ~mask;
|
|
hardwareFlipSet &= ~mask;
|
|
} else
|
|
{
|
|
mode |= mask;
|
|
hardwareFlipSet |= mask;
|
|
}
|
|
hr = videoControl->SetMode(oPin, mode & hardwareFlipAvailable);
|
|
hr = videoControl->GetMode(oPin, &mode);
|
|
return true;
|
|
} else
|
|
{
|
|
hardwareFlipAvailable ^= mask;
|
|
return false;
|
|
}
|
|
} else
|
|
{
|
|
if (hardwareFlipAvailable == 0)
|
|
hardwareFlipAvailable |= 0x80;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MyFreeMediaType(AM_MEDIA_TYPE& mt)
|
|
{
|
|
if (mt.cbFormat != 0)
|
|
{
|
|
CoTaskMemFree((PVOID)mt.pbFormat);
|
|
mt.cbFormat = 0;
|
|
mt.pbFormat = NULL;
|
|
}
|
|
if (mt.pUnk != NULL)
|
|
{
|
|
// Unecessary because pUnk should not be used, but safest.
|
|
mt.pUnk->Release();
|
|
mt.pUnk = NULL;
|
|
}
|
|
}
|
|
|
|
void MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
|
|
{
|
|
if (pmt != NULL)
|
|
{
|
|
MyFreeMediaType(*pmt); // See FreeMediaType for the implementation.
|
|
CoTaskMemFree(pmt);
|
|
}
|
|
}
|
|
|
|
void ARFrameGrabber::DisplayProperties()
|
|
{
|
|
CComPtr<ISpecifyPropertyPages> pPages;
|
|
HRESULT hr;
|
|
IAMStreamConfig *pConfig;
|
|
AM_MEDIA_TYPE *pt_Media;
|
|
VIDEOINFOHEADER *pt_Vid;
|
|
|
|
// try doing ersolution change automatically
|
|
hr = pCameraOutput->QueryInterface(IID_IAMStreamConfig,(void**) &pConfig);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = pConfig->GetFormat( &pt_Media );
|
|
pt_Vid = (VIDEOINFOHEADER *) pt_Media->pbFormat;
|
|
if (CAMERA_SpecifyedW == 160)
|
|
{
|
|
pt_Vid->bmiHeader.biWidth = 160;
|
|
pt_Vid->bmiHeader.biHeight = 120;//*/
|
|
} else
|
|
if (CAMERA_SpecifyedW == 352)
|
|
{
|
|
pt_Vid->bmiHeader.biWidth = 352;
|
|
pt_Vid->bmiHeader.biHeight = 288;//*/
|
|
} else
|
|
if (CAMERA_SpecifyedW == 640)
|
|
{
|
|
pt_Vid->bmiHeader.biWidth = 640;
|
|
pt_Vid->bmiHeader.biHeight = 480;//*/
|
|
} else
|
|
if (CAMERA_SpecifyedW == 800)
|
|
{
|
|
pt_Vid->bmiHeader.biWidth = 800;
|
|
pt_Vid->bmiHeader.biHeight = 600;//*/
|
|
} else
|
|
if (CAMERA_SpecifyedW == 1024)
|
|
{
|
|
pt_Vid->bmiHeader.biWidth = 1024;
|
|
pt_Vid->bmiHeader.biHeight = 768;//*/
|
|
} else
|
|
{
|
|
pt_Vid->bmiHeader.biWidth = 320;
|
|
pt_Vid->bmiHeader.biHeight = 240;
|
|
}
|
|
pt_Vid->bmiHeader.biBitCount = 24;
|
|
pt_Media->lSampleSize = pt_Vid->bmiHeader.biSizeImage = (pt_Vid->bmiHeader.biWidth * pt_Vid->bmiHeader.biHeight * pt_Vid->bmiHeader.biBitCount)>>3;
|
|
/*pt_Vid->bmiHeader.biWidth = 352;
|
|
pt_Vid->bmiHeader.biHeight = 288;//*/
|
|
/*pt_Vid->bmiHeader.biWidth = 640;
|
|
pt_Vid->bmiHeader.biHeight = 480;//*/
|
|
hr = pConfig->SetFormat( pt_Media );
|
|
pConfig->Release();
|
|
|
|
|
|
bufferSize = pt_Vid->bmiHeader.biWidth * pt_Vid->bmiHeader.biHeight;
|
|
if (pBuffer) CC_free(pBuffer);
|
|
if (bufferSize)
|
|
{
|
|
pBuffer = (long *)CC_malloc(bufferSize* sizeof(long));
|
|
}
|
|
else
|
|
pBuffer = NULL;
|
|
|
|
MyDeleteMediaType( pt_Media );
|
|
|
|
|
|
if (hr == S_OK )
|
|
return;
|
|
}
|
|
|
|
// automatic resolution change does'nt work, display property page
|
|
hr = pCameraOutput->QueryInterface(IID_ISpecifyPropertyPages, (void**)&pPages);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
PIN_INFO PinInfo;
|
|
pCameraOutput->QueryPinInfo(&PinInfo);
|
|
|
|
CAUUID caGUID;
|
|
pPages->GetPages(&caGUID);
|
|
|
|
OleCreatePropertyFrame(
|
|
NULL,
|
|
0,
|
|
0,
|
|
L"Property Sheet",
|
|
1,
|
|
(IUnknown **)&(pCameraOutput.p),
|
|
caGUID.cElems,
|
|
caGUID.pElems,
|
|
0,
|
|
0,
|
|
NULL);
|
|
CoTaskMemFree(caGUID.pElems);
|
|
PinInfo.pFilter->Release();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ARFrameGrabber::ReportError(char *msg)
|
|
{
|
|
MessageBox(NULL, msg, "ARFrameGrabber Error", MB_ICONSTOP);
|
|
}
|
|
|
|
|
|
class WEBCAM:public INPUT_IO
|
|
{
|
|
public:
|
|
ARFrameGrabber *grabber;
|
|
WORLD*pScene;
|
|
u32 DeviceID;
|
|
u32 LastTime;
|
|
u32 AvergageDT_x16;
|
|
|
|
u32 frameTime ;
|
|
u32 Locker ;
|
|
u32 UnplugCount ;
|
|
u32 UnplugWait;
|
|
u32 camOK;
|
|
|
|
int INIT (class WORLD*);
|
|
int FRAME (void);
|
|
int END (void);
|
|
IOTYPE GetType() {return IOtype_CAM;};
|
|
void *GetData(int dataIdx);
|
|
};
|
|
|
|
int WEBCAM::INIT(WORLD*pSc)
|
|
{
|
|
CoInitialize( NULL);
|
|
int defaultCam = 0;
|
|
|
|
LastTime = timeGetTime();
|
|
AvergageDT_x16 = 0;
|
|
|
|
grabber = new ARFrameGrabber();
|
|
Image.SX = Image.SY = 0;
|
|
|
|
|
|
if (*CurrWebCam)
|
|
{
|
|
defaultCam = GetWebCamByName(CurrWebCam, NULL);
|
|
if (defaultCam == -1)
|
|
defaultCam = 0;
|
|
}
|
|
|
|
if (grabber->Init(defaultCam) == CAM_USED)
|
|
{
|
|
UnplugWait = 63;
|
|
} else
|
|
if (grabber->hrinit != S_OK)
|
|
{
|
|
delete grabber;
|
|
grabber = new ARFrameGrabber();
|
|
Image.SX = Image.SY = 0;
|
|
grabber->Init(1);
|
|
if (grabber->hrinit != S_OK)
|
|
{
|
|
delete grabber;
|
|
grabber = new ARFrameGrabber();
|
|
Image.SX = Image.SY = 0;
|
|
grabber->Init(2);
|
|
if (grabber->hrinit != S_OK)
|
|
{
|
|
delete grabber;
|
|
grabber = new ARFrameGrabber();
|
|
Image.SX = Image.SY = 0;
|
|
grabber->Init(3);
|
|
if (grabber->hrinit != S_OK)
|
|
{
|
|
delete grabber;
|
|
grabber = new ARFrameGrabber();
|
|
Image.SX = Image.SY = 0;
|
|
grabber->Init(0);
|
|
if (grabber->hrinit != S_OK)
|
|
{
|
|
delete grabber;
|
|
grabber = NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (grabber->hrinit != S_OK)
|
|
{
|
|
delete grabber;
|
|
grabber = NULL;
|
|
return 0;
|
|
}
|
|
if (grabber->Vih.bmiHeader.biWidth > 640)
|
|
{
|
|
delete grabber;
|
|
grabber = NULL;
|
|
return 0;
|
|
}
|
|
|
|
grabber->CB.ImageCounter = 1;
|
|
grabber->GrabFrame();
|
|
|
|
//memset(&Image, 0, sizeof(MAP));
|
|
if (grabber->Vih.bmiHeader.biWidth * grabber->Vih.bmiHeader.biHeight)
|
|
Image.SetSize(grabber->Vih.bmiHeader.biWidth, grabber->Vih.bmiHeader.biHeight);
|
|
pScene = pSc;
|
|
|
|
|
|
return 1;
|
|
}
|
|
|
|
u32 webcamInitTime = 0;
|
|
|
|
int WEBCAM::FRAME(void)
|
|
{
|
|
int i, j;
|
|
if (pScene->bManualBoot & 2) Locker = 8;
|
|
/* if (Locker)
|
|
{
|
|
Locker--;
|
|
return 1;
|
|
}*/
|
|
|
|
if (!grabber)
|
|
{
|
|
MAP SaveImage;
|
|
SaveImage = Image; SaveImage.staticBase = 1;
|
|
if (UnplugCount > 3)
|
|
{
|
|
UnplugCount++;
|
|
if ((UnplugCount & UnplugWait) != 0) return 1;
|
|
if (!INIT(pScene))
|
|
{
|
|
Image = SaveImage; Image.staticBase = 0;
|
|
grabber = NULL;
|
|
camOK = 0;
|
|
memset(Image.GetBase(),rand()&7,Image.PITCH * Image.SY * 4);
|
|
DRawTEXT_Soft_B_Centered((u8*)"Camera do not respond!!\nPlease restart or re-plug",(u32*)Image.GetBase(),Image.SX, Image.SY, 0xffff0000 + (rand()&7) + ((rand()&7)<<8));
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
SaveImage.Delete();
|
|
if (ulAssociatedTextureIndex != -1)
|
|
pScene->DI->DestroyTexture(ulAssociatedTextureIndex);
|
|
ulAssociatedTextureIndex = pScene->DI->CreateTexture(&Image,ulColorMode);
|
|
|
|
UnplugCount = 0;
|
|
UnplugWait = 15;
|
|
frameTime = timeGetTime();
|
|
}
|
|
}
|
|
}
|
|
START_RASTER(WebCam);
|
|
if (grabber && grabber->GrabFrame())
|
|
{
|
|
camOK++;
|
|
UnplugCount = 0;
|
|
u32 curTime = timeGetTime();
|
|
if (!frameTime)
|
|
webcamInitTime = curTime;
|
|
else
|
|
webcamInitTime = curTime - ((curTime - frameTime)>>1);
|
|
frameTime = curTime;
|
|
|
|
AvergageDT_x16 -= AvergageDT_x16>>4;
|
|
AvergageDT_x16 += (curTime - LastTime)<<4;
|
|
LastTime = curTime;
|
|
|
|
|
|
int *dstPtr = Image.GetBase();
|
|
int *srcPtr = (int *)grabber->GetBuffer();
|
|
for (int y=0; y<Image.SY; y++)
|
|
{
|
|
for (int x=0; x<Image.SX; x++, srcPtr++, dstPtr++)
|
|
*dstPtr = *srcPtr | 0xFF000000;
|
|
dstPtr += Image.PITCH - Image.SX;
|
|
srcPtr += Image.PITCH - Image.SX;
|
|
}
|
|
|
|
if (pScene && pScene->WebCamXInvert)
|
|
{
|
|
if (!grabber->SetVideoControl(VideoControlFlag_FlipVertical))
|
|
{
|
|
s32 *ImageB,*ImageE;
|
|
ImageB = Image.GetBase();
|
|
ImageE = Image.GetBase() + Image.PITCH * Image.SY;
|
|
while (ImageB < ImageE)
|
|
{
|
|
s32 *RB,*RE;
|
|
RB = ImageB;
|
|
RE = ImageB + Image.SX - 1;
|
|
while (RB < RE)
|
|
{
|
|
s32 Swap;
|
|
Swap = *RB;
|
|
*RB = *RE;
|
|
*RE = Swap;
|
|
RB++;
|
|
RE--;
|
|
}
|
|
ImageB+=Image.PITCH;
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
grabber->SetVideoControl(VideoControlFlag_FlipVertical, 1);
|
|
}
|
|
if (pScene && pScene->WebCamYInvert)
|
|
{
|
|
if (!grabber->SetVideoControl(VideoControlFlag_FlipHorizontal))
|
|
{
|
|
s32 *ImageB = Image.GetBase();
|
|
int PITCH = Image.PITCH;
|
|
int tmp;
|
|
int SX = Image.SX;
|
|
int SY = Image.SY;
|
|
for(int px=0; px<SX; px++)
|
|
for(int py=0; py<SY/2; py++)
|
|
{
|
|
tmp = *(ImageB + px + py*PITCH);
|
|
*(ImageB + px + py*PITCH) = *(ImageB + px + (SY-1-py)*PITCH);
|
|
*(ImageB + px + (SY-1-py)*PITCH) = tmp;
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
grabber->SetVideoControl(VideoControlFlag_FlipHorizontal, 1);
|
|
}
|
|
{
|
|
s32 *ImageB,*ImageE;
|
|
ImageB = Image.GetBase();
|
|
ImageE = Image.GetBase() + Image.PITCH * Image.SY;
|
|
while (ImageB < ImageE)
|
|
{
|
|
*(ImageB++) |= 0xff000000 ;
|
|
*(ImageB++) |= 0xff000000 ;
|
|
*(ImageB++) |= 0xff000000 ;
|
|
*(ImageB++) |= 0xff000000 ;
|
|
|
|
}
|
|
}
|
|
#ifdef Draw_Histogram
|
|
s32 Histo[2048],*pX;
|
|
pX = Image.GetBase() + Image.PITCH * Image.SY/2;
|
|
for (s32 XCounter = 0 ; XCounter < Image.SX ; XCounter ++ , pX++)
|
|
Histo [XCounter]=(*pX &0xff) + ((*pX>>8) &0xff) + ((*pX>>16) &0xff);
|
|
DrawLine_Clip(&Image,
|
|
0,Image.SY>>1 ,
|
|
Image.SX ,Image.SY>>1 , 0xff0000);
|
|
for (s32 XCounter = 0 ; XCounter < Image.SX - 1; XCounter ++ )
|
|
DrawLine_Clip(&Image,
|
|
XCounter,(Histo [XCounter] >>2) ,
|
|
XCounter+1,(Histo [XCounter+1] >>2) , 0xff00);
|
|
#endif
|
|
#ifdef DRAW_FPS
|
|
char FrameRate[1024];
|
|
|
|
if (RRRRRR)
|
|
{
|
|
sprintf(FrameRate,"%d : %d",(s32)(256000.0f / (double)(AvergageDT_x16)),RRRRRR);
|
|
DRawTEXT_Soft_B((u8*)FrameRate,(u32*)Image.BASE,20,20, Image.PITCH , Image.SY, 0xffff0000);
|
|
}
|
|
else
|
|
{
|
|
sprintf(FrameRate,"%d",(s32)(256000.0f / (double)(AvergageDT_x16)));
|
|
DRawTEXT_Soft_B((u8*)FrameRate,(u32*)Image.BASE,20,20, Image.PITCH , Image.SY, 0xff00ff00);
|
|
}
|
|
#endif
|
|
STOP_RASTER(WebCam);
|
|
START_RASTER(Shots)
|
|
void FindHotSpot(MAP *pSrc,float Focale);
|
|
FindHotSpot(&Image,MediaFocale == 0.0 ? 2.2 : MediaFocale);
|
|
STOP_RASTER(Shots);//*/
|
|
return 1;
|
|
} else
|
|
{
|
|
static DWORD waitTime = 500;
|
|
if (timeGetTime() - frameTime > waitTime)
|
|
{
|
|
if (UnplugCount == 3)
|
|
{
|
|
if (grabber) delete grabber;
|
|
grabber = NULL;
|
|
camOK = 0;
|
|
Image.SetSize(Image.SX, Image.SY);
|
|
memset(Image.GetBase(),0,Image.PITCH * Image.SY * 4);
|
|
DRawTEXT_Soft_B_Centered((u8*)"Camera do not respond!!\nPlease restart or re-plug",(u32*)Image.GetBase(),Image.SX, Image.SY, 0xffff0000);
|
|
STOP_RASTER(WebCam);
|
|
UnplugCount ++;
|
|
waitTime = waitTime + 500;
|
|
return 1;
|
|
} else
|
|
UnplugCount ++;
|
|
} else
|
|
UnplugCount = 0;
|
|
}
|
|
|
|
|
|
STOP_RASTER(WebCam);
|
|
return 0;
|
|
}
|
|
|
|
int WEBCAM::END(void)
|
|
{
|
|
if (grabber) delete grabber;
|
|
Image.Delete();
|
|
return 0;
|
|
}
|
|
|
|
void *WEBCAM::GetData(int dataIdx)
|
|
{
|
|
switch (dataIdx)
|
|
{
|
|
case 3:
|
|
return (void *)(camOK > 1); // one frame waiting
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
INPUT_IO *WEBCAM_CREATE(WORLD *pScene,char *MediaName)
|
|
{
|
|
INPUT_IO *Ret;
|
|
u32 FFF = GetFileNameExtend((char *)MediaName) - 'CAM0';
|
|
Ret = (INPUT_IO *)new(WEBCAM);
|
|
strcpy((char*)Ret->MediaName,MediaName);
|
|
((WEBCAM *)Ret)->DeviceID = FFF;
|
|
Ret->dTotalTime = 0;
|
|
Ret->dAvgFramePerSecond = 30.0;
|
|
|
|
/* PHILIPPE : LOADING OPTIMIZE -> Create an unplugged camera */
|
|
if (0)
|
|
{
|
|
((WEBCAM *)Ret)->grabber = NULL;
|
|
((WEBCAM *)Ret)->Image.SetSize(320, 240, 1);
|
|
DRawTEXT_Soft_B_Centered((u8*)"Init Camera...",(u32*)((WEBCAM *)Ret)->Image.GetBase(),((WEBCAM *)Ret)->Image.SX, ((WEBCAM *)Ret)->Image.SY, 0xffff0000);
|
|
((WEBCAM *)Ret)->pScene = pScene;
|
|
((WEBCAM *)Ret)->UnplugCount = 0;
|
|
((WEBCAM *)Ret)->UnplugWait = 15;
|
|
((WEBCAM *)Ret)->camOK = 0;
|
|
((WEBCAM *)Ret)->frameTime = timeGetTime() - 200;
|
|
((WEBCAM *)Ret)->Locker = 0;
|
|
} else
|
|
/* PHILIPPE : LOADING OPTIMIZE -> instead of this */
|
|
Ret->INIT(pScene);
|
|
|
|
if (Ret->Image.SX == 0)
|
|
{
|
|
char String[1024];
|
|
delete Ret;
|
|
sprintf(String,"No Camera\n%s\nPlease Restart\nwith camera device",MediaName);
|
|
return ERROR_CREATE(String);
|
|
}
|
|
return Ret;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
int GetWebCamNames(char compressors[][256], int *nbCompressors, int maxCompressors)
|
|
{
|
|
HRESULT hr;
|
|
ICreateDevEnum *pSysDevEnum = NULL;
|
|
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_ICreateDevEnum, (void **)&pSysDevEnum);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Obtain a class enumerator for the video compressor category.
|
|
IEnumMoniker *pEnumCat = NULL;
|
|
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
|
|
|
|
*nbCompressors = 0;
|
|
if (hr == S_OK)
|
|
{
|
|
// Enumerate the monikers.
|
|
IMoniker *pMoniker = NULL;
|
|
ULONG cFetched;
|
|
while(*nbCompressors < maxCompressors && pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
|
|
{
|
|
IPropertyBag *pPropBag;
|
|
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
|
|
(void **)&pPropBag);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// To retrieve the filter's friendly name, do the following:
|
|
VARIANT varName;
|
|
VariantInit(&varName);
|
|
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
int net_len =WideCharToMultiByte(CP_ACP, 0,varName.bstrVal, -1, NULL, 0, NULL, NULL);
|
|
WideCharToMultiByte(CP_ACP, 0, varName.bstrVal, -1, compressors[(*nbCompressors)++], net_len+1, NULL, NULL);
|
|
for (int uf=0; uf < NB_UNFRENDLY_CAMS; uf++)
|
|
{
|
|
if (!strnicmp(compressors[*nbCompressors-1], unfrendlyCams[uf], strlen(unfrendlyCams[uf])))
|
|
{
|
|
(*nbCompressors)--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
VariantClear(&varName);
|
|
pPropBag->Release();
|
|
}
|
|
pMoniker->Release();
|
|
}
|
|
pEnumCat->Release();
|
|
}
|
|
pSysDevEnum->Release();
|
|
return *nbCompressors;
|
|
}
|
|
|
|
int GetWebCamByName(char *compressorsName)
|
|
{
|
|
return GetWebCamByName(compressorsName, NULL);
|
|
}
|
|
|
|
int GetWebCamByName(char *compressorsName, IBaseFilter **FilterPtr)
|
|
{
|
|
HRESULT hr;
|
|
char filterName[256];
|
|
int resIndex = -1;
|
|
|
|
ICreateDevEnum *pSysDevEnum = NULL;
|
|
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_ICreateDevEnum, (void **)&pSysDevEnum);
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
// Obtain a class enumerator for the video compressor category.
|
|
IEnumMoniker *pEnumCat = NULL;
|
|
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
|
|
|
|
int currIndex = -1;
|
|
if (hr == S_OK)
|
|
{
|
|
// Enumerate the monikers.
|
|
IMoniker *pMoniker = NULL;
|
|
ULONG cFetched;
|
|
while(resIndex != 1 && pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
|
|
{
|
|
IPropertyBag *pPropBag;
|
|
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
|
|
(void **)&pPropBag);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// To retrieve the filter's friendly name, do the following:
|
|
VARIANT varName;
|
|
VariantInit(&varName);
|
|
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
currIndex++;
|
|
int net_len =WideCharToMultiByte(CP_ACP, 0,varName.bstrVal, -1, NULL, 0, NULL, NULL);
|
|
WideCharToMultiByte(CP_ACP, 0, varName.bstrVal, -1, filterName, net_len+1, NULL, NULL);
|
|
if (!strcmp(filterName, compressorsName))
|
|
{
|
|
if (FilterPtr != NULL)
|
|
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)FilterPtr);
|
|
resIndex = currIndex;
|
|
}
|
|
}
|
|
VariantClear(&varName);
|
|
pPropBag->Release();
|
|
}
|
|
pMoniker->Release();
|
|
}
|
|
pEnumCat->Release();
|
|
}
|
|
pSysDevEnum->Release();
|
|
return resIndex;
|
|
}
|
|
|
|
|
|
|
|
void PropertyPageCall(void *params)
|
|
{
|
|
IBaseFilter *filter = (IBaseFilter *)params;
|
|
HRESULT hr = E_FAIL;
|
|
CComPtr<ISpecifyPropertyPages> pPages;
|
|
|
|
hr = filter->QueryInterface(IID_ISpecifyPropertyPages, (void**)&pPages);
|
|
CAUUID caGUID;
|
|
|
|
pPages->GetPages(&caGUID);
|
|
|
|
OleCreatePropertyFrame(
|
|
NULL,
|
|
0,
|
|
0,
|
|
L"Property Sheet",
|
|
1,
|
|
(IUnknown **)&(filter),
|
|
caGUID.cElems,
|
|
caGUID.pElems,
|
|
0,
|
|
0,
|
|
NULL);
|
|
CoTaskMemFree(caGUID.pElems);
|
|
pPages.Release();
|
|
}
|
|
|
|
|
|
BOOL GetWebCamFilterPropertyByName(char *name, bool openPage)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
if (!*name)
|
|
return hr;
|
|
IBaseFilter *filter;
|
|
if (GetWebCamByName(name, &filter) != -1)
|
|
{
|
|
CComPtr<ISpecifyPropertyPages> pPages;
|
|
hr = filter->QueryInterface(IID_ISpecifyPropertyPages, (void**)&pPages);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pPages.Release();
|
|
if (openPage)
|
|
_beginthread(PropertyPageCall, 0, filter);
|
|
}
|
|
}
|
|
return hr == S_OK;
|
|
}
|
|
|