我正在寻找一种从视频文件中获取图像数据的有效方法。我目前正在测试 Interop.QuartzTypeLib
库中的 FilgraphManagerClass.GetCurrentImage()
。这可以满足我的需要,但速度非常慢。我需要处理每个视频的所有帧。我有什么更好的选择?
要求
- 必须精确到帧。 <-- 非常重要!
- 让我可以访问解码后的像素缓冲区(
int
或byte[]
数组),最好是 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
来实现,而且效果也很好。那里的其他示例也使用这种方法。
您会发现其他代码片段非常接近此任务:
- Seeking keyframes using DirectShowNet - 使用样本采集器
- BufferCB not being called by SampleGrabber - 音频部分的任务相同
- How to access an audio stream using DirectShow.NET C#
关于 MP4
文件,您应该考虑以下几点:
- Windows 对 MPEG-4 的支持有限,您可能需要安装第三方组件才能播放文件。如果 GraphEdit 可以读取它们,那么您也可以。
- Windows Media Player 可能正在使用并且很可能会使用更新的 API,您应该看看 GraphEdit
- 请务必在您的应用程序上使用
Win32
/x86
平台,以避免遇到您的应用程序在 64 位域中运行而仅支持 MP4 的情况在已安装的 32 位组件/库中
关于c# - 有效地从视频中抓取像素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11593140/