前言

  1. 刚接触RK平台,目前正在学习探索阶段,欢迎朋友们一起讨论,指出文章错误和可以优化的地方;
  2. 如果想参照文中描述进行编译、执行程序,请先参考阅读rv1126 SDK编译和rv1126 数据流;

版本说明,测试使用SDK版本是2020-0912版本,文中记录的问题,可能在新版本已经解决;文中使用的接口函数,可能老版本没有实现。
备注:后续重新购买了2020-1212版本SDK,旋转问题已经解决,不需要再修改源码。另外,编译时,需要多带上如下几个库:-lrknn_runtime -lod_share -lrockx -lOpenVX -lVSC -lGAL -lArchModelSw -lNNArchPerf


代码

直接上代码,代码将同一帧图像数据,利用RK平台的RGA功能,分别对图像进行了格式转换、缩放+旋转+格式转换、裁剪+格式转换,得到3路图像输出,并存储成文件。
代码是参考SDK包rv1126_1109/external/rkmedia/test/c_api/rkmedia_vi_rga_test.c修改而成。
说明:

  1. 编译后,执行可能遇到旋转效果无法实现,可以参考后续说明的方法修改;
  2. RK平台提供的接口,缩放图的长宽应该是要16的倍数,如果参照rv1126_1109/external/rkmedia/test/c_api/rkmedia_vi_rga_test.c里缩放输出960x540,会发现存储得到的图像数据有异常。修改输出尺寸为960x544后正常;
