视频编码的保存和重用设置
从嵌入式机器人平台的远程监控系统,自动或自主录制视频的应用程序变得比以往更加无处不在的设备,如相机价格作为和存储空间滴眼液和计算性能,提高了。然而,经常远程配置此类系统不选项,同时部署和安装必须是简单和自动。
最近,我需要在远程系统上的视频录制设置预配置,所以它会自动加载,并在启动时使用相同的设置方式。Web 搜索多个论坛,回到了十多年,但只有部分和满意的解决方案带来了很多类似的问题。
在本文中,我会提出简单但一般的方式,允许使用一致的压缩设置,保存视频的视频处理应用程序从而避免不必手动指定的编码解码器设置在每次启动该应用程序或机器。我将展示如何访问内部设置缓冲区的编码解码器,使他们可以轻松地保存、 重新加载和重新使用。这将为任何视频编解码器,而无需使用任何特定编码解码器的 Api 在机器上安装工作。
视频 101
原始视频数据是巨大的。考虑适度谦卑每秒 15 帧的速度沿溜溜达达的 VGA 摄像头。三通道 640 × 480 像素的每个帧是 900 KB 和生成的数据速率 (也就是约 105Mbps) 的 13MBps !略高清晰度 (HD) 决议、 较高的帧速率或超过 8 位色深,可能会有较温和视频设备,您可能会发现手机上的类型。90 分钟的高清电影将占用大约 1TB 原始形式。幸运的是,视频数据包含很多冗余,和视频压缩算法可以非常有效地存储视频文件。压缩算法选择的类型取决于特定的应用程序、 其要求和它的约束。几个因素而异的压缩方法,包括实时率、 性能注意事项和视觉质量和产生的文件大小之间的平衡。
在 Windows 上,视频压缩服务是由编码解码器 (压缩程序解压缩程序) 提供的。我将重点视频的窗口 (VfW) API.avi 压缩视频文件的保存。音频视频交错 (.avi) 是一种多媒体的容器文件格式,可以包含多个数据流的音频和视频,并允许选定流同步音频与视频播放。我会展示如何压缩编码解码器设置可以手动选择和持久的方式存储,因此他们可以稍后重新加载并自动重复使用同一编码解码器安装的任何计算机上的应用程序。
使用 VfW 保存视频
虽然在 1992 年回介绍 VfW 是持久的 API,今天仍在被广泛使用。新的编解码器和编解码器实现,如 ffmpeg 套件 (ffmpeg.org),继续提供 Microsoft Windows VfW 界面。
视频刻录程序的典型流通常采用以下步骤:
- 创建一个新的 AVI 文件、 创建一个新的压缩视频流,里面,选择所需的压缩设置和从压缩数据库创建一个新的压缩的流。
- 根据需要添加新的框架。
- 完成后,释放资源以相反的顺序。
使用 VfW,如下所示:
- 打开并准备的 AVI 视频文件,使用下面的代码:
- AVIFileInit: 初始化 AVIFile 图书馆在使用任何其它 AVIFile 函数之前,必须调用。
- AVIFileOpen: 将打开一个 AVI 文件。
- AVIFileCreateStream: 创建一个新的视频流的 AVI 文件内。一个 AVI 文件可以包含多个数据流 (各种类型)。
- AVISaveOptions: 提供了一个标准的压缩选项对话框 (请参阅图 1).用户完成时选择压缩选项,在 AVICOMPRESSOPTIONS 结构中返回选项。
- AVIMakeCompressedStream: 返回从 AVIFileCreateStream 的未压缩的流和压缩筛选器返回从 AVISaveOptions 中创建一个压缩的流。
- AVIStreamSetFormat: 设置流的图像格式。
- 将帧添加到视频流:
- AVIStreamWrite: 添加到视频流的单个帧。多次调用所需的其他帧。
- 清理并关闭:
- AVIStreamRelease: 关闭压缩的流 (从 AVIMakeCompressedStream)。
- AVIStreamRelease: 关闭未压缩的流 (从 AVIFileCreateStream)。
- AVISaveOptionsFree: 释放由 AVISaveOptions 功能 (这常常忘记了,导致内存泄漏) 分配的资源。
- AVIFileRelease: 关闭 AVI 文件 (从 AVIFileOpen)。
- AVIFileExit: 退出 AVIFile 图书馆。
图 1 AVISaveOptions 函数打开的视频压缩对话框
详细解释如何使用 VfW 录制视频是超出了本文的范围。你可以找到许多事例,在线教程。我将重点在这里只有 1.4 步骤: 压缩机的选择和编解码器设置部分。陪同本文的源代码基于从 (opencv.willowgarage.com) OpenCV 开放源码项目的 c + + 实现,并且可以从下载 code.msdn.microsoft.com/mag201112Video。然而,我在这里展示的技术是适用于 — — 和方便地集成到 — — 任何视频录制使用 VfW API 并不专门针对特定的实现的应用程序或编程语言。
常见的解决方案
如前面所示,以指定的压缩设置的常用方法是通过调用 AVISaveOptions 函数来显示压缩选项对话框。然后用户可以手动选择所需的编解码器。所选择的编解码器可能或不可能有"Configure…"选项,它允许进行特定的编码解码器设置自定义的编解码器。当然,在系统上没有活动的用户或甚至一个 GUI,此对话框不是选项。
要手动选择常见的替代方法是以编程方式选择特定的编码解码器,使用的编解码器 fourcc (四个字符代码 ; 请参阅 fourcc.org) 的标识符,并设置某些附加的一般设置共同为所有的编码解码器,如数据速率、 质量和关键帧速率。这种方法的主要缺点是它不允许任何特定编码解码器的设置。此外,它使编码解码器使用其当前的内部设置是什么。这些可能是默认值,或者,更糟的是,设置任意设置由其他程序。此外,系统上可用的并不是所有 fourcc 编解码器都支持 VfW API,这可能会导致压缩的流创建失败。
某些编解码器提供特殊的配置工具,以允许更改其内部设置外部。这些工具可能需要一个 GUI 或命令行工具的形式。然而,大多数编解码器不提供这种工具,并为特定的编码解码器自定义每个工具,因为你要了解其特定的语法和用法,利用它。
想要的东西是手动选择模式的灵活性与自动选择的编解码器和其内部的所有设置。
这两个领域的最佳产品
第一种方法,在 AVISaveOptions 调用返回 AVICOMPRESSOPTIONS 完全填充的对象。第二种方法,本质上,填满的某些值在 AVICOMPRESSOPTIONS 对象中,从内的代码,而无需使用 AVISaveOptions。
事实上,它是可以调用 AVISaveOptions 后保存完整、 内部编码解码器状态,以便稍后恢复此状态而无需再次调用 AVISaveOptions。特定于视频的压缩机内部数据和格式的秘密是不透明的指针 lpParms 和 lpFormat 的 AVICOMPRESSOPTIONS。从 AVISaveOptions 回来时,这两个指针包含一切功能需要进一步压缩的流 (大概是 AVISaveOptionsFree 发表的资源) 的 AVIMakeCompressedStream。
然后,我的技术的本质保存 lpParms 和 lpFormat,使其能够重复使用不透明的数据。幸运的是,这很容易做的。AVICOMPRESSOPTIONS 结构包含说明指出,通过 lpParms 和 lpFormat,尊重的不透明的二进制缓冲区的大小的两个有用的整数成员、 cbParms 和 cbFormat,ively。根据选定的特定编码解码器,这些大小更改。
若要简而言之,有三个二进制"斑点",需要保存后对 AVISaveOptions 的调用。这些都是 AVICOMPRESSOPTIONS 对象本身,这两个二进制缓冲区指出其 lpParms 和 lpFormat 的成员。这些缓冲区的长度 (以字节为单位),,分别来自 cbParms,cbFormat。还原的编解码器设置只扭转过程: 从文件中读取的 AVICOMPRESSOPTIONS 对象并设置其 lpParms 和 lpFormat 的成员,以指向从文件中读取的各自的二进制缓冲区。还原二进制缓冲区的分配,并由应用程序本身。
有许多方法来存储二进制数据。如图所示,在图 2,我的代码示例将数据保存在二进制形式。此外,在那里应该避免非打印字符 (如.txt 或.xml 文件) 的情况下,我已经成功使用基地-64 编码存储缓冲区。
图 2 的存储和恢复的编解码器设置示例
bool CvVideoWriter_VFW::writeCodecParams( char const* configFileName ) const
{
using namespace std;
try
{ // Open config file
ofstream cfgFile(configFileName, ios::out | ios::binary);
cfgFile.exceptions ( fstream::failbit | fstream::badbit );
// Write AVICOMPRESSOPTIONS struct data
cfgFile.write(reinterpret_cast<char const*>(&copts_), sizeof(copts_));
if (copts_.cbParms != 0)// Write codec param buffer
cfgFile.write(reinterpret_cast<char const*>(copts_.lpParms), copts_.cbParms);
if (copts_.cbFormat != 0)// Write codec format buffer
cfgFile.write(reinterpret_cast<char const*>(copts_.lpFormat),
copts_.cbFormat);
}
catch (fstream::failure const&)
{ return false; } // Write failed
return true;
}
bool CvVideoWriter_VFW::readCodecParams( char const* configFileName )
{
using namespace std;
try
{ // Open config file
ifstream cfgFile(configFileName, ios::in | ios::binary);
cfgFile.exceptions (
fstream::failbit | fstream::badbit | fstream::eofbit );
// Read AVICOMPRESSOPTIONS struct data
cfgFile.read(reinterpret_cast<char*>(&copts_), sizeof(copts_));
if (copts_.cbParms != 0)
{ copts_Parms_.resize(copts_.cbParms,0); // Allocate buffer
cfgFile.read(&copts_Parms_[0], copts_Parms_.size()); // Read param buffer
copts_.lpParms = &copts_Parms_[0]; // Set lpParms to buffer
}
else
{ copts_Parms_.clear();
copts_.lpParms = NULL;
}
if (copts_.cbFormat != 0)
{ copts_Format_.resize(copts_.cbFormat,0); // Allocate buffer
cfgFile.read(&copts_Format_[0], copts_Format_.size());// Read format buffer
copts_.lpFormat = &copts_Format_[0]; // Set lpFormat to buffer
}
else
{ copts_Format_.clear();
copts_.lpFormat = NULL;
}
}
catch (fstream::failure const&)
{ // A read failed, clean up
ZeroMemory(&copts_,sizeof(AVICOMPRESSOPTIONS));
copts_Parms_.clear();
copts_Format_.clear();
return false;
}
return true;
}
示例代码说明
示例代码捕获视频从视频照相机或网络摄像头,并将其保存到一个 AVI 文件。它使用 OpenCV VideoCapture 类来访问相机和捕获视频。保存该视频是使用 OpenCV CvVideoWriter_VFW 类我支持的编解码器设置保存修改过的版本。我试着保持所做的更改的原始代码尽可能小。在代码中,第二个参数的 CvVideoWriter_VFW::open 是 std::string。如果此字符串是中的四个字符长 (如 fourcc),它被认为是 fourcc,选择对应于此 fourcc 的编解码器 — — 从四个 1 字节字符转换为整数 fourcc 代码通常是使用 mmioFOURCC 宏,在 mmioFOURCC('D','I','V','X') ; 请参阅 tinyurl.com/mmioFOURCC 的详细信息。否则,该字符串是作为一个编解码器设置文件的名称。如果该文件存在,设置是从文件中读取,并用于视频压缩。如果它不存在,然后打开压缩选项对话框,并可以手动选择编解码器和它的设置 ; 然后,选择的设置将保存到所选名称可重用在下次运行应用程序的文件。注意: 你需要 OpenCV 安装编译和运行代码示例。
几个优势
我提出的解决方案具有几个优点。只是更改它的参数之一更改应用程序的压缩设置。有无需重新编译它,或甚至停止正在运行的应用程序。该方法是独立的编解码器和工程所有 VfW 编码解码器。某些编解码器甚至允许附加的自定义图像处理帧大小和去隔行如。所有这些选项也能够自动捕获编解码器设置文件中。
方法同样适用对旧微软 Windows 系统 (从 Windows 2000 起),还带着旧的编译器如 Visual Studio 6.0 版。另外,它可以用多种语言,公开 VfW 接口,例如,Visual Basic 和 C#。它可以部署到多台机器无关的每台机器内部的编解码器的当前状态。
主要的需要说明的是这种解决方案保证工作只在使用的编解码器版本相同时。如果编解码器缺少一台特定的计算机上,或者是用来使设置文件的不同版本,结果可能是不确定的。很明显,不能使用 nonVfW 的编解码器,因为此解决方案基于 VfW API。
可能的扩展,对这项工作包括同样保存音频压缩机的设置,以相同的方式处理的视频压缩设置。此外,AVISaveOptions 提供本机支持报与多个数据流,因为同一解决方案也将在这些情况下,工作和每个流的编码解码器设置可以写入单个文件。
其他常见的和更多的现代视频和音频处理对 Windows API 是 DirectShow。应该尽可能为 DirectShow,以及执行类似的解决方案,但那是以后的文章的主题。
Adi Shavit 是一个计算机视觉顾问。他一直在图像和视频处理系统超过 15 年,专业从事实时视频分析。他可以通过 adishavit@gmail.com。
衷心感谢以下 Microsoft 技术专家对本文的审阅: Dana Shavit 和 Matthew Wilson