一.RGA模块概念
- RGA模块:就是处理VI模块获取的2D图像,可以裁剪、缩放、旋转、镜像、图片叠加等格式转换。可以理解为:VI模块从摄像头获取图片,通过RGA可以处理VI模块获取的的图片,然后输出成想要的样子。(VI模块相当于截图,RGA模块相当于编辑图片)
二.RGA结构体定义
1.RGA 结构体分为:RGA 区域属性结构体,RGA 属性结构体
区域属性结构体:
imgType:图像格式类型
u32X:RGA 的 X 轴坐标
u32Y:RGA 的 Y 轴坐标
u32Width:RGA 的宽度
u32Height:RGA 的高度
u32HorStride:虚宽,一般和宽度一样
u32VirStride:虚高,一般和高度一样
属性结构体:
stImgIn:输入图像信息,一般填写的是原分辨率参数。比方说 CMOS 摄像头分辨率1920*1080,则 stImgIn 分辨率就是 1920*1080
stImgOut:输出图像信息,一般填写的是原分辨率参数。比方说要输出的是 1280 * 720,stImgOut 分辨率就是 1280 * 720
u16Rotation: 旋转角度,取值范围 0, 90 ,180, 270
bEnBufPool:使能缓冲池
u16BufPoolCnt:缓冲池计数
enFlip:镜像控制,RGA_FLIP_E 具体选项如下:
三. RGA 常用的 API
1.创建 RGA 通道
第一个参数:RGA 通道号,取值范围是[0, RGA_MAX_CHN_NUM],也就是 16
第二个参数:RGA 通道属性结构体指针
2.销毁 RGA 通道
第一个参数:RGA 通道号
四.实现RGA获取数据
RV1126 VI 模块采集摄像头并通过 RGA 缩小分辨率然后保存到本地文件的流程
1.VI模块初始化
int ret;
RK_MPI_SYS_Init();//系统初始化
VI_CHN_ATTR_S vi_chn_attr;
vi_chn_attr.pcVideoNode = "rkispp_scale0";
vi_chn_attr.u32Width = 1920;
vi_chn_attr.u32Height = 1080;
vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;
vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;
vi_chn_attr.u32BufCnt = 3;
vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
//PIPE_ID是通道,相当于哪个摄像头;VI_CHN_ID是VI模块管道
ret = RK_MPI_VI_SetChnAttr(PIPE_ID, VI_CHN_ID, &vi_chn_attr);
if(ret)
{
printf("VI_CHN_ATTR Set Failed.....\n");
return -1;
}
else
{
printf("VI_CHN_ATTR Set Success.....\n");
}
ret = RK_MPI_VI_EnableChn(PIPE_ID, VI_CHN_ID);
if(ret)
{
printf("Enable_Vi Failed.....\n");
return -1;
}
else
{
printf("Enable_Vi Success.....\n");
}
ret = RK_MPI_VI_StartStream(PIPE_ID, VI_CHN_ID);
if(ret)
{
printf("Start Vi Failed.....\n");
return -1;
}
else
{
printf("Start Vi Success.....\n");
}
2.RGA模块初始化
RGA_ATTR_S rga_attr;
//先对获取数据初始化stImgIn
rga_attr.stImgIn.u32Width = 1920;
rga_attr.stImgIn.u32Height = 1080;
rga_attr.stImgIn.imgType = IMAGE_TYPE_NV12;
rga_attr.stImgIn.u32X = 0;
rga_attr.stImgIn.u32Y = 0;
rga_attr.stImgIn.u32VirStride = 1080;
rga_attr.stImgIn.u32HorStride = 1920;
//后初始化想转化成stImgOut
rga_attr.stImgOut.u32Width = 1280;
rga_attr.stImgOut.u32Height = 720;
rga_attr.stImgOut.imgType = IMAGE_TYPE_NV12;
rga_attr.stImgOut.u32X = 0;
rga_attr.stImgOut.u32Y = 0;
rga_attr.stImgOut.u32VirStride = 720;
rga_attr.stImgOut.u32HorStride = 1280;
//旋转角度为0
rga_attr.u16Rotaion = 0;
//缓冲池数为3
rga_attr.u16BufPoolCnt = 3;
//使能缓冲池
rga_attr.bEnBufPool = RK_TRUE;
//创建通道
ret = RK_MPI_RGA_CreateChn(RGA_CHN_ID, &rga_attr);
if(ret)
{
printf("RK_MPI_RGA_CreateChn Failed.....\n");
return -1;
}
else
{
printf("RK_MPI_RGA_CreateChn Success.....\n");
}
3.绑定 VI 节点和 RGA 节点
//VI通道结构体指针
MPP_CHN_S vi_chn_s;
vi_chn_s.enModId = RK_ID_VI;//模块号
vi_chn_s.s32ChnId = VI_CHN_ID;//通道号
//RGA通道结构体指针
MPP_CHN_S rga_chn_s;
rga_chn_s.enModId = RK_ID_RGA;
rga_chn_s.s32ChnId = RGA_CHN_ID;
//绑定两个模块API
ret = RK_MPI_SYS_Bind(&vi_chn_s, &rga_chn_s);
if(ret)
{
printf("RK_MPI_SYS_Bind Failed.....\n");
return -1;
}
else
{
printf("RK_MPI_SYS_Bind Success.....\n");
}
4.开启多线程采集 RGA 的数据
//main函数里面创建线程
pthread_t pid;
pthread_create(&pid, NULL, get_rga_data_thread, NULL);
void *get_rga_data_thread(void *args)
{
FILE * rga_nv12_file = fopen("vi_rga.nv12", "w+");
MEDIA_BUFFER mb;
while (1)
{
//获取RGA模块,通道,-1为不阻塞
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, RGA_CHN_ID, -1);
if(!mb)
{
printf("get_rga_buffer break....\n");
break;
}
printf("get_rga_buffer Success....\n");
fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb) ,rga_nv12_file);
RK_MPI_MB_ReleaseBuffer(mb);
}
return NULL;
}
5.释放空间
RK_MPI_VI_DisableChn(PIPE_ID, VI_CHN_ID);
RK_MPI_RGA_DestroyChn(RGA_CHN_ID);