How to connect object to the filter graph?

0

What I need to do is - get decoded sample frames (like vector<frames>) from DirectShow in order to do it I follow this implementation https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber

There is my implementation

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

I get an error here :

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

Error code is - 0x8004025F, which according to this error table https://docs.microsoft.com/en-us/windows/win32/directshow/error-and-success-codes means that

Cannot perform the requested function on an object that is not in the filter graph.

I see there is an example in doc https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber#build-the-filter-graph

But this an example use path to file as a first param in this method pGraph->AddSourceFilter(pszVideoFile, L&quot;Source&quot;, &pSourceF), I don't have path to file instead I have m_pMemReader = new CMemReader(m_pMemStream, m_pMediaType, &hr).

Question is - How to connect object to the filter graph if I have CMemReader ?

EDIT

changed these lines

    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

In order to include m_pMemReader to graph I added this line

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

Then in I set media type as MEDIATYPE_Audio I get an error 0x80040200 - The specified media type is invalid. , if I try to use media type as MEDIATYPE_Stream I get follow error 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.

What is a problem here? What I undrstand from here is - my upstream filter is CMemReader * m_pMemReader; , but CMemReader under the hood it inherit from IBaseFilter, then my downstream is IBaseFilter * m_pGrabberF; which is also IBaseFilter. What am I missing here?

c++
audio
directshow
asked on Stack Overflow Nov 22, 2020 by Aleksey Timoshchenko • edited Nov 23, 2020 by Aleksey Timoshchenko

2 Answers

1

DirectShow is outdated. You should use MediaFoundation instead. I didn't test it but I think the following code will decode audio and let you manipulate raw audio frames (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
}
answered on Stack Overflow Nov 22, 2020 by user123
1

There are a few problems with the code and overall the code snippet is inconsistent, not even telling that one can't build it. You should probably create a small project and upload to GitHub to use as a reference.

Problems to resolve are:

  1. there is no visible reason why m_pMemReader would have a suitable pin that belongs to filter graph
  2. Sample Grabber is initialized with media type MEDIATYPE_Stream which contradicts to your intent to have decoded audio (you would need MEDIATYPE_Audio, MEDIASUBTYPE_PCM instead)
  3. it is generally not a good idea to use Render method at all; I will leave this reference to read up on what problems are associated with use of DirectShow Intelligent Connect

Since you seem to be mostly trying to make it work blindfold, it would probably be a good idea to use GraphStudioNext (analog of SDK GraphEdit tool) and build pipelines interactively to get an idea what kind of filter graph you would need to build. You will get a better idea about building similar gaph from code then.

answered on Stack Overflow Nov 22, 2020 by Roman R. • edited Nov 22, 2020 by Roman R.

User contributions licensed under CC BY-SA 3.0