C:打开视频文件最简单的库是什么

新手上路,请多包涵

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

我尝试将 Direct Show 与 SampleGrabber 过滤器一起使用(使用此示例 http://msdn.microsoft.com/en-us/library/ms787867(VS.85).aspx ),但我只设法抓取了一些帧(不是每一帧!)。我是视频软件编程的新手,也许我没有使用最好的库,或者我做错了。

我已经粘贴了我的一部分代码(主要是来自 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;

    [...]
}

[...]

有没有具有视频软件经验的人可以就代码或其他更简单的库向我提供建议?

谢谢

编辑:Msdn 链接似乎不起作用( 请参阅错误

原文由 Steve Gury 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 426
2 个回答

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

  1. Video for Windows:来自 Win95 时代的旧 windows 框架,但仍然被广泛使用,因为它使用起来非常简单。不幸的是,它仅支持已安装正确 VFW 编解码器的 AVI 文件。

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

  3. Ffmpeg :更准确地说是 Ffmpeg 开源多媒体实用程序附带的 libavcodec 和 libavformat。即使您没有在系统上安装编解码器,它也非常强大并且可以读取很多格式(几乎所有您可以使用 VLC 播放的格式)。它使用起来相当复杂,但你总是可以从它附带的 ffplay 代码或开源软件中的其他实现中获得灵感。无论如何,我认为它仍然比 DS 更容易使用(而且速度更快)。它需要在Windows上由MinGW编译,但所有步骤在 这里 都解释得很好(此时链接已关闭,希望不要死)。

  4. QuickTime :Apple 框架不是 Windows 平台的最佳解决方案,因为它需要安装 QuickTime 应用程序以及适用于每种格式的 QuickTime 编解码器;它不支持多种格式,但在专业领域中很常见(因此某些编解码器实际上仅适用于QuickTime)。实施起来应该不会太难。

  5. Gstreamer :最新的开源框架。我对此了解不多,我想它涵盖了其他一些系统(但我不确定)。

除 DirectShow 外,所有这些框架都在 OpenCv Highgui 中作为后端实现。 Win32 OpenCV 的默认框架是使用 VFW(因此只能打开一些 AVI 文件),如果你想使用其他的,你必须下载 CVS 而不是官方版本,并且仍然对代码进行一些黑客攻击,无论如何它不是太完整,例如 FFMPEG 后端不允许在流中搜索。如果您想将 QuickTime 与 OpenCV 一起使用, 可以为您提供帮助。

原文由 martjno 发布,翻译遵循 CC BY-SA 2.5 许可协议

我知道在 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"));
        }
    }

原文由 Bob 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题