在网上找了一个测试程序, 看了看,是根据capture.c修改的。测试步骤如下
1. gcc -o capture_image capture_image.c
2. ctrl+alt+f1 切换到ubuntu的控制台,切换到控制台模式是因为在图形模式下看不到测试图形,这可能和framebuffer的设置有关
3. sudo modprobe vivi
4. sudo ./capture_image -d /dev/video0
这时可以看到在屏幕左上角有一个640x480大小窗口,内容是彩色条格,彩色条格不停的移动,持续时间5秒
在ubuntu下还可以使用cheese测试 1. sudo apt-get install cheese 2. sudo modprobe vivi
2. 启动 cheese后,就可以看到滚动的彩色条格
附上测试程序
[c-sharp] view plaincopy 1. #include 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. rno)); 38. 39. #include #define CLEAR(x) memset (&(x), 0, sizeof (x)) struct buffer { void * start; size_t length; }; static char * dev_name = NULL; static int fd = -1; struct buffer * buffers = NULL; static unsigned int n_buffers = 0; static int time_in_sec_capture=5; static int fbfd = -1; static struct fb_var_screeninfo vinfo; static struct fb_fix_screeninfo finfo; static char *fbp=NULL; static long screensize=0; static void errno_exit (const char * s) { fprintf (stderr, \"%s error %d, %s/n\exit (EXIT_FAILURE); } 40. 41. static int xioctl (int fd,int request,void * arg) 42. { 43. int r; 44. do r = ioctl (fd, request, arg); 45. while (-1 == r && EINTR == errno); 46. return r; 47. } 48. 49. inline int clip(int value, int min, int max) { 50. return (value > max ? max : value < min ? min : value); 51. } 52. 53. static void process_image (const void * p){ 54. 55. 56. //ConvertYUVToRGB32 57. 1; 58. unsigned char* in=(char*)p; 59. int width=640; 60. int height=480; 61. int istride=1280; 62. int x,y,j; 63. int y0,u,y1,v,r,g,b; 64. long location=0; 65. 66. for ( y = 100; y < height + 100; ++y) { 67. for (j = 0, x=100; j < width * 2 ; j += 4,x +=2) { 68. location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + 69. (y+vinfo.yoffset) * finfo.line_length; 70. 71. y0 = in[j]; 72. u = in[j + 1] - 128; 73. y1 = in[j + 2]; 74. v = in[j + 3] - 128; 75. 76. r = (298 * y0 + 409 * v + 128) >> 8; 77. g = (298 * y0 - 100 * u - 208 * v + 128) >> 8; 78. b = (298 * y0 + 516 * u + 128) >> 8; 79. 80. fbp[ location + 0] = clip(b, 0, 255); 81. fbp[ location + 1] = clip(g, 0, 255); 82. fbp[ location + 2] = clip(r, 0, 255); 83. fbp[ location + 3] = 255; 84. 85. r = (298 * y1 + 409 * v + 128) >> 8; 86. g = (298 * y1 - 100 * u - 208 * v + 128) >> 8; 87. b = (298 * y1 + 516 * u + 128) >> 8; 88. 89. fbp[ location + 4] = clip(b, 0, 255); 90. fbp[ location + 5] = clip(g, 0, 255); 91. fbp[ location + 6] = clip(r, 0, 255); 92. fbp[ location + 7] = 255; 93. } 94. in +=istride; 95. } 96. } 97. 98. static int read_frame (void) 99. { 100. struct v4l2_buffer buf; 101. unsigned int i; 102. 103. CLEAR (buf); 104. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 105. buf.memory = V4L2_MEMORY_MMAP; 106. 107. if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { 108. switch (errno) { 109. case EAGAIN: 110. return 0; 111. case EIO: 112. 113. 114. 115. default: 116. errno_exit (\"VIDIOC_DQBUF\"); 117. } 118. } 119. 120. assert (buf.index < n_buffers); 121. printf(\"v4l2_pix_format->field(%d)/n\122. //assert (buf.field ==V4L2_FIELD_NONE); 123. process_image (buffers[buf.index].start); 124. if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 125. errno_exit (\"VIDIOC_QBUF\"); 126. 127. return 1; 128. } 129. 130. static void run (void) 131. { 132. unsigned int count; 133. int frames; 134. frames = 30 * time_in_sec_capture; 135. 136. while (frames-- > 0) { 137. for (;;) { 138. fd_set fds; 139. struct timeval tv; 140. int r; 141. FD_ZERO (&fds); 142. FD_SET (fd, &fds); 143. 144. 145. tv.tv_sec = 2; 146. tv.tv_usec = 0; 147. 148. r = select (fd + 1, &fds, NULL, NULL, &tv); 149. 150. if (-1 == r) { 151. if (EINTR == errno) 152. continue; 153. errno_exit (\"select\"); 154. } 155. 156. if (0 == r) { 157. fprintf (stderr, \"select timeout/n\"); 158. exit (EXIT_FAILURE); 159. } 160. 161. if (read_frame ()) 162. break; 163. 164. } 165. } 166. } 167. 168. static void stop_capturing (void) 169. { 170. enum v4l2_buf_type type; 171. 172. type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 173. if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type)) 174. errno_exit (\"VIDIOC_STREAMOFF\"); 175. } 176. 177. static void start_capturing (void) 178. { 179. unsigned int i; 180. enum v4l2_buf_type type; 181. 182. for (i = 0; i < n_buffers; ++i) { 183. struct v4l2_buffer buf; 184. CLEAR (buf); 185. 186. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 187. buf.memory = V4L2_MEMORY_MMAP; 188. buf.index = i; 189. 190. if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 191. errno_exit (\"VIDIOC_QBUF\"); 192. } 193. 194. type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 195. 196. if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) 197. errno_exit (\"VIDIOC_STREAMON\"); 198. 199. } 200. 201. static void uninit_device (void) 202. { 203. unsigned int i; 204. 205. for (i = 0; i < n_buffers; ++i) 206. if (-1 == munmap (buffers[i].start, buffers[i].length)) 207. errno_exit (\"munmap\"); 208. 209. if (-1 == munmap(fbp, screensize)) { 210. printf(\" Error: framebuffer device munmap() failed./n\"); 211. exit (EXIT_FAILURE) ; 212. } 213. free (buffers); 214. } 215. 216. 217. static void init_mmap (void) 218. { 219. struct v4l2_requestbuffers req; 220. 221. //mmap framebuffer 222. fbp = (char *)mmap(NULL,screensize,PROT_READ | PROT_WRITE,MAP_SHARED ,fbfd, 0); 223. if ((int)fbp == -1) { 224. printf(\"Error: failed to map framebuffer device to memory./n\"); 225. exit (EXIT_FAILURE) ; 226. } 227. memset(fbp, 0, screensize); 228. CLEAR (req); 229. 230. req.count = 4; 231. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 232. req.memory = V4L2_MEMORY_MMAP; 233. 234. if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { 235. if (EINVAL == errno) { 236. fprintf (stderr, \"%s does not support memory mapping/n\ 237. exit (EXIT_FAILURE); 238. } else { 239. errno_exit (\"VIDIOC_REQBUFS\"); 240. } 241. } 242. 243. if (req.count < 4) { //if (req.count < 2) 244. fprintf (stderr, \"Insufficient buffer memory on %s/n\ev_name); 245. exit (EXIT_FAILURE); 246. } 247. 248. buffers = calloc (req.count, sizeof (*buffers)); 249. 250. if (!buffers) { 251. fprintf (stderr, \"Out of memory/n\"); 252. exit (EXIT_FAILURE); 253. } 254. 255. for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 256. struct v4l2_buffer buf; 257. 258. CLEAR (buf); 259. 260. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 261. buf.memory = V4L2_MEMORY_MMAP; 262. buf.index = n_buffers; 263. 264. if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf)) 265. errno_exit (\"VIDIOC_QUERYBUF\"); 266. 267. buffers[n_buffers].length = buf.length; 268. buffers[n_buffers].start =mmap (NULL,buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd, buf.m.offset); 269. 270. if (MAP_FAILED == buffers[n_buffers].start) 271. errno_exit (\"mmap\"); 272. } 273. 274. } 275. 276. 277. 278. static void init_device (void) 279. { 280. struct v4l2_capability cap; 281. struct v4l2_cropcap cropcap; 282. struct v4l2_crop crop; 283. struct v4l2_format fmt; 284. unsigned int min; 285. 286. 287. // Get fixed screen information 288. if (-1==xioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { 289. printf(\"Error reading fixed information./n\"); 290. exit (EXIT_FAILURE); 291. } 292. 293. // Get variable screen information 294. if (-1==xioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { 295. printf(\"Error reading variable information./n\"); 296. exit (EXIT_FAILURE); 297. } 298. screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; 299. 300. 301. if (-1 == xioctl (fd, VIDIOC_QUERYCAP, ∩)) { 302. if (EINVAL == errno) { 303. fprintf (stderr, \"%s is no V4L2 device/n\304. exit (EXIT_FAILURE); 305. } else { 306. errno_exit (\"VIDIOC_QUERYCAP\"); 307. } 308. } 309. 310. if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { 311. fprintf (stderr, \"%s is no video capture device/n\ame); 312. exit (EXIT_FAILURE); 313. } 314. 315. if (!(cap.capabilities & V4L2_CAP_STREAMING)) { 316. fprintf (stderr, \"%s does not support streaming i/o/n\dev_name); 317. exit (EXIT_FAILURE); 318. } 319. 320. 321. 322. CLEAR (cropcap); 323. 324. cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 325. 326. if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) { 327. crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 328. crop.c = cropcap.defrect; 329. 330. if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) { 331. switch (errno) { 332. case EINVAL: 333. break; 334. default: 335. break; 336. } 337. } 338. }else { } 339. 340. CLEAR (fmt); 341. 342. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 343. fmt.fmt.pix.width = 640; 344. fmt.fmt.pix.height = 480; 345. fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 346. fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 347. 348. if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) 349. errno_exit (\"VIDIOC_S_FMT\"); 350. 351. init_mmap (); 352. 353. } 354. 355. static void close_device (void) 356. { 357. if (-1 == close (fd)) 358. errno_exit (\"close\"); 359. fd = -1; 360. close(fbfd); 361. } 362. 363. static void open_device (void) 364. { 365. struct stat st; 366. 367. if (-1 == stat (dev_name, &st)) { 368. fprintf (stderr, \"Cannot identify '%s': %d, %s/n\me, errno, strerror (errno)); 369. exit (EXIT_FAILURE); 370. } 371. 372. if (!S_ISCHR (st.st_mode)) { 373. fprintf (stderr, \"%s is no device/n\374. exit (EXIT_FAILURE); 375. } 376. 377. //open framebuffer 378. fbfd = open(\"/dev/fb0\379. if (fbfd==-1) { 380. printf(\"Error: cannot open framebuffer device./n\"); 381. exit (EXIT_FAILURE); 382. } 383. 384. //open camera 385. fd = open (dev_name, O_RDWR| O_NONBLOCK, 0); 386. 387. if (-1 == fd) { 388. fprintf (stderr, \"Cannot open '%s': %d, %s/n\e, errno, strerror (errno)); 389. exit (EXIT_FAILURE); 390. } 391. } 392. 393. static void usage (FILE * fp,int argc,char ** argv) 394. { 395. fprintf (fp, 396. \"Usage: %s [options]/n/n\" 397. \"Options:/n\" 398. \"-d | --device name Video device name [/dev/video]/n\" 399. \"-h | --help Print this message/n\" 400. \"-t | --how long will display in seconds/n\" 401. \"\402. argv[0]); 403. } 404. 405. static const char short_options [] = \"d:ht:\"; 406. static const struct option long_options [] = { 407. { \"device\408. { \"help\409. { \"time\410. { 0, 0, 0, 0 } 411. }; 412. 413. int main (int argc,char ** argv) 414. { 415. dev_name = \"/dev/video0\"; 416. 417. for (;;) 418. { 419. int index; 420. int c; 421. 422. c = getopt_long (argc, argv,short_options, long_options,&index); 423. if (-1 == c) 424. break; 425. 426. switch (c) { 427. case 0: 428. break; 429. 430. case 'd': 431. dev_name = optarg; 432. break; 433. 434. case 'h': 435. usage (stdout, argc, argv); 436. exit (EXIT_SUCCESS); 437. case 't': 438. time_in_sec_capture = atoi(optarg); 439. break; 440. 441. default: 442. usage (stderr, argc, argv); 443. exit (EXIT_FAILURE); 444. } 445. } 446. 447. open_device (); 448. 449. init_device (); 450. 451. start_capturing (); 452. 453. run (); 454. 455. stop_capturing (); 456. 457. uninit_device (); 458. 459. close_device (); 460. 461. exit (EXIT_SUCCESS); 462. 463. return 0; 464. } 这个测试程序是根据vivi驱动hard code的, 并不一定适合其他的camera驱动 比如,我手头上的logitech stv06xx usb camera, 因为不支持640x480模式,参见代码59 60行, 代码348行 if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) 应该是个协商的过程, 343 fmt.fmt.pix.width = 640; 344 fmt.fmt.pix.height = 480; 345 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 346 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 这几行只是应用的期望格式,驱动会根据这个格式选择一个相近的格式返回,应用最后的显示处理要根据返回的格式进行处理,即process_image要做相应修改 因篇幅问题不能全部显示,请点此查看更多更全内容