v4l2-helpers.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. Copyright (C) 2014 by Leonhard Oelke <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <sys/mman.h>
  15. #include <util/bmem.h>
  16. #include "v4l2-helpers.h"
  17. #define blog(level, msg, ...) blog(level, "v4l2-helpers: " msg, ##__VA_ARGS__)
  18. int_fast32_t v4l2_start_capture(int_fast32_t dev, struct v4l2_buffer_data *buf)
  19. {
  20. enum v4l2_buf_type type;
  21. struct v4l2_buffer enq;
  22. memset(&enq, 0, sizeof(enq));
  23. enq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  24. enq.memory = V4L2_MEMORY_MMAP;
  25. for (enq.index = 0; enq.index < buf->count; ++enq.index) {
  26. if (v4l2_ioctl(dev, VIDIOC_QBUF, &enq) < 0) {
  27. blog(LOG_ERROR, "unable to queue buffer");
  28. return -1;
  29. }
  30. }
  31. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  32. if (v4l2_ioctl(dev, VIDIOC_STREAMON, &type) < 0) {
  33. blog(LOG_ERROR, "unable to start stream");
  34. return -1;
  35. }
  36. return 0;
  37. }
  38. int_fast32_t v4l2_stop_capture(int_fast32_t dev)
  39. {
  40. enum v4l2_buf_type type;
  41. type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  42. if (v4l2_ioctl(dev, VIDIOC_STREAMOFF, &type) < 0) {
  43. blog(LOG_ERROR, "unable to stop stream");
  44. return -1;
  45. }
  46. return 0;
  47. }
  48. int_fast32_t v4l2_reset_capture(int_fast32_t dev, struct v4l2_buffer_data *buf)
  49. {
  50. blog(LOG_DEBUG, "attempting to reset capture");
  51. if (v4l2_stop_capture(dev) < 0)
  52. return -1;
  53. if (v4l2_start_capture(dev, buf) < 0)
  54. return -1;
  55. return 0;
  56. }
  57. #ifdef _DEBUG
  58. int_fast32_t v4l2_query_all_buffers(int_fast32_t dev,
  59. struct v4l2_buffer_data *buf_data)
  60. {
  61. struct v4l2_buffer buf;
  62. blog(LOG_DEBUG, "attempting to read buffer data for %ld buffers",
  63. buf_data->count);
  64. for (uint_fast32_t i = 0; i < buf_data->count; i++) {
  65. buf.index = i;
  66. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  67. buf.memory = V4L2_MEMORY_MMAP;
  68. if (v4l2_ioctl(dev, VIDIOC_QUERYBUF, &buf) < 0) {
  69. blog(LOG_DEBUG,
  70. "failed to read buffer data for buffer #%ld", i);
  71. } else {
  72. blog(LOG_DEBUG,
  73. "query buf #%ld info: ts: %06ld buf id #%d, flags 0x%08X, seq #%d, len %d, used %d",
  74. i, buf.timestamp.tv_usec, buf.index, buf.flags,
  75. buf.sequence, buf.length, buf.bytesused);
  76. }
  77. }
  78. return 0;
  79. }
  80. #endif
  81. int_fast32_t v4l2_create_mmap(int_fast32_t dev, struct v4l2_buffer_data *buf)
  82. {
  83. struct v4l2_requestbuffers req;
  84. struct v4l2_buffer map;
  85. memset(&req, 0, sizeof(req));
  86. req.count = 4;
  87. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  88. req.memory = V4L2_MEMORY_MMAP;
  89. if (v4l2_ioctl(dev, VIDIOC_REQBUFS, &req) < 0) {
  90. blog(LOG_ERROR, "Request for buffers failed !");
  91. return -1;
  92. }
  93. if (req.count < 2) {
  94. blog(LOG_ERROR, "Device returned less than 2 buffers");
  95. return -1;
  96. }
  97. buf->count = req.count;
  98. buf->info = bzalloc(req.count * sizeof(struct v4l2_mmap_info));
  99. memset(&map, 0, sizeof(map));
  100. map.type = req.type;
  101. map.memory = req.memory;
  102. for (map.index = 0; map.index < req.count; ++map.index) {
  103. if (v4l2_ioctl(dev, VIDIOC_QUERYBUF, &map) < 0) {
  104. blog(LOG_ERROR, "Failed to query buffer details");
  105. return -1;
  106. }
  107. buf->info[map.index].length = map.length;
  108. buf->info[map.index].start =
  109. v4l2_mmap(NULL, map.length, PROT_READ | PROT_WRITE,
  110. MAP_SHARED, dev, map.m.offset);
  111. if (buf->info[map.index].start == MAP_FAILED) {
  112. blog(LOG_ERROR, "mmap for buffer failed");
  113. return -1;
  114. }
  115. }
  116. return 0;
  117. }
  118. int_fast32_t v4l2_destroy_mmap(struct v4l2_buffer_data *buf)
  119. {
  120. for (uint_fast32_t i = 0; i < buf->count; ++i) {
  121. if (buf->info[i].start != MAP_FAILED && buf->info[i].start != 0)
  122. v4l2_munmap(buf->info[i].start, buf->info[i].length);
  123. }
  124. if (buf->count) {
  125. bfree(buf->info);
  126. buf->count = 0;
  127. }
  128. return 0;
  129. }
  130. int_fast32_t v4l2_set_input(int_fast32_t dev, int *input)
  131. {
  132. if (!dev || !input)
  133. return -1;
  134. return (*input == -1) ? v4l2_ioctl(dev, VIDIOC_G_INPUT, input)
  135. : v4l2_ioctl(dev, VIDIOC_S_INPUT, input);
  136. }
  137. int_fast32_t v4l2_get_input_caps(int_fast32_t dev, int input, uint32_t *caps)
  138. {
  139. if (!dev || !caps)
  140. return -1;
  141. if (input == -1) {
  142. if (v4l2_ioctl(dev, VIDIOC_G_INPUT, &input) < 0)
  143. return -1;
  144. }
  145. struct v4l2_input in;
  146. memset(&in, 0, sizeof(in));
  147. in.index = input;
  148. if (v4l2_ioctl(dev, VIDIOC_ENUMINPUT, &in) < 0)
  149. return -1;
  150. *caps = in.capabilities;
  151. return 0;
  152. }
  153. int_fast32_t v4l2_set_format(int_fast32_t dev, int *resolution,
  154. int *pixelformat, int *bytesperline)
  155. {
  156. bool set = false;
  157. int width, height;
  158. struct v4l2_format fmt;
  159. if (!dev || !resolution || !pixelformat || !bytesperline)
  160. return -1;
  161. /* We need to set the type in order to query the settings */
  162. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  163. if (v4l2_ioctl(dev, VIDIOC_G_FMT, &fmt) < 0)
  164. return -1;
  165. if (*resolution != -1) {
  166. v4l2_unpack_tuple(&width, &height, *resolution);
  167. fmt.fmt.pix.width = width;
  168. fmt.fmt.pix.height = height;
  169. set = true;
  170. }
  171. if (*pixelformat != -1) {
  172. fmt.fmt.pix.pixelformat = *pixelformat;
  173. set = true;
  174. }
  175. if (set && (v4l2_ioctl(dev, VIDIOC_S_FMT, &fmt) < 0))
  176. return -1;
  177. *resolution = v4l2_pack_tuple(fmt.fmt.pix.width, fmt.fmt.pix.height);
  178. *pixelformat = fmt.fmt.pix.pixelformat;
  179. *bytesperline = fmt.fmt.pix.bytesperline;
  180. return 0;
  181. }
  182. int_fast32_t v4l2_set_framerate(int_fast32_t dev, int *framerate)
  183. {
  184. bool set = false;
  185. int num, denom;
  186. struct v4l2_streamparm par;
  187. if (!dev || !framerate)
  188. return -1;
  189. /* We need to set the type in order to query the stream settings */
  190. par.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  191. if (v4l2_ioctl(dev, VIDIOC_G_PARM, &par) < 0)
  192. return -1;
  193. if (*framerate != -1) {
  194. v4l2_unpack_tuple(&num, &denom, *framerate);
  195. par.parm.capture.timeperframe.numerator = num;
  196. par.parm.capture.timeperframe.denominator = denom;
  197. set = true;
  198. }
  199. if (set && (v4l2_ioctl(dev, VIDIOC_S_PARM, &par) < 0))
  200. return -1;
  201. *framerate = v4l2_pack_tuple(par.parm.capture.timeperframe.numerator,
  202. par.parm.capture.timeperframe.denominator);
  203. return 0;
  204. }
  205. int_fast32_t v4l2_set_standard(int_fast32_t dev, int *standard)
  206. {
  207. if (!dev || !standard)
  208. return -1;
  209. if (*standard == -1) {
  210. if (v4l2_ioctl(dev, VIDIOC_G_STD, standard) < 0)
  211. return -1;
  212. } else {
  213. if (v4l2_ioctl(dev, VIDIOC_S_STD, standard) < 0)
  214. return -1;
  215. }
  216. return 0;
  217. }
  218. int_fast32_t v4l2_enum_dv_timing(int_fast32_t dev, struct v4l2_dv_timings *dvt,
  219. int index)
  220. {
  221. #if !defined(VIDIOC_ENUM_DV_TIMINGS) || !defined(V4L2_IN_CAP_DV_TIMINGS)
  222. UNUSED_PARAMETER(dev);
  223. UNUSED_PARAMETER(dvt);
  224. UNUSED_PARAMETER(index);
  225. return -1;
  226. #else
  227. if (!dev || !dvt)
  228. return -1;
  229. struct v4l2_enum_dv_timings iter;
  230. memset(&iter, 0, sizeof(iter));
  231. iter.index = index;
  232. if (v4l2_ioctl(dev, VIDIOC_ENUM_DV_TIMINGS, &iter) < 0)
  233. return -1;
  234. memcpy(dvt, &iter.timings, sizeof(struct v4l2_dv_timings));
  235. return 0;
  236. #endif
  237. }
  238. int_fast32_t v4l2_set_dv_timing(int_fast32_t dev, int *timing)
  239. {
  240. if (!dev || !timing)
  241. return -1;
  242. if (*timing == -1)
  243. return 0;
  244. struct v4l2_dv_timings dvt;
  245. if (v4l2_enum_dv_timing(dev, &dvt, *timing) < 0)
  246. return -1;
  247. if (v4l2_ioctl(dev, VIDIOC_S_DV_TIMINGS, &dvt) < 0)
  248. return -1;
  249. return 0;
  250. }