基于S3C2440的Linux-3.6.6移植——基于UVC的USB摄像头移植及视频显示




基于UVCUSB摄像头的移植很简单,只需要在menuconfig中进行适当的配置即可,如下所示:

Device Drivers --->

     <*> Multimedia support --->

               [*] Video capture adapters--->

                            [*] V4L USBdevices --->

                                        <*> USB Video Class (UVC)

                                        [*]    UVC input events devicesupport

                                        <*> GSPCA based webcams --->

      [*] USB support --->

               [*] USB announce newdevices

                            <*> USB Gadget Support--->

                                       <*>    USB Webcam Gadget

 

经过上述配置以后的系统就能够正确识别出UVCUSB摄像头。把我的罗技C525摄像头插到开发板上,就会显示下列信息:

usb 1-1: new full-speed USB device number 2using s3c2410-ohci

usb 1-1: New USB device found,idVendor=046d, idProduct=0826

usb 1-1: New USB device strings: Mfr=0,Product=2, SerialNumber=1

usb 1-1: Product: HD Webcam C525

usb 1-1: SerialNumber: 19E19A50

uvcvideo: Found UVC 1.00 device HD WebcamC525 (046d:0826)

input: HD Webcam C525 as/devices/platform/s3c2410-ohci/usb1/1-1/1-1:1.2/input/input3

并且在/dev目录下,会自动创建video0设备节点,这就说明该摄像头可以正常使用了。

 

下面就介绍对摄像头的测试,在这里我们是利用摄像头采集视频信号并在LCD上实时显示。要完成上述工作,需要解决三个关键问题。一是V4L2编程;二是LCD的显示;三是彩色空间的转换。

V4L2是内核提供给应用程序访问音、视频驱动的统一接口。它的基本工作流程为:

打开设备文件--->查询设备属性--->设置视频格式--->请求分配内存,并映射到用户空间--->申请到的内存入队列,开始视频采集--->内存出队列,得到原始数据,这时就可以对原始数据进行适当处理--->内存重新入队列,以便循环--->停止采集--->关闭设备。

LCD的显示较简单,主要就是把framebuffer映射到用户空间,对该空间进行操作即可。

摄像头输出的主要格式是YUV422,该格式不能直接用于LCD的显示,所以需要彩色空间的转换,即把它转换为RGB格式。转换的公式其实很简单,但考虑到用于嵌入式系统,因此需要一些优化处理。

 

