Linux驱动:VPU
1. 前言
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
2. 概述
VPU
是用来进行图像、视频数据进行硬件编、解码的硬件模块。内部集成了 Encoder
、Decoder
功能部件进行图像、视频数据进行硬件编、解码,以加速处理。
3. VPU 工作原理
3.1 VPU 编码工作流程
---------------| --------- |
输入数据 -->|->| Encoder |->|-> 编码后的输出数据| --------- || || --------- || | Decoder | || --------- |---------------
3.2 VPU解码工作流程
---------------| --------- || | Encoder | || --------- || || --------- |输入数据 -->|->| Decoder |->|-> 解码后的输出数据| --------- |---------------
4. Linux 下的 VPU
4.1 驱动架构
VPU驱动
可基于 V4L2子系统
框架完成。
1. 分别为 Encoder
和 Decoder
各注册1个 /dev/videoX
设备(总共2个video设备)。
/* 注册 Encoder 设备 */
vfd->vfl_dir = VFL_DIR_M2M;
video_register_device(vfd, VFL_TYPE_GRABBER, ...)/* 注册 Decoder 设备 */
vfd->vfl_dir = VFL_DIR_M2M;
video_register_device(vfd, VFL_TYPE_GRABBER, ...)
设备数据传输方向为 VFL_DIR_M2M
, 表明设备是设备完成的功能内存间的数据传输拷贝
。
2. 在 open() 调用中,在打开文件句柄的私有数据 file_private 绑定设备 buffer 队列(vb2_queue)的类型、接口、IO模式、数据传输方向等。
这里以 Encoder 的 open() 调用为例加以说明:
/* Encoder【输入】数据队列初始化 */
encoder_vq_input.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
encoder_vq_input.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
encoder_vq_input.ops = &xxx_vpu_encoder_qops;
encoder_vq_input.mem_ops = &vb2_dma_contig_memops;
...
vb2_queue_init(&encoder_vq_input);/* Encoder【输出】数据队列初始化 */
encoder_vq_output.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
encoder_vq_output.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
encoder_vq_output.ops = &xxx_vpu_encoder_qops;
encoder_vq_output.mem_ops = &vb2_dma_contig_memops;
...
vb2_queue_init(&encoder_vq_output);...
4.2 用户空间编程框架(Encoder编码示例)
/* 打开设备(/dev/videoX为Encoder设备) */
fd = open("/dev/videoX", O_RDWR);/* 设置输入、输出数据格式 *//* 设置编码【输入】数据格式 */
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
...
ioctl(fd, VIDIOC_S_FMT, &fmt);
/* 设置编码【输出】数据格式 */
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
...
ioctl(fd, VIDIOC_S_FMT, &fmt);/* 请求输入、输出buffer,然后映射内核buffer到用户空间(IO模式为 V4l2_MEMORY_MMAP) *//* 请求【输入】buffer并映射到用户空间 */
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
rb.memory = V4l2_MEMORY_MMAP;
rb.count = 1;
ioctl(fd, VIDIOC_REQBUFS, &rb);buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4l2_MEMORY_MMAP;
buf.length = num_input_planes;
buf.m.planes = input_planes;
ioctl(fd, VIDIOC_QUERYBUF, &buf);input_buffer.start = mmap(0, ..., PROT_READ|PROT_WRITE, ...);
input_buffer.length = ...;/* 请求【输出】buffer并映射到用户空间 */
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
rb.memory = V4l2_MEMORY_MMAP;
rb.count = 1;
ioctl(fd, VIDIOC_REQBUFS, &rb);buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4l2_MEMORY_MMAP;
buf.length = num_output_planes;
buf.m.planes = output_planes;
ioctl(fd, VIDIOC_QUERYBUF, &buf);output_buffer.start = mmap(0, ..., PROT_READ|PROT_WRITE, ...);
output_buffer.length = ...;/* 将【输出】buffer入队,然后开启【输出流】 */
buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
buf.memory = V4l2_MEMORY_MMAP;
buf.length = num_output_planes;
buf.m.planes = output_planes;
output_planes[i].bytesused = output_planes[i].length;
ioctl(fd, VIDIOC_QBUF, &buf);type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
ioctl(fd, VIDIOC_STREAMON, &type);/* 设置编码输入数据,将【输入】buffer入队,然后开启【输入流】 */
/* 设置编码输入数据 */
memcpy(input_buffer.start, input_data, input_data_size);buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4l2_MEMORY_MMAP;
buf.length = num_input_planes;
buf.m.planes = input_planes;
input_planes[i].bytesused = input_planes[i].length;
ioctl(fd, VIDIOC_QBUF, &buf);type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
ioctl(fd, VIDIOC_STREAMON, &type);/* 出队编码队列(vb2_queue)中就绪的【输出缓冲】 */
(vb2_buffer/v4l2_buffer, vb2_plane/v4l2_plane)
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
buf.memory = V4L2_MEM_TYPE;
buf.length = num_output_planes;
buf.m.planes = output_planes;
ioctl(fd, VIDIOC_DQBUF, &buf);/* 拷贝编码好的数据到目的缓冲(假定 output plane 数目为1) */
memcpy(output_data, output_buffer.start, buf.m.planes[0].bytesused);/* 关闭设备 */
close(fd);
4.3 VPU 驱动工作流程小结
VPU-----------------------------| ----------------------- || | Encoder | || | ----------------- | |--->|->|->| encoding buffer |->|->|--->^ | | ----------------- | | |输入数据队列(vb2_queue) | | ----------------------- | | 输出数据队列(vb2_queue)----------------------- | | | | -----------------------| vb2_buffer[] |-->| | ----------------------- | |--> | vb2_buffer[] |----------------------- | | | Decoder | | | -----------------------v | | ----------------- | | |--->|->|->| decoding buffer |->|->|--->| | ----------------- | || ----------------------- |-----------------------------
Encoder/Decoder完成编、解码动作后:
(1) 拷贝编、解码后的数据到输出队列中某个vb2_buffer的缓冲: memcpy(output_buffer, input_buffer, size);
(2) 标记输入数据队列中某个vb2_buffer中的数据编、解码完成: vb2_buffer_done(&in_vb, VB2_BUF_STATE_DONE);
(3) 设置输出缓冲负载(输出数据大小): vb2_set_plane_payload(&out_vb, 0, size);
(4) 标记输出数据队列中某个vb2_buffer中的数据编、解码输出数据就绪: vb2_buffer_done(&out_vb, VB2_BUF_STATE_DONE);
4.4 示例
这是一个实际的范例,来自开源方案 FrienlyARM
:VPU范例 。
该方案基于 S5P6818
的 SoC 。
4.4.1 FrienlyARM的方案内核NX VPU驱动补丁
/** drivers/media/platform/nx-vpu/nx_vpu_enc_v4l2.c */
void vpu_enc_get_seq_info(struct nx_vpu_ctx *ctx)
{.../* 注释下面这一段代码 *//*{struct nx_vpu_buf *dst_mb;unsigned long flags;spin_lock_irqsave(&ctx->dev->irqlock, flags);dst_mb = list_entry(ctx->strm_queue.next, struct nx_vpu_buf,list);list_del(&dst_mb->list);ctx->strm_queue_cnt--;vb2_set_plane_payload(&dst_mb->vb, 0, ctx->strm_size);vb2_buffer_done(&dst_mb->vb, VB2_BUF_STATE_DONE);spin_unlock_irqrestore(&ctx->dev->irqlock, flags);}*/
}static void nx_vpu_enc_buf_queue(struct vb2_buffer *vb)
{...if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {...} else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {buf->used = 0;if (ctx->img_fmt.num_planes == 1)NX_DbgMsg(INFO_MSG, "adding to src: %p(%08lx)\n",vb, (unsigned long)nx_vpu_mem_plane_addr(ctx, vb, 0));else if (ctx->img_fmt.num_planes == 2)NX_DbgMsg(INFO_MSG, "adding to src: %p(%08lx, %08lx)\n",vb, (unsigned long)nx_vpu_mem_plane_addr(ctx, vb, 0),(unsigned long)nx_vpu_mem_plane_addr(ctx, vb, 1));else if (ctx->img_fmt.num_planes == 3)NX_DbgMsg(INFO_MSG, "adding to src: %p(%08lx, %08lx, %08lx)\n",vb, (unsigned long)nx_vpu_mem_plane_addr(ctx, vb, 0),(unsigned long)nx_vpu_mem_plane_addr(ctx, vb, 1),(unsigned long)nx_vpu_mem_plane_addr(ctx, vb, 2));}...
}int nx_vpu_enc_open(struct nx_vpu_ctx *ctx)
{...ctx->vq_img.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;......ctx->vq_strm.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;...
}
/** drivers\media\platform\nx-vpu\nx_vpu_v4l2.c*/
#define DST_QUEUE_OFF_BASE (1 << 30)int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{struct nx_vpu_ctx *ctx = fh_to_ctx(file->private_data);int ret = 0;FUNC_IN();...if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {...} else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {...//buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE;/* Adjust MMAP memory offsets for the CAPTURE queue */if (buf->memory == V4L2_MEMORY_MMAP /*&& !V4L2_TYPE_IS_OUTPUT(ctx->vq_img->type)*/) {if (V4L2_TYPE_IS_MULTIPLANAR(ctx->vq_img.type)) {int i;for (i = 0; i < buf->length; ++i)buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;} else {buf->m.offset += DST_QUEUE_OFF_BASE;}}} else {...}return ret;
}
我为 S5P6818
的 VPU 编写了一个测试程序 nxvpu-yuv2jpg.c
,该程序用于将 YUV420 或 GREY
格式数据转换为 MJEPG
格式数据,实现代码见 S5P6818 VPU测试范例代码 。
5. 参考资料
https://wiki.friendlyelec.com/wiki/index.php/NanoPC-T3_Plus/zh
相关文章:
Linux驱动:VPU
1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。 2. 概述 VPU 是用来进行图像、视频数据进行硬件编、解码的硬件模块。内部集成了 Encoder、Decoder 功能部件进行图像、视频数据进行硬件编、解码&a…...

