连接到GMFBridge接收器滤波器的输入引脚的问题

时间:2018-09-28 18:34:47

标签: c++-cli directshow

当尝试在Euresys UxH264卡的输出中使用 GMFBridge 过滤器时遇到一个奇怪的问题。

我正在尝试将此卡集成到我们的解决方案中,该解决方案依靠GMFBridge处理连续捕获多个文件,执行合并和文件拆分的能力,而不必停止捕获图。

此卡可捕获来自模拟输入的视频和音频。它提供了DirectShow过滤器,可同时显示视频输入的原始流和硬件编码的H.264流。音频流仅作为未压缩的流提供。

当我尝试将Euresys源滤波器的任何输出引脚直接连接到GMFBridge接收器的输入引脚时,它们会被拒绝,代码为VFW_E_NO_ALLOCATOR。 (过去我已经成功地将H.264和原始音频流都连接到了网桥。)

在吸管上抓草,我在Euresys卡式过滤器和桥式水槽过滤器之间插入了一对SampleGrabber过滤器,并且-就像那样-样品采集器和水槽之间的连接被接受。

但是,我在网桥的另一侧(复用图)没有收到任何数据包。我用GraphStudioNext检查了运行中的捕获图,并以某种方式将样品采集器从图形上分离了,即使将它们连接到源过滤器时也得到了成功的确认!

这是创建图形的源代码。

void EuresysSourceBox::BuildGraph() {
   HRESULT hRes;

   CComPtr<IGraphBuilder> pGraph;
   COM_CALL(pGraph.CoCreateInstance(CLSID_FilterGraph));
   #ifdef REGISTER_IN_ROT
      _rotEntry1 = FilterTools::RegisterGraphInROT(IntPtr(pGraph), "euresys graph");
   #endif

   // [*Video Source*]

   String^ filterName = "Ux H.264 Visual Source";
   Guid category = _GUIDToGuid((GUID)AM_KSCATEGORY_CAPTURE);
   FilterMonikerList^ videoSourceList = FilterTools::GetFilterMonikersByName(category, filterName);
   CComPtr<IBaseFilter> pVideoSource;
   int monikerIndex = config->BoardIndex;  // a filter instance will be retrieved for every installed board
   clr_scoped_ptr<CComPtr<IMoniker>>^ ppVideoSourceMoniker = videoSourceList[monikerIndex];

   COM_CALL((*ppVideoSourceMoniker->get())->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pVideoSource));
   COM_CALL(pGraph->AddFilter(pVideoSource, L"VideoSource"));

   // [Video Source]
   //
   // [*Audio Source*]

   filterName = "Ux H.264 Audio Encoder";
   FilterMonikerList^ audioSourceList = FilterTools::GetFilterMonikersByName(category, filterName);
   CComPtr<IBaseFilter> pAudioSource;
   clr_scoped_ptr<CComPtr<IMoniker>>^ ppAudioSourceMoniker = audioSourceList[monikerIndex];
   COM_CALL((*ppAudioSourceMoniker->get())->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pAudioSource));
   COM_CALL(pGraph->AddFilter(pAudioSource, L"AudioSource"));

   CComPtr<IPin> pVideoCompressedOutPin(FilterTools::GetPin(pVideoSource, "Encoded"));
   CComPtr<IPin> pAudioOutPin(FilterTools::GetPin(pAudioSource, "Audio"));

   CComPtr<IBaseFilter> pSampleGrabber;
   COM_CALL(pSampleGrabber.CoCreateInstance(CLSID_SampleGrabber));
   COM_CALL(pGraph->AddFilter(pSampleGrabber, L"SampleGrabber"));
   CComPtr<IPin> pSampleGrabberInPin(FilterTools::GetPin(pSampleGrabber, "Input"));
   COM_CALL(pGraph->ConnectDirect(pVideoCompressedOutPin, pSampleGrabberInPin, NULL));    // DOES NOT FAIL!!


   CComPtr<IBaseFilter> pSampleGrabber2;
   COM_CALL(pSampleGrabber2.CoCreateInstance(CLSID_SampleGrabber));
   COM_CALL(pGraph->AddFilter(pSampleGrabber2, L"SampleGrabber2"));
   CComPtr<IPin> pSampleGrabber2InPin(FilterTools::GetPin(pSampleGrabber2, "Input"));
   COM_CALL(pGraph->ConnectDirect(pAudioOutPin, pSampleGrabber2InPin, NULL));             // DOES NOT FAIL!!

   // [Video Source]---
   //                  |-->[*Bridge Sink*]
   // [Audio Source]---


   CComPtr<IPin> pSampleGrabberOutPin(FilterTools::GetPin(pSampleGrabber, "Output"));
   CComPtr<IPin> pSampleGrabber2OutPin(FilterTools::GetPin(pSampleGrabber2, "Output"));

   CreateGraphBridge(
      IntPtr(pGraph),
      IntPtr(pSampleGrabberOutPin),
      IntPtr(pSampleGrabber2OutPin)
   );

   // Root graph to parent object
   _ppCaptureGraph.reset(new CComPtr<IGraphBuilder>(pGraph));
}

COM_CALL是我的HRESULT检查宏,如果结果不是S_OK,它将引发托管异常。因此,引脚之间的连接成功了,但是下面是该图在运行时的样子:

Disjoint Graph after running

所以,我有三个问题:

1)VFW_E_NO_ALLOCATOR在这种情况下意味着什么?(源过滤器可以成功连接到LAV Video解码器或ffdshow视频解码器等其他组件)。

