2. 编写第一个 V4L2 字符设备驱动骨架
任务目标
编写一个Linux用户空间程序,通过V4L2接口打开摄像头设备(如/dev/video0),查询并打印其设备能力信息,包括驱动名称、设备名称、总线信息、版本号、支持的文件格式(I/O方法)以及设备能力标志。该程序是后续所有V4L2摄像头操作(采集、设置格式等)的基础探测步骤。
环境与依赖
- Linux系统(带V4L2内核支持,标准内核均已包含)
- 摄像头设备节点:
/dev/video0(若设备不同,通过命令行参数指定) - 编译器:gcc
- 头文件:
linux/videodev2.h(系统自带)、sys/ioctl.h、fcntl.h
关键完整代码
// v4l2_query_caps.c
#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_capability(const struct v4l2_capability *cap) {
printf("驱动名称 (driver) : %s\n", cap->driver);
printf("设备名称 (card) : %s\n", cap->card);
printf("总线信息 (bus_info) : %s\n", cap->bus_info);
printf("内核版本 (version) : %u.%u.%u\n",
(cap->version >> 16) & 0xFF,
(cap->version >> 8) & 0xFF,
cap->version & 0xFF);
printf("设备能力 (capabilities): 0x%08X\n", cap->capabilities);
printf(" 支持的文件格式:\n");
if (cap->capabilities & V4L2_CAP_VIDEO_CAPTURE)
printf(" - 视频采集 (Video Capture)\n");
if (cap->capabilities & V4L2_CAP_VIDEO_OUTPUT)
printf(" - 视频输出 (Video Output)\n");
if (cap->capabilities & V4L2_CAP_STREAMING)
printf(" - 流式I/O (Streaming)\n");
if (cap->capabilities & V4L2_CAP_READWRITE)
printf(" - 读写I/O (Read/Write)\n");
printf("设备专用能力 (device_caps): 0x%08X\n", cap->device_caps);
}
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("打开设备失败");
return 1;
}
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
perror("VIDIOC_QUERYCAP 失败");
close(fd);
return 1;
}
print_capability(&cap);
close(fd);
return 0;
}
编译与运行
# 编译
gcc -o v4l2_query_caps v4l2_query_caps.c
# 运行(默认查询 /dev/video0)
./v4l2_query_caps
# 指定其他设备节点
./v4l2_query_caps /dev/video1
验证方法与判定标准
- 权限检查:若打开设备返回
Permission denied,将当前用户加入video组或使用sudo运行。 - 成功标志:程序正常退出(exit code 0),并打印出非空的driver、card、bus_info字段。
- 能力字段合理性:对于标准UVC摄像头,
driver通常为uvcvideo;capabilities应包含V4L2_CAP_VIDEO_CAPTURE和V4L2_CAP_STREAMING。若打印的driver为uvcvideo且包含上述标志,说明查询成功。 - 交叉验证:可运行系统命令
v4l2-ctl --device=/dev/video0 --all(需安装v4l-utils包)对比Driver name、Card type等字段,应与本程序输出一致。
常见问题
- ioctl返回ENOTTY:设备节点不是V4L2设备(如普通串口),确认
/dev/video*路径正确。 - 打开设备失败ENOENT:设备节点不存在,检查摄像头是否连接或驱动是否加载(
ls /dev/video*)。 - device_caps与capabilities的区别:
capabilities表示设备整体能力,device_caps表示当前设备节点实际可用的能力。对大多数单节点摄像头,两者一致。