rv1126 读取sensor输入,输出到屏幕显示【RK_MPI API接口】

介绍

rv1126使用libdrm作为显示操作接口。相关说明介绍参考如下:

《Rockchip_Developer_Guide_Linux_Graphics_CN.pdf》文档中,DRM介绍如下:

  • Connectors,就是屏幕,比如主控芯片通过HDMI、MIPI DSI,分别接2个屏幕显示,就会有2个对应的Connectors ID;
  • CRTCs,表示VOP,一个屏幕一般对应一个crtc;
  • Planes,就是图层,比如视频层在plane2,UI在plane1,视频在UI上面;
    在这里插入图片描述
    可以通过modetest程序查看系统当前DRM情况:
# modetest 
Encoders:
id      crtc    type    possible crtcs  possible clones
56      0       DSI     0x00000001      0x00000000

Connectors:
id      encoder status          name            size (mm)       modes   encoders
57      0       connected       DSI-1           107x172         1       56
  modes:
        name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
  800x1280 60 800 818 819 837 1280 1292 1293 1305 66000 flags: phsync, pvsync; type: preferred, driver
  props:
      ......

CRTCs:
id      fb      pos     size
54      0       (0,0)   (0x0)
   0 0 0 0 0 0 0 0 0 0 flags: ; type: 
  props:
      ......

Planes:
id      crtc    fb      CRTC x,y        x,y     gamma size      possible crtcs
53      54      61      0,0             0,0     0               0x00000001
  formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16
  props:
        9 type:
                flags: immutable enum
                enums: Overlay=0 Primary=1 Cursor=2
                value: 1
        51 FEATURE:
                flags: immutable bitmask
                values: scale=0x1 alpha=0x2 hdr2sdr=0x4 sdr2hdr=0x8 afbdc=0x10
                value: 2
55      0       0       0,0             0,0     0               0x00000001
  formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16 NV12 NV16 NV24
  props:
        9 type:
                flags: immutable enum
                enums: Overlay=0 Primary=1 Cursor=2
                value: 0
        51 FEATURE:
                flags: immutable bitmask
                values: scale=0x1 alpha=0x2 hdr2sdr=0x4 sdr2hdr=0x8 afbdc=0x10
                value: 3

Frame buffers:
id      size    pitch

上面信息表明当前系统的DRM情况:

  • Connectors,有1个,代表可以接1个屏幕输出,ID是57。该显示输出的最大分辨率是800x1280,刷新频率60hz;
  • CRTCs,有1个,ID是54;
  • Planes,有2个,代表有2个图层,ID分别是53、55。plane 53当前type值是1,代表是Primary层;plane 55当前type值是0,代表是Overlay层;

可以用指令测试屏幕输出显示:modetest -s 57@54:800x1280@RG24

  • 57,对应Connectors ID;
  • 54,对应CRTCs ID;
  • 800x1280,输出最大分辨率;
  • RG24,代表RGB888,每个像素点24bit,R/G/B各8bit;

使用RK_MPI输出

单板上是比较老的RK SDK包,新购买的2020-1212版本SDK包支持RK_MPI接口输出图像到屏幕。将新SDK包编译后,将libeasymedia.solibrga.so更新到单板即可。
编译时,lib库参数:

-lpthread -ldl -lm -lpcre -lz -lglib-2.0 -leasymedia -ldrm -lrockchip_mpp -lavformat -lavcodec -lswresample -lavutil -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment -lasound -lv4l2 -lv4lconvert -lrga -lRKAP_ANR -lRKAP_Common -lRKAP_AEC -lrknn_api -lrockface -lsqlite3 -lmd_share -lrkaiq -lssl -lcrypto -lrknn_runtime -lod_share -lrockx -lOpenVX -lVSC -lGAL -lArchModelSw -lNNArchPerf 

源码实现从sensor获取图像,输出到屏幕显示,同时将一路输入存储到文件:

// Copyright 2020 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <assert.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#include <pthread.h>

//#include "common/sample_common.h"
#include "rkmedia_api.h"

static bool quit = false;

// 信号处理程序
static void sigterm_handler(int sig)
{
    fprintf(stderr, "signal %d\n", sig);
    quit = true;
}

