Andrew Huang <bluedrum@163.com> 转载请注明作者及联络方式
V4L2驱动里,对于采集和显示的驱动有少许复杂.有多个地方出现对长,宽的参数,但其含义不近相同.
比如要在硬件支持 640*480采集的摄像头,如果想在4.3"(482*280)的LCD显示,要如何处理?
一.硬件的采集区域,裁剪和缩放
第一个是硬件采集的区域.这里涉及三个的ioctl命令, VIDIOC_CROPCAP : 查询驱动采集区域的缺省值,最大值。从驱动代码来看,如果当前值小于最大值,即是硬件部分截取相关区域。它使用如下数据结构 struct v4l2_cropcap - struct v4l2_rect {
-
__s32 left;
-
__s32 top;
-
__s32 width;
-
__s32 height;
-
};
-
-
struct v4l2_fract {
-
__u32 numerator;
-
__u32 denominator;
-
};
-
-
struct v4l2_cropcap {
-
enum v4l2_buf_type type;
-
struct v4l2_rect bounds;
-
struct v4l2_rect defrect;
-
struct v4l2_fract pixelaspect;
-
};
其中 Cropping 的本意是裁剪,相关参数是 其中bounds是最大采样区域 ,defrect是缺省采样区域,
pixelaspect 即pixel aspect (像素长度比)。 其中结构成员 numberrator即分子,demominator即分母之意。
第二是个设置当前采集区间。使用命令VIDIOC_S_CROP,它使用数据结构struct v4l2_crop 它必须少于 bounds.综合如下。
第三个是取得当前截取的区域,用VIDIOC_S_CROP,它使用数据结构struct v4l2_crop 二.最终输出区域。
最终输出即,应用程序看到输出视频的长,宽,这个也可以用VIDIOC_S_FMT来设置,如果与采集不一致,驱动应当负责缩放。 如何, 首先如果采集视频区域与最终输出区域长宽比不一致,强行进行缩放驱动可以返回一个最接近format的长度比相同的值,如果为了精确显示,可以考虑,用VIDIOC_S_CROP截取与最终输出长宽比相同的最大区域,最终进行缩放。
还有一种复杂的缩放,是调整长宽比的缩放,关健于在设定的 pixelaspect,这个比较复杂, 三.实现代码 3.1 重设采样区域为缺省值 - struct v4l2_cropcap cropcap;
-
struct v4l2_crop crop;
-
-
memset (&cropcap, 0, sizeof (cropcap));
-
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-
if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
-
perror ("VIDIOC_CROPCAP");
-
exit (EXIT_FAILURE);
-
}
-
-
memset (&crop, 0, sizeof (crop));
-
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
crop.c = cropcap.defrect;
-
-
/* Ignore if cropping is not supported (EINVAL). */
-
-
if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop)
-
&& errno != EINVAL) {
-
perror ("VIDIOC_S_CROP");
-
exit (EXIT_FAILURE);
-
}
按比例缩小图像,下例中,最终输出采集区域一半。
- struct v4l2_cropcap cropcap;
-
struct v4l2_format format;
-
-
reset_cropping_parameters ();
-
-
/* Scale down to 1/4 size of full picture. */
-
-
memset (&format, 0, sizeof (format)); /* defaults */
-
-
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-
format.fmt.pix.width = cropcap.defrect.width >> 1;
-
format.fmt.pix.height = cropcap.defrect.height >> 1;
-
format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-
-
if (-1 == ioctl (fd, VIDIOC_S_FMT, &format)) {
-
perror ("VIDIOC_S_FORMAT");
-
exit (EXIT_FAILURE);
-
}
设定采集区域 ,下例将从最大区域的中心采集原来尺寸一半的区域。
- struct v4l2_cropcap cropcap;
-
struct v4l2_crop crop;
-
-
memset (&cropcap, 0, sizeof (cropcap));
-
cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-
-
if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
-
perror ("VIDIOC_CROPCAP");
-
exit (EXIT_FAILURE);
-
}
-
-
memset (&crop, 0, sizeof (crop));
-
-
crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-
crop.c = cropcap.defrect;
-
-
/* Scale the width and height to 50 % of their original size
-
and center the output. */
-
-
crop.c.width /= 2;
-
crop.c.height /= 2;
-
crop.c.left += crop.c.width / 2;
-
crop.c.top += crop.c.height / 2;
-
-
/* Ignore if cropping is not supported (EINVAL). */
-
-
if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop)
-
&& errno != EINVAL) {
-
perror ("VIDIOC_S_CROP");
-
exit (EXIT_FAILURE);
-
}
调整长宽比的缩放。 - struct v4l2_cropcap cropcap;
-
struct v4l2_crop crop;
-
struct v4l2_format format;
-
double hscale, vscale;
-
double aspect;
-
int dwidth, dheight;
-
-
memset (&cropcap, 0, sizeof (cropcap));
-
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-
if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
-
perror ("VIDIOC_CROPCAP");
-
exit (EXIT_FAILURE);
-
}
-
-
memset (&crop, 0, sizeof (crop));
-
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-
if (-1 == ioctl (fd, VIDIOC_G_CROP, &crop)) {
-
if (errno != EINVAL) {
-
perror ("VIDIOC_G_CROP");
-
exit (EXIT_FAILURE);
-
}
-
-
/* Cropping not supported. */
-
crop.c = cropcap.defrect;
-
}
-
-
memset (&format, 0, sizeof (format));
-
format.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-
if (-1 == ioctl (fd, VIDIOC_G_FMT, &format)) {
-
perror ("VIDIOC_G_FMT");
-
exit (EXIT_FAILURE);
-
}
-
-
/* The scaling applied by the driver. */
-
-
hscale = format.fmt.pix.width / (double) crop.c.width;
-
vscale = format.fmt.pix.height / (double) crop.c.height;
-
-
aspect = cropcap.pixelaspect.numerator /
-
(double) cropcap.pixelaspect.denominator;
-
aspect = aspect * hscale / vscale;
-
-
/* Devices following ITU-R BT.601 do not capture
-
square pixels. For playback on a computer monitor
-
we should scale the images to this size. */
-
-
dwidth = format.fmt.pix.width / aspect;
-
dheight = format.fmt.pix.height;
|