#include "video_device.h"
#include <mtype.h>
#include "end_render.h"
#include <boost/shared_array.hpp>
const wchar_t render_filter_name[20] = L"Render Filter";
namespace nmt
{
HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
{
IMoniker * pMoniker;
IRunningObjectTable *pROT;
if (FAILED(GetRunningObjectTable(0, &pROT)))
{
return E_FAIL;
}
WCHAR wsz[256];
wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
if (SUCCEEDED(hr))
{
hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph, pMoniker, pdwRegister);
pMoniker->Release();
}
pROT->Release();
return hr;
}
DshowVideoCap::DshowVideoCap()
{
m_graph = NULL;
m_render_filter = NULL;
m_cap_filter = NULL;
}
DshowVideoCap::~DshowVideoCap()
{
if (m_render_filter != NULL)
{
delete m_render_filter;
}
m_render_filter = NULL;
}
int DshowVideoCap::start()
{
CoInitialize(NULL);
int succeeded = init();
if (succeeded != 0)
{
return succeeded;
}
//
IMediaControl *mctrl = NULL;
HRESULT hr = m_graph->QueryInterface(IID_IMediaControl, (void **)&mctrl);
if(SUCCEEDED(hr))
{
hr = mctrl->Run();
if(FAILED(hr))
{
mctrl->Stop();
}
mctrl->Release();
}
return 0;
}
void DshowVideoCap::stop()
{
IMediaControl *mctrl = NULL;
HRESULT hr = m_graph->QueryInterface(IID_IMediaControl, (void **)&mctrl);
if(SUCCEEDED(hr))
{
hr = mctrl->Stop();
if(FAILED(hr))
{
}
mctrl->Release();
}
if (m_cap_filter != NULL)
{
m_cap_filter->Release();
}
m_cap_filter = NULL;
if (m_render_filter != NULL)
{
delete m_render_filter;
}
m_render_filter = NULL;
//销毁对象
std::map<IMoniker *, int>::iterator iter = m_dev_monikers.begin();
while (iter != m_dev_monikers.end())
{
IMoniker *moniker = (IMoniker *)iter->first;
m_dev_monikers.erase(iter);
moniker->Release();
iter++;
}
//
if (m_graph != NULL)
{
m_graph->Release();
}
CoUninitialize();
}
void DshowVideoCap::setVfwFormat(bool show_dlg, IAMVfwCaptureDialogs *dlg, HWND parent_wnd)
{
if (show_dlg)
{
if (S_OK == dlg->HasDialog(VfwCaptureDialog_Source))
{
dlg->ShowDialog(VfwCaptureDialog_Format, parent_wnd);
}
}
else
{
}
}
void DshowVideoCap::setFormat()
{
if (m_cap_filter == NULL)
{
return;
}
IAMStreamConfig *vsc = NULL;
IPin *cap_pin = NULL;
HRESULT hr = m_cap_filter->FindPin(L"Capture", &cap_pin);
cap_pin->QueryInterface(IID_IAMStreamConfig, (void **)&vsc);
AM_MEDIA_TYPE *pmt = NULL;
hr = vsc->GetFormat(&pmt);
if(hr == NOERROR)
{
if(pmt->formattype == FORMAT_VideoInfo)
{
VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)pmt->pbFormat;
// pvi->AvgTimePerFrame = (LONGLONG)(10000000 / gcap.FrameRate);
vsc->SetFormat(pmt);
}
DeleteMediaType(pmt);
}
vsc->Release();
cap_pin->Release();
}
void DshowVideoCap::getFormat()
{
}
void DshowVideoCap::setVfwSource(bool show_dlg, IAMVfwCaptureDialogs *dlg, HWND parent_wnd)
{
if (show_dlg)
{
dlg->ShowDialog(VfwCaptureDialog_Source, parent_wnd);
}
else
{
}
}
void DshowVideoCap::getSource()
{
}
void DshowVideoCap::setVfwDisplay(bool show_dlg, IAMVfwCaptureDialogs *dlg, HWND parent_wnd)
{
if (show_dlg)
{
dlg->ShowDialog(VfwCaptureDialog_Display, parent_wnd);
}
else
{
}
}
void DshowVideoCap::setDisplay()
{
if (m_cap_filter == NULL)
{
return;
}
IAMVideoProcAmp *proc = NULL;
HRESULT hr = m_cap_filter->QueryInterface(IID_IAMVideoProcAmp, (void **)&proc);
if (FAILED(hr))
{
return ;
}
}
void DshowVideoCap::getDisplay()
{
}
void DshowVideoCap::enumVideoInputDevs(std::map<IMoniker *, int> &dev_monikers)
{
ICreateDevEnum *pCreateDevEnum = NULL;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum);
if(hr != NOERROR)
{
return ;
}
IEnumMoniker *pEm=0;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);
if(hr != NOERROR)
{
return ;
}
pEm->Reset();
ULONG cFetched;
IMoniker *pM;
int index = 0;
while(pEm->Next(1,&pM,&cFetched) == S_OK)
{
IPropertyBag *pBag = NULL;
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)
{
SysFreeString(var.bstrVal);
dev_monikers[pM] = index;
pM->AddRef();
}
pBag->Release();
}
pM->Release();
index++;
}
pEm->Release();
pCreateDevEnum->Release();
}
IBaseFilter *DshowVideoCap::getCapFilterFromMoniker(IMoniker *moniker)
{
if (moniker == NULL)
{
//throw_trackerr("moniker == NULL");
}
IBaseFilter *capFilter = NULL;
moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&capFilter);
return capFilter;
}
void DshowVideoCap::getMonikerFriendlyName(IMoniker *moniker, wchar_t *name, int max_len)
{
if (moniker == NULL)
{
}
if (name == NULL)
{
}
if (max_len <= 0)
{
}
IPropertyBag *pBag = NULL;
HRESULT hr = moniker->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)
{
int len = min(wcslen(var.bstrVal), max_len);
wmemcpy(name, var.bstrVal, len);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
}
void DshowVideoCap::DeleteMediaType(AM_MEDIA_TYPE *pmt)
{
if (pmt == NULL)
{
return;
}
FreeMediaType(*pmt);
CoTaskMemFree((PVOID)pmt);
}
int DshowVideoCap::init()
{
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_graph);
DWORD dwRegister;
hr = AddToRot(m_graph, &dwRegister);
enumVideoInputDevs(m_dev_monikers);
if (m_dev_monikers.size() == 0)
{
return 2;
}
std::map<IMoniker *, int>::iterator iter = m_dev_monikers.begin();
IBaseFilter *cap_filter = getCapFilterFromMoniker((IMoniker *)iter->first);
boost::shared_array<char> name = boost::shared_array<char>(new char[100]);
memset(name.get(), 0, 100);
getMonikerFriendlyName((IMoniker *)iter->first, (wchar_t *)name.get(), 100/sizeof(wchar_t));
hr = m_graph->AddFilter(cap_filter, (LPCWSTR)name.get());
if (FAILED(hr))
{
return 3;
}
HRESULT result;
IUnknown *unknown = NULL;
if (m_render_filter != NULL)
{
delete m_render_filter;
}
m_render_filter = (CRenderFilter *)new CRenderFilter(unknown, &result);
hr = m_graph->AddFilter(m_render_filter, render_filter_name);
if (FAILED(hr))
{
return 1;
}
IPin *pOut = NULL;
hr = GetUnconnectedPin(cap_filter, PINDIR_OUTPUT, &pOut);
if (FAILED(hr))
{
pOut->Release();
}
IPin *pIn = NULL;
hr = GetUnconnectedPin(m_render_filter, PINDIR_INPUT, &pIn);
if (FAILED(hr))
{
pIn->Release();
}
hr = m_graph->Connect(pOut, pIn);
if (FAILED(hr))
{
return 4;
}
return 0;
}
int DshowVideoCap::GetUnconnectedPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin)
{
*ppPin = 0;
IEnumPins *pEnum = 0;
IPin *pPin = 0;
HRESULT hr = pFilter->EnumPins(&pEnum);
if (FAILED(hr))
{
return hr;
}
while (pEnum->Next(1, &pPin, NULL) == S_OK)
{
PIN_DIRECTION ThisPinDir;
pPin->QueryDirection(&ThisPinDir);
if (ThisPinDir == PinDir)
{
IPin *pTmp = 0;
hr = pPin->ConnectedTo(&pTmp);
if (SUCCEEDED(hr))
{
pTmp->Release();
}