Android12之DRM基本接口实现(二)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

1.前言
本篇目的:探究DRM基本接口的实现,底层实现到底是如何与DRM驱动通信的?
2.DRM基本接口实现解析
<1>.DRM之drmModeGetResources获取CRTC和Connector的id号
drm_public drmModeResPtr drmModeGetResources(int fd)
{struct drm_mode_card_res res, counts;drmModeResPtr r = 0;retry:memclear(res);if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))return 0;counts = res;if (res.count_fbs) {res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));if (!res.fb_id_ptr)goto err_allocs;}if (res.count_crtcs) {res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));if (!res.crtc_id_ptr)goto err_allocs;}if (res.count_connectors) {res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));if (!res.connector_id_ptr)goto err_allocs;}if (res.count_encoders) {res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));if (!res.encoder_id_ptr)goto err_allocs;}if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))goto err_allocs;/* The number of available connectors and etc may have changed with a* hotplug event in between the ioctls, in which case the field is* silently ignored by the kernel.*/if (counts.count_fbs < res.count_fbs ||counts.count_crtcs < res.count_crtcs ||counts.count_connectors < res.count_connectors ||counts.count_encoders < res.count_encoders){drmFree(U642VOID(res.fb_id_ptr));drmFree(U642VOID(res.crtc_id_ptr));drmFree(U642VOID(res.connector_id_ptr));drmFree(U642VOID(res.encoder_id_ptr));goto retry;}/** return*/if (!(r = drmMalloc(sizeof(*r))))goto err_allocs;r->min_width = res.min_width;r->max_width = res.max_width;r->min_height = res.min_height;r->max_height = res.max_height;r->count_fbs = res.count_fbs;r->count_crtcs = res.count_crtcs;r->count_connectors = res.count_connectors;r->count_encoders = res.count_encoders;r->fbs = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));r->crtcs = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));r->encoders = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));if ((res.count_fbs && !r->fbs) ||(res.count_crtcs && !r->crtcs) ||(res.count_connectors && !r->connectors) ||(res.count_encoders && !r->encoders)){drmFree(r->fbs);drmFree(r->crtcs);drmFree(r->connectors);drmFree(r->encoders);drmFree(r);r = 0;}err_allocs:drmFree(U642VOID(res.fb_id_ptr));drmFree(U642VOID(res.crtc_id_ptr));drmFree(U642VOID(res.connector_id_ptr));drmFree(U642VOID(res.encoder_id_ptr));return r;
}
核心要点1
1.调用drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)获取CRTC和Connector的id号。
2.drm_mode_card_res数据结构
struct drm_mode_card_res {__u64 fb_id_ptr;__u64 crtc_id_ptr;__u64 connector_id_ptr;__u64 encoder_id_ptr;__u32 count_fbs;__u32 count_crtcs;__u32 count_connectors;__u32 count_encoders;__u32 min_width;__u32 max_width;__u32 min_height;__u32 max_height;
};
<2>.DRM之drmModeGetConnector连接Connector显示器
static drmModeConnectorPtr
_drmModeGetConnector(int fd, uint32_t connector_id, int probe)
{struct drm_mode_get_connector conn, counts;drmModeConnectorPtr r = NULL;struct drm_mode_modeinfo stack_mode;memclear(conn);conn.connector_id = connector_id;if (!probe) {conn.count_modes = 1;conn.modes_ptr = VOID2U64(&stack_mode);}if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))return 0;retry:counts = conn;if (conn.count_props) {conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));if (!conn.props_ptr)goto err_allocs;conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));if (!conn.prop_values_ptr)goto err_allocs;}if (conn.count_modes) {conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));if (!conn.modes_ptr)goto err_allocs;} else {conn.count_modes = 1;conn.modes_ptr = VOID2U64(&stack_mode);}if (conn.count_encoders) {conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));if (!conn.encoders_ptr)goto err_allocs;}if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))goto err_allocs;/* The number of available connectors and etc may have changed with a* hotplug event in between the ioctls, in which case the field is* silently ignored by the kernel.*/if (counts.count_props < conn.count_props ||counts.count_modes < conn.count_modes ||counts.count_encoders < conn.count_encoders) {drmFree(U642VOID(conn.props_ptr));drmFree(U642VOID(conn.prop_values_ptr));if (U642VOID(conn.modes_ptr) != &stack_mode)drmFree(U642VOID(conn.modes_ptr));drmFree(U642VOID(conn.encoders_ptr));goto retry;}if(!(r = drmMalloc(sizeof(*r)))) {goto err_allocs;}r->connector_id = conn.connector_id;r->encoder_id = conn.encoder_id;r->connection = conn.connection;r->mmWidth = conn.mm_width;r->mmHeight = conn.mm_height;/* convert subpixel from kernel to userspace */r->subpixel = conn.subpixel + 1;r->count_modes = conn.count_modes;r->count_props = conn.count_props;r->props = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));r->prop_values = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));r->modes = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo));r->count_encoders = conn.count_encoders;r->encoders = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t));r->connector_type = conn.connector_type;r->connector_type_id = conn.connector_type_id;if ((r->count_props && !r->props) ||(r->count_props && !r->prop_values) ||(r->count_modes && !r->modes) ||(r->count_encoders && !r->encoders)) {drmFree(r->props);drmFree(r->prop_values);drmFree(r->modes);drmFree(r->encoders);drmFree(r);r = 0;}err_allocs:drmFree(U642VOID(conn.prop_values_ptr));drmFree(U642VOID(conn.props_ptr));if (U642VOID(conn.modes_ptr) != &stack_mode)drmFree(U642VOID(conn.modes_ptr));drmFree(U642VOID(conn.encoders_ptr));return r;
}
核心要点2
1.drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn):连接CONNECTOR到显示器
2.drm_mode_get_connector数据结构
struct drm_mode_get_connector {__u64 encoders_ptr;__u64 modes_ptr;__u64 props_ptr;__u64 prop_values_ptr;__u32 count_modes;__u32 count_props;__u32 count_encoders;__u32 encoder_id;__u32 connector_id;__u32 connector_type;__u32 connector_type_id;__u32 connection;__u32 mm_width;__u32 mm_height;__u32 subpixel;__u32 pad;
};
<3>.DRM之modeset_create_fb添加framebuffer设备
static int modeset_create_fb(int fd, struct buffer_object *bo) {struct drm_mode_create_dumb create = {};struct drm_mode_map_dumb map = {};create.width = bo->width;create.height = bo->height;create.bpp = 32;drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);printf("create dumb w %d h %d\n", bo->width, bo->height);getchar();bo->pitch = create.pitch;bo->size = create.size;bo->handle = create.handle;drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch, bo->handle,&bo->fb_id);printf("drmModeAddFB\n");getchar();map.handle = create.handle;drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);printf("map dumb\n");getchar();bo->vaddr = static_cast<unsigned char *>(mmap64(0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset));memset(bo->vaddr, 0xff, bo->size);return 0;
}
核心要点3
1.drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create): 增加申请DUMB共享内存
2.drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch, bo->handle,&bo->fb_id);
DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB, &f);:添加一个FrameBuffer
3.bo->vaddr = static_cast<unsigned char *>(mmap64( 0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset));:映射DRM图形buffer的共享内存到bo->vaddr地址。
memset(bo->vaddr, 0xff, bo->size);:设置白色。
4.drm_mode_create_dumb和drm_mode_map_dumb数据结构
struct drm_mode_create_dumb {__u32 height;__u32 width;__u32 bpp;__u32 flags;__u32 handle;__u32 pitch;__u64 size;
};struct drm_mode_map_dumb {__u32 handle;__u32 pad;__u64 offset;
};
<4>.DRM之drmModeSetCrtcCRTC开始扫描framebuffer数据显示
drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,uint32_t x, uint32_t y, uint32_t *connectors, int count,drmModeModeInfoPtr mode)
{struct drm_mode_crtc crtc;memclear(crtc);crtc.x = x;crtc.y = y;crtc.crtc_id = crtcId;crtc.fb_id = bufferId;crtc.set_connectors_ptr = VOID2U64(connectors);crtc.count_connectors = count;if (mode) {memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));crtc.mode_valid = 1;}return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
}
核心要点4
1.DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc):CRTC对framebuffer的数据进行扫描
2.drm_mode_crtc数据结构
struct drm_mode_crtc {__u64 set_connectors_ptr;__u32 count_connectors;__u32 crtc_id;__u32 fb_id;__u32 x;__u32 y;__u32 gamma_size;__u32 mode_valid;struct drm_mode_modeinfo mode;
};
<5>.DRM之modeset_destroy_fb关闭framebuffer设备
static void modeset_destroy_fb(int fd, struct buffer_object *bo) {struct drm_mode_destroy_dumb destroy = {};drmModeRmFB(fd, bo->fb_id);munmap(bo->vaddr, bo->size);destroy.handle = bo->handle;drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
}
核心要点5
1.drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);:销毁DUMB共享内存
2.drm_mode_destroy_dumb数据结构
struct drm_mode_destroy_dumb {__u32 handle;
};
<6>.DRM之drmModeFreeConnector断开Connector连接
drm_public void drmModeFreeConnector(drmModeConnectorPtr ptr)
{if (!ptr)return;drmFree(ptr->encoders);drmFree(ptr->prop_values);drmFree(ptr->props);drmFree(ptr->modes);drmFree(ptr);
}
核心要点6
1.调用drmFree释放内存,内部调用free()函数。
2.drmFree函数实现
drm_public void drmFree(void *pt)
{free(pt);
}
<7>.DRM之drmModeFreeResources释放资源
drm_public void drmModeFreeResources(drmModeResPtr ptr)
{if (!ptr)return;drmFree(ptr->fbs);drmFree(ptr->crtcs);drmFree(ptr->connectors);drmFree(ptr->encoders);drmFree(ptr);
}
核心要点7
1.调用drmFree释放资源,本质和drmModeFreeConnector一样,也是释放内存资源。
3.DRM基本接口总结
- 1.drmModeGetResources函数调用DRM驱动通过ioctl(DRM_IOCTL_MODE_GETRESOURCES):获取CRTC和Connector的id号。
- 2.drmModeGetConnector函数调用ioctl(DRM_IOCTL_MODE_GETCONNECTOR):连接CONNECTOR到显示器
- 3.modeset_create_fb函数调用ioctl(DRM_IOCTL_MODE_ADDFB):添加一个FrameBuffer
- 4.drmModeSetCrtc函数调用ioctl(DRM_IOCTL_MODE_SETCRTC):CRTC对framebuffer的数据进行扫描
- 5.modeset_destroy_fb函数调用ioctl(DRM_IOCTL_MODE_DESTROY_DUMB):销毁DUMB共享内存
- 6.drmModeFreeConnector函数调用drmFree释放内存资源
- 7.drmModeFreeResources函数调用drmFree释放内存资源
相关文章:
Android12之DRM基本接口实现(二)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
普通二维码跳转微信小程序实战
简介 服务端springboot项目,前端基于uniapp的微信小程序,要求扫描二维码之后进入到小程序指定页面,下面记录一下实现过程以及过程中遇到的问题. 实现过程 下面是成功跳转的配置截图: 首先说下二维码规则,这个地方需要填写扫描二维码之后打开的地址,这个地址在我的项目里…...
spring boot 配置加载顺序
由官网的文档得知 https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config Default properties (specified by setting SpringApplication.setDefaultProperties).PropertySource annotations on your Configuration classe…...
基于stm32控制的4G模块在设备模式下通讯
这里的32控制其实和51的控制思路都是一样的,都是先利用一个网络助手将家里的无线网生成局域网,接着通过花生壳软件将局域网变成公共网,最后是利用串口助手,在4G模块的AT指令模式写入命令ATSOCKTCPC,公共网IP地址,公共网端口号&…...
预测宝可梦武力值、分类宝可梦
regression case 股票预测 无人车看到的各种sensor 影像镜头看到马路上的东西作为输入,输出就是方向盘角度等等的操纵策略 scalar 标量 这个是热力图,相当于你的XYZ但是Z用颜色表示了 closed-form solution 闭合解 learning rate事先定好的数值 在lin…...
Linux使用find命令查找文件
find命令 简介语法格式基本参数 参考实例根目录下文件名称的例子指定路径下特定类型的例子指定路径、文件类型特定文件名称的例子指定路径、文件类型特定文件大小的例子指定路径、文件类型 查找近期修改时间的例子指定路径、文件类型 查找空文件或目录的例子指定路径、文件类型…...
安卓使用android studio跨进程通信之AIDL
我写这篇文章不想从最基础的介绍开始,我直接上步骤吧. 1.创建服务端 1.1:创建服务端项目:我的as版本比较高,页面就是这样的 1.2:创建AIDL文件,右键项目,选中aidl aidl名字可以自定义也可以默认 basicTypes是自带的,可以删掉,也可以不删,然后把你自己所需的接口写上去 1.3:创建…...
RabbitMQ基础篇 笔记
RabbitMQ 余额支付 同步调用 一步一步的来,支付业务写完后,如果之后加需求,还需要增加代码,不符合开闭原则。 性能上也有问题,openfeign是同步调用,性能太差。 同步调用耦合太多。 同步的优势是可以立…...
实践小记—静态成员的使用注意(或许由此产生的不知名Bug)
序言 在实际生产过程中,为了便于调用,static修饰的成员会比较容易出现。 如果后期该变量并不会被修改,可以考虑使用。但如果后期需要被修改,使用该变量修饰符则需要慎重考虑。 尤其是在对硬件控制的实际生产中,更需…...
华为OD 身高体重排序(100分)【java】A卷+B卷
华为OD统一考试A卷B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载,请点击以下链接进入ÿ…...
在Word中,图片显示不全
在今天交作业的时候,发现了一个非常SB的事情,把图片复制过去显示不完全: 使用文心一言查看搜索了一下,发现可能是以下几种原因: 图片所在行的行高设置不正确。可以重新设置行高,具体步骤包括打开图片显示…...
C++数据结构X篇_20_选择排序
文章目录 1. 选择排序原理2. 选择排序原理核心代码3. 选择排序时间消耗 1. 选择排序原理 选择排序:相对于冒泡排序,减少了交换次数,下图展示了选择排序的原理,具体仍需要结合代码分析。 2. 选择排序原理核心代码 //选择排序 v…...
华为OD技术面试-最短距离矩阵(动态规划、广度优先)
背景 记录2023-10-21 晚华为OD三面的手撕代码题,当时没做出来,给面试官说了我的想法,评价:解法复杂了,只是简单的动态规范 或 广度优先算法,事后找资料记录实现方式。 题目 腐烂的橘子 问题描述ÿ…...
【代码规范】switch 块级的作用域问题
代码规范的一些事儿 问题 今日 Git 提交代码时,出现报错: error Unexpected lexical declaration in case block no-case-declarations 解决过程 我马上就去百度,就找到了这篇文章:解决 Unexpected lexical declaration in ca…...
PHP 基础/练习
练习 成绩定级 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>成绩定级脚本</title> </…...
TCP协议与UDP协议
UDP协议 UDP协议端的格式 16位UDP长度,表示整个数据报(UDP首部UDP数据)的最大长度;如果校验和出错,就会直接丢弃; UDP的特点 UDP传输过程类似寄信 无连接 知道对端的IP和端口号就直接进行传输,不需要建立连接; 不可靠 没有任何安全机制,…...
极智嘉(Geek+)柔性货箱到人拣选方案,助力Starlinks实现高效运营
近些年,电商业务席卷全球,一众企业蓬勃发展。比如沙特阿拉伯先进的物流与供应链解决方案供应商Starlinks的电子商务的销售额从6%增长到了23%。为满足日益增长的国际电商业务需求,以及订单交付时效性更高的要求,Starlinks与全球仓储…...
Hadoop3教程(三十一):(生产调优篇)异构存储
文章目录 (157)异构存储概述概述异构存储的shell操作 (158)异构存储案例实操参考文献 (157)异构存储概述 概述 异构存储,也叫做冷热数据分离。其中,经常使用的数据被叫做是热数据&…...
网络协议--UDP:用户数据报协议
11.1 引言 UDP是一个简单的面向数据报的运输层协议:进程的每个输出操作都正好产生一个UDP数据报,并组装成一份待发送的IP数据报。这与面向流字符的协议不同,如TCP,应用程序产生的全体数据与真正发送的单个IP数据报可能没有什么联…...
vscode摸鱼插件开发
不知道大家在写代码的时候,摸不摸鱼,是不是时不时得打开一下微博,看看今天发生了什么大事,又有谁塌房,而你没有及时赶上。 为此,我决定开发一个vscode插件,来查看微博热搜 插件名称࿱…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
