26

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

我尝试将 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 链接似乎不起作用(请参阅错误

4

7 回答 7

29

目前这些是 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 一起使用,可以为您提供帮助。

于 2008-09-01T14:53:38.503 回答
2

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

于 2008-09-01T13:59:40.630 回答
2

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

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

于 2008-09-01T15:16:09.807 回答
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"));
        }
    } 
于 2014-01-21T12:59:15.800 回答
1

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

本指南有一个关于从视频文件中访问帧的部分。

于 2008-09-01T14:01:03.200 回答
1

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

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

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

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

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

于 2009-05-16T18:13:57.410 回答
1

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

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

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

于 2010-09-20T20:21:47.077 回答