如何将对象连接到过滤器图?
How to connect object to the filter graph?
我需要做的是 - 从 DirectShow
获取解码的样本帧(如 vector<frames>
)为了做到这一点我遵循这个实现 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
,根据这个错误 table https://docs.microsoft.com/en-us/windows/win32/directshow/error-and-success-codes 意味着
Cannot perform the requested function on an object that is not in the filter graph.
我看到文档中有一个示例 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
-
Pins cannot connect because they don't support the same transport.
For example, the upstream filter might require the IAsyncReader interface, while the downstream filter requires 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
会有一个属于过滤器图的合适的 pin
- Sample Grabber 初始化为媒体类型
MEDIATYPE_Stream
,这与您解码音频的意图相矛盾(您需要 MEDIATYPE_Audio
、MEDIASUBTYPE_PCM
)
- 使用
Render
方法通常不是一个好主意;我将离开 this reference 阅读有关使用 DirectShow Intelligent Connect 的相关问题
因为你似乎主要是试图让它工作蒙住眼睛,使用 GraphStudioNext (analog of SDK GraphEdit 工具可能是个好主意)并以交互方式构建管道以了解你需要什么样的过滤器图建造。届时您将更好地了解如何从代码构建类似的 gaph。
我需要做的是 - 从 DirectShow
获取解码的样本帧(如 vector<frames>
)为了做到这一点我遵循这个实现 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
,根据这个错误 table https://docs.microsoft.com/en-us/windows/win32/directshow/error-and-success-codes 意味着
Cannot perform the requested function on an object that is not in the filter graph.
我看到文档中有一个示例 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
-
Pins cannot connect because they don't support the same transport. For example, the upstream filter might require the IAsyncReader interface, while the downstream filter requires 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
会有一个属于过滤器图的合适的 pin - Sample Grabber 初始化为媒体类型
MEDIATYPE_Stream
,这与您解码音频的意图相矛盾(您需要MEDIATYPE_Audio
、MEDIASUBTYPE_PCM
) - 使用
Render
方法通常不是一个好主意;我将离开 this reference 阅读有关使用 DirectShow Intelligent Connect 的相关问题
因为你似乎主要是试图让它工作蒙住眼睛,使用 GraphStudioNext (analog of SDK GraphEdit 工具可能是个好主意)并以交互方式构建管道以了解你需要什么样的过滤器图建造。届时您将更好地了解如何从代码构建类似的 gaph。