linux音视频采集技术: v4l2
简介
在 Linux 系统中,视频设备的支持和管理离不开 V4L2(Video for Linux 2)。作为 Linux 内核的一部分,V4L2 提供了一套统一的接口,允许开发者与视频设备(如摄像头、视频采集卡等)进行交互。无论是视频采集、处理,还是编码和显示,V4L2 都提供了强大的支持。本文将简单介绍一下 V4L2 的工作流程以及如何使用它进行视频采集。
参数介绍
v4l2并没有提供单独封装的API接口,而是通过 ioctl 系统调用以及v4l2所提供的特定参数来对设备进行控制和采集。
下面是主要的 ioctl 控制参数:
1.VIDIOC_QUERYCAP:查询设备能力。
可用于查询枚举视频设备,获取设备名、总线名、支持的能力等。并非所有设备都支持,有可能会查询失败。
相关结构定义:
struct v4l2_capability {__u8 driver[16]; // 驱动名称__u8 card[32]; // 设备名称__u8 bus_info[32]; // 设备的总线信息__u32 version; // 驱动版本号__u32 capabilities; // 设备支持的功能__u32 device_caps; // 设备的具体能力__u32 reserved[3]; // 保留字段
};
2.VIDIOC_S_FMT:设置视频格式。
不同设备所支持的 pixelformat 不尽相同,所以设置的某些格式可能不会生效,比如我使用的海康摄像头只支持mjpg和yuyv。因此最好先使用 VIDIOC_ENUM_FMT 查询设备设备支持的格式,以确保设置生效。
相关结构定义:
struct v4l2_format {enum v4l2_buf_type type; // 缓冲区类型(如视频采集)union {struct v4l2_pix_format pix; // 视频帧格式// 其他格式(如 overlay、视频输出等)} fmt;
};struct v4l2_pix_format {__u32 width; // 视频宽度__u32 height; // 视频高度__u32 pixelformat; // 像素格式(如 V4L2_PIX_FMT_YUYV)__u32 field; // 场序(如逐行扫描、隔行扫描)__u32 bytesperline; // 每行的字节数__u32 sizeimage; // 每帧的总字节数// 其他字段
};
3.VIDIOC_REQBUFS:请求分配缓冲区。
memory类型使用MMAP,后续用于mmap内核缓冲区到用户态,避免内存拷贝
相关结构定义:
struct v4l2_requestbuffers {__u32 count; // 请求的缓冲区数量enum v4l2_buf_type type; // 缓冲区类型enum v4l2_memory memory; // 内存类型(如 MMAP、USERPTR)// 其他字段
};
4.VIDIOC_QUERYBUF:查询缓冲区信息。
相关结构定义:
struct v4l2_buffer {__u32 index; // 缓冲区索引enum v4l2_buf_type type; // 缓冲区类型__u32 bytesused; // 缓冲区中实际使用的字节数__u32 flags; // 缓冲区标志__u32 field; // 场序struct timeval timestamp; // 时间戳// 其他字段
};
5.VIDIOC_QBUF:将缓冲区加入队列。
将申请的 v4l2_buffer 实例入队
6.VIDIOC_DQBUF:从队列中取出缓冲区。
弹出 v4l2_buffer 实例,并通过mmap映射的地址读取采集数据
7.VIDIOC_STREAMON:开始视频采集。
8.VIDIOC_STREAMOFF:停止视频采集。
9.VIDIOC_ENUM_FMT:枚举设备支持的像素格式。
用于提前枚举支持的图像采集格式,以便选择最合适的采集方式。
相关结构定义:
struct v4l2_fmtdesc {__u32 index; // 格式索引(从 0 开始)enum v4l2_buf_type type; // 缓冲区类型(如视频采集)__u32 flags; // 格式标志__u8 description[32]; // 格式描述__u32 pixelformat; // 像素格式(如 V4L2_PIX_FMT_YUYV)__u32 reserved[4]; // 保留字段
};
流程
通常使用的采集流程如下:
1.查询设备能力:使用 VIDIOC_QUERYCAP 查询枚举设备是否支持采集。
2.打开设备:使用 open 打开设备节点。
3.查询设备图像能力:使用 VIDIOC_ENUM_FMT 查询设备支持的像素格式是否匹配。
4.设置视频格式:使用 VIDIOC_S_FMT 设置分辨率、像素格式等。
5.请求缓冲区:使用 VIDIOC_REQBUFS 请求分配缓冲区。
6.映射缓冲区:使用 mmap 将缓冲区映射到用户空间。
7.开始采集:使用 VIDIOC_STREAMON 开始视频采集。
8.采集数据:使用 VIDIOC_DQBUF 从队列中取出缓冲区,处理数据后使用 VIDIOC_QBUF 将缓冲区重新加入队列。
9.停止采集:使用 VIDIOC_STREAMOFF 停止视频采集。
10.释放资源:使用 munmap 释放缓冲区,并关闭设备。
代码示例
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <fstream>
#include <vector>
#include <cstring>#define VIDEO_DEVICE "/dev/video0"
#define WIDTH 640
#define HEIGHT 480
#define FPS 30
#define OUTPUT_FILE "output.yuv"
#define BUFFER_COUNT 4 // 缓冲区数量// 检查 V4L2 调用的返回值
#define CHECK(x) \if ((x) < 0) { \std::cerr << "ioctl error at " << __FILE__ << ":" << __LINE__ << " - " << strerror(errno) << std::endl; \exit(EXIT_FAILURE); \}// 检查设备是否支持指定格式
bool is_format_supported(int fd, unsigned int pixel_format) {struct v4l2_fmtdesc fmt_desc = {};fmt_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt_desc.index = 0;while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_desc) == 0) {if (fmt_desc.pixelformat == pixel_format) {std::cout << "Device supports format: " << fmt_desc.description << std::endl;return true;}fmt_desc.index++;}std::cerr << "Device does not support the required format (YUV420)" << std::endl;return false;
}int main() {// 打开视频设备int fd = open(VIDEO_DEVICE, O_RDWR);CHECK(fd);// 检查设备是否支持 YUV420P 格式if (!is_format_supported(fd, V4L2_PIX_FMT_YUV420)) {close(fd);return -1;}// 设置视频格式struct v4l2_format 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_YUV420; // YUV420P 格式fmt.fmt.pix.field = V4L2_FIELD_NONE;CHECK(ioctl(fd, VIDIOC_S_FMT, &fmt));// 检查设备是否实际设置了 YUV420P 格式if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) {std::cerr << "Device does not support YUV420P format" << std::endl;close(fd);return -1;}// 设置帧率struct v4l2_streamparm streamparm = {};streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;streamparm.parm.capture.timeperframe.numerator = 1;streamparm.parm.capture.timeperframe.denominator = FPS;CHECK(ioctl(fd, VIDIOC_S_PARM, &streamparm));// 请求缓冲区struct v4l2_requestbuffers req = {};req.count = BUFFER_COUNT; // 4 个缓冲区req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;req.memory = V4L2_MEMORY_MMAP;CHECK(ioctl(fd, VIDIOC_REQBUFS, &req));// 映射所有缓冲区std::vector<unsigned char *> buffers(BUFFER_COUNT);std::vector<size_t> buffer_sizes(BUFFER_COUNT);for (unsigned int i = 0; i < BUFFER_COUNT; i++) {struct v4l2_buffer buf = {};buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index = i;CHECK(ioctl(fd, VIDIOC_QUERYBUF, &buf));buffers[i] = (unsigned char *)mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);if (buffers[i] == MAP_FAILED) {std::cerr << "Failed to mmap buffer " << i << std::endl;close(fd);return -1;}buffer_sizes[i] = buf.length;// 将缓冲区加入队列CHECK(ioctl(fd, VIDIOC_QBUF, &buf));}// 开始采集enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;CHECK(ioctl(fd, VIDIOC_STREAMON, &type));// 打开输出文件std::ofstream outfile(OUTPUT_FILE, std::ios::binary);if (!outfile) {std::cerr << "Failed to open output file" << std::endl;close(fd);return -1;}// 采集 100 帧数据并保存到文件for (int i = 0; i < 100; i++) {struct v4l2_buffer buf = {};buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;// 从队列中取出缓冲区CHECK(ioctl(fd, VIDIOC_DQBUF, &buf));// 将 YUV420P 数据写入文件outfile.write((char *)buffers[buf.index], buf.bytesused);// 将缓冲区重新加入队列CHECK(ioctl(fd, VIDIOC_QBUF, &buf));}// 停止采集CHECK(ioctl(fd, VIDIOC_STREAMOFF, &type));// 释放资源for (unsigned int i = 0; i < BUFFER_COUNT; i++) {munmap(buffers[i], buffer_sizes[i]);}close(fd);outfile.close();std::cout << "YUV420P data saved to " << OUTPUT_FILE << std::endl;return 0;
}
编译前需要先安装v4l2的开发包:
sudo apt install libv4l-dev
也可以同时安装v4l2的工具包,用于信息查询:
sudo apt install v4l-utils
注:webrtc在linux下提供了两种采集方式,一种是v4l2,另一种是pipewire,感兴趣的可以看一下它们的实现
相关文章:
linux音视频采集技术: v4l2
简介 在 Linux 系统中,视频设备的支持和管理离不开 V4L2(Video for Linux 2)。作为 Linux 内核的一部分,V4L2 提供了一套统一的接口,允许开发者与视频设备(如摄像头、视频采集卡等)进行交互。无…...
MySQL使用navicat新增触发器
找到要新增触发器的表,然后点击设计,找到触发器标签。 根据实际需要,填写相关内容,操作完毕,点击保存按钮。 在右侧的预览界面,可以看到新生成的触发器脚本...
voice agent实现方案调研
前言 目前语音交互主要的实现大体有两种: 级联方案,指的是,大规模语言模型 (LLM)、文本转语音 (TTS) 和语音转文本 (STT),客户的话通过vad断句到STT的语音转文本,经过大模型进行生成文本,生成文本后通过TTS进行回复给用户。(主流方案)端到端的方案,开发者无需再…...
TCP通信原理学习
TCP三次握手和四次挥手以及为什么_哔哩哔哩_bilibili...
Three.js 基础概念:构建3D世界的核心要素
文章目录 前言一、场景(Scene)二、相机(Camera)三、渲染器(Renderer)四、物体(Object)五、材质(Material)六、几何体(Geometry)七、光…...
如何用代码提交spark任务并且获取任务权柄
在国内说所有可能有些绝对,因为确实有少数大厂技术底蕴确实没的说能做出自己的东西,但其他的至少95%数据中台平台研发方案,都是集群中有一个持久化的程序,来接收任务信息,并向集群提交任务同时获取任务的权柄ÿ…...
关于Mac中的shell
1 MacOS中的shell 介绍: 在 macOS 系统中,Shell 是命令行与系统交互的工具,用于执行命令、运行脚本和管理系统。macOS 提供了多种 Shell,主要包括 bash 和 zsh。在 macOS Catalina(10.15)之前,…...
【npm依赖包介绍】借助rimraf依赖包,在用npm run build构建项目时,清空dist目录,避免新旧混合
文章目录 背景如何使用附上rimraf的介绍和说明主要作用使用场景安装使用示例异步删除同步删除 参考资料 背景 在npm run build时,一般都会清空项目中已有的dist目录再构建,避免新旧混合。 如何使用 可以简单使用rimraf这个npm依赖包。 目前rimraf的最…...
爬虫学习记录
1.概念 通过编写程序,模拟浏览器上网,然后让其去互联网上抓取数据的过程 通用爬虫:抓取的是一整张页面数据聚焦爬虫:抓取的是页面中的特定局部内容增量式爬虫:监测网站中数据更新的情况,只会抓取网站中最新更新出来的数据 robots.txt协议: 君子协议,网站后面添加robotx.txt…...
Java Spring Boot实现基于URL + IP访问频率限制
点击下载《Java Spring Boot实现基于URL IP访问频率限制(源代码)》 1. 引言 在现代 Web 应用中,接口被恶意刷新或暴力请求是一种常见的攻击手段。为了保护系统资源,防止服务器过载或服务不可用,需要对接口的访问频率进行限制。本文将介绍如…...
C4D2025 win版本安装完无法打开,提示请将你的maxon App更新至最新版本,如何解决
最近安装C4D2025 win版本时,明明按步骤安装完成,结果打开提示提示请将你的maxon App更新至最新版本?遇到这种情况该如何解决呢。 一开始我的思路以为是旧版本没有删除干净,所以将电脑里有关maxon的软件插件都卸载了,重…...
微信小程序实现登录注册
文章目录 1. 官方文档教程2. 注册实现3. 登录实现4. 关于作者其它项目视频教程介绍 1. 官方文档教程 https://developers.weixin.qq.com/miniprogram/dev/framework/路由跳转的几种方式: https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.switchTab…...
SpringBoot环境和Maven配置
SpringBoot环境和Maven配置 1. 环境准备2. Maven2.1 什么是Maven2.2 为什么要学 Maven2.3 创建一个 Maven项目2.4 Maven核心功能2.4.1 项目构建2.4.2 依赖管理2.4.3 Maven Help插件 2.5 Maven 仓库2.5.1本地仓库2.5.2 中央仓库2.5.3 私有服务器, 也称为私服 2.6 Maven设置国内源…...
大语言模型训练所需的最低显存,联邦大语言模型训练的传输优化技术
联邦大语言模型训练的传输优化技术 目录 联邦大语言模型训练的传输优化技术大语言模型训练所需的最低显存大语言模型训练所需的最低显存 基于模型微调、压缩和分布式并行处理的方法,介绍了相关开源模型及技术应用 核心创新点 多维度优化策略:综合运用基于模型微调、模型压缩和…...
1.07 标准IO
1.思维导图 2.先编写以下结构体 struct Student { char name[20]; double math; double chinese; double english; double physical; double chemical; double…...
恒压恒流原边反馈控制芯片 CRE6289F
CRE6289F 系列产品是一款内置高压 MOS 功率开关管的高性能多模式原边控制的开关电源芯片。较少的外围元器件、较低的系统成本设计出高性能的交直流转换开关电源。CRE6289F 系列产品提供了极为全面和性能优异的智能化保护功能,包括逐周期过流保护、软启动、芯片过温保…...
Java中线程中断的几种方式,你了解吗?
Java中线程,可以使用 interrupt() 方法来实现线程的中断,那么,线程中中断的方式有几种呢?接下来,我们将介绍3种不同的线程中断方式,跟随我们的脚步,一起去看看! 目录 第一招…...
Tesseract5.4.0自定义LSTM训练
准备jTessBoxEditor,然后配置环境变量。 1、将图片转换成tif格式的,这里需要用画图工具另存为; 2、生成box文件 执行命令: tesseract agv.normal.exp1.tif agv.normal.exp1 -l eng --psm 6 batch.nochop makebox 关于box文件…...
centOS7
特殊权限 set_uid 赋予所有者身份 chmod us 文件 set_gid 赋予所有组身份 chmod gs 文件/目录 sticky_bit 防火墙 firewall-cmd 开启端口 firewall-cmd --zonepublic --add-port8080/tcp --permanent 重启防火墙 systemctl restart firewalld 查看开启的所有端口 fi…...
HTML5 弹跳动画(Bounce Animation)详解
HTML5 弹跳动画(Bounce Animation)详解 弹跳动画是一种动态效果,使元素在出现或消失时看起来像是在跳动。这种效果可以通过 CSS 动画或 JavaScript 来实现,增强用户体验。 1. 使用 CSS 实现弹跳动画 可以使用 CSS 的 keyframes…...
为什么92%的LLM项目在Q3前无法通过等保三级?2026奇点大会首次发布《LLM生产安全合规检查清单V2.1》
第一章:2026奇点智能技术大会:LLM生产环境部署指南 2026奇点智能技术大会(https://ml-summit.org) 在真实生产环境中部署大语言模型,需兼顾推理延迟、显存效率、服务可观测性与安全合规性。本次大会实践工作坊基于 Llama-3-70B-Instruct 与 …...
从‘它怎么又挂了’到‘服务真稳’:我是如何用Docker给老旧PHP项目续命的
从‘它怎么又挂了’到‘服务真稳’:我是如何用Docker给老旧PHP项目续命的 维护一个运行了十年的PHP项目就像照顾一位脾气古怪的老教授——你知道他肚子里有货,但那些过时的习惯和依赖总能让你在深夜崩溃。上周五下午4点,当我第17次收到"…...
ArcGIS进阶:利用Python脚本在字段计算器中实现复杂条件赋值
1. 为什么需要Python脚本进行复杂字段赋值 在ArcGIS中处理属性表数据时,新手最常犯的错误就是手动逐条编辑。我曾经接手过一个项目,同事花了整整三天时间手动修改5000多条记录,结果还出现了大量错误。实际上,字段计算器(Field Ca…...
基于eNSP的企业级网络规划与高可用性设计实战:从需求分析到配置验证
1. 企业级网络规划的核心挑战与eNSP价值 刚接手公司网络改造项目时,我最头疼的就是如何在纸上方案和真实环境之间架起桥梁。直到接触华为eNSP模拟器,才发现这个神器完美解决了网络工程师的三大痛点: 真实设备价格昂贵的问题被彻底化解。用笔记…...
技术拆解:豆包接入抖音电商的AI购物链路,从对话到下单如何实现15秒闭环
技术拆解:豆包接入抖音电商的AI购物链路,从对话到下单如何实现15秒闭环前言字节豆包App内测接入抖音电商,实现对话内下单闭环。本文从技术架构角度拆解AI购物链路的实现方式,以及对电商开发者的影响。一、AI购物链路架构用户自然语…...
第6章 6.1.2 数据呈现的艺术:sprintf格式化操作符深度解析(MATLAB入门课程)
1. 为什么数据需要格式化呈现? 第一次处理实验数据时,我直接把MATLAB工作区的变量值复制到论文里,结果被导师狠狠批评了一顿。那些密密麻麻的数字堆在一起,小数点位数参差不齐,有些科学计数法显示,有些又是…...
电容是什么?一个“快充快放”的微型充电宝麓
一、前言:什么是 OFA VQA 模型? OFA(One For All)是字节跳动提出的多模态预训练模型,支持视觉问答、图像描述、图像编辑等多种任务,其中视觉问答(VQA)是最常用的功能之一——输入一张…...
Umi-CUT:三步批量处理图片黑边,解放你的生产力
Umi-CUT:三步批量处理图片黑边,解放你的生产力 【免费下载链接】Umi-CUT 项目地址: https://gitcode.com/gh_mirrors/um/Umi-CUT 还在为海量图片的黑边烦恼吗?Umi-CUT批量图片处理工具就是你的终极解决方案。这款开源软件专为图片批量…...
AgentCPM-Report实战案例:Pixel Epic在跨境数据合规白皮书撰写中的应用
AgentCPM-Report实战案例:Pixel Epic在跨境数据合规白皮书撰写中的应用 1. 引言:当数据合规遇上像素冒险 跨境数据合规是当前企业出海面临的重要挑战之一。传统白皮书撰写需要耗费大量时间收集法规、分析案例、整理框架,而Pixel Epic这款基…...
当Aurora IP遇上多板卡互联:灵活分配GT Quad与Lane的实战策略
Aurora IP在多板卡系统中的GT资源规划与实战技巧 在当今高速数据通信和雷达信号处理领域,多FPGA系统已成为主流架构。这类系统通常需要处理数十Gbps甚至上百Gbps的数据吞吐量,而Xilinx的Aurora协议配合GT高速串行收发器,为这种高带宽需求提供…...
