개체를 필터 그래프에 연결하는 방법은 무엇입니까?
내가해야 할 것은 - (같은 샘플 프레임을 디코딩 얻을 vector<frames>
에서) DirectShow
나는이 구현에 따라 그것을하기 위해https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber
내 구현이 있습니다
bool coAudioPlayerSampleGrabber::LoadImp(SoundDataType dataType,
unsigned char const * pData,
int64_t dataLen)
{
Cleanup();
m_bReady = false;
HRESULT hr = S_OK;
assert(pData);
assert(dataLen);
m_memBuffer.resize(dataLen);
memcpy(m_memBuffer.data(), pData, dataLen);
m_memBufferDataType = dataType;
m_pMediaType = new CMediaType();
m_pMediaType->majortype = MEDIATYPE_Stream;
switch (dataType)
{
case SoundDataType::WAV: m_pMediaType->subtype = MEDIASUBTYPE_WAVE; break;
case SoundDataType::MP3: m_pMediaType->subtype = MEDIASUBTYPE_MPEG1Audio; break;
default: return false;
}
m_pMemStream = new CMemStream((BYTE*)m_memBuffer.data(), m_memBuffer.size());
m_pMemReader = new CMemReader(m_pMemStream, m_pMediaType, &hr);
if (FAILED(hr) || m_pMemReader == NULL)
{
printf("Could not create filter - HRESULT 0x%8.8X\n", hr);
return false;
}
// Make sure we don't accidentally go away!
m_pMemReader->AddRef();
// *** Create the Filter Graph Manager
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pGraph));
if (FAILED(hr))
{
if (hr == CO_E_NOTINITIALIZED)
{
printf("coAudioPlayerSampleGrabberImplementation::Load: FAILED CoCreateInstance(CLSID_FilterGraph,...) FAILED hRes: %x (CoInitialize has not been called)\n", hr);
}
else
{
printf("coAudioPlayerSampleGrabberImplementation::Load: FAILED CoCreateInstance(CLSID_FilterGraph FAILED hRes: %x\n", hr);
}
return false;
}
hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pControl));
if (FAILED(hr))
{
std::cout << "coAudioPlayerSampleGrabberImplementation::Load: FAILED QueryInterface IMediaControl" << std::endl;
return false;
}
hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pEvent));
if (FAILED(hr))
{
std::cout << "coAudioPlayerSampleGrabberImplementation::Load: FAILED QueryInterface IMediaEventEx" << std::endl;
return false;
}
// *** end Create the Filter Graph Manager
// *** Add the Sample Grabber to the Filter Graph
// Create the Sample Grabber filter.
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_pGrabberF));
if (FAILED(hr))
{
std::cout << "coAudioPlayerSampleGrabberImplementation::Load: FAILED CoCreateInstance CLSID_SampleGrabber" << std::endl;
return false;
}
hr = m_pGraph->AddFilter(m_pGrabberF, LPCWSTR("Sample Grabber"));
if (FAILED(hr))
{
std::cout << "coAudioPlayerSampleGrabberImplementation::Load: FAILED AddFilter m_pGrabberF" << std::endl;
return false;
}
hr = m_pGrabberF->QueryInterface(IID_PPV_ARGS(&m_pGrabber));
if (FAILED(hr))
{
std::cout << "coAudioPlayerSampleGrabberImplementation::Load: FAILED QueryInterface ISampleGrabber" << std::endl;
return false;
}
// *** end Add the Sample Grabber to the Filter Graph
// *** Set the Media Type
hr = m_pGrabber->SetMediaType(m_pMediaType);
if (FAILED(hr))
{
std::cout << "coAudioPlayerSampleGrabberImplementation::Load: FAILED SetMediaType" << std::endl;
return false;
}
// *** end Set the Media Type
IPin *ppinOut = m_pMemReader->GetPin(0);
hr = m_pGraph->Render(ppinOut);
if (FAILED(hr))
{
printf("coAudioPlayerSampleGrabberImplementation::Load: FAILED to load (Render) audio file from data (hRes: %x)\n", hr);
return false;
}
m_bReady = true;
return m_bReady;
}
여기에 오류가 발생합니다.
IPin *ppinOut = m_pMemReader->GetPin(0);
hr = m_pGraph->Render(ppinOut);
if (FAILED(hr)) <------------- HERE!!
{
printf("TV_AudioPlayerSampleGrabberImplementation::Load: FAILED to load (Render) audio file from data (hRes: %x)\n", hr);
return false;
}
오류 코드는-이며이 0x8004025F
오류 테이블에 따라https://docs.microsoft.com/en-us/windows/win32/directshow/error-and-success-codes 의미
필터 그래프에없는 개체에 대해 요청 된 기능을 수행 할 수 없습니다.
문서에 예제가 있음을 알았습니다. https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber#build-the-filter-graph
그러나이 예제에서는이 메서드에서 첫 번째 매개 변수 pGraph->AddSourceFilter(pszVideoFile, L"Source", &pSourceF)
로 파일 경로를 사용합니다. 대신 파일 경로가 없습니다 m_pMemReader = new CMemReader(m_pMemStream, m_pMediaType, &hr)
.
질문은-내가 가진 경우 개체를 필터 그래프에 연결하는 방법은 CMemReader
무엇입니까?
편집하다
이 라인을 변경
m_pMediaType = new CMediaType();
m_pMediaType->majortype = MEDIATYPE_Audio; <---------- First line
switch (dataType)
{
//case SoundDataType::WAV: m_pMediaType->subtype = MEDIASUBTYPE_WAVE; break;
case SoundDataType::WAV: m_pMediaType->subtype = MEDIASUBTYPE_PCM; break; <-------- Second line
case SoundDataType::MP3: m_pMediaType->subtype = MEDIASUBTYPE_MPEG1Audio; break;
default: return false;
}
EDIT2
m_pMemReader
그래프 에 포함 하기 위해이 선을 추가했습니다.
hr = m_pGraph->AddFilter(m_pMemReader, NULL);
그런 다음 MEDIATYPE_Audio
오류가 발생하면 미디어 유형을 설정합니다 0x80040200
- The specified media type is invalid.
, MEDIATYPE_Stream
후속 오류가 발생할 때 미디어 유형을 사용하려고하면 0x80040266
-
핀은 동일한 전송을 지원하지 않기 때문에 연결할 수 없습니다. 예를 들어 업스트림 필터에는 IAsyncReader 인터페이스가 필요한 반면 다운 스트림 필터에는 IMemInputPin이 필요할 수 있습니다.
여기서 문제는 무엇입니까? 여기에서 내가 이해하지 못하는 것은-내 업스트림 필터가 CMemReader * m_pMemReader;
있지만 CMemReader
내부적으로는 상속받은 IBaseFilter
다음 내 다운 스트림 IBaseFilter * m_pGrabberF;
도 마찬가지 IBaseFilter
입니다. 내가 여기서 무엇을 놓치고 있습니까?
답변
DirectShow가 오래되었습니다. 대신 MediaFoundation을 사용해야합니다. 나는 그것을 테스트하지 않았지만 다음 코드가 오디오를 디코딩하고 원시 오디오 프레임을 조작 할 수 있다고 생각합니다.https://docs.microsoft.com/en-us/windows/win32/medfound/tutorial--decoding-audio) :
IMFSourceReader *pReader = NULL;
hr = MFCreateSourceReaderFromURL(L"C:\\users\\video", NULL, &pReader);
if (FAILED(hr))
{
printf("Error opening input file");
}
IMFMediaType *type = NULL;
IMFMediaType *pPartialType = NULL;
hr = MFCreateMediaType(&pPartialType);
hr = pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
hr = pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
// Set this type on the source reader. The source reader will
// load the necessary decoder.
if (SUCCEEDED(hr))
{
hr = pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, pPartialType);
}
hr = pReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, &type);
//Do something with type which is a pointer to IMFMediaType
IMFSample *pSample = NULL;
IMFMediaBuffer *pBuffer = NULL;
BYTE *pAudioData = NULL;
DWORD cbBuffer = 0;
while(true){
DWORD dwFlags = 0;
hr = pReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &dwFlags, NULL, &pSample);
hr = pSample->ConvertToContiguousBuffer(&pBuffer);
hr = pBuffer->Lock(&pAudioData, NULL, &cbBuffer);
//Do something with the pAudioData which is an array of unsigned chars of lenth cbBuffer
}
코드에는 몇 가지 문제가 있으며 전체 코드 스 니펫은 일관성이 없어서 빌드 할 수 없다는 사실조차 알려주지 않습니다. 작은 프로젝트를 만들고 GitHub에 업로드하여 참조로 사용해야합니다.
해결해야 할 문제는 다음과 같습니다.
m_pMemReader
필터 그래프에 속하는 적합한 핀이있는 가시적 인 이유가 없습니다.- 샘플 그래버는 미디어 타입으로 초기화됩니다
MEDIATYPE_Stream
의도에 모순 오디오를 디코딩 한 수 (당신이 필요로하는 것MEDIATYPE_Audio
,MEDIASUBTYPE_PCM
대신) - 일반적으로
Render
방법 을 사용하는 것은 좋지 않습니다 . DirectShow Intelligent Connect 사용과 관련된 문제에 대해 읽어보기 위해이 참조 를 남겨 두겠습니다.
대부분 눈가리개로 작동하도록하는 것 같기 때문에 GraphStudioNext (SDK GraphEdit 도구의 아날로그 )를 사용하고 파이프 라인을 대화 형으로 빌드하여 어떤 종류의 필터 그래프를 빌드해야하는지 파악하는 것이 좋습니다. 그러면 코드에서 유사한 gaph를 작성하는 방법에 대해 더 나은 아이디어를 얻을 수 있습니다.