在线问答
直播中

ycdhonker

13年用户 131经验值
擅长:EDA/IC设计 处理器/DSP 接口/总线/驱动
私信 关注

【OK210试用体验】OK210 V4l2视频采集

本帖最后由 ycdhonker 于 2015-8-11 20:51 编辑

硬件平台OK210 开发板 + USB 摄像头
开发环境:Windows XP 32 bit + Vmware 10.0 + Ubuntu 10.04 + arm-none-linux-gnueabi交叉编译环境
一、视频采集相关知识
1、V4L和V4L2。
V4L是Linux环境下开发视频采集设备驱动程序的一套规范(API),它为驱动程序的编写提供统一的接口,并将所有的视频采集设备的驱动程序都纳入其的管理之中。V4L不仅给驱动程序编写者带来极大的方便,同时也方便了应用程序的编写和移植。V4L2是V4L的升级版,由于我们使用的OOB是3.3的内核,不再支持V4L,因而编程不再考虑V4L的api和参数定义。
2、YUYV与RGB24
RGB是一种颜色的表示法,计算机中一般采用24位来存储,每个颜色占8位。YUV也是一种颜色空间,为什么要出现YUV,主要有两个原因,一个是为了让彩色信号兼容黑白电视机,另外一个原因是为了减少传输的带宽。YUV中,Y表示亮度,U和V表示色度,总之它是将RGB信号进行了一种处理,根据人对亮度更敏感些,增加亮度的信号,减少颜色的信号,以这样“欺骗”人的眼睛的手段来节省空间。YUV到RGB颜色空间转换关系是:
R = Y + 1.042*(V-128);G = Y - 0.34414*(U-128) - 0.71414*(V-128);B = Y + 1.772*(U-128);
YUV的格式也很多,不过常见的就是422、420等。YUYV就是422形式,简单来说就是,两个像素点P1、P2本应该有Y1、U1、V1和Y2、U2、V2这六个分量,但是实际只保留Y1、U1、Y2、V2。
二、应用程序设计
先定义一些宏和结构体,方便后续编程
引用: #define  TRUE        1
#define  FALSE        0

#define FILE_VIDEO         "/dev/video2"
#define BMP              "/usr/image_bmp.bmp"
#define YUV                        "/usr/image_yuv.yuv"

