1. V4L2框架初探

V4L2框架初探 学习卡片

任务目标

在Linux系统中,通过V4L2框架打开摄像头设备节点(如/dev/video0),验证设备可访问性,并读取设备的基本能力信息。这是V4L2驱动开发的第一步,后续所有采集、控制操作都建立在此基础之上。

环境与依赖

  • Linux系统(带V4L2内核支持,标准内核已包含)
  • 摄像头设备(USB摄像头或板载摄像头),设备节点存在:ls /dev/video*
  • 编译器:gcc
  • 无需额外安装库,直接使用系统头文件<linux/videodev2.h>和<sys/ioctl.h>

关键完整代码

// open_camera.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[]) {
    const char *dev_path = (argc > 1) ? argv[1] : "/dev/video0";
    
    // 1. 打开设备(非阻塞模式,避免某些驱动在无信号时阻塞)
    int fd = open(dev_path, O_RDWR | O_NONBLOCK);
    if (fd < 0) {
        printf("打开 %s 失败: %s\n", dev_path, strerror(errno));
        return 1;
    }
    printf("成功打开 %s (fd=%d)\n", dev_path, fd);
    
    // 2. 查询设备能力,确认这是一个V4L2设备
    struct v4l2_capability cap;
    memset(&cap, 0, sizeof(cap));
    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
        printf("VIDIOC_QUERYCAP 失败: %s\n", strerror(errno));
        close(fd);
        return 1;
    }
    
    // 3. 打印关键信息
    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);
    
    // 4. 检查是否为视频采集设备
    if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
        printf("支持视频采集\n");
    } else {
        printf("警告: 该设备不支持视频采集\n");
    }
    
    // 5. 关闭设备
    close(fd);
    printf("设备已关闭\n");
    return 0;
}

编译与运行

# 编译
gcc -o open_camera open_camera.c

# 运行(默认打开 /dev/video0,也可指定其他设备节点)
./open_camera
# 或指定设备
./open_camera /dev/video1

验证方法与判定标准

运行程序后,观察输出:

  • 通过条件:程序依次打印“成功打开设备”、驱动名称、设备名称、总线信息、驱动版本,最后打印“设备已关闭”,退出码为0。
  • 驱动名称:USB摄像头通常显示uvcvideo;板载摄像头可能显示ov5640、imx219等SoC驱动名。
  • 设备名称:显示摄像头型号或平台名称,如USB Camera或OV5640。
  • 失败排查:若打开失败提示No such file or directory,说明设备节点不存在,检查摄像头连接或使用ls /dev/video*确认节点号;若提示Permission denied,需要将当前用户加入video组或使用sudo运行。

常见问题

  • VIDIOC_QUERYCAP失败:该节点可能不是V4L2设备(如某些虚拟节点),确认/dev/video*对应的设备类型。
  • 打开阻塞:部分驱动在打开时若没有视频源会阻塞,使用O_NONBLOCK标志可避免此问题,本代码已包含。
  • 多摄像头设备:系统中有多个摄像头时,/dev/video0不一定是第一个物理摄像头,可通过cat /sys/class/video4linux/video0/name查看对应关系。