野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 219|回复: 0

[求助] imx6ull + ov2640 + LCD 的视频流显示问题

[复制链接]
发表于 2024-1-9 16:21:38 | 显示全部楼层 |阅读模式
[size=15.008px]目前我使用的是IMX6ULL, 摄像头是ov2640 .
摄像头驱动和LCD驱动已经完成;
应用程序使用的是正点原子的V4l2测试程序,debug发现 ioctl(fd, VIDIOC_ENUM_FRAMESIZES,&fsize) 出错. 这一项枚举不成功,返回值是 -1 ;
  1. # ./a.out /dev/video0
  2. width =480,height= 272
  3. 枚举成功0
  4. 枚举成功1
  5. 枚举成功2
  6. 枚举成功3
  7. format<0x56595559>, description<YUYV-16>
  8. ret = -1
  9. Inappropriate ioctl for device
  10. format<0x59565955>, description<UYVY-16>
  11. ret = -1
  12. Inappropriate ioctl for device
  13. format<0x50424752>, description<RGB565_BE>
  14. ret = -1
  15. Inappropriate ioctl for device
  16. format<0x50424752>, description<RGB565_LE>
  17. ret = -1
  18. Inappropriate ioctl for device
  19. v4l2_set_format : width =480,height=272
  20. RGB565设置成功
  21. 视频帧大小<640 * 480>