#define  IMAGEWIDTH    640
#define  IMAGEHEIGHT   480


  1. static   int      fd;
  2. static   struct   v4l2_capability   cap;
  3. struct v4l2_fmtdesc fmtdesc;
  4. struct v4l2_format fmt,fmtack;
  5. struct v4l2_streamparm setfps;  
  6. struct v4l2_requestbuffers req;
  7. struct v4l2_buffer buf;
  8. enum v4l2_buf_type type;
  9. unsigned char frame_buffer[IMAGEWIDTH*IMAGEHEIGHT*3];


  10. struct buffer
  11. {
  12.         void * start;
  13.         unsigned int length;
  14. } * buffers;

  15. int init_v4l2(void)
  16. {
  17.         int i;
  18.         int ret = 0;
  19.        
  20.         //opendev
  21.         if ((fd = open(FILE_VIDEO, O_RDWR)) == -1)
  22.         {
  23.                 printf("Error opening V4L interfacen");
  24.                 return (FALSE);
  25.         }

  26.         //query cap
  27.         if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
  28.         {
  29.                 printf("Error opening device %s: unable to query device.n",FILE_VIDEO);
  30.                 return (FALSE);
  31.         }
  32.         else
  33.         {
  34.              printf("driver:tt%sn",cap.driver);
  35.              printf("card:tt%sn",cap.card);
  36.              printf("bus_info:t%sn",cap.bus_info);
  37.              printf("version:t%dn",cap.version);
  38.              printf("capabilities:t%xn",cap.capabilities);
  39.             
  40.              if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE)
  41.              {
  42.                         printf("Device %s: supports capture.n",FILE_VIDEO);
  43.                 }

  44.                 if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
  45.                 {
  46.                         printf("Device %s: supports streaming.n",FILE_VIDEO);
  47.                 }
  48.         }
  49.        
  50.         //emu all support fmt
  51.         fmtdesc.index=0;
  52.         fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
  53.         printf("Support format:n");
  54.         while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
  55.         {
  56.                 printf("t%d.%sn",fmtdesc.index+1,fmtdesc.description);
  57.                 fmtdesc.index++;
  58.         }
  59.        
  60.     //set fmt
  61.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  62.         fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  63.         fmt.fmt.pix.height = IMAGEHEIGHT;
  64.         fmt.fmt.pix.width = IMAGEWIDTH;
  65.         fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
  66.        
  67.         if(ioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
  68.         {
  69.                 printf("Unable to set formatn");
  70.                 return FALSE;
  71.         }        
  72.         if(ioctl(fd, VIDIOC_G_FMT, &fmt) == -1)
  73.         {
  74.                 printf("Unable to get formatn");
  75.                 return FALSE;
  76.         }
  77.         {
  78.              printf("fmt.type:tt%dn",fmt.type);
  79.              printf("pix.pixelformat:t%c%c%c%cn",fmt.fmt.pix.pixelformat & 0xFF, (fmt.fmt.pix.pixelformat >> 8) & 0xFF,(fmt.fmt.pix.pixelformat >> 16) & 0xFF, (fmt.fmt.pix.pixelformat >> 24) & 0xFF);
  80.              printf("pix.height:tt%dn",fmt.fmt.pix.height);
  81.              printf("pix.width:tt%dn",fmt.fmt.pix.width);
  82.              printf("pix.field:tt%dn",fmt.fmt.pix.field);
  83.         }
  84.         //set fps
  85.         setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  86.         setfps.parm.capture.timeperframe.numerator = 10;
  87.         setfps.parm.capture.timeperframe.denominator = 10;
  88.        
  89.         printf("init %s t[OK]n",FILE_VIDEO);
  90.             
  91.         return TRUE;
  92. }

  93. int v4l2_grab(void)
  94. {
  95.         unsigned int n_buffers;
  96.        
  97.         //request for 4 buffers
  98.         req.count=4;
  99.         req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
  100.         req.memory=V4L2_MEMORY_MMAP;
  101.         if(ioctl(fd,VIDIOC_REQBUFS,&req)==-1)
  102.         {
  103.                 printf("request for buffers errorn");
  104.         }

  105.         //mmap for buffers
  106.         buffers = malloc(req.count*sizeof (*buffers));
  107.         if (!buffers)
  108.         {
  109.                 printf ("Out of memoryn");
  110.                 return(FALSE);
  111.         }
  112.        
  113.         for (n_buffers = 0; n_buffers < req.count; n_buffers++)
  114.         {
  115.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  116.                 buf.memory = V4L2_MEMORY_MMAP;
  117.                 buf.index = n_buffers;
  118.                 //query buffers
  119.                 if (ioctl (fd, VIDIOC_QUERYBUF, &buf) == -1)
  120.                 {
  121.                         printf("query buffer errorn");
  122.                         return(FALSE);
  123.                 }

  124.                 buffers[n_buffers].length = buf.length;
  125.                 //map
  126.                 buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ |PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
  127.                 if (buffers[n_buffers].start == MAP_FAILED)
  128.                 {
  129.                         printf("buffer map errorn");
  130.                         return(FALSE);
  131.                 }
  132.         }
  133.                
  134.         //queue
  135.         for (n_buffers = 0; n_buffers < req.count; n_buffers++)
  136.         {
  137.                 buf.index = n_buffers;
  138.                 ioctl(fd, VIDIOC_QBUF, &buf);
  139.         }
  140.        
  141.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  142.         ioctl (fd, VIDIOC_STREAMON, &type);
  143.        
  144.         ioctl(fd, VIDIOC_DQBUF, &buf);

  145.     printf("grab yuyv OKn");
  146.         return(TRUE);
  147. }


  148. int yuyv_2_rgb888(void)
  149. {
  150.         int           i,j;
  151.     unsigned char y1,y2,u,v;
  152.     int r1,g1,b1,r2,g2,b2;
  153.     char * pointer;
  154.    
  155.         pointer = buffers[0].start;
  156.        
  157.     for(i=0;i<480;i++)
  158.     {
  159.             for(j=0;j<320;j++)
  160.             {
  161.                     y1 = *( pointer + (i*320+j)*4);
  162.                     u  = *( pointer + (i*320+j)*4 + 1);
  163.                     y2 = *( pointer + (i*320+j)*4 + 2);
  164.                     v  = *( pointer + (i*320+j)*4 + 3);
  165.                    
  166.                     r1 = y1 + 1.042*(v-128);
  167.                     g1 = y1 - 0.34414*(u-128) - 0.71414*(v-128);
  168.                     b1 = y1 + 1.772*(u-128);
  169.                    
  170.                     r2 = y2 + 1.042*(v-128);
  171.                     g2 = y2 - 0.34414*(u-128) - 0.71414*(v-128);
  172.                     b2 = y2 + 1.772*(u-128);
  173.                    
  174.                     if(r1>255)
  175.                             r1 = 255;
  176.                     else if(r1<0)
  177.                             r1 = 0;
  178.                    
  179.                     if(b1>255)
  180.                             b1 = 255;
  181.                     else if(b1<0)
  182.                             b1 = 0;       
  183.                    
  184.                     if(g1>255)
  185.                             g1 = 255;
  186.                     else if(g1<0)
  187.                             g1 = 0;       
  188.                            
  189.                     if(r2>255)
  190.                             r2 = 255;
  191.                     else if(r2<0)
  192.                             r2 = 0;
  193.                    
  194.                     if(b2>255)
  195.                             b2 = 255;
  196.                     else if(b2<0)
  197.                             b2 = 0;       
  198.                    
  199.                     if(g2>255)
  200.                             g2 = 255;
  201.                     else if(g2<0)
  202.                             g2 = 0;               
  203.                            
  204.                     *(frame_buffer + ((480-1-i)*320+j)*6    ) = (unsigned char)b1;
  205.                     *(frame_buffer + ((480-1-i)*320+j)*6 + 1) = (unsigned char)g1;
  206.                     *(frame_buffer + ((480-1-i)*320+j)*6 + 2) = (unsigned char)r1;
  207.                     *(frame_buffer + ((480-1-i)*320+j)*6 + 3) = (unsigned char)b2;
  208.                     *(frame_buffer + ((480-1-i)*320+j)*6 + 4) = (unsigned char)g2;
  209.                     *(frame_buffer + ((480-1-i)*320+j)*6 + 5) = (unsigned char)r2;
  210.             }
  211.     }
  212.     printf("change to RGB OK n");
  213. }

  214. int close_v4l2(void)
  215. {
  216.      if(fd != -1)
  217.      {
  218.          close(fd);
  219.          return (TRUE);
  220.      }
  221.      return (FALSE);
  222. }


  223. int main(void)
  224. {

  225.     FILE * fp1,* fp2;

  226.     BITMAPFILEHEADER   bf;
  227.     BITMAPINFOHEADER   bi;
  228.    

  229.     fp1 = fopen(BMP, "wb");
  230.     if(!fp1)
  231.         {
  232.                 printf("open "BMP"errorn");
  233.                 return(FALSE);
  234.         }
  235.        
  236.         fp2 = fopen(YUV, "wb");
  237.     if(!fp2)
  238.         {
  239.                 printf("open "YUV"errorn");
  240.                 return(FALSE);
  241.         }

  242.         if(init_v4l2() == FALSE)
  243.         {
  244.              return(FALSE);
  245.         }
  246.        
  247.         //Set BITMAPINFOHEADER
  248.         bi.biSize = 40;
  249.         bi.biWidth = IMAGEWIDTH;
  250.         bi.biHeight = IMAGEHEIGHT;
  251.         bi.biPlanes = 1;
  252.         bi.biBitCount = 24;
  253.         bi.biCompression = 0;
  254.         bi.biSizeImage = IMAGEWIDTH*IMAGEHEIGHT*3;
  255.         bi.biXPelsPerMeter = 0;
  256.         bi.biYPelsPerMeter = 0;
  257.         bi.biClrUsed = 0;
  258.         bi.biClrImportant = 0;


  259.     //Set BITMAPFILEHEADER
  260.     bf.bfType = 0x4d42;
  261.     bf.bfSize = 54 + bi.biSizeImage;     
  262.         bf.bfReserved = 0;
  263.     bf.bfOffBits = 54;
  264.    
  265.     v4l2_grab();
  266.     fwrite(buffers[0].start, 640*480*2, 1, fp2);
  267.     printf("save "YUV"OKn");
  268.    
  269.     yuyv_2_rgb888();
  270.     fwrite(&bf, 14, 1, fp1);
  271.     fwrite(&bi, 40, 1, fp1);   
  272.     fwrite(frame_buffer, bi.biSizeImage, 1, fp1);
  273.     printf("save "BMP"OKn");
  274.    
  275.    
  276.     fclose(fp1);
  277.     fclose(fp2);
  278.     close_v4l2();
  279.    
  280.     return(TRUE);
  281. }