// 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"
#include "rkmedia_venc.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_%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_1 = 1;//RGA_CHN rga_chn_0 = 0;RGA_CHN rga_chn_1 = 1;RGA_CHN rga_chn_2 = 2;// 初始化mpi sysRK_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_1, &vi_chn_attr);ret |= RK_MPI_VI_EnableChn(vi_pipe_0, vi_chn_1);if (ret){printf("Create vi[%d] failed! ret=%d\n", vi_chn_1, ret);return -1;}//// 源数据配置//MPP_CHN_S stSrcChn;stSrcChn.enModId = RK_ID_VI;stSrcChn.s32DevId = vi_pipe_0;stSrcChn.s32ChnId = vi_chn_1;//// 输出-0// 格式转换 IMAGE_TYPE_NV12 -> IMAGE_TYPE_YUV420P//RGA_ATTR_S stRgaAttr_0;stRgaAttr_0.bEnBufPool = RK_TRUE;stRgaAttr_0.u16BufPoolCnt = 4;stRgaAttr_0.u16Rotaion = 0;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_YUV420P;stRgaAttr_0.stImgOut.u32Width = 1920;stRgaAttr_0.stImgOut.u32Height = 1080;stRgaAttr_0.stImgOut.u32HorStride = 1920;stRgaAttr_0.stImgOut.u32VirStride = 1080;//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_0;}pthread_t read_thread_0;pthread_create(&read_thread_0, NULL, GetMediaBuffer, &rga_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, &stDestChn_0);if (ret){printf("Bind vi[1] and rga[%d] failed! ret=%d\n", rga_chn_0, ret);goto EXIT_1;}//// 输出-1// 旋转 270 度// 缩放 1920 -> 960// 缩放 1080 -> 544// 格式转换 IMAGE_TYPE_NV12 -> IMAGE_TYPE_YUV420P//RGA_ATTR_S stRgaAttr_1;stRgaAttr_1.bEnBufPool = RK_TRUE;stRgaAttr_1.u16BufPoolCnt = 4;stRgaAttr_1.u16Rotaion = 270;stRgaAttr_1.stImgIn.u32X = 0;stRgaAttr_1.stImgIn.u32Y = 0;stRgaAttr_1.stImgIn.imgType = IMAGE_TYPE_NV12;stRgaAttr_1.stImgIn.u32Width = 1920;stRgaAttr_1.stImgIn.u32Height = 1080;stRgaAttr_1.stImgIn.u32HorStride = 1920;stRgaAttr_1.stImgIn.u32VirStride = 1080;stRgaAttr_1.stImgOut.u32X = 0;stRgaAttr_1.stImgOut.u32Y = 0;stRgaAttr_1.stImgOut.imgType = IMAGE_TYPE_YUV420P;stRgaAttr_1.stImgOut.u32Width = 544;stRgaAttr_1.stImgOut.u32Height = 960;stRgaAttr_1.stImgOut.u32HorStride = 544;stRgaAttr_1.stImgOut.u32VirStride = 960;//ret = RK_MPI_RGA_CreateChn(rga_chn_1, &stRgaAttr_1);if (ret){printf("Create rga[%d] falied! ret=%d\n", rga_chn_1, ret);goto EXIT_2;}pthread_t read_thread_1;pthread_create(&read_thread_1, NULL, GetMediaBuffer, &rga_chn_1);//MPP_CHN_S stDestChn_1;stDestChn_1.enModId = RK_ID_RGA;stDestChn_1.s32DevId = 0;stDestChn_1.s32ChnId = rga_chn_1;//ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn_1);if (ret){printf("Bind vi[1] and rga[%d] failed! ret=%d\n", rga_chn_1, ret);goto EXIT_3;}//// 输出-2// 裁剪 1920 -> 1000, 取中间部分// 裁剪 1080 -> 800, 取中间部分// 格式转换 IMAGE_TYPE_NV12 -> IMAGE_TYPE_YUV420P//RGA_ATTR_S stRgaAttr_2;stRgaAttr_2.bEnBufPool = RK_TRUE;stRgaAttr_2.u16BufPoolCnt = 4;stRgaAttr_2.u16Rotaion = 0;stRgaAttr_2.stImgIn.u32X = 460;stRgaAttr_2.stImgIn.u32Y = 140;stRgaAttr_2.stImgIn.imgType = IMAGE_TYPE_NV12;stRgaAttr_2.stImgIn.u32Width = 1000;stRgaAttr_2.stImgIn.u32Height = 800;stRgaAttr_2.stImgIn.u32HorStride = 1920;stRgaAttr_2.stImgIn.u32VirStride = 1080;stRgaAttr_2.stImgOut.u32X = 0;stRgaAttr_2.stImgOut.u32Y = 0;stRgaAttr_2.stImgOut.imgType = IMAGE_TYPE_YUV420P;stRgaAttr_2.stImgOut.u32Width = 1000;stRgaAttr_2.stImgOut.u32Height = 800;stRgaAttr_2.stImgOut.u32HorStride = 1000;stRgaAttr_2.stImgOut.u32VirStride = 800;//ret = RK_MPI_RGA_CreateChn(rga_chn_2, &stRgaAttr_2);if (ret){printf("Create rga[%d] falied! ret=%d\n", rga_chn_2, ret);goto EXIT_4;}pthread_t read_thread_2;pthread_create(&read_thread_2, NULL, GetMediaBuffer, &rga_chn_2);//MPP_CHN_S stDestChn_2;stDestChn_2.enModId = RK_ID_RGA;stDestChn_2.s32DevId = 0;stDestChn_2.s32ChnId = rga_chn_2;//ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn_2);if (ret){printf("Bind vi[1] and rga[%d] failed! ret=%d\n", rga_chn_2, ret);goto EXIT_5;}//// 监听退出信号//printf("%s initial finish\n", __func__);signal(SIGINT, sigterm_handler);//// 等待退出信号while (!quit){usleep(100);}//// 退出//ret = 0;EXIT_6:RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn_2);
EXIT_5:RK_MPI_RGA_DestroyChn(rga_chn_2);
EXIT_4:RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn_1);
EXIT_3:RK_MPI_RGA_DestroyChn(rga_chn_1);
EXIT_2:RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn_0);
EXIT_1:RK_MPI_RGA_DestroyChn(rga_chn_0);
EXIT_0:RK_MPI_VI_DisableChn(vi_pipe_0, vi_chn_1);return ret;
}

如果已经完成SDK包的编译,可以参考如下编译该源码:

