4. 设置视频格式为YUYV

任务目标

通过 V4L2 接口将摄像头采集格式设置为 YUYV,分辨率设置为 640x480,并读取当前格式进行验证,确认设置生效。

核心实现

本案例使用 Linux 标准 V4L2 框架,通过 VIDIOC_S_FMT 设置格式,再用 VIDIOC_G_FMT 读回确认。代码不依赖第三方库,仅需内核头文件,适用于嵌入式 Linux 或桌面 Linux 环境。

#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 fd;
    struct v4l2_format fmt;

    if (argc > 1)
        dev = argv[1];

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

    /* 1. 设置格式:YUYV 640x480 */
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = 640;
    fmt.fmt.pix.height = 480;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field = V4L2_FIELD_NONE;

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

    /* 2. 读回实际生效的格式 */
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0) {
        perror("VIDIOC_G_FMT");
        close(fd);
        return 1;
    }

    /* 3. 打印并验证 */
    printf("Driver: %s\n", dev);
    printf("Width:  %u\n", fmt.fmt.pix.width);
    printf("Height: %u\n", fmt.fmt.pix.height);
    printf("PixFmt: %c%c%c%c\n",
           (fmt.fmt.pix.pixelformat >> 0) & 0xff,
           (fmt.fmt.pix.pixelformat >> 8) & 0xff,
           (fmt.fmt.pix.pixelformat >> 16) & 0xff,
           (fmt.fmt.pix.pixelformat >> 24) & 0xff);

    close(fd);

    /* 4. 判定条件 */
    if (fmt.fmt.pix.width == 640 &&
        fmt.fmt.pix.height == 480 &&
        fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
        printf("RESULT: PASS\n");
        return 0;
    } else {
        printf("RESULT: FAIL (driver adjusted parameters)\n");
        return 1;
    }
}

编译与运行

# 编译
gcc -o set_yuyv set_yuyv.c

# 运行(默认 /dev/video0,可指定其他设备)
./set_yuyv /dev/video0

验证方法

  • 程序输出 Width: 640、Height: 480、PixFmt: YUYV,且最后一行显示 RESULT: PASS,表示设置成功。
  • 若输出 RESULT: FAIL,说明驱动不支持该格式或分辨率,实际参数已被驱动调整,可查看打印出的实际值确认驱动支持的能力。
  • 也可用 v4l2-ctl --list-formats-ext -d /dev/video0 预先确认设备是否支持 YUYV 640x480。

常见问题

  • 打开设备失败:确认设备节点存在,且当前用户有读写权限(可尝试 sudo)。
  • VIDIOC_S_FMT 返回错误:多为设备不支持 YUYV 或该分辨率,改用驱动支持的格式(如 MJPG)或降低分辨率测试。
  • 设置后读回值不同:部分驱动会就近调整参数,以读回值为准,这是正常行为。