【C++】开源:Linux端V4L2视频设备库

news2024/11/24 16:46:02

😏★,°:.☆( ̄▽ ̄)/$:.°★ 😏
这篇文章主要介绍Linux端V4L2视频设备库。
无专精则不能成,无涉猎则不能通。——梁启超
欢迎来到我的博客,一起学习,共同进步。
喜欢的朋友可以关注一下,下次更新不迷路🥞

文章目录

    • :smirk:1. 项目介绍
    • :blush:2. 环境配置
    • :satisfied:3. 使用说明

😏1. 项目介绍

Video4Linux2(V4L2)是一个用于Linux操作系统的视频设备驱动框架。它提供了一个统一的接口,用于在应用程序和视频设备之间进行通信和交互。

V4L2支持各种类型的视频设备,包括USB摄像头、摄像机、TV调谐器、网络摄像头等。通过使用V4L2,开发者可以轻松地访问和控制视频设备,以捕获视频流、调整图像参数、设置视频格式和分辨率等。

以下是V4L2的一些重要特点和概念:

1.设备节点:每个视频设备在Linux系统中都表示为一个设备节点,通常位于/dev/video*路径下。应用程序通过打开这些设备节点来访问相应的视频设备。

2.视频捕捉:V4L2允许应用程序从视频设备中捕获视频帧或图像。它提供了一系列的API函数,使应用程序能够请求存储视频帧的缓冲区,并在设备准备好时将其读取到内存中。

3.视频输出:除了捕获视频,V4L2还支持将视频数据发送到视频设备,以便在外部显示设备上进行输出。应用程序可以将视频帧写入输出缓冲区,并通过相应的IOCTL调用将其发送到视频设备。

4.控制和参数设置:V4L2允许应用程序对视频设备进行控制和配置。例如,应用程序可以设置摄像头的亮度、对比度、饱和度等参数,选择摄像头的输入源,设置视频格式和分辨率等。

5.帧缓冲管理:V4L2通过Frame Buffer子系统来管理视频帧的缓冲区。它提供了API函数来请求和管理用于存储视频帧的缓冲区,并进行帧缓冲的交换和处理。

😊2. 环境配置

下面进行环境配置:

# v4l2是linux内核的一部分,只需安装开发库
sudo apt-get install libv4l-dev
# 使用v4l2开发
# 在应用程序中使用 #include <linux/videodev2.h> 来引入V4L2的头文件,并使用相关的API函数

😆3. 使用说明

下面进行使用分析:

基于v4l2调用usb摄像头并用opencv显示示例:

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>	//共享内存
#include <linux/videodev2.h>
#include <opencv2/opencv.hpp>

#define WIDTH 640
#define HEIGHT 480

int main() {
    int fd;
    struct v4l2_capability cap;
    struct v4l2_format fmt;
    struct v4l2_requestbuffers req;
    struct v4l2_buffer buf;
    enum v4l2_buf_type type;

    // 打开摄像头设备
    fd = open("/dev/video0", O_RDWR);
    if (fd == -1) {
        std::cerr << "无法打开摄像头设备" << std::endl;
        return 1;
    }

    // 查询摄像头能力
    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
        std::cerr << "无法查询摄像头能力" << std::endl;
        close(fd);
        return 1;
    }

    // 设置视频格式
    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; // YUV格式
    if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
        std::cerr << "无法设置视频格式" << std::endl;
        close(fd);
        return 1;
    }

    // 请求视频缓冲区
    memset(&req, 0, sizeof(req));
    req.count = 1;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
        std::cerr << "无法请求视频缓冲区" << std::endl;
        close(fd);
        return 1;
    }

    // 映射视频缓冲区到用户空间
    struct v4l2_buffer* buffers = new v4l2_buffer[req.count];
    void** frame_buffers = new void*[req.count];
    for (int i = 0; i < req.count; i++) {
        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) {
            std::cerr << "无法查询视频缓冲区" << std::endl;
            close(fd);
            return 1;
        }
        frame_buffers[i] = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
        if (frame_buffers[i] == MAP_FAILED) {
            std::cerr << "无法映射视频缓冲区到用户空间" << std::endl;
            close(fd);
            return 1;
        }
    }

    // 入队视频缓冲区
    for (int i = 0; i < req.count; i++) {
        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) {
            std::cerr << "无法入队视频缓冲区" << std::endl;
            close(fd);
            return 1;
        }
    }

    // 开始视频流采集
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) {
        std::cerr << "无法开始视频流采集" << std::endl;
        close(fd);
        return 1;
    }

    // 循环获取并显示相机数据
    cv::Mat frame(HEIGHT, WIDTH, CV_8UC2);
    cv::namedWindow("Camera", cv::WINDOW_AUTOSIZE);
    while (true) {
        // 出队视频缓冲区
        memset(&buf, 0, sizeof(buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
            std::cerr << "无法出队视频缓冲区" << std::endl;
            close(fd);
            return 1;
        }

        // 处理相机数据(这里只是简单地将YUYV格式的数据转换为RGB格式)
        cv::cvtColor(cv::Mat(HEIGHT, WIDTH, CV_8UC2, frame_buffers[buf.index]), frame, cv::COLOR_YUV2BGR_YUYV);

        // 显示相机数据
        cv::imshow("Camera", frame);
        if (cv::waitKey(1) == 27) {
            break; // 按下Esc键退出循环
        }

        // 再次入队视频缓冲区
        if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
            std::cerr << "无法再次入队视频缓冲区" << std::endl;
            close(fd);
            return 1;
        }
    }

    // 停止视频流采集
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) {
        std::cerr << "无法停止视频流采集" << std::endl;
        close(fd);
        return 1;
    }

    // 解除映射视频缓冲区
    for (int i = 0; i < req.count; i++) {
        munmap(frame_buffers[i], buf.length);
    }

    // 关闭摄像头设备
    close(fd);

    delete[] buffers;
    delete[] frame_buffers;

    return 0;
}

