Comment connecter un objet au graphique de filtre?
Ce que je dois faire est - obtenir des images d'échantillons décodées (comme vector<frames>
) DirectShow
pour le faire Je suis cette implémentationhttps://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber
Il y a ma mise en œuvre
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;
}
J'obtiens une erreur ici:
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;
}
Le code d'erreur est - 0x8004025F
, qui selon cette table d'erreurhttps://docs.microsoft.com/en-us/windows/win32/directshow/error-and-success-codes signifie que
Impossible d'exécuter la fonction demandée sur un objet qui ne figure pas dans le graphique de filtre.
Je vois qu'il y a un exemple dans la doc https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber#build-the-filter-graph
Mais cet exemple utilise le chemin d'accès au fichier comme premier paramètre dans cette méthode pGraph->AddSourceFilter(pszVideoFile, L"Source", &pSourceF)
, je n'ai pas de chemin d'accès au fichier à la place m_pMemReader = new CMemReader(m_pMemStream, m_pMediaType, &hr)
.
La question est - Comment connecter un objet au graphique de filtre si je l'ai CMemReader
?
ÉDITER
changé ces lignes
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
Afin d'inclure m_pMemReader
au graphique j'ai ajouté cette ligne
hr = m_pGraph->AddFilter(m_pMemReader, NULL);
Ensuite, dans je définis le type de support lorsque MEDIATYPE_Audio
j'obtiens une erreur 0x80040200
- The specified media type is invalid.
, si j'essaie d'utiliser le type de support lorsque MEDIATYPE_Stream
j'obtiens une erreur de suivi 0x80040266
-
Les broches ne peuvent pas se connecter car elles ne prennent pas en charge le même transport. Par exemple, le filtre en amont peut nécessiter l'interface IAsyncReader, tandis que le filtre en aval nécessite IMemInputPin.
Quel est le problème ici? Ce que je comprends d'ici, c'est - mon filtre en amont est CMemReader * m_pMemReader;
, mais CMemReader
sous le capot dont il hérite IBaseFilter
, alors mon en aval est IBaseFilter * m_pGrabberF;
ce qui l'est aussi IBaseFilter
. Qu'est-ce que j'oublie ici?
Réponses
DirectShow est obsolète. Vous devez utiliser MediaFoundation à la place. Je ne l'ai pas testé mais je pense que le code suivant décodera l'audio et vous permettra de manipuler des images audio brutes (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
}
Il y a quelques problèmes avec le code et dans l'ensemble, l'extrait de code est incohérent, ne disant même pas qu'on ne peut pas le construire. Vous devriez probablement créer un petit projet et le télécharger sur GitHub pour l'utiliser comme référence.
Les problèmes à résoudre sont:
- il n'y a aucune raison visible pour laquelle
m_pMemReader
aurait une broche appropriée qui appartient au graphique de filtre - Sample Grabber est initialisé avec un type de média
MEDIATYPE_Stream
qui contredit votre intention d'avoir décodé l'audio (vous auriez besoinMEDIATYPE_Audio
, à laMEDIASUBTYPE_PCM
place) - ce n'est généralement pas une bonne idée d'utiliser la
Render
méthode du tout; Je laisserai cette référence pour lire quels problèmes sont associés à l'utilisation de DirectShow Intelligent Connect
Puisque vous semblez surtout essayer de le faire fonctionner les yeux bandés, il serait probablement une bonne idée d'utiliser GraphStudioNext (analogue de l' outil SDK GraphEdit ) et de créer des pipelines de manière interactive pour avoir une idée du type de graphique de filtre que vous auriez besoin de créer. Vous aurez alors une meilleure idée de la construction de gaph similaire à partir du code.