【问题标题】:Get continuous frames from camera filter when source filter stops sending?当源过滤器停止发送时从相机过滤器获取连续帧?
【发布时间】:2013-07-28 06:01:26
【问题描述】:

大家好,

我有一个转换过滤器,它接受两个输入,一个来自相机,另一个来自文件源。在我的变换过滤器中,我混合了来自两个来源的输入。

变换过滤器派生自 CTransformFilter

class CWMTransformFilter : public CTransformFilter

额外的 pin 来自:CTransformInputPin(它又来自 CBaseInputPin)

class CFileInputPin : public CTransformInputPin

在我的情况下,如果文件源很小(假设 10 秒),我也会从相机获得输入 10 秒,稍后相机会停止向输入引脚发送帧。

所以我现在需要的是:
1.即使源过滤器停止发送,如何通知相机发送帧?
2. 源文件播放停止时如何重启源过滤器?
(类似于循环播放文件)

更新:

STDMETHODIMP CFileInputPin::EndOfStream()
{
    //return CTransformInputPin::EndOfStream();
    return S_OK;
}

STDMETHODIMP CFileInputPin::Receive(IMediaSample* pSample)
{
    HRESULT hr;
    BYTE* pBufferIn;
    long lBufferLength, lBufferSize;
    hr = CBaseInputPin::Receive(pSample);
    if (FAILED(hr))
    {
        printf("Error !!\n");
        return hr;
    }
    hr = pSample->GetPointer(&pBufferIn);
    DWORD stat = WaitForSingleObject(m_pFil->m_QSem,0L);
    BOOL bSem = FALSE;
    if( WAIT_OBJECT_0 == stat )
    {
        BYTE *pBuf = (BYTE *) malloc( Wsize*2 );
        memcpy(pBuf,pBufferIn,Wsize); //lBufferLength);
        sEncodedFrame CurFrame={pBuf,Wsize};
        m_pFil->m_Q.push(CurFrame); //push it onto the queue

        bSem = ReleaseSemaphore(m_pFil->m_QSem,1,NULL);
        if(!bSem)
        {
            printf("ReleaseSemaphore error: %d \n", GetLastError());
        }

        return S_OK;
    }
    else
    {
        printf("Cant Receive frame 0x%x \n",stat);
        return E_FAIL;
    }
    return S_OK;
}

HRESULT CWMTransformFilter::Transform(IMediaSample *pSource, IMediaSample *pDest)
{
    unsigned char r,g,b;
    unsigned char y,u,v;

    BYTE *pBufferIn, *pBufferOut, *pBuf;
    HRESULT hr = pSource->GetPointer(&pBufferIn);
    hr = pDest->GetPointer(&pBufferOut);
    if (FAILED(hr))
    {
        return hr;
    }
    long srclen = pSource->GetActualDataLength();
    long dstlen = pDest->GetActualDataLength();

    LONG pLastCnt;
    BOOL bSem = FALSE;
    //printf("Waiting to fill buffer %d\n",pSource);
    //return S_OK;
    //try
    //{
    while(1)
    {
        //if(1)
        DWORD ret = WaitForSingleObject(m_QSem,0L);
        if(ret != WAIT_OBJECT_0)
        {
            printf("Get error %d \n",GetLastError());
        }
        if( WAIT_OBJECT_0 == ret )
        {
            
            sEncodedFrame Frame;
            if( m_Q.empty() == false )
            {
                Frame = m_Q.front();
                m_Q.pop();
                pBuf = (BYTE*) malloc(dstlen*2);
                pLastCnt = Frame.iValidSize;
                printf("Copy onto queue \n");
                memcpy(pBuf,Frame.pFrame,pLastCnt); //Frame.iValidSize);
                free(Frame.pFrame);
                //delete &Frame;
                bSem = ReleaseSemaphore(m_QSem,1,NULL);
                if(!bSem)
                {
                    printf("ReleaseSemaphore error: %d \n", GetLastError());
                }
                hr = S_OK;
                break;
            }
            else
            {
                bSem = ReleaseSemaphore(m_QSem,1,NULL);
                if(!bSem)
                {
                    printf("ReleaseSemaphore error: %d \n", GetLastError());
                }
                //return S_OK;
                hr = E_FAIL;
            }
        }
        else
        {
            //return S_OK;
            hr = E_FAIL;
        }
    }

    for(i = 0; i < windowWidth*2*windowHeight ; i+=4)
    {
     y = pBufferIn[i];
     u = pBufferIn[i+1];
     v = pBufferIn[i+3];
     r = y + 1.4075 * (v - 128);
     g = y - 0.3455 * (u - 128) - (0.7169 * (v - 128));
     b = y + 1.7790 * (u - 128);

    if(((r > b) &&(g > b)) && (g <= 200) )
    {
        pBufferIn[i] = pBuf[i];
        pBufferIn[i+1] = pBuf[i+1];
        pBufferIn[i+2] = pBuf[i+2];
        pBufferIn[i+3] = pBuf[i+3];
    }
}

    // Process the data.
    memcpy(pBufferOut,pBufferIn,pSource->GetSize()); //after blend

    pDest->SetActualDataLength(pDest->GetSize());
    pDest->SetSyncPoint(TRUE);
    return S_OK;
}

