RK3568笔记九: DRM显示摄像头

若该文为原创文章,转载请注明原文出处。

一、介绍

学习DRM的目的是想做类似NVR显示多路实时流,通过勇哥(Marc)的指导,大概流程是通过Zlmedia拉流,RK3568的MPP解码,DRM显示,可以使用HDMI或DIS屏幕,所以为了后面的实现,先测试摄像头采集DRM显示。

二、移植过程

测试过程在笔记八里,如有不懂的,请看笔迹八。

移植过程参考GitHub - MontaukLaw/cvv_test

里面有DRM显示两个屏的例子。

程序是以正点原子里的rknn_yolov5_demo例程修改。主要修改几个地方。

大概流程:

1、初始化屏幕  drm_dis_init();

2、opencv打开摄像头cv::VideoCapture cap(0);

3、循环读数据并显示

cap.read(orig_img);

draw_lcd_screen_rgb_960((uint8_t *)img.data, 720 * 1280 * 3);

代码:

main.cc

// Copyright (c) 2021 by Rockchip Electronics Co., Ltd. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License./*-------------------------------------------Includes
-------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <dlfcn.h>
#include <vector>
#include <string>#include "drm_func.h"
#include "rga_func.h"
#include "rknn_api.h"
#include "yolo.h"#include "RgaUtils.h"
#include "im2d.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <opencv2/opencv.hpp>
#include "rga.h"
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "dev.h"
#include "bo.h"static sp_dev *mDev;
#define OUTPUT_DEVICE_LCD 1static drmModeConnectorPtr lcdConnectorPtr = nullptr;
static struct sp_crtc *lcdCRPtr;
static drmModeEncoderPtr lcdEncoderPtr = nullptr;
static uint32_t lcdCrtcId = 0;
static drmModeModeInfoPtr lcdModInfoPtr;static void get_connector(uint8_t outpuDevice)
{int i, j = 0;int ret = 0;printf("mDev->num_connectors = %d\n", mDev->num_connectors);for (j = 0; j < mDev->num_connectors; j++){// name 是分辨率信息printf("connector name:%d\n", j);printf("connector_type:%d\n", j);printf("connector_type_id:%d\n", j);printf("connector status:%d\n", j);// 对应不同的输出设备, 指定不同的connector跟encoderif (outpuDevice == OUTPUT_DEVICE_LCD){if (mDev->connectors[j]->connector_type == DRM_MODE_CONNECTOR_DSI &&mDev->connectors[j]->connection == DRM_MODE_CONNECTED){lcdConnectorPtr = mDev->connectors[j];}}}
}static void get_encoder(uint8_t outpuDevice)
{int i;for (i = 0; i < mDev->num_encoders; i++){if (outpuDevice == OUTPUT_DEVICE_LCD){if (mDev->encoders[i]->encoder_type == DRM_MODE_ENCODER_DSI){lcdEncoderPtr = mDev->encoders[i];lcdCrtcId = lcdEncoderPtr->crtc_id;}}}
}static void get_crtc()
{int j;printf("lcd crtc id:%d\n", lcdCrtcId);for (j = 0; j < mDev->num_crtcs; j++){printf("encoderPtr->crtc_id:%d\n", mDev->crtcs[j].crtc->crtc_id);printf("mode_valid:%d\n", mDev->crtcs[j].crtc->mode_valid);printf("mode_name:%s\n", mDev->crtcs[j].crtc->mode.name);if (mDev->crtcs[j].crtc->crtc_id == lcdCrtcId && mDev->crtcs[j].crtc->mode_valid){lcdCRPtr = &mDev->crtcs[j];}}
}static int init_screens()
{int ret = 0;// 获取lcd connectorget_connector(OUTPUT_DEVICE_LCD);if (!lcdConnectorPtr){printf("failed to get hdmi connector or encoder.\n");return -1;}printf("lcd connector id:%d\n", lcdConnectorPtr->connector_id);// 获取lcd encoderget_encoder(OUTPUT_DEVICE_LCD);if (!lcdEncoderPtr){printf("failed to get encoder.\n");return -2;}printf("lcd encoder id:%d\n", lcdEncoderPtr->encoder_id);// 获取一下显示分辨率之类lcdModInfoPtr = &lcdConnectorPtr->modes[0];// 把connector的encoder id赋值为encoder的idlcdConnectorPtr->encoder_id = lcdEncoderPtr->encoder_id;// 获取lcd crtcget_crtc();if (!lcdCRPtr){printf("failed to get crtc.\n");return -3;}if (lcdCRPtr->scanout){printf("crtc already in use\n");return -4;}printf("lcd crtc id:%d\n", lcdCRPtr->crtc->crtc_id);// allset// 获取bo, 只需要输入分辨率即可.lcdCRPtr->scanout = create_sp_bo(mDev, lcdModInfoPtr->hdisplay, lcdModInfoPtr->vdisplay, 24, 32, DRM_FORMAT_XRGB8888, 0);if (!lcdCRPtr->scanout){printf("failed to create new scanout bo\n");return -5;}printf("fill test color\n");fill_bo(lcdCRPtr->scanout, 0xff, 0xff, 0x0, 0x0);ret = drmModeSetCrtc(mDev->fd, lcdEncoderPtr->crtc_id, lcdCRPtr->scanout->fb_id, 0, 0, &lcdConnectorPtr->connector_id, 1, lcdModInfoPtr);if (ret){printf("failed to set crtc mode ret=%d\n", ret);return -6;}lcdCRPtr->crtc = drmModeGetCrtc(mDev->fd, lcdCRPtr->crtc->crtc_id);memcpy(&lcdCRPtr->crtc->mode, lcdModInfoPtr, sizeof(*lcdModInfoPtr));return 0;
}int drm_dis_init(void)
{int ret = 0;int i = 0;printf("create sp dev\n");// 创建显示设备mDev = create_sp_dev();if (!mDev){printf("failed to exec create_sp_dev.\n");return -10;}printf("init_screen\n");// 初始化屏幕ret = init_screens();if (ret != 0){printf("failed to exec initialize_screens.\n");return -11;}return 0;
}void draw_lcd_screen_rgb_960(uint8_t *data, uint32_t dataSize)
{uint32_t colIdx = 0;uint32_t rowIdx = 0;uint8_t *dataPtr = data;for (rowIdx = 0; rowIdx < 1280; rowIdx++){uint8_t *rowPtr = (uint8_t *)lcdCRPtr->scanout->map_addr + rowIdx * lcdCRPtr->scanout->pitch;for (colIdx = 0; colIdx < 720; colIdx++){uint8_t *pixel = rowPtr + colIdx * 4;pixel[0] = *dataPtr;dataPtr++;pixel[1] = *dataPtr;dataPtr++;pixel[2] = *dataPtr;dataPtr++;pixel[3] = 0xff;}}
}int main(int argc, char **argv)
{int i,j;drm_dis_init();cv::VideoCapture cap(0);if (!cap.isOpened()){std::cout << "无法打开摄像头" << std::endl;return -1;}cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720);// using opencvusing namespace cv;using namespace std;cv::Mat orig_img;cv::Mat img;char  data_u8[4];while(1){cap.read(orig_img);cv::rotate(orig_img, orig_img, ROTATE_90_COUNTERCLOCKWISE);cv::cvtColor(orig_img, img, cv::COLOR_BGR2RGB);draw_lcd_screen_rgb_960((uint8_t *)img.data, 720 * 1280 * 3);}exit(0);
}

