http://linuxtv.org/downloads/v4l-dvb-apis/crop.html
一些视频捕捉设备可以取一张图片的小部分,然后对图片进行任意尺寸的放大或缩小。我们将这些能力称之为裁剪和缩放。一些视频使出设备可以将图片放大或缩小,然后将其插入到视频信号的任意扫描线和横向偏移中。
应用程序可以使用一下API来选择视频信号中的区域,查询默认区域以及硬件限制。不管他们的名字是什么,VIDIOC_CROPCAP VIDIOC_G_CROP VIDIOC_S_CROP ioctl都可以作用于输入及输出设备。
裁剪需要源和目标。在视频捕捉或overlay设备上源就是视频信号,然后通过裁剪ioctl决定需要裁剪的区域。目标就是程序读取的图片或overlay到物理屏幕上。他们的尺寸(overlay可选)是通过VIDIOC_G_FMT和VIDIOC_S_FMT ioctl协商决定的。
在一个视频输出设备上源是应用程序走过的图片,他们的尺寸还是通过VIDIOC_G/S_FMT ioctl协商确定的,或者也可能是编码压缩入了视频流中。目标是视频信号,且才加你ioctl决定图片插入哪个区域。
就算设备不支持裁剪或VIDIOC_G/S_FMT等ioctl源和目标矩形区域依然被定义。他们的尺寸(或许是位置)在这种情况下将不变。所有捕捉及输出设备必须支持VIDIOC_CROPCAP ioctl,这样应用程序就可以决定能否进行裁剪。
视频捕捉设备左上角,可取样区域的宽高可以通过VIDIOC_CRAOCAP ioctl返回的struct v4l2_cropcap结构体中的bound子成员结构体给出。为了兼容更广泛的硬件设备,这里不会定义起点和单位。按照惯例,驱动应该横向计算相对于0H的取样范围,竖向的是第一个区域(4.2 ITU-R 525)的ITU-R线数量。如果驱动能够捕获两个区域则乘以二。
左上角源矩形的宽高是实际能取样的区域,通过struct v4l2_crop结构体给出,坐标系统与struct v4l2_cropcap相同。应用程序可以通过使用VIDIOC_G_CROP和VIDIOC_S_CROP ioctl来获取和设置矩形区域。它必须完全在捕捉范围内,而且驱动之后可能根据硬件限制修改所请求的尺寸及(或)位置。
每个捕捉设备都有一个默认的源矩形,通过struct v4l2_cropcap结构提中的defrect成员结构体给出。矩形的中心应该与视频信号中的活跃图片区域中心对准,且涵盖驱动编写者所关心的完整图片。在驱动首次加载时,驱动就应对源矩形区域进行重置,而不是之后再做。
对于输出设备来说,这些结构体和ioctl的使用就要看情况。定义目标矩形区域即代表要把图片插入到视频信号中的哪里。
视频硬件可拥有各种裁剪、插入及缩放限制。可能只能放大或缩小,只支持离散的缩放系数,或在横向和竖向上有不同的缩放能力,也可能根本就不支持缩放。struct v4l2_crop矩形被对齐的同时,源和目标矩形可能拥有了无限制的缩放尺寸。特别是在结构体struct v4l2_crop中的最大width和height可能会比struct v4l2_cropcap.bounds区域要小。因此,惯例,驱动要对请求的参数进行调整然后返回选择的实际值。
应用程序可以首先改变源或目标的矩形区域,比如一张特殊的图片尺寸或视频信号中的明确区域。如果驱动不得不因为硬件限制进行调整,那么最后的请求是最优先的,且驱动应该倾向于调整相反的那一个。无论如何,VIDIOC_TRY_FMT ioctl不应该修改驱动状态,且只是调整所请求的矩形区域。
假设在一个视频捕捉设备上进行缩放,在每个方向上其系数为1:1或2:1,且图像尺寸必须是16 x 16像素的整数倍。源裁剪矩形区域被设置为默认,这个区域也作为此例中的上限值。640 x 400像素为偏移0,0。一个应用程序请求一张300 x 225像素的图片,假设视频会根据全图进行缩小。驱动设置图像尺寸为最接近的数值304 x 224,然后选择裁剪矩形区域为最接近请求尺寸的608 x 224(224 x 2:1会超过400的限制)。偏移0,0依然有效,因为未修改过。通过VIDIOC_CROPCAP给出的默认裁剪矩形区域,应用程序可以轻松的修改此区域中心。
现在,应用程序可以使用像素纵横比接近原始请求的图片来覆盖区域,所以它请求裁剪608 x 456像素的矩形区域。当前缩放系数限制裁剪只能到640 x 384,所以驱动返回608 x 384的裁剪尺寸,并且调整图片尺寸为最接近的304 x 192。
源和目标矩形区域在关闭和重打开一个设备时应保持不变,以至于穿梭与设备的管道数据不需要特别的准备。高级的应用程序会在开始IO操作前确认参数是否合适。
例1.10 重置裁剪参数
假设一个视频捕捉设备,为其他设备修改V4L2_BUF_TYPE_VIDEO_CAPTURE。
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);
}
例1.11 简单缩放
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);
}
例1.12 选择输出区域
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);
}
例1.13 当前缩放系数与像素纵横比
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;