源程序附件
OK210usb摄像头图像抓取.rar (24.51 KB)
(下载次数: 7, 2015-8-11 20:50 上传)
在Ubuntu下交叉编译后得到可执行bin文件,通过tftp命令下载到开发板,主要执行chmod +x 改变文件执行权限,生成相应的图片和yuv格式视频文件,可以通过 tftp -p -r 文件名 远程IP 地址传输到ubuntu 端 这里需要注意的是 需要在tftp 文件接收目录中建立一个与开发板下所生成的图片名相同的文件,并且该文件必须有读写权限才能放到ubuntu 端[/url]可惜的是的 我的板子没有执行成功 在ubuntu可以正常执行
QQ截图20150811204551.png
QQ截图20150811194755.png 结果执行的时候出现了错误
s3c-fimc-0 : fimc_enum_fmt_vid_capture: No capture device.[ 2292.374615] s3c-fimc-0 : fimc_s_fmt_vid_capture: No capture device.Samsung FIMC Dris3c-fimc0card:s3c-fimc0bus_info:FIMC AHB-busversion:0capabilities:4000007Device /dev/video0: supports capture.Device /dev/video0: supports streaming.Support format:Unable to set format
[url=]从网上查询了一下 说s5p210视频驱动架构有两种:一种是用的linuxV4l2驱动架构,一种是三星自己的
驱动可以有两种实现方法:第一种是把摄像头驱动做成普通的V4L2设备,直接调用FIMC里的寄存器实现视频数据的捕捉和处理;第二种利用内核已经实现好的FIMC的驱动,通过某种接口形式,把我们的摄像头驱动挂接在FIMC驱动之下。
这两种方法第一种实现起来代码量比较大,因为需要直接操作FIMC的寄存器,难度也大一些;第二种方法是利用内核已经做好的FIMC驱动,难点在于如何把摄像头驱动和FIMC驱动整合起来。
这个问题还需要解决。
未完待续----



更多回帖

发帖
×
20
完善资料,
赚取积分