0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

开发板试用精选 来源:开发板试用 作者:电子发烧友论坛 2022-10-24 17:01 次阅读

本文来源电子发烧友社区,作者: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应该能够开发出多种音视频应用,比如视频的采集编码,视频直播,电视电话会议,视频实时处理等。
poYBAGMQ1T6ACCNLABDWcy96wsw771.png
图1
二、配置开发网络环境
在前面的测试中已经建立基本的串口调试环境。为了后面更方便的在主机与开发板间传送文件,还需要建立开发板和主机的网络通讯,以便通过主机对开发板下载和上传文件。这里主机的开发环境是基于Windows 10操作系统的Ubuntu虚机系统,在Win10上安装vmware 虚机和串口超级终端,vmware里安装了 uBuntu18.4版本的linux环境。
在启动开发板之后,使用ifconfig 命令查看网络配置,可见网卡都不通,因此需要进行网络配置。
首先把一条有线网络插入到开发板的网口中,其中下图左边的网口对应的是系统里的eth0, 右侧的网口对应的是 eth1
pYYBAGMQ1T-AXUSCABCcvfh5ygk725.png
图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
poYBAGMQ1UGAG9n6AADJo-EOzKA871.png
图3
配置完后,重启开发板,再使用ifconfig查看网络设备,eth0设备已经有IP地址,并且检查ping是否能连通通外部主机。同时通过SecureCRT建立SSH登录,也能够顺利登录开发板了。
poYBAGMQ1UKAbFP4AAE2fQv8K9o621.png
图4
三、连接检查网络摄像头 因为手边暂时没有MIPI CSI的摄像头器件。因此查看开发板文档,开发板系统是一个标准的ARMLinux 4.19系统,那么它就可以支持uvcamera, 因此找了一款通用型的网络摄像头Logitech Webcam C270 USB网络摄像头作为视频采集的设备,把摄像头插入开发板的USB口,检测开发板是否能够支持该摄像头,。连接好摄像头后,进入系统查看驱动加载信息
pYYBAGMQ1UKAcGd3AABjO6dnYLA819.png
图5查看系统的版本
pYYBAGMQ1UOAfzUxABBRXaQAX8Q964.png
图6 连接USB摄像头
SecureCRT工具里进入开发板环境里,查看USB总线信息以及开发板USB设备信息如下图:
poYBAGMQ1USAAL3wAAD1xPEgRp0120.png
图7
poYBAGMQ1UWADydJAAEmm5KKrqM427.png
图8
从系统设备驱动加载信息上看,开发板已经为这个摄像头识别出 audio 和 uvcvideo 设备,并成功加载驱动。
使用查看USB设备详细驱动参数命令,可查看到连入开发板的所有USB设备,以及连接位置,USB总线结构等信息。进一步查看摄像头所对应的USB设备号和相关参数,如下图红色圈设备即为该摄像头设备,记下这些参数,后面软件开发时需要,否则程序将不能正确的采集到视频画面。
usb-devices
pYYBAGMQ1UaAHuvXAAJ6g5AEdYg336.png
图9

四、检测摄像头支持的采集视频规格 连接好开发板和USB摄像头后,还需要获得开发板支持这款摄像头对视频采集的规格,不同摄像头采集的规则并不相同,不同开发板支持采集的规格也不同,因此需要对当前的硬件连接做一下摄像头视频支持规则检测。
可采集视频规格检测代码在网上就有,在github上搜索Vv4l2_apture c++ 开源工程,即可以到该原始工程,git下载到主机环境中,然后根据板子的SDK,开始修改…(此处省去代码修改的一万字),主要是修改相关参数和函数。
https://github.com/soramimi/v4l2capture
poYBAGMQ1UiAWFY3AAGR-0O-oew318.png
图10
pYYBAGMQ1UmAHcvgAAU5hRmkdV8698.png
图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高频头设备接收来的音频流.
pYYBAGMQ1UuAWkfcAACdboRPmxE574.png
图12
poYBAGMQ1U2AFc7uAAaps5GQXb8153.png
图13
代码比较长,这里放出修改的部分关键代码如下:



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


编写好的代码,可以参照例程工程里的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 采集帧数
poYBAGMQ1U-AMoufAACEjrdFPOw460.png
图14
采集完成后,将yuv数据上传到windows下,使用GL2工具包下的tools目录下的YUV Player.exe,播放,因为yuv文件不记录视频的长宽,以及格式信息,所以需要在yuv播放器中需要配置正确的尺寸,和视频格式信息,才能正确的播出。
pYYBAGMQ1VCAFTW4AA16ZBunvMw979.png
图15
文末放了两段视频,一段是是手机拍摄,拍摄启动采集程序和移动摄像头的过程。另外一段视频为采集到的yuv数据上传到Ubuntu主机后,经过转换和编码生成mp4,可以看摄像头到实际采集到的画面效果。

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


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


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

    关注

    0

    文章

    130

    浏览量

    15955
  • 开发板试用
    +关注

    关注

    3

    文章

    299

    浏览量

    1904
