如何将对象连接到过滤图? [英] How to connect object to the filter graph?

查看:46
本文介绍了如何将对象连接到过滤图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要做的-从 DirectShow 获取解码后的样本帧(例如 vector< frames> ),为了做到这一点,我遵循此实现 https://docs.microsoft.com/zh-cn/Windows/Win32/DirectShow/using-the-sample-grabber

有我的实现方式

  bool coAudioPlayerSampleGrabber :: LoadImp(SoundDataType dataType,unsigned char const * pData,int64_t dataLen){清理(​​);m_bReady = false;HRESULT hr = S_OK;assert(pData);断言(dataLen);m_memBuffer.resize(dataLen);memcpy(m_memBuffer.data(),pData,dataLen);m_memBufferDataType = dataType;m_pMediaType = new CMediaType();m_pMediaType-> majortype = MEDIATYPE_Stream;开关(数据类型){情况SoundDataType :: WAV:m_pMediaType-> subtype = MEDIASUBTYPE_WAVE;休息;情况SoundDataType :: MP3:m_pMediaType-> subtype = MEDIASUBTYPE_MPEG1Audio;休息;默认值:返回false;否则返回false.}m_pMemStream = new CMemStream((BYTE *)m_memBuffer.data(),m_memBuffer.size());m_pMemReader =新的CMemReader(m_pMemStream,m_pMediaType,& hr);如果(FAILED(hr)|| m_pMemReader == NULL){printf(无法创建过滤器-HRESULT 0x%8.8X \ n",hr);返回false;}//确保我们不会意外消失!m_pMemReader-> AddRef();//***创建过滤器图形管理器hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(& m_pGraph));如果(FAILED(hr)){如果(hr == CO_E_NOTINITIALIZED){printf("coAudioPlayerSampleGrabberImplementation :: Load:FAILED CoCreateInstance(CLSID_FilterGraph,...)FAILED hRes:%x(未调用CoInitialize)\ n",hr);}别的{printf("coAudioPlayerSampleGrabberImplementation :: Load:FAILED CoCreateInstance(CLSID_FilterGraph FAILED hRes:%x \ n,hr);}返回false;}hr = m_pGraph-> QueryInterface(IID_PPV_ARGS(& m_pControl));如果(FAILED(hr)){std :: cout<<"coAudioPlayerSampleGrabberImplementation :: Load:FAILED QueryInterface IMediaControl"<<std :: endl;返回false;}hr = m_pGraph-> QueryInterface(IID_PPV_ARGS(& m_pEvent));如果(FAILED(hr)){std :: cout<<"coAudioPlayerSampleGrabberImplementation :: Load:FAILED QueryInterface IMediaEventEx"<<std :: endl;返回false;}//***结束创建过滤器图形管理器//***将样本抓取器添加到过滤器图形//创建Sample Grabber过滤器.hr = CoCreateInstance(CLSID_SampleGrabber,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(& m_pGrabberF));如果(FAILED(hr)){std :: cout<<"coAudioPlayerSampleGrabberImplementation :: Load:FAILED CoCreateInstance CLSID_SampleGrabber"<<std :: endl;返回false;}hr = m_pGraph-> AddFilter(m_pGrabberF,LPCWSTR("Sample Grabber")));如果(FAILED(hr)){std :: cout<<"coAudioPlayerSampleGrabberImplementation :: Load:FAILED AddFilter m_pGrabberF"<<std :: endl;返回false;}hr = m_pGrabberF-> QueryInterface(IID_PPV_ARGS(& m_pGrabber));如果(FAILED(hr)){std :: cout<<"coAudioPlayerSampleGrabberImplementation :: Load:FAILED QueryInterface ISampleGrabber"<<std :: endl;返回false;}//***结束将Sample Grabber添加到过滤器图//***设置媒体类型hr = m_pGrabber-> SetMediaType(m_pMediaType);如果(FAILED(hr)){std :: cout<<"coAudioPlayerSampleGrabberImplementation :: Load:FAILED SetMediaType"<<std :: endl;返回false;}//*** end设置媒体类型IPin * ppinOut = m_pMemReader-> GetPin(0);hr = m_pGraph-> Render(ppinOut);如果(FAILED(hr)){printf("coAudioPlayerSampleGrabberImplementation :: Load:FAILED无法从数据中加载(渲染)音频文件(hRes:%x)\ n",hr);返回false;}m_bReady = true;返回m_bReady;} 

我在这里遇到错误:

  IPin * ppinOut = m_pMemReader-> GetPin(0);hr = m_pGraph-> Render(ppinOut);如果(FAILED(hr))< -------------在这里!!{printf("TV_AudioPlayerSampleGrabberImplementation :: Load:FAILED无法从数据(hRes:%x)中加载(渲染)音频文件",hr);返回false;} 

错误代码为- 0x8004025F ,根据此错误表 https://docs.microsoft.com/zh-cn/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;< ----------第一行开关(数据类型){//案例SoundDataType :: WAV:m_pMediaType-> subtype = MEDIASUBTYPE_WAVE;休息;情况SoundDataType :: WAV:m_pMediaType-> subtype = MEDIASUBTYPE_PCM;休息;< --------第二行情况SoundDataType :: MP3:m_pMediaType-> subtype = MEDIASUBTYPE_MPEG1Audio;休息;默认值:返回false;否则返回false.} 

EDIT2

为了在图形中包含 m_pMemReader ,我添加了这一行

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

然后在我将媒体类型设置为 MEDIATYPE_Audio 时出现错误 0x80040200 -指定的媒体类型无效.,如果我尝试将媒体类型用作 MEDIATYPE_Stream 我得到关注错误 0x80040266 -

针无法连接,因为它们不支持相同的传输.例如,上游过滤器可能需要IAsyncReader接口,而下游过滤器则需要IMemInputPin.

这是什么问题?我从这里无法理解的是-我的上游过滤器是 CMemReader * m_pMemReader; ,但是 CMemReader 是它继承自 IBaseFilter ,然后是我的下游是 IBaseFilter * m_pGrabberF; ,它也是 IBaseFilter .我在这里想念什么?

解决方案

DirectShow已过时.您应该改用MediaFoundation.我没有对其进行测试,但是我认为以下代码将解码音频并让您处理原始音频帧( SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,NULL,pPartialType);}hr = pReader-> GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,& type);//使用类型指向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);//使用pAudioData做某事,pAudioData是lenth cbBuffer的无符号字符数组}

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?

解决方案

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
}

这篇关于如何将对象连接到过滤图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