有效地从video中抓取像素

我正在寻找一种从video文件中获取图像数据的有效方法。 我目前正在测试Interop.QuartzTypeLib库中的FilgraphManagerClass.GetCurrentImage() 。 这就是我需要的,但速度很慢。 我需要处理每个video的所有帧。 我有什么更好的选择?

要求

  • 必须是帧精确的。 < – 非常重要!
  • 允许我访问解码的像素缓冲区( intbyte[]数组),理想情况下是RGB24或RGB32。
  • 可以实时或更快地抓取缓冲区。 我不需要显示video,我只需要分析像素。
  • 处理mp4文件(h264 / aac)。 如果需要,我可以通过AviSynth重新打包或帧服务,但不能涉及重新编码。

欢迎大家提出意见。

一些代码请求:

 FilgraphManagerClass graphClass = new FilgraphManagerClass(); graphClass.RenderFile(@"C:\tmp\tmp.avs"); int sz = (graphClass.Width * graphClass.Height + 10) * 4; int[] buffer = new int[sz - 1]; 

然后我逐步走过每一帧。 我在循环中有这样的东西:

 graphClass.GetCurrentImage(ref sz, out buffer[0]); //DoStuff(buffer); graphClass.CurrentPosition += graphClass.AvgTimePerFrame; 

您正在使用的IBasicVideo::GetCurrentImage方法基本上用于快照,并且仅适用于传统模式下的传统video渲染。 也就是说,(a)它不是时间准确,它可以让你复制帧,或相反,丢帧; (b)假设您显示video。

相反,您需要构建以下类型的filter图形:文件源 – > … – >样本抓取器filter – >空渲染器。 Sample Grabber是一个标准组件,可以提供一个回调,以便它通过它来调用任何帧数据。

然后通过在filter图上调用SetReferenceClock(null)来从图中删除时钟,以便它尽可能快地运行(而不是实时)。 然后Run图表,所有video帧都提供给您的回调。

要在C#中完成任务,您需要使用DirectShow.NET库 。 它的Capture\DxSnap示例提供了如何使用Sample Grabber的简短示例。 他们通过BufferCB而不是BufferCB来做到这SampleCB并且效果也很好。 其他样品也使用这种方法。

您将找到非常接近此任务的其他代码段:

  • 使用DirectShowNet寻求关键帧 – 使用Sample Grabber
  • SampleGrabber没有调用BufferCB – 音频部分的任务相同
  • 如何使用DirectShow.NET C#访问音频流

关于MP4文件,您应该考虑以下因素:

  1. Windows中对MPEG-4的支持有限,您可能需要安装第三方组件才能使文件可播放。 如果GraphEdit可以读取它们,那么你也可以。
  2. Windows Media Player可能正在使用,而且可能是更新的API,您应该更好地查看GraphEdit
  3. 确保在应用程序上使用Win32 / x86平台,以避免遇到应用程序在64位域中运行的情况,而对MP4的支持仅存在于安装的32位组件/库中

您还可以使用Windows Media Foundation创建一个allocator-presenter。 这将为您提供已解码的video帧作为GPU纹理,您还可以使用CUDA或OpenCL执行所需的处理(如果可能),这将有助于您的处理速度极大。