Comment connecter un objet au graphique de filtre?

Nov 22 2020

Ce que je dois faire est - obtenir des images d'échantillons décodées (comme vector<frames>) DirectShowpour 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&quot;Source&quot;, &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_pMemReaderau graphique j'ai ajouté cette ligne

hr = m_pGraph->AddFilter(m_pMemReader, NULL);

Ensuite, dans je définis le type de support lorsque MEDIATYPE_Audioj'obtiens une erreur 0x80040200- The specified media type is invalid., si j'essaie d'utiliser le type de support lorsque MEDIATYPE_Streamj'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 CMemReadersous 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

1 user123 Nov 22 2020 at 19:07

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
}
1 RomanR. Nov 22 2020 at 20:18

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:

  1. il n'y a aucune raison visible pour laquelle m_pMemReaderaurait une broche appropriée qui appartient au graphique de filtre
  2. Sample Grabber est initialisé avec un type de média MEDIATYPE_Streamqui contredit votre intention d'avoir décodé l'audio (vous auriez besoin MEDIATYPE_Audio, à la MEDIASUBTYPE_PCMplace)
  3. ce n'est généralement pas une bonne idée d'utiliser la Rendermé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.