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

时间:2008-09-01 13:35:42

标签: c++ windows video

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

我尝试将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链接似乎不起作用(see the bug

7 个答案:

答案 0 :(得分:28)

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

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

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

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

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

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:2)

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

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

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

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

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

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

答案 6 :(得分:1)

OpenCV是最好的解决方案,如果您的情况下的视频只需要导致一系列图片。如果您愿意进行真正的视频处理,那么ViDeo等于“Visual Audio”,您需要跟上“martjno”提供的那些。 Win7的新Windows解决方案还包括3种新的可能性:

  1. Windows Media Foundation:DirectShow的继任者;清理界面
  2. Windows Media Encoder 9:它不仅包含程序,还提供用于编码的库
  3. Windows Expression 4:2的继承者。
  4. 最后2个是仅商业解决方案,但第一个是免费的。要编写WMF代码,您需要安装Windows SDK。