0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【飛凌RZ/G2L開發(fā)板試用體驗(yàn)】飛凌RZ/G2L的開發(fā)板試用測評報告二 — 視頻采集開發(fā)

開發(fā)板試用精選 ? 來源:開發(fā)板試用 ? 作者:電子發(fā)燒友論壇 ? 2022-10-24 17:01 ? 次閱讀

本文來源電子發(fā)燒友社區(qū),作者:ALSET, 帖子地址:https://bbs.elecfans.com/jishu_2303429_1_1.html


測試攝像頭采集視頻數(shù)據(jù)

飛凌RZ/G2L的開發(fā)板試用測評報告二 — 視頻采集開發(fā)

大信(QQ:8125036)
電子發(fā)燒友論壇上看到飛凌RZ/G2L的開發(fā)板介紹,其優(yōu)秀的高性能低能耗引起我的興趣,在結(jié)合其強(qiáng)大的音視頻能力,感覺該開發(fā)板非常適合開發(fā)音視頻產(chǎn)品,就申請?jiān)囉?,很快很幸運(yùn)得拿到這塊開發(fā)板進(jìn)行試用,通過個把月的試用與探索,基本了解了開發(fā)板的基本功能,性能,接口以及開發(fā)環(huán)境等,這里就進(jìn)一步結(jié)合該開發(fā)板強(qiáng)大的音視頻功能,針對一些音視頻基礎(chǔ)功能的開發(fā)與測試。

一、硬件音視頻能力了解

OK-G2LD-C開發(fā)板擁有豐富的多媒體資源,支持多種顯示、攝像頭、音頻接口,滿足多場景下的人機(jī)交互和圖像采集需求;核心板同時配備500MHz 3D GPU Mali-G31,支持Vulkan、OpenGL、OpenCL,同時VPU支持1080P高清顯示,可進(jìn)行H.264 1080P分辨率的硬件編解碼。
同時板子帶有2個有線網(wǎng)口和wifi無線網(wǎng)絡(luò),這也給音視頻實(shí)時傳輸提供了硬件基礎(chǔ)。
因此基于RZG2l應(yīng)該能夠開發(fā)出多種音視頻應(yīng)用,比如視頻的采集編碼,視頻直播,電視電話會議,視頻實(shí)時處理等。
poYBAGMQ1T6ACCNLABDWcy96wsw771.png
圖1
二、配置開發(fā)網(wǎng)絡(luò)環(huán)境
在前面的測試中已經(jīng)建立基本的串口調(diào)試環(huán)境。為了后面更方便的在主機(jī)與開發(fā)板間傳送文件,還需要建立開發(fā)板和主機(jī)的網(wǎng)絡(luò)通訊,以便通過主機(jī)對開發(fā)板下載和上傳文件。這里主機(jī)的開發(fā)環(huán)境是基于Windows 10操作系統(tǒng)的Ubuntu虛機(jī)系統(tǒng),在Win10上安裝vmware 虛機(jī)和串口超級終端,vmware里安裝了 uBuntu18.4版本的linux環(huán)境。
在啟動開發(fā)板之后,使用ifconfig 命令查看網(wǎng)絡(luò)配置,可見網(wǎng)卡都不通,因此需要進(jìn)行網(wǎng)絡(luò)配置。
首先把一條有線網(wǎng)絡(luò)插入到開發(fā)板的網(wǎng)口中,其中下圖左邊的網(wǎng)口對應(yīng)的是系統(tǒng)里的eth0, 右側(cè)的網(wǎng)口對應(yīng)的是 eth1
pYYBAGMQ1T-AXUSCABCcvfh5ygk725.png
圖2
插好網(wǎng)線后,進(jìn)入系統(tǒng)網(wǎng)口配置文件所在目錄:
cd /etc/systemd/network
打開10-eth.network 文件
vim 10-eth.network
根據(jù)自己網(wǎng)絡(luò)段,配置好開發(fā)板的地址,這里使用的靜態(tài)地址,在與主機(jī)相同網(wǎng)段內(nèi)找一個空閑的IP地址,配置上即可,這樣避免動態(tài)地址分配,導(dǎo)致每次重啟可能會造成地址改變,帶來不必要的麻煩。
[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
配置完后,重啟開發(fā)板,再使用ifconfig查看網(wǎng)絡(luò)設(shè)備,eth0設(shè)備已經(jīng)有IP地址,并且檢查ping是否能連通通外部主機(jī)。同時通過SecureCRT建立SSH登錄,也能夠順利登錄開發(fā)板了。
poYBAGMQ1UKAbFP4AAE2fQv8K9o621.png
圖4
三、連接檢查網(wǎng)絡(luò)攝像頭 因?yàn)槭诌厱簳r沒有MIPI CSI的攝像頭器件。因此查看開發(fā)板文檔,開發(fā)板系統(tǒng)是一個標(biāo)準(zhǔn)的ARMLinux 4.19系統(tǒng),那么它就可以支持uvcamera, 因此找了一款通用型的網(wǎng)絡(luò)攝像頭Logitech Webcam C270 USB網(wǎng)絡(luò)攝像頭作為視頻采集的設(shè)備,把攝像頭插入開發(fā)板的USB口,檢測開發(fā)板是否能夠支持該攝像頭,。連接好攝像頭后,進(jìn)入系統(tǒng)查看驅(qū)動加載信息
pYYBAGMQ1UKAcGd3AABjO6dnYLA819.png
圖5查看系統(tǒng)的版本
pYYBAGMQ1UOAfzUxABBRXaQAX8Q964.png
圖6 連接USB攝像頭
SecureCRT工具里進(jìn)入開發(fā)板環(huán)境里,查看USB總線信息以及開發(fā)板USB設(shè)備信息如下圖:
poYBAGMQ1USAAL3wAAD1xPEgRp0120.png
圖7
poYBAGMQ1UWADydJAAEmm5KKrqM427.png
圖8
從系統(tǒng)設(shè)備驅(qū)動加載信息上看,開發(fā)板已經(jīng)為這個攝像頭識別出 audio 和 uvcvideo 設(shè)備,并成功加載驅(qū)動。
使用查看USB設(shè)備詳細(xì)驅(qū)動參數(shù)命令,可查看到連入開發(fā)板的所有USB設(shè)備,以及連接位置,USB總線結(jié)構(gòu)等信息。進(jìn)一步查看攝像頭所對應(yīng)的USB設(shè)備號和相關(guān)參數(shù),如下圖紅色圈設(shè)備即為該攝像頭設(shè)備,記下這些參數(shù),后面軟件開發(fā)時需要,否則程序?qū)⒉荒苷_的采集到視頻畫面。
usb-devices
pYYBAGMQ1UaAHuvXAAJ6g5AEdYg336.png
圖9

