前天机芯部门给了我一个mipi的摄像头,让我接到rv1126上看看能不能抓到图。这个感觉简单啊,而且我们的摄像头都不需要配置寄存器。
这个摄像头参数:raw8,2lanes,512*192,25fps
复制一份imx291的代码直接修改,改完之后测试
测试方法如下:
v4l2-ctl -d /dev/video0 --set-fmt-video=width=512,height=192,pixelformat=BG12 --stream-mmap=3 --stream-to=/tmp/bg12.bin --stream-count=1 --stream-poll
执行发现,没有抓到数据也没有timeout,直接退出了。
dmesg发现出现了如下一条信息
rkcif_mipi_lvds: crop size is bigger than input
这部分代码如下:
rkcif_start_streaming() -> rkcif_sanity_check_fmt(stream, NULL)
static int rkcif_sanity_check_fmt(struct rkcif_stream *stream,
const struct v4l2_rect *s_crop)
{
struct rkcif_device *dev = stream->cifdev;
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
struct v4l2_rect input, *crop;
stream->cif_fmt_in = get_input_fmt(dev->active_sensor->sd,
&input, stream->id + 1);
if (!stream->cif_fmt_in) {
v4l2_err(v4l2_dev, "Input fmt is invalid\n");
return -EINVAL;
}
if (s_crop)
crop = (struct v4l2_rect *)s_crop;
else
crop = &stream->crop[CROP_SRC_ACT];
if (crop->width + crop->left > input.width ||
crop->height + crop->top > input.height) {
v4l2_err(v4l2_dev, "crop size is bigger than input\n");
return -EINVAL;
}
...
}
看代码可以知道input.width及heigth小于crop的width或者heigth
于是去找crop的赋值代码
rkcif_stream_init()
#define RKCIF_DEFAULT_WIDTH 640
#define RKCIF_DEFAULT_HEIGHT 480
void rkcif_stream_init(struct rkcif_device *dev, u32 id)
{
...
for (i = 0; i < CROP_SRC_MAX; i++) {
stream->crop[i].left = 0;
stream->crop[i].top = 0;
stream->crop[i].width = RKCIF_DEFAULT_WIDTH;
stream->crop[i].height = RKCIF_DEFAULT_HEIGHT;
}
...
}
于是一顿修改
#define RKCIF_DEFAULT_WIDTH 480
#define RKCIF_DEFAULT_HEIGHT 120
v4l2-ctl可以正常跑了,于是这件事也就扔到脑后了....
时间来到今天,最近一直在学习v4l2,于是建了一个群讨论v4l2相关问题。
问题的起源是:
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080 ...
v4l2-ctl -d /dev/video0 --set-fmt-video=width=720,height=480 ...
这2条命令设置的分辨率不同,但是抓到的图的大小相同,都是1080p的大小,于是开始分析
首先开启log,抓取v4l2-ctl过程中的ioctl的调用
echo 3 > /sys/class/video4linux/video0/dev_debug
可以看到如下log
720*480
1920*1080
可以看到sizeimage都是4147200,这就导致了抓到的数据大小都一样。
看到这里就知道下一步去看对应代码
rkcif_set_fmt() -> rkcif_sync_crop_info()
static void rkcif_sync_crop_info(struct rkcif_stream *stream)
{
struct rkcif_device *dev = stream->cifdev;
struct v4l2_subdev_selection input_sel;
int ret;
if (dev->terminal_sensor.sd) {
input_sel.target = V4L2_SEL_TGT_CROP_BOUNDS;
ret = v4l2_subdev_call(dev->terminal_sensor.sd,
pad, get_selection, NULL,
&input_sel);
if (!ret) {
stream->crop[CROP_SRC_SENSOR] = input_sel.r;
stream->crop_enable = true;
stream->crop_mask |= CROP_SRC_SENSOR_MASK;
dev->terminal_sensor.selection = input_sel;
} else {
dev->terminal_sensor.selection.r = dev->terminal_sensor.raw_rect;
}
}
stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_SENSOR];
...
}
讨论的问题驱动代码有这个get_selection,里面将input_sel.r.width = 1920,input_sel.r.height = 1080
这里导致了v4l2-ctl修改分辨率,但是抓图数据大小不变。
其实到这里就可以停下了,但是由于之前阅读代码的时候跳过了crop这些代码,所以这里打算再追一下,
于是发现
.vidioc_s_crop = rkcif_s_crop,
.vidioc_g_crop = rkcif_g_crop,
.vidioc_s_selection = rkcif_s_selection,
.vidioc_g_selection = rkcif_g_selection,
这几个ioctl中都有对crop的操作,于是就想到v4l2-ctl是不是支持直接设置?
v4l2-ctl -h
可以看到一条这样的信息
--help-selection crop/selection options
于是
4l2-ctl --help-selection
打印如下
Selection/Cropping options:
--get-cropcap query the crop capabilities [VIDIOC_CROPCAP]
--get-crop query the video capture crop window [VIDIOC_G_CROP]
--set-crop top=,left=,width=,height=
set the video capture crop window [VIDIOC_S_CROP]
--get-cropcap-output
query crop capabilities for video output [VIDIOC_CROPCAP]
--get-crop-output query the video output crop window [VIDIOC_G_CROP]
--set-crop-output top=,left=,width=,height=
set the video output crop window [VIDIOC_S_CROP]
--get-cropcap-overlay
query crop capabilities for video overlay [VIDIOC_CROPCAP]
--get-crop-overlay query the video overlay crop window [VIDIOC_G_CROP]
--set-crop-overlay top=,left=,width=,height=
set the video overlay crop window [VIDIOC_S_CROP]
--get-cropcap-output-overlay
query the crop capabilities for video output overlays
[VIDIOC_CROPCAP]
--get-crop-output-overlay
query the video output overlay crop window [VIDIOC_G_CROP]
--set-crop-output-overlay top=,left=,width=,height=
set the video output overlay crop window [VIDIOC_S_CROP]
--get-selection target=
query the video capture selection rectangle [VIDIOC_G_SELECTION]
See --set-selection command for the valid values.
--set-selection target=,flags=,top=,left=,width=,height=
set the video capture selection rectangle [VIDIOC_S_SELECTION]
target=crop|crop_bounds|crop_default|compose|compose_bounds|
compose_default|compose_padded|native_size
flags=le|ge|keep-config
--get-selection-output target=
query the video output selection rectangle [VIDIOC_G_SELECTION]
See --set-selection command for the valid values.
--set-selection-output target=,flags=,top=,left=,width=,height=
set the video output selection rectangle [VIDIOC_S_SELECTION]
See --set-selection command for the arguments.
ok,现在可以这样操作
[root@RV1126_RV1109:/]#v4l2-ctl -d /dev/video0 --get-crop
Crop: Left 0, Top 0, Width 1920, Height 1080
[root@RV1126_RV1109:/]#v4l2-ctl -d /dev/video0 --set-crop top=0,left=0,width=720,heigth=480
[root@RV1126_RV1109:/]#v4l2-ctl -d /dev/video0 --get-crop
Crop: Left 0, Top 0, Width 720, Height 480
用v4l2-ctl测试
v4l2-ctl -d /dev/video0 --set-fmt-video=width=720,height=480 ...
发现抓到的数据大小没有问题了。
故事结束了,后面就开始分析具体的代码,看看是如何实现的