c# - 有效地从视频中抓取像素

标签 c# video directshow

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

要求

  • 必须精确到帧。 <-- 非常重要!
  • 让我可以访问解码后的像素缓冲区(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;

最佳答案

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

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

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

要在 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 位组件/库中

关于c# - 有效地从视频中抓取像素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11593140/

相关文章:

c# - 使用 Linq 返回具有最小值的行

c# - 奇怪的 C# 变量声明

c++ - DirectShow 使用回调方法从内存中读取

c# - 删除 EWS EmailMessage 正文中的 HTML 部分

c# - 枚举由 Autofac 生命周期跟踪的一次性元素

c++ - 使用 libde265 直接显示过滤器

security - 如何在网站上安全地提供视频

apache-flex - 用 Java 开发视频聊天 Web 应用程序的最佳方法是什么? Flex 还是 JMF?

.net - 模拟 DirectShow 网络摄像头

c++ - 如何在 PCM 音频中使用 IMediaSample 检测静音