四、檢測攝像頭支持的采集視頻規(guī)格 連接好開發(fā)板和USB攝像頭后,還需要獲得開發(fā)板支持這款攝像頭對視頻采集的規(guī)格,不同攝像頭采集的規(guī)則并不相同,不同開發(fā)板支持采集的規(guī)格也不同,因此需要對當(dāng)前的硬件連接做一下攝像頭視頻支持規(guī)則檢測。
可采集視頻規(guī)格檢測代碼在網(wǎng)上就有,在github上搜索Vv4l2_apture c++ 開源工程,即可以到該原始工程,git下載到主機(jī)環(huán)境中,然后根據(jù)板子的SDK,開始修改…(此處省去代碼修改的一萬字),主要是修改相關(guān)參數(shù)和函數(shù)。
https://github.com/soramimi/v4l2capture
poYBAGMQ1UiAWFY3AAGR-0O-oew318.png
圖10
pYYBAGMQ1UmAHcvgAAU5hRmkdV8698.png
圖11
經(jīng)過修改調(diào)試代碼后,最后在板上成功的運(yùn)行,并輸出開發(fā)板對攝像頭支持的格式列表,如下:
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


五、采集程序開發(fā)測試 獲得攝像頭的設(shè)備參數(shù)以及能夠采集的視頻規(guī)格參數(shù)以后,就可以開發(fā)視頻采集程序,在開發(fā)采集程序前,還需要查看一下攝像頭的用戶層抽象操作設(shè)備,一般在/dev/下,使用以下命令查看抽象出的設(shè)備文件:
ls –ls /dev/video*
可以看到抽象的視頻采集設(shè)備,后面將試用設(shè)備控制代碼來打開操作它。
另外在看一下采集設(shè)備對 v4l2 系統(tǒng)的驅(qū)動,命令如下:
ls -l/sys/class/video4linux/video*
這兩個命令是在攝像頭底層驅(qū)動加載工作正常后才會出現(xiàn),如果底層驅(qū)動有任何問題,這兩個命令將不會有相應(yīng)信息顯示。
采集視頻采用的是V4L2視頻框架。V4L2是Video for linux2的簡稱,為linux中關(guān)于視頻設(shè)備的內(nèi)核驅(qū)動。在Linux中視頻設(shè)備是設(shè)備文件,可以像訪問普通文件一樣對其進(jìn)行讀寫,攝像頭在/dev/video*下,如果只有一個視頻設(shè)備,通常為/dev/video0。V4L2在設(shè)計時,是能支持很多廣泛的設(shè)備,但它們之中只有一部分是真正的視頻設(shè)備:
可以支持多種設(shè)備,它可以有以下幾種接口:
1. 視頻采集接口(video capture interface):這種應(yīng)用的設(shè)備可以是高頻頭或者攝像頭.V4L2的最初設(shè)計就是應(yīng)用于這種功能的.
2. 視頻輸出接口(video output interface):可以驅(qū)動計算機(jī)的外圍視頻圖像設(shè)備--像可以輸出電視信號格式的設(shè)備.
3. 直接傳輸視頻接口(video overlay interface):它的主要工作是把從視頻采集設(shè)備采集過來的信號直接輸出到輸出設(shè)備之上,而不用經(jīng)過系統(tǒng)的CPU.
4. 視頻間隔消隱信號接口(VBI interface):它可以使應(yīng)用可以訪問傳輸消隱期的視頻信號.
5. 收音機(jī)接口(radio interface):可用來處理從AM或FM高頻頭設(shè)備接收來的音頻流.
pYYBAGMQ1UuAWkfcAACdboRPmxE574.png
圖12
poYBAGMQ1U2AFc7uAAaps5GQXb8153.png
圖13
代碼比較長,這里放出修改的部分關(guān)鍵代碼如下:



  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. }
