RK3568笔记九: DRM显示摄像头

这篇具有很好参考价值的文章主要介绍了RK3568笔记九: DRM显示摄像头。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

一、介绍

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

二、移植过程

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

移植过程参考GitHub - MontaukLaw/cvv_test

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

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

RK3568笔记九: DRM显示摄像头,RK3568学习笔记,笔记

大概流程:

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 1

static 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跟encoder
        if (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 connector
    get_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 encoder
    get_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的id
    lcdConnectorPtr->encoder_id = lcdEncoderPtr->encoder_id;

    // 获取lcd crtc
    get_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 opencv
	using 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);
}

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

RK3568笔记九: DRM显示摄像头,RK3568学习笔记,笔记

显示是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_demo
        src/drm_func.c
        src/rga_func.c
        src/yolo.cc
        src/main.cc
        src/bo.cc
        src/dev.cc
        src/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显示摄像头,RK3568学习笔记,笔记

如有侵权,或需要完整代码,请及时联系博主。文章来源地址https://www.toymoban.com/news/detail-792686.html

到了这里,关于RK3568笔记九: DRM显示摄像头的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • RK3568-android11-适配ov13850摄像头

    参考链接 相关概念 相关接口 相关协议 图像格式

    2024年02月09日
    浏览(53)
  • rk3568mipi摄像头调试(gc2385 + gc2053)

    RK3568平台仅有一个标准物理mipi csi2 dphy,可以工作在full mode 和split mode两个模式, 拆分为csi2_dphy0/csi2_dphy1/csi2_dphy2三个逻辑dphy Full Mode: 仅使用csi2_dphy0,csi2_dphy0与csi2_dphy1/csi2_dphy2互斥,不可同时使用; data lane最大4 lanes; 最大速率2.5Gbps/lane; Split Mode: 仅使用csi2_dphy1和csi2_dphy2, 与csi2_dph

    2024年02月16日
    浏览(36)
  • RK3568 android11 调试mipi摄像头 gc2093

    GC2093是一个高质量的1080P CMOS图像传感器,用于安全相机产品、数码相机产品和手机相机应用程序。包含了一个1920H x 1080V像素阵列、片上10位ADC和图像信号处理器。高性能和低功耗功能的全面集成使GC2093最适合设计,减少了实现过程,并延长了运动相机、汽车DVR和各种移动应用

    2024年01月17日
    浏览(49)
  • RK3568平台开发系列讲解(视频篇)摄像头采集视频的相关配置

    🚀返回专栏总目录 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 Android 平台的摄像头的采集核心部分都是在 Native 层构建的,所以这就会涉及 JNI 层的一些转换操作。 要想使用 Android 平台提供的摄像头,必须在配置文件里添加权限要求。

    2023年04月08日
    浏览(41)
  • RK3568 android11 移植 v4l2loopback 虚拟摄像头

    v4l2loopback是一个Linux内核模块,它允许用户创建虚拟视频设备。这种虚拟视频设备可以用于各种用途,例如将实际摄像头的视频流复制到虚拟设备上,或者用于视频流的处理和分析等。v4l2loopback的主要作用是 创建一个虚拟的Video4Linux2设备,它可以接收来自其他应用程序的视频

    2024年01月19日
    浏览(49)
  • yolov5-6.0项目部署+自用Pytorch模型转换rknn模型并在RK3568 linux(Debian)平台上使用qt部署使用NPU推理加速摄像头目标识别详细新手教程

    1 我们打开yolov的官网,Tags选择6.0版本 2. 下载该压缩包并解压到工程目录下 3. 我们这里使用pycharm,专门针对python的IDE,用起来非常方便,下载方式就是官网直接下载,用的是社区版 4. 我们需要安装环境,这里我推荐安装Anaconda在电脑上,这是一个非常方便的包管理工具,可

    2024年02月05日
    浏览(52)
  • ZYNQ学习——(摄像头_VDMA_HDMI显示工程搭建)

    工程结构: 设置完毕zynq核以后,先搭建读取DDR部分,即摄像头显示: 开始加入PS部分: 1.新建vitis文件夹后,导出硬件信息到此文件夹,lunch vitis打开vitis软件,新建project。 2. 在src文件夹下新建main.c文件 3.在vivado中查看DDR3中AXI_HPO高速总线对应的地址为0x0000_0000到0x0FFF_FFFF,其

    2024年02月05日
    浏览(27)
  • RK平台USB摄像头FAQ

    (记录android9以后调试所遇到的常见问题,有错请批评指正)         UVC全称为USB video(device) class,是微软与另外几家设备厂商联合推出的为usb视频捕获设备定义的协议标准;所以说UVC仅仅是usb规范协议中设备类规范的其中一种,是用作usb接口的视频设备的一个统一的数据

    2023年04月20日
    浏览(38)
  • K210学习笔记(六):摄像头的应用

    在学习了利用lcd显示固定文件的照片之后。我们知道的是手上的这块K210开发板还集成了一枚摄像头模块,因此我们就可以利用摄像头模块捕捉照片并且实时的显示在板载lcd显示屏和IDE上,我们知道视频实际上由一帧一帧的照片组成,所以我们只需要让摄像头不断地拍照片,然

    2024年02月12日
    浏览(47)
  • 迅为RK3588开发板-基于瑞芯微RK3588摄像头方案

    硬件: RK3588开发板+摄像头   MIPI摄像头:   1.1 硬件连接 RK3588 底板上有四个摄像头接口,如下图所示,此四个接口均可连接摄像头 ov5695 和 摄像头 ov13850。   摄像头模块连接硬件时要将模块对准插槽缺口处,J1 接口连接摄像头模块如下图所示:   J2 接口连接摄像头模块

    2024年02月09日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包