2. 查询Camera能力集
任务说明
本案例实现一个Linux用户空间程序,通过V4L2接口的ioctl系统调用查询摄像头设备的能力集,包括支持的像素格式、分辨率范围及当前格式信息,并将结果打印输出。程序直接操作/dev/video0设备节点,适用于嵌入式Linux或标准Linux系统中接入的UVC/CSI摄像头。
核心实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
static void print_fourcc(__u32 fourcc) {
char code[5] = {
(char)(fourcc & 0xFF),
(char)((fourcc >> 8) & 0xFF),
(char)((fourcc >> 16) & 0xFF),
(char)((fourcc >> 24) & 0xFF),
'\0'
};
printf("%s", code);
}
static void query_capability(int fd) {
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
perror("VIDIOC_QUERYCAP");
return;
}
printf("驱动: %s\n", cap.driver);
printf("设备: %s\n", cap.card);
printf("总线: %s\n", cap.bus_info);
printf("版本: %u.%u.%u\n",
(cap.version >> 16) & 0xFF,
(cap.version >> 8) & 0xFF,
cap.version & 0xFF);
printf("能力标志: 0x%08X\n", cap.capabilities);
}
static void query_formats(int fd) {
struct v4l2_fmtdesc fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("\n支持的像素格式:\n");
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0) {
printf(" 索引 %d: ", fmt.index);
print_fourcc(fmt.pixelformat);
printf(" - %s\n", fmt.description);
fmt.index++;
}
}
static void query_frame_sizes(int fd, __u32 pixfmt) {
struct v4l2_frmsizeenum frmsize;
memset(&frmsize, 0, sizeof(frmsize));
frmsize.pixel_format = pixfmt;
printf(" 分辨率:\n");
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 ||
frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
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);
}
frmsize.index++;
}
}
static void query_current_format(int fd) {
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
perror("VIDIOC_G_FMT");
return;
}
printf("\n当前格式:\n");
printf(" 像素格式: ");
print_fourcc(fmt.fmt.pix.pixelformat);
printf("\n");
printf(" 分辨率: %ux%u\n",
fmt.fmt.pix.width,
fmt.fmt.pix.height);
printf(" 行字节数: %u\n", fmt.fmt.pix.bytesperline);
printf(" 图像大小: %u\n", fmt.fmt.pix.sizeimage);
}
int main(int argc, char *argv[]) {
const char *dev_path = "/dev/video0";
if (argc > 1) {
dev_path = argv[1];
}
int fd = open(dev_path, O_RDWR);
if (fd == -1) {
perror("open");
return 1;
}
query_capability(fd);
query_formats(fd);
struct v4l2_fmtdesc fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0) {
printf("\n格式: ");
print_fourcc(fmt.pixelformat);
printf("\n");
query_frame_sizes(fd, fmt.pixelformat);
fmt.index++;
}
query_current_format(fd);
close(fd);
return 0;
}
编译与运行
# 编译
gcc -o query_camera query_camera.c
# 运行(默认查询 /dev/video0)
./query_camera
# 指定其他设备节点
./query_camera /dev/video1
验证方法
在目标板上连接摄像头并确认设备节点存在后,执行编译好的程序。预期输出应包含以下内容:
- 设备信息段:以
驱动:、设备:、总线:开头的三行,分别显示摄像头驱动名称、设备名称和总线信息; - 格式枚举段:列出所有支持的像素格式,每行包含格式索引、四字符编码(如YUYV、MJPG、H264)和描述文字;
- 分辨率枚举段:对每种格式列出支持的分辨率,离散型显示为
宽x高,步进型显示为范围及步进值; - 当前格式段:以
当前格式:开头,显示当前生效的像素格式、分辨率、行字节数和图像大小。
判定标准:程序能完整打印上述四类信息且无VIDIOC_*错误输出,即表示ioctl查询能力集功能正常。若某个ioctl调用失败,程序会通过perror打印具体错误原因,可据此排查设备权限或驱动兼容性问题。