Linux基于V4L2的视频捕捉
简介
linux环境使用V4l2实现摄像头捕捉,界面流畅播放并可以保存图片到本地。
代码
void VideoCapture::run()
{qDebug() << "VideoCapture start";// 打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){qDebug("video设备打开失败\n");return;}else{qDebug("video设备打开成功\n");}//查看设备是否为视频采集设备struct v4l2_capability vcap;ioctl(fd, VIDIOC_QUERYCAP, &vcap);if (!(V4L2_CAP_VIDEO_CAPTURE & vcap.capabilities)){qDebug("No capture video device!\n");return;}// 枚举帧格式struct v4l2_fmtdesc fmtdesc;fmtdesc.index = 0;fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;qDebug("Video支持所有格式如下:");while(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0){qDebug("v4l2_format %d:%s",fmtdesc.index, fmtdesc.description);fmtdesc.index++;}// 枚举分辨率struct v4l2_frmsizeenum frmsize;frmsize.index = 0;frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;qDebug("Video支持分辨率如下:");while(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0){qDebug("%d frame_size<%d*%d %d>", frmsize.index, frmsize.discrete.width, frmsize.discrete.height, frmsize.pixel_format);frmsize.index++;}// 枚举某分辨率下的帧速率int pixel_width = 1280;int pixel_height = 720;struct v4l2_frmivalenum frmival;frmival.index = 0;frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;frmival.pixel_format = V4L2_PIX_FMT_MJPEG;frmival.width = pixel_width;frmival.height = pixel_height;while(ioctl(fd,VIDIOC_ENUM_FRAMEINTERVALS, &frmival) == 0){qDebug("<%d*%d> support frame_size %dfps", frmival.width, frmival.height, frmival.discrete.denominator / frmival.discrete.numerator);frmival.index++;}// 设置采集格式struct v4l2_format vfmt;vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;vfmt.fmt.pix.width = pixel_width;vfmt.fmt.pix.height = pixel_height;vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;if(ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0){qDebug("video设置格式失败\n");return;}// 检查设置参数是否生效if(ioctl(fd, VIDIOC_G_FMT, &vfmt) < 0){qDebug("video获取格式失败\n");return;}// 获取帧信息struct v4l2_streamparm streamparm;streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;ioctl(fd, VIDIOC_G_PARM, &streamparm);qDebug("current frameRate <%d * %d>\n", streamparm.parm.capture.timeperframe.numerator, streamparm.parm.capture.timeperframe.denominator);// 设置帧信息if(V4L2_CAP_TIMEPERFRAME & streamparm.parm.capture.capability){streamparm.parm.capture.timeperframe.numerator = 1;streamparm.parm.capture.timeperframe.denominator = 30;
// if(ioctl(fd, VIDIOC_S_PARM, &streamparm) < 0)
// {
// qDebug("video设置帧率失败 <%d * %d>", streamparm.parm.capture.timeperframe.numerator, streamparm.parm.capture.timeperframe.denominator);
// }}// 申请缓冲区空间struct v4l2_requestbuffers reqbuf;reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;reqbuf.count = m_frameCount;reqbuf.memory = V4L2_MEMORY_MMAP;if(ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0){qDebug("video申请缓冲区失败\n");return;}// 将帧缓冲映射到进程地址空间struct v4l2_buffer buf;buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;// 将每一帧对应的缓冲区的起始地址保存在m_userVideoBuf数组中,读取采集数据时,只需直接读取映射区即可for(buf.index=0; buf.index<m_frameCount; buf.index++){ioctl(fd, VIDIOC_QUERYBUF, &buf);m_userVideoBuf[buf.index] = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);m_userVideoBufSize[buf.index] = buf.length;if(m_userVideoBuf[buf.index] == MAP_FAILED){qDebug("video mmap failed\n");return;}// 入队操作if(ioctl(fd, VIDIOC_QBUF, &buf) < 0){qDebug("入队失败\n");return;}}// 开始采集enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (ioctl(fd, VIDIOC_STREAMON, &type) < 0){qDebug("video开始采集失败");m_isRun = false;}//持续读取图像数据 使用select监听数据fd_set fds;struct timeval tv;tv.tv_sec = 2;tv.tv_usec = 0;//图片文件缓存char *fileBuf = new char[3*1024*1024];while(m_isRun){FD_ZERO(&fds);FD_SET(fd, &fds);int ret = select(fd+1, &fds, NULL, NULL, &tv);if(ret < 0){qDebug("select io error\n");break;}// 读取帧struct v4l2_buffer readbuffer;readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;readbuffer.memory = V4L2_MEMORY_MMAP;if(ioctl(fd, VIDIOC_DQBUF, &readbuffer) < 0){qDebug("读取帧失败\n");}// qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss:zzz");//重点:帧数据处理const uchar *data = (const uchar *)m_userVideoBuf[readbuffer.index];int length = readbuffer.length;//构造并显示QImage image = QImage::fromData(data, length);emit sigUpdateImage(image.copy());// 再次入队if(ioctl(fd, VIDIOC_QBUF, &readbuffer) < 0){qDebug("再次入队失败\n");}}// 停止采集if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0){qDebug("停止采集失败\n");}// 释放映射for(uint i=0; i<m_frameCount; i++){munmap(m_userVideoBuf[i], m_userVideoBufSize[i]);}//关闭文件emit sigUpdateImage(QImage());close(fd);delete[] fileBuf;qDebug() << "VideoCapture stop";
}相关文章:
Linux基于V4L2的视频捕捉
简介 linux环境使用V4l2实现摄像头捕捉,界面流畅播放并可以保存图片到本地。 代码 void VideoCapture::run() {qDebug() << "VideoCapture start";// 打开设备int fd open("/dev/video0", O_RDWR);if(fd < 0){qDebug("video设…...
ECS搭建2.8版本的redis
要在ECS(Elastic Compute Service)上手动搭建Redis 2.8版本,你可以按照以下步骤操作: 步骤1:更新系统和安装依赖 首先,登录到你的ECS实例,确保系统是最新的并安装必要的依赖包: s…...
[机器学习]GPT LoRA 大模型微调,生成猫耳娘
往期热门专栏回顾 专栏描述Java项目实战介绍Java组件安装、使用;手写框架等Aws服务器实战Aws Linux服务器上操作nginx、git、JDK、VueJava微服务实战Java 微服务实战,Spring Cloud Netflix套件、Spring Cloud Alibaba套件、Seata、gateway、shadingjdbc…...
代码随想录算法训练营Day24|216.组合总和III、17.电话号码的字母组合
组合总和III 216. 组合总和 III - 力扣(LeetCode) 思路和昨日的组合题类似,但注意对回溯算法中,收获时的条件需要写对,path的长度要为k的同时,path中元素总和要为n。 class Solution { public:vector<…...
【Python系列】Python 中方法定义与方法调用详解
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
Java 基础面试300题 (201-230)
Java 基础面试300题 (201-230) 201.下面代码片段的输出是什么? Predicate<Integer> numberChecker (num)–> num > 20; int input 10; System.out.println(input” greater than 20–”numberChecker.test(input)); //Line 1…...
Go-知识并发控制Context
Go-知识并发控制Context 1. 介绍2. 实现原理2.1 接口定义2.2 Deadline()2.3 Done()2.4 Err()2.5 Value() 3. 空 context4. cancelCtx4.1 Done()4.2 Err()4.3 cancel()4.4 WithCancel4.5 例子4.6 总结 5. timerCtx5.1 Deadline5.2 cancel5.3 WithDeadline5.4 WithTimeout5.5 例子…...
Vue + Nodejs + socket.io 实现聊天
Vue 代码 // 安装 socket.io-clientnpm i socket.io-clientimport io from socket.io-client;mounted () {// * location.origin 表示你的 socket 服务地址// * /XXXX/socket.io 表示 你的 socket 在服务器配置的 访问地址let socket io(location.origin, {path: "/XX…...
cocos creator 3.x实现手机虚拟操作杆
简介 在许多移动游戏中,虚拟操纵杆是一个重要的用户界面元素,用于控制角色或物体的移动。本文将介绍如何在Unity中实现虚拟操纵杆,提供了一段用于移动控制的代码。我们将讨论不同类型的虚拟操纵杆,如固定和跟随,以及如…...
【数据分享】中国电力年鉴(2004-2022)
大家好!今天我要向大家介绍一份重要的中国电力统计数据资源——《中国电力年鉴》。这份年鉴涵盖了从2004年到2022年中国电力统计全面数据,并提供限时免费下载。(无需分享朋友圈即可获取) 数据介绍 自1993年首次出版以来…...
两个数组的交集Ⅱ-力扣
想到的解法是使用两个map来进行记录,mp1用来统计num1中每个元素出现的次数。当nums2的元素能够在mp1中查找到时,将这个元素添加到mp2,按照这个规则统计得到nums2和nums1重复的元素,mp2中的value记录了nums2中这个元素出现的次数最…...
【TCP协议中104解析】wireshark抓取流量包工具,群殴协议解析基础
Tcp ,104 ,wireshark工具进行解析 IEC104 是用于监控和诊断工业控制网络的一种标准,而 Wireshark则是一款常用的网络协议分析工具,可以用干解析TEC104 报文。本文将介绍如何使用 Wireshark解析 IEC104报文,以及解析过 程中的注意事项。 一、安…...
[个人笔记] 记录docker-compose使用和Harbor的部署过程
容器技术 第三章 记录docker-compose使用和Harbor的部署过程 容器技术记录docker-compose使用和Harbor的部署过程Harborhttps方式部署:测试环境部署使用自签名SSL证书https方式部署:正式环境部署使用企业颁发的SSL证书给Docker守护进程添加Harbor的SSL证…...
详细介绍运算符重载函数,清晰明了
祝各位六一快乐~ 前言 1.为什么要进行运算符重载? C中预定义的运算符的操作对象只能是基本数据类型。但实际上,对于许多用户自定义类型(例如类),也需要类似的运算操作。这时就必须在C中重新定义这些运算符ÿ…...
国内外知名的低代码开发平台下载地址
以下是国内外几款低代码开发平台的列表,包含了下载地址、适应操作系统、是否可以独立部署、优点、缺点以及是否包含流程引擎的信息。 平台名称 下载地址 适应操作系统 是否可以独立部署 优点 缺点 是否包含流程引擎 国内平台 阿里云宜搭 阿里云官网 跨平台…...
【Pr学习】01新建项目起步
【Pr学习】01新建项目起步 1、新建项目2.序列设置2.1新建序列2.2序列参数讲解2.3自定义设置 3.PR窗口认识3.1 项目窗口3.2 源窗口2.4 保存面板 4.剪辑导入4.1 素材导入4.2 视图切换4.3 时间轴4.4轨道工具4.5 节目窗口素材导入 5.基础操作5.1 取消视频音频链接5.2 单独渲染&…...
【Redis延迟队列】redis中的阻塞队列和延迟队列
阻塞队列(RBlockingQueue) 作用和特点: 实时性:阻塞队列用于实时处理消息。生产者将消息放入队列,消费者可以立即从队列中取出并处理消息。阻塞特性:如果队列为空,消费者在尝试获取消息时会被…...
el-tree常用操作
一、定义 <el-treeclass"myTreeClass":data"dirTreeData":props"dirTreeProps":filter-node-method"filterDirTree":expand-on-click-node"false"node-key"id"node-click"dirTreeNodeClick":allow-…...
SQL 语言:存储过程和触发器
文章目录 基本概述创建触发器更改和删除触发器总结 基本概述 存储过程,类似于高阶语言的函数或者方法,包含SQL语句序列,是可复用的语句,保存在数据库中,在服务器中执行。特点是复用,提高了效率,…...
Ubuntu Linux 24.04 使用certbot生成ssl证书
设置域名 1. 将需要生成SSL证书的域名解析到IP地址 idealand.xyz <> 64.176.82.190 检查防火墙的设置 1. 首先查看防火墙的状态: # ufw status 2. 如果防火墙开启了,要开放80和443端口用于certbot验证 # ufw allow 80 # ufw allow 443 生…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
高防服务器价格高原因分析
高防服务器的价格较高,主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因: 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器,因此…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...
DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...
VSCode 使用CMake 构建 Qt 5 窗口程序
首先,目录结构如下图: 运行效果: cmake -B build cmake --build build 运行: windeployqt.exe F:\testQt5\build\Debug\app.exe main.cpp #include "mainwindow.h"#include <QAppli...