arm-linux-gnueabihf-gcc -I/home/user/work/sdk/rv1126_1109/external/rkmedia/include/rkmedia -L/home/user/work/sdk/rv1126_1109/buildroot/output/rockchip_rv1126_rv1109/staging/usr/lib -o rkmedia_vi_get_frame_test rkmedia_vi_get_frame_test.c -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

执行的部分输出如下。可以看到图像数据的时间戳是同一个,个人感觉应该可以说明图像输入的源为同一帧图像。

Get Frame-chn-0:ptr:0xa1d2a000, fd:13, size:3133440, mode:16, channel:0, timestamp:3698073427
Get Frame-chn-1:ptr:0xa1100000, fd:18, size:783360, mode:16, channel:1, timestamp:3698073427
Get Frame-chn-2:ptr:0xa026c000, fd:23, size:1209600, mode:16, channel:2, timestamp:3698073427Get Frame-chn-0:ptr:0xa2612000, fd:10, size:3133440, mode:16, channel:0, timestamp:3698106734
Get Frame-chn-1:ptr:0xa1340000, fd:15, size:783360, mode:16, channel:1, timestamp:3698106734
Get Frame-chn-2:ptr:0xa05db000, fd:20, size:1209600, mode:16, channel:2, timestamp:3698106734Get Frame-chn-0:ptr:0xa231a000, fd:11, size:3133440, mode:16, channel:0, timestamp:3698140083
Get Frame-chn-1:ptr:0xa1280000, fd:16, size:783360, mode:16, channel:1, timestamp:3698140083
Get Frame-chn-2:ptr:0xa04b6000, fd:21, size:1209600, mode:16, channel:2, timestamp:3698140083

旋转功能处理

在刚开始测试时,发现无论如何配置旋转参数,输出的图像都无法实现旋转,于是查看了一下rkmedia的源码。在rv1126_1109/external/rkmedia/src/c_api/rkmedia_api.cc文件中发现了一些蹊跷,RK_S32 RK_MPI_RGA_CreateChn(RGA_CHN RgaChn, RGA_ATTR_S *pstRgaAttr)函数里对输入的旋转参数进行校验后,就把他遗忘了,后续再也没有给他出场的机会:

  RK_U16 u16Rotaion = pstRgaAttr->u16Rotaion;if ((u16Rotaion != 0) && (u16Rotaion != 90) && (u16Rotaion != 180) &&(u16Rotaion != 270)) {LOG("ERROR: %s rotation only support: 0/90/180/270!\n", __func__);return -RK_ERR_RGA_ILLEGAL_PARAM;}

所以,对以下源码进行了修改,大概在2373行:

  // org code: // PARAM_STRING_APPEND_TO(filter_param, KEY_BUFFER_ROTATE, 0);// modify code: PARAM_STRING_APPEND_TO(filter_param, KEY_BUFFER_ROTATE, u16Rotaion);

修改后,参考rv1126 SDK编译,删除buildroot/output/rockchip_rv1126_rv1109/build/rkmedia目录,再重新编译,将新编译得到的buildroot/output/rockchip_rv1126_rv1109/staging/usr/lib/libeasymedia.so.1.0.1文件,替换单板上/usr/lib/libeasymedia.so.1.0.1。替换后,重新执行测试程序,旋转功能正常。
出现这个问题,可能是因为我的SDK包是某宝上买的吧。