简介Servlet
目录 一、maven中心库 二、简介Servlet 三、实现Servlet动态页面 1、创建一个maven项目 2、引入依赖 3、创建目录结构 4、编写Servlet代码 5、打包 6、部署 7、验证程序 四、Servlet的运行原理 五、Tomcat伪代码 1、Tomcat初始化 a、让Tomcat先从指定的目录…...

Learning C++ No.7
引言: 北京时间:20223/2/9/22:20,距离大一下学期开学还有2天,昨天收到好消息,开学不要考试了,我并不是害怕考试,考试在我心里,地位不高,可能只有当我挂了,才能…...

【MyBatis】第八篇:一级,二级缓存
其实缓存字面的意思就是将一些内容缓存下来,等下次使用的时候可以直接调用,通过数据库得到数据,有时候会使用相同的数据,所以mybatis自然也支持缓存。 而mybatis按照缓存的效果可以分两大类:一级缓存和二级缓存。 一…...

【大唐杯备考】——5G基站开通与调测(学习笔记)
📖 前言:本期介绍5G基站开通与调测。 目录🕒 1. 概述🕒 2. 5G基站开通与调测基础🕘 2.1 3.5GHz单模100MHz配置(S111)🕘 2.2 3.5GHz单模100MHz配置(S111111)&a…...
redhat7 忘记root密码,重置办法
来自https://www.tracymc.cn/archives/802 亲测可用,太感谢了,在此记录一下,原文有图 1.启动的时候,在有启动项界面,相应启动项内核名称上按“e”; 2.进入后,找到linux16开头的地方,按“end”键或者controle到最后,输入rd.break,再按ctrlx进…...
QML- 对象属性
QML- 对象属性一、概述二、id 属性三、Property 属性1. 定义属性1. 自定义属性定义中的有效类型2. 为属性属性赋值1. 初始化时的值赋值2. 命令式赋值3. 静态值和绑定表达式值4. 类型安全5. 特殊属性类型1. 对象列表属性2. 分组属性6. 属性别名1. 属性别名的注意事项2. 属性别名…...