这里需要注意的是显示部分

显示是32位的RGBA,所以需要封装一下,初始化得到了map_addr映射地址,直接填充数据,就会显示。

使用正点原子需要先关闭QT应用程序,不然运行一会就会退出。

CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)project(rknn_yolov5v7x_demo)set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_SKIP_INSTALL_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")# rknn api
set(PLATFORM RK3566_3568)
set(LIB_ARCH aarch64)
set(RKNN_API_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libs/rknpu2/runtime/RK356X/Linux/librknn_api)
set(RKNN_RT_LIB ${RKNN_API_PATH}/aarch64/librknnrt.so)
include_directories(${RKNN_API_PATH}/include)# drm
set(DRM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/common/drm)
set(DRM_RT_LIB ${CMAKE_CURRENT_SOURCE_DIR}/libs/libdrm/lib/libdrm.so)
include_directories(${DRM_DIR}/include)
include_directories(${DRM_DIR}/include/libdrm)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs/rkdrm/)#rga
set(RGA_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libs/librga)
set(RGA_LIB ${RGA_PATH}/libs/Linux/gcc-aarch64/librga.so)
include_directories(${RGA_PATH}/include)set(OPENCV_LIBS opencv_core opencv_flann opencv_videoio opencv_video opencv_highgui opencv_imgcodecs opencv_imgproc)
set(TOOLCHAIN_DIR /opt/atk-dlrk356x-toolchain)
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/usr/bin/aarch64-buildroot-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/usr/bin/aarch64-buildroot-linux-gnu-c++)
set(SYSROOT ${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu//sysroot/usr/include)
set(CMAKE_SYSROOT ${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu/sysroot)
include_directories(${SYSROOT})
include_directories(${SYSROOT}/opencv4)set(CMAKE_INSTALL_RPATH "lib")# rknn_yolo_demo
include_directories( ${CMAKE_SOURCE_DIR}/include)
add_executable(rknn_yolo_demosrc/drm_func.csrc/rga_func.csrc/yolo.ccsrc/main.ccsrc/bo.ccsrc/dev.ccsrc/modeset.cc
)target_link_libraries(rknn_yolo_demo${RKNN_RT_LIB}${RGA_LIB}${OPENCV_LIBS}${DRM_RT_LIB}dl
)# install target and libraries
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install/atk_rknn_yolo_v5_demo)
install(TARGETS rknn_yolo_demo DESTINATION ./)install(PROGRAMS ${RKNN_RT_LIB} DESTINATION lib)
install(PROGRAMS ${RGA_LIB} DESTINATION lib)
install(DIRECTORY model DESTINATION ./)

编译后,把可执行文件上传到板子运行后,测试正常。

如有侵权,或需要完整代码,请及时联系博主。

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

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

相关文章

ssm+vue的物流配送人员车辆调度管理系统的设计与实现(有报告)。Javaee项目,ssm vue前后端分离项项目。

演示视频&#xff1a; ssmvue的物流配送人员车辆调度管理系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&…

【C++干货铺】会旋转的二叉树——AVLTree

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 前言 AVL树 AVL树的概念 AVL树结点的定义 AVL树的插入 寻找插入结点的位置 修改平衡因子 AVL树的旋转 右单旋 左单旋 先右旋再左旋 先左旋再右旋 AVL树…

Kubernetes (十三) 存储——持久卷-动静态分配

一. 简介 二. NFS持久化存储步骤&#xff08;静态分配&#xff09; 1. 集群外…

数字信号处理教程学习笔记1-第2章时域中的离散信号和系统

信号处理的任务示意方框图 模拟信号和数字信号分别是啥样的,有啥区别

freetos day1

作业&#xff1a;使用计数型信号量设计&#xff1a;生产者和消费者模型 总结今天学习的API函数&#xff0c;写出函数参数和返回值的意思&#xff0c;并且说明函数功能 1 2 3

如何结合主从复制,不停服情况下解决分库分表

首先我们要知道主从复制和分库分表两个概念&#xff0c;在此基础上可以将问题分为几个阶段来执行&#xff0c;参考了公众号 双写读老 双写双读 写新读新

WEB 3D技术 three.js 3D贺卡(1) 搭建基本项目环境

好 今天 我也是在网上学的 带着大家一起来做个3D贺卡 首先 我们要创建一个vue3的项目、 先创建一个文件夹 装我们的项目 终端执行 vue create 项目名称 例如 我的名字想叫 greetingCards 就是 vue create greetingcards因为这个名录 里面是全部都小写的 然后 下面选择 vue3 …

代码随想录算法训练营Day21| 93.复原IP地址、78.子集、90.子集||

LeetCode 93 复原 IP 地址 本题思路&#xff1a;最重要的是想到一个收集结果的条件&#xff0c;也就是终止条件。 当 . 的个数达到三个时候&#xff0c;并且&#xff0c;判断最后剩余的是否符合要求&#xff0c;如果符合&#xff0c;说明整个ip地址可以&#xff0c;就加入到结…

【数据结构】C语言实现共享栈

共享栈的C语言实现 导言一、共享栈1.1 共享栈的初始化1.2 共享栈的判空1.3 共享栈的入栈1.3.1 空指针1.3.2 满栈1.3.3 入栈空间错误1.3.4 正常入栈1.3.5 小结 1.4 共享栈的查找1.5 共享栈的出栈1.6 共享栈的销毁 二、共享栈的实现演示结语 导言 大家好&#xff0c;很高兴又和大…

腾讯云主机价格表和优惠活动汇总(2024年更新)

腾讯云服务器租用价格表&#xff1a;轻量应用服务器2核2G3M价格62元一年、2核2G4M价格118元一年&#xff0c;540元三年、2核4G5M带宽218元一年&#xff0c;2核4G5M带宽756元三年、轻量4核8G12M服务器446元一年、646元15个月&#xff0c;云服务器CVM S5实例2核2G配置280.8元一年…

检索增强生成RAG

文章目录 RAG解释混合检索重排序Rerank为什么需要RerankHNSW带来的随机性问题 当前大模型处理长输入的水平依然不够大模型如何处理长输入&#xff1f;重要信息位置为什么会影响大模型的效果LangChain的解决方案-检索后重新排序文档 召回模式N选1召回模式多路召回模式 摘要 在RA…

记录一次git merge后发现有些文件不对的问题,排查过程

分支进行merge&#xff08;A merge到B&#xff09;之后&#xff0c;发现string.xml中有些字段的值没有merge过来&#xff0c;一开始还以为自己是自己merge错误&#xff0c;检查了一遍自己的merge操作没有问题。 那为啥没有merge过来呢&#xff1f;有一种可能是&#xff0c;merg…

排序——计数排序

文章目录 概念思路绝对映射&#xff1a;相对映射 代码实现特性结果演示 概念 计数排序是一个非基于比较的排序算法&#xff0c;该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时&#xff0c;它的复杂度为Ο(nk)&#xff08;其中k是整数的范围…

内网穿透[让你在家里也能榨干学校的服务器]Yep!

内网穿透 问题&#xff1a;什么是内网穿透&#xff0c;内网穿透的作用是什么&#xff1f; 前提&#xff01;&#xff01;&#xff01;&#xff01;你得拥有超级管理员的权限&#xff0c;比如root&#xff0c;不然后面的一切免提&#xff01; 应用场景如下&#xff1a;比如你…

中科院国产多语言大模型-YAYI2开源!家族AI应用场景全覆盖!

项目简介 YAYI 2 是中科闻歌研发的新一代开源大语言模型&#xff0c;中文名&#xff1a;雅意&#xff0c;采用了超过 2 万亿 Tokens 的高质量、多语言语料进行预训练。 开源地址&#xff1a;https://github.com/wenge-research/YAYI2 YAYI2-30B是其模型规模&#xff0c;是基…

文件上传进阶绕过(二)4个技巧和靶场实战

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 0、环境准备 请移步《文件上传靶场实战&#xff1a;upl…

C++ | 四、指针、链表

指针 指针用来储存地址定义方式&#xff0c;int *ptr;&#xff0c;使用*来表示所定义的变量是指针取地址符&#xff0c;ptr &a;&#xff0c;通过&来取得一个普通变量的地址&#xff0c;并储存到指针中取值&#xff08;解引用&#xff09;&#xff0c;想要取得一个指针…

【华为OD机试真题2023CD卷 JAVAJS】查找一个有向网络的头节点和尾节点

华为OD2023(C&D卷)机试题库全覆盖,刷题指南点这里 查找一个有向网络的头节点和尾节点 知识点图DFS搜索 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 给定一个有向图,图中可能包含有环,图使用二维矩阵表示,每一行的第一列表示起始节点,第二列表示终止节…

Java 线程

1. 实现多线程的 2 种方式 Oracle 官网的文档中给出了 2 种实现多线程的方式&#xff1a; 实现 Runnable 接口&#xff1b;继承 Thread 类。 以上两种方式都会调用 Thread.run() 方法&#xff0c;区别是&#xff1a; 实现 Runnable 接口&#xff0c;只是执行 Thread.run() …

【新】Unity Meta Quest MR 开发(一):Passthrough 透视配置

文章目录 &#x1f4d5;教程说明&#x1f4d5;配置透视的串流调试功能&#x1f4d5;第一步&#xff1a;设置 OVRManager&#x1f4d5;第二步&#xff1a;添加 OVRPassthroughLayer 脚本&#x1f4d5;第三步&#xff1a;在场景中添加虚拟物体&#x1f4d5;第四步&#xff1a;设置…