Linux下V4L2实时显示摄像头捕捉画面(完整QT+C++代码)

目录

一、V4L2

1、简介

2、编程与应用

二、示例演示

1、例子说明:

2、关键的代码演示

3、完整的例子的代码


一、V4L2

1、简介

        V4L2,即Video for Linux Two,是Linux下关于视频设备的内核驱动框架,为驱动和应用程序提供了一套统一的接口规范。

        在Linux中,视频设备被视为设备文件,通常位于/dev/video目录下。如果只有一个视频设备,它通常是/dev/video0

2、编程与应用

(1)编程框架:V4L2是针对UVC免驱USB设备的编程框架,主要用于采集USB摄像头等。编程时,开发者可以通过ioctl函数对设备的I/O通道进行管理,使用一系列特定的命令标志符来实现不同的功能。

(2)重要数据结构:V4L2在include/linux/videodev.h文件中定义了一些重要的数据结构,如v4l2_formatv4l2_crop等,用于描述视频设备的行为和数据的格式。

(3)主要函数:通过ioctl函数和一系列特定的命令标志符(如VIDIOC_REQBUFS、VIDIOC_QUERYBUF、VIDIOC_STREAMON等),开发者可以对视频设备进行参数设置、数据采集和处理等操作。

(4)注册流程:在进行视频数据流操作之前,首先需要通过标准的字符设备操作接口open方法来打开一个video设备,并返回设备句柄。之后的一系列操作都是基于对这个句柄的操作。在打开的过程中,会给每一个子设备进行各自的一系列初始化操作。

(5)应用场景:V4L2在远程会议、可视电话、视频监控系统和嵌入式多媒体终端等领域有广泛应用。

        总之,V4L2是Linux下功能强大的视频设备驱动框架,它提供了丰富的接口和灵活的数据结构,使得开发者能够轻松地实现视频数据的采集、处理和传输等功能。

二、示例演示

1、例子说明:

在ARM系统的机器中有摄像头,要对此机器的摄像头进行开关控制,并显示在屏幕上(或者实时显示Qt的窗口上)

或者用你的虚拟机连接摄像头设备也是可以。

(1)查看机器上面的摄像机设备号

2、关键的代码演示

(1)打开设备

int CameraCapture::Camera_OpenCam(const char *devicePath)
{
    qDebug() << __FUNCTION__ << __LINE__ ;

    fd_cam = open(devicePath, O_RDWR, 0);
    if (fd_cam < 0)
    {
        qDebug() << QString("Open failed (%1), %2 ")
                    .arg(QString::fromStdString(devicePath))
                    .arg(strerror(errno));
        return -1;
    }

    qDebug() << QString("fd_cam (%1) open successfully ").arg(QString::number(fd_cam));
    return fd_cam ;

}

(2)关闭摄像头

int CameraCapture::closeCamera()
{
    qDebug() << __FUNCTION__ << __LINE__ ;

    // 防止打开程序时候,就要关闭摄像头。
    if(fd_cam == -1)
    {
        qDebug() << __FUNCTION__ << __LINE__ << "当前没有打开摄像头,直接返回。";
        return 0;
    }

    // 清空当前数据
    Camera_UNMap(framebuf1);

    qDebug() << __FUNCTION__ << __LINE__  << QString("fd_cam " + QString::number(fd_cam));

    return close(fd_cam);
}

(3)获取摄像头的相关信息

int CameraCapture::Camera_GetCamInfo()
{
    int ret=-1 ;

    // GetDevicInfo
    struct v4l2_capability cap;
    ret = ioctl(fd_cam, VIDIOC_QUERYCAP, &cap);
    if (ret < 0)
    {
        qDebug() << "VIDIOC_QUERYCAP failed: " << QString::number(ret);
        return ret;
    }

    return ret ;
}

(4)获取摄像头中视频流的数据

int CameraCapture::Camera_RequestBuffers(v4l2_requestbuffers *reqbuf__)
{
    // Request Buffers from kernel
    int ret =-1 ;
    reqbuf__->count = BUFFER_COUNT;
    reqbuf__->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf__->memory = V4L2_MEMORY_MMAP;

    ret = ioctl(fd_cam , VIDIOC_REQBUFS, reqbuf__);

    if(ret < 0)
    {
        qDebug() << "VIDIOC_REQBUFS failed: " << QString::number(ret);
        return ret;
    }
    return ret ;
}
3、完整的例子的代码