CFileInputPin::Receive 是我从文件输入引脚接收样本的地方,
CFileInputPin::EndOfStream(),通知样本完成。
CWMTransformFilter::Transform(),是将样本发送到渲染器的输出端。

谢谢,
夏姆

【问题讨论】:

    标签: c++ visual-c++ filter transform directshow


    【解决方案1】:

    这个问题有很多棘手的问题。

    首先,第一个兴趣点是自定义双输入过滤器。无论输入过滤器做什么,这个变换过滤器都可以排除这些事情——它完全取决于它的实现是允许两个输入分支流,还是阻止其中一个。常见(典型)规则是,如果过滤器有 2 个以上的输入,则它是以下两者之一:

    1. 其中一个流是主流,其他输入要么在有意义的情况下进行处理,要么被丢弃
    2. 过滤器会阻止输入输入支路以继续获取具有匹配时间戳的数据,然后在其内部处理过程中合并流。

    输入流通常是样本序列,然后是 EOS 通知。特别是,如果其中一个源没有发送 EOS,或者转换过滤器没有正确处理它,则可能会发生冻结。

    第二个大问题是寻求。您通常不会寻找图表的一部分。但是,这正是您想要做的。您可以尝试独立地查找源过滤器来定位其自己的查找接口,或者您可以实现一个缓冲区并保存它发送的所有内容,并在源发送 EOS 后无限循环。对此没有任何建议 - 您决定什么适合您的方案。

    另一种选择是拆分图并桥接它们,以便您可以按常规方式查找/重新启动源图。

    【讨论】:

    • 其实我对directshow还是很陌生。在我的情况下,我在文件输入引脚上收到 EOS 通知,表明文件读取已完成。但是为什么相机停止发送帧?渲染器在显示文件的最后一帧后冻结。
    • 相机不发送帧 - 据说 - 因为引脚连接用完了缓冲区,这是因为双输入过滤器没有释放缓冲区,或者它仍在尝试匹配时间戳而忽略 EOS。这是要检查的第一件事。
    • 感谢您的回复。您能告诉我如何确认: 1. 过滤器不释放缓冲液吗? 2. 忽略 EOS 匹配时间戳?
    • 1 通过在冻结时检查调用堆栈2 您需要打印出所有连接处的媒体样本/时间,并查看它们作为一个整体有什么问题 - 没有细节关于你的问题来猜测到底出了什么问题,对不起。
    • 我已经添加了实现细节,请您进一步帮助我吗?
    猜你喜欢
    • 1970-01-01
    • 2015-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多