復(fù)制代碼


編寫好的代碼,可以參照例程工程里的Makefile文件,編寫編譯腳本,進(jìn)入GL2編譯環(huán)境下,進(jìn)行編譯調(diào)試(省去調(diào)試修改代碼xxx字)最后把編譯好的程序上傳到開發(fā)板上,啟動運(yùn)行如下;
v4l2capture-m save -d /dev/video0 -t usb -F YUYV -w 640 -h 480 -f 15 -o/home/root/test.yuv -n 300
參數(shù)含義如下:
-d 選擇采集設(shè)備
-t usb采集
-F 采集視頻色彩數(shù)據(jù)組織格式,YUYV對應(yīng)的ffmpeg里就是 YUV422格式
-w 采集視頻畫面長度,這個寬度必須是采集設(shè)備支持的規(guī)格表里的參數(shù)
-h 采集視頻畫面高度,同上需要滿足視頻規(guī)格標(biāo)準(zhǔn)
-f 采集幀率,必須是視頻采集支持的規(guī)格
-o 輸出文件
-n 采集幀數(shù)
poYBAGMQ1U-AMoufAACEjrdFPOw460.png
圖14
采集完成后,將yuv數(shù)據(jù)上傳到windows下,使用GL2工具包下的tools目錄下的YUV Player.exe,播放,因?yàn)閥uv文件不記錄視頻的長寬,以及格式信息,所以需要在yuv播放器中需要配置正確的尺寸,和視頻格式信息,才能正確的播出。
pYYBAGMQ1VCAFTW4AA16ZBunvMw979.png
圖15
文末放了兩段視頻,一段是是手機(jī)拍攝,拍攝啟動采集程序和移動攝像頭的過程。另外一段視頻為采集到的yuv數(shù)據(jù)上傳到Ubuntu主機(jī)后,經(jīng)過轉(zhuǎn)換和編碼生成mp4,可以看攝像頭到實(shí)際采集到的畫面效果。

六、視頻采集開發(fā)測評總結(jié) 通過對Logitech C270 攝像頭的視頻采集開發(fā)測試來看,RZGL2開發(fā)板支持視頻采集功能很完善,支持V4L2,F(xiàn)FMPEG這樣常用的音視頻處理框架,使得很多音視頻應(yīng)用移植起來成為可能,也比較簡單。
從采集到的視頻看,采集速率較高,支持視頻的規(guī)格也很廣。這為后面開發(fā)提供很好的基礎(chǔ),在后面較長時間(>60分鐘)的視頻采集測試中,采集程序和系統(tǒng)運(yùn)行非常穩(wěn)定,沒有出現(xiàn)異常中斷等現(xiàn)象,并且在持續(xù)視頻采集中,觸摸CPU感覺升溫不明顯,這也可以看該處理優(yōu)良的功耗表現(xiàn)。


攝像頭采集到的視頻回放,開發(fā)板體驗(yàn)視頻詳見作者原帖子


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 飛凌
    +關(guān)注

    關(guān)注

    0

    文章

    132

    瀏覽量

    16073
  • 開發(fā)板試用
    +關(guān)注

    關(guān)注

    3

    文章

    300

    瀏覽量

    2024
