VideoWriter 类

最近几个项目都需要保存相机图像数据,也就是存成视频。有的要求保存源视频,有的要求保存处理后的视频。

由于图像数据的读取使用 OpenCV,目标检测框架也是建立在 OpenCV 的基础上,所以保存图像顺理成章也使用 OpenCV。这里主要使用 OpenCV 的 VideoWriter 类。

根据操作系统和 OpenCV 编译选项的不同,保存视频时使用的 videoio backend 也不同。在 Linux 上常见的是 FFmpeg 或 GStreamer;在 Windows 上可以使用 FFmpeg、MSMF(Microsoft Media Foundation)或 DSHOW(DirectShow);在 macOS 上常见的是 AVFoundation。

根据官方文档,VideoWriter 类其中一个定义如下(有多个重载):

cv::VideoWriter::VideoWriter(
    const String& filename,
    int fourcc,
    double fps,
    Size frameSize,
    bool isColor = true
);
  • filename:输出视频文件名。
  • fourcc:由 4 个字符拼接成的编码器标识,例如 cv::VideoWriter::fourcc('M', 'J', 'P', 'G')
  • fps:输出视频流的帧率。
  • frameSize:输出帧尺寸,可以写成 (width, height)cv::Size(width, height)
  • isColor:是否按彩色帧写入。isColor=false 表示写入灰度帧,但实际是否支持还取决于 backend、编码器和输入帧格式。

其中,fourcc 支持的编码格式列表可以参考 Video Codecs by FOURCC - fourcc.org

实例化可以参考:

cv::VideoWriter video(
    "output.avi",
    cv::VideoWriter::fourcc('M', 'J', 'P', 'G'),
    10,
    cv::Size(frameWidth, frameHeight)
);

随后在循环中,使用下面的方式即可向指定文件持续写入当前 Frame:

video.write(frame);

需要注意,frame 的宽和高需要和 VideoWriter 实例化时设置的宽和高一致,否则保存的视频可能无法正常打开,或者写入失败。


主流视频编码格式

编码的目的是压缩。视频编码是一种压缩技术,可以减少数据量,并按照某种编码规范组织视频数据。

封装格式也叫容器,它会把已经编码压缩好的视频轨、音频轨、字幕、时间戳等信息按照一定格式放到一个文件中。常见封装格式(也就是常见后缀)有 mp4movavimkv 等。

有博主对这些编码器生成的视频体积做了测试:

编解码器代码 编解码器类型 文件大小 后缀
'X', '2', '6', '4' x264 / H.264 编码相关标识 较小 .mp4
'P', 'I', 'M', 'I' MPEG-1 不会特别大 .avi
'M', 'P', '4', '2' MPEG-4.2 不会特别大 .avi
'D', 'I', 'V', '3' DivX 3 / 早期 MPEG-4 Part 2 相关编码 不会特别大 .avi
'D', 'I', 'V', 'X' 早期 MPEG-4 Part 2 相关编码 不会特别大 .avi
'X', 'V', 'I', 'D' Xvid / MPEG-4 Part 2 不会特别大 .avi
'M', 'P', '4', 'V' MPEG-4 Part 2 不会特别大 .m4v
'T', 'H', 'E', 'O' Theora 视频编码 相对较大 .ogv
'F', 'L', 'V', '1' Flash Video 相对较大 .flv
'M', 'J', 'P', 'G' Motion JPEG 较大 .avi
'I', '4', '2', '0' 未压缩或低压缩的 YUV 4:2:0 数据 特别大 .avi

需要注意,fourcc、编码器、封装格式之间不是一一对应关系。OpenCV 最终能不能写出某种格式,取决于 OpenCV 使用的 backend、系统安装的编码器、输出文件后缀和具体参数组合。


H.264 和 x264

名字里都有 264,在安装 OpenCV 依赖的时候也无脑安装了 x264 的依赖,但是一直不知道这是个什么东西。

H.264,也叫 AVC,是 MPEG-4 Part 10 / Advanced Video Coding。相比 RAW、MJPEG 等格式,H.264 通常可以在相近画质下获得更高压缩率,也就是文件更小。缺点是编码复杂度更高,编码时往往需要更多计算量。很多平台也支持 H.264 的硬件编码和硬件解码。

x264 则不是一种视频格式,而是一个开源的 H.264 / MPEG-4 AVC 软件编码器。它可以输出符合 H.264 标准的码流,常被 FFmpeg、GStreamer 等工具或库调用。

更准确地说:

  • H.264 是视频编码标准。
  • x264 是 H.264 标准的一个软件编码器实现。
  • x264 主要负责软件编码;解码由播放器、解码器库或硬件解码器负责。
  • x264 输出的 H.264 码流并不天然排斥硬件解码。能不能硬解,取决于码流 profile / level、解码器、驱动和硬件支持情况。
  • x264 产生的 H.264 码流可以封装到 mp4mkvavi 等多种容器中,具体取决于封装工具和参数。

关于授权也要区分几个概念:H.264 标准本身涉及专利授权问题,x264 软件本身也有自己的开源许可证。实际项目中是否可以直接使用,取决于你的发行方式、使用场景、平台依赖和相关授权要求。

所以,不能简单说 x264 是 H.264 的子集,也不能说 x264 只能封装为 mkv,更不能说 x264 去除了帧内预测和帧间预测。x264 反而是一个功能完整、工程上非常常用的 H.264 软件编码器实现。


参考文章

[1] 车载前摄像头学习笔记 —— 视频编码格式_摄像头图像编码类型-CSDN 博客

[2] OpenCV: cv::VideoWriter Class Reference

[3] Video Codecs by FOURCC - fourcc.org

[4] 音视频笔记 | H264 基础原理介绍 - Eren の 宇宙船

[5] OpenCV 图片转换视频文件时的编码问题总结_opencv mp4 编码-CSDN 博客

[6] h264 与 x264 区别 - GitHub