ISampleGrabberFilter一次一帧的步骤

时间:2017-08-30 13:41:36

标签: c++ winapi directshow samplegrabber

我的图表结束点是 SampleGrabber ,其中我使用回调函数获取所有帧的未压缩数据。

在我的顶级界面代码中,我希望有一个函数 ReadNextFrame(),它可以获取图中下一帧的数据(直到它到达文件末尾)。

性能差的实现方法是将 nextFrameIndex 传递给grabberCB类,指定此时我想要的帧。所以我的回调函数会跳过所有其他帧,并只选择我想要的那个。这是昂贵的,因为图表必须遍历整个文件以选择单个帧数据。

我注意到有一个 IVideoFrameStep 界面,这是我想要的理想选择。但似乎这个界面与Sample Grabber不兼容,它的文档说:

  

在Microsoft下实现帧精确搜索的解码器   DirectShow必须实现AM_KSPROPSETID_FrameStep属性集,   它与IVideoFrameStep接口一起使用。

我尝试将其连接到我的图表,但 IVideoFrameStep :: CanStep()函数对我来说返回false,这意味着我无法将其与Sample Grabber一起使用。

所以我的问题是:是否有一个简单且性能良好的解决方案,因此我可以让我的图表保持当前状态,然后使用单帧前进并使用Sample Grabber获取数据?

1 个答案:

答案 0 :(得分:2)

您发现IVideoFrameStep有一定的工作要求,其背后的想法是整个过滤器图形执行状态转换,运行和暂停只播放一帧。

要使用Sample Grabber逐个获取所有帧,您可以实现更简单的方法,没有任何特殊要求。

  1. 让您的过滤器图表运行;从图表中删除时钟是有意义的 - 请参阅IMediaFilter::SetSyncSource(NULL)
  2. 使用SampleCB回调
  3. 在感兴趣的位置设置一个示例抓取器
  4. 执行SampleCB后,对数据执行操作并指示运行图表的更高级代码的框架可用性
  5. 在上面的SampleCB和#3内部完成时,不要从方法返回而是等待事件,这表示您已准备好继续
  6. 高级应用程序代码将处理一个帧并将事件从#4设置为允许SampleCB退出并进一步获取新帧;使用上面#3重复的新框架。
  7. 也就是说,您的SampleCB等待锁定整个管道,保持其状态所需的时间,让您以方便的速度逐帧处理。

    SampleCB的伪代码(带手动设置/重置事件):

    data m_Data;
    event m_DataAvailability;
    event m_NextFrameRequest;
    
    void SampleCB(Frame)
    {
      m_Data = Frame.GetData();
      m_DataAvailability.Set();
      m_NextFrameRequest.WaitFor(); // Sleeping here until signaled to continue
      m_NextFrameRequest.Reset();
    }
    
    data ReadNextFrame()
    {
      m_DataAvailability.WaitFor();
      data Data = m_Data;
      m_DataAvailability.Reset(); // Current data processed, we need next portion
      m_NextFrameRequest.Set(); // Indicate that we allow next callback call
      return Data; // Make captured frame available
    }