如何将对象连接到过滤器图?

Posted

技术标签:

【中文标题】如何将对象连接到过滤器图?【英文标题】:How to connect object to the filter graph? 【发布时间】:2020-11-22 18:15:56 【问题描述】:

我需要做的是 - 从DirectShow 获取解码的样本帧(如vector<frames>)为了做到这一点我遵循这个实现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-&gt;AddSourceFilter(pszVideoFile, L&amp;quot;Source&amp;quot;, &amp;pSourceF) 中的第一个参数的示例,我没有文件路径而是m_pMemReader = new CMemReader(m_pMemStream, m_pMediaType, &amp;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; ,但在它从 IBaseFilter 继承的引擎盖下是 CMemReader,那么我的下游是 IBaseFilter * m_pGrabberF; 也是 IBaseFilter。我在这里错过了什么?

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

代码存在一些问题,总体而言,sn-p 代码不一致,甚至没有说无法构建它。您可能应该创建一个小项目并上传到 GitHub 以用作参考。

要解决的问题是:

    m_pMemReader 有一个合适的属于过滤图的 pin 没有明显的原因 Sample Grabber 使用媒体类型 MEDIATYPE_Stream 进行初始化,这与您解码音频的意图相矛盾(您需要 MEDIATYPE_AudioMEDIASUBTYPE_PCM 代替) 一般来说使用Render方法根本不是一个好主意;我将离开this reference 了解与使用 DirectShow Intelligent Connect 相关的问题

由于您似乎主要是试图让它蒙住眼睛,因此使用GraphStudioNext(类似于 SDK GraphEdit 工具)并以交互方式构建管道以了解什么样的过滤器图可能是一个好主意你需要建造。然后,您将更好地了解如何从代码中构建类似的间隙。

【讨论】:

我编辑了我的问题,我的编辑与关于类型的案例 2 相关。但是我对案例 1 和 3 并没有真正了解。关于我看到的第一个案例 - 我创建了 CMemReader 给它一个源字节流,而不是我得到 IPin 并将它传递给 Render,所以我认为它应该开始渲染给定的源流,不是吗?关于案例 3 - 但我需要改用什么?也许您可以在答案中添加代码? 首先,无处可添加代码 - 您没有可​​构建的项目。其次,你得到的错误是VFW_E_NOT_IN_GRAPH,这正是我在上面1中写的。你不能Render甚至不属于过滤图的东西。 我编辑了我的问题EDIT2,请你看一下 老实说,我看不出它与这个问题和之前的问题有什么关系。你为什么还要在这里使用 CMemReader。 “它与”你的意思是错误,对吧?我不知道,但这是我得到的。正如您在问题中看到的那样,我使用CMemReader 来读取字节流。我没有文件作为源,我拥有的是字节指针和大小,因此为此我使用CMemReader。没有?

以上是关于如何将对象连接到过滤器图?的主要内容,如果未能解决你的问题,请参考以下文章

尝试将 UIButton 连接到代码时出现“对象退出”功能

Xcode 问题 - 无法将按钮连接到对象

Quickblox - 将对象连接到一个查询中

如何使用凭据连接到SharePoint列表使用客户端对象模型?

将 IBAction 连接到自定义类

C# directshow 连接多个图