3. 枚举视频格式

枚举视频格式:获取支持的像素格式 学习卡片

任务目标

编写一个V4L2用户空间程序,通过 VIDIOC_ENUM_FMT ioctl 枚举摄像头设备支持的像素格式,并打印每种格式的描述字符串、四字符像素格式标识(如 YUYV、MJPG)以及该格式是否为压缩格式。此操作是后续调用 VIDIOC_S_FMT 设置采集格式前的必要准备步骤。

核心实现

#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_fmtdesc fmt;
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    printf("设备: %s\n", dev_path);
    printf("支持的像素格式:\n");
    printf("%-8s %-12s %-10s %s\n", "索引", "四字符码", "压缩", "描述");

    while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0) {
        char fourcc[5] = {0};
        memcpy(fourcc, &fmt.pixelformat, 4);

        const char *compressed = (fmt.flags & V4L2_FMT_FLAG_COMPRESSED) ?
                                 "是" : "否";

        printf("%-8u %-12s %-10s %s\n",
               fmt.index, fourcc, compressed, fmt.description);

        fmt.index++;
    }

    close(fd);
    return 0;
}

编译与运行

# 编译(需要内核头文件,通常由 build-essential / linux-libc-dev 提供)
gcc -o enum_fmt enum_fmt.c

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

验证方法

在已接入USB摄像头或具备Video Capture能力的开发板上执行上述程序。判定通过的观察点:

  • 程序正常退出且无 Invalid argument 错误——若设备不支持视频采集,ioctl 会返回 EINVAL,此时应检查设备节点是否为正确的capture设备。
  • 输出中至少包含一行格式记录,且四字符码与描述对应合理(例如 YUYV 对应 “YUV 4:2:2”,MJPG 对应 “MJPEG”)。
  • 压缩标志与格式性质一致:MJPG、H264 等编码格式显示“是”,原始 YUV/RGB 格式显示“否”。
  • 可用 v4l2-ctl --list-formats 交叉验证(若已安装 v4l-utils),两者列出的格式集合应一致。

关键说明

程序通过递增 fmt.index 遍历所有格式,直到 ioctl 返回非零值(EINVAL)表示枚举完毕。V4L2_FMT_FLAG_COMPRESSED 标志位用于区分压缩格式,该标志并非所有驱动都会正确设置,若某些已知压缩格式未显示“是”,属于驱动实现差异,不影响格式枚举主流程。此程序仅完成格式查询,不修改设备任何状态,可安全重复执行。