下面就给出一段完整的视频显示的程序,我的开发板的LCD分辨率为320×240,彩色空间为RGB32,摄像头输出设置为176×144


  1. #include <unistd.h>  
  2. #include <linux/fb.h>  
  3.   
  4. #include <stdio.h>  
  5. #include <stdlib.h>  
  6. #include <string.h>  
  7. #include <assert.h>  
  8. #include <getopt.h>             
  9. #include <fcntl.h>              
  10. #include <unistd.h>  
  11. #include <errno.h>  
  12. #include <malloc.h>  
  13. #include <sys/stat.h>  
  14. #include <sys/types.h>  
  15. #include <sys/time.h>  
  16. #include <sys/mman.h>  
  17. #include <sys/ioctl.h>  
  18.   
  19. #include <asm/types.h>          
  20. #include <linux/videodev2.h>  
  21.   
  22. #define CAMERA_DEVICE "/dev/video0"  
  23. #define FB_DEVICE "/dev/fb0"  
  24.   
  25. #define VIDEO_WIDTH 176  
  26. #define VIDEO_HEIGHT 144  
  27. #define BUFFER_COUNT 4  
  28.   
  29. const int rvarrxyp[]={  
  30. -180,-179,-177,-176,-175,-173,-172,-170,-169,-167,-166,-165,-163,-162,-160,-159,-158,-156,-155,-153,-152,-151,  
  31. -149,-148,-146,-145,-144,-142,-141,-139,-138,-137,-135,-134,-132,-131,-129,-128,-127,-125,-124,-122,-121,-120,  
  32. -118,-117,-115,-114,-113,-111,-110,-108,-107,-106,-104,-103,-101,-100,-99,-97,-96,-94,-93,-91,-90,-89,-87,-86,  
  33. -84,-83,-82,-80,-79,-77,-76,-75,-73,-72,-70,-69,-68,-66,-65,-63,-62,-61,-59,-58,-56,-55,-53,-52,-51,-49,-48,  
  34. -46,-45,-44,-42,-41,-39,-38,-37,-35,-34,-32,-31,-30,-28,-27,-25,-24,-23,-21,-20,-18,-17,-15,-14,-13,-11,-10,  
  35. -8,-7,-6,-4,-3,-1,0,1,3,4,6,7,8,10,11,13,14,15,17,18,20,21,23,24,25,27,28,30,31,32,34,35,37,38,39,41,42,44,45,  
  36. 46,48,49,51,52,53,55,56,58,59,61,62,63,65,66,68,69,70,72,73,75,76,77,79,80,82,83,84,86,87,89,90,91,93,94,96,  
  37. 97,99,100,101,103,104,106,107,108,110,111,113,114,115,117,118,120,121,122,124,125,127,128,129,131,132,134,135,  
  38. 137,138,139,141,142,144,145,146,148,149,151,152,153,155,156,158,159,160,162,163,165,166,167,169,170,172,173,175,  
  39. 176,177,179};  
  40.   
  41. const int guarrxyp[]={  
  42. -44,-44,-44,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-39,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,  
  43. -35,-34,-34,-34,-33,-33,-32,-32,-32,-31,-31,-31,-30,-30,-30,-29,-29,-29,-28,-28,-28,-27,-27,-27,-26,-26,-26,-25,  
  44. -25,-25,-24,-24,-23,-23,-23,-22,-22,-22,-21,-21,-21,-20,-20,-20,-19,-19,-19,-18,-18,-18,-17,-17,-17,-16,-16,-16,  
  45. -15,-15,-15,-14,-14,-13,-13,-13,-12,-12,-12,-11,-11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-8,-7,-7,-7,-6,-6,-6,-5,-5,-4,  
  46. -4,-4,-3,-3,-3,-2,-2,-2,-1,-1,-1,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,11,11,11,12,12,  
  47. 12,13,13,13,14,14,15,15,15,16,16,16,17,17,17,18,18,18,19,19,19,20,20,20,21,21,21,22,22,22,23,23,23,24,24,25,25,25,  
  48. 26,26,26,27,27,27,28,28,28,29,29,29,30,30,30,31,31,31,32,32,32,33,33,34,34,34,35,35,35,36,36,36,37,37,37,38,38,38,  
  49. 39,39,39,40,40,40,41,41,41,42,42,42,43,43,44,44};  
  50.   
  51. const int gvarrxyp[]={  
  52. -92,-91,-90,-90,-89,-88,-87,-87,-86,-85,-85,-84,-83,-82,-82,-81,-80,-80,-79,-78,-77,-77,-76,-75,-75,-74,-73,-72,  
  53. -72,-71,-70,-70,-69,-68,-67,-67,-66,-65,-65,-64,-63,-62,-62,-61,-60,-60,-59,-58,-57,-57,-56,-55,-54,-54,-53,-52,-52,  
  54. -51,-50,-49,-49,-48,-47,-47,-46,-45,-44,-44,-43,-42,-42,-41,-40,-39,-39,-38,-37,-37,-36,-35,-34,-34,-33,-32,-32,-31,  
  55. -30,-29,-29,-28,-27,-27,-26,-25,-24,-24,-23,-22,-22,-21,-20,-19,-19,-18,-17,-16,-16,-15,-14,-14,-13,-12,-11,-11,-10,  
  56. -9,-9,-8,-7,-6,-6,-5,-4,-4,-3,-2,-1,-1,0,1,1,2,3,4,4,5,6,6,7,8,9,9,10,11,11,12,13,14,14,15,16,16,17,18,19,19,20,21,  
  57. 22,22,23,24,24,25,26,27,27,28,29,29,30,31,32,32,33,34,34,35,36,37,37,38,39,39,40,41,42,42,43,44,44,45,46,47,47,48,49,  
  58. 49,50,51,52,52,53,54,54,55,56,57,57,58,59,60,60,61,62,62,63,64,65,65,66,67,67,68,69,70,70,71,72,72,73,74,75,75,76,77,  
  59. 77,78,79,80,80,81,82,82,83,84,85,85,86,87,87,88,89,90,90,91};  
  60.   
  61. const int buarrxyp[]={  
  62. -228,-226,-224,-222,-221,-219,-217,-215,-213,-212,-210,-208,-206,-205,-203,-201,-199,-197,-196,-194,-192,-190,-189,  
  63. -187,-185,-183,-181,-180,-178,-176,-174,-173,-171,-169,-167,-165,-164,-162,-160,-158,-157,-155,-153,-151,-149,-148,  
  64. -146,-144,-142,-141,-139,-137,-135,-133,-132,-130,-128,-126,-125,-123,-121,-119,-117,-116,-114,-112,-110,-109,-107,  
  65. -105,-103,-101,-100,-98,-96,-94,-93,-91,-89,-87,-85,-84,-82,-80,-78,-76,-75,-73,-71,-69,-68,-66,-64,-62,-60,-59,-57,  
  66. -55,-53,-52,-50,-48,-46,-44,-43,-41,-39,-37,-36,-34,-32,-30,-28,-27,-25,-23,-21,-20,-18,-16,-14,-12,-11,-9,-7,-5,-4,  
  67. -2,0,2,4,5,7,9,11,12,14,16,18,20,21,23,25,27,28,30,32,34,36,37,39,41,43,44,46,48,50,52,53,55,57,59,60,62,64,66,68,69,  
  68. 71,73,75,76,78,80,82,84,85,87,89,91,93,94,96,98,100,101,103,105,107,109,110,112,114,116,117,119,121,123,125,126,128,  
  69. 130,132,133,135,137,139,141,142,144,146,148,149,151,153,155,157,158,160,162,164,165,167,169,171,173,174,176,178,180,  
  70. 181,183,185,187,189,190,192,194,196,197,199,201,203,205,206,208,210,212,213,215,217,219,221,222,224,226};  
  71.   
  72. typedef struct VideoBuffer {  
  73.     void   *start;  
  74.     size_t  length;  
  75. } VideoBuffer;  
  76.   
  77. VideoBuffer framebuf[BUFFER_COUNT];  
  78.   
  79. //查表法,把YUV422转换为RGB32  
  80. void process(unsigned long  *fb_buf, unsigned char *v_buf)  
  81. {  
  82.     int r,g,b;  
  83.     int y0,u,y1,v;  
  84.     y0=(int)*v_buf;  
  85.     v=(int)*(v_buf+1);  
  86.     y1=(int)*(v_buf+2);  
  87.     u=(int)*(v_buf+3);  
  88.   
  89.     r=y0+rvarrxyp[v];  
  90.     g=y0-guarrxyp[u]-gvarrxyp[v];  
  91.     b=y0+buarrxyp[u];  
  92.     if (r>255) r=255;  
  93.     if (r<0) r=0;  
  94.     if (g>255) g=255;  
  95.     if (g<0) g=0;  
  96.     if (b>255) b=255;  
  97.     if (b<0) b=0;  
  98.     *fb_buf=(b<<16)+(g<<8)+r;  
  99.   
  100.     r=y1+rvarrxyp[v];  
  101.     g=y1-guarrxyp[u]-gvarrxyp[v];  
  102.     b=y1+buarrxyp[u];  
  103.     if (r>255) r=255;  
  104.     if (r<0) r=0;  
  105.     if (g>255) g=255;  
  106.     if (g<0) g=0;  
  107.     if (b>255) b=255;  
  108.     if (b<0) b=0;  
  109.     *(fb_buf+1)=(b<<16)+(g<<8)+r;  
  110. }  
  111.   
  112. int main()  
  113. {  
  114.     int i, ret;    
  115.   
  116.     // 打开摄像头设备  
  117.     int fd;  
  118.     fd = open(CAMERA_DEVICE, O_RDWR, 0);  
  119.     if (fd < 0) {  
  120.         printf("Open %s failed\n", CAMERA_DEVICE);  
  121.         return -1;  
  122.     }  
  123.   
  124.     // 获取驱动信息  
  125.     struct v4l2_capability cap;  
  126.     ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);  
  127.     if (ret < 0) {  
  128.         printf("VIDIOC_QUERYCAP failed (%d)\n", ret);  
  129.         return ret;  
  130.     }  
  131.   
  132.     printf("Capability Informations:\n");  
  133.     printf(" driver: %s\n", cap.driver);  
  134.     printf(" card: %s\n", cap.card);  
  135.     printf(" bus_info: %s\n", cap.bus_info);  
  136.     printf(" version: %u.%u.%u\n", (cap.version>>16)&0XFF, (cap.version>>8)&0XFF,cap.version&0XFF);  
  137.     printf(" capabilities: %08X\n", cap.capabilities);  
  138.   
  139.     // 设置视频格式  
  140.     struct v4l2_format fmt;  
  141.     memset(&fmt, 0, sizeof(fmt));  
  142.     fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  143.     fmt.fmt.pix.width       = VIDEO_WIDTH;  
  144.     fmt.fmt.pix.height      = VIDEO_HEIGHT;  
  145.     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;  
  146.     fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;  
  147.     ret = ioctl(fd, VIDIOC_S_FMT, &fmt);  
  148.     if (ret < 0) {  
  149.         printf("VIDIOC_S_FMT failed (%d)\n", ret);  
  150.         return ret;  
  151.     }  
  152.   
  153.     //获取视频格式  
  154.     ret = ioctl(fd, VIDIOC_G_FMT, &fmt);  
  155.     if (ret < 0) {  
  156.         printf("VIDIOC_G_FMT failed (%d)\n", ret);  
  157.         return ret;  
  158.     }  
  159.     // Print Stream Format  
  160.     printf("Stream Format Informations:\n");  
  161.     printf(" type: %d\n", fmt.type);  
  162.     printf(" width: %d\n", fmt.fmt.pix.width);  
  163.     printf(" height: %d\n", fmt.fmt.pix.height);  
  164.     char fmtstr[8];  
  165.     memset(fmtstr, 0, 8);  
  166.     memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4);  
  167.     printf(" pixelformat: %s\n", fmtstr);  
  168.     printf(" field: %d\n", fmt.fmt.pix.field);  
  169.     printf(" bytesperline: %d\n", fmt.fmt.pix.bytesperline);  
  170.     printf(" sizeimage: %d\n", fmt.fmt.pix.sizeimage);  
  171.     printf(" colorspace: %d\n", fmt.fmt.pix.colorspace);  
  172.     printf(" priv: %d\n", fmt.fmt.pix.priv);  
  173.     printf(" raw_date: %s\n", fmt.fmt.raw_data);  
  174.   
  175.     //请求分配内存  
  176.     struct v4l2_requestbuffers reqbuf;  
  177.       
  178.     reqbuf.count = BUFFER_COUNT;  
  179.     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  180.     reqbuf.memory = V4L2_MEMORY_MMAP;  
  181.       
  182.     ret = ioctl(fd , VIDIOC_REQBUFS, &reqbuf);  
  183.     if(ret < 0) {  
  184.         printf("VIDIOC_REQBUFS failed (%d)\n", ret);  
  185.         return ret;  
  186.     }  
  187.   
  188.     VideoBuffer*  buffers = calloc( reqbuf.count, sizeof(*buffers) );  
  189.     struct v4l2_buffer buf;  
  190.   
  191.     for (i = 0; i < reqbuf.count; i++)   
  192.     {  
  193.         buf.index = i;  
  194.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  195.         buf.memory = V4L2_MEMORY_MMAP;  
  196.         //获取内存空间  
  197.         ret = ioctl(fd , VIDIOC_QUERYBUF, &buf);  
  198.         if(ret < 0) {  
  199.             printf("VIDIOC_QUERYBUF (%d) failed (%d)\n", i, ret);  
  200.             return ret;  
  201.         }  
  202.   
  203.         //映射到用户空间  
  204.         framebuf[i].length = buf.length;  
  205.         framebuf[i].start = (char *) mmap(0, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, buf.m.offset);  
  206.         if (framebuf[i].start == MAP_FAILED) {  
  207.             printf("mmap (%d) failed: %s\n", i, strerror(errno));  
  208.             return -1;  
  209.         }  
  210.       
  211.         //内存入队列  
  212.         ret = ioctl(fd , VIDIOC_QBUF, &buf);  
  213.         if (ret < 0) {  
  214.             printf("VIDIOC_QBUF (%d) failed (%d)\n", i, ret);  
  215.             return -1;  
  216.         }  
  217.   
  218.         printf("Frame buffer %d: address=0x%x, length=%d\n", i, (unsigned int)framebuf[i].start, framebuf[i].length);  
  219.     }  
  220.   
  221.     // 启动视频流  
  222.     enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  223.     ret = ioctl(fd, VIDIOC_STREAMON, &type);  
  224.     if (ret < 0) {  
  225.         printf("VIDIOC_STREAMON failed (%d)\n", ret);  
  226.         return ret;  
  227.     }  
  228.   
  229.     struct fb_var_screeninfo vinfo;  
  230.     struct fb_fix_screeninfo finfo;  
  231.     int x,y;  
  232.     int fd_fb;  
  233.     long int screen_size = 0;  
  234.     unsigned long  *fbp32 = NULL;  
  235.     //打开LCD设备  
  236.     fd_fb = open(FB_DEVICE, O_RDWR);  
  237.     if (!fd_fb)  
  238.     {  
  239.         printf("Error: cannot open framebuffer device.\n");  
  240.         return(1);  
  241.     }  
  242.     if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &finfo))  
  243.     {  
  244.         printf("Error reading fixed information.\n");  
  245.         return(2);  
  246.     }  
  247.     //获取LCD属性信息  
  248.     if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &vinfo))  
  249.     {  
  250.         printf("Error 2 reading variable information.\n");  
  251.         return(3);  
  252.     }  
  253.   
  254.     //一屏的字节数  
  255.     screen_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;  
  256.     printf("LCD:  %dx%d, %dbpp, screen_size = %ld\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel, screen_size );  
  257.   
  258.     //映射framebuffer到用户空间  
  259.     fbp32 = (unsigned long *)mmap(0, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);  
  260.   
  261.     if ((int)fbp32 == -1)  
  262.     {  
  263.         printf("Error: failed to map framebuffer device to memory.\n");  
  264.         return(4);  
  265.     }  
  266.   
  267.     printf("start camera testing...\n");  
  268.     //开始视频显示  
  269.     while(1)  
  270.     {  
  271.         //内存空间出队列  
  272.         ret = ioctl(fd, VIDIOC_DQBUF, &buf);  
  273.         if (ret < 0)   
  274.          {  
  275.             printf("VIDIOC_DQBUF failed (%d)\n", ret);  
  276.             return ret;  
  277.          }  
  278.   
  279.        if(vinfo.bits_per_pixel == 32)  
  280.          {  
  281.            for(y = 0; y < fmt.fmt.pix.height;  y++)  
  282.               {  
  283.                for(x = 0; x < fmt.fmt.pix.width; x++)  
  284.                    {  
  285.                    //YUV422转换为RGB32  
  286.                    process(fbp32+y * vinfo.xres + x, framebuf[buf.index].start+y * fmt.fmt.pix.width*2+x*2);  
  287.                    x++;  
  288.                    }  
  289.                }  
  290.   
  291.           }  
  292.    
  293.         // 内存重新入队列  
  294.         ret = ioctl(fd, VIDIOC_QBUF, &buf);  
  295.         if (ret < 0)   
  296.           {  
  297.             printf("VIDIOC_QBUF failed (%d)\n", ret);  
  298.             return ret;  
  299.           }  
  300.   
  301.     }//while(1)  
  302.   
  303.     //释放资源  
  304.     for (i=0; i< 4; i++)   
  305.     {  
  306.         munmap(framebuf[i].start, framebuf[i].length);  
  307.     }  
  308.     munmap(fbp32, screen_size);  
  309.     //关闭设备  
  310.     close(fd);  
  311.     close(fd_fb);  
  312.     return 0;  
  313. }  