rv1126 获取图像数据,实现图像裁剪、缩放、旋转【RK_MPI API接口】相关推荐

  1. R语言使用magick包的image_rotate函数、image_flip函数、image_flop函数对图像进行缩放旋转、镜像、翻转(Rotate or mirror the image)

    R语言使用magick包的image_rotate函数.image_flip函数.image_flop函数对图像进行缩放旋转.镜像.翻转(Rotate or mirror the image) 目录

  2. 建筑市场数据(四库一平台)API接口开放

    全国建筑市场监管平台(四库一平台)[http://jzsc.mohurd.gov.cn]已经关闭的老板,现在对数据采集的要求原来越高.经过自己的学习和整理发布的一个建筑市场数据(四库一平台)API接口 ...

  3. koa 接口返回数据_koa+node基础搭建到实现api接口

    初始koa koa是一个新的web框架,基于nodejs平台,koa没有捆绑任何中间件,而是提供了一套优雅的函数库,帮助您快速而愉快的编写服务端应用程序. 一个demo带你了解koa

  4. 最新最全的免费股票数据接口--沪深A股深度分析财务分析数据API接口(十一)

    沪深深度分析数据API文档 数据来源:麦蕊智数 请求方式:Get(直接在浏览器打开就可以看到返回的数据) 数据格式:标准Json格式[{},...{}] 数据时效:实时更新 API说明文档:https ...

  5. 【免费股票数据接口|实测可用|史上最全】沪深A股实时交易数据数据API接口

    沪深A股基础实时数据API 数据来源:麦蕊智数 请求方式:Get(直接在浏览器打开就可以看到返回的数据) 数据格式:标准Json格式[{},...{}] 数据时效:实时更新 API说明文档:https ...

  6. 最新最全的免费股票数据接口--沪深A股基础列表数据API接口(三)

    沪深A股基础实时数据API 数据来源:麦蕊智数 请求方式:Get(直接在浏览器打开就可以看到返回的数据) 数据格式:标准Json格式[{},...{}] 数据时效:实时更新 API说明文档:https ...

  7. 最新最全的免费股票数据接口--沪深A股深度分析龙虎榜数据API接口(九)

    沪深深度分析数据API文档 数据来源:麦蕊智数 请求方式:Get(直接在浏览器打开就可以看到返回的数据) 数据格式:标准Json格式[{},...{}] 数据时效:实时更新 API说明文档:https ...

  8. 最新最全的免费股票数据接口--沪深A股基本面数据API接口(四)

    沪深A股基础实时数据API 数据来源:麦蕊智数 请求方式:Get(直接在浏览器打开就可以看到返回的数据) 数据格式:标准Json格式[{},...{}] 数据时效:实时更新 API说明文档:https ...

  9. 拼多多商品数据如何通过api接口获取

    要从拼多多获取商品数据,可以使用拼多多提供的API接口.首先需要注册一个拼多多开放平台的开发者账号,然后创建一个应用程序,获取应用程序的app_id和app_secret,以在API请求中进行身份验证 ...

最新文章

  1. java 拉姆表达式_Java8 lambda表达式10个示例
  2. Android ViewModel详解
  3. jvm(2)-java内存区域
  4. nginx python cgi_Python的CGIHTTPServer交互实现详解
  5. struts配置通配符*来匹配方法,实现动态调用
  6. “龙书”作者斩获图灵奖!谷歌 AI 大神、Swift 之父都受它启蒙
  7. 用VS2008做博客¥(^_^)¥
  8. ie8不支持console.log()的解决方法
  9. dateformat java 并发_SimpleDateFormat并发隐患及其解决
  10. Masonry 在swift下的使用
  11. hdu 6096 String(AC自动机巧妙建图)
  12. Center OS 7
  13. 几种路由器、WIFI网络中无线中继、无线桥接WDS的信号扩展、增强
  14. 抖音网页版上线:这回可以在电脑上刷抖音啦!
  15. 为什么我们要用密码生成器?
  16. muti-thread fork
  17. adb发送什么命令能在手机屏幕弹窗显示_将平板、手机作为电脑第二屏幕(Linux系统下)...
  18. 倍福--授权等级的区别
  19. MFC中关于char[]转换成LPCWSTR的问题
  20. 【管理者】精读德鲁克教授《卓有成效的管理者》(一)

热门文章

  1. JDK 8 - computeIfAbsent,computeIfPresent,compute
  2. 视频直播推流技术(MediaCodec硬编码+libRTMP,编码器),Demo - Android
  3. 防火墙与入侵检测系统
  4. 基于nginx tomcat redis分布式web应用的session共享配置
  5. 基于SSH开发service电子信箱(邮箱)管理系统
  6. Enhancement
  7. lol云顶之奕助手_LOL云顶之弈助手app下载-LOL云顶之弈助手官网版下载v1.1.2-FC游戏网...
  8. keepalive (1)
  9. 几张图看懂区块链是什么?
  10. elementUI table表格合并相同的内容