Проблемы с подключением к входным контактам GMFBridge Sink Filter - PullRequest
0 голосов
/ 28 сентября 2018

Возникает странная проблема при попытке использования фильтра GMFBridge с выходом карты Euresys UxH264.

Я пытаюсь интегрировать эту карту в наше решение, которое использует GMFBridge для обеспечения возможности непрерывного захвата нескольких файлов, выполнения мультиплексирования и разделения файлов без необходимости остановки графа захвата.

Эта карта записывает видео и аудио с аналоговых входов.Он обеспечивает фильтр DirectShow, представляющий как необработанный поток видеовхода, так и аппаратно-кодированный поток H.264.Аудиопоток предоставляется только в виде несжатого потока.

Когда я пытаюсь напрямую подключить любой из выходных выводов исходных фильтров Euresys к входным выводам приемника GMFBridge, они отклоняются вместе с кодом VFW_E_NO_ALLOCATOR.(В прошлом я успешно подключал к мосту и H.264, и необработанные аудиопотоки).

Захватив соломинку, я подключил пару фильтров SampleGrabber между фильтрами карт Euresys и фильтром приемника моста,и - просто так - соединения между образцами и приемником были приняты.

Однако я не получаю никаких пакетов на другой стороне моста (граф мультиплексирования).Я проверил текущий график захвата с помощью 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 или видео декодер ffdshow).

2) Существует ли известный обходной путь, позволяющий обойти проблему VFW_E_NO_ALLOCATOR?

3) Возможно ли, что фильтр отключается во время работы, как это происходит в моемслучай

1 Ответ

0 голосов
/ 29 сентября 2018

I нашел ссылку 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.Если кто-нибудь может дать мне объяснение, я был бы очень благодарен.

...