C ++:什么是最简单的库打开video文件

我想打开一个小的video文件,并映射内存中的每一帧(应用一些自定义filter)。 我不想处理video编解码器,我宁愿让图书馆为我处理。

我试图使用直接显示与SampleGrabber筛选器(使用此示例http://msdn.microsoft.com/en-us/library/ms787867(VS.85).aspx ),但我只设法抓住一些框架(不是每个帧!)。 我在video软件编程方面很新,也许我没有使用最好的库,或者我做错了。

我已经粘贴了部分代码(主要是msdn示例中的一个修改后的副本/粘贴),不幸的是,它并没有像预期的那样抓取25个第一帧。

[...] hr = pGrabber->SetOneShot(TRUE); hr = pGrabber->SetBufferSamples(TRUE); pControl->Run(); // Run the graph. pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till it's done. // Find the required buffer size. long cbBuffer = 0; hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL); for( int i = 0 ; i < 25 ; ++i ) { pControl->Run(); // Run the graph. pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till it's done. char *pBuffer = new char[cbBuffer]; hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer); AM_MEDIA_TYPE mt; hr = pGrabber->GetConnectedMediaType(&mt); VIDEOINFOHEADER *pVih; pVih = (VIDEOINFOHEADER*)mt.pbFormat; [...] } [...] 

有没有人,有video软件经验,谁可以告诉我有关代码或其他更简单的库?

谢谢

编辑:Msdn链接似乎不工作( 见错误 )

目前这些是Win32平台上最流行的视频框架:

  1. Windows视频:从Win95时代开始的老式Windows框架,但仍然被广泛使用,因为它使用起来非常简单。 不幸的是,它只支持安装了正确的VFW编解码器的AVI文件。

  2. DirectShow:标准的WinXP框架,它基本上可以加载Windows Media Player可以播放的所有格式。 很难使用。

  3. Ffmpeg :更精确地说,Favmpeg开源多媒体工具附带的libavcodec和libavformat。 这是非常强大的,可以阅读很多格式(几乎所有你可以玩VLC ),即使你没有安装在系统上的编解码器。 使用起来相当复杂,但是您始终可以从随附的ffplay代码或开源软件中的其他实现获得灵感。 无论如何,我认为它比DS更容易使用(而且速度更快)。 它需要由Windows上的MinGW来完成,但是这里所有的步骤都已经很好的解释了 (在这个时候链接已经关闭,希望不会死掉)。

  4. QuickTime :Apple框架并不是Windows平台的最佳解决方案,因为它需要安装QuickTime应用程序,并且还需要适合每种格式的QuickTime编解码器; 它不支持多种格式,但在专业领域相当普遍(所以一些编解码器实际上只用于QuickTime)。 不应太难实施。

  5. Gstreamer :最新的开源框架。 我不太了解这个,我猜想它覆盖了其他一些系统(但我不确定)。

所有这些框架已经在OpenCv Highgui中作为后端实现,除了DirectShow。 Win32 OpenCV的默认框架是使用VFW(因此只能打开一些AVI文件),如果你想使用其他人,你必须下载CVS而不是正式版本,仍然对代码进行一些黑客攻击,反正不是太完整,例如FFMPEG后端不允许在流中查找。 如果你想使用OpenCV的QuickTime, 这可以帮助你。

我用OpenCV加载视频文件并处理它们。 对于许多类型的视频处理,包括对计算机视觉有用的视频处理来说,这也很方便。

使用SampleGrabber的“回调”模型可能会给你更好的结果。 请参阅Samples \ C ++ \ DirectShow \ Editing \ GrabBitmaps中的示例。

Samples \ C ++ \ DirectShow \ Filters \ Grabber2 \ grabber_text.txt和readme.txt中还有很多信息。

尝试使用OpenCV库。 它绝对有你需要的能力。

本指南有关于从视频文件访问帧的章节。

如果是AVI文件,我会从AVI文件自己读取数据并提取帧。 现在使用视频压缩管理器来解压缩它。

该AVI文件格式非常简单,请参阅: http : //msdn.microsoft.com/en-us/library/dd318187 (VS.85) .aspx (和使用谷歌)。

一旦你打开文件,你只需提取每一帧,并将其传递给ICDecompress()来解压缩。

这似乎是很多工作,但这是最可靠的方法。

如果这是太多的工作,或者如果你想比AVI文件,然后使用ffmpeg。

如果视频在你的情况下只需要导致一系列的图片,OpenCV是最好的解决方案。 如果你愿意做真正的视频处理,所以ViDeo等于“视频音频”,你需要保持与“martjno”提供的跟踪。 Win7的新窗口解决方案还包括3个新的可能性:

  1. Windows Media Foundation:DirectShow的继任者; 清理界面
  2. Windows Media编码器9:它不仅包括程序,它还提供编码库
  3. Windows表达式4:2的后继

最后2个是商业解决方案,但第一个是免费的。 要编码WMF,您需要安装Windows SDK。

我知道在C ++中非常有诱惑力,可以让视频文件得到正确的分解,只需要自己做。 但是,虽然信息已经存在了,但是如此漫长的过程,建立每个文件格式的文件类型,并使其易于改变,以考虑未来的结构变化,坦率地说,这是不值得的努力。

相反,我建议ffmpeg。 上面有提到,但说难,不难。 比大多数人需要更多的选择,这使得它看起来更难。 对于大多数操作,您可以让ffmpeg自行解决。

例如一个文件转换ffmpeg -i inputFile.mp4 outputFile.avi

从一开始就决定要在一个线程中运行ffmpeg操作,或者更准确地说,是一个线程库。 但是有自己的线程类包装它,以便您可以有自己的EventAgs和检查线程完成的方法。 就像是 :-

 ThreadLibManager() { List<MyThreads> listOfActiveThreads; public AddThread(MyThreads); } Your thread class is something like:- class MyThread { public Thread threadForThisInstance { get; set; } public MyFFMpegTools mpegTools { get; set; } } MyFFMpegTools performs many different video operations, so you want your own event args to tell your parent code precisely what type of operation has just raised and event. enum MyFmpegArgs { public int thisThreadID { get; set; } //Set as a new MyThread is added to the List<> public MyFfmpegType operationType {get; set;} //output paths etc that the parent handler will need to find output files } enum MyFfmpegType { FF_CONVERTFILE = 0, FF_CREATETHUMBNAIL, FF_EXTRACTFRAMES ... } 

这里是我的ffmpeg工具类的一小部分,这部分收集关于视频的信息。 我把FFmpeg放在一个特定的位置,在软件运行开始的时候确保它在那里。 对于这个版本,我把它移到了桌面上,我确信我已经为你正确地写了路径(我真的很讨厌MS的特殊文件夹系统,所以我尽可能地忽略它)。

无论如何,这是一个使用无窗口ffmpeg的例子。

  public string GetVideoInfo(FileInfo fi) { outputBuilder.Clear(); string strCommand = string.Concat(" -i \"", fi.FullName, "\""); string ffPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\ffmpeg.exe"; string oStr = ""; try { Process build = new Process(); //build.StartInfo.WorkingDirectory = @"dir"; build.StartInfo.Arguments = strCommand; build.StartInfo.FileName = ffPath; build.StartInfo.UseShellExecute = false; build.StartInfo.RedirectStandardOutput = true; build.StartInfo.RedirectStandardError = true; build.StartInfo.CreateNoWindow = true; build.ErrorDataReceived += build_ErrorDataReceived; build.OutputDataReceived += build_ErrorDataReceived; build.EnableRaisingEvents = true; build.Start(); build.BeginOutputReadLine(); build.BeginErrorReadLine(); build.WaitForExit(); string findThis = "start"; int offset = 0; foreach (string str in outputBuilder) { if (str.Contains("Duration")) { offset = str.IndexOf(findThis); oStr = str.Substring(0, offset); } } } catch { oStr = "Error collecting file information"; } return oStr; } private void build_ErrorDataReceived(object sender, DataReceivedEventArgs e) { string strMessage = e.Data; if (outputBuilder != null && strMessage != null) { outputBuilder.Add(string.Concat(strMessage, "\n")); } }