【飞凌RZ/G2L开发板试用体验】飞凌RZ/G2L的开发板试用测评报告二 — 视频采集开发

描述

本文来源电子发烧友社区,作者:ALSET, 帖子地址:https://bbs.elecfans.com/jishu_2303429_1_1.html


测试摄像头采集视频数据

飞凌RZ/G2L的开发板试用测评报告二 — 视频采集开发

大信(QQ:8125036)
 
      在电子发烧友论坛上看到飞凌RZ/G2L的开发板介绍,其优秀的高性能低能耗引起我的兴趣,在结合其强大的音视频能力,感觉该开发板非常适合开发音视频产品,就申请试用,很快很幸运得拿到这块开发板进行试用,通过个把月的试用与探索,基本了解了开发板的基本功能,性能,接口以及开发环境等,这里就进一步结合该开发板强大的音视频功能,针对一些音视频基础功能的开发与测试。

一、硬件音视频能力了解

      OK-G2LD-C开发板拥有丰富的多媒体资源,支持多种显示、摄像头、音频接口,满足多场景下的人机交互和图像采集需求;核心板同时配备500MHz 3D GPU Mali-G31,支持Vulkan、OpenGL、OpenCL,同时VPU支持1080P高清显示,可进行H.264 1080P分辨率的硬件编解码。
同时板子带有2个有线网口和wifi无线网络,这也给音视频实时传输提供了硬件基础。
因此基于RZG2l应该能够开发出多种音视频应用,比如视频的采集编码,视频直播,电视电话会议,视频实时处理等。
开发板试用
 
图1
二、配置开发网络环境
      在前面的测试中已经建立基本的串口调试环境。为了后面更方便的在主机与开发板间传送文件,还需要建立开发板和主机的网络通讯,以便通过主机对开发板下载和上传文件。这里主机的开发环境是基于Windows 10操作系统的Ubuntu虚机系统,在Win10上安装vmware 虚机和串口超级终端,vmware里安装了 uBuntu18.4版本的linux环境。
在启动开发板之后,使用ifconfig 命令查看网络配置,可见网卡都不通,因此需要进行网络配置。
首先把一条有线网络插入到开发板的网口中,其中下图左边的网口对应的是系统里的eth0, 右侧的网口对应的是 eth1
开发板试用
 
图2
   插好网线后,进入系统网口配置文件所在目录:
cd /etc/systemd/network
打开10-eth.network 文件
vim 10-eth.network
根据自己网络段,配置好开发板的地址,这里使用的静态地址,在与主机相同网段内找一个空闲的IP地址,配置上即可,这样避免动态地址分配,导致每次重启可能会造成地址改变,带来不必要的麻烦。
[Match]
Name=eth0
KernelCommandLine=!root=/dev/nfs
[Network]
Address=192.168.3.232
Gateway=192.168.3.1
DNS=192.168.3.1
ConfigureWithoutCarrier=true
IgnoreCarrierLoss=true
开发板试用
 
图3
配置完后,重启开发板,再使用ifconfig查看网络设备,eth0设备已经有IP地址,并且检查ping是否能连通通外部主机。同时通过SecureCRT建立SSH登录,也能够顺利登录开发板了。
开发板试用
 
图4
三、连接检查网络摄像头      因为手边暂时没有MIPI CSI的摄像头器件。因此查看开发板文档,开发板系统是一个标准的ARM Linux 4.19系统,那么它就可以支持uvcamera, 因此找了一款通用型的网络摄像头Logitech Webcam C270 USB网络摄像头作为视频采集的设备,把摄像头插入开发板的USB口,检测开发板是否能够支持该摄像头,。连接好摄像头后,进入系统查看驱动加载信息。
开发板试用
 
图5查看系统的版本
开发板试用
 
图6 连接USB摄像头
SecureCRT工具里进入开发板环境里,查看USB总线信息以及开发板USB设备信息如下图:
开发板试用
 
图7
开发板试用
 
图8
      从系统设备驱动加载信息上看,开发板已经为这个摄像头识别出 audio 和 uvcvideo 设备,并成功加载驱动。
使用查看USB设备详细驱动参数命令,可查看到连入开发板的所有USB设备,以及连接位置,USB总线结构等信息。进一步查看摄像头所对应的USB设备号和相关参数,如下图红色圈设备即为该摄像头设备,记下这些参数,后面软件开发时需要,否则程序将不能正确的采集到视频画面。
usb-devices
开发板试用
 
图9

四、检测摄像头支持的采集视频规格       连接好开发板和USB摄像头后,还需要获得开发板支持这款摄像头对视频采集的规格,不同摄像头采集的规则并不相同,不同开发板支持采集的规格也不同,因此需要对当前的硬件连接做一下摄像头视频支持规则检测。
可采集视频规格检测代码在网上就有,在github上搜索Vv4l2_apture c++ 开源工程,即可以到该原始工程,git下载到主机环境中,然后根据板子的SDK,开始修改…(此处省去代码修改的一万字),主要是修改相关参数和函数。
https://github.com/soramimi/v4l2capture
开发板试用
 
图10
开发板试用
 
图11
经过修改调试代码后,最后在板上成功的运行,并输出开发板对摄像头支持的格式列表,如下:
Supported Formats:
  V4L2_CAP_VIDEO_CAPTURE: pixelformat = YUYV, description = 'YUYV 4:2:2'
        resolution:640x480 fps: 30, 25, 20, 15, 10, 5  
        resolution:160x120 fps: 30, 25, 20, 15, 10, 5  
        resolution:176x144 fps: 30, 25, 20, 15, 10, 5  
        resolution:320x176 fps: 30, 25, 20, 15, 10, 5  
        resolution:320x240 fps: 30, 25, 20, 15, 10, 5  
        resolution:352x288 fps: 30, 25, 20, 15, 10, 5  
        resolution:432x240 fps: 30, 25, 20, 15, 10, 5  
        resolution:544x288 fps: 30, 25, 20, 15, 10, 5  
        resolution:640x360 fps: 30, 25, 20, 15, 10, 5  
        resolution:752x416 fps: 25, 20, 15, 10, 5  
        resolution:800x448 fps: 25, 20, 15, 10, 5  
        resolution:800x600 fps: 20, 15, 10, 5  
        resolution:864x480 fps: 20, 15, 10, 5  
        resolution:960x544 fps: 15, 10, 5  
        resolution:960x720 fps: 10, 5  
        resolution:1024x576 fps: 10, 5  
        resolution:1184x656 fps: 10, 5  
        resolution:1280x720 fps: 10, 5  
        resolution:1280x960 fps: 7, 5  
  V4L2_CAP_VIDEO_CAPTURE: pixelformat = MJPG, description = 'Motion-JPEG'
        resolution:640x480 fps: 30, 25, 20, 15, 10, 5  
        resolution:160x120 fps: 30, 25, 20, 15, 10, 5  
        resolution:176x144 fps: 30, 25, 20, 15, 10, 5  
        resolution:320x176 fps: 30, 25, 20, 15, 10, 5  
        resolution:320x240 fps: 30, 25, 20, 15, 10, 5  
        resolution:352x288 fps: 30, 25, 20, 15, 10, 5  
        resolution:432x240 fps: 30, 25, 20, 15, 10, 5  
        resolution:544x288 fps: 30, 25, 20, 15, 10, 5  
        resolution:640x360 fps: 30, 25, 20, 15, 10, 5  
        resolution:752x416 fps: 30, 25, 20, 15, 10, 5  
        resolution:800x448 fps: 30, 25, 20, 15, 10, 5  
        resolution:800x600 fps: 30, 25, 20, 15, 10, 5  
        resolution:864x480 fps: 30, 25, 20, 15, 10, 5  
        resolution:960x544 fps: 30, 25, 20, 15, 10, 5  
        resolution:960x720 fps: 30, 25, 20, 15, 10, 5  
        resolution:1024x576 fps: 30, 25, 20, 15, 10, 5  
        resolution:1184x656 fps: 30, 25, 20, 15, 10, 5  
        resolution:1280x720 fps: 30, 25, 20, 15, 10, 5  
        resolution:1280x960 fps: 30, 25, 20, 15, 10, 5  


