第一篇: DirectShow视频采集_会头痛的可达鸭的博客-CSDN博客
IFilterGraph CLSID_FilterGraph
IFilterGraph2 CLSID_CaptureGraphBuilder
IGraphBuilder CLSID_CaptureGraphBuilder
ICaptureGraphBuiler2 CLSID_CaptureGraphBuilder2
继承关系:
IFilterGraph——>IGraphBuilder——>IFilterGraph2——>IFilterGraph3
通过
pFilterGraph2->AddSourceFilterForMoniker()
用Moniker指针将filter添加到graph,则不必创建IcaptureGraphBuiler2这个接口。
如果需要需要视频流,则需要使用IFilterGraph
ICaptureGraphBuilder2->SetFiltergraph(IFilterGraph)
创建了IcaptureGraphBuiler2,仍然需要创建IGraphBuilder 因为在预览视频时处理播放,暂停,停止这些动作,需要用到IGraphBuilder,而这些功能IcaptureGraphBuiler2 是没有的,所以需要而这协调处理。 IcaptureGraphBuiler2创建后,要将IGraphBuilder的指针与他关联:
pCaptureGraphBuiler2->captureGraphBuiler2(pGraphBuilder).
// 写法1: 将视频设备绑定到基础过滤器上
IBaseFilter* GetDeviceFilter(const char* deviceUniqueIdUTF8,
char* productUniqueIdUTF8,
uint32_t productUniqueIdUTF8Length)
{
const int32_t deviceUniqueIdUTF8Length = (int32_t)strlen(
(char*)deviceUniqueIdUTF8); // UTF8 is also NULL terminated
if (deviceUniqueIdUTF8Length >= kVideoCaptureUniqueNameLength) {
RTC_LOG(LS_INFO) << "Device name too long";
return NULL;
}
// enumerate all video capture devices
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
HRESULT hr = _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
&_dsMonikerDevEnum, 0);
if (hr != NOERROR)
{
RTC_LOG(LS_INFO) << "Failed to enumerate CLSID_SystemDeviceEnum, error 0x"
<< rtc::ToHex(hr) << ". No webcam exist?";
return 0;
}
_dsMonikerDevEnum->Reset();
ULONG cFetched;
IMoniker* pM;
IBaseFilter* captureFilter = NULL;
bool deviceFound = false;
while (S_OK == _dsMonikerDevEnum->Next(1, &pM, &cFetched) && !deviceFound)
{
IPropertyBag* pBag;
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pBag);
if (S_OK == hr)
{
// Find the description or friendly name.
VARIANT varName;
VariantInit(&varName);
if (deviceUniqueIdUTF8Length > 0)
{
hr = pBag->Read(L"DevicePath", &varName, 0);
if (FAILED(hr)) {
hr = pBag->Read(L"Description", &varName, 0);
if (FAILED(hr)) {
hr = pBag->Read(L"FriendlyName", &varName, 0);
}
}
if (SUCCEEDED(hr))
{
char tempDevicePathUTF8[256];
tempDevicePathUTF8[0] = 0;
WideCharToMultiByte(CP_UTF8, 0, varName.bstrVal, -1,
tempDevicePathUTF8, sizeof(tempDevicePathUTF8),
NULL, NULL);
if (strncmp(tempDevicePathUTF8, (const char*)deviceUniqueIdUTF8,
deviceUniqueIdUTF8Length) == 0)
{
// We have found the requested device
deviceFound = true;
hr = pM->BindToObject(0, 0, IID_IBaseFilter, (void**)&captureFilter);
if(FAILED(hr))
{
RTC_LOG(LS_ERROR) << "Failed to bind to the selected "
"capture device " << hr;
}
if (productUniqueIdUTF8 &&
productUniqueIdUTF8Length > 0) // Get the device name
{
GetProductId(deviceUniqueIdUTF8, productUniqueIdUTF8,
productUniqueIdUTF8Length);
}
}
}
}
VariantClear(&varName);
pBag->Release();
}
pM->Release();
}
return captureFilter;
}
//写法2:枚举设备并绑定设备
BOOL BindToVideoDev(int deviceId, IBaseFilter **pFilter)
{
if (deviceId < 0)
{
return FALSE;
}
CComPtr pCreateDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
if (hr != NOERROR)
{
//ERR_DEBUG("Instance DeviceEnum Failed");
return FALSE;
}
CComPtr pEm;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0);
if (hr != NOERROR)
{
//ERR_DEBUG("Enum VideoInputDeviceCategory Failed");
return FALSE;
}
pEm->Reset();
ULONG cFetched;
IMoniker *pM=NULL;
int index = 0;
while((( pEm->Next(1, &pM, &cFetched))==S_OK)&&( index <= deviceId))
{
IPropertyBag *pBag=NULL;
if (pM==NULL)
{
break;
}
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(pBag!=NULL)
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL);
if (hr == NOERROR)
{
if (index == deviceId)
{
//将视频设备绑定到基础过滤器上
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);
}
SysFreeString(var.bstrVal);
pBag->Release();
}
}
pM->Release();
index++;
}
return TRUE;
}
// 添加到过滤器
// AddFilter调用过滤器的IBaseFilter::JoinFilterGraph方法来通知过滤器它已被添加
// AddFilter必须在尝试使用IGraphBuilder::Connect、IFilterGraph::ConnectDirect或IGraphBuilder::Render
// 方法连接或渲染属于添加的过滤器的引脚之前调用
IFilterGraph->AddFilter(IBaseFilter, "name");
// 获取InputPin
IPin* GetInputPin(IBaseFilter* filter)
{
IPin* pin = NULL;
IEnumPins* pPinEnum = NULL;
filter->EnumPins(&pPinEnum);
if (pPinEnum == NULL)
{
return NULL;
}
// get first unconnected pin
pPinEnum->Reset(); // set to first pin
while (S_OK == pPinEnum->Next(1, &pin, NULL)) {
PIN_DIRECTION pPinDir;
pin->QueryDirection(&pPinDir);
if (PINDIR_INPUT == pPinDir) // This is an input pin
{
IPin* tempPin = NULL;
if (S_OK != pin->ConnectedTo(&tempPin)) // The pint is not connected
{
pPinEnum->Release();
return pin;
}
}
pin->Release();
}
pPinEnum->Release();
return NULL;
}
HRESULT SetVideoSize(int nPreview,CString strRGBBytes,int nFrameRate,int iWidth , int iHeight)
{
HRESULT hr=E_FAIL;
if(m_pCaptureGraphBulid==NULL)
return hr;
IAMStreamConfig *pAMStreamConfig=NULL;
if(nPreview==0)
{
hr = m_pCaptureGraphBulid->FindInterface(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,
m_pBaseFilter,IID_IAMStreamConfig,(void **)&pAMStreamConfig);
}
else
{
hr = m_pCaptureGraphBulid->FindInterface(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,
m_pBaseFilter,IID_IAMStreamConfig,(void **)&pAMStreamConfig);
}
if(FAILED( hr ))
{
SAFE_RELEASE(pAMStreamConfig);
return hr;
}
//得到视频格式大小
AM_MEDIA_TYPE *pmt;
pAMStreamConfig->GetFormat(&pmt);
//设置视频格式
pmt->majortype = MEDIATYPE_Video;
pmt->subtype = GetMediaTypeGuid(strRGBBytes);
VIDEOINFOHEADER *pvih = reinterpret_cast(pmt->pbFormat);
//设置回去
int nDefualWidth = pvih->bmiHeader.biWidth;
int nDefualHeight = pvih->bmiHeader.biHeight;
pvih->bmiHeader.biWidth = iWidth;
pvih->bmiHeader.biHeight = iHeight;
pvih->bmiHeader.biSizeImage = pmt->lSampleSize = iWidth*iHeight*pvih->bmiHeader.biPlanes*pvih->bmiHeader.biBitCount/8;
pvih->AvgTimePerFrame = (LONGLONG)(10000000/nFrameRate);
hr = pAMStreamConfig->SetFormat(pmt);
if(FAILED(hr))
{
//如果设置失败可以选用默认的,但运用之后,小屏幕初始化时会出现闪动的情况
pvih->bmiHeader.biWidth = nDefualWidth;
pvih->bmiHeader.biHeight = nDefualHeight;
pvih->bmiHeader.biSizeImage = pmt->lSampleSize = nDefualWidth*nDefualHeight*pvih->bmiHeader.biPlanes*pvih->bmiHeader.biBitCount/8;
hr = pAMStreamConfig->SetFormat(pmt);
if(FAILED(hr))
{
SAFE_RELEASE(pAMStreamConfig);
FreeMediaType(*pmt);
//ERR_DEBUG("初始化设置视频格式失败");
return hr;
}
}
SAFE_RELEASE(pAMStreamConfig);
FreeMediaType(*pmt);//
return hr;
}
(1)、创建CLSID_FilterGraph---- CoCreateInstance--- IFilterGraph
(2)、创建IID_IMediaControl --- IFilterGraph->QueryInterface --- IMediaControl
(3)、获取并连接:IBaseFilter---GetDeviceFilter---BindToObject
IFilterGraph->AddFilter(IBaseFilter, L"VideoCaptureFilter")
(4)、创建自定义的IBaseFilter(成员有IPin)---CaptureSinkFilter
IFilterGraph->AddFilter(CaptureSinkFilter)
(5)、获取InputPin,通过自定义的CaptureSinkFilter,并连接CaptureInputPin::ConnectedTo
(6)、连接OutputPin和InputPin(直接连接两个引脚, 无需中间滤波器)
IFilterGraph->ConnectDirect(OutputPin, InputPin, NULL)
// 基类: VideoCaptureImpl
VideoCaptureDS :public VideoCaptureImpl
// 初始化并且创建:
// IBaseFilter DirectShow主要过滤器
// IGraphBuilder DirectShow图形生成器
// IMediaControl DirectShow媒体控制器
// CaptureSinkFilter
// IPin
VideoCaptureDS::Init
// 基类
// 创建 CaptureInputPin
CaptureSinkFilter : public IBaseFilter
// Input Pin--->camera input
// 负责绑定: receive_pin 和 媒体类型
// 接受视频数据发送给observer
class CaptureInputPin : public IMemInputPin, public IPin
// 主要提供设备能力、获取设备信息、获取Filter
DeviceInfoDS : public DeviceInfoImpl