2

我正在尝试使用 Video For Windows 界面编写 C++ Video 类,基于此 NeHe 教程中的概念,但使用更现代的代码(用于 OpenGL 3/4)。在我最初加载视频(不检索帧)的函数中,我指的是AVIStreamGetFrameOpen(),根据MSDN

返回可与 AVIStreamGetFrame 函数一起使用的 GetFrame 对象。

同一页面还说:

如果系统找不到可以将流解压缩为给定格式或任何 RGB 格式的解压缩器,则该函数返回 NULL。

我的问题是返回AVIStreamGetFrameOpen(),如前所述NULL,这意味着没有找到与文件匹配的解压缩器。但是,我的文件可以毫无问题地使用 Windows Media Player 播放,我相信这意味着应该可以使用解压缩器。

VFW 似乎缺乏文档,而且 MSDN 页面并不总是非常有用。任何人都知道可能导致此问题的原因是什么?

这是相关函数的代码:

bool Video::Load(std::string FileName) {
    try {
        if (this->bLoaded)
            this->UnLoad();

        AVIFileInit();

        if (AVIStreamOpenFromFile(&pavi, FileName.c_str(), streamtypeVIDEO, 0, OF_READ, NULL) != 0)
            throw "Failed to open the AVI video stream.";

        AVIStreamInfo(pavi, &psi, sizeof(psi));             // Reads Information About The Stream Into psi
        this->szWidth = psi.rcFrame.right - psi.rcFrame.left;           // Width Is Right Side Of Frame Minus Left
        this->szHeight = psi.rcFrame.bottom - psi.rcFrame.top;          // Height Is Bottom Of Frame Minus Top

        ulnLastFrame = AVIStreamLength(pavi);                // The Last Frame Of The Stream

        this->dDuration = AVIStreamSampleToTime(pavi, ulnLastFrame) / 1000.0f;
        this->dSecondsPerFrame = this->dDuration / ulnLastFrame;

        pgf = AVIStreamGetFrameOpen(pavi, NULL);              // Create The PGETFRAME Using Our Request Mode
        if (pgf == NULL)
            // ===== ERROR THROWN HERE =====
            throw "Failed to open the AVI GetFrame object.";

        glGenTextures(1, &this->unTexID);
        glBindTexture(GL_TEXTURE_2D, this->unTexID);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, this->szWidth, this->szHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        glBindTexture(GL_TEXTURE_2D, 0);
    }
    catch (const char* e) {
        Message((std::string("Error: ") + e + "\nFile: \"" + FileName + "\"").c_str(), "Error");
        return false;
    }


    this->bLoaded = true;
    return true;
}

忽略我奇怪的变量前缀。

4

2 回答 2

1

VFW 非常旧/遗留/已弃用。

根据https://en.wikipedia.org/wiki/Video_for_Windows,VFW 仅支持以下格式:

  • msrle
  • msvideo1
  • cinepak
  • 印地欧 3.2

我也在阅读 NeHe 教程。第 35 课中使用的格式Face2.avi是编码的。cinepak

E:\>ffmpeg -i Face2.avi -hide_banner
Input #0, avi, from 'Face2.avi':
  Duration: 00:00:03.04, start: 0.000000, bitrate: 1116 kb/s
    Stream #0:0: Video: cinepak (cvid / 0x64697663), rgb24, 160x120, 29.97 tbr, 29.97 tbn, 29.97 tbc
                        ~~~~~~~

如果您必须使用 VFW,您可以使用ffmpeg for Windows将您的视频转换为cinepakmsvideo1格式:

ffmpeg -i your_video.xxx -vcodec cinepak output.avi

(转换为cinepak比 需要更长的时间msvideo1,但会产生更好的质量。)

于 2019-02-13T14:28:24.500 回答
1

我的问题是 AVIStreamGetFrameOpen() 返回 NULL,如前所述,这意味着没有找到与文件匹配的解压缩器。但是,我的文件可以毫无问题地使用 Windows Media Player 播放,我相信这意味着应该可以使用解压缩器。

您认为解压器应该可用的假设是不正确的。

Windows 提供了几个与视频和音频相关的基线 API:Video for Windows、DirectShow、Media Foundation 以及 Windows Media。在此之上还有层(AudioVideoPlayback、MediaElement 等。

API 之间存在一定的互操作性:有时编解码器和其他对象在 API 之间共享,或者一个 API 提供了对其他对象的兼容性包装器。

但是,您的情况并非如此。Video For Windows 是旧版 API,无法将编解码器用于较新的 API。Windows Media Player 反过来使用 Media Foundation 作为主要 API,而 DirectShow 作为复杂场景的后备 API,它提供了第二次尝试播放文件的机会。基本上,当前版本的 Windows 中仍然存在 Video For Windows 的唯一原因是支持旧版应用程序:VFW 不提供新可用的视频/音频相关功能,不仅是微软,第三方也一样。

此外,32 位编解码器和 64 位编解码器是独立的,某些代码只能使用各自位数的编解码器。

也就是说,在使用相同的 API 方面,Windows Media Player 和您的代码之间没有交集。Windows Media Player 播放文件的事实并不意味着您的 VFW 代码也应该能够播放。您遇到的问题是没有安装合适的解码器来读取和解码文件中的视频(您没有提到格式,这里盲目猜测它是带有 H.264 视频的 AVI)。

于 2016-08-30T18:53:22.267 回答