linux学习:视频输入+V4L2

目录

V4L2 视频采集流程

代码例子

核心命令字和结构体

VIDIOC_ENUM_FMT

VIDIOC_G_FMT / VIDIOC_S_FMT / VIDIOC_TRY_FM

VIDIOC_REQBUFS

VIDIOC_QUERYBUF

VIDIOC_QBUF /VIDIOC_DQBUF

VIDIOC_STREAMON / VIDIOC_STREAMOFF


V4L2 是 Linux 处理视频的最新标准代码模块,这其中包括对视频输入设备的处理,比 如高频头(即电视机信号输入端子)或者摄像头,还包括对视频输出设备的处理。一般而言, 最常见的是使用 V4L2 来处理摄像头数据采集的问题

我们平常所使用的摄像头,实际上就是一个图像传感器,将光线捕捉到之后经过视频芯 片的处理,编码成 JPG/MJPG 或者 YUV 格式输出。而通过 V4L2 我们可以很方便地跟摄像 头等视频设备“沟通”,比如设置或者获取它们的工作参数

V4L2 视频采集流程

在内核中,摄像头所捕获的视频数据,我们可以通过一个队列来存储,我们所做的工作 大致是这样的:首先配置好摄像头的相关参数,使之能正常工作,然后申请若干个内核视频 缓存,并且将它们一一送到队列中,就好比三个空盘子被一一放到传送带上一样。然后我们 还需要将这三个内核的缓存区通过 mmap 函数映射到用户空间,这样我们在用户层就可以 操作摄像头数据了,紧接着我们就可以启动摄像头了开始数据捕获,每捕获一帧数据我们就 可以做一个出队操作,读取数据,然后将读过数据的内核缓存再次入队,依次循环

代码例子

