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 实例化时设置的宽和高一致,否则保存的视频可能无法正常打开,或者写入失败。
主流视频编码格式
编码的目的是压缩。视频编码是一种压缩技术,可以减少数据量,并按照某种编码规范组织视频数据。
封装格式也叫容器,它会把已经编码压缩好的视频轨、音频轨、字幕、时间戳等信息按照一定格式放到一个文件中。常见封装格式(也就是常见后缀)有 mp4、mov、avi、mkv 等。
有博主对这些编码器生成的视频体积做了测试:
| 编解码器代码 | 编解码器类型 | 文件大小 | 后缀 |
|---|---|---|---|
'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 码流可以封装到
mp4、mkv、avi等多种容器中,具体取决于封装工具和参数。
关于授权也要区分几个概念: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 の 宇宙船
评论