五、采集程序开发测试       获得摄像头的设备参数以及能够采集的视频规格参数以后,就可以开发视频采集程序,在开发采集程序前,还需要查看一下摄像头的用户层抽象操作设备,一般在/dev/下,使用以下命令查看抽象出的设备文件:
ls –ls /dev/video*
可以看到抽象的视频采集设备,后面将试用设备控制代码来打开操作它。
另外在看一下采集设备对 v4l2 系统的驱动,命令如下:
ls -l/sys/class/video4linux/video*
      这两个命令是在摄像头底层驱动加载工作正常后才会出现,如果底层驱动有任何问题,这两个命令将不会有相应信息显示。
     采集视频采用的是V4L2视频框架。V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动。在Linux中视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video*下,如果只有一个视频设备,通常为/dev/video0。V4L2在设计时,是能支持很多广泛的设备,但它们之中只有一部分是真正的视频设备:
可以支持多种设备,它可以有以下几种接口:
1. 视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的.
2. 视频输出接口(video output interface):可以驱动计算机的外围视频图像设备--像可以输出电视信号格式的设备.
3. 直接传输视频接口(video overlay interface):它的主要工作是把从视频采集设备采集过来的信号直接输出到输出设备之上,而不用经过系统的CPU.
4. 视频间隔消隐信号接口(VBI interface):它可以使应用可以访问传输消隐期的视频信号.
5. 收音机接口(radio interface):可用来处理从AM或FM高频头设备接收来的音频流.
开发板试用
 
图12
开发板试用
 
