前言
代码分析
VideoCaptureDS::Init
int32_t VideoCaptureDS::Init(const char* deviceUniqueIdUTF8) {
****
_outputCapturePin = GetOutputPin(_captureFilter, PIN_CATEGORY_CAPTURE);
if (!_outputCapturePin) {
RTC_LOG(LS_INFO) << "Failed to get output capture pin";
return -1;
}
// Create the sink filte used for receiving Captured frames.
sink_filter_ = new ComRefCount<CaptureSinkFilter>(this);
hr = _graphBuilder->AddFilter(sink_filter_, SINK_FILTER_NAME);
if (FAILED(hr)) {
RTC_LOG(LS_INFO) << "Failed to add the send filter to the graph.";
return -1;
}
_inputSendPin = GetInputPin(sink_filter_);
if (!_inputSendPin) {
RTC_LOG(LS_INFO) << "Failed to get input send pin";
return -1;
}
****
}
实际上在调用graphBuilder->AddFilter(sink_filter, SINK_FILTER_NAME);之后,后面还会去调用CaptureSinkFilter::JoinFilterGraph,去告诉上层已经加入到FilterGraphl .
STDMETHODIMP CaptureSinkFilter::JoinFilterGraph(IFilterGraph* graph,
LPCWSTR name) {
RTC_DCHECK_RUN_ON(&main_checker_);
RTC_DCHECK(IsStopped());
// Note, since a reference to the filter is held by the graph manager,
// filters must not hold a reference to the graph. If they would, we'd have
// a circular reference. Instead, a pointer to the graph can be held without
// reference. See documentation for IBaseFilter::JoinFilterGraph for more.
info_.pGraph = graph; // No AddRef().
sink_ = nullptr;
if (info_.pGraph) {
// make sure we don't hold on to the reference we may receive.
// Note that this assumes the same object identity, but so be it.
// 当filter有事件发生时,通过sink来通知filtergraph
rtc::scoped_refptr<IMediaEventSink> sink;
GetComInterface(info_.pGraph, &sink);
sink_ = sink.get();
}
info_.achName[0] = L'\0';
if (name)
lstrcpynW(info_.achName, name, arraysize(info_.achName));
return S_OK;
}
—》 inputSendPin = GetInputPin(sink_filter);
GetInputPin
IPin* GetInputPin(IBaseFilter* filter) {
HRESULT hr;
IPin* pin = NULL;
IEnumPins* pPinEnum = NULL;
filter->EnumPins(&pPinEnum);
if (pPinEnum == NULL) {
return NULL;
}
// get first unconnected pin
// 引用计数设置为0,从第一个pin开始
hr = 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;
}
1、 filter->EnumPins(&pPinEnum); 的定义如下
STDMETHODIMP CaptureSinkFilter::EnumPins(IEnumPins** pins) {
RTC_DCHECK_RUN_ON(&main_checker_);
*pins = new ComRefCount<class EnumPins>(input_pin_.get());
(*pins)->AddRef();
return S_OK;
}
2、 hr = pPinEnum->Reset();
STDMETHOD(Reset)() {
pos_ = 0;
return S_OK;
}
3、while (S_OK == pPinEnum->Next(1, &pin, NULL)) {
STDMETHOD(Next)(ULONG count, IPin** pins, ULONG* fetched) {
RTC_DCHECK(count > 0);
RTC_DCHECK(pins);
// fetched may be NULL.
if (pos_ > 0) { // 正常不会大于0
if (fetched)
*fetched = 0;
return S_FALSE;
}
++pos_;
pins[0] = pin_.get();
pins[0]->AddRef(); // 引用计数的增加
if (fetched)
*fetched = 1;
return count == 1 ? S_OK : S_FALSE;
}
4、pin->QueryDirection(&pPinDir);
STDMETHODIMP CaptureInputPin::QueryDirection(PIN_DIRECTION* pin_dir) {
RTC_DCHECK_RUN_ON(&main_checker_);
*pin_dir = info_.dir;
return S_OK;
}
5、 if (S_OK != pin->ConnectedTo(&tempPin)) // The pint is not connected
判断当前引脚是否已经和其他引脚连接,正常不连接
STDMETHODIMP CaptureInputPin::ConnectedTo(IPin** pin) {
RTC_DCHECK_RUN_ON(&main_checker_);
if (!receive_pin_)
return VFW_E_NOT_CONNECTED; //正常返回这个
*pin = receive_pin_.get();
receive_pin_->AddRef();
return S_OK;
}