1.整体框图
(1)所选SOC为瑞芯微RK3566,或者rv1126,图像信号处理为ISP21,Sensor为imx219 或者 ar0144
2.图像数据流拓扑
(1)驱动程序有 4 个视频设备:
rkisp1_mainpath:用于检索图像的捕获设备,通常具有更高的分辨率。
rkisp1_selfpath:用于检索图像的捕获设备。
rkisp1_stats:发送统计数据的元数据捕获设备。
rkisp1_params:从用户空间接收参数配置的元数据输出设备。
(2)驱动程序有 3 个子设备:
rkisp1_resizer_mainpath:用于调整主路径捕获设备的帧大小和下采样帧。
rkisp1_resizer_selfpath:用于为自路径捕获设备调整帧大小和下采样帧。
rkisp1_isp:与传感器相连,负责所有的isp操作。
3.图像数据链路层
(1)链路图
(2)如果mainpath没有开通需要开通(比如rv1126平台没有开通)
4.根据链路层修改sensor、subdev、isp分辨率
(1)subdev
void setSubdev(int w,int h,const char *node_path)
{
int subdev_fd = 0;
subdev_fd = open(node_path, O_RDWR , 0); // set sensor
if(-1 == subdev_fd)
{
ERR("open v4l-subdev3 fail \n");
}
struct v4l2_subdev_format subfmt;
subfmt.pad = 0;
subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
subfmt.format.width = w;
subfmt.format.height = h;
DBG("---%s:set subdev: w:%d h:%d \n",__FUNCTION__,w,h);
if (-1 == ioctl(subdev_fd,VIDIOC_SUBDEV_S_FMT, &subfmt))
{
ERR("VIDIOC_SUBDEV_S_FMT");
exit(EXIT_FAILURE);
}
if (-1 == ioctl(subdev_fd,VIDIOC_SUBDEV_G_FMT, &subfmt))
{
ERR("VIDIOC_SUBDEV_G_FMT");
exit(EXIT_FAILURE);
}
DBG("---%s:VIDIOC_SUBDEV_G_FMT: w:%d h:%d \n",__FUNCTION__,subfmt.format.width,subfmt.format.height);
close(subdev_fd);
}
(2)sensor
void setSensor(int w,int h,const char *node_path)
{
int sensor_fd = 0;
sensor_fd = open(node_path, O_RDWR , 0);
if(-1 == sensor_fd)
{
ERR("open /dev/video0 fail \n");
}
struct v4l2_crop video_crop;
video_crop.c.left = 0;
video_crop.c.top = 0;
video_crop.c.width = w;
video_crop.c.height = h;
if (-1 == ioctl(sensor_fd,VIDIOC_S_CROP, &video_crop))
{
ERR("VIDIOC_S_CROP");
exit(EXIT_FAILURE);
}
if (-1 == ioctl(sensor_fd,VIDIOC_G_CROP, &video_crop))
{
ERR("VIDIOC_G_CROP");
exit(EXIT_FAILURE);
}
DBG("---%s:VIDIOC_G_CROP: w:%d h:%d \n",__FUNCTION__,video_crop.c.width,video_crop.c.height);
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix.width = w;
fmt.fmt.pix.height = h;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;//V4L2_PIX_FMT_YUV420
if (-1 == ioctl(sensor_fd, VIDIOC_S_FMT, &fmt))//set image format
{
ERR("VIDIOC_S_FMT");
exit(EXIT_FAILURE);
}
if (-1 == ioctl(sensor_fd, VIDIOC_G_FMT, &fmt))//get image format
{
ERR("VIDIOC_G_FMT");
exit(EXIT_FAILURE);
}
DBG("---%s:VIDIOC_G_FMT: w:%d h:%d \n",__FUNCTION__,fmt.fmt.pix.width,fmt.fmt.pix.height);
close(sensor_fd);
}
(3)isp
void setIsp(int w,int h,const char *node_path)
{
int ispdev_fd = 0;
ispdev_fd = open(node_path, O_RDWR , 0);
if(-1 == ispdev_fd)
{
ERR("open v4l-subdev0 fail \n");
}
struct v4l2_subdev_format subfmt;
subfmt.pad = 0;
subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
subfmt.format.width = w;
subfmt.format.height = h;
struct v4l2_subdev_selection subsel;
subsel.r.left = 0;
subsel.r.top = 0;
subsel.r.width = w;
subsel.r.height = h;
subsel.target = V4L2_SEL_TGT_CROP;
subsel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
/* change fmt&size for RKISP1_ISP_PAD_SINK */
subfmt.pad = 0;//RKISP1_ISP_PAD_SINK;
subsel.pad = 0;//RKISP1_ISP_PAD_SINK;
if (-1 == ioctl(ispdev_fd,VIDIOC_SUBDEV_S_FMT, &subfmt))
{
ERR("VIDIOC_SUBDEV_S_FMT");
exit(EXIT_FAILURE);
}
if (-1 == ioctl(ispdev_fd,VIDIOC_SUBDEV_S_SELECTION, &subsel))
{
ERR("VIDIOC_SUBDEV_S_SELECTION");
exit(EXIT_FAILURE);
}
subfmt.pad = 2;//RKISP1_ISP_PAD_SOURCE_PATH;
subsel.pad = 2;//RKISP1_ISP_PAD_SOURCE_PATH;
if (-1 == ioctl(ispdev_fd,VIDIOC_SUBDEV_S_FMT, &subfmt))
{
ERR("VIDIOC_SUBDEV_S_FMT");
exit(EXIT_FAILURE);
}
if (-1 == ioctl(ispdev_fd,VIDIOC_SUBDEV_S_SELECTION, &subsel))
{
ERR("VIDIOC_SUBDEV_S_SELECTION");
exit(EXIT_FAILURE);
}
close(ispdev_fd);
}
(4)测试
int main(void)
{
int w = 1280;
int h = 800;
printf("Please inpu W and h:\n");
scanf("%d %d",&w,&h);
while((getchar())!='\n');
setSubdev(w,h,"/dev/v4l-subdev3"); //source pad0
setIsp(w,h,"/dev/v4l-subdev0"); //Sink pad0, source pad2
setSensor(w,h,"/dev/video0");
return 0;
}