// 图像数据处理线程
static void *GetMediaBuffer(void *arg)
{
    RGA_CHN rga_chn = *(RGA_CHN *)arg;
    char save_path[512];

    //
    printf("#Start %s thread, rga_chn:%d\n", __func__, rga_chn);
    sprintf(save_path, "/userdata/output_vo_%d.nv12", rga_chn);
    //
    FILE *save_file = fopen(save_path, "w");
    if (!save_file)
        printf("ERROR: Open %s failed!\n", save_path);

    MEDIA_BUFFER mb = NULL;
    int save_cnt = 0;
    int recv_len;
    while (!quit)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, rga_chn, 50);
        if (!mb)
        {
            if (!quit)
            {
                continue;
            }
            printf("chn-%d:RK_MPI_SYS_GetMediaBuffer get null buffer!\n", rga_chn);
            break;
        }

        recv_len = RK_MPI_MB_GetSize(mb);
        printf("Get Frame-chn-%d:ptr:%p, fd:%d, size:%zu, mode:%d, channel:%d, "
               "timestamp:%lld\n",
               rga_chn,
               RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetFD(mb), recv_len,
               RK_MPI_MB_GetModeID(mb), RK_MPI_MB_GetChannelID(mb),
               RK_MPI_MB_GetTimestamp(mb));

        if (save_file && (save_cnt < 1))
        {
            int rtn = fwrite(RK_MPI_MB_GetPtr(mb), 1, recv_len, save_file);
            fsync(fileno(save_file));
            printf("#Save frame-chn-%d:%d to %s, rtn = %d\n", rga_chn, save_cnt, save_path, rtn);
            save_cnt++;
        }

        RK_MPI_MB_ReleaseBuffer(mb);
    }

    if (save_file)
        fclose(save_file);
    printf("%s-chn-%d - exit\r\n", __func__, rga_chn);

    return NULL;
}

