【问题标题】:C++ : What's the easiest library to open video fileC++:打开视频文件最简单的库是什么
【发布时间】:2010-09-07 11:13:03
【问题描述】:

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

我尝试使用带有 SampleGrabber 过滤器的 Direct Show(使用此示例 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 链接似乎不起作用 (see the bug)

【问题讨论】:

    标签: c++ windows video


    【解决方案1】:

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

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

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

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

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

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

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

    【讨论】:

      【解决方案2】:

      我使用OpenCV 加载视频文件并进行处理。它也适用于许多类型的视频处理,包括对计算机视觉有用的视频处理。

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

          我知道在 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 工具类的一个小 sn-p,这部分收集有关视频的信息。 我将 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"));
                  }
              } 
          

          【讨论】:

            【解决方案5】:

            尝试使用OpenCV 库。它绝对具有您需要的功能。

            This guide 有一个关于从视频文件中访问帧的部分。

            【讨论】:

            • 其实OpenCV依赖gstreamer或者ffmpeg等其他框架来处理视频。仅使用 OpenCV 来阅读视频需要一个庞大的库来仅使用其中的一小部分,并且维护其构建和依赖项对我来说似乎是一项浪费时间的任务。
            【解决方案6】:

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

            AVI文件格式很简单,见:http://msdn.microsoft.com/en-us/library/dd318187(VS.85).aspx(并用google)。

            打开文件后,您只需提取每一帧并将其传递给 ICDecompress() 进行解压缩。

            看起来工作量很大,但这是最可靠的方法。

            如果工作量太大,或者您想要的不仅仅是 AVI 文件,那么请使用 ffmpeg。

            【讨论】:

              【解决方案7】:

              如果您的视频只需要生成一系列图片,那么 OpenCV 是最佳解决方案。如果你愿意做真正的视频处理,所以ViDeo等于“Visual Audio”,你需要跟上“martjno”提供的那些。 Win7 的新 Windows 解决方案还包括 3 个新的可能性:

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2013-11-05
                • 2015-05-09
                • 1970-01-01
                • 2021-07-02
                • 2023-03-03
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多