2. 查询摄像头能力集

任务目标

编写一个Linux用户空间程序,通过 VIDIOC_QUERYCAP ioctl 查询摄像头设备(如 /dev/video0)的能力集,判断该设备是否为视频采集设备,并输出驱动名称(driver)、卡名(card)、总线信息(bus_info)、驱动版本(version)及设备能力标志(capabilities)。

环境与依赖

  • Linux 系统(带 V4L2 支持的内核)
  • 摄像头设备节点(如 /dev/video0),或使用 v4l2loopback 虚拟设备
  • 内核头文件(提供 <linux/videodev2.h>)
  • 编译器:gcc

关键完整代码

#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_capability cap;
    memset(&cap, 0, sizeof(cap));

    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
        perror("VIDIOC_QUERYCAP");
        close(fd);
        return 1;
    }

    printf("设备节点: %s\n", dev_path);
    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("设备能力标志 (capabilities): 0x%08X\n", cap.capabilities);
    printf("设备能力标志 (device_caps): 0x%08X\n", cap.device_caps);

    // 判断是否为视频采集设备
    if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
        printf("判定: 支持视频采集 (V4L2_CAP_VIDEO_CAPTURE)\n");
    } else if (cap.device_caps & V4L2_CAP_VIDEO_CAPTURE) {
        printf("判定: 通过 device_caps 支持视频采集\n");
    } else {
        printf("判定: 不是视频采集设备\n");
    }

    close(fd);
    return 0;
}

编译与运行

# 编译
gcc -o querycap querycap.c

# 运行(默认查询 /dev/video0,也可指定其他设备节点)
./querycap /dev/video0

验证方法与判定标准

  • 正常输出:程序能打印 driver、card、bus_info、version 及 capabilities 字段,说明 ioctl 调用成功。
  • 采集能力判断:对于真实摄像头或 v4l2loopback 设备,输出应包含“支持视频采集”的判定;若查询非采集设备(如 /dev/video0 为输出设备),则输出“不是视频采集设备”。
  • 错误处理:当设备节点不存在或无权限时,程序应通过 perror 打印错误信息并返回非零退出码。
  • 交叉验证:可使用 v4l2-ctl --all -d /dev/video0 对比 driver、card 等字段是否一致(若系统已安装 v4l2-utils)。

常见问题

  • 编译报错找不到头文件:确认内核头文件已安装(Debian/Ubuntu 安装 linux-libc-dev)。
  • ioctl 返回 EINVAL:设备节点不是 V4L2 设备,或内核不支持该 ioctl。
  • capabilities 与 device_caps 的区别:capabilities 表示设备整体能力,device_caps 表示当前设备节点实际可用的能力;对于多功能设备,两者可能不同。