2. 视频设备打开与关闭

任务目标

实现V4L2视频设备的打开与关闭操作,包含打开失败时的错误处理,并确保设备文件描述符在关闭时正确释放。本案例以Linux字符设备(如/dev/video0)为操作对象,通过系统调用完成设备生命周期管理。

核心实现

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

#define DEVICE_PATH "/dev/video0"

/**
 * 打开V4L2视频设备
 * @param path 设备文件路径
 * @return 成功返回文件描述符(>=0),失败返回-1
 */
int v4l2_open_device(const char *path) {
    if (path == NULL) {
        fprintf(stderr, "错误:设备路径为空\n");
        return -1;
    }

    int fd = open(path, O_RDWR);
    if (fd < 0) {
        perror("打开设备失败");
        return -1;
    }

    // 验证设备是否为V4L2视频设备
    struct v4l2_capability cap;
    memset(&cap, 0, sizeof(cap));
    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
        perror("查询设备能力失败");
        close(fd);
        return -1;
    }

    // 检查是否为视频采集设备(可选校验)
    if (!(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
        fprintf(stderr, "错误:%s 不是视频采集设备\n", path);
        close(fd);
        return -1;
    }

    printf("成功打开设备: %s\n", path);
    printf("驱动名称: %s\n", cap.driver);
    printf("设备名称: %s\n", cap.card);

    return fd;
}

/**
 * 关闭V4L2视频设备
 * @param fd 设备文件描述符
 * @return 0表示成功,-1表示失败
 */
int v4l2_close_device(int fd) {
    if (fd < 0) {
        fprintf(stderr, "错误:无效的文件描述符\n");
        return -1;
    }

    if (close(fd) < 0) {
        perror("关闭设备失败");
        return -1;
    }

    printf("设备已关闭 (fd=%d)\n", fd);
    return 0;
}

int main(void) {
    int fd = v4l2_open_device(DEVICE_PATH);
    if (fd < 0) {
        return EXIT_FAILURE;
    }

    // 此处可插入后续操作(如格式设置、缓冲申请等)

    if (v4l2_close_device(fd) < 0) {
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

编译与运行

# 编译(需要Linux内核头文件)
gcc -o v4l2_open_close v4l2_open_close.c

# 运行(需要root权限或video组权限)
./v4l2_open_close

验证方法

  • 正常路径:运行程序后,终端应依次输出设备打开成功信息(含驱动名称和设备名称)以及设备关闭信息,程序退出码为0。
  • 错误路径测试:将DEVICE_PATH改为不存在的路径(如/dev/video99),重新编译运行,程序应输出打开设备失败错误并返回非零退出码。
  • 资源释放验证:在程序运行期间,通过另一终端执行ls -l /proc/$(pgrep v4l2_open_close)/fd,可观察到设备文件描述符在关闭后不再出现在列表中。

关键说明

  • 打开设备使用O_RDWR模式,确保后续可进行读写操作;若仅需查询能力,可使用O_RDONLY。
  • 通过VIDIOC_QUERYCAP ioctl验证设备身份,避免误操作非V4L2设备;若设备不支持该ioctl,open虽成功但后续操作会失败,因此必须检查此步骤。
  • 关闭设备时只需调用close(),内核会自动释放相关资源;本案例中的v4l2_close_device封装主要用于统一错误处理和日志输出。
  • 若系统存在多个视频设备,可通过修改DEVICE_PATH宏或将其改为命令行参数来适配不同设备。