收藏 人收藏

    评论

    相关推荐

    OK113i-S开发板试用】开机测评--硬件篇

    OK113i-S开发板试用】开机测评--硬件篇 一,开箱见图 包装精致 注意:上面红黄的先是本人接上的 配了电源线和一根usb线一根天
    发表于 12-24 20:51

    AM6254开发板试用】 4-机器视觉(原创)

    /jishu_2374537_1_1.html 【AM6254开发板试用】+2机器视觉环境搭建(原创) -
    发表于 09-12 22:57

    【米尔瑞萨RZ/G2L开发板-试用体验】认识一下米尔瑞萨RZ/G2L开发板的核心

    收到米尔瑞萨RZ/G2L开发板后一直对米尔旗下开发板的做工感到非常精致,同时也有着很强大的功能,也一直很喜欢米尔系列开发板。 引领工业市场从
    发表于 07-29 00:21

    【米尔瑞萨RZ/G2L开发板-试用体验】米尔瑞萨RZ/G2L开发板使用SSH登录

    收到的米尔瑞萨RZ/G2L开发板上电测试一下SSH登录方式和其它测试! SSH登录 在使用之前,需要事先连接网络,笔者这里使用的是以太网,事先需要使用串口的登录,然后输入以下命令查看IP地址
    发表于 06-11 21:47

    【米尔瑞萨RZ/G2L开发板-试用体验】创建TCP服务器

    在米尔RZ/G2L开发板上用C 创建TCP服务器
    的头像 发表于 05-27 08:59 7492次阅读
    【米尔瑞萨<b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b><b class='flag-5'>开发板</b>-<b class='flag-5'>试用</b>体验】创建TCP服务器

    米尔瑞萨RZ/G2L开发板 安装交叉编译器

    米尔瑞萨RZ/G2L开发板安装交叉编译器
    的头像 发表于 05-26 22:05 1702次阅读
    米尔瑞萨<b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b><b class='flag-5'>开发板</b> 安装交叉编译器

    150套开发板免费送!还有5G手机拿?米尔RZ/G2L开发板创意秀

    人间最美五月天不负韶华不负卿米尔又来送板子了不是3套,也不是4套150套米尔RZ/G2L开发板送!免费!板卡不回收!01这是什么样的有奖活动?米尔RZ/
    的头像 发表于 05-25 10:42 323次阅读
    150套<b class='flag-5'>开发板</b>免费送!还有5G手机拿?米尔<b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b><b class='flag-5'>开发板</b>创意秀

    150套开发板免费送!还有5G手机拿?米尔RZ/G2L开发板创意秀

    150套开发板支持开发者创新开发开发者只需要提供项目需求申请即有机会获得RZ/G2L
    发表于 05-24 16:36

    【米尔瑞萨RZ/G2L开发板-试用体验】米尔瑞萨RZ/G2L开发板开箱视频

    今天刚刚收到米尔瑞萨RZ/G2L开发板,拆开包裹后给人的感觉是惊艳,板卡设计真的很棒,来看看视频做个简单了解吧。 更多板卡可以登录官网了解哦。https://www.myi
    发表于 05-22 21:58

    【米尔瑞萨RZ/G2L开发板-试用体验】米尔-瑞萨RZG2L - 64位双核MPU开发板开箱测评

    刚收到米尔瑞萨RZ/G2L开发板打开包装后看到的很大的一块黑色PCB,做工精美的开发板,给人眼前一亮的感觉。 首先来介绍以下这家公司: 深圳市米尔电子有限公司,是一家专注于嵌入式处理器
    发表于 05-22 21:53

    【米尔瑞萨RZ/G2L开发板-试用体验】LCD 显示测试

    实验器材 1、米尔瑞萨RZ/G2L开发板 2、MY-TFT070-K显示屏 实现步骤 1、连接开发板与显示屏,这次配的数据线有点特殊,大家一
    发表于 05-22 19:26

    米尔瑞萨RZ/G2L开发板 TF卡读写速度测试

    米尔瑞萨RZ/G2L开发板TF卡读写测试
    的头像 发表于 05-22 09:07 1000次阅读
    米尔瑞萨<b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b><b class='flag-5'>开发板</b> TF卡读写速度测试

    【米尔瑞萨RZ/G2L开发板-试用体验】开箱 + 开机

    感谢 感谢电子发烧友论坛、感谢米尔电子,把米尔瑞萨RZ/G2L开发板试用话动的机会给了我。最近事情比较多,赶在这个空挡时间完成开箱报告。 开
    发表于 05-18 19:33

    米尔瑞萨RZ/G2L开发板-初体验

    介绍米尔RZ/G2L开发板
    的头像 发表于 05-15 09:10 695次阅读
    米尔瑞萨<b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b><b class='flag-5'>开发板</b>-初体验

    【米尔瑞萨RZ/G2L开发板-试用体验】开箱

    感谢 感谢电子发烧友论坛、感谢米尔电子,把米尔瑞萨RZ/G2L开发板试用话动的机会给了我。虽然周五就收到了开发板,但是由于复阳了,为了能及时
    发表于 05-14 19:41