ловите...
// FrameRenderer.h: interface for the CFrameRenderer class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_FRAMERENDERER_H__93D88322_AAAA_11D5_BD90_E5B9C216A273__INCLUDED_)
#define AFX_FRAMERENDERER_H__93D88322_AAAA_11D5_BD90_E5B9C216A273__INCLUDED_
#include <strmif.h>
#include <uuids.h>
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define SAFE_RELEASE(p) if(p)|p->Release();p = NULL;}
const GUID IID_ISampleGrabber = {0x6B652FFF,0x11FE,0x4fce,{0x92,0xAD,0x02,0x66,0xB5,0xD7,0xC7,0x8F}};
const GUID CLSID_SampleGrabber = {0xC1F400A0,0x3F08,0x11D3,{0x9F,0x0B,0x00,0x60,0x08,0x03,0x9E,0x37}};
const GUID CLSID_NullRenderer = {0xC1F400A4,0x3F08,0x11d3,{0x9F,0x0B,0x00,0x60,0x08,0x03,0x9E,0x37}};
const GUID CLSID_AviDecompressor = {0xCF49D4E0,0x1115,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
DECLARE_INTERFACE(ISampleGrabberCB) : public IBaseFilter
{
};
DECLARE_INTERFACE(ISampleGrabber) : public IUnknown
{
STDMETHOD(SetOneShot(BOOL OneShot)) = 0;
STDMETHOD(SetMediaType(const AM_MEDIA_TYPE *pType)) = 0;
STDMETHOD(GetConnectedMediaType(AM_MEDIA_TYPE *pType)) = 0;
STDMETHOD(SetBufferSamples(BOOL BufferThem)) = 0;
STDMETHOD(GetCurrentBuffer(long *pBufferSize,long *pBuffer)) = 0;
STDMETHOD(GetCurrentSample(IMediaSample **ppSample)) = 0;
STDMETHOD(SetCallback(ISampleGrabberCB *pCallback,long WhichMethodToCallback)) = 0;
};
class CSampleGrabber
{
public:
bool SelectBestCompatibleFormat(IPin* ppin);
bool ReconfigureGraph(IGraphBuilder* pgraph);
void AddToGraph(IGraphBuilder *pgraph);
void SetVideoFormat(GUID format = MEDIASUBTYPE_RGB24);
CSampleGrabber();
virtual ~CSampleGrabber();
public:
IBaseFilter* m_pNullRenderer;
IBaseFilter* m_pAviDecompressor;
ISampleGrabber *m_pGrabber;
IBaseFilter *m_pFilter;
IPin* m_pInputPin;
IPin* m_pOutputPin;
};
UINT ConfigureCamera_thread( LPVOID pParam );
class CFrameGrabber
{
friend UINT ConfigureCamera_thread( LPVOID pParam );
friend UINT ConfigureCamera_thread_new( LPVOID pParam );
public:
void ConfigureCamera();
void *RecieveBitmap();
void QueryGraphInfo(IGraphBuilder* pgb);
CString m_sfile; // имя AVI-файла, to be played
void Stop();
bool Run();
bool ConstructCaptureGraph(CString capdev);
CFrameGrabber();
virtual ~CFrameGrabber();
bool EnumDevices(CStringArray *psa) { return ScanDevices(psa,NULL,false) != NULL;}
private:
HANDLE mutex;
void ListGraphFilters();
void CreateGraph();
void ResetGraph();
bool m_bCapturing;
IBaseFilter* SelectDevice(CString sref)
{ return ScanDevices(NULL,&sref,true);}
IBaseFilter* ScanDevices(CStringArray *psa,CString* prefs, bool bsearch = FALSE);
IGraphBuilder* m_pGraph;
ICaptureGraphBuilder *m_pBuilder;
CSampleGrabber *m_pGrabber;
IBaseFilter* m_camera;
HANDLE m_flog;
};
#endif // !defined(AFX_FRAMERENDERER_H__93D88322_AAAA_11D5_BD90_E5B9C216A273__INCLUDED_)
// FrameRenderer.cpp: implementation of the CFrameRenderer class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "FrameRenderer.h"
#include <strmif.h>
#include <control.h>
#include <uuids.h>
#include <amvideo.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
LPCWSTR WSTR(char* s)
{
static WCHAR buf[128];
MultiByteToWideChar(CP_ACP, 0, s, -1,buf, 128);
return buf;
}
extern void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt);
extern void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt);
//////////////////////////////////////////////////////////////////////
// CFrameGrabber Class
//////////////////////////////////////////////////////////////////////
CSampleGrabber::CSampleGrabber()
{
// создаем фильтр-граббер
HRESULT hr = CoCreateInstance((REFCLSID)CLSID_SampleGrabber,
NULL, CLSCTX_INPROC, (REFIID)IID_IBaseFilter,(void **)&m_pFilter);
ASSERT(SUCCEEDED(hr));
// ищем интрефейс самого граббера
hr = m_pFilter->QueryInterface(IID_ISampleGrabber,(void**)&m_pGrabber);
ASSERT(SUCCEEDED(hr));
// смотрим пины
IEnumPins *penum;
ULONG cbReturned;
m_pFilter->EnumPins(&penum);
hr = penum->Next(1,&m_pInputPin,&cbReturned);
hr = penum->Next(1,&m_pOutputPin,&cbReturned);
penum->Release();
// создаем рендерер
hr = CoCreateInstance((REFCLSID)CLSID_NullRenderer,
NULL, CLSCTX_INPROC, (REFIID)IID_IBaseFilter,(void **)&m_pNullRenderer);
ASSERT(SUCCEEDED(hr));
// создаем avi-декомпрессор (вдруг придется обрабатывать видеофайлы!)
hr = CoCreateInstance((REFCLSID)CLSID_AviDecompressor,
NULL, CLSCTX_INPROC, (REFIID)IID_IBaseFilter,(void **)&m_pAviDecompressor);
ASSERT(SUCCEEDED(hr));
// устанавливаем всякие свойства
hr = m_pGrabber->SetBufferSamples(true);
}
CSampleGrabber::~CSampleGrabber()
{
SAFE_RELEASE(m_pFilter);
SAFE_RELEASE(m_pGrabber);
SAFE_RELEASE(m_pInputPin);
SAFE_RELEASE(m_pOutputPin);
SAFE_RELEASE(m_pNullRenderer);
SAFE_RELEASE(m_pAviDecompressor);
}
void CSampleGrabber::SetVideoFormat(GUID format)
{
AM_MEDIA_TYPE mt;
memset(&mt,0,sizeof(mt));
mt.majortype = MEDIATYPE_Video;
mt.formattype = FORMAT_VideoInfo;
mt.subtype = format;
HRESULT hr = m_pGrabber->SetMediaType(&mt);
ASSERT(SUCCEEDED(hr));
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFrameGrabber::CFrameGrabber()
{
m_bCapturing = false;
m_camera = NULL;
mutex = CreateMutex(NULL,false,"framegrabber_mutex");
// создаем GraphBuilder
CreateGraph();
}
CFrameGrabber::~CFrameGrabber()
{
WaitForSingleObject(mutex,INFINITE);
CloseHandle(mutex);
Stop();
ResetGraph();
SAFE_RELEASE(m_camera);
}
IBaseFilter* CFrameGrabber::ScanDevices(CStringArray *psa,CString* refs, bool bsearch)
{
// !!! There's got to be a way to cache these from building the menu
// Enumerate all the video devices. We want #gcap.iVideoDevice
ICreateDevEnum *pCreateDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
if (hr != NOERROR)
return NULL;
IEnumMoniker *pEm;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);
pCreateDevEnum->Release();
if (hr != NOERROR)
return NULL;
pEm->Reset();
ULONG cFetched;
IMoniker *pM;
char achFriendlyName[120];
IBaseFilter *pVCap;
while(hr = pEm->Next(1, &pM, &cFetched), hr==S_OK) {
// this is the one we want. Get its name, and instantiate it.
IPropertyBag *pBag;
achFriendlyName[0] = 0;
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, achFriendlyName, 80, NULL, NULL);
SysFreeString(var.bstrVal);
if (!bsearch) // если не поиск, то заполняем список
psa->Add(achFriendlyName);
else // иначе ищем такое же имя
if (refs->CompareNoCase(achFriendlyName) == 0){ // если строки одинаковы (НАШЛИ!!!)
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)&pVCap);
pBag->Release();
pM->Release();
pEm->Release();
return pVCap;
}
}
pBag->Release();
}
pM->Release();
}
pEm->Release();
return NULL;
}
bool CFrameGrabber::Run()
{
if (m_bCapturing)
return true; // уже выполняемся
// run the graph
IMediaControl *pMC = NULL;
HRESULT hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&pMC);
if (FAILED(hr))
return false;
hr = pMC->Run();
if (FAILED(hr)) {
// stop parts that started
pMC->Stop();
pMC->Release();
return false;
}
pMC->Release();
m_bCapturing = true;
return true;
}
void CFrameGrabber::Stop()
{
if (!m_bCapturing)
return;
IMediaControl *pMC = NULL;
HRESULT hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&pMC);
if (SUCCEEDED(hr))
hr = pMC->Stop();
pMC->Release();
}
void CFrameGrabber::ResetGraph()
{
SAFE_RELEASE(m_pBuilder);
SAFE_RELEASE(m_pGraph);
delete m_pGrabber;
}
void CFrameGrabber::CreateGraph()
{
// capture graph builder
HRESULT hr = CoCreateInstance((REFCLSID)CLSID_CaptureGraphBuilder,
NULL, CLSCTX_INPROC, (REFIID)IID_ICaptureGraphBuilder,(void **)&m_pBuilder);
ASSERT(SUCCEEDED(hr));
// simple graph builder
hr = CoCreateInstance((REFCLSID)CLSID_FilterGraph,
NULL, CLSCTX_INPROC, (REFIID)IID_IGraphBuilder,(void **)&m_pGraph);
ASSERT(SUCCEEDED(hr));
// sample grabber
m_pGrabber = new CSampleGrabber;
hr = m_pBuilder->SetFiltergraph(m_pGraph);
ASSERT(SUCCEEDED(hr));
// добавляем фильтры в граф
m_pGrabber->AddToGraph(m_pGraph);
}
bool CFrameGrabber::ConstructCaptureGraph(CString capdev)
{
// нашли выбранное устройство
SAFE_RELEASE(m_camera);
m_camera = SelectDevice(capdev);
HRESULT hr;
if (m_camera)| // capture driver
WCHAR ws[] = {'U','M','_','C','A','P','T','U','R','E',0};
hr = m_pGraph->AddFilter(m_camera,ws);
QueryGraphInfo(m_pGraph);
m_pGrabber->SetVideoFormat();
hr = m_pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, m_camera, m_pGrabber->m_pFilter, m_pGrabber->m_pNullRenderer);
if (FAILED(hr))
return false;
QueryGraphInfo(m_pGraph);
hr = m_pGrabber->m_pGrabber->SetOneShot(false);
if (FAILED(hr))
return false;
// убираем синхронизацию
IMediaFilter *pmf;
hr = m_pGraph->QueryInterface(IID_IMediaFilter,(void**)&pmf);
if (SUCCEEDED(hr)){
hr = pmf->SetSyncSource(NULL);
pmf->Release();
}
}
return hr == S_OK;
}
void CFrameGrabber::ListGraphFilters()
{
IEnumFilters *pEnum;
m_pGraph->EnumFilters(&pEnum);
HRESULT hr;
IBaseFilter *pf;
FILTER_INFO fi;
ULONG cFetched;
char achFriendlyName[128];
while(hr = pEnum->Next(1, &pf, &cFetched), hr==S_OK) {
// this is the one we want. Get its name, and instantiate it.
pf->QueryFilterInfo(&fi);
achFriendlyName[0] = 0;
WideCharToMultiByte(CP_ACP, 0, fi.achName, -1, achFriendlyName, 80, NULL, NULL);
pf->Release();
}
pEnum->Release();
}
void CFrameGrabber::QueryGraphInfo(IGraphBuilder *pgb)
{
#ifdef _DEBUG
IEnumFilters *pfenum;
m_pGraph->EnumFilters(&pfenum);
ULONG cbFetched;
IBaseFilter *pf;
FILTER_INFO fi;
while(pfenum->Next(1,&pf,&cbFetched)==S_OK && cbFetched == 1){
pf->QueryFilterInfo(&fi);
afxDump << "Filter [" << fi.achName << "] at address " << pf << "\n"; // name of filter
IEnumPins *ppenum;
pf->EnumPins(&ppenum);
IPin* pp;
PIN_INFO pi;
while(ppenum->Next(1,&pp,&cbFetched)==S_OK && cbFetched == 1){
pp->QueryPinInfo(&pi);
CString sdir = pi.dir == PINDIR_INPUT ? "IN" : "OUT";
afxDump << "\t " << sdir << " pin [" << pi.achName << "] at address "<< pp; // name of pin
IPin *ptemp;
HRESULT hr = pp->ConnectedTo(&ptemp);
if (hr == S_OK){
afxDump << " is connected to pin at " << ptemp << "\n";
ptemp->Release();
} else
afxDump << " is NOT connected!\n";
}
pp->Release();
ppenum->Release();
pf->Release();
}
pfenum->Release();
#endif
}
void CSampleGrabber::AddToGraph(IGraphBuilder *pgraph)
{
pgraph->AddFilter(m_pFilter,WSTR("SampleGrabber"));
pgraph->AddFilter(m_pNullRenderer,WSTR("NULL_Renderer"));
SetVideoFormat();
}
bool CSampleGrabber::ReconfigureGraph(IGraphBuilder *pgraph)
{
IPin *pin;
HRESULT hr = m_pInputPin->ConnectedTo(&pin);
// если же мы не соединены, то ...
// ... смотрим пины у рендерера
IPin *pp;
IEnumPins *penum;
ULONG cbReturned;
m_pNullRenderer->EnumPins(&penum);
penum->Next(1,&pp,&cbReturned); // только один пин
ULONG u = penum->Release();
hr = pp->ConnectedTo(&pin); // получаем пин, с которым соединен рендерер
SelectBestCompatibleFormat(pin);
hr = pgraph->Disconnect(pin); // удаляем соединение
hr = pgraph->Disconnect(pp); // удаляем соединение
u = pp->Release();
// соединяем заново
hr = pgraph->ConnectDirect(pin,m_pInputPin,NULL);
hr = pgraph->Render(m_pOutputPin); // соединяем с рендерером
u = pin->Release();
return true;
}
bool CSampleGrabber::SelectBestCompatibleFormat(IPin *ppin)
{
IEnumMediaTypes *penum;
ppin->EnumMediaTypes(&penum);
AM_MEDIA_TYPE *pmt;
GUID fmt;
ULONG cbReturned;
BYTE check = 0xFF; // nothing is selected
// ищем только RGB uncompressed formats
while(penum->Next(1,&pmt,&cbReturned)==S_OK && cbReturned == 1){
if (IsEqualGUID(pmt->subtype,MEDIASUBTYPE_RGB24)){
check = 0;
fmt = MEDIASUBTYPE_RGB24;
} else
if (IsEqualGUID(pmt->subtype,MEDIASUBTYPE_RGB32) && check>1){
check = 1; // we found it
fmt = MEDIASUBTYPE_RGB32;
} else
if (IsEqualGUID(pmt->subtype,MEDIASUBTYPE_RGB565) && check>2){
check = 2; // we found it
fmt = MEDIASUBTYPE_RGB565;
} else
if (IsEqualGUID(pmt->subtype,MEDIASUBTYPE_RGB555) && check>3){
check = 3; // we found it
fmt = MEDIASUBTYPE_RGB555;
} else
if (IsEqualGUID(pmt->subtype,MEDIASUBTYPE_RGB8) && check>4){
check = 4; // we found it
fmt = MEDIASUBTYPE_RGB8;
}
DeleteMediaType(pmt);
}
penum->Release();
if (check < 5){
SetVideoFormat(fmt);
return true;
}
return false;
}
void* CFrameGrabber::RecieveBitmap()
{
long cbBuffer = 0;
HRESULT hr = m_pGrabber->m_pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
if (FAILED(hr)) return NULL;
void *pBuffer = malloc(cbBuffer);
hr = m_pGrabber->m_pGrabber->GetCurrentBuffer(&cbBuffer,(long*)pBuffer);
return pBuffer;
}
static bool in_thread = false;
UINT ConfigureCamera_thread( LPVOID pParam )
{
in_thread = true;
CFrameGrabber* pfg = (CFrameGrabber*)pParam;
IBaseFilter* pcamera = pfg->m_camera;
if (!pcamera)
return 0;
ISpecifyPropertyPages *pProp;
HRESULT hr = pcamera->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
if (SUCCEEDED(hr)) {
// Get the filter's name and IUnknown pointer.
FILTER_INFO FilterInfo;
pcamera->QueryFilterInfo(&FilterInfo);
IUnknown* pfilterUnk;
pcamera->QueryInterface(IID_IUnknown, (void **)&pfilterUnk);
// Show the page.
CAUUID caGUID;
pProp->GetPages(&caGUID);
pProp->Release();
OleCreatePropertyFrame(
NULL, // Parent window
0, 0, // (Reserved)
FilterInfo.achName, // Caption for the dialog box
1, // Number of objects (just the filter)
&pfilterUnk, // Array of object pointers.
caGUID.cElems, // Number of property pages
caGUID.pElems, // Array of property page CLSIDs
0, // Locale identifier
0, NULL // Reserved
);
// Clean up.
pfilterUnk->Release();
FilterInfo.pGraph->Release();
CoTaskMemFree(caGUID.pElems);
}
ReleaseMutex(pfg->mutex);
in_thread = false;
return 0;
}
IUnknown* GetPropPages(IBaseFilter* filter,CAUUID* pcaGUID)
{
ISpecifyPropertyPages *pProp;
HRESULT hr = filter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
IUnknown* pfilterUnk=NULL;
if (SUCCEEDED(hr)) {
// Get the filter's name and IUnknown pointer.
FILTER_INFO FilterInfo;
filter->QueryFilterInfo(&FilterInfo);
filter->QueryInterface(IID_IUnknown, (void **)&pfilterUnk);
FilterInfo.pGraph->Release();
if (pfilterUnk){
pProp->GetPages(pcaGUID);
pProp->Release();
}
}
return pfilterUnk;
}
UINT ConfigureCamera_thread_new( LPVOID pParam )
{
CFrameGrabber* pfg = (CFrameGrabber*)pParam;
IBaseFilter* pcamera = pfg->m_camera;
if (!pcamera)
return 0;
in_thread = true;
IEnumFilters *pfenum;
pfg->m_pGraph->EnumFilters(&pfenum);
IUnknown* punk[100]; memset(punk,0,sizeof(IUnknown*));
GUID guids[100]; CAUUID caGUID = |0,guids";
DWORD cbFetched;
long num=0;
IBaseFilter* pf;
while(pfenum->Next(1,&pf,&cbFetched)==S_OK && cbFetched == 1){
CAUUID tmpGUID;
IUnknown* unk = GetPropPages(pf,&tmpGUID);
pf->Release();
if (!unk) continue;
num++;
WCHAR wch[] = {'C','A','P',0};
DWORD dw = OleCreatePropertyFrame(
NULL, // Parent window
0, 0, // (Reserved)
wch, // Caption for the dialog box
1, // Number of objects (just the filter)
&unk, // Array of object pointers.
tmpGUID.cElems, // Number of property pages
tmpGUID.pElems, // Array of property page CLSIDs
0, // Locale identifier
0, NULL // Reserved
);
CoTaskMemFree(tmpGUID.pElems);
unk->Release();
}
pfenum->Release();
ReleaseMutex(pfg->mutex);
in_thread = false;
return 0;
}
void CFrameGrabber::ConfigureCamera()
{
if (!in_thread)
AfxBeginThread(&ConfigureCamera_thread_new,this);
}