3. 枚举视频格式
任务目标
编写一个V4L2用户空间程序,通过 VIDIOC_ENUM_FMT ioctl 枚举摄像头设备支持的像素格式,并打印每种格式的描述字符串、四字符像素格式标识(如 YUYV、MJPG)以及该格式是否为压缩格式。此操作是后续调用 VIDIOC_S_FMT 设置采集格式前的必要准备步骤。
核心实现
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
int main(int argc, char *argv[])
{
const char *dev_path = argc > 1 ? argv[1] : "/dev/video0";
int fd = open(dev_path, O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
struct v4l2_fmtdesc fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("设备: %s\n", dev_path);
printf("支持的像素格式:\n");
printf("%-8s %-12s %-10s %s\n", "索引", "四字符码", "压缩", "描述");
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0) {
char fourcc[5] = {0};
memcpy(fourcc, &fmt.pixelformat, 4);
const char *compressed = (fmt.flags & V4L2_FMT_FLAG_COMPRESSED) ?
"是" : "否";
printf("%-8u %-12s %-10s %s\n",
fmt.index, fourcc, compressed, fmt.description);
fmt.index++;
}
close(fd);
return 0;
}
编译与运行
# 编译(需要内核头文件,通常由 build-essential / linux-libc-dev 提供)
gcc -o enum_fmt enum_fmt.c
# 运行(默认打开 /dev/video0,也可指定其他设备节点)
./enum_fmt /dev/video0
验证方法
在已接入USB摄像头或具备Video Capture能力的开发板上执行上述程序。判定通过的观察点:
- 程序正常退出且无
Invalid argument错误——若设备不支持视频采集,ioctl 会返回EINVAL,此时应检查设备节点是否为正确的capture设备。 - 输出中至少包含一行格式记录,且四字符码与描述对应合理(例如
YUYV对应 “YUV 4:2:2”,MJPG对应 “MJPEG”)。 - 压缩标志与格式性质一致:MJPG、H264 等编码格式显示“是”,原始 YUV/RGB 格式显示“否”。
- 可用
v4l2-ctl --list-formats交叉验证(若已安装 v4l-utils),两者列出的格式集合应一致。
关键说明
程序通过递增 fmt.index 遍历所有格式,直到 ioctl 返回非零值(EINVAL)表示枚举完毕。V4L2_FMT_FLAG_COMPRESSED 标志位用于区分压缩格式,该标志并非所有驱动都会正确设置,若某些已知压缩格式未显示“是”,属于驱动实现差异,不影响格式枚举主流程。此程序仅完成格式查询,不修改设备任何状态,可安全重复执行。