当前位置: 首页 > news >正文

Linux驱动:VPU

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 概述

VPU 是用来进行图像、视频数据进行硬件编、解码的硬件模块。内部集成了 EncoderDecoder 功能部件进行图像、视频数据进行硬件编、解码,以加速处理。

3. VPU 工作原理

3.1 VPU 编码工作流程

            ---------------|   ---------   |
输入数据 -->|->| Encoder |->|-> 编码后的输出数据|   ---------   ||               ||   ---------   ||  | Decoder |  ||   ---------   |---------------

3.2 VPU解码工作流程

              ---------------|   ---------   ||  | Encoder |  ||   ---------   ||               ||   ---------   |输入数据 -->|->| Decoder |->|-> 解码后的输出数据|   ---------   |---------------

4. Linux 下的 VPU

4.1 驱动架构

VPU驱动 可基于 V4L2子系统 框架完成。
1. 分别为 EncoderDecoder 各注册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. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 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

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

【MyBatis】第八篇:一级,二级缓存

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

【大唐杯备考】——5G基站开通与调测(学习笔记)

&#x1f4d6; 前言&#xff1a;本期介绍5G基站开通与调测。 目录&#x1f552; 1. 概述&#x1f552; 2. 5G基站开通与调测基础&#x1f558; 2.1 3.5GHz单模100MHz配置&#xff08;S111&#xff09;&#x1f558; 2.2 3.5GHz单模100MHz配置&#xff08;S111111&#xff09;&a…...

redhat7 忘记root密码,重置办法

来自https://www.tracymc.cn/archives/802 亲测可用&#xff0c;太感谢了&#xff0c;在此记录一下&#xff0c;原文有图 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标签结构的样式

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

前端知识点复盘

组件和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获取图片文件的真实格式

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

今天面了一个来华为要求月薪25K,明显感觉他背了很多面试题...

最近有朋友去华为面试&#xff0c;面试前后进行了20天左右&#xff0c;包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说&#xff0c;80%的人都会栽在第一轮面试&#xff0c;要不是他面试前做足准备&#xff0c;估计都坚持不完后面几轮面试。 其实&…...

11 Advanced CNN

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

亿级高并发电商项目---万达商城项目搭建(二)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是小童&#xff0c;Java开发工程师&#xff0c;CSDN博客博主&#xff0c;Java领域新星创作者 &#x1f4d5;系列专栏&#xff1a;前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶 &#x1f4…...

UML术语标准和分类

一、UML术语标准 1&#xff0e;中文UML术语标准 中国软件行业协会&#xff08;CSIA&#xff09;与日本UML建模推进协会&#xff08;UMTP&#xff09;共同在中国推动的UML专家认证&#xff0c;两个协会共同颁发认证证书、两国互认&#xff0c;CSIA与UMTP共同推出了UML中文术语…...

LeetCode 刷题系列 -- 151. 反转字符串中的单词

给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。注意&#xff1a;输入字符串 s中可能会存在前导空格、尾随空格或…...

二十二、Gtk4-ListView

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

ASP.NET Core3.1实战教程---基于Jquery单文件上传

这个必须记录一下费劲啊&#xff01;废了我2天的时间&#xff0c;昔日的net快速已经没落....就文件上传都这么费劲。 先说下要求&#xff08;在线apk文件上传实现手机端整包更新&#xff09;&#xff1a; 1、为了简化需求文件上传和数据提交分开执行 2、选完文件后按钮变成上…...

10 卷积神经网络CNN(基础篇)

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

Windows下LuaBridge2.8的环境配置及简单应用

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

每天10个前端小知识 【Day 10】

前端面试基础知识题 1. es5 中的类和es6中的class有什么区别&#xff1f; 在es5中主要是通过构造函数方式和原型方式来定义一个类&#xff0c;在es6中我们可以通过class来定义类。 class类必须new调用&#xff0c;不能直接执行。 class类执行的话会报错&#xff0c;而es5中…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...