本章描述rkmedia vp模块 即视频一入四处功能的介绍。
使用场景:主要用在DVR/DMS产品上,需要多路视频节点的输入和获取。
可以rv1126/rv1109可以外接模拟高清RX芯片(NVP6188,TP2815等),达到8路camera输入的能力。
在rga部分也有提及过,rv1126/rv1109只有一个硬件rga,所以工作能力有限,在dvr这种产品中需要多路视频的缩放,使用rga的话就无法达到需求。vp就可以解决视频分辨率缩放的功能,缓解rga的压力。
vp实际上就是使用RK平台上ispp模块,实现一个视频数据从rkispp_input_image节点对应的video节点输入,四个视频数据从rkispp_m_bypass、rkispp_scale0、rkispp_scale1、rkispp_scale2节点对应video输出。。这样四个输出的节点中rkispp_scale0、rkispp_scale1、rkispp_scale2是具有缩放能力的。
使用方式:
因为我是使用的evb板,默认ispp0已经打开,也在使用。所以我用ispp1来做讲解。在实际使用时,你们的ispp可能都没有使用,所以可以从ispp0开始使用。
1、在dts文件中打开ispp1
* 1. add code to kernel dts:
&rkispp_vir1 {
status = "okay";
};
在dts里面打开ispp1后,重新编译kernel,烧录到开发板。启动后会在/dev/ 生成新的media节点
2、检查新的media节点所对应的video号,使用media-ctl -p -d 查看
[root@RV1126_RV1109:/userdata]# ls /dev/media
media0 media1 media2 media3
[root@RV1126_RV1109:/userdata]# media-ctl -p -d /dev/media3
Media controller API version 4.19.111
Media device information
------------------------
driver rkispp
model rkispp1
serial
bus info
hw revision 0x0
driver version 4.19.111
Device topology
- entity 1: rkispp_input_image (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video25
pad0: Source
-> "rkispp-subdev":0 [ENABLED]
- entity 5: rkispp_m_bypass (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video26
pad0: Sink
<- "rkispp-subdev":2 [ENABLED]
- entity 9: rkispp_scale0 (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video27
pad0: Sink
<- "rkispp-subdev":2 [ENABLED]
- entity 13: rkispp_scale1 (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video28
pad0: Sink
<- "rkispp-subdev":2 [ENABLED]
- entity 17: rkispp_scale2 (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video29
pad0: Sink
<- "rkispp-subdev":2 [ENABLED]
- entity 21: rkispp_iqtool (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video30
pad0: Sink
<- "rkispp-subdev":2 [ENABLED]
- entity 25: rkispp_input_params (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video31
pad0: Source
-> "rkispp-subdev":1 [ENABLED]
- entity 29: rkispp-stats (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video32
pad0: Sink
<- "rkispp-subdev":3 [ENABLED]
- entity 33: rkispp-subdev (4 pads, 8 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev1
pad0: Sink
[fmt:unknown/0x0
crop.bounds:(0,0)/0x0
crop:(0,0)/0x0
compose.bounds:(0,0)/0x0
compose:(0,0)/0x0]
<- "rkispp_input_image":0 [ENABLED]
pad1: Sink
<- "rkispp_input_params":0 [ENABLED]
pad2: Source
[fmt:unknown/0x0]
-> "rkispp_m_bypass":0 [ENABLED]
-> "rkispp_scale0":0 [ENABLED]
-> "rkispp_scale1":0 [ENABLED]
-> "rkispp_scale2":0 [ENABLED]
-> "rkispp_iqtool":0 [ENABLED]
pad3: Source
-> "rkispp-stats":0 [ENABLED]
[root@RV1126_RV1109:/userdata]#
如上所示,在打开ispp1的时候,会多出一个media3。使用命令查看media3的拓扑结构。
rkispp_input_image | video25 |
rkispp_m_bypass | video26 |
rkispp_scale0 | video27 |
rkispp_scale1 | video28 |
rkispp_scale2 | video29 |
3、配置media节点
media-ctl -d /dev/media3 -l '"rkispp_input_image":0->"rkispp-subdev":0[1]'
media-ctl -d /dev/media3 --set-v4l2 '"rkispp-subdev":0[fmt:YUYV8_2X8/1920x1080]'
media-ctl -d /dev/media3 --set-v4l2 '"rkispp-subdev":2[fmt:YUYV8_2X8/1920x1080]'
以上是命令行执行的,在rkmedia_vi_vp_vo_test中是在代码中调用:
char cmd[256];
snprintf(
cmd, sizeof(cmd),
"media-ctl -d %s -l '\"rkispp_input_image\":0->\"rkispp-subdev\":0[1]'",
media);
system(cmd);
snprintf(cmd, sizeof(cmd),
"media-ctl -d %s --set-v4l2 "
"'\"rkispp-subdev\":0[fmt:YUYV8_2X8/1920x1080]'",
media);
system(cmd);
snprintf(cmd, sizeof(cmd),
"media-ctl -d %s --set-v4l2 "
"'\"rkispp-subdev\":2[fmt:YUYV8_2X8/1920x1080]'",
media);
system(cmd);
4、配置rkmedia vi 节点初始化。(输出的四个节点初始化要在vp之前)
int video_width = 1920;
int video_height = 1080;
int video1_width = 1920;
int video1_height = 1080;
int video2_width = 640;
int video2_height = 360;
// 先配置原始输入节点,就是用nvp6188在开发板上生成的节点
vi_chn_attr.pcVideoNode = "/dev/video0";
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;
//video0节点不支持dma申请内存,所以要配置成mmap
vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;
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;
}
//配置media3 中的rkispp_m_bypass节点video26,rkispp_scale0 video27
//我这里就先用两个输出,如需多个,就再继续初始化即可
memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
vi_chn_attr.pcVideoNode = "/dev/video26";
vi_chn_attr.u32BufCnt = 3;
vi_chn_attr.u32Width = video1_width;
vi_chn_attr.u32Height = video1_height;
vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;
vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
ret = RK_MPI_VI_SetChnAttr(2, 2, &vi_chn_attr);
ret |= RK_MPI_VI_EnableChn(2, 2);
if (ret) {
printf("Create vi[2] failed! ret=%d\n", ret);
return -1;
}
memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
vi_chn_attr.pcVideoNode = "/dev/video27";
vi_chn_attr.u32BufCnt = 3;
vi_chn_attr.u32Width = video2_width;
vi_chn_attr.u32Height = video2_height;
vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;
vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
ret = RK_MPI_VI_SetChnAttr(3, 3, &vi_chn_attr);
ret |= RK_MPI_VI_EnableChn(3, 3);
if (ret) {
printf("Create vi[3] failed! ret=%d\n", ret);
return -1;
}
//接着初始化vp,实际上就是初始化media中rkispp_input_image 节点video25
VP_CHN_ATTR_S vp_chn_attr;
vp_chn_attr.pcVideoNode = "/dev/video25";
vp_chn_attr.u32BufCnt = 3;
vp_chn_attr.u32Width = video_width;
vp_chn_attr.u32Height = video_height;
vp_chn_attr.enPixFmt = IMAGE_TYPE_NV12;
vp_chn_attr.enWorkMode = VP_WORK_MODE_NORMAL;
ret = RK_MPI_VP_SetChnAttr(0, 0, &vp_chn_attr);
ret |= RK_MPI_VP_EnableChn(0, 0);
if (ret) {
printf("Create vp[0] failed! ret=%d\n", ret);
return -1;
}
//最后就是将video0 绑定到video25, 这样video26、video27就可以像正常的video节点取流、绑定后级
MPP_CHN_S stSrcChn = {0};
MPP_CHN_S stDestChn = {0};
printf("#Bind VI[0] to VP[0]....\n");
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32ChnId = 0;
stDestChn.enModId = RK_ID_VP;
stDestChn.s32ChnId = 0;
ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if (ret) {
printf("Bind vi[0] to vp[0] failed! ret=%d\n", ret);
return -1;
}
注意点:
1、video0不支持dma申请内存
2、rkispp_m_bypass节点不支持缩放。四个节点的缩放能力可以去看我前面介绍VI模块的章节。
RKMEDIA--VI的使用_未_定的博客-CSDN博客
3、vp要放在最后初始化
以上就是一路vp的使用方式。在使用8路vp的时候基本上就是照葫芦画瓢,但是也需要改一些地方,需要修改的地方放在下面。
主要修改的是:
1、dts加上其余的ispp和配置
2、设置ispp虚拟节点的数量
3、修改v4l2节点的数量
diff --git a/arch/arm/boot/dts/rv1109-evb-ddr3-v13-facial-gate.dts b/arch/arm/boot/dts/rv1109-evb-ddr3-v13-facial-gate.dts
index 982da51..97d91931 100644
--- a/arch/arm/boot/dts/rv1109-evb-ddr3-v13-facial-gate.dts
+++ b/arch/arm/boot/dts/rv1109-evb-ddr3-v13-facial-gate.dts
@@ -30,6 +30,26 @@
+&rkispp_vir2 {
+ status = "okay";
+};
+&rkispp_vir3 {
+ status = "okay";
+};
+
+&rkispp_vir4 {
+ status = "okay";
+};
+
+&rkispp_vir5 {
+ status = "okay";
+};
+
+&rkispp_vir6 {
+ status = "okay";
+};
+
+&rkispp_vir7 {
+ status = "okay";
+};
+
&isp_reserved {
size = <0x8000000>;
};
diff --git a/arch/arm/boot/dts/rv1126.dtsi b/arch/arm/boot/dts/rv1126.dtsi
index 194f2d1..c40fc92 100644
--- a/arch/arm/boot/dts/rv1126.dtsi
+++ b/arch/arm/boot/dts/rv1126.dtsi
@@ -2115,6 +2115,36 @@
+ rkispp_vir2: rkispp-vir2 {
+ compatible = "rockchip,rv1126-rkispp-vir";
+ rockchip,hw = <&rkispp>;
+ status = "disabled";
+ };
+ rkispp_vir3: rkispp-vir3 {
+ compatible = "rockchip,rv1126-rkispp-vir";
+ rockchip,hw = <&rkispp>;
+ status = "disabled";
+ };
+
+ rkispp_vir4: rkispp-vir4 {
+ compatible = "rockchip,rv1126-rkispp-vir";
+ rockchip,hw = <&rkispp>;
+ status = "disabled";
+ };
+
+ rkispp_vir5: rkispp-vir5 {
+ compatible = "rockchip,rv1126-rkispp-vir";
+ rockchip,hw = <&rkispp>;
+ status = "disabled";
+ };
+
+ rkispp_vir6: rkispp-vir6 {
+ compatible = "rockchip,rv1126-rkispp-vir";
+ rockchip,hw = <&rkispp>;
+ status = "disabled";
+ };
+
+ rkispp_vir7: rkispp-vir7 {
+ compatible = "rockchip,rv1126-rkispp-vir";
+ rockchip,hw = <&rkispp>;
+ status = "disabled";
+ };
+
rkvdec: rkvdec@ffb80000 {
compatible = "rockchip,rkv-decoder-v1";
reg = <0xffb80000 0x400>;
diff --git a/drivers/media/platform/rockchip/isp/isp_ispp.h b/drivers/media/platform/rockchip/isp/isp_ispp.h
index 71878ca..beae6c6 100644
--- a/drivers/media/platform/rockchip/isp/isp_ispp.h
+++ b/drivers/media/platform/rockchip/isp/isp_ispp.h
@@ -34,6 +34,10 @@ enum rkisp_ispp_dev {
DEV_ID1,
DEV_ID2,
DEV_ID3,
+ DEV_ID4,
+ DEV_ID5,
+ DEV_ID6,
+ DEV_ID7,
DEV_MAX,
};
diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h
index cce6de4..83dc659 100644
--- a/lib/libv4l2/libv4l2-priv.h
+++ b/lib/libv4l2/libv4l2-priv.h
@@ -25,7 +25,7 @@
#include "../libv4lconvert/libv4lsyscall-priv.h"
-#define V4L2_MAX_DEVICES 16
+#define V4L2_MAX_DEVICES 32
/* Warning when making this larger the frame_queued and frame_mapped members of
the v4l2_dev_info struct can no longer be a bitfield, so the code needs to
be adjusted! */
diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c
index f949b5d..ab0cffc 100644
--- a/lib/libv4l2/libv4l2.c
+++ b/lib/libv4l2/libv4l2.c
@@ -96,7 +96,11 @@ static struct v4l2_dev_info devices[V4L2_MAX_DEVICES] = {
{ .fd = -1 },
{ .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
{ .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
- { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
+ { .fd = -1 }
};
static int devices_used;
以上就是vp的介绍,如有问题可在评论区探讨。
文章汇总:RKMEDIA使用简介_未_定的博客-CSDN博客