(1)简单的例子演示

//下面是一段使用 V4L2 (Video for Linux 2) API 来打开和关闭摄像头的基本示例代码。
//这段代码展示了如何初始化设备、设置视频格式、捕获一帧图像并释放资源。

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

#define DEVICE_NAME "/dev/video0"
#define BUFFER_COUNT 4

// 结构体用于存储缓冲区信息
struct buffer {
    void *start;
    size_t length;
};

// 初始化缓冲区
int init_buffers(int fd, struct buffer *buffers) {
    struct v4l2_requestbuffers req;

    memset(&req, 0, sizeof(req));
    req.count = BUFFER_COUNT;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;

    if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
        perror("VIDIOC_REQBUFS");
        return -1;
    }

    buffers->length = req.length;
    for (unsigned int i = 0; i < req.count; ++i) {
        struct v4l2_buffer buf;

        memset(&buf, 0, sizeof(buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;

        if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
            perror("VIDIOC_QUERYBUF");
            return -1;
        }

        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("mmap");
            return -1;
        }
    }

    return 0;
}

// 清理缓冲区
void cleanup_buffers(int fd, struct buffer *buffers) 
{
    for (unsigned int i = 0; i < BUFFER_COUNT; ++i)
        munmap(buffers[i].start, buffers[i].length);
}

int main()
{
    int fd;
    struct v4l2_capability cap;
    struct v4l2_format fmt;
    struct buffer buffers[BUFFER_COUNT];
    struct v4l2_buffer buf;
    int ret;

    // 打开设备
    fd = open(DEVICE_NAME, O_RDWR);
    if (fd == -1) 
    {
        perror("open");
        return -1;
    }

    // 获取设备能力
    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
    {
        perror("VIDIOC_QUERYCAP");
    }
}
      

(2)将摄像头的功能进行简单封装,项目中实际应用

由于代码有点长,直接上传资源,有需要自行下载。

Linux下V4L2实时显示摄像头捕捉画面(完整QT+C++代码)资源-CSDN文库

要在Qt C++显示摄像头,请使用Video for Linux 2(V4L2)API。 以下是显示摄像头的基本步骤: 1. 打开摄像头设备: ```c++ int fd = open("/dev/video0", O_RDWR); if (fd == -1) { perror("Error opening device"); return -1; } ``` 2. 查询摄像头设备的参数: ```c++ struct v4l2_capability cap; if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) { perror("Error querying device capabilities"); return -1; } ``` 3. 设置摄像头设备的参数,如图像格式、分辨率、帧率等: ```c++ struct v4l2_format fmt; 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_INTERLACED; if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { perror("Error setting device format"); return -1; } ``` 4. 创建视频缓冲区: ```c++ struct v4l2_requestbuffers req; memset(&req, 0, sizeof(req)); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) { perror("Error requesting buffers"); return -1; } struct buffer { void *start; size_t length; }; buffer *buffers = new buffer[req.count]; for (int i = 0; i < req.count; ++i) { v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); 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"); return -1; } 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"); return -1; } } ``` 5. 开始视频采集: ```c++ for (int i = 0; i < req.count; ++i) { v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { perror("Error queuing buffer"); return -1; } } enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) { perror("Error starting stream"); return -1; } ``` 6. 读取视频数据并显示: ```c++ while (true) { fd_set fds; FD_ZERO(&fds); FD_SET(fd, &fds); timeval tv = {0}; tv.tv_sec = 2; int r = select(fd + 1, &fds, NULL, NULL, &tv); if (r == -1) { perror("Error waiting for frame"); return -1; } else if (r == 0) { perror("Timeout waiting for frame"); return -1; } v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) { perror("Error dequeuing buffer"); return -1; } // buf.index is the index of the buffer that contains the captured frame // buffers[buf.index].start contains the frame data // buffers[buf.index].length contains the length of the frame data // Display the frame using Qt or other libraries if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { perror("Error queuing buffer"); return -1; } } ``` 以上是基本的代码框架,你可以根据需要进行修改和优化。注意,这里没有包含错误处理和资源释放的代码,你需要自己添加。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值