收藏 人收藏

    評論

    相關(guān)推薦

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

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

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

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

    RZ/G2L Demo調(diào)試經(jīng)驗(yàn)流程分享(1)

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

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

    RZ/G2L微處理器配備Cortex?-A55 (1.2 GHz) CPU、16位DDR3L/DDR4接口、帶Arm Mali-G31的3D圖形加速引擎以及
    的頭像 發(fā)表于 02-28 13:44 ?1139次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b>微處理器DDR ECC功能和機(jī)制概要

    【米爾-瑞薩RZ/G2UL開發(fā)板】1.開箱

    【米爾-瑞薩RZ/G2UL開發(fā)板】1.開箱 開箱視頻 開箱也許會遲到,但是絕對不會缺席。今天開箱的是米爾-瑞薩 RZ/
    發(fā)表于 02-04 23:38

    RZ/G2LRZ/G2LC和RZ/G2UL的SMARC EVK啟動指南Rev.1.01

    電子發(fā)燒友網(wǎng)站提供《RZ/G2L、RZ/G2LC和RZ/G2UL的SMARC EVK啟動指南Re
    發(fā)表于 02-02 09:45 ?1次下載
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b>、<b class='flag-5'>RZ</b>/<b class='flag-5'>G2</b>LC和<b class='flag-5'>RZ</b>/<b class='flag-5'>G2</b>UL的SMARC EVK啟動指南Rev.1.01

    米爾RZ/G2L開發(fā)板瑞米派雙核A55Remi Pi學(xué)習(xí)兼容樹莓派擴(kuò)展模塊

    RemiPi瑞薩第一款MPU生態(tài)板卡兼容樹莓派擴(kuò)展模塊瑞薩RZ/G2L工業(yè)級處理器,便于企業(yè)客戶產(chǎn)品開發(fā);RemiPi兼容樹莓派所有配件,方便產(chǎn)品原型搭建和創(chuàng)新應(yīng)用;更多的工業(yè)接口,兼顧開發(fā)
    發(fā)表于 01-29 17:05 ?4次下載

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

    瑞薩RZ/G2L的串口簡稱SCI,全稱Serial Communication Interface。
    的頭像 發(fā)表于 01-17 12:19 ?1329次閱讀
    瑞薩<b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b>串口SCI的使用(上)

    【米爾-瑞薩RZ/G2UL開發(fā)板開發(fā)板開箱與接口介紹

    開發(fā)板簡介 MYC-YG2UL核心開發(fā)板基于RZ/G2UL處理器,通用64位工業(yè)MPU
    發(fā)表于 01-14 13:25

    RZ/G2L RZ/G2LC RZ/G2UL用靈活的軟件包設(shè)置GPIO

    電子發(fā)燒友網(wǎng)站提供《RZ/G2L RZ/G2LC RZ/G2UL用靈活的軟件包設(shè)置GPIO.pd
    發(fā)表于 01-14 10:53 ?0次下載
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b> <b class='flag-5'>RZ</b>/<b class='flag-5'>G2</b>LC <b class='flag-5'>RZ</b>/<b class='flag-5'>G2</b>UL用靈活的軟件包設(shè)置GPIO

    RZ/G2L RZ/G2LC RZ/G2UL RZ/G3S靈活軟件包應(yīng)用說明

    電子發(fā)燒友網(wǎng)站提供《RZ/G2L RZ/G2LC RZ/G2UL
    發(fā)表于 01-14 10:46 ?1次下載
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b> <b class='flag-5'>RZ</b>/<b class='flag-5'>G2</b>LC <b class='flag-5'>RZ</b>/<b class='flag-5'>G2</b>UL <b class='flag-5'>RZ</b>/<b class='flag-5'>G</b>3S靈活軟件包應(yīng)用說明

    RZ/G2L Linux系統(tǒng)如何添加新的內(nèi)核模塊

    RZ/G2L Linux系統(tǒng)的鏡像基于yocto構(gòu)建,本篇介紹如何添加新的內(nèi)核模塊。
    的頭像 發(fā)表于 01-04 12:19 ?1617次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b> Linux系統(tǒng)如何添加新的內(nèi)核模塊

    OK113i-S開發(fā)板試用】開機(jī)測評--軟件測試篇

    OK113i-S開發(fā)板試用】開機(jī)測評--軟件測試篇
    發(fā)表于 12-25 11:03

    OK113i-S開發(fā)板試用】開機(jī)測評--硬件篇

    OK113i-S開發(fā)板試用】開機(jī)測評--硬件篇 一,開箱見圖 包裝精致 注意:上面紅黃的先是本人接上的 配了電源線和一根usb線一根天
    發(fā)表于 12-24 20:51

    RZ/G2L開發(fā)板使用指南(上)

    如果需要評估RZ/G2L產(chǎn)品的各項(xiàng)功能,RZ/G2L評估是最合適的平臺。
    的頭像 發(fā)表于 11-03 12:19 ?988次閱讀
    <b class='flag-5'>RZ</b>/<b class='flag-5'>G2L</b><b class='flag-5'>開發(fā)板</b>使用指南(上)