免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2851 | 回复: 0
打印 上一主题 下一主题

linux v4l 编程(6) V4L 采集和显示区域的设置 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-22 08:51 |只看该作者 |倒序浏览
Andrew Huang <bluedrum@163.com> 转载请注明作者及联络方式

 V4L2驱动里,对于采集和显示的驱动有少许复杂.有多个地方出现对长,宽的参数,但其含义不近相同.

  比如要在硬件支持 640*480采集的摄像头,如果想在4.3"(482*280)的LCD显示,要如何处理?

一.硬件的采集区域,裁剪和缩放

 第一个是硬件采集的区域.这里涉及三个的ioctl命令,
 VIDIOC_CROPCAP : 查询驱动采集区域的缺省值,最大值。从驱动代码来看,如果当前值小于最大值,即是硬件部分截取相关区域。它使用如下数据结构 struct v4l2_cropcap
  
  1. struct v4l2_rect {
  2.     __s32 left;
  3.     __s32 top;
  4.     __s32 width;
  5.     __s32 height;
  6. };

  7. struct v4l2_fract {
  8.     __u32 numerator;
  9.     __u32 denominator;
  10. };

  11.   struct v4l2_cropcap {
  12.     enum v4l2_buf_type type;
  13.     struct v4l2_rect bounds;
  14.     struct v4l2_rect defrect;
  15.     struct v4l2_fract pixelaspect;
  16. };
 其中 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,这个比较复杂,
  
三.实现代码
 
以下代码直接来于v4l2的文档 http://v4l2spec.byte***.org/spec/x1904.htm
  3.1 重设采样区域为缺省值
   
  1. struct v4l2_cropcap cropcap;
  2. struct v4l2_crop crop;

  3. memset (&cropcap, 0, sizeof (cropcap));
  4. cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  5. if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
  6.         perror ("VIDIOC_CROPCAP");
  7.         exit (EXIT_FAILURE);
  8. }

  9. memset (&crop, 0, sizeof (crop));
  10. crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  11. crop.c = cropcap.defrect;

  12. /* Ignore if cropping is not supported (EINVAL). */

  13. if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop)
  14.     && errno != EINVAL) {
  15.         perror ("VIDIOC_S_CROP");
  16.         exit (EXIT_FAILURE);
  17. }
  
按比例缩小图像,下例中,最终输出采集区域一半。

  1. struct v4l2_cropcap cropcap;
  2. struct v4l2_format format;

  3. reset_cropping_parameters ();

  4. /* Scale down to 1/4 size of full picture. */

  5. memset (&format, 0, sizeof (format)); /* defaults */

  6. format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  7. format.fmt.pix.width = cropcap.defrect.width >> 1;
  8. format.fmt.pix.height = cropcap.defrect.height >> 1;
  9. format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;

  10. if (-1 == ioctl (fd, VIDIOC_S_FMT, &format)) {
  11.         perror ("VIDIOC_S_FORMAT");
  12.         exit (EXIT_FAILURE);
  13. }
 
设定采集区域 ,下例将从最大区域的中心采集原来尺寸一半的区域。

  1. struct v4l2_cropcap cropcap;
  2. struct v4l2_crop crop;

  3. memset (&cropcap, 0, sizeof (cropcap));
  4. cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;

  5. if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
  6.         perror ("VIDIOC_CROPCAP");
  7.         exit (EXIT_FAILURE);
  8. }

  9. memset (&crop, 0, sizeof (crop));

  10. crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
  11. crop.c = cropcap.defrect;

  12. /* Scale the width and height to 50 % of their original size
  13.    and center the output. */

  14. crop.c.width /= 2;
  15. crop.c.height /= 2;
  16. crop.c.left += crop.c.width / 2;
  17. crop.c.top += crop.c.height / 2;

  18. /* Ignore if cropping is not supported (EINVAL). */

  19. if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop)
  20.     && errno != EINVAL) {
  21.         perror ("VIDIOC_S_CROP");
  22.         exit (EXIT_FAILURE);
  23. }

调整长宽比的缩放。
  1. struct v4l2_cropcap cropcap;
  2. struct v4l2_crop crop;
  3. struct v4l2_format format;
  4. double hscale, vscale;
  5. double aspect;
  6. int dwidth, dheight;

  7. memset (&cropcap, 0, sizeof (cropcap));
  8. cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  9. if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
  10.         perror ("VIDIOC_CROPCAP");
  11.         exit (EXIT_FAILURE);
  12. }

  13. memset (&crop, 0, sizeof (crop));
  14. crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  15. if (-1 == ioctl (fd, VIDIOC_G_CROP, &crop)) {
  16.         if (errno != EINVAL) {
  17.                 perror ("VIDIOC_G_CROP");
  18.                 exit (EXIT_FAILURE);
  19.         }

  20.         /* Cropping not supported. */
  21.         crop.c = cropcap.defrect;
  22. }

  23. memset (&format, 0, sizeof (format));
  24. format.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  25. if (-1 == ioctl (fd, VIDIOC_G_FMT, &format)) {
  26.         perror ("VIDIOC_G_FMT");
  27.         exit (EXIT_FAILURE);
  28. }

  29. /* The scaling applied by the driver. */

  30. hscale = format.fmt.pix.width / (double) crop.c.width;
  31. vscale = format.fmt.pix.height / (double) crop.c.height;

  32. aspect = cropcap.pixelaspect.numerator /
  33.          (double) cropcap.pixelaspect.denominator;
  34. aspect = aspect * hscale / vscale;

  35. /* Devices following ITU-R BT.601 do not capture
  36.    square pixels. For playback on a computer monitor
  37.    we should scale the images to this size. */

  38. dwidth = format.fmt.pix.width / aspect;
  39. dheight = format.fmt.pix.height;

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP