用CLSID_FilterGraph+TV卡实现视频采集
【转自】http://blog.csdn.net/wickkid/archive/2010/01/14/5190527.aspx
USB摄像头,视频采集卡采集视频都没问题,换用了一款TV采集卡后,出问题了。曾怀疑是驱动没装好,但是winDVR选择视频源为“S 视频”时能看到图像。
主要症状:
症状一:GraphEdit运行Capture+VideoRender,run后报错0x8007048f(设备没有连接);或者,可以运行,但是窗口全黑。
症状二:参考《失误精选》使用CCrossbar类改进原来的程序,new的时候,CCrossbar::BuildRoutingList()里的pStartingInputPin->ConnectedTo(&pStartingOutputPin);时返回错误“接口的方法太多,无法从中启用事件”。
考虑到winDVR里是选了视频源后有图像的,所以搜索选择视频源的方法,结论是用Crossbar。结果出了症状二。
dshow的help文档上说“The IAMCrossbar interface is implemented by the Analog Video Crossbar Filter.”“The Analog Video Crossbar filter represents a video crossbar on a video capture device that supports the Windows Driver Model (WDM).”“This filter is a wrapper filter for crossbars on WDM streaming devices. The filter's friendly name is taken from the device. Each output pin represents a hardware path for analog baseband video. One of the input pins comes from a TV Tuner (the TV Tuner Filter). Other input pins support video or audio streams. The filter supports any media subtypes and formats that are supported on the downstream connections.
You cannot directly create this filter with CoCreateInstance. The ICaptureGraphBuilder2 interface automatically adds this filter to the graph as needed. ”。
也就是说,想要使用IAMCrossbar,graph里必须有 Analog Video Crossbar ,而且Analog Video Crossbar 是和驱动相关的,不能创建的。
解决的方法:
step1:不能创建就枚举,枚举后Add到Graph里。
跟枚举采集设备一样,枚举器创建为AM_KSCATEGORY_CROSSBAR。即:
if (SUCCEEDED(enumHardware->CreateClassEnumerator(AM_KSCATEGORY_CROSSBAR, &enumMoniker, 0)))
{……}
用名称确定用哪个。测试时通过枚举发现,卡的Capture Filter和Crossbar Filter的名字只是最后一个单词不一样。可以这样得到对应的Crossbar名称:strCaptureFilterName.Replace("Capture","Crossbar")。
枚举后,加入Graph:
if(!SUCCEEDED(mGraph->AddFilter(pDevice,L"Capture Crossbar"))
{……}
step2:获取IAMCrossbar接口。这个就是Filter获得接口。即:
hr = mCrossFilter->QueryInterface(IID_IAMCrossbar,(void**)&mCrossBar);
step3:建立通路的vector。
1、用vector存储路径,每个路径包括inputPin,outputPin和PhysicalType。即:
class CConnectRoute
{
public:
CConnectRoute(long inIn,long inOut):inIndex(inIn),outIndex(inOut){};
~CConnectRoute(){};
long inIndex;
long outIndex;
long pt;
};
vector<CConnectRoute> mConnectRoute;
2、获得所有通路:
mCrossBar->get_PinCounts(&outCount,&inCount);
for (long i=0;i<inCount;i++)
{
for (long j=0;j<outCount;j++)
{
if (S_OK==mCrossBar->CanRoute(j,i))
{
CConnectRoute cr(i,j);
long index=0;
mCrossBar->get_CrossbarPinInfo(TRUE,i,&index,&(cr.pt));
mConnectRoute.push_back(cr);
}
}
}
Step4:设置指定的PhysicalType,并将Crossbar Filter的输出与Capture Filter的输入连起来:
long count = mConnectRoute.size();
long physicalType = 0;
for (long i=0;i<count;i++)
{
if (inPhysicalType==mConnectRoute[i].pt)
{
long inIndex = 0;
if (S_OK==mCrossBar->Route(mConnectRoute[i].outIndex,mConnectRoute[i].inIndex))
{
if (mConnectRoute[i].inIndex == inIndex)
{
IPin* pOut = UFilterUtils::GetPin(mCrossFilter,FALSE,mConnectRoute[i].outIndex);//通路的输出管脚
IPin* pIn =NULL;
pIn = UFilterUtils::GetPin(mFilter,TRUE);//Capture Filter的输入管脚
if(S_OK==mGraph->Connect(pOut, pIn))
{
result = TRUE;
break;
}
}
}
}
}
最后,别忘了release Crossbar Filter和 IAMCrossbar接口。
Crossbar Filter + Capture Filter 作为采集Filter的一个整体,Crossbar Filter对外不可见,在CreateFilter时连接Crossbar Filter 和Capture Filter,其它程序都不用动了。
PS: 在GraphEdit里的VideoCapture前面连接WDM crossbar(流十字型设备),并且编辑crossbar把S-video接在输出上,就能看见图像了。还是研究不够深入啊。
发表于 @ 2010年01月14日