capture.c.rst 15 KB

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