4. 设置摄像头采集分辨率

任务目标

本案例实现通过V4L2 API设置摄像头采集分辨率,并验证设置是否生效。核心目标是:打开视频设备后,使用VIDIOC_S_FMT设置指定分辨率(如640x480),再通过VIDIOC_G_FMT读取实际生效格式,确认驱动接受该分辨率。

核心实现

#include <stdio.h>
#include <stdlib.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 = "/dev/video0";
    int width = 640, height = 480;
    if (argc >= 2) dev = argv[1];
    if (argc >= 4) { width = atoi(argv[2]); height = atoi(argv[3]); }

    int fd = open(dev, O_RDWR);
    if (fd < 0) { perror("open"); return 1; }

    struct v4l2_format fmt;
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = width;
    fmt.fmt.pix.height = height;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field = V4L2_FIELD_ANY;

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

    // 读取驱动实际采用的格式
    struct v4l2_format cur;
    memset(&cur, 0, sizeof(cur));
    cur.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl(fd, VIDIOC_G_FMT, &cur) < 0) {
        perror("VIDIOC_G_FMT");
        close(fd);
        return 1;
    }

    printf("请求: %dx%d\n", width, height);
    printf("实际: %dx%d, 像素格式: %c%c%c%c\n",
           cur.fmt.pix.width, cur.fmt.pix.height,
           (cur.fmt.pix.pixelformat >> 0) & 0xff,
           (cur.fmt.pix.pixelformat >> 8) & 0xff,
           (cur.fmt.pix.pixelformat >> 16) & 0xff,
           (cur.fmt.pix.pixelformat >> 24) & 0xff);

    close(fd);
    return 0;
}

编译与运行

# 编译
gcc -o set_resolution set_resolution.c

# 运行(默认 /dev/video0,640x480)
./set_resolution

# 指定设备和分辨率
./set_resolution /dev/video1 1280 720

验证方法

程序执行后观察输出:

  • 通过条件:输出中“实际”分辨率与“请求”一致(例如均为640x480),且像素格式为YUYV,说明驱动接受了设置。
  • 驱动调整情况:若实际分辨率与请求不同(如请求1280x720但实际为640x480),说明该设备/驱动不支持请求的分辨率,自动回退到最接近的可用值——这属于正常行为,并非程序错误。
  • 错误排查:若VIDIOC_S_FMT返回错误,常见原因是设备不支持YUYV格式或分辨率超出范围,可改用V4L2_PIX_FMT_MJPEG等格式测试。

关键说明

本程序仅完成格式协商,不涉及帧缓冲申请或数据采集。设置分辨率是采集流程的第一步,后续需通过VIDIOC_REQBUFS申请缓冲区并启动流,才能实际获取图像数据。像素格式V4L2_PIX_FMT_YUYV为大多数UVC摄像头默认支持,若设备不支持会返回错误,此时可查询驱动支持的格式列表(通过VIDIOC_ENUM_FMT)后替换。