编译运行:

g++ -o main main.cpp `pkg-config --libs opencv`
./main

在这里插入图片描述

以上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/820073.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

笨办法学python3进阶篇pdf,笨办法学python3pdf完整版

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;笨办法学python 3电子书下载&#xff0c;笨办法学python3pdf完整版&#xff0c;今天让我们一起来看看吧&#xff01; 1、笨方法学python习题43 按照你说的 Map是一个类&#xff0c;scene_map是一老胡镇个类实例 scene_…

Scratch 详解 流畅光线追踪(盲区)引擎:角度 + 一次函数 + 区域判断

【提示1】本文将全程使用原版积木实现这一功能&#xff0c;请不要在评论区发送扩展中有相应积木。若喜欢使用扩展&#xff0c;可以自行将本文介绍的方法用扩展积木替代。 【提示2】本文中代码里出现的所有最后带*号的变量&#xff0c;均为私有变量&#xff01; 正文 近日&…

C数据结构——无向图(邻接矩阵方式) 创建与基本使用

源码注释 // // Created by Lenovo on 2022-05-13-上午 9:06. // 作者&#xff1a;小象 // 版本&#xff1a;1.0 //#include <stdio.h> #include <malloc.h>#define MAXSIZE 1000 // BFS队列可能达到的最大长度 #define MAX_AMVNUMS 100 // 最大顶点数typedef enu…

用SpringBoot实现post和get请求(多图)

用SpringBoot实现post和get请求&#xff08;多图&#xff09; 用SpringBoot实现post和get请求创建SpringBoot工程创建controller验证FAQ创建项目后依赖报错Project org.springframework.boot:spring-boot-starter-parent:3.1.2.RELEASE not found more 用SpringBoot实现post和g…

AQS构建锁和同步器的框架

1.概述 AQS全称AbstractQueuedSynchronizer&#xff0c;此类在java.util.concurrent.locks包下面&#xff0c;是一个构建锁和同步器的框架&#xff0c;比如ReentrantLock就是基于AQS来实现的。 2.AQS实现原理 AQS内部有一个由volatile修饰(保证其可见性)的变量state&#xf…

PDF文件忘记密码,怎么办?

PDF文件设置密码分为打开密码和限制密码&#xff0c;忘记了密码分别如何解密PDF密码&#xff1f; 如果是限制编辑密码忘记了&#xff0c;我们可以试着将PDF文件转换成其他格式来避开限制编辑&#xff0c;然后重新将文件转换回PDF格式就可以了。 如果因为转换之后导致文件格式…

Tuxera NTFS2023Mac强大的Mac读写工具

Mac用户在使用NTFS格式移动硬盘时&#xff0c;会遇到无法写入硬盘的情况。要想解决无法写入的问题&#xff0c;很多人选择使用Mac读写软件。面对市面上“众多”的读写硬盘软件&#xff0c;用户应该怎么选择呢&#xff1f;初次接触移动硬盘的伙伴可能不知道移动硬盘怎么和电脑连…

RabbitMQ 教程 | 第6章 RabbitMQ 配置

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

科大讯飞 - 基于论文摘要的文本分类与关键词抽取挑战赛(DataWhale-Camp)