复制代码
[size=15.008px]应用层代码如下:
  1. /***************************************************************
  2. Copyright © ALIENTEK Co., Ltd. 1998-2021. All rights reserved.
  3. 文件名 : v4l2_camera.c
  4. 作者 : 邓涛
  5. 版本 : V1.0
  6. 描述 : V4L2摄像头应用编程实战
  7. 其他 : 无
  8. 论坛 : www.openedv.com
  9. 日志 : 初版 V1.0 2021/7/09 邓涛创建
  10. ***************************************************************/

  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <fcntl.h>
  16. #include <unistd.h>
  17. #include <sys/ioctl.h>
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <sys/mman.h>
  21. #include <linux/videodev2.h>
  22. #include <linux/fb.h>

  23. #define FB_DEV              "/dev/fb0"      //LCD设备节点
  24. #define FRAMEBUFFER_COUNT   10               //帧缓冲数量

  25. /*** 摄像头像素格式及其描述信息 ***/
  26. typedef struct camera_format {
  27.     unsigned char description[32];  //字符串描述信息
  28.     unsigned int pixelformat;       //像素格式
  29. } cam_fmt;

  30. /*** 描述一个帧缓冲的信息 ***/
  31. typedef struct cam_buf_info {
  32.     unsigned short *start;      //帧缓冲起始地址
  33.     unsigned long length;       //帧缓冲长度
  34. } cam_buf_info;

  35. static int width;                       //LCD宽度
  36. static int height;                      //LCD高度
  37. static unsigned short *screen_base = NULL;//LCD显存基地址
  38. static int fb_fd = -1;                  //LCD设备文件描述符
  39. static int v4l2_fd = -1;                //摄像头设备文件描述符
  40. static cam_buf_info buf_infos[FRAMEBUFFER_COUNT];
  41. static cam_fmt cam_fmts[10];
  42. static int frm_width, frm_height;   //视频帧宽度和高度

  43. static int fb_dev_init(void)
  44. {
  45.     struct fb_var_screeninfo fb_var = {0};
  46.     struct fb_fix_screeninfo fb_fix = {0};
  47.     unsigned long screen_size;

  48.     /* 打开framebuffer设备 */
  49.     fb_fd = open(FB_DEV, O_RDWR);
  50.     if (0 > fb_fd) {
  51.         fprintf(stderr, "open error: %s: %s\n", FB_DEV, strerror(errno));
  52.         return -1;
  53.     }

  54.     /* 获取framebuffer设备信息 */
  55.     ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var);
  56.     ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix);

  57.     screen_size = fb_fix.line_length * fb_var.yres * 8;
  58.     width = fb_var.xres;
  59.     height = fb_var.yres;
  60.     printf("width =%d,height= %d\n",width,height) ;
  61.     /* 内存映射 */
  62.     screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
  63.     if (MAP_FAILED == (void *)screen_base) {
  64.         perror("mmap error");
  65.         close(fb_fd);
  66.         return -1;
  67.     }

  68.     /* LCD背景刷白 */
  69.     memset(screen_base, 0xFF, screen_size);
  70.     return 0;
  71. }

  72. static int v4l2_dev_init(const char *device)
  73. {
  74.     struct v4l2_capability cap = {0};

  75.     /* 打开摄像头 */
  76.     v4l2_fd = open(device, O_RDWR);
  77.     if (0 > v4l2_fd) {
  78.         fprintf(stderr, "open error: %s: %s\n", device, strerror(errno));
  79.         return -1;
  80.     }

  81.     /* 查询设备功能 */
  82.     ioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap);

  83.     /* 判断是否是视频采集设备 */
  84.     if (!(V4L2_CAP_VIDEO_CAPTURE & cap.capabilities)) {
  85.         fprintf(stderr, "Error: %s: No capture video device!\n", device);
  86.         close(v4l2_fd);
  87.         return -1;
  88.     }

  89.     return 0;
  90. }

  91. static void v4l2_enum_formats(void)
  92. {
  93.     struct v4l2_fmtdesc fmtdesc = {0};

  94.     /* 枚举摄像头所支持的所有像素格式以及描述信息 */
  95.     fmtdesc.index = 0;
  96.     fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  97.     while (0 == ioctl(v4l2_fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
  98.         printf("枚举成功%d\n",fmtdesc.index) ;
  99.         // 将枚举出来的格式以及描述信息存放在数组中
  100.         cam_fmts[fmtdesc.index].pixelformat = fmtdesc.pixelformat;
  101.         strcpy(cam_fmts[fmtdesc.index].description, fmtdesc.description);
  102.         fmtdesc.index++;
  103.     }
  104. }

  105. static void v4l2_print_formats(void)
  106. {
  107.     struct v4l2_frmsizeenum frmsize = {0};
  108.     struct v4l2_frmivalenum frmival = {0};
  109.     int i;
  110.     int ret = 0 ;
  111.     frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  112.     frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  113.     for (i = 0; cam_fmts[i].pixelformat; i++) {

  114.         printf("format<0x%x>, description<%s>\n", cam_fmts[i].pixelformat,
  115.                     cam_fmts[i].description);

  116.         /* 枚举出摄像头所支持的所有视频采集分辨率 */
  117.         frmsize.index = 0;
  118.         frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
  119.         frmsize.pixel_format = cam_fmts[i].pixelformat;
  120.         frmival.pixel_format = cam_fmts[i].pixelformat;

  121.         printf("ret = %d\n",ret= ioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) )  ;
  122.         if(ret < 0)
  123.             fprintf(stderr, "%s\n", strerror(errno));

  124.         while ( ret>= 0 ) {
  125.             printf("LQB\n");
  126.             printf("size<%d*%d> ",
  127.                     frmsize.discrete.width,
  128.                     frmsize.discrete.height);
  129.             frmsize.index++;

  130.             /* 获取摄像头视频采集帧率 */
  131.             frmival.index = 0;
  132.             frmival.width = frmsize.discrete.width;
  133.             frmival.height = frmsize.discrete.height;
  134.             while (0 == ioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival)) {

  135.                 printf("<%dfps>", frmival.discrete.denominator /
  136.                         frmival.discrete.numerator);
  137.                 frmival.index++;
  138.             }
  139.         }
  140.     }
  141. }

  142. static int v4l2_set_format(void)
  143. {
  144.     struct v4l2_format fmt = {0};
  145.     struct v4l2_streamparm streamparm = {0};

  146.     /* 设置帧格式 */
  147.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//type类型
  148.     fmt.fmt.pix.width = width;  //视频帧宽度
  149.     fmt.fmt.pix.height = height;//视频帧高度
  150.     printf("v4l2_set_format : width =%d,height=%d\n",width,height) ;
  151.     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565;  //像素格式
  152.     if (0 > ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt)) {
  153.         fprintf(stderr, "ioctl error: VIDIOC_S_FMT: %s\n", strerror(errno));
  154.         return -1;
  155.     }
  156.     /*** 判断是否已经设置为我们要求的RGB565像素格式
  157.     如果没有设置成功表示该设备不支持RGB565像素格式 */
  158.     if (V4L2_PIX_FMT_RGB565 != fmt.fmt.pix.pixelformat) {
  159.         fprintf(stderr, "Error: the device does not support RGB565 format!\n");
  160.         return -1;
  161.     }
  162.     else
  163.         printf("RGB565设置成功\n");
  164.     frm_width = fmt.fmt.pix.width;  //获取实际的帧宽度
  165.     frm_height = fmt.fmt.pix.height;//获取实际的帧高度
  166.     printf("视频帧大小<%d * %d>\n", frm_width, frm_height);

  167.     /* 获取streamparm */
  168.     streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  169.     ioctl(v4l2_fd, VIDIOC_G_PARM, &streamparm);

  170.     /** 判断是否支持帧率设置 **/
  171.     if (V4L2_CAP_TIMEPERFRAME & streamparm.parm.capture.capability) {
  172.         streamparm.parm.capture.timeperframe.numerator = 1;
  173.         streamparm.parm.capture.timeperframe.denominator = 30;//30fps
  174.         if (0 > ioctl(v4l2_fd, VIDIOC_S_PARM, &streamparm)) {
  175.             fprintf(stderr, "ioctl error: VIDIOC_S_PARM: %s\n", strerror(errno));
  176.             return -1;
  177.         }
  178.     }

  179.     return 0;
  180. }

  181. static int v4l2_init_buffer(void)
  182. {
  183.     struct v4l2_requestbuffers reqbuf = {0};
  184.     struct v4l2_buffer buf = {0};

  185.     /* 申请帧缓冲 */
  186.     reqbuf.count = FRAMEBUFFER_COUNT;       //帧缓冲的数量
  187.     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  188.     reqbuf.memory = V4L2_MEMORY_MMAP;
  189.     if (0 > ioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf)) {
  190.         fprintf(stderr, "ioctl error: VIDIOC_REQBUFS: %s\n", strerror(errno));
  191.         return -1;
  192.     }

  193.     /* 建立内存映射 */
  194.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  195.     buf.memory = V4L2_MEMORY_MMAP;
  196.     for (buf.index = 0; buf.index < FRAMEBUFFER_COUNT; buf.index++) {

  197.         ioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf);
  198.         buf_infos[buf.index].length = buf.length;
  199.         buf_infos[buf.index].start = mmap(NULL, buf.length,
  200.                 PROT_READ | PROT_WRITE, MAP_SHARED,
  201.                 v4l2_fd, buf.m.offset);
  202.         if (MAP_FAILED == buf_infos[buf.index].start) {
  203.             perror("mmap error");
  204.             return -1;
  205.         }
  206.     }

  207.     /* 入队 */
  208.     for (buf.index = 0; buf.index < FRAMEBUFFER_COUNT; buf.index++) {

  209.         if (0 > ioctl(v4l2_fd, VIDIOC_QBUF, &buf)) {
  210.             fprintf(stderr, "ioctl error: VIDIOC_QBUF: %s\n", strerror(errno));
  211.             return -1;
  212.         }
  213.     }

  214.     return 0;
  215. }

  216. static int v4l2_stream_on(void)
  217. {
  218.     /* 打开摄像头、摄像头开始采集数据 */
  219.     enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  220.     if (0 > ioctl(v4l2_fd, VIDIOC_STREAMON, &type)) {
  221.         fprintf(stderr, "ioctl error: VIDIOC_STREAMON: %s\n", strerror(errno));
  222.         return -1;
  223.     }

  224.     return 0;
  225. }

  226. static void v4l2_read_data(void)
  227. {
  228.     struct v4l2_buffer buf = {0};
  229.     unsigned short *base;
  230.     unsigned short *start;
  231.     int min_w, min_h;
  232.     int j;

  233.     if (width > frm_width)
  234.         min_w = frm_width;
  235.     else
  236.         min_w = width;
  237.     if (height > frm_height)
  238.         min_h = frm_height;
  239.     else
  240.         min_h = height;

  241.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  242.     buf.memory = V4L2_MEMORY_MMAP;
  243.     for ( ; ; ) {

  244.         for(buf.index = 0; buf.index < FRAMEBUFFER_COUNT; buf.index++) {

  245.             ioctl(v4l2_fd, VIDIOC_DQBUF, &buf);     //出队
  246.             for (j = 0, base=screen_base, start=buf_infos[buf.index].start;
  247.                         j < min_h; j++) {

  248.                 memcpy(base, start, min_w * 2); //RGB565 一个像素占2个字节
  249.                 base += width;  //LCD显示指向下一行
  250.                 start += frm_width;//指向下一行数据
  251.             }

  252.             // 数据处理完之后、再入队、往复
  253.             ioctl(v4l2_fd, VIDIOC_QBUF, &buf);
  254.         }
  255.     }
  256. }

  257. int main(int argc, char *argv[])
  258. {
  259.     if (2 != argc) {
  260.         fprintf(stderr, "Usage: %s <video_dev>\n", argv[0]);
  261.         exit(EXIT_FAILURE);
  262.     }

  263.     /* 初始化LCD */
  264.     if (fb_dev_init())
  265.         exit(EXIT_FAILURE);

  266.     /* 初始化摄像头 */
  267.     if (v4l2_dev_init(argv[1]))
  268.         exit(EXIT_FAILURE);

  269.     /* 枚举所有格式并打印摄像头支持的分辨率及帧率 */
  270.     v4l2_enum_formats();
  271.     v4l2_print_formats();

  272.     /* 设置格式 */
  273.     if (v4l2_set_format())
  274.         exit(EXIT_FAILURE);

  275.     /* 初始化帧缓冲:申请、内存映射、入队 */
  276.     if (v4l2_init_buffer())
  277.         exit(EXIT_FAILURE);

  278.     /* 开启视频采集 */
  279.     if (v4l2_stream_on())
  280.         exit(EXIT_FAILURE);

  281.     /* 读取数据:出队 */
  282.     v4l2_read_data();       //在函数内循环采集数据、将其显示到LCD屏

  283.     exit(EXIT_SUCCESS);
  284. }
复制代码
[size=15.008px] 2.jpg



回复

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-5-2 02:55 , Processed in 0.125268 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表