STDMETHODIMP CBasePin::Connect(IPin *pReceivePin,const AM_MEDIA_TYPE *pmt/*optinal media type*/)
{
CheckPointer(pReceivePin,E_POINTER);
ValidateReadPtr(pReceivePin,sizeof(IPin));
CAutoLock cObjectLock(m_pLock);
DisplayPinInfo(pReceivePin);
\检查该Pin是否已连接
if(m_Connected)
{
DbgLog((LOG_TRACE,CONNECT_TRACE_LEVEL,TEXT(“Already connected”)));
return VFW_E_ALREADY_CONNECTED;
}
\一般Filter只能在停止状态下进行连接
if(!IsStopped()&&!m_bCanReconnectWhenActive)
{
return VFW_E_NOT_STOPPED;
}
\开始媒体类型的检查过程,找出一种连接双方都支持的媒体类型
const CMediaType *ptype=(CMediaType *)pmt;
HRESULT hr=AgreeMediaType(pReceivePin,ptype);
if(FAILED(hr))
{
DbgLog((LOG_TRACE,CONNECT_TRACE_LEVEL,TEXT(“Failed to agree type”)));
EXECUTE_ASSERT(SUCCEEDED(BreakConnect()));
return hr;
}
DbgLog((LOG_TRACE,CONNECT_TRACE_LEVEL,TEXT(“Connection succeeded”)));
return NOERROR;
}
HRESULT CBasePin::AgreeMediaType(IPin *pReceivePin,const CMediaType *pmt)
{
ASSERT(pReceivePin);
IEnumMediaType *pEnumMediaTypes=NULL;
\判断pmt是不是一个完全指定的媒体类型
if((pmt!=NULL)&&(!pmt->IsPartiallySpecified()))
{
\用这个完全指定的媒体类型进行试连接,如果试连接失败,不再作其他尝试
return AttemptConnection(pReceivePin,pmt);
}
HRESULT hrFailure=VFW_E_NO_ACCEPTABLE_TYPES;
\进行Pin上支持的媒体类型枚举,开始媒体类型的“协商”过程
for(int i=0;i<2;i++)
{
HRESULT hr;
if(i==(int)m_bTryMyTypesFirst)
{
hr=pReceivePin->EnumMediaTypes(&pEnumMediaTypes);
}
else
{
hr=EnumMediaTypes(&pEnumMediaTypes);
}
if(SUCCEEDED(hr))
{
ASSERT(pEnumMediaTypes);
hr=TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes);
pEnumMediaTypes->Release();
if(SUCCEEDED(hr))
{
return NOERROR;
}
else
{
if((hr!=E_FAIL)&&(hr!=E_INVALIDARG)&&(hr!=VFW_E_TYPE_NOT_ACCEPTED))
{
hrFailure=hr;
}
}
}
}
return hrFailure;
}
HRESULT CBasePin::TryMediaTypes(IPin *pReceivePin,const CMediaType *pmt,IEnumMediaType *pEnum)
{
\复位枚举器内部状态
HRESULT hr=pEnum->Reset();
if(FAILED(hr))
{
return hr;
}
CMediaType *pMediaType=NULL;
ULONG ulMediaCount=0;
HRESULT hrFailure=S_OK;
for(;;)
{
hr=pEnum->Next(1,(AM_MEDIA_TYPE **)&pMediaType,&ulMediaCount);
if(hr!=S_OK)
{
if(S_OK==hrFailure)
{
hrFailure=VFW_E_NO_ACCEPTABLE_TYPES;
}
return hrFailure;
}
ASSERT(ulMediaCount==1);
ASSERT(pMediaType);
\检查当前枚举得到的媒体类型是否与不完全指定的媒体类型参数匹配
if((pmt==NULL)||pMediaType->MatchesPartial(pmt))
{
\进行试连接
hr=AttemptConnection(pReceivePin,pMediaType);
if(FAILED(hr)&&SUCCEEDED(hrFailure)&&(hr!=E_FAIL)&&(hr!=E_INVALIDARG)&&(hr!=VFW_E_TYPE_NOT_ACCEPTED))
{
hrFailure=hr;
}
}
else
{
hr=VFW_E_NO_ACCEPTABLE_TYPES;
}
DeleteMediaType(pMediaType);
if(S_OK==hr)
{
return hr;
}
}
}
HRESULT CBasePin::AttemptConnection(IPin * pReceivePin,const CMediaType *pmt)
{
//获取Filter对象上的操作权
ASSERT(CritCheckIn(m_pLock));
HRESULT hr=CheckConnect(pReceivePin);
if(FAILED(hr))
{
DbgLog((LOG_TRACE,CONNECT_TRACE_LEVEL,TEXT(“CheckConnect failed”)));
EXECUTE_ASSERT(SUCCEEDED(BreakConnect()));
return hr;
}
\一个很有用的调试函数,可以显示媒体类型
DisplayTypeInfo(pReceivePin,pmt);
\Pin上的媒体类型检查
hr=CheckMediaType(pmt);
if(hr==NOERROR)
{
m_Connected=pReceivePin;
m_Connected->AddRef();
\在Pin上保存媒体类型
hr=SetMediaType(pmt);
if(SUCCEEDED(hr))
{
\询问连接对方Pin是否也能接受当前的媒体类型
hr=pReceivePin->ReceiveConnection((IPin *)this,pmt);
if(SUCCEEDED(hr))
{
\完成连接
hr=CompleteConnect(pReceivePin);
if(SUCCEEDED(hr))
{
return hr;
}
else
{
DbgLog((LOG_TRACE,CONNECT_TRACE_LEVEL,TEXT(“Failed to complete connection”)));
pReceivePin->Disconnect();
}
}
}
}
else
{
if(SUCCEEDED(hr)||(hr==E_FAIL)||(hr==E_INVALIDARG))
{
hr=VFW_E_TYPE_NOT_ACCEPTED;
}
}
EXECUTE_ASSERT(SUCCEEDED(BreakConnect()));
if(m_Connected)
{
m_Connected->Release();
m_Connected=NULL:
}
return hr;
}
HRESULT CBaseOutputPin::CompleteConnect(IPin *pReceivePin)
{
UNREFERENCED_PARAMETER(pReceivePin);
return DecideAllocator(m_pInputPin,&m_pAllocator);
}
HRESULT CBaseOutputPin::DecideAllocator(IMemInputPin *pPin,IMemAllocator **ppAlloc)
{
HRESULT hr=NOERROR;
*ppAlloc=NULL;
ALLOCATOR_PROPERTIES prop;
ZeroMemory(&prop,sizeof(prop));
\询问输入Pin对分配器的要求
pPin->GetAllocatorRequirements(&prop);
if(prop.cbAlign==0)
{
prop.cbAlign=1;
}
\询问输入Pin是否提供一个分配器
hr=pPin->GetAllocator(ppAlloc);
if(SUCCEEDED(hr))
{
\决定Sample使用的内存大小,以及分配器管理的Sample数量
hr=DecideBufferSize(*ppAlloc,&prop);
if(SUCCEEDED(hr))
{
\通知输入Pin最终使用的分配器对象
hr=pPin->NotifyAllocator(*ppAlloc,FALSE);
if(SUCCEEDED(hr))
{
return NOERROR;
}
}
}
\如果输入Pin上不提供分配器,则必须在输出Pin上创建一个分配器
if(*ppAlloc)
{
(*ppAlloc)->Release();
*ppAlloc=NULL;
}
\创建一个输出Pin上的分配器
hr=InitAllocator(ppAlloc);
if(SUCCEEDED(hr))
{
hr=DecideBufferSize(*ppAlloc,&prop);
if(SUCCEEDED(hr))
{
hr=pPin->NotifyAllocator(*ppAlloc,FALSE);
if(SUCCEEDED(hr))
{
return NOERROR;
}
}
}
if(*ppAlloc)
{
(*ppAlloc)->Release();
*ppAlloc=NULL;
}
return hr;
}
HRESULT CBaseOutputPin::Active(void)
{
if(m_pAllocator==NULL)
{
return VFW_E_NO_ALLOCATOR;
}
return m_pAllocator->Commit();
}