文章目录 1、赛题信息2、解决方案2.1 飞桨Baseline&#xff08;提供代码&#xff09;2.2 Bert和调参2.3 chatGLMlora大模型 3、关于DataWhale-NLP 1、赛题信息 提交地址&#xff1a;https://challenge.xfyun.cn/topic/info?typeabstract-of-the-paper&chymfk4uU 项目题目…

我的会议(会议通知)

前言: 我们在实现了发布会议功能&#xff0c;我的会议功能的基础上&#xff0c;继续来实现会议通知的功能。 4.1实现的特色功能&#xff1a; 当有会议要参加时&#xff0c;通过查询会议通知可以知道会议的内容&#xff0c;以及当前会议状态&#xff08;未读&#xff09; 4.2思路…

在Linux中怎么查找文件

2023年8月1日&#xff0c;周二上午 目录 Linux的四种搜索命令find简要说明举例说明拓展阅读locate 简要说明举例说明whereis简要说明举例说明which简要说明举例说明 Linux的四种搜索命令 findlocate&#xff08;不一定内置有&#xff0c;可能要下载mlocate包&#xff09;wher…

【概念理解】HAL库的滴答定时器HAL_Delay()函数的实现原理

来源&#xff1a;bilibili视频 这里写目录标题 概述一、寄存器部分1. 控制和状态寄存器(STK_CTRL)2. 加载值寄存器&#xff08;STK_LOAD&#xff09;3.当前值寄存器&#xff08;STK_VAL&#xff09; 二、代码部分hal_delay()1. hal_initTick()滴答定时器的初始化2. 将七万二传…

Redis 客户端有哪些?

文章目录 JedisLettuceRedisson最佳实践 - 到底用哪个&#xff1f; Redis 最常见的 Java 客户端有两个&#xff0c;Jedis 和 Lettuce&#xff0c;高级客户端有 Redisson&#xff0c;见下图&#xff08;图源 Clients | Redis&#xff09; Jedis Github地址&#xff1a;redis/j…

Windows下安装Hive(包安装成功)

Windows下安装Hive Hive与Hadoop的版本选择很关键&#xff0c;千万不能选错&#xff0c;否则各种报错。一、Hive下载1.1、官网下载Hive1.2、网盘下载Hive 二、解压安装包&#xff0c;配置Hive环境变量2.1、环境变量新增&#xff1a;HIVE_HOME2.2、修改Path环境变量&#xff0c;…

Oracle免费在线编程:Oracle APEX

前提&#xff1a; 注意&#xff1a;你要有个梯子才能更稳定的访问。 不需要安装Oracle&#xff0c;但是需要注册。&#xff08;还算方便的&#xff09; 注册&登录过程 进入Oracle APEX官网&#xff0c;我们选择免费的APEX工作区即可&#xff0c;点击“免费注册”。在注册…

基于H5或者微信小程序开发GIS地图实战全套代码

1 下面有一定基础的可以不看 (1)第一篇请看 微信小程序开发天地图 (2)第二篇请看 http://GeoServer+PostgreSQL+PostGIS+Tomcat+QGIS一整套相关 (3)第三篇请看 有国产化需求的 (4)第四篇请看 支持国家EPSG:4490 2 vue+openlayers实例代码

ThreadLocal原理

ThreadLocal原理 ThreadLocal对象new出来存放到堆中&#xff0c;ThreadLocal引用是存放在栈里 Thread 类有个 ThreadLocalMap 成员变量&#xff0c;Map的key是Threadlocal 对象&#xff0c;value是你要存放的线程局部变量。 public void set(T value) {//获取当前线程Thread&…

SpringBoot复习:(11)SpringApplication中的listeners成员变量是怎么初始化的?

initializers成员变量定义如下&#xff1a; 在构造方法中&#xff1a; setListeners代码如下&#xff1a; 给setListeners方法传递的是getSpringFactoriesInstances(ApplicationListener.class). getSpringFactoriesInstances代码如下&#xff1a; 调用的重载的getSpringFa…

redis 高级篇4 分布式锁

一 redis架构图 1.1 redis的架构图 1.2 分布式锁满足条件 1.独占性&#xff1b;2.高可用&#xff1b;3.防死锁&#xff1b;4.不乱抢&#xff1b;5.重入性 二 分布式锁的案例情况 2.1 分布式锁1:单机分布式部署 描述&#xff1a; 使用lock锁和synchronized&#xff0c;单机…

【shell】获取ping的时延数据并分析网络情况及常用命令学习

文章目录 获取ping的时延数据并分析网络情况|、||、&、&&辨析teetailkillall 获取ping的时延数据并分析网络情况 网络情况经常让我们头疼&#xff0c;每次都需要手动在终端ping太麻烦了&#xff0c;不如写个脚本ping并将数据带上时间戳存入文件&#xff0c;然后也…