Wie verbinde ich ein Objekt mit dem Filtergraphen?

Nov 22 2020

Was ich tun muss, ist - dekodierte Beispielrahmen (wie vector<frames>) DirectShowzu erhalten, um dies zu tun, folge ich dieser Implementierunghttps://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber

Da ist meine Implementierung

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;
}

Ich erhalte hier eine Fehlermeldung:

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;
    }

Fehlercode ist - 0x8004025F, was laut dieser Fehlertabellehttps://docs.microsoft.com/en-us/windows/win32/directshow/error-and-success-codes bedeutet, dass

Die angeforderte Funktion kann nicht für ein Objekt ausgeführt werden, das sich nicht im Filterdiagramm befindet.

Ich sehe, dass es ein Beispiel in doc gibt https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber#build-the-filter-graph

In diesem Beispiel wird der Pfad zur Datei als erster Parameter in dieser Methode verwendet. Stattdessen habe pGraph->AddSourceFilter(pszVideoFile, L&quot;Source&quot;, &pSourceF)ich keinen Pfad zur Datei m_pMemReader = new CMemReader(m_pMemStream, m_pMediaType, &hr).

Die Frage ist - Wie verbinde ich ein Objekt mit dem Filterdiagramm, wenn ich habe CMemReader?

BEARBEITEN

änderte diese Zeilen

    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

Um das m_pMemReaderDiagramm aufzunehmen, habe ich diese Linie hinzugefügt

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

Dann setze ich den Medientyp , wenn ich MEDIATYPE_Audioeine Fehlermeldung erhalte 0x80040200- The specified media type is invalid.wenn ich versuche, den Medientyp zu verwenden, wenn MEDIATYPE_Streamich den folgenden Fehler erhalte 0x80040266-

Pins können keine Verbindung herstellen, da sie nicht denselben Transport unterstützen. Beispielsweise erfordert der Upstream-Filter möglicherweise die IAsyncReader-Schnittstelle, während der Downstream-Filter IMemInputPin erfordert.

Was ist hier ein Problem? Was ich von hier aus nicht verstehe, ist - mein vorgelagerter Filter ist CMemReader * m_pMemReader;, aber CMemReaderunter der Haube, von der er erbt IBaseFilter, dann ist mein nachgelagerter, IBaseFilter * m_pGrabberF;der auch ist IBaseFilter. Was fehlt mir hier?

Antworten

1 user123 Nov 22 2020 at 19:07

DirectShow ist veraltet. Sie sollten stattdessen MediaFoundation verwenden. Ich habe es nicht getestet, aber ich denke, der folgende Code wird Audio dekodieren und Sie können rohe Audio-Frames manipulieren (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

Es gibt ein paar Probleme mit dem Code und insgesamt ist das Code-Snippet inkonsistent und sagt nicht einmal, dass man es nicht erstellen kann. Sie sollten wahrscheinlich ein kleines Projekt erstellen und auf GitHub hochladen, um es als Referenz zu verwenden.

Zu lösende Probleme sind:

  1. Es gibt keinen sichtbaren Grund, warum m_pMemReaderein geeigneter Pin zum Filtergraphen gehört
  2. Beispiel Grabber mit Medientyp initialisiert , MEDIATYPE_Streamdie im Widerspruch zu Ihrer Absicht Audio dekodiert haben (Sie müssen MEDIATYPE_Audio, MEDIASUBTYPE_PCMstatt)
  3. Es ist im Allgemeinen keine gute Idee, überhaupt eine RenderMethode anzuwenden . Ich werde diese Referenz verlassen, um zu erfahren, welche Probleme mit der Verwendung von DirectShow Intelligent Connect verbunden sind

Da Sie anscheinend hauptsächlich versuchen, es mit verbundenen Augen zum Laufen zu bringen, ist es wahrscheinlich eine gute Idee, GraphStudioNext (analog zum SDK GraphEdit- Tool) zu verwenden und Pipelines interaktiv zu erstellen, um eine Vorstellung davon zu erhalten, welche Art von Filterdiagramm Sie erstellen müssten. Sie erhalten dann eine bessere Vorstellung davon, wie Sie aus Code eine ähnliche Grafik erstellen können.