暂停和寻找到第一帧后,DirectShow CSourceStream :: FillBuffer无法预测的调用次数

时间:2018-03-22 09:32:36

标签: c++ directshow source-filter

我有一个Directshow文件源过滤器,它有音频和帧输出引脚。它是基于MSDN上的tutorial基于C ++编写的。我的过滤器使用Medialooks MFormats SDK打开视频,并将原始数据提供给输出引脚。两个引脚在渲染时直接连接到渲染器滤镜。

当我运行图形,暂停视频并寻找帧编号0时出现问题。在输出帧引脚中调用ChangeStart方法后,有时会调用FillBuffer三次和帧1显示在屏幕上而不是0.当它被调用两次时,它显示正确的帧,即帧0。

输出引脚继承自CSourceStreamCSourceSeeking类。以下是输出帧引脚的FillBufferChangeStart方法;

FillBuffer方法

HRESULT frame_pin::FillBuffer(IMediaSample *sample)
{
     CheckPointer(sample, E_POINTER);

    BYTE *frame_buffer;
    sample->GetPointer(&frame_buffer);

    // Check if the downstream filter is changing the format.
    CMediaType *mt;
    HRESULT hr = sample->GetMediaType(reinterpret_cast<AM_MEDIA_TYPE**>(&mt));
    if (hr == S_OK)
    {
        auto new_width = reinterpret_cast<VIDEOINFOHEADER2*>(mt->pbFormat)->bmiHeader.biWidth;
        auto old_witdh = reinterpret_cast<VIDEOINFOHEADER2*>(m_mt.pbFormat)->bmiHeader.biWidth;

        if(new_width != old_witdh)
            format_changed_ = true;

        SetMediaType(mt);
        DeleteMediaType(mt);
    }

    ASSERT(m_mt.formattype == FORMAT_VideoInfo2);

    VIDEOINFOHEADER2 *vih = reinterpret_cast<VIDEOINFOHEADER2*>(m_mt.pbFormat);

    CComPtr<IMFFrame> mf_frame;

    {
        CAutoLock lock(&shared_state_);

        if (source_time_ >= m_rtStop)
            return S_FALSE;

        // mf_reader_ is a member external SDK instance which gets the frame data with this function call
        hr = mf_reader_->SourceFrameConvertedGetByNumber(&av_props_, frame_number_, -1, &mf_frame, CComBSTR(L""));
        if (FAILED(hr))
            return hr;

        REFERENCE_TIME start, stop = 0;

        start = stream_time_;
        stop = static_cast<REFERENCE_TIME>(tc_.get_stop_time() / m_dRateSeeking);

        sample->SetTime(&start, &stop);

        stream_time_ = stop;
        source_time_ += (stop - start);

        frame_number_++;
    }

    if (format_changed_)
    {
        CComPtr<IMFFrame> mf_frame_resized;
        mf_frame->MFResize(eMFCC_YUY2, std::abs(vih->bmiHeader.biWidth), std::abs(vih->bmiHeader.biHeight), 0, &mf_frame_resized, CComBSTR(L""), CComBSTR(L""));
        mf_frame = mf_frame_resized;
    }


    MF_FRAME_INFO mf_frame_info;
    mf_frame->MFAllGet(&mf_frame_info);

    memcpy(frame_buffer, reinterpret_cast<BYTE*>(mf_frame_info.lpVideo), mf_frame_info.cbVideo);

    sample->SetActualDataLength(static_cast<long>(mf_frame_info.cbVideo));
    sample->SetSyncPoint(TRUE);
    sample->SetPreroll(FALSE);

    if (discontinuity_)
    {
        sample->SetDiscontinuity(TRUE);
        discontinuity_ = FALSE;
    }

    return S_OK;
}

ChangeStart方法

HRESULT frame_pin::ChangeStart()
{
    {
        CAutoLock lock(CSourceSeeking::m_pLock);
        tc_.reset();
        stream_time_ = 0;
        source_time_ = m_rtStart;
        frame_number_ = static_cast<int>(m_rtStart / frame_lenght_);
    }

    update_from_seek();
    return S_OK;
}

1 个答案:

答案 0 :(得分:0)

从Microsoft DirectShow文档中:

  

CSourceSeeking类是用于实现的抽象类   使用一个输出引脚查找源滤波器。

     

对于不止一个过滤器,不建议使用CSourceSeeking   输出引脚。主要问题是只有一个针脚可以响应   寻找请求。通常,这需要引脚之间的通信   和过滤器。

您的源滤波器中有两个输出引脚。

可以使用自定义编码扩展CSourceSeeking类以管理多个输出引脚。当搜索命令进入时,它们将同时通过两个输入引脚,因此您需要确定哪个引脚在控制搜索,而忽略到达另一个输入引脚的搜索命令。