2)是否有已知的解决方法来规避VFW_E_NO_ALLOCATOR问题?

3)在我看来,过滤器是否可能在运行时断开连接?

1 个答案:

答案 0 :(得分:0)

found a reference by Geraint Davies给出了GMFBridge接收器过滤器可能拒绝连接的原因。

  

解析器似乎坚持使用自己的分配器   -这在解析器中很常见,在解析器中,输出样本只是指向输入样本的指针。但是,桥无法实现   暂停模式,而无需使用其自己的分配器,因此需要一个副本。

利用这些信息,我决定创建一个超简单的CTransformFilter过滤器,该过滤器仅接受网桥提供的分配器并将任何来自输入样本的内容复制到输出样本。我不是100%地确定我所做的是正确的,但是它现在正在起作用。我可以成功地将Euresys卡插入到我的捕获基础结构中。

作为参考,如果有人遇到类似的情况,以下是我创建的过滤器的代码:

class SampleCopyGeneratorFilter : public CTransformFilter {
protected:
   HRESULT CheckInputType(const CMediaType* mtIn) override { return S_OK; }
   HRESULT GetMediaType(int iPosition, CMediaType* pMediaType) override;
   HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) override { return S_OK; }
   HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp) override;
   HRESULT Transform(IMediaSample *pSource, IMediaSample *pDest) override;
public:
   SampleCopyGeneratorFilter();
};

//--------------------------------------------------------------------------------------------------------------------

SampleCopyGeneratorFilter::SampleCopyGeneratorFilter() 
   : CTransformFilter(NAME("SampleCopyGeneratorFilter"), NULL, GUID_NULL)       
{

}


HRESULT SampleCopyGeneratorFilter::GetMediaType(int iPosition, CMediaType* pMediaType) {
   HRESULT hRes;
   ASSERT(m_pInput->IsConnected());
   if( iPosition < 0 )
      return E_INVALIDARG;

   CComPtr<IPin> connectedTo;
   COM_CALL(m_pInput->ConnectedTo(&connectedTo));

   CComPtr<IEnumMediaTypes> pMTEnumerator;
   COM_CALL(connectedTo->EnumMediaTypes(&pMTEnumerator));
   AM_MEDIA_TYPE* pIteratedMediaType;
   for( int i = 0; i <= iPosition; i++ ) {
      if( pMTEnumerator->Next(1, &pIteratedMediaType, NULL) != S_OK )
         return VFW_S_NO_MORE_ITEMS;
      if( i == iPosition )
         *pMediaType = *pIteratedMediaType;
      DeleteMediaType(pIteratedMediaType);
   }
   return S_OK;
}


HRESULT SampleCopyGeneratorFilter::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp) {
   HRESULT hRes;
   AM_MEDIA_TYPE mt;
   COM_CALL(m_pInput->ConnectionMediaType(&mt));
   try {
      BITMAPINFOHEADER* pBMI = HEADER(mt.pbFormat);
      pProp->cbBuffer = DIBSIZE(*pBMI);   // format is compressed, uncompressed size should be enough
      if( !pProp->cbAlign )
         pProp->cbAlign = 1;
      pProp->cbPrefix = 0;
      pProp->cBuffers = 4;

      ALLOCATOR_PROPERTIES actualProperties;
      COM_CALL(pAlloc->SetProperties(pProp, &actualProperties));
      if( pProp->cbBuffer > actualProperties.cbBuffer )
         return E_FAIL;
      return S_OK;
   } finally{
      FreeMediaType(mt);
   }
}


HRESULT SampleCopyGeneratorFilter::Transform(IMediaSample *pSource, IMediaSample *pDest) {
   HRESULT hRes;
   BYTE* pBufferIn;
   BYTE* pBufferOut;
   long destSize = pDest->GetSize();
   long dataLen = pSource->GetActualDataLength();
   if( dataLen > destSize )
      return VFW_E_BUFFER_OVERFLOW;
   COM_CALL(pSource->GetPointer(&pBufferIn));
   COM_CALL(pDest->GetPointer(&pBufferOut));
   memcpy(pBufferOut, pBufferIn, dataLen);
   pDest->SetActualDataLength(dataLen);
   pDest->SetSyncPoint(pSource->IsSyncPoint() == S_OK);
   return S_OK;
}

这是我在捕获图中插入过滤器的方式:

   CComPtr<IPin> pAACEncoderOutPin(FilterTools::GetPin(pAACEncoder, "XForm Out"));
   CComPtr<IPin> pVideoSourceCompressedOutPin(FilterTools::GetPin(pVideoSource, "Encoded"));

   CComPtr<IBaseFilter> pSampleCopier;
   pSampleCopier = new SampleCopyGeneratorFilter();
   COM_CALL(pGraph->AddFilter(pSampleCopier, L"SampleCopier"));
   CComPtr<IPin> pSampleCopierInPin(FilterTools::GetPin(pSampleCopier, "XForm In"));
   COM_CALL(pGraph->ConnectDirect(pVideoSourceCompressedOutPin, pSampleCopierInPin, NULL));
   CComPtr<IPin> pSampleCopierOutPin(FilterTools::GetPin(pSampleCopier, "XForm Out"));


   CreateGraphBridge(
      IntPtr(pGraph),
      IntPtr(pSampleCopierOutPin),
      IntPtr(pAACEncoderOutPin)
   );

现在,我仍然不知道为什么插入样本采集卡不起作用,并导致图形分离。我也通过使用Graphedit Plus检查图形来证实了这个怪癖。如果有人可以给我一个解释,我的确会非常感激。