1. 程式人生 > 其它 >v4l2架構專題模組crop及selection分析 --- 從一個camera測試說起

v4l2架構專題模組crop及selection分析 --- 從一個camera測試說起

Linux v4l2架構學習總連結

前天機芯部門給了我一個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=<x>,left=<y>,width=<w>,height=<h>
                     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=<x>,left=<y>,width=<w>,height=<h>
                     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=<x>,left=<y>,width=<w>,height=<h>
                     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=<x>,left=<y>,width=<w>,height=<h>
                     set the video output overlay crop window [VIDIOC_S_CROP]
  --get-selection target=<target>
                     query the video capture selection rectangle [VIDIOC_G_SELECTION]
                     See --set-selection command for the valid <target> values.
  --set-selection target=<target>,flags=<flags>,top=<x>,left=<y>,width=<w>,height=<h>
                     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=<target>
                     query the video output selection rectangle [VIDIOC_G_SELECTION]
                     See --set-selection command for the valid <target> values.
  --set-selection-output target=<target>,flags=<flags>,top=<x>,left=<y>,width=<w>,height=<h>
                     set the video output selection rectangle [VIDIOC_S_SELECTION]
                     See --set-selection command for the arguments.

ok,現在可以這樣操作

[[email protected]_RV1109:/]#v4l2-ctl -d /dev/video0 --get-crop
Crop: Left 0, Top 0, Width 1920, Height 1080

[[email protected]_RV1109:/]#v4l2-ctl -d /dev/video0 --set-crop top=0,left=0,width=720,heigth=480

[[email protected]_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 ...

發現抓到的資料大小沒有問題了。

故事結束了,後面就開始分析具體的程式碼,看看是如何實現的