RKMedia
的核心思想是把各个硬件资源独立成模块,模块开放出输入和输出端通过绑定的方式控制流从某个模块流出并且流入另外一个模块
目前 rk 平台可以支持的摄像头数据 yuv 和 raw 数据。 Raw 数据是没有经过 isp 信号处理的原始数据,需要 rk 芯片内部 isp 图像处理才能还原真实图像。 Yuv 数据是 camera 端的 isp 经过处理后送出来的数据。
代码目录:external/rkmedia/examples/
本文以rkmedia_vi_vo_test.c为例,还有许多的例程,大家可以自行研究。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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 RK_CHAR optstr[] = "?::a::I:M:";
static const struct option long_options[] = {
{"aiq", optional_argument, NULL, 'a'},
{"camid", required_argument, NULL, 'I'},
{"multictx", required_argument, NULL, 'M'},
{"help", optional_argument, NULL, '?'},
{NULL, 0, NULL, 0},
};
static void print_usage(const RK_CHAR *name) {
printf("usage example:\n");
#ifdef RKAIQ
printf("\t%s [-a [iqfiles_dir]]"
"[-I 0] "
"[-M 0] "
"\n",
name);
printf("\t-a | --aiq: enable aiq with dirpath provided, eg:-a "
"/oem/etc/iqfiles/, "
"set dirpath empty to using path by default, without this option aiq "
"should run in other application\n");
printf("\t-M | --multictx: switch of multictx in isp, set 0 to disable, set "
"1 to enable. Default: 0\n");
#else
printf("\t%s [-I 0]\n", name);
#endif
printf("\t-I | --camid: camera ctx id, Default 0\n");
}
int main(int argc, char *argv[]) {
int ret = 0;
int video_width = 400;
int video_height = 400;
int disp_width = 720;
int disp_height = 1280;
RK_S32 s32CamId = 0;
#ifdef RKAIQ
RK_BOOL bMultictx = RK_FALSE;
#endif
int c;
char *iq_file_dir = NULL;
while ((c = getopt_long(argc, argv, optstr, long_options, NULL)) != -1) {
const char *tmp_optarg = optarg;
switch (c) {
case 'a':
if (!optarg && NULL != argv[optind] && '-' != argv[optind][0]) {
tmp_optarg = argv[optind++];
}
if (tmp_optarg) {
iq_file_dir = (char *)tmp_optarg;
} else {
iq_file_dir = "/oem/etc/iqfiles";
}
break;
case 'I':
s32CamId = atoi(optarg);
break;
#ifdef RKAIQ
case 'M':
if (atoi(optarg)) {
bMultictx = RK_TRUE;
}
break;
#endif
case '?':
default:
print_usage(argv[0]);
return 0;
}
}
printf("#zcy CameraIdx: %d\n\n", s32CamId);
if (iq_file_dir) {
#ifdef RKAIQ
printf("#Rkaiq XML DirPath: %s\n", iq_file_dir);
printf("#bMultictx: %d\n\n", bMultictx);
rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
int fps = 30;
SAMPLE_COMM_ISP_Init(s32CamId, hdr_mode, bMultictx, iq_file_dir);
SAMPLE_COMM_ISP_Run(s32CamId);
SAMPLE_COMM_ISP_SetFrameRate(s32CamId, fps);
#endif
}
RK_MPI_SYS_Init();
VI_CHN_ATTR_S vi_chn_attr;
vi_chn_attr.pcVideoNode = "rkispp_scale0";
vi_chn_attr.u32BufCnt = 3;
vi_chn_attr.u32Width = video_width;
vi_chn_attr.u32Height = video_height;
vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;
vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
ret = RK_MPI_VI_SetChnAttr(s32CamId, 0, &vi_chn_attr);
ret |= RK_MPI_VI_EnableChn(s32CamId, 0);
if (ret) {
printf("Create vi[0] failed! ret=%d\n", ret);
return -1;
}
/* test rgn cover */
COVER_INFO_S CoverInfo;
OSD_REGION_INFO_S RngInfo;
memset(&CoverInfo, 0, sizeof(CoverInfo));
memset(&RngInfo, 0, sizeof(RngInfo));
CoverInfo.enPixelFormat = PIXEL_FORMAT_ARGB_8888;
CoverInfo.u32Color = 0xFFFF0000; // blue
RngInfo.enRegionId = REGION_ID_0;
RngInfo.u32PosX = 0;
RngInfo.u32PosY = 0;
RngInfo.u32Width = 100;
RngInfo.u32Height = 100;
RngInfo.u8Enable = 1;
RK_MPI_VI_RGN_SetCover(s32CamId, 1, &RngInfo, &CoverInfo);
// rga0 for primary plane
RGA_ATTR_S stRgaAttr;
memset(&stRgaAttr, 0, sizeof(stRgaAttr));
stRgaAttr.bEnBufPool = RK_TRUE;
stRgaAttr.u16BufPoolCnt = 3;
stRgaAttr.u16Rotaion = 90;
stRgaAttr.stImgIn.u32X = 0;
stRgaAttr.stImgIn.u32Y = 0;
stRgaAttr.stImgIn.imgType = IMAGE_TYPE_NV12;
stRgaAttr.stImgIn.u32Width = video_width;
stRgaAttr.stImgIn.u32Height = video_height;
stRgaAttr.stImgIn.u32HorStride = video_width;
stRgaAttr.stImgIn.u32VirStride = video_height;
stRgaAttr.stImgOut.u32X = 0;
stRgaAttr.stImgOut.u32Y = 0;
stRgaAttr.stImgOut.imgType = IMAGE_TYPE_RGB888;
stRgaAttr.stImgOut.u32Width = disp_width;
stRgaAttr.stImgOut.u32Height = disp_height;
stRgaAttr.stImgOut.u32HorStride = disp_width;
stRgaAttr.stImgOut.u32VirStride = disp_height;
ret = RK_MPI_RGA_CreateChn(0, &stRgaAttr);
if (ret) {
printf("Create rga[0] falied! ret=%d\n", ret);
return -1;
}
VO_CHN_ATTR_S stVoAttr = {0};
// VO[0] for primary plane
stVoAttr.pcDevNode = "/dev/dri/card0";
stVoAttr.emPlaneType = VO_PLANE_PRIMARY;
stVoAttr.enImgType = IMAGE_TYPE_RGB888;
stVoAttr.u16Zpos = 0;
stVoAttr.stDispRect.s32X = 0;
stVoAttr.stDispRect.s32Y = 0;
stVoAttr.stDispRect.u32Width = disp_width;
stVoAttr.stDispRect.u32Height = disp_height;
ret = RK_MPI_VO_CreateChn(0, &stVoAttr);
if (ret) {
printf("Create vo[0] failed! ret=%d\n", ret);
return -1;
}
MPP_CHN_S stSrcChn = {0};
MPP_CHN_S stDestChn = {0};
printf("#Bind VI[0] to RGA[0]....\n");
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = RK_ID_RGA;
stDestChn.s32ChnId = 0;
ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if (ret) {
printf("Bind vi[0] to rga[0] failed! ret=%d\n", ret);
return -1;
}
printf("# Bind RGA[0] to VO[0]....\n");
stSrcChn.enModId = RK_ID_RGA;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = RK_ID_VO;
stDestChn.s32ChnId = 0;
ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if (ret) {
printf("Bind rga[0] to vo[0] failed! ret=%d\n", ret);
return -1;
}
printf("%s initial finish\n", __func__);
signal(SIGINT, sigterm_handler);
while (!quit) {
usleep(500000);
}
printf("%s exit!\n", __func__);
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = RK_ID_RGA;
stDestChn.s32ChnId = 0;
ret = RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
if (ret) {
printf("UnBind vi[0] to rga[0] failed! ret=%d\n", ret);
return -1;
}
stSrcChn.enModId = RK_ID_RGA;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = RK_ID_VO;
stDestChn.s32ChnId = 0;
ret = RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
if (ret) {
printf("UnBind rga[0] to vo[0] failed! ret=%d\n", ret);
return -1;
}
RK_MPI_VO_DestroyChn(0);
RK_MPI_RGA_DestroyChn(0);
RK_MPI_VI_DisableChn(s32CamId, 0);
if (iq_file_dir) {
#ifdef RKAIQ
SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
}
return 0;
}
具体地解释一下代码的功能。
查看图像的stride,图像的stride(跨度、跨距、步长、步幅),表示在内存中每行像素所占的字节数。
在RKMedia下,设置采集的图像的宽度能被16整除,且stride=图像的宽度即可!
即:400x400
图像buffer宽度 = stride宽度
stride宽度 / 16 = 整数n
1.不能在开启ispserver服务的时候又指定 iqfiles,会报错,两者存在冲突,二者选其一。
1)查看ispserver服务是否已经开启了:
ps -aux | grep ispserver
2)开启ispserver服务:
ispserver --no-sync-db & // 表示不开启数据库服务dbserver
// 或者
ispserver &
3)关闭ispserver服务:
kill -9 3050
2.如果开启了摄像头应用(mediaserver),请先将其关闭后才可以使用RKMedia抓取图片。
开启和关闭mediaserver的脚本在开发板的/oem目录下:
// 开启摄像头应用(mediaserver)
/oem/RkLunch.sh &
// 关闭摄像头应用(mediaserver)
/oem/RkLunch-stop.sh