RK3568笔记九: DRM显示摄像头

2024-01-16 00:36

本文主要是介绍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 ./)

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

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

这篇关于RK3568笔记九: DRM显示摄像头的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/610738

相关文章

Python如何将OpenCV摄像头视频流通过浏览器播放

《Python如何将OpenCV摄像头视频流通过浏览器播放》:本文主要介绍Python如何将OpenCV摄像头视频流通过浏览器播放的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完... 目录方法1:使用Flask + MJPEG流实现代码使用方法优点缺点方法2:使用WebSocket传输视

SpringSecurity显示用户账号已被锁定的原因及解决方案

《SpringSecurity显示用户账号已被锁定的原因及解决方案》SpringSecurity中用户账号被锁定问题源于UserDetails接口方法返回值错误,解决方案是修正isAccountNon... 目录SpringSecurity显示用户账号已被锁定的解决方案1.问题出现前的工作2.问题出现原因各

java对接海康摄像头的完整步骤记录

《java对接海康摄像头的完整步骤记录》在Java中调用海康威视摄像头通常需要使用海康威视提供的SDK,下面这篇文章主要给大家介绍了关于java对接海康摄像头的完整步骤,文中通过代码介绍的非常详细,需... 目录一、开发环境准备二、实现Java调用设备接口(一)加载动态链接库(二)结构体、接口重定义1.类型

RedisTemplate默认序列化方式显示中文乱码的解决

《RedisTemplate默认序列化方式显示中文乱码的解决》本文主要介绍了SpringDataRedis默认使用JdkSerializationRedisSerializer导致数据乱码,文中通过示... 目录1. 问题原因2. 解决方案3. 配置类示例4. 配置说明5. 使用示例6. 验证存储结果7.

C/C++和OpenCV实现调用摄像头

《C/C++和OpenCV实现调用摄像头》本文主要介绍了C/C++和OpenCV实现调用摄像头,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录准备工作1. 打开摄像头2. 读取视频帧3. 显示视频帧4. 释放资源5. 获取和设置摄像头属性

idea中project的显示问题及解决

《idea中project的显示问题及解决》:本文主要介绍idea中project的显示问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录idea中project的显示问题清除配置重China编程新生成配置总结idea中project的显示问题新建空的pr

电脑显示mfc100u.dll丢失怎么办?系统报错mfc90u.dll丢失5种修复方案

《电脑显示mfc100u.dll丢失怎么办?系统报错mfc90u.dll丢失5种修复方案》最近有不少兄弟反映,电脑突然弹出“mfc100u.dll已加载,但找不到入口点”的错误提示,导致一些程序无法正... 在计算机使用过程中,我们经常会遇到一些错误提示,其中最常见的就是“找不到指定的模块”或“缺少某个DL

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js

QT移植到RK3568开发板的方法步骤

《QT移植到RK3568开发板的方法步骤》本文主要介绍了QT移植到RK3568开发板的方法步骤,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录前言一、获取SDK1. 安装依赖2. 获取SDK资源包3. SDK工程目录介绍4. 获取补丁包二