//
int main()
{
    int ret = -1;
    //
    VI_PIPE vi_pipe_0 = 0;
    VI_CHN vi_chn_0 = 0;
    //
    RGA_CHN rga_chn_0 = 0;
    //
    VO_CHN vo_chn_0 = 0;

    // 初始化mpi sys
    RK_MPI_SYS_Init();

    //
    // 数据源,ISP20的输出:
    // rkispp_m_bypass, 不支持设置分辨率,不支持缩放,         NV12/NV16/YUYV/FBC0/FBC2
    // rkispp_scale0,   max width: 3264,最大支持 8 倍缩放, NV12/NV16/YUYV
    // rkispp_scale1,   max width: 1280,最大支持 8 倍缩放, NV12/NV16/YUYV
    // rkispp_scale2,   max width: 1280,最大支持 8 倍缩放, NV12/NV16/YUYV
    //
    VI_CHN_ATTR_S vi_chn_attr;
    vi_chn_attr.pcVideoNode = "rkispp_scale0";
    vi_chn_attr.u32BufCnt = 4;
    vi_chn_attr.u32Width = 1920;
    vi_chn_attr.u32Height = 1080;
    vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;
    vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
    //
    ret = RK_MPI_VI_SetChnAttr(vi_pipe_0, vi_chn_0, &vi_chn_attr);
    ret |= RK_MPI_VI_EnableChn(vi_pipe_0, vi_chn_0);
    if (ret)
    {
        printf("Create vi[%d] failed! ret=%d\n", vi_chn_0, ret);
        return -1;
    }
    printf("### Create VI DONE\r\n");

    //
    // 输出图层:
    // VO_PLANE_PRIMARY, XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16
    // VO_PLANE_OVERLAY, XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16 NV12 NV16 NV24

    //
    // 创建VO:VO_PLANE_OVERLAY
    // 全屏
    VO_CHN_ATTR_S stVoAttr_0 = {0};
    stVoAttr_0.pcDevNode = "/dev/dri/card0";
    stVoAttr_0.emPlaneType = VO_PLANE_OVERLAY;
    stVoAttr_0.enImgType = IMAGE_TYPE_NV12;
    stVoAttr_0.u16Zpos = 0;
    stVoAttr_0.stDispRect.s32X = 0;
    stVoAttr_0.stDispRect.s32Y = 0;
    stVoAttr_0.stDispRect.u32Width = 800;
    stVoAttr_0.stDispRect.u32Height = 1280;
    ret = RK_MPI_VO_CreateChn(vo_chn_0, &stVoAttr_0);
    if (ret)
    {
        goto EXIT_0;
    }
    printf("### Create VO_PLANE_OVERLAY DONE\r\n");

    //
    // 输出的RGA
    // 旋转 270 度
    // 缩放 1920 -> 1280
    // 缩放 1080 -> 800
    //
    RGA_ATTR_S stRgaAttr_0;
    stRgaAttr_0.bEnBufPool = RK_TRUE;
    stRgaAttr_0.u16BufPoolCnt = 4;
    stRgaAttr_0.u16Rotaion = 270;
    stRgaAttr_0.stImgIn.u32X = 0;
    stRgaAttr_0.stImgIn.u32Y = 0;
    stRgaAttr_0.stImgIn.imgType = IMAGE_TYPE_NV12;
    stRgaAttr_0.stImgIn.u32Width = 1920;
    stRgaAttr_0.stImgIn.u32Height = 1080;
    stRgaAttr_0.stImgIn.u32HorStride = 1920;
    stRgaAttr_0.stImgIn.u32VirStride = 1080;
    stRgaAttr_0.stImgOut.u32X = 0;
    stRgaAttr_0.stImgOut.u32Y = 0;
    stRgaAttr_0.stImgOut.imgType = IMAGE_TYPE_NV12;
    stRgaAttr_0.stImgOut.u32Width = 800;
    stRgaAttr_0.stImgOut.u32Height = 1280;
    stRgaAttr_0.stImgOut.u32HorStride = 800;
    stRgaAttr_0.stImgOut.u32VirStride = 1280;
    //
    ret = RK_MPI_RGA_CreateChn(rga_chn_0, &stRgaAttr_0);
    if (ret)
    {
        printf("Create rga[%d] falied! ret=%d\n", rga_chn_0, ret);
        goto EXIT_1;
    }
    printf("### Create RGA DONE\r\n");

    //
    // 绑定VI输入

    //
    // 绑定源数据配置
    MPP_CHN_S stSrcChn_0;
    stSrcChn_0.enModId = RK_ID_VI;
    stSrcChn_0.s32DevId = vi_pipe_0;
    stSrcChn_0.s32ChnId = vi_chn_0;

    //
    // 绑定目标数据配置
    MPP_CHN_S stDestChn_0;
    stDestChn_0.enModId = RK_ID_RGA;
    stDestChn_0.s32DevId = 0;
    stDestChn_0.s32ChnId = rga_chn_0;
    //
    ret = RK_MPI_SYS_Bind(&stSrcChn_0, &stDestChn_0);
    if (ret)
    {
        printf("Bind vi[0] and rga[%d] failed! ret=%d\n", rga_chn_0, ret);
        goto EXIT_2;
    }
    printf("### Bind VI-RGA  DONE\r\n");

    //
    // 绑定VO输出

    //
    // 绑定源数据配置
    MPP_CHN_S stSrcChn_1;
    stSrcChn_1.enModId = RK_ID_RGA;
    stSrcChn_1.s32DevId = 0;
    stSrcChn_1.s32ChnId = rga_chn_0;

    //
    // 绑定目标数据配置
    MPP_CHN_S stDestChn_1;
    stDestChn_1.enModId = RK_ID_VO;
    stDestChn_1.s32DevId = 0;
    stDestChn_1.s32ChnId = vo_chn_0;
    //
    ret = RK_MPI_SYS_Bind(&stSrcChn_1, &stDestChn_1);
    if (ret)
    {
        printf("Bind v0[0] and rga[%d] failed! ret=%d\n", rga_chn_0, ret);
        goto EXIT_3;
    }
    printf("### Bind RGA-VO  DONE\r\n");

    //
    // 顺带把VO显示的图,存储下来
    pthread_t read_thread_1;
    pthread_create(&read_thread_1, NULL, GetMediaBuffer, &rga_chn_0);

    //
    // 监听退出信号
    //
    printf("%s initial finish\n", __func__);
    signal(SIGINT, sigterm_handler);

    //
    // 等待退出信号
    while (!quit)
    {
        usleep(100);
    }

    //
    // 退出
    //
    ret = 0;

EXIT_4:
    RK_MPI_SYS_UnBind(&stSrcChn_1, &stDestChn_1);
EXIT_3:
    RK_MPI_SYS_UnBind(&stSrcChn_0, &stDestChn_0);
EXIT_2:
    RK_MPI_RGA_DestroyChn(rga_chn_0);
EXIT_1:
    RK_MPI_VO_DestroyChn(vo_chn_0);
EXIT_0:
    RK_MPI_VI_DisableChn(vi_pipe_0, vi_chn_0);

    return ret;
}
  • 11
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值