3. 视频格式查询与打印
任务目标
编写一个V4L2用户态程序,打开指定摄像头设备,查询其支持的像素格式(YUYV、NV12、MJPG等)以及每种格式对应的分辨率列表,并将全部信息格式化打印到终端。
环境与依赖
- Linux系统(含V4L2框架),摄像头设备节点如
/dev/video0 - 内核已加载
videodev模块,摄像头驱动支持标准V4L2查询接口 - 编译依赖:Linux内核头文件(提供
<linux/videodev2.h>),gcc编译器
核心实现
程序通过 VIDIOC_ENUM_FMT 遍历所有像素格式,对每种格式再通过 VIDIOC_ENUM_FRAMESIZES 遍历其支持的分辨率。使用 ioctl 系统调用与驱动交互,全程无额外依赖库。
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
static const char *fourcc_to_str(unsigned int fourcc) {
static char buf[5];
buf[0] = (fourcc >> 0) & 0xFF;
buf[1] = (fourcc >> 8) & 0xFF;
buf[2] = (fourcc >> 16) & 0xFF;
buf[3] = (fourcc >> 24) & 0xFF;
buf[4] = '\0';
return buf;
}
int main(int argc, char *argv[]) {
const char *dev = (argc > 1) ? argv[1] : "/dev/video0";
int fd = open(dev, 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);
printf("========================================\n");
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0) {
printf("格式[%d]: %s (0x%08X) %s\n",
fmt.index, fourcc_to_str(fmt.pixelformat),
fmt.pixelformat, fmt.description);
struct v4l2_frmsizeenum frmsize;
memset(&frmsize, 0, sizeof(frmsize));
frmsize.pixel_format = fmt.pixelformat;
frmsize.index = 0;
while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) {
if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
printf(" %ux%u\n", frmsize.discrete.width,
frmsize.discrete.height);
} else if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
printf(" 步进范围: %u-%u x %u-%u (步长 %u x %u)\n",
frmsize.stepwise.min_width,
frmsize.stepwise.max_width,
frmsize.stepwise.min_height,
frmsize.stepwise.max_height,
frmsize.stepwise.step_width,
frmsize.stepwise.step_height);
break; // 步进范围只有一条记录
} else if (frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
printf(" 连续范围: %u-%u x %u-%u\n",
frmsize.stepwise.min_width,
frmsize.stepwise.max_width,
frmsize.stepwise.min_height,
frmsize.stepwise.max_height);
break;
}
frmsize.index++;
}
fmt.index++;
}
close(fd);
return 0;
}
编译与运行
# 编译
gcc -o v4l2_list_fmt v4l2_list_fmt.c
# 运行(默认查询 /dev/video0,也可指定其他设备)
./v4l2_list_fmt /dev/video0
验证方法
运行程序后,观察输出是否包含摄像头实际支持的格式与分辨率。可通过以下方式交叉验证:
- 使用
v4l2-ctl --list-formats-ext(若已安装v4l-utils)对比输出结果,两者应一致。 - 若摄像头支持YUYV且最大分辨率1920x1080,输出中应出现
YUYV条目且包含1920x1080。 - 程序正常退出且无
Invalid argument错误,说明所有格式枚举完成。
通过条件:程序能完整列出摄像头所有像素格式及对应分辨率,且与 v4l2-ctl 查询结果一致。
常见问题
- 打开设备失败:确认设备节点存在且当前用户有读写权限(可尝试
sudo)。 - 无任何输出:摄像头不支持
V4L2_BUF_TYPE_VIDEO_CAPTURE类型,或驱动未实现枚举接口。 - 分辨率缺失:部分驱动对
VIDIOC_ENUM_FRAMESIZES支持不完整,此时输出仅含格式名,属驱动限制。