Linux v4l2架构学习总链接
gitee源码
设置图像格式 VIDIOC_S_FMT
v4l2应用代码如下:
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(struct v4l2_format));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.width = 2400;
fmt.fmt.pix_mp.height = 1920;
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_SRGGB12;
fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
printf("Set format fail\n");
goto err;
}
printf("width = %d\n", fmt.fmt.pix_mp.width);
printf("height = %d\n", fmt.fmt.pix_mp.height);
驱动调用顺序如下:
v4l_s_fmt ->
vidioc_s_fmt_vid_cap_mplane ->
rkcif_s_fmt_vid_cap_mplane ->
rkcif_set_fmt
分析最终源码:
static void rkcif_set_fmt(struct rkcif_stream *stream,
struct v4l2_pix_format_mplane *pixm,
bool try)
{
struct rkcif_device *dev = stream->cifdev;
const struct cif_output_fmt *fmt;
struct v4l2_rect input_rect;
unsigned int imagesize = 0, planes;
u32 xsubs = 1, ysubs = 1, i;
struct rkmodule_hdr_cfg hdr_cfg;
int ret;
/* 以BG12为例,这里得到的fmt如下
* @cplanes: number of colour planes
* @mplanes: number of planes for format
* .fourcc = V4L2_PIX_FMT_SBGGR12,
* .cplanes = 1,
* .mplanes = 1,
* .bpp = { 16 },
* .raw_bpp = 12,
* .csi_fmt_val = CSI_WRDDR_TYPE_RAW12,
* .fmt_type = CIF_FMT_TYPE_RAW,
* }
*/
fmt = find_output_fmt(stream, pixm->pixelformat);
if (!fmt)
fmt = &out_fmts[0];
input_rect.width = RKCIF_DEFAULT_WIDTH;
input_rect.height = RKCIF_DEFAULT_HEIGHT;
/* 注意:
* 虽然我们传入了width和height,但是还是需要从sensor获取真实的width和height
* 防止超过实际范围
*/
if (dev->active_sensor && dev->active_sensor->sd)
get_input_fmt(dev->active_sensor->sd,
&input_rect, stream->id + 1);
/* CIF has not scale function,
* the size should not be larger than input
*/
pixm->width = clamp_t(u32, pixm->width,
CIF_MIN_WIDTH, input_rect.width);
pixm->height = clamp_t(u32, pixm->height,
CIF_MIN_HEIGHT, input_rect.height);
pixm->num_planes = fmt->mplanes;
pixm->field = V4L2_FIELD_NONE;
pixm->quantization = V4L2_QUANTIZATION_DEFAULT;
rkcif_sync_crop_info(stream);
/* calculate plane size and image size */
fcc_xysubs(fmt->fourcc, &xsubs, &ysubs);
planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes;
for (i = 0; i < planes; i++) {
struct v4l2_plane_pix_format *plane_fmt;
int width, height, bpl, size, bpp;
... ... ...
size = bpl * height;
imagesize += size;
if (fmt->mplanes > i) {
/* Set bpl and size for each mplane */
plane_fmt = pixm->plane_fmt + i;
plane_fmt->bytesperline = bpl;
plane_fmt->sizeimage = size;
}
v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
"C-Plane %i size: %d, Total imagesize: %d\n",
i, size, imagesize);
}
/* convert to non-MPLANE format.
* It's important since we want to unify non-MPLANE
* and MPLANE.
*/
/* rk的注释,意思是统一格式为non-MPLANE
*/
if (fmt->mplanes == 1)
pixm->plane_fmt[0].sizeimage = imagesize;
/* try 为 false
* stream中保存相关数据
*/
if (!try) {
stream->cif_fmt_out = fmt;
stream->pixm = *pixm;
v4l2_dbg(1, rkcif_debug, &stream->cifdev->v4l2_dev,
"%s: req(%d, %d) out(%d, %d)\n", __func__,
pixm->width, pixm->height,
stream->pixm.width, stream->pixm.height);
}
}
上面的代码删除了计算imagesize部分的代码,这里不影响分析。
以上面对代码为例,传入的是2400x1920,但是实际sensor是1280x1024,那么最终打印的也是1280x1024,也就是说S_FMT的ioctl会根据实际sensor进行修改。