将.js文件转成vue标签结构的样式
例如:下图所示: 依次识别获取.js文件中的tag和props,可以理解为字符串拼接,将整个vue的标签结构看作是一个字符串。 话不多说,先放上完整代码,思路看代码备注。(自己实现的时候,可以…...

前端知识点复盘
组件和jsx <body><div id"root"></div><script type"text/babel">const root ReactDOM.createRoot(document.getElementById("root"))class App extends React.Component {render() {return (<div> <h1>s…...

前端JavaScript获取图片文件的真实格式
常见方式判断图片格式 当我们进行前端开发,需要处理图片上传功能,针对图片格式做判断时,常规的方法都是使用文件后缀名来判断,如下代码所示: input.addEventListener(change, (e) > {const file e.target.files[…...

今天面了一个来华为要求月薪25K,明显感觉他背了很多面试题...
最近有朋友去华为面试,面试前后进行了20天左右,包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说,80%的人都会栽在第一轮面试,要不是他面试前做足准备,估计都坚持不完后面几轮面试。 其实&…...

11 Advanced CNN
文章目录GoogLeNetInception Module1x1 Conv计算效果代码实现总结ResNet (残差网络)问题引入梯度消失与传统神经网络的比较代码实现课程来源: 链接对于前篇中所提到问题,设计出的是一种类似于LeNet5的线性结构,而对于大多数问题,简…...

亿级高并发电商项目---万达商城项目搭建(二)
👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者 📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶 Ǵ…...

UML术语标准和分类
一、UML术语标准 1.中文UML术语标准 中国软件行业协会(CSIA)与日本UML建模推进协会(UMTP)共同在中国推动的UML专家认证,两个协会共同颁发认证证书、两国互认,CSIA与UMTP共同推出了UML中文术语…...
LeetCode 刷题系列 -- 151. 反转字符串中的单词
给你一个字符串 s ,请你反转字符串中 单词 的顺序。单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。注意:输入字符串 s中可能会存在前导空格、尾随空格或…...

二十二、Gtk4-ListView
GTK 4添加了新的列表对象GtkListView、GtkGridView和GtkColumnView。这个新特性在Gtk API参考—列表小构件概述中有描述。 GTK 4还有其他实现列表的方法。它们是GtkListBox和GtkTreeView,它们是从GTK 3接管的。在Gtk开发博客中有一篇关于Matthias Clasen所写的列表…...

ASP.NET Core3.1实战教程---基于Jquery单文件上传
这个必须记录一下费劲啊!废了我2天的时间,昔日的net快速已经没落....就文件上传都这么费劲。 先说下要求(在线apk文件上传实现手机端整包更新): 1、为了简化需求文件上传和数据提交分开执行 2、选完文件后按钮变成上…...

10 卷积神经网络CNN(基础篇)
文章目录全连接CNN过程卷积过程下采样过程全连接层卷积原理单通道卷积多通道卷积改进多通道总结以及课程代码卷积改进PaddingStride下采样过程大池化层(Max Pooling)简单卷积神经网络的实现课程代码本篇课程来源: 链接部分文本来源参考&#…...

Windows下LuaBridge2.8的环境配置及简单应用
Windows下LuaBridge2.8的环境配置及简单应用 LuaBridge2.8下载链接: https://github.com/vinniefalco/LuaBridge/tags 关于Lua的环境配置可参考以下链接(这里不做简述): https://ufgnix0802.blog.csdn.net/article/details/125341…...

每天10个前端小知识 【Day 10】
前端面试基础知识题 1. es5 中的类和es6中的class有什么区别? 在es5中主要是通过构造函数方式和原型方式来定义一个类,在es6中我们可以通过class来定义类。 class类必须new调用,不能直接执行。 class类执行的话会报错,而es5中…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
鸿蒙(HarmonyOS5)实现跳一跳小游戏
下面我将介绍如何使用鸿蒙的ArkUI框架,实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...