2. 查询设备能力

任务目标

编写一个Linux用户空间程序,通过 VIDIOC_QUERYCAP ioctl 查询摄像头设备(如 /dev/video0)的能力信息,解析并打印驱动名称、设备名称、驱动版本号、总线信息以及设备支持的能力标志,并判断该设备是否为视频捕获设备(V4L2_CAP_VIDEO_CAPTURE)。

环境与依赖

  • Linux 系统(含 V4L2 框架,内核开启 CONFIG_VIDEO_DEV)
  • 摄像头设备节点 /dev/video0(或通过参数指定其他节点)
  • 内核头文件 linux/videodev2.h(通常由 libv4l-dev 或内核头文件包提供)
  • 编译工具:gcc

关键完整代码

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

static void print_capability_flag(__u32 flag, const char *name) {
    printf("    %s\n", name);
}

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("能力标志 (0x%08x):\n", cap.capabilities);
    if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
        print_capability_flag(V4L2_CAP_VIDEO_CAPTURE, "V4L2_CAP_VIDEO_CAPTURE - 视频捕获");
    if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
        print_capability_flag(V4L2_CAP_VIDEO_OUTPUT, "V4L2_CAP_VIDEO_OUTPUT - 视频输出");
    if (cap.capabilities & V4L2_CAP_STREAMING)
        print_capability_flag(V4L2_CAP_STREAMING, "V4L2_CAP_STREAMING - 流式I/O");
    if (cap.capabilities & V4L2_CAP_READWRITE)
        print_capability_flag(V4L2_CAP_READWRITE, "V4L2_CAP_READWRITE - 读写I/O");
    if (cap.capabilities & V4L2_CAP_DEVICE_CAPS)
        print_capability_flag(V4L2_CAP_DEVICE_CAPS, "V4L2_CAP_DEVICE_CAPS - 设备能力");

    if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
        printf("\n结论: 是视频捕获设备\n");
    else
        printf("\n结论: 不是视频捕获设备\n");

    close(fd);
    return 0;
}

编译与运行

# 编译
gcc -o querycap querycap.c

# 运行(默认查询 /dev/video0)
./querycap

# 指定其他设备节点
./querycap /dev/video1

验证方法与判定标准

  • 正常执行:程序能打开设备并成功调用 VIDIOC_QUERYCAP,输出驱动名、设备名、版本号等信息,无错误提示。
  • 能力解析正确:输出的能力标志与 v4l2-ctl --all -d /dev/video0 中 Driver Info 部分展示的 Capabilities 字段一致(若系统装有 v4l-utils)。
  • 捕获判断准确:对于标准 UVC 摄像头,输出应包含 V4L2_CAP_VIDEO_CAPTURE 且结论为“是视频捕获设备”;对于 TV 调谐器或视频输出设备,结论应相应变化。
  • 错误路径:指定不存在的设备节点(如 /dev/video99)时,程序应报错并返回非零退出码。

常见问题

  • 编译报错找不到 linux/videodev2.h:安装 libv4l-dev(Debian/Ubuntu)或 v4l-utils-devel(RHEL/Fedora)。
  • 打开设备失败 Permission denied:将当前用户加入 video 组,或使用 sudo 运行。
  • ioctl 返回 EINVAL:确认设备节点确实是 V4L2 视频设备,而非 DVB 或 radio 设备。