개체를 필터 그래프에 연결하는 방법은 무엇입니까?

Nov 22 2020

내가해야 할 것은 - (같은 샘플 프레임을 디코딩 얻을 vector<frames>에서) DirectShow나는이 구현에 따라 그것을하기 위해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오류 테이블에 따라https://docs.microsoft.com/en-us/windows/win32/directshow/error-and-success-codes 의미

필터 그래프에없는 개체에 대해 요청 된 기능을 수행 할 수 없습니다.

문서에 예제가 있음을 알았습니다. https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber#build-the-filter-graph

그러나이 예제에서는이 메서드에서 첫 번째 매개 변수 pGraph->AddSourceFilter(pszVideoFile, L&quot;Source&quot;, &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-

핀은 동일한 전송을 지원하지 않기 때문에 연결할 수 없습니다. 예를 들어 업스트림 필터에는 IAsyncReader 인터페이스가 필요한 반면 다운 스트림 필터에는 IMemInputPin이 필요할 수 있습니다.

여기서 문제는 무엇입니까? 여기에서 내가 이해하지 못하는 것은-내 업스트림 필터가 CMemReader * m_pMemReader;있지만 CMemReader내부적으로는 상속받은 IBaseFilter다음 내 다운 스트림 IBaseFilter * m_pGrabberF;도 마찬가지 IBaseFilter입니다. 내가 여기서 무엇을 놓치고 있습니까?

답변

1 user123 Nov 22 2020 at 19:07

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

코드에는 몇 가지 문제가 있으며 전체 코드 스 니펫은 일관성이 없어서 빌드 할 수 없다는 사실조차 알려주지 않습니다. 작은 프로젝트를 만들고 GitHub에 업로드하여 참조로 사용해야합니다.

해결해야 할 문제는 다음과 같습니다.

  1. m_pMemReader필터 그래프에 속하는 적합한 핀이있는 가시적 인 이유가 없습니다.
  2. 샘플 그래버는 미디어 타입으로 초기화됩니다 MEDIATYPE_Stream의도에 모순 오디오를 디코딩 한 수 (당신이 필요로하는 것 MEDIATYPE_Audio, MEDIASUBTYPE_PCM대신)
  3. 일반적으로 Render방법 을 사용하는 것은 좋지 않습니다 . DirectShow Intelligent Connect 사용과 관련된 문제에 대해 읽어보기 위해이 참조 를 남겨 두겠습니다.

대부분 눈가리개로 작동하도록하는 것 같기 때문에 GraphStudioNext (SDK GraphEdit 도구의 아날로그 )를 사용하고 파이프 라인을 대화 형으로 빌드하여 어떤 종류의 필터 그래프를 빌드해야하는지 파악하는 것이 좋습니다. 그러면 코드에서 유사한 gaph를 작성하는 방법에 대해 더 나은 아이디어를 얻을 수 있습니다.