// 1,打开摄像头设备文件
int cam_fd = open("/dev/video3", O_RDWR);// 2,获取摄像头当前的采集格式
struct v4l2_format *fmt = calloc(1, sizeof(*fmt));
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(cam_fd, VIDIOC_G_FMT, fmt);
show_camfmt(fmt); // 显示具体参数(详见 v4l2_jpeg_videostream.c)// 3,配置摄像头的采集格式为 JPEG
bzero(fmt, sizeof(*fmt));
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt->fmt.pix.width = lcdinfo.xres;
fmt->fmt.pix.height = lcdinfo.yres;
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
ioctl(cam_fd, VIDIOC_S_FMT, fmt);// 4,设置即将要申请的摄像头缓存的参数
int nbuf = 3;
struct v4l2_requestbuffers reqbuf;
bzero(&reqbuf, sizeof(reqbuf));
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = nbuf;// 5,使用该参数 reqbuf 来申请缓存
ioctl(cam_fd, VIDIOC_REQBUFS, &reqbuf);// 6,根据刚设置的 reqbuf.count 的值,来定义相应数量的 struct v4l2_buffer
// 每一个 struct v4l2_buffer 对应内核摄像头驱动中的一个缓存
struct v4l2_buffer buffer[nbuf];
int length[nbuf];
unsigned char *start[nbuf];
for (i = 0; i < nbuf; i++) {bzero(&buffer[i], sizeof(buffer[i]));buffer[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buffer[i].memory = V4L2_MEMORY_MMAP;buffer[i].index = i;ioctl(cam_fd, VIDIOC_QUERYBUF, &buffer[i]);length[i] = buffer[i].length;start[i] = mmap(NULL, buffer[i].length, PROT_READ | PROT_WRITE, MAP_SHARED, cam_fd, buffer[i].m.offset);ioctl(cam_fd, VIDIOC_QBUF, &buffer[i]);
}// 7,启动摄像头数据采集
enum v4l2_buf_type vtype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(cam_fd, VIDIOC_STREAMON, &vtype);
struct v4l2_buffer v4lbuf;
bzero(&v4lbuf, sizeof(v4lbuf));
v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4lbuf.memory = V4L2_MEMORY_MMAP;// 8,循环读取摄像头数据
i = 0;
while (1) {// 从队列中取出填满数据的缓存v4lbuf.index = i % nbuf;// VIDIOC_DQBUF 在摄像头没数据的时候会阻塞ioctl(cam_fd, VIDIOC_DQBUF, &v4lbuf);shooting(start[i % nbuf], length[i % nbuf], fb_mem); // 显示到 LCD// 将已经读取过数据的缓存块重新置入队列中v4lbuf.index = i % nbuf;ioctl(cam_fd, VIDIOC_QBUF, &v4lbuf);i++;
}

核心命令字和结构体

VIDIOC_ENUM_FMT

含义:枚举出当前摄像头(驱动)所支持的所有数据格式

使用方法:ioctl(fd, VIDIOC_ENUM_FMT, struct v4l2_fmtdesc *argp);

通过迭代结构体 struct v4l2_fmtdesc 中的 index 成员,来枚举罗列支持的所有格式, 该结构体的详细信息如下

struct v4l2_fmtdesc
{ 
__u32 index; // 数据格式的索引
__u32 type; // 一般设置为 V4L2_BUF_TYPE_VIDEO_CAPTURE 
__u32 flags; 
__u8 description[32]; 
__u32 pixelformat;//表示像素格式的值,是一个32位的标识符,用于指定视频数据的像素编码格式,如 YUV420、RGB24 等 
__u32 reserved[4];
};
  • 其中 type 跟 v4l2_format 中的 type 设置要一致。
  • 在成功调用ioctl 之后,description 将保存对当前获取的数据格式的描述。

VIDIOC_G_FMT / VIDIOC_S_FMT / VIDIOC_TRY_FM

含义: 1,获取当前摄像头驱动数据格式 2,设置摄像头驱动数据格式 3,尝试设置格式

具体用法:

  1. ioctl(fd, VIDIOC_G_FMT, struct v4l2_format *argp);
  2. ioctl(fd, VIDIOC_S_FMT, struct v4l2_format *argp);
  3. ioctl(fd, VIDIOC_TRY_FMT, struct v4l2_format *argp);

涉及数据结构

struct v4l2_format
{ 
__u32 type;
union
{
struct v4l2_pix_format pix;
struct v4l2_pix_format_mplane pix_mp;
struct v4l2_window win;
struct v4l2_vbi_format vbi;
struct v4l2_sliced_vbi_format sliced; __u8 raw_data[200];
} fmt;
};
  • V4l2_format 中的 fmt 是一个 union,其中哪个成员有效取决于 type 的取值,
  • 一般较常用的是取类型 type 为 V4L2_BUF_TYPE_VIDEO_CAPTURE,此时 pix 生效。
struct v4l2_pix_format
{ 
__u32 width; 
__u32 height; 
__u32 pixelformat; 
__u32 field;
__u32 bytesperline;
__u32 sizeimage; 
__u32 colorspace; 
__u32 priv;
};
  • 该结构体中的成员 pixelformat 代表视频输入驱动所使用的像素格式,常见的有 V4L2_PIX_FMT_JPEG、V4L2_PIX_FMT_YUV、V4L2_PIX_FMT_MJPG等。
  • 而成员field 代表视频帧传输的方式,选择 V4L2_FIELD_INTERLACED 为交错式

VIDIOC_REQBUFS

含义:向内核申请视频缓存(内核中处理视频数据的队列缓存)

用法: ioctl(fd, VIDIOC_REQBUFS, v4l2_requestbuffers *argp);

struct v4l2_requestbuffers
{ 
__u32 count; // 申请缓存总个数
__u32 type; // 与 struct v4l2_format 中的 type 一致
__u32 memory; 
__u32 reserved[2];
};
  •  其中 memory 的取值为 V4L2_MEMORY_MMAP 或 V4L2_MEMORY_USERPTR, 取决于,当该字段被设置为 V4L2_MEMORY_MMAP 时,count 字段才有效。

VIDIOC_QUERYBUF

含义:内核成功分配了缓存后,取得这些缓存的具体参数

用法: ioctl(fd, VIDIOC_QUERYBUF, v4l2_buffer *argp);

取得这些缓存的具体参数的目的是:这些缓存都是处在内核空间的,我们并不能直接操作他们,因此需要将他们通过 mmap 映射到用户空间,这就要求必须知道他们的大小、偏移等信息。这些信息统一被储存到如下结构体中

struct v4l2_buffer
{ 
__u32 index; // 内核缓存索引号,由用户指定,范围是[0 ~ count-1] 
__u32 type; // 与 v4l2_format 中的 type 一致
__u32 bytesused; 
__u32 flags; 
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence; 
__u32 memory; // 与 v4l2_requestbuffers 中的 memory 一致
union
{ 
__u32 offset; // 缓存相对于设备内存的偏移
unsigned long userptr;
struct v4l2_plane *planes; 
__s32 fd;
} m; 
__u32 length; // 缓存大小
__u32 reserved2; 
__u32 reserved;
};

VIDIOC_QBUF /VIDIOC_DQBUF

含义:

  1. 使一个空的(视频输入时)或者一个满的(视频输出时)缓存入队
  2. 使一个满的(视频输入时)或者一个空的(视频输出时)缓存出队

用法:

  1. ioctl(fd, VIDIOC_QBUF, v4l2_buffer *argp);
  2. ioctl(fd, VIDIOC_DQBUF, v4l2_buffer *argp);

 

  • 在尚未开启摄像头取像之前,需要将空的缓存一一入队。
  • 针对视频输入,出队的时候如果缓存没有数据,那么出队将阻塞。
  • 虽然内核对这些内存的定义是“队列”,但实际上不按顺序“加塞(插队)”也是 可以的。但一般不那么做

VIDIOC_STREAMON / VIDIOC_STREAMOFF

含义:

  1. 开启 I/O 流
  2. 关闭 I/O 流

用法:

  1. ioctl(fd, VIDIOC_STREAMON, const int *argp);
  2. ioctl(fd, VIDIOC_STREAMOFF, const int *argp);

不管 I/O 方式被设定为内存映射(MMAP)方式还是用户指针(USERPTR)方式,都可以使用 VIDIOC_STREAMON 和 VIDIOC_STREAMOFF 来启停 I/O 流。事实上,在使用 ioctl 调用 VIDIOC_STREAMON 之前,物理硬件将暂时被禁用且没有缓存被填充数据。

VIDIOC_STREAMOFF 除了终止进程的 DMA 操作(如果有的话)之外,还将解锁用户指针指向的物理内存,队列中的所有缓存都将被移除,这意味着如果是视频输入,那么那些没来得及读取的视频帧将被丢弃,如果是视频输出,那么那写没来及传输的视频帧也同样会被丢弃

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣HOT100 - 45. 跳跃游戏 II

解题思路&#xff1a; 贪心 class Solution {public int jump(int[] nums) {int end 0;int maxPosition 0;int steps 0;for (int i 0; i < nums.length - 1; i) {maxPosition Math.max(maxPosition, i nums[i]);if (i end) {end maxPosition;steps;}}return steps;…

Java | Leetcode Java题解之第86题分隔链表

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode partition(ListNode head, int x) {ListNode small new ListNode(0);ListNode smallHead small;ListNode large new ListNode(0);ListNode largeHead large;while (head ! null) {if (head.val < x…

java sql中 大于 小于 大于等于 小于等于 代替符号

在写java时sql会经常会忘记大于小于号的表示方法导致无法运行&#xff0c;总结一下 第一种方法&#xff1a; < &#xff1a;< < &#xff1a; < &#xff1a;> &#xff1a; > sql如下&#xff1a; create_at > #{startTime} and create_at < #{end…

Linux系统编程:进程控制

1.进程创建 1.1 fork函数 fork&#xff08;&#xff09;通过复制调用进程来创建一个新进程。新进程称为子进程&#xff0c;是调用进程的精确副本 进程&#xff0c;但以下几点除外&#xff1a; 子进程有自己的PID&#xff0c;此PID与任何现有进程组的ID不匹配子进程的父进程ID…

【全开源】废品回收微信小程序基于FastAdmin+ThinkPHP+UniApp

介绍 一款基于FastAdminThinkPHPUniApp开发的废品回收系统&#xff0c;适用废品回收站、再生资源回收公司上门回收使用的小程序 功能特性 1、会员注册 支持小程序授权注册和手机号注册 2、回收品类 可设置回收品类&#xff0c;废纸、废金属、废玻璃、旧衣服等 3、今日指导价…

简单实现---基于STL的演讲比赛流程管理系统(C++实现)

前言 事先声明&#xff1a;本文章中编写的代码仅用于学习算法思想和编写基础形式使用&#xff0c;并未进行太多的代码优化&#xff0c;因此&#xff0c;若需要对代码进行优化以及异常处理的小伙伴们&#xff0c;可自行添加相关操作&#xff0c;谢谢&#xff01; 一、题…

jenkins使用gitLab(极狐)认证登陆

jenkins安装 GitLab Authentication插件 我因为java版本和最新GitLab Authentication 1.19版本不兼容&#xff0c;选择了本地安装 找个历史版本1.13版本&#xff0c;然后下载到电脑上 - 本地上传插件并安装 在极狐上创建一个应用 - 配置应用信息 应用名&#xff1a;jenkinsLo…

[Linux][网络][高级IO][一][五种IO模型][同步通信][异步通信][非阻塞IO]详细讲解

目录 0.预备知识 && 思考问题1.五种IO模型0.形象理解五种模型1.阻塞IO2.非阻塞IO3.信号驱动IO4.多路转接/多路复用5.异步IO 2.高级IO重要概念1.同步通信 vs 异步通信2.阻塞 vs 非阻塞 3.非阻塞IO1.fcntl()2.实现SetNonBlock 0.预备知识 && 思考问题 网络通信本…

了解 GaussDB SQL 中 CASE 表达式

一、前言 SQL 是用于访问和处理数据库的标准计算机语言。GaussDB 支持 SQL 标准&#xff08;默认支持 SQL2、SQL3 和 SQL4 的主要特性&#xff09;。 本系列将以《云数据库 GaussDB—SQL 参考》在线文档为主线进行介绍。 二、CASE Expression&#xff08;CASE 表达式&#x…

sCrypt受邀在中国人民大学举办《区块链与数字经济》课程讲座

4月17日&#xff0c;可一科技特邀美国sCrypt公司的开发工程师周全&#xff0c;在中国人民大学的《区块链与数字经济》课程上进行了讲座。周全讲解了区块链的分布式设计、不可篡改特性&#xff0c;以及智能合约的基本原理&#xff0c;利用“智能家居触发机制”等生动比喻&#x…

laravel 使用 MongoDB

MongoDB MongoDB是一个基于分布式文件存储的数据库。由C语言编写。MongoDB 提供了面向文档的存储方式&#xff0c;操作起来比较简单和容易&#xff0c;支持“无模式”的数据建模&#xff0c;可以存储比较复杂的数据类型&#xff0c;是一款非常流行的文档类型数据库 使用场景 …

IDEA中git的常用操作(保姆级教学)

IDEA中git的常用操作&#xff08;保姆级教学&#xff09; 以下是git的工作原理&#xff0c;觉得繁琐的可以跳过不看 Workspace&#xff1a;工作区 (平时存放代码的地方) Index / Stage&#xff1a;暂存区&#xff08;用于临时存放存放你的改动&#xff0c;事实上就是一个文件&…

OSPF虚链路

原理概述 通常情况下&#xff0c;一个OSPF网络的每个非骨干区域都必须与骨干区域通过ABR路由器直接连接&#xff0c;非骨干区域之间的通信都需要通过骨干区域进行中转。但在现实中&#xff0c;可能会因为各种条件限制&#xff0c;导致非骨干区域和骨干区域无法直接连接&#x…

Unity自定义动画-Animation动画数据-How is “fileIDToRecycleName“ generated

一般美术和程序分工明确的项目 fbx确实是和动画一一对应的&#xff1b; 但一些独立&#xff0c;或者小工作室的项目&#xff0c;就没法保证了&#xff0c;关键还是在于 Unity的 .meta 目录 查找和对比了一下 .fbx 和 .meta&#xff1a; 缓存和不缓存Animation 具体的Animat…

记录MySQL数据库查询不等于xxx时的坑

目录 一、背景 二、需求 三、方法 四、示例 一、背景 在使用MySQL数据库查询数据时&#xff0c;需要查询字段name不等于xxx的记录&#xff0c;通过where name ! xxx查询出来的记录不符合预期&#xff0c;通过检查发现少了name字段为null的记录&#xff0c;后经查询得知在My…

安全加固

目录 1.文件锁定管理 2.设置用户账户有效期 3.查看并清除命令历史记录 4.设置用户超时登出时间 5.用户切换 6.用户提权 7.禁用重启热键CtrlAltDel 8.设置单用户模式密码 9.调整BIOS引导设置 10.禁止root用户从本地登录&#xff1a; 11.禁止root用户通过ss…

IDM下载器激活

文章目录 1、Internet Download Manager简介2、Internet Download Managery应用3、Internet Download Managery下载 1、Internet Download Manager简介 Internet Download Manager (IDM) 是一款功能强大的下载管理软件&#xff0c;旨在帮助用户更高效地管理和加速其下载任务。它…

Hive JSON数据处理

Hive JSON数据处理 JSON&#xff08;JavaScript Object Notation&#xff09;文件格式是一种轻量级的数据交换格式&#xff0c;用于存储和传输结构化的数据。它基于JavaScript的语法&#xff0c;但是可以被多种编程语言所支持和解析&#xff0c;因此被广泛应用于各种场景。 J…

AWS云优化:实现性能和成本的最佳平衡

随着企业数字化转型的加速&#xff0c;对云计算平台的需求也不断增长。AWS作为云计算行业的领导者之一&#xff0c;提供了广泛的云服务和解决方案&#xff0c;帮助企业实现业务的创新和发展。在AWS云上部署应用程序和服务后&#xff0c;对其进行优化是至关重要的&#xff0c;以…

易图讯科技数字武装三维电子沙盘

深圳易图讯科技(www.3dgis.top)集成了高清卫星影像、地形数据、实景三维模型、基干民兵、普通民兵、重要目标、兵要地志、企业潜力 、行业潜力 、社会组织潜力 、特种装备器材潜力、敌情数据、现场环境数据、物联感知信息&#xff0c;构建一体化的数字孪生空间&#xff0c;实现…