免费注册 查看新帖 |

Chinaunix

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

[驱动] 【已解决】通过V4L2采集的图片怎么无法打开?请教什么原因 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-01-23 19:02 |只看该作者 |倒序浏览
本帖最后由 Huntsmen 于 2014-01-24 08:56 编辑

在网上找的一个V4L2编程的经典例子,程序运行后,保存了2张jpg的图片,但是保存图片在windows下无法打开,想请教一下是什么原因?

PS:实验环境是arm9开发板,usb的UVC摄像头;利用开发板自带的usb摄像头测试app是能看到图像的;
[ 8802.695000] usb 1-1.2: new full-speed USB device number 3 using s3c2410-ohci
[ 8802.825000] uvcvideo: Found UVC 1.00 device USB 2.0 CAMERA (1c4f:3002)
[ 8802.890000] input: USB 2.0 CAMERA as /devices/platform/s3c2410-ohci/usb1/1-1/1-1.2/1-1.2:1.0/input/input1
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <errno.h>
  4. #include <stdlib.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <sys/mman.h>
  9. #include <assert.h>
  10. #include <linux/videodev2.h>


  11. typedef struct
  12. {
  13.         void *start;
  14.         int length;
  15. }BUFTYPE;

  16. BUFTYPE *user_buf;
  17. int n_buffer = 0;

  18. //打开摄像头设备
  19. int open_camer_device()
  20. {
  21.         int fd;

  22.         if((fd = open("/dev/video0",O_RDWR | O_NONBLOCK)) < 0)
  23.         {
  24.                 perror("Fail to open");
  25.                 exit(EXIT_FAILURE);
  26.         }
  27.        
  28.         return fd;
  29. }

  30. int init_mmap(int fd)
  31. {
  32.         int i = 0;
  33.         struct v4l2_requestbuffers reqbuf;

  34.         bzero(&reqbuf,sizeof(reqbuf));
  35.         reqbuf.count = 4;
  36.         reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  37.         reqbuf.memory = V4L2_MEMORY_MMAP;
  38.        
  39.         //申请视频缓冲区(这个缓冲区位于内核空间,需要通过mmap映射)
  40.         //这一步操作可能会修改reqbuf.count的值,修改为实际成功申请缓冲区个数
  41.         if(-1 == ioctl(fd,VIDIOC_REQBUFS,&reqbuf))
  42.         {
  43.                 perror("Fail to ioctl 'VIDIOC_REQBUFS'");
  44.                 exit(EXIT_FAILURE);
  45.         }
  46.        
  47.         n_buffer = reqbuf.count;
  48.        
  49.         printf("n_buffer = %d\n",n_buffer);

  50.         user_buf = calloc(reqbuf.count,sizeof(*user_buf));
  51.         if(user_buf == NULL){
  52.                 fprintf(stderr,"Out of memory\n");
  53.                 exit(EXIT_FAILURE);
  54.         }

  55.         //将内核缓冲区映射到用户进程空间
  56.         for(i = 0; i < reqbuf.count; i ++)
  57.         {
  58.                 struct v4l2_buffer buf;
  59.                
  60.                 bzero(&buf,sizeof(buf));
  61.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  62.                 buf.memory = V4L2_MEMORY_MMAP;
  63.                 buf.index = i;
  64.                 //查询申请到内核缓冲区的信息
  65.                 if(-1 == ioctl(fd,VIDIOC_QUERYBUF,&buf))
  66.                 {
  67.                         perror("Fail to ioctl : VIDIOC_QUERYBUF");
  68.                         exit(EXIT_FAILURE);
  69.                 }

  70.                 user_buf[i].length = buf.length;
  71.                 user_buf[i].start =
  72.                         mmap(
  73.                                         NULL,/*start anywhere*/
  74.                                         buf.length,
  75.                                         PROT_READ | PROT_WRITE,
  76.                                         MAP_SHARED,
  77.                                         fd,buf.m.offset
  78.                                 );
  79.                 if(MAP_FAILED == user_buf[i].start)
  80.                 {
  81.                         perror("Fail to mmap");
  82.                         exit(EXIT_FAILURE);
  83.                 }
  84.         }       

  85.         return 0;
  86. }

  87. //初始化视频设备
  88. int init_camer_device(int fd)
  89. {
  90.         struct v4l2_fmtdesc fmt;
  91.         struct v4l2_capability cap;
  92.         struct v4l2_format stream_fmt;
  93.         int ret;
  94.        
  95.         //当前视频设备支持的视频格式
  96.         memset(&fmt,0,sizeof(fmt));
  97.         fmt.index = 0;
  98.         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  99.         while((ret = ioctl(fd,VIDIOC_ENUM_FMT,&fmt)) == 0)
  100.         {
  101.                 fmt.index ++ ;

  102.                 printf("{pixelformat = %c%c%c%c},description = '%s'\n",
  103.                                 fmt.pixelformat & 0xff,(fmt.pixelformat >> 8)&0xff,
  104.                                 (fmt.pixelformat >> 16) & 0xff,(fmt.pixelformat >> 24)&0xff,
  105.                                 fmt.description);
  106.         }

  107.         //查询视频设备驱动的功能
  108.         ret = ioctl(fd,VIDIOC_QUERYCAP,&cap);
  109.         if(ret < 0){
  110.                 perror("FAIL to ioctl VIDIOC_QUERYCAP");
  111.                 exit(EXIT_FAILURE);
  112.         }

  113.         //判断是否是一个视频捕捉设备
  114.         if(!(cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE))
  115.         {
  116.                 printf("The Current device is not a video capture device\n");
  117.                 exit(EXIT_FAILURE);
  118.        
  119.         }

  120.         //判断是否支持视频流形式
  121.         if(!(cap.capabilities & V4L2_CAP_STREAMING))
  122.         {
  123.                 printf("The Current device does not support streaming i/o\n");
  124.                 exit(EXIT_FAILURE);
  125.         }

  126.         //设置摄像头采集数据格式,如设置采集数据的
  127.         //长,宽,图像格式(JPEG,YUYV,MJPEG等格式)
  128.         stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  129.         stream_fmt.fmt.pix.width = 640;
  130.         stream_fmt.fmt.pix.height = 480;
  131.         stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  132.         stream_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

  133.         if(-1 == ioctl(fd,VIDIOC_S_FMT,&stream_fmt))
  134.         {
  135.                 perror("Fail to ioctl");
  136.                 exit(EXIT_FAILURE);
  137.         }

  138.        
  139.         //初始化视频采集方式(mmap)
  140.         init_mmap(fd);

  141.         return 0;
  142. }

  143. int start_capturing(int fd)
  144. {
  145.         unsigned int i;
  146.         enum v4l2_buf_type type;

  147.         //将申请的内核缓冲区放入一个队列中
  148.         for(i = 0;i < n_buffer;i ++)
  149.         {
  150.                 struct v4l2_buffer buf;

  151.                 bzero(&buf,sizeof(buf));
  152.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  153.                 buf.memory = V4L2_MEMORY_MMAP;
  154.                 buf.index = i;
  155.                
  156.                 if(-1 == ioctl(fd,VIDIOC_QBUF,&buf))
  157.                 {
  158.                         perror("Fail to ioctl 'VIDIOC_QBUF'");
  159.                         exit(EXIT_FAILURE);
  160.                 }
  161.         }

  162.         //开始采集数据
  163.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  164.         if(-1 == ioctl(fd,VIDIOC_STREAMON,&type))
  165.         {
  166.                 printf("i = %d.\n",i);
  167.                 perror("Fail to ioctl 'VIDIOC_STREAMON'");
  168.                 exit(EXIT_FAILURE);
  169.         }

  170.         return 0;
  171. }

  172. //将采集好的数据放到文件中
  173. int process_image(void *addr,int length)
  174. {
  175.         FILE *fp;
  176.         static int num = 0;
  177.         char picture_name[20];
  178.        
  179.         sprintf(picture_name,"picture_%d.jpg",num ++);
  180.        
  181.         if((fp = fopen(picture_name,"w")) == NULL)
  182.         {
  183.                 perror("Fail to fopen");
  184.                 exit(EXIT_FAILURE);
  185.         }

  186.         printf("len=%d\n",length);
  187.         fwrite(addr,length,1,fp);
  188.         usleep(500);

  189.         fclose(fp);

  190.         return 0;
  191. }

  192. int read_frame(int fd)
  193. {
  194.         struct v4l2_buffer buf;
  195.         unsigned int i;

  196.         bzero(&buf,sizeof(buf));
  197.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  198.         buf.memory = V4L2_MEMORY_MMAP;
  199.        
  200.         //从队列中取缓冲区
  201.         if(-1 == ioctl(fd,VIDIOC_DQBUF,&buf))
  202.         {
  203.                 perror("Fail to ioctl 'VIDIOC_DQBUF'");
  204.                 exit(EXIT_FAILURE);
  205.         }

  206.         assert(buf.index < n_buffer);
  207.         //读取进程空间的数据到一个文件中
  208.         process_image(user_buf[buf.index].start,user_buf[buf.index].length);
  209.        
  210.         if(-1 == ioctl(fd,VIDIOC_QBUF,&buf))
  211.         {
  212.                 perror("Fail to ioctl 'VIDIOC_QBUF'");
  213.                 exit(EXIT_FAILURE);
  214.         }

  215.         return 1;
  216. }

  217. int mainloop(int fd)
  218. {
  219.         int count = 2;

  220.         while(count -- > 0)
  221.         {
  222.                 for(;;)
  223.                 {
  224.                         fd_set fds;
  225.                         struct timeval tv;
  226.                         int r;

  227.                         FD_ZERO(&fds);
  228.                         FD_SET(fd,&fds);

  229.                         /*Timeout*/
  230.                         tv.tv_sec = 2;
  231.                         tv.tv_usec = 0;
  232.                
  233.                         r = select(fd + 1,&fds,NULL,NULL,&tv);

  234.                         if(-1 == r)
  235.                         {
  236.                                 if(EINTR == errno)
  237.                                         continue;
  238.                                
  239.                                 perror("Fail to select");
  240.                                 exit(EXIT_FAILURE);
  241.                         }

  242.                         if(0 == r)
  243.                         {
  244.                                 fprintf(stderr,"select Timeout\n");
  245.                                 exit(EXIT_FAILURE);
  246.                         }

  247.                         if(read_frame(fd))
  248.                                 break;
  249.                 }
  250.         }

  251.         return 0;
  252. }

  253. void stop_capturing(int fd)
  254. {
  255.         enum v4l2_buf_type type;
  256.        
  257.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  258.         if(-1 == ioctl(fd,VIDIOC_STREAMOFF,&type))
  259.         {
  260.                 perror("Fail to ioctl 'VIDIOC_STREAMOFF'");
  261.                 exit(EXIT_FAILURE);
  262.         }
  263.        
  264.         return;
  265. }

  266. void uninit_camer_device()
  267. {
  268.         unsigned int i;

  269.         for(i = 0;i < n_buffer;i ++)
  270.         {
  271.                 if(-1 == munmap(user_buf[i].start,user_buf[i].length))
  272.                 {
  273.                         exit(EXIT_FAILURE);
  274.                 }
  275.         }
  276.        
  277.         free(user_buf);

  278.         return;
  279. }

  280. void close_camer_device(int fd)
  281. {
  282.         if(-1 == close(fd))
  283.         {
  284.                 perror("Fail to close fd");
  285.                 exit(EXIT_FAILURE);
  286.         }

  287.         return;
  288. }

  289. int main()
  290. {
  291.         int fd;      
  292.                         
  293.         fd = open_camer_device();

  294.         init_camer_device(fd);
  295.        
  296.         start_capturing(fd);
  297.        
  298.         mainloop(fd);
  299.        
  300.         stop_capturing(fd);

  301.         uninit_camer_device(fd);

  302.         close_camer_device(fd);

  303.         return 0;
  304. }
