音视频开发之V4L2

V4L2(Video for Linux 2)是 Linux 内核中用于视频设备的子系统,提供了统一的接口,使用户空间程序能够与各种视频设备进行通信和控制。V4L2 主要用于处理视频输入设备(例如摄像头)和视频输出设备(例如显示屏等)。

V4L2 提供了一个统一的接口,允许用户空间程序与各种视频设备进行通信,而无需了解底层硬件的具体细节。这使得开发视频应用程序更加方便。 同时V4L2 支持各种不同类型的视频设备,包括摄像头、视频采集卡、Webcam 等。这些设备可以通过 V4L2 接口进行访问和控制。V4L2 支持多种视频和图像格式,包括 YUV 格式、RGB 格式等。V4L2 允许用户从视频设备中采集视频流,并提供了配置和控制相关参数的功能,除了采集视频流,V4L2 还支持将视频流输出到显示设备或其他目标等。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define VIDEO_DEVICE "/dev/video0"
#define WIDTH 640
#define HEIGHT 480
#define NUM_BUFFERS 4

//打开摄像头设备
int fd = open(VIDEO_DEVICE, O_RDWR);
if (fd == -1) {
    perror("Error opening device");
    exit(EXIT_FAILURE);
}

//设置视频格式
struct v4l2_format fmt = {0};
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = WIDTH;
fmt.fmt.pix.height = HEIGHT;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; // 使用 MJPEG 格式,可以根据需求选择其他格式

if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
    perror("Error setting format");
    exit(EXIT_FAILURE);
}


//请求缓冲区
struct v4l2_requestbuffers req = {0};
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
req.count = NUM_BUFFERS;

if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
    perror("Error requesting buffers");
    exit(EXIT_FAILURE);
}

struct buffer {
    void *start;
    size_t length;
} *buffers = calloc(req.count, sizeof(*buffers));


// 映射缓冲区到用户空间
for (unsigned int i = 0; i < req.count; ++i) {
    struct v4l2_buffer buf = {0};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;

    if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
        perror("Error querying buffer");
        exit(EXIT_FAILURE);
    }

    buffers[i].length = buf.length;
    buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);

    if (buffers[i].start == MAP_FAILED) {
        perror("Error mapping buffer");
        exit(EXIT_FAILURE);
    }
}

// 启动视频流
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) {
    perror("Error starting stream");
    exit(EXIT_FAILURE);
}

//捕获视频帧
while (1) {
    struct v4l2_buffer buf = {0};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
        perror("Error dequeueing buffer");
        exit(EXIT_FAILURE);
    }

    // 处理图像数据,可以在这里添加对图像的处理代码

    if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
        perror("Error queueing buffer");
        exit(EXIT_FAILURE);
    }
}

// 停止视频流和清理资源
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) {
    perror("Error stopping stream");
    exit(EXIT_FAILURE);
}

for (unsigned int i = 0; i < req.count; ++i) {
    munmap(buffers[i].start, buffers[i].length);
}

free(buffers);
close(fd);


步骤总结

  1. 打开设备: 使用 open 函数打开视频设备文件。
  2. 配置参数: 使用 VIDIOC_S_FMT 设置视频设备的格式和参数。
  3. 请求缓冲区: 使用 VIDIOC_REQBUFS 请求视频缓冲区。
  4. 映射缓冲区: 使用 mmap 将内核缓冲区映射到用户空间。
  5. 启动视频流: 使用 VIDIOC_STREAMON 启动视频流。
  6. 捕获和处理帧:使用 VIDIOC_QBUF 将缓冲区排队,然后使用 VIDIOC_DQBUF 从队列中取出缓冲区并处理捕获的帧。
  7. 停止视频流使用 VIDIOC_STREAMOFF 停止视频流。
  8. 释放资源:释放映射的缓冲区和关闭设备文件。

编程的注意事项
1.确保硬件设备(例如摄像头)支持 V4L2 接口。确保V4L2 内核模块已加载。可以使用 lsmod | grep videodev 命令来检查是否加载了 videodev 模块。
2.对于每个 V4L2 API 调用都要进行错误处理。V4L2 操作可能会失败,需要适当地处理错误情况
3.使用 mmap 函数将内核缓冲区映射到用户空间。注意处理内存映射的错误和释放映射的资源。

你可能感兴趣的:(音视频开发,音视频)