有效地从视频中抓取像素

时间:2012-07-21 14:46:49

标签: c# video directshow

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

要求

  • 必须是帧精确的。 < - 非常重要!
  • 允许我访问已解码的像素缓冲区(intbyte[]数组),理想情况下为RGB24或RGB32。
  • 可以实时或更快地抓取缓冲区。我不需要显示视频,我只需要分析像素。
  • 处理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;

2 个答案:

答案 0 :(得分:5)

您正在使用的

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

相反,您需要构建以下类型的过滤器图:文件来源 - > ... - >样品采集器过滤器 - >空渲染器。 Sample Grabber是一个标准组件,可以提供一个回调,以便它通过它来传递任何帧数据。

然后通过调用过滤器图形上的SetReferenceClock(null)从图中删除时钟,使其尽可能快地运行(而不是实时)。然后,您Run图表和所有视频帧都会提供给您的回调。

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

您会发现非常接近此任务的其他代码段:

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

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

答案 1 :(得分:0)

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