capture.c.rst 15 KB

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