吴忠躺衫网络科技有限公司

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

    文章

    134

    瀏覽量

    16171
  • 開發板試用
    +關注

    關注

    3

    文章

    301

    瀏覽量

    2147
收藏 人收藏

    評論

    相關推薦

    【ELF 2學習試用】ELF 2開發板開箱測評

    簡介 很高興收到嵌入式提供的ELF 2開發板,ELF 2學習基于瑞芯微RK3588旗艦處理
    發表于 01-15 09:43

    瑞薩電子RZ MPU家族精品RZ/N2L產品介紹

    瑞薩生態合作伙伴RT-Thread推出了一款高性能、多功能以太網MPU開發板EtherKit,搭載瑞薩電子RZ/N2L,并攜手瑞薩電子舉辦了產品發布會和產品研討。瑞薩電子在本次活動中介紹了瑞薩明星
    的頭像 發表于 12-23 14:10 ?142次閱讀
    瑞薩電子<b class='flag-5'>RZ</b> MPU家族精品<b class='flag-5'>RZ</b>/N<b class='flag-5'>2L</b>產品介紹

    嵌入式受邀亮相瑞薩2024工業技術研討會

    嵌入式作為瑞薩電子的生態合作伙伴,給2024瑞薩電子MCU/MPU工業技術研討會的現場觀眾帶去了基于RZ/G2L高性能多核異構處理器設計開發
    的頭像 發表于 12-07 14:27 ?412次閱讀
    <b class='flag-5'>飛</b><b class='flag-5'>凌</b>嵌入式受邀亮相瑞薩2024工業技術研討會

    瑞薩RZ/G2L微處理器的SD卡GPIO控制功能介紹

    RZ/G2L微處理器配備Cortex-A55(1.2 GHz) CPU、16位DDR3L/DDR4接口、帶Arm Mali-G31的3D圖形加速引擎以及
    的頭像 發表于 12-06 10:25 ?1209次閱讀
    瑞薩<b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b>微處理器的SD卡GPIO控制功能介紹

    RZ/G2L高速虛擬串口方案 基于瑞薩RZ/G2L SMARC開發板的虛擬(Virtual UART)實現方案

    RZ/G2L具有豐富的外設,比如千兆以太網,CANFD以及豐富的UART接口,可以滿足工業數據收集處理相關的應用。本文主要介紹基于瑞薩RZ/G2L SMARC
    發表于 11-20 14:41 ?572次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b>高速虛擬串口方案 基于瑞薩<b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b> SMARC<b class='flag-5'>開發板</b>的虛擬(Virtual UART)實現方案

    嵌入式OK3576-C開發板體驗】開箱報告

    簡介 很榮幸參與到本次由嵌入式和電子發燒友提供的OK3576-C開發板試用機會。 嵌入
    發表于 08-22 02:13

    RZ/G2L串口SCI的使用(下)

    RZ/G2L串口SCI的使用
    的頭像 發表于 08-03 08:06 ?565次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b>串口SCI的使用(下)

    RZ/G2L串口SCI的使用(上)

    RZ/G2L串口SCI的使用
    的頭像 發表于 07-25 08:06 ?559次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b>串口SCI的使用(上)

    全志T527開發板buildroot系統下擴大rootfs分區

    一、實驗環境介紹 硬件:T527開發板2G+16G) 軟件:全志Tina sdk 、查看當前存儲分布 登入
    發表于 07-18 14:45

    【米爾-瑞米派兼容樹莓派擴展模塊-試用體驗】值得擁有的米爾-瑞米派兼容樹莓派生態

    今天為大家介紹一塊米爾出的精致生態開發板-米爾-瑞米派兼容樹莓派擴展模塊。 超高性價比的RZ/G2L工業級處理器 RZ/G2L是瑞薩在智
    發表于 05-13 11:28

    RZ/G2L Demo調試經驗流程分享(1)

    r01us0553ej0107-rz-g(Release Note).pdf,r01us0556ej0102-rz-g(Board_StartUp_Guide_smarcEVK).pdf,對SMARC EVK of RZ/
    的頭像 發表于 05-06 14:25 ?738次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b> Demo調試經驗流程分享(1)

    【米爾-瑞米派兼容樹莓派擴展模塊-試用體驗】初始開發板_米爾-瑞米派兼容樹莓派擴展模塊

    開發板,他兼顧了嚴肅產品開發和愛好者創意實現兩種需要。告訴你,選擇它的五大理由: 1.工業芯片:采用瑞薩RZ/G2L雙核A55芯片,芯片是工業級,結溫可達-40到+125度,滿足10
    發表于 04-29 11:42

    RZ/G2L SD卡啟動環境變量存儲設置

    RZ/G2L微處理器配備Cortex-A55(1.2 GHz)CPU、16位DDR3L/DDR4接口、帶Arm Mali-G31的3D圖形加速引擎以及
    的頭像 發表于 03-21 13:56 ?632次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b> SD卡啟動環境變量存儲設置

    瑞薩RZ/V2L預訓練的人工智能模型

    RZ/V2L還與RZ/G2L封裝和引腳兼容。這使得RZ/G2L用戶可輕松升級至
    發表于 03-21 13:51 ?455次閱讀
    瑞薩<b class='flag-5'>RZ</b>/V<b class='flag-5'>2L</b>預訓練的人工智能模型

    RZ/G2L微處理器DDR ECC功能和機制概要

    RZ/G2L微處理器配備Cortex?-A55 (1.2 GHz) CPU、16位DDR3L/DDR4接口、帶Arm Mali-G31的3D圖形加速引擎以及
    的頭像 發表于 02-28 13:44 ?1407次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b>微處理器DDR ECC功能和機制概要
    凤凰百家乐的玩法技巧和规则| 足球百家乐投注计算| 网上赌博| 百家乐傻瓜式投注法| 百家乐官网什么牌最大| 广州太阳城巧克力社区| 百家乐官网百胜注码法| 百家乐赌博博彩赌博网| 百家乐官网赌注| 网上百家乐官网危险| 大发888斗地主| 百家乐赢的秘诀| 百家乐官网任你博娱乐场| 长泰县| 大发8888备用网址| 百家乐娱乐网备用网址| 风水24山图片| 太原百家乐官网招聘| 百家乐官网桌蓝盾在线| 皇冠国际| 大发888casino| 姚记百家乐的玩法技巧和规则| 百家乐经验在哪找| 百家乐官网网络赌城| 达日县| 六合彩码报| 大发888娱乐场and| 芝加哥百家乐的玩法技巧和规则| 杨公24山择日| 百家乐官网奥| A8百家乐官网娱乐场| 百家乐官网翻天粤语快播| 孟州市| 政和县| 网络百家乐官网可靠吗| 大发888真钱游戏平台| 百家乐平游戏| 模拟百家乐下| 百家乐必胜绝| 大发888官网df888| 顶级赌场官网|