图13
代码比较长,这里放出修改的部分关键代码如下:



  1.  
  2. #include
  3. #include
  4. #include
  5. #include
  6.  
  7. #include              /* getopt_long() */
  8.  
  9. #include               /* low-level i/o */
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include
  15. #include
  16. #include
  17.  
  18. #include
  19.  
  20. #define CLEAR(x) memset(&(x), 0, sizeof(x))
  21.  
  22. #ifndef V4L2_PIX_FMT_H264
  23. #define V4L2_PIX_FMT_H264     v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */
  24. #endif
  25.  
  26. enum io_method {
  27.         IO_METHOD_READ,
  28.         IO_METHOD_MMAP,
  29.         IO_METHOD_USERPTR,
  30. };
  31.  
  32. struct buffer {
  33.         void   *start;
  34.         size_t length;
  35. };
  36.  
  37. static char            *dev_name;
  38. static enum io_method io = IO_METHOD_MMAP;
  39. static int fd = -1;
  40. struct buffer          *buffers;
  41. static unsigned int n_buffers;
  42. static int out_buf;
  43. static int force_format = 0;
  44. static int frame_count = 200;
  45. static int frame_number = 0;
  46.  
  47. static void errno_exit(const char *s)
  48. {
  49.         fprintf(stderr, "%s error %d, %sn", s, errno, strerror(errno));
  50.         exit(EXIT_FAILURE);
  51. }
  52.  
  53. static int xioctl(int fh, int request, void *arg)
  54. {
  55.         int r;
  56.  
  57.         do {
  58.                 r = ioctl(fh, request, arg);
  59.         } while (-1 == r && EINTR == errno);
  60.  
  61.         return r;
  62. }
  63.  
  64. static void process_image(const void *p, int size)
  65. {
  66.   int status;
  67.     frame_number++;
  68.  
  69.     if (out_buf==0)
  70.     {
  71.         /* write to file */
  72.         FILE *fp=fopen("video.raw","ab");
  73.         fwrite(p, size, 1, fp);
  74.         fflush(fp);
  75.         fclose(fp);
  76.     }
  77.     else
  78.     {
  79.         /* write to stdout */
  80.       status = write(1, p, size);
  81.       if(status == -1)
  82.         perror("write");
  83.     }
  84. }
  85.  
  86. static int read_frame(void)
  87. {
  88.         struct v4l2_buffer buf;
  89.         unsigned int i;
  90.  
  91.         switch (io) {
  92.         case IO_METHOD_READ:
  93.                 if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
  94.                         switch (errno) {
  95.                         case EAGAIN:
  96.                                 return 0;
  97.  
  98.                         case EIO:
  99.                         /* Could ignore EIO, see spec. */
  100.  
  101.                         /* fall through */
  102.  
  103.                         default:
  104.                                 errno_exit("read");
  105.                         }
  106.                 }
  107.  
  108.                 process_image(buffers[0].start, buffers[0].length);
  109.                 break;
  110.  
  111.         case IO_METHOD_MMAP:
  112.                 CLEAR(buf);
  113.  
  114.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  115.                 buf.memory = V4L2_MEMORY_MMAP;
  116.  
  117.                 if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
  118.                         switch (errno) {
  119.                         case EAGAIN:
  120.                                 return 0;
  121.  
  122.                         case EIO:
  123.                         /* Could ignore EIO, see spec. */
  124.  
  125.                         /* fall through */
  126.  
  127.                         default:
  128.                                 errno_exit("VIDIOC_DQBUF");
  129.                         }
  130.                 }
  131.  
  132.                 assert(buf.index < n_buffers);
  133.  
  134.                 process_image(buffers[buf.index].start, buf.bytesused);
  135.  
  136.                 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  137.                         errno_exit("VIDIOC_QBUF");
  138.                 break;
  139.  
  140.         case IO_METHOD_USERPTR:
  141.                 CLEAR(buf);
  142.  
  143.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  144.                 buf.memory = V4L2_MEMORY_USERPTR;
  145.  
  146.                 if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
  147.                         switch (errno) {
  148.                         case EAGAIN:
  149.                                 return 0;
  150.  
  151.                         case EIO:
  152.                         /* Could ignore EIO, see spec. */
  153.  
  154.                         /* fall through */
  155.  
  156.                         default:
  157.                                 errno_exit("VIDIOC_DQBUF");
  158.                         }
  159.                 }
  160.  
  161.                 for (i = 0; i < n_buffers; ++i)
  162.                         if (buf.m.userptr == (unsigned long)buffers[i].start
  163.                             && buf.length == buffers[i].length)
  164.                                 break;
  165.  
  166.                 assert(i < n_buffers);
  167.  
  168.                 process_image((void *)buf.m.userptr, buf.bytesused);
  169.  
  170.                 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  171.                         errno_exit("VIDIOC_QBUF");
  172.                 break;
  173.         }
  174.  
  175.         return 1;
  176. }
  177.  
  178. static void mainloop(void)
  179. {
  180.         unsigned int count;
  181.         unsigned int loopIsInfinite = 0;
  182.  
  183.         if (frame_count == 0) loopIsInfinite = 1; //infinite loop
  184.         count = frame_count;
  185.  
  186.         while ((count-- > 0) || loopIsInfinite) {
  187.                 for (;; ) {
  188.                         fd_set fds;
  189.                         struct timeval tv;
  190.                         int r;
  191.  
  192.                         FD_ZERO(&fds);
  193.                         FD_SET(fd, &fds);
  194.  
  195.                         /* Timeout. */
  196.                         tv.tv_sec = 2;
  197.                         tv.tv_usec = 0;
  198.  
  199.                         r = select(fd + 1, &fds, NULL, NULL, &tv);
  200.  
  201.                         if (-1 == r) {
  202.                                 if (EINTR == errno)
  203.                                         continue;
  204.                                 errno_exit("select");
  205.                         }
  206.  
  207.                         if (0 == r) {
  208.                                 fprintf(stderr, "select timeoutn");
  209.                                 exit(EXIT_FAILURE);
  210.                         }
  211.  
  212.                         if (read_frame())
  213.                                 break;
  214.                         /* EAGAIN - continue select loop. */
  215.                 }
  216.         }
  217. }
  218.  
  219. static void stop_capturing(void)
  220. {
  221.         enum v4l2_buf_type type;
  222.  
  223.         switch (io) {
  224.         case IO_METHOD_READ:
  225.                 /* Nothing to do. */
  226.                 break;
  227.  
  228.         case IO_METHOD_MMAP:
  229.         case IO_METHOD_USERPTR:
  230.                 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  231.                 if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
  232.                         errno_exit("VIDIOC_STREAMOFF");
  233.                 break;
  234.         }
  235. }
  236.  
  237. static void start_capturing(void)
  238. {
  239.         unsigned int i;
  240.         enum v4l2_buf_type type;
  241.  
  242.         switch (io) {
  243.         case IO_METHOD_READ:
  244.                 /* Nothing to do. */
  245.                 break;
  246.  
  247.         case IO_METHOD_MMAP:
  248.                 for (i = 0; i < n_buffers; ++i) {
  249.                         struct v4l2_buffer buf;
  250.  
  251.                         CLEAR(buf);
  252.                         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  253.                         buf.memory = V4L2_MEMORY_MMAP;
  254.                         buf.index = i;
  255.  
  256.                         if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  257.                                 errno_exit("VIDIOC_QBUF");
  258.                 }
  259.                 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  260.                 if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
  261.                         errno_exit("VIDIOC_STREAMON");
  262.                 break;
  263.  
  264.         case IO_METHOD_USERPTR:
  265.                 for (i = 0; i < n_buffers; ++i) {
  266.                         struct v4l2_buffer buf;
  267.  
  268.                         CLEAR(buf);
  269.                         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  270.                         buf.memory = V4L2_MEMORY_USERPTR;
  271.                         buf.index = i;
  272.                         buf.m.userptr = (unsigned long)buffers[i].start;
  273.                         buf.length = buffers[i].length;
  274.  
  275.                         if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  276.                                 errno_exit("VIDIOC_QBUF");
  277.                 }
  278.                 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  279.                 if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
  280.                         errno_exit("VIDIOC_STREAMON");
  281.                 break;
  282.         }
  283. }
  284.  
  285. static void uninit_device(void)
  286. {
  287.         unsigned int i;
  288.  
  289.         switch (io) {
  290.         case IO_METHOD_READ:
  291.                 free(buffers[0].start);
  292.                 break;
  293.  
  294.         case IO_METHOD_MMAP:
  295.                 for (i = 0; i < n_buffers; ++i)
  296.                         if (-1 == munmap(buffers[i].start, buffers[i].length))
  297.                                 errno_exit("munmap");
  298.                 break;
  299.  
  300.         case IO_METHOD_USERPTR:
  301.                 for (i = 0; i < n_buffers; ++i)
  302.                         free(buffers[i].start);
  303.                 break;
  304.         }
  305.  
  306.         free(buffers);
  307. }
  308.  
  309. static void init_read(unsigned int buffer_size)
  310. {
  311.         buffers = calloc(1, sizeof(*buffers));
  312.  
  313.         if (!buffers) {
  314.                 fprintf(stderr, "Out of memoryn");
  315.                 exit(EXIT_FAILURE);
  316.         }
  317.  
  318.         buffers[0].length = buffer_size;
  319.         buffers[0].start = malloc(buffer_size);
  320.  
  321.         if (!buffers[0].start) {
  322.                 fprintf(stderr, "Out of memoryn");
  323.                 exit(EXIT_FAILURE);
  324.         }
  325. }
  326.  
  327. static void init_mmap(void)
  328. {
  329.         struct v4l2_requestbuffers req;
  330.  
  331.         CLEAR(req);
  332.  
  333.         req.count = 4;
  334.         req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  335.         req.memory = V4L2_MEMORY_MMAP;
  336.  
  337.         if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
  338.                 if (EINVAL == errno) {
  339.                         fprintf(stderr, "%s does not support "
  340.                                 "memory mappingn", dev_name);
  341.                         exit(EXIT_FAILURE);
  342.                 } else {
  343.                         errno_exit("VIDIOC_REQBUFS");
  344.                 }
  345.         }
  346.  
  347.         if (req.count < 2) {
  348.                 fprintf(stderr, "Insufficient buffer memory on %sn",
  349.                         dev_name);
  350.                 exit(EXIT_FAILURE);
  351.         }
  352.  
  353.         buffers = calloc(req.count, sizeof(*buffers));
  354.  
  355.         if (!buffers) {
  356.                 fprintf(stderr, "Out of memoryn");
  357.                 exit(EXIT_FAILURE);
  358.         }
  359.  
  360.         for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
  361.                 struct v4l2_buffer buf;
  362.  
  363.                 CLEAR(buf);
  364.  
  365.                 buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  366.                 buf.memory      = V4L2_MEMORY_MMAP;
  367.                 buf.index       = n_buffers;
  368.  
  369.                 if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
  370.                         errno_exit("VIDIOC_QUERYBUF");
  371.  
  372.                 buffers[n_buffers].length = buf.length;
  373.                 buffers[n_buffers].start =
  374.                         mmap(NULL /* start anywhere */,
  375.                              buf.length,
  376.                              PROT_READ | PROT_WRITE /* required */,
  377.                              MAP_SHARED /* recommended */,
  378.                              fd, buf.m.offset);
  379.  
  380.                 if (MAP_FAILED == buffers[n_buffers].start)
  381.                         errno_exit("mmap");
  382.         }
  383. }
  384.  
  385. static void init_userp(unsigned int buffer_size)
  386. {
  387.         struct v4l2_requestbuffers req;
  388.  
  389.         CLEAR(req);
  390.  
  391.         req.count  = 4;
  392.         req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  393.         req.memory = V4L2_MEMORY_USERPTR;
  394.  
  395.         if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
  396.                 if (EINVAL == errno) {
  397.                         fprintf(stderr, "%s does not support "
  398.                                 "user pointer i/on", dev_name);
  399.                         exit(EXIT_FAILURE);
  400.                 } else {
  401.                         errno_exit("VIDIOC_REQBUFS");
  402.                 }
  403.         }
  404.  
  405.         buffers = calloc(4, sizeof(*buffers));
  406.  
  407.         if (!buffers) {
  408.                 fprintf(stderr, "Out of memoryn");
  409.                 exit(EXIT_FAILURE);
  410.         }
  411.  
  412.         for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
  413.                 buffers[n_buffers].length = buffer_size;
  414.                 buffers[n_buffers].start = malloc(buffer_size);
  415.  
  416.                 if (!buffers[n_buffers].start) {
  417.                         fprintf(stderr, "Out of memoryn");
  418.                         exit(EXIT_FAILURE);
  419.                 }
  420.         }
  421. }
  422.  
  423. static void init_device(void)
  424. {
  425.         struct v4l2_capability cap;
  426.         struct v4l2_cropcap cropcap;
  427.         struct v4l2_crop crop;
  428.         struct v4l2_format fmt;
  429.         unsigned int min;
  430.  
  431.         if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
  432.                 if (EINVAL == errno) {
  433.                         fprintf(stderr, "%s is no V4L2 devicen",
  434.                                 dev_name);
  435.                         exit(EXIT_FAILURE);
  436.                 } else {
  437.                         errno_exit("VIDIOC_QUERYCAP");
  438.                 }
  439.         }
  440.  
  441.         if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
  442.                 fprintf(stderr, "%s is no video capture devicen",
  443.                         dev_name);
  444.                 exit(EXIT_FAILURE);
  445.         }
  446.  
  447.         switch (io) {
  448.         case IO_METHOD_READ:
  449.                 if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
  450.                         fprintf(stderr, "%s does not support read i/on",
  451.                                 dev_name);
  452.                         exit(EXIT_FAILURE);
  453.                 }
  454.                 break;
  455.  
  456.         case IO_METHOD_MMAP:
  457.         case IO_METHOD_USERPTR:
  458.                 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
  459.                         fprintf(stderr, "%s does not support streaming i/on",
  460.                                 dev_name);
  461.                         exit(EXIT_FAILURE);
  462.                 }
  463.                 break;
  464.         }
  465.  
  466.  
  467.         /* Select video input, video standard and tune here. */
  468.  
  469.  
  470.         CLEAR(cropcap);
  471.  
  472.         cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  473.  
  474.         if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
  475.                 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  476.                 crop.c = cropcap.defrect; /* reset to default */
  477.  
  478.                 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
  479.                         switch (errno) {
  480.                         case EINVAL:
  481.                                 /* Cropping not supported. */
  482.                                 break;
  483.                         default:
  484.                                 /* Errors ignored. */
  485.                                 break;
  486.                         }
  487.                 }
  488.         } else {
  489.                 /* Errors ignored. */
  490.         }
  491.  
  492.  
  493.         CLEAR(fmt);
  494.  
  495.         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  496.         fprintf(stderr, "Force Format %dn", force_format);
  497.         if (force_format) {
  498.                 if (force_format==2){
  499.                              fmt.fmt.pix.width       = 1920;     
  500.                            fmt.fmt.pix.height      = 1080;  
  501.                           fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
  502.                         fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
  503.                 }
  504.                 else if(force_format==1){
  505.                         fmt.fmt.pix.width        = 640;
  506.                         fmt.fmt.pix.height        = 480;
  507.                         fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  508.                         fmt.fmt.pix.field        = V4L2_FIELD_INTERLACED;
  509.                 }
  510.  
  511.                 if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
  512.                         errno_exit("VIDIOC_S_FMT");
  513.  
  514.                 /* Note VIDIOC_S_FMT may change width and height. */
  515.         } else {
  516.                 /* Preserve original settings as set by v4l2-ctl for example */
  517.                 if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
  518.                         errno_exit("VIDIOC_G_FMT");
  519.         }
  520.  
  521.         /* Buggy driver paranoia. */
  522.         min = fmt.fmt.pix.width * 2;
  523.         if (fmt.fmt.pix.bytesperline < min)
  524.                 fmt.fmt.pix.bytesperline = min;
  525.         min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
  526.         if (fmt.fmt.pix.sizeimage < min)
  527.                 fmt.fmt.pix.sizeimage = min;
  528.  
  529.         switch (io) {
  530.         case IO_METHOD_READ:
  531.                 init_read(fmt.fmt.pix.sizeimage);
  532.                 break;
  533.  
  534.         case IO_METHOD_MMAP:
  535.                 init_mmap();
  536.                 break;
  537.  
  538.         case IO_METHOD_USERPTR:
  539.                 init_userp(fmt.fmt.pix.sizeimage);
  540.                 break;
  541.         }
  542. }
  543.  
  544. static void close_device(void)
  545. {
  546.         if (-1 == close(fd))
  547.                 errno_exit("close");
  548.  
  549.         fd = -1;
  550. }
  551.  
  552. static void open_device(void)
  553. {
  554.         struct stat st;
  555.  
  556.         if (-1 == stat(dev_name, &st)) {
  557.                 fprintf(stderr, "Cannot identify '%s': %d, %sn",
  558.                         dev_name, errno, strerror(errno));
  559.                 exit(EXIT_FAILURE);
  560.         }
  561.  
  562.         if (!S_ISCHR(st.st_mode)) {
  563.                 fprintf(stderr, "%s is no devicen", dev_name);
  564.                 exit(EXIT_FAILURE);
  565.         }
  566.  
  567.         fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
  568.  
  569.         if (-1 == fd) {
  570.                 fprintf(stderr, "Cannot open '%s': %d, %sn",
  571.                         dev_name, errno, strerror(errno));
  572.                 exit(EXIT_FAILURE);
  573.         }
  574. }
  575.  