复制代码
上面程序运行结果如下:
{pixelformat = YUYV},description = 'YUV 4:2:2 (YUYV)'
n_buffer = 4
len=153600
len=153600

论坛徽章:
0
2 [报告]
发表于 2014-01-24 08:55 |只看该作者
已经知道原因,是因为这个摄像头的输出格式是YUV格式,V4L2采集保存的文件也是YUV格式的,这种格式用常见的看图工具是无法显示的,需要专门的YUV查看工具才可以看;比如YUVviewer

论坛徽章:
0
3 [报告]
发表于 2014-03-04 16:43 |只看该作者
不能显示是因为格式不对,可以直接输出jpg格式的文件修改
//stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
改成 V4L2_PIX_FMT_MJPEG 就可以了

论坛徽章:
0
4 [报告]
发表于 2015-08-27 23:47 |只看该作者
本帖最后由 peterpeter2015 于 2015-08-27 23:47 编辑

你好,在你的贴子里http://bbs.chinaunix.net/thread-4120327-1-1.html 我改了stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV  为stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;因为程序输出为:{pixelformat = GREY},description = 'Greyscale 8-bit (Y800)'
n_buffer = 4
len=307200
len=307200

但是jpg文件还是不可以看,为什么?是不是不能直接将内存里的数据存为jpg?需要转换原始数据才能变成jpg?谢谢回复.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP