Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1675686
  • 博文数量: 311
  • 博客积分: 7778
  • 博客等级: 少将
  • 技术积分: 4186
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-09 19:59
个人简介

蓝点工坊(http://www.bluedrum.cn) 创始人,App和嵌入式产品开发。同时也做相应培训和外包工作。 详细介绍 http://pan.baidu.com/s/1y2g88

文章存档

2012年(3)

2011年(115)

2010年(170)

2009年(23)

分类: 嵌入式

2011-10-01 01:04:25

Andrew Huang 转载请注明作者及联络方式

三星为测试CMOS模块,有一个简单的cam2fb.c 演示.它演示了RGB格式的CMOS摄像头,但是代码风格太乱了,因此我把代码重写,写成几个函数来简化处理.

这个代码只是简单的使用RGB格式,直接在屏幕上显示.


  1. /*
  2.   hxy_cam2fb.c
  3.     Author : Andrew Huang <bluedrum@163.com>
  4.     CMOS Camra RGB Format test
  5.     
  6.  */
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <fcntl.h>
  11. #include <unistd.h>
  12. #include <ctype.h>
  13. #include <errno.h>
  14. #include <sys/mman.h>
  15. #include <sys/time.h>
  16. #include <sys/ioctl.h>
  17. #include <asm/types.h>
  18. #include <linux/videodev2.h>
  19. #include <linux/fb.h>
  20. #include <signal.h>


  21. #define CAM_DEV_NAME "/dev/video0"
  22. #define FB_DEV_NAME "/dev/fb0"

  23. #define CAM_TYPE_RGB_16BPP (0)
  24. #define CAM_TYPE_YUV_420 (1)


  25. #define CAM_DATA_READ (0)
  26. #define CAM_DATA_MMAP (1)

  27. struct cam_dev {
  28.   int height;
  29.   int width;
  30.   int format;
  31.   int data_mode; /* 0 - 使用read(),1--使用mmap() 缓冲 */
  32.   
  33.   int fd;
  34.   char * buf;
  35.   int buf_size;
  36. };

  37. struct fb_dev {
  38.   int height;
  39.   int width;
  40.   int bpp;
  41.   int bytes_by_pixel;

  42.   int fd;
  43.   char * buf;
  44.   int buf_size;
  45. };
  46. static inline void print_fps(struct timeval *s, struct timeval *e)
  47. {
  48.     unsigned long time;
  49.     unsigned long sec;
  50.     unsigned long usec;
  51.     int fps = 0;
  52.     
  53.     sec = e->tv_sec - s->tv_sec;
  54.     if (e->tv_usec > s->tv_usec)
  55.         usec = e->tv_usec - s->tv_usec;
  56.     else {
  57.         usec = e->tv_usec + 1000000 - s->tv_usec;    
  58.         sec--;
  59.     }
  60.     time = sec * 1000 + (usec+1) / 1000;
  61.     
  62.     if(time==0)
  63.      return;
  64.     
  65.     fps = 30000 / time;
  66.     printf("%d fps\n", fps);
  67. }

  68. /* 打开FB设备 */
  69. int fb_dev_open(struct fb_dev * pdev,int bpp,char * dev_name)
  70. {
  71.   struct fb_var_screeninfo var;
  72.  
  73.   
  74.   if(dev_name == NULL)
  75.       dev_name = FB_DEV_NAME;

  76.     switch(bpp )
  77.        {
  78.        case 16:
  79.          pdev->bytes_by_pixel = 2;
  80.          break;
  81.     case 18:
  82.     case 24:
  83.            pdev->bytes_by_pixel = 4;
  84.         break;
  85.     default:
  86.         fprintf(stderr,"error bpp %d\n",bpp);
  87.         return -1;
  88.        }

  89.  
  90.   pdev->fd = open(dev_name,O_RDWR);
  91.   if(pdev->fd == -1)
  92.       {
  93.        fprintf(stderr,"open %s failure\n",dev_name);
  94.        return -1;
  95.       }

  96.    if (ioctl(pdev->fd, FBIOGET_VSCREENINFO, &var)!=0)
  97.        {
  98.         close(pdev->fd);
  99.      perror("ioctl FBVAR");
  100.      return -2;
  101.        }

  102.    if(bpp != var.bits_per_pixel)
  103.        {
  104.         var.bits_per_pixel = bpp;
  105.      if (ioctl(pdev->fd, FBIOPUT_VSCREENINFO, &var)!=0)
  106.         {
  107.         close(pdev->fd);
  108.      perror("ioctl PUT FBVAR");
  109.      return -3;
  110.         }
  111.        }

  112.    pdev->width = var.xres;
  113.    pdev->height = var.yres;
  114.    pdev->bpp = bpp;

  115.    pdev->buf_size = pdev->width * pdev->height * pdev->bytes_by_pixel;

  116.    pdev->buf = mmap(NULL,pdev->buf_size,PROT_READ | PROT_WRITE, MAP_SHARED,pdev->fd,0);
  117.    if(pdev->buf == MAP_FAILED)
  118.        {
  119.         perror("mmap fb");
  120.         return -4;
  121.        }

  122.  
  123.    printf("open fb %s :width %d,height %d ,bpp %d,buf 0x%x,size %d\n",
  124.       dev_name,pdev->width,pdev->height,pdev->bpp,pdev->buf,pdev->buf_size);
  125.    
  126.    return 0;
  127.   
  128. }

  129. int fb_dev_close(struct fb_dev* pdev)
  130. {
  131.    munmap(pdev->buf,pdev->buf_size);

  132.   close(pdev->fd);

  133.   return 0;
  134. }


  135. int cam_dev_open(struct cam_dev * pdev,int width,int height,int format,int mode,char * dev_name)
  136. {
  137.   struct v4l2_capability cap;
  138.   struct v4l2_input input;
  139.   struct v4l2_framebuffer fb;
  140.   int ret,on,index = 0;
  141.   
  142.    if(dev_name == NULL)
  143.       dev_name = CAM_DEV_NAME;
  144.    
  145.    memset(pdev,0,sizeof(struct cam_dev));

  146.     pdev->width = width;
  147.    pdev->height = height;
  148.    

  149.   if(format == CAM_TYPE_RGB_16BPP)    
  150.     pdev->buf_size = pdev->width * pdev->height * 2;
  151.   else if(format == CAM_TYPE_YUV_420)    
  152.       pdev->buf_size = pdev->width * pdev->height * 4/3;
  153.   else
  154.       {
  155.        fprintf(stderr,"error camera format %d\n",format);
  156.        return -1;
  157.       }

  158.   pdev->fd = open(dev_name,O_RDWR);
  159.   if(pdev->fd == -1)
  160.       {
  161.        fprintf(stderr,"open %s failure\n",dev_name);
  162.        return -2;
  163.       }

  164.     if((ret=ioctl(pdev->fd, VIDIOC_QUERYCAP, &cap))!=0) {
  165.         fprintf(stderr,"VIDIOC_QUERYCAP error, %s\n",strerror(ret));
  166.         goto SET_ERROR;
  167.     }

  168.     printf("Driver:%s, Card:%s, cap=0x%x\n",cap.driver,cap.card,cap.capabilities);

  169.     memset(&input, 0, sizeof(input));
  170.     input.index= index;
  171.     if(ioctl(pdev->fd, VIDIOC_ENUMINPUT, &input)<0)
  172.         goto SET_ERROR;
  173.     
  174.     printf("input[%d] name:%s\n",input.index,input.name);

  175.     index=0;
  176.     if((ret = ioctl(pdev->fd, VIDIOC_S_INPUT, &index))<0)
  177.         goto SET_ERROR;

  178.     if((ret = ioctl(pdev->fd, VIDIOC_S_OUTPUT, &index))<0)
  179.      goto SET_ERROR;

  180.     if((ret = ioctl(pdev->fd, VIDIOC_G_FBUF, &fb))<0)
  181.         goto SET_ERROR;

  182.     printf("g_fbuf:capabilities=0x%x,flags=0x%x,width=%d,height=%d\npixelformat=0x%x,bytesperline=%d,colorspace=%d,base=0x%x\n",
  183.         fb.capability,fb.flags,fb.fmt.width,fb.fmt.height,fb.fmt.pixelformat,
  184.         fb.fmt.bytesperline,fb.fmt.colorspace,fb.base);

  185.     //set capture format to yuv
  186.     fb.capability = cap.capabilities;
  187.     fb.fmt.width =width;
  188.     fb.fmt.height = height;
  189.     if(format == CAM_TYPE_RGB_16BPP)
  190.      fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
  191.     else if(format == CAM_TYPE_YUV_420)
  192.      fb.fmt.pixelformat = V4L2_PIX_FMT_YUV420;

  193.     if((ret = ioctl(pdev->fd, VIDIOC_S_FBUF, &fb))<0)
  194.         goto SET_ERROR;

  195.     on = 1;
  196.     if((ret = ioctl(pdev->fd, VIDIOC_OVERLAY, &on))<0)
  197.         goto SET_ERROR;

  198.   if(mode == CAM_DATA_READ)
  199.     pdev->buf = malloc(pdev->buf_size);
  200.   else
  201.       {
  202.        fprintf(stderr,"error data mode %d\n",mode);
  203.        goto SET_ERROR;
  204.       }

  205.    pdev->data_mode = mode;
  206.    
  207.    return 0;
  208.    
  209. SET_ERROR:
  210.     close(pdev->fd);
  211.     return ret;
  212. }

  213. int cam_dev_close(struct cam_dev * pdev)
  214. {
  215.   int on=0;
  216.   
  217.   if(ioctl(pdev->fd, VIDIOC_OVERLAY, &on)<0)
  218.       {
  219.        perror("ioctl");
  220.       }
  221.       
  222.    if(pdev->buf)
  223.         free(pdev->buf);

  224.    close(pdev->fd);

  225.    return 0;
  226. }


  227. void show_camera_on_fb(struct fb_dev* fdev,struct cam_dev * cdev)
  228. {
  229.   unsigned int frames = 0;
  230.     struct timeval tv1;
  231.     struct timeval start_tv, end_tv;
  232.     struct timezone tz;
  233.     int len;
  234.     
  235.     gettimeofday(&start_tv, &tz);

  236.     while(1)
  237.     {

  238.      if((len = read(cdev->fd,cdev->buf,cdev->buf_size)) <=0)
  239.      {
  240.          printf("read error\n");
  241.              continue;
  242.      }

  243.         if(len>fdev->buf_size)
  244.             len = fdev->buf_size;

  245.      memcpy(fdev->buf,cdev->buf,len);

  246.      frames++;
  247.      if(frames==30){
  248.          gettimeofday(&end_tv, &tz);
  249.          print_fps(&start_tv, &end_tv);
  250.          gettimeofday(&start_tv, &tz);
  251.          frames = 0;
  252.      }

  253.         
  254.      }    
  255. }

  256. struct fb_dev fbdev;
  257. struct cam_dev camdev;

  258. void exit_func(int sig)
  259. {
  260.   printf("signal %d\n",sig);

  261.    cam_dev_close(&camdev);
  262.    fb_dev_close(&fbdev);

  263.    exit(0);
  264. }


  265. int main(int argc,char * argv[])
  266. {
  267.   char cam_name[64] = CAM_DEV_NAME;

  268.   signal(SIGTERM,exit_func);
  269.   signal(SIGINT,exit_func);

  270.   if(argc > 1)
  271.        strncpy(cam_name,argv[1],sizeof(cam_name)-1);

  272.    if(fb_dev_open(&fbdev,16,NULL)!=0)
  273.        {
  274.         return -1;
  275.        }

  276.    if(cam_dev_open(&camdev,fbdev.width,fbdev.height,CAM_TYPE_RGB_16BPP,CAM_DATA_READ,cam_name)!=0)
  277.        {
  278.         fb_dev_close(&fbdev);
  279.      return -2;
  280.        }

  281.    show_camera_on_fb(&fbdev,&camdev);

  282.    cam_dev_close(&camdev);
  283.    fb_dev_close(&fbdev);

  284.    return 0;
  285. }

测试结果在s3c6410上用cam测试成功



阅读(3895) | 评论(5) | 转发(4) |
0

上一篇:Linux 下使用USB 网络

下一篇:YUV格式分析

给主人留下些什么吧!~~

papaep2011-11-15 09:15:02

bluedrum: 你庆应该用的telechip的板吧? 标准内核没有这个目录。不同CMOS的驱动是不一样的,一般初始化代码都不一样的。所以可能重写V4L驱动,一般可以参考ov系列的来写。.....
我们是用telechip的板。谢谢老师的解答,那我只能参考ov的来写啦,

papaep2011-11-15 08:53:56

bluedrum: 你庆应该用的telechip的板吧? 标准内核没有这个目录。不同CMOS的驱动是不一样的,一般初始化代码都不一样的。所以可能重写V4L驱动,一般可以参考ov系列的来写。.....
我们是用telechip的板。谢谢老师的解答!我就只能ov系列的来写了,

bluedrum2011-11-12 19:16:00

papaep: 补充一下:在linux-2.6.28\drivers\media\video\tcccam里面有一些驱动源代码,我们公司的开发板的数字摄像头芯片用的是MT9D112,而在tcccam里面有mt9d112_2mp.c.....
你庆应该用的telechip的板吧? 标准内核没有这个目录。不同CMOS的驱动是不一样的,一般初始化代码都不一样的。所以可能重写V4L驱动,一般可以参考ov系列的来写。

papaep2011-11-02 16:18:29

补充一下:在linux-2.6.28\drivers\media\video\tcccam里面有一些驱动源代码,我们公司的开发板的数字摄像头芯片用的是MT9D112,而在tcccam里面有mt9d112_2mp.c和mt9d112_2mp.h,ov9650.c,ov9650.h,ov9650_hw.c,ov9650_hw.h。是不是根据这些文件来修改?

papaep2011-11-02 15:45:14

老师,你好,我是你在尚观的学生,现在我有个问题想问:我们公司用的cmos摄像头芯片是adv7180,cpu是tcc8900,我在这里http://linuxtv.org/downloads/drivers/下载的最新内核包的linux-media-2011-11-01\drivers\media\video里面有个adv7180.c文件。请问如何才能把我的摄影头驱动起来工作。非常感谢!