复制代码


      编写好的代码,可以参照例程工程里的Makefile文件,编写编译脚本,进入GL2编译环境下,进行编译调试(省去调试修改代码xxx字)最后把编译好的程序上传到开发板上,启动运行如下;
v4l2capture-m save -d /dev/video0 -t usb -F YUYV -w 640 -h 480 -f 15 -o/home/root/test.yuv -n 300
参数含义如下:
-d 选择采集设备
-t usb采集
-F 采集视频色彩数据组织格式,YUYV对应的ffmpeg里就是 YUV422格式
-w 采集视频画面长度,这个宽度必须是采集设备支持的规格表里的参数
-h 采集视频画面高度,同上需要满足视频规格标准
-f 采集帧率,必须是视频采集支持的规格
-o 输出文件
-n 采集帧数
开发板试用
 
图14
      采集完成后,将yuv数据上传到windows下,使用GL2工具包下的tools目录下的YUV Player.exe,播放,因为yuv文件不记录视频的长宽,以及格式信息,所以需要在yuv播放器中需要配置正确的尺寸,和视频格式信息,才能正确的播出。
开发板试用
 
图15
      文末放了两段视频,一段是是手机拍摄,拍摄启动采集程序和移动摄像头的过程。另外一段视频为采集到的yuv数据上传到Ubuntu主机后,经过转换和编码生成mp4,可以看摄像头到实际采集到的画面效果。

六、视频采集开发测评总结       通过对Logitech C270 摄像头的视频采集开发测试来看,RZGL2开发板支持视频采集功能很完善,支持V4L2,FFMPEG这样常用的音视频处理框架,使得很多音视频应用移植起来成为可能,也比较简单。
      从采集到的视频看,采集速率较高,支持视频的规格也很广。这为后面开发提供很好的基础,在后面较长时间(>60分钟)的视频采集测试中,采集程序和系统运行非常稳定,没有出现异常中断等现象,并且在持续视频采集中,触摸CPU感觉升温不明显,这也可以看该处理优良的功耗表现。


摄像头采集到的视频回放,开发板体验视频详见作者原帖子


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分