#include <unistd.h>
#include <linux/fb.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>           
#include <fcntl.h>            
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <asm/types.h>        
#include <linux/videodev2.h>

#define CAMERA_DEVICE "/dev/video0"
#define FB_DEVICE "/dev/fb0"

#define VIDEO_WIDTH 176
#define VIDEO_HEIGHT 144
#define BUFFER_COUNT 4

const int rvarrxyp[]={
-180,-179,-177,-176,-175,-173,-172,-170,-169,-167,-166,-165,-163,-162,-160,-159,-158,-156,-155,-153,-152,-151,
-149,-148,-146,-145,-144,-142,-141,-139,-138,-137,-135,-134,-132,-131,-129,-128,-127,-125,-124,-122,-121,-120,
-118,-117,-115,-114,-113,-111,-110,-108,-107,-106,-104,-103,-101,-100,-99,-97,-96,-94,-93,-91,-90,-89,-87,-86,
-84,-83,-82,-80,-79,-77,-76,-75,-73,-72,-70,-69,-68,-66,-65,-63,-62,-61,-59,-58,-56,-55,-53,-52,-51,-49,-48,
-46,-45,-44,-42,-41,-39,-38,-37,-35,-34,-32,-31,-30,-28,-27,-25,-24,-23,-21,-20,-18,-17,-15,-14,-13,-11,-10,
-8,-7,-6,-4,-3,-1,0,1,3,4,6,7,8,10,11,13,14,15,17,18,20,21,23,24,25,27,28,30,31,32,34,35,37,38,39,41,42,44,45,
46,48,49,51,52,53,55,56,58,59,61,62,63,65,66,68,69,70,72,73,75,76,77,79,80,82,83,84,86,87,89,90,91,93,94,96,
97,99,100,101,103,104,106,107,108,110,111,113,114,115,117,118,120,121,122,124,125,127,128,129,131,132,134,135,
137,138,139,141,142,144,145,146,148,149,151,152,153,155,156,158,159,160,162,163,165,166,167,169,170,172,173,175,
176,177,179};

const int guarrxyp[]={
-44,-44,-44,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-39,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,
-35,-34,-34,-34,-33,-33,-32,-32,-32,-31,-31,-31,-30,-30,-30,-29,-29,-29,-28,-28,-28,-27,-27,-27,-26,-26,-26,-25,
-25,-25,-24,-24,-23,-23,-23,-22,-22,-22,-21,-21,-21,-20,-20,-20,-19,-19,-19,-18,-18,-18,-17,-17,-17,-16,-16,-16,
-15,-15,-15,-14,-14,-13,-13,-13,-12,-12,-12,-11,-11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-8,-7,-7,-7,-6,-6,-6,-5,-5,-4,
-4,-4,-3,-3,-3,-2,-2,-2,-1,-1,-1,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,11,11,11,12,12,
12,13,13,13,14,14,15,15,15,16,16,16,17,17,17,18,18,18,19,19,19,20,20,20,21,21,21,22,22,22,23,23,23,24,24,25,25,25,
26,26,26,27,27,27,28,28,28,29,29,29,30,30,30,31,31,31,32,32,32,33,33,34,34,34,35,35,35,36,36,36,37,37,37,38,38,38,
39,39,39,40,40,40,41,41,41,42,42,42,43,43,44,44};

const int gvarrxyp[]={
-92,-91,-90,-90,-89,-88,-87,-87,-86,-85,-85,-84,-83,-82,-82,-81,-80,-80,-79,-78,-77,-77,-76,-75,-75,-74,-73,-72,
-72,-71,-70,-70,-69,-68,-67,-67,-66,-65,-65,-64,-63,-62,-62,-61,-60,-60,-59,-58,-57,-57,-56,-55,-54,-54,-53,-52,-52,
-51,-50,-49,-49,-48,-47,-47,-46,-45,-44,-44,-43,-42,-42,-41,-40,-39,-39,-38,-37,-37,-36,-35,-34,-34,-33,-32,-32,-31,
-30,-29,-29,-28,-27,-27,-26,-25,-24,-24,-23,-22,-22,-21,-20,-19,-19,-18,-17,-16,-16,-15,-14,-14,-13,-12,-11,-11,-10,
-9,-9,-8,-7,-6,-6,-5,-4,-4,-3,-2,-1,-1,0,1,1,2,3,4,4,5,6,6,7,8,9,9,10,11,11,12,13,14,14,15,16,16,17,18,19,19,20,21,
22,22,23,24,24,25,26,27,27,28,29,29,30,31,32,32,33,34,34,35,36,37,37,38,39,39,40,41,42,42,43,44,44,45,46,47,47,48,49,
49,50,51,52,52,53,54,54,55,56,57,57,58,59,60,60,61,62,62,63,64,65,65,66,67,67,68,69,70,70,71,72,72,73,74,75,75,76,77,
77,78,79,80,80,81,82,82,83,84,85,85,86,87,87,88,89,90,90,91};

const int buarrxyp[]={
-228,-226,-224,-222,-221,-219,-217,-215,-213,-212,-210,-208,-206,-205,-203,-201,-199,-197,-196,-194,-192,-190,-189,
-187,-185,-183,-181,-180,-178,-176,-174,-173,-171,-169,-167,-165,-164,-162,-160,-158,-157,-155,-153,-151,-149,-148,
-146,-144,-142,-141,-139,-137,-135,-133,-132,-130,-128,-126,-125,-123,-121,-119,-117,-116,-114,-112,-110,-109,-107,
-105,-103,-101,-100,-98,-96,-94,-93,-91,-89,-87,-85,-84,-82,-80,-78,-76,-75,-73,-71,-69,-68,-66,-64,-62,-60,-59,-57,
-55,-53,-52,-50,-48,-46,-44,-43,-41,-39,-37,-36,-34,-32,-30,-28,-27,-25,-23,-21,-20,-18,-16,-14,-12,-11,-9,-7,-5,-4,
-2,0,2,4,5,7,9,11,12,14,16,18,20,21,23,25,27,28,30,32,34,36,37,39,41,43,44,46,48,50,52,53,55,57,59,60,62,64,66,68,69,
71,73,75,76,78,80,82,84,85,87,89,91,93,94,96,98,100,101,103,105,107,109,110,112,114,116,117,119,121,123,125,126,128,
130,132,133,135,137,139,141,142,144,146,148,149,151,153,155,157,158,160,162,164,165,167,169,171,173,174,176,178,180,
181,183,185,187,189,190,192,194,196,197,199,201,203,205,206,208,210,212,213,215,217,219,221,222,224,226};

typedef struct VideoBuffer {
    void   *start;
    size_t  length;
} VideoBuffer;

VideoBuffer framebuf[BUFFER_COUNT];

//查表法,把YUV422转换为RGB32
void process(unsigned long  *fb_buf, unsigned char *v_buf)
{
    int r,g,b;
    int y0,u,y1,v;
    y0=(int)*v_buf;
    v=(int)*(v_buf+1);
    y1=(int)*(v_buf+2);
    u=(int)*(v_buf+3);

    r=y0+rvarrxyp[v];
    g=y0-guarrxyp[u]-gvarrxyp[v];
    b=y0+buarrxyp[u];
    if (r>255) r=255;
    if (r<0) r=0;
    if (g>255) g=255;
    if (g<0) g=0;
    if (b>255) b=255;
    if (b<0) b=0;
    *fb_buf=(b<<16)+(g<<8)+r;

    r=y1+rvarrxyp[v];
    g=y1-guarrxyp[u]-gvarrxyp[v];
    b=y1+buarrxyp[u];
    if (r>255) r=255;
    if (r<0) r=0;
    if (g>255) g=255;
    if (g<0) g=0;
    if (b>255) b=255;
    if (b<0) b=0;
    *(fb_buf+1)=(b<<16)+(g<<8)+r;
}

int main()
{
    int i, ret;  

    // 打开摄像头设备
    int fd;
    fd = open(CAMERA_DEVICE, O_RDWR, 0);
    if (fd < 0) {
        printf("Open %s failed\n", CAMERA_DEVICE);
        return -1;
    }

    // 获取驱动信息
    struct v4l2_capability cap;
    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
    if (ret < 0) {
        printf("VIDIOC_QUERYCAP failed (%d)\n", ret);
        return ret;
    }

    printf("Capability Informations:\n");
    printf(" driver: %s\n", cap.driver);
    printf(" card: %s\n", cap.card);
    printf(" bus_info: %s\n", cap.bus_info);
    printf(" version: %u.%u.%u\n", (cap.version>>16)&0XFF, (cap.version>>8)&0XFF,cap.version&0XFF);
    printf(" capabilities: %08X\n", cap.capabilities);

    // 设置视频格式
    struct v4l2_format fmt;
    memset(&fmt, 0, sizeof(fmt));
    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width       = VIDEO_WIDTH;
    fmt.fmt.pix.height      = VIDEO_HEIGHT;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
    ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
    if (ret < 0) {
        printf("VIDIOC_S_FMT failed (%d)\n", ret);
        return ret;
    }

    //获取视频格式
    ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
    if (ret < 0) {
        printf("VIDIOC_G_FMT failed (%d)\n", ret);
        return ret;
    }
    // Print Stream Format
    printf("Stream Format Informations:\n");
    printf(" type: %d\n", fmt.type);
    printf(" width: %d\n", fmt.fmt.pix.width);
    printf(" height: %d\n", fmt.fmt.pix.height);
    char fmtstr[8];
    memset(fmtstr, 0, 8);
    memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4);
    printf(" pixelformat: %s\n", fmtstr);
    printf(" field: %d\n", fmt.fmt.pix.field);
    printf(" bytesperline: %d\n", fmt.fmt.pix.bytesperline);
    printf(" sizeimage: %d\n", fmt.fmt.pix.sizeimage);
    printf(" colorspace: %d\n", fmt.fmt.pix.colorspace);
    printf(" priv: %d\n", fmt.fmt.pix.priv);
    printf(" raw_date: %s\n", fmt.fmt.raw_data);

    //请求分配内存
    struct v4l2_requestbuffers reqbuf;
    
    reqbuf.count = BUFFER_COUNT;
    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf.memory = V4L2_MEMORY_MMAP;
    
    ret = ioctl(fd , VIDIOC_REQBUFS, &reqbuf);
    if(ret < 0) {
        printf("VIDIOC_REQBUFS failed (%d)\n", ret);
        return ret;
    }

    VideoBuffer*  buffers = calloc( reqbuf.count, sizeof(*buffers) );
    struct v4l2_buffer buf;

    for (i = 0; i < reqbuf.count; i++) 
    {
        buf.index = i;
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        //获取内存空间
        ret = ioctl(fd , VIDIOC_QUERYBUF, &buf);
        if(ret < 0) {
            printf("VIDIOC_QUERYBUF (%d) failed (%d)\n", i, ret);
            return ret;
        }

        //映射到用户空间
        framebuf[i].length = buf.length;
        framebuf[i].start = (char *) mmap(0, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
        if (framebuf[i].start == MAP_FAILED) {
            printf("mmap (%d) failed: %s\n", i, strerror(errno));
            return -1;
        }
    
        //内存入队列
        ret = ioctl(fd , VIDIOC_QBUF, &buf);
        if (ret < 0) {
            printf("VIDIOC_QBUF (%d) failed (%d)\n", i, ret);
            return -1;
        }

        printf("Frame buffer %d: address=0x%x, length=%d\n", i, (unsigned int)framebuf[i].start, framebuf[i].length);
    }

    // 启动视频流
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd, VIDIOC_STREAMON, &type);
    if (ret < 0) {
        printf("VIDIOC_STREAMON failed (%d)\n", ret);
        return ret;
    }

    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    int x,y;
    int fd_fb;
    long int screen_size = 0;
    unsigned long  *fbp32 = NULL;
    //打开LCD设备
    fd_fb = open(FB_DEVICE, O_RDWR);
    if (!fd_fb)
    {
        printf("Error: cannot open framebuffer device.\n");
        return(1);
    }
    if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &finfo))
    {
        printf("Error reading fixed information.\n");
        return(2);
    }
    //获取LCD属性信息
    if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &vinfo))
    {
        printf("Error 2 reading variable information.\n");
        return(3);
    }

    //一屏的字节数
    screen_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
    printf("LCD:  %dx%d, %dbpp, screen_size = %ld\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel, screen_size );

    //映射framebuffer到用户空间
    fbp32 = (unsigned long *)mmap(0, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);

    if ((int)fbp32 == -1)
    {
        printf("Error: failed to map framebuffer device to memory.\n");
        return(4);
    }

    printf("start camera testing...\n");
    //开始视频显示
    while(1)
    {
        //内存空间出队列
        ret = ioctl(fd, VIDIOC_DQBUF, &buf);
        if (ret < 0) 
         {
            printf("VIDIOC_DQBUF failed (%d)\n", ret);
            return ret;
         }

       if(vinfo.bits_per_pixel == 32)
         {
           for(y = 0; y < fmt.fmt.pix.height;  y++)
              {
               for(x = 0; x < fmt.fmt.pix.width; x++)
                   {
                   //YUV422转换为RGB32
                   process(fbp32+y * vinfo.xres + x, framebuf[buf.index].start+y * fmt.fmt.pix.width*2+x*2);
                   x++;
                   }
               }

          }
 
        // 内存重新入队列
        ret = ioctl(fd, VIDIOC_QBUF, &buf);
        if (ret < 0) 
          {
            printf("VIDIOC_QBUF failed (%d)\n", ret);
            return ret;
          }

    }//while(1)

    //释放资源
    for (i=0; i< 4; i++) 
    {
        munmap(framebuf[i].start, framebuf[i].length);
    }
    munmap(fbp32, screen_size);
    //关闭设备
    close(fd);
    close(fd_fb);
    return 0;
}
这里有一个问题,我的摄像头是支持 320×240 ,但无法实现该格式的视频输出,也不能设置更高的视频分辨率,不知何故?
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值