2
0

camera_source.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. /*
  2. * Copyright 2015 Rockchip Electronics Co. LTD
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #define MODULE_TAG "camera_source"
  17. #include <stdio.h>
  18. #include <fcntl.h>
  19. #include <unistd.h>
  20. #include <errno.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <time.h>
  24. #include <sys/select.h>
  25. #include <sys/mman.h>
  26. #include <sys/ioctl.h>
  27. #include <linux/videodev2.h>
  28. #include "mpp_log.h"
  29. #include "mpp_mem.h"
  30. #include "camera_source.h"
  31. typedef struct CamFrame_t {
  32. void *start;
  33. size_t length;
  34. RK_S32 export_fd;
  35. RK_S32 sequence;
  36. MppBuffer buffer;
  37. } CamFrame;
  38. struct CamSource {
  39. RK_S32 fd; // Device handle
  40. RK_U32 bufcnt; // # of buffers
  41. enum v4l2_buf_type type;
  42. MppFrameFormat fmt;
  43. CamFrame fbuf[10];// frame buffers
  44. };
  45. static RK_U32 V4L2_yuv_cfg[MPP_FMT_YUV_BUTT] = {
  46. V4L2_PIX_FMT_NV12,
  47. 0,
  48. V4L2_PIX_FMT_NV16,
  49. 0,
  50. V4L2_PIX_FMT_YVU420,
  51. V4L2_PIX_FMT_NV21,
  52. V4L2_PIX_FMT_YUV422P,
  53. V4L2_PIX_FMT_NV61,
  54. V4L2_PIX_FMT_YUYV,
  55. V4L2_PIX_FMT_YVYU,
  56. V4L2_PIX_FMT_UYVY,
  57. V4L2_PIX_FMT_VYUY,
  58. V4L2_PIX_FMT_GREY,
  59. 0,
  60. 0,
  61. 0,
  62. };
  63. static RK_U32 V4L2_RGB_cfg[MPP_FMT_RGB_BUTT - MPP_FRAME_FMT_RGB] = {
  64. V4L2_PIX_FMT_RGB565,
  65. 0,
  66. V4L2_PIX_FMT_RGB555,
  67. 0,
  68. V4L2_PIX_FMT_RGB444,
  69. 0,
  70. V4L2_PIX_FMT_RGB24,
  71. V4L2_PIX_FMT_BGR24,
  72. 0,
  73. 0,
  74. V4L2_PIX_FMT_RGB32,
  75. V4L2_PIX_FMT_BGR32,
  76. 0,
  77. 0,
  78. };
  79. #define FMT_NUM_PLANES 1
  80. // Wrap ioctl() to spin on EINTR
  81. static RK_S32 camera_source_ioctl(RK_S32 fd, RK_S32 req, void* arg)
  82. {
  83. struct timespec poll_time;
  84. RK_S32 ret;
  85. while ((ret = ioctl(fd, req, arg))) {
  86. if (ret == -1 && (EINTR != errno && EAGAIN != errno)) {
  87. // mpp_err("ret = %d, errno %d", ret, errno);
  88. break;
  89. }
  90. // 10 milliseconds
  91. poll_time.tv_sec = 0;
  92. poll_time.tv_nsec = 10000000;
  93. nanosleep(&poll_time, NULL);
  94. }
  95. return ret;
  96. }
  97. // Create a new context to capture frames from <fname>.
  98. // Returns NULL on error.
  99. CamSource *camera_source_init(const char *device, RK_U32 bufcnt, RK_U32 width, RK_U32 height, MppFrameFormat format)
  100. {
  101. struct v4l2_capability cap;
  102. struct v4l2_format vfmt;
  103. struct v4l2_requestbuffers req;
  104. struct v4l2_buffer buf;
  105. enum v4l2_buf_type type;
  106. RK_U32 i;
  107. RK_U32 buf_len = 0;
  108. CamSource *ctx;
  109. ctx = mpp_calloc(CamSource, 1);
  110. if (!ctx)
  111. return NULL;
  112. ctx->bufcnt = bufcnt;
  113. ctx->fd = open(device, O_RDWR, 0);
  114. if (ctx->fd < 0) {
  115. mpp_err_f("Cannot open device\n");
  116. goto FAIL;
  117. }
  118. // Determine if fd is a V4L2 Device
  119. if (0 != camera_source_ioctl(ctx->fd, VIDIOC_QUERYCAP, &cap)) {
  120. mpp_err_f("Not v4l2 compatible\n");
  121. goto FAIL;
  122. }
  123. if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)) {
  124. mpp_err_f("Capture not supported\n");
  125. goto FAIL;
  126. }
  127. if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
  128. mpp_err_f("Streaming IO Not Supported\n");
  129. goto FAIL;
  130. }
  131. // Preserve original settings as set by v4l2-ctl for example
  132. vfmt = (struct v4l2_format) {0};
  133. vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  134. if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
  135. vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
  136. vfmt.fmt.pix.width = width;
  137. vfmt.fmt.pix.height = height;
  138. if (MPP_FRAME_FMT_IS_YUV(format)) {
  139. vfmt.fmt.pix.pixelformat = V4L2_yuv_cfg[format - MPP_FRAME_FMT_YUV];
  140. } else if (MPP_FRAME_FMT_IS_RGB(format)) {
  141. vfmt.fmt.pix.pixelformat = V4L2_RGB_cfg[format - MPP_FRAME_FMT_RGB];
  142. }
  143. if (!vfmt.fmt.pix.pixelformat)
  144. vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
  145. type = vfmt.type;
  146. ctx->type = vfmt.type;
  147. if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_S_FMT, &vfmt)) {
  148. mpp_err_f("VIDIOC_S_FMT\n");
  149. goto FAIL;
  150. }
  151. if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_G_FMT, &vfmt)) {
  152. mpp_err_f("VIDIOC_G_FMT\n");
  153. goto FAIL;
  154. }
  155. mpp_log("get width %d height %d", vfmt.fmt.pix.width, vfmt.fmt.pix.height);
  156. // Request memory-mapped buffers
  157. req = (struct v4l2_requestbuffers) {0};
  158. req.count = ctx->bufcnt;
  159. req.type = type;
  160. req.memory = V4L2_MEMORY_MMAP;
  161. if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_REQBUFS, &req)) {
  162. mpp_err_f("Device does not support mmap\n");
  163. goto FAIL;
  164. }
  165. if (req.count != ctx->bufcnt) {
  166. mpp_err_f("Device buffer count mismatch\n");
  167. goto FAIL;
  168. }
  169. // mmap() the buffers into userspace memory
  170. for (i = 0 ; i < ctx->bufcnt; i++) {
  171. buf = (struct v4l2_buffer) {0};
  172. buf.type = type;
  173. buf.memory = V4L2_MEMORY_MMAP;
  174. buf.index = i;
  175. struct v4l2_plane planes[FMT_NUM_PLANES];
  176. buf.memory = V4L2_MEMORY_MMAP;
  177. if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
  178. buf.m.planes = planes;
  179. buf.length = FMT_NUM_PLANES;
  180. }
  181. if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_QUERYBUF, &buf)) {
  182. mpp_err_f("ERROR: VIDIOC_QUERYBUF\n");
  183. goto FAIL;
  184. }
  185. ctx->fbuf[i].start = mmap(NULL, buf.length,
  186. PROT_READ | PROT_WRITE, MAP_SHARED,
  187. ctx->fd, buf.m.offset);
  188. if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == buf.type) {
  189. // tmp_buffers[n_buffers].length = buf.m.planes[0].length;
  190. buf_len = buf.m.planes[0].length;
  191. ctx->fbuf[i].start =
  192. mmap(NULL /* start anywhere */,
  193. buf.m.planes[0].length,
  194. PROT_READ | PROT_WRITE /* required */,
  195. MAP_SHARED /* recommended */,
  196. ctx->fd, buf.m.planes[0].m.mem_offset);
  197. } else {
  198. buf_len = buf.length;
  199. ctx->fbuf[i].start =
  200. mmap(NULL /* start anywhere */,
  201. buf.length,
  202. PROT_READ | PROT_WRITE /* required */,
  203. MAP_SHARED /* recommended */,
  204. ctx->fd, buf.m.offset);
  205. }
  206. if (MAP_FAILED == ctx->fbuf[i].start) {
  207. mpp_err_f("ERROR: Failed to map device frame buffers\n");
  208. goto FAIL;
  209. }
  210. struct v4l2_exportbuffer expbuf = (struct v4l2_exportbuffer) {0} ;
  211. // xcam_mem_clear (expbuf);
  212. expbuf.type = type;
  213. expbuf.index = i;
  214. expbuf.flags = O_CLOEXEC;
  215. if (camera_source_ioctl(ctx->fd, VIDIOC_EXPBUF, &expbuf) < 0) {
  216. mpp_err_f("get dma buf failed\n");
  217. goto FAIL;
  218. } else {
  219. mpp_log("get dma buf(%d)-fd: %d\n", i, expbuf.fd);
  220. MppBufferInfo info;
  221. memset(&info, 0, sizeof(MppBufferInfo));
  222. info.type = MPP_BUFFER_TYPE_EXT_DMA;
  223. info.fd = expbuf.fd;
  224. info.size = buf_len & 0x07ffffff;
  225. info.index = (buf_len & 0xf8000000) >> 27;
  226. mpp_buffer_import(&ctx->fbuf[i].buffer, &info);
  227. }
  228. ctx->fbuf[i].export_fd = expbuf.fd;
  229. }
  230. for (i = 0; i < ctx->bufcnt; i++ ) {
  231. struct v4l2_plane planes[FMT_NUM_PLANES];
  232. buf = (struct v4l2_buffer) {0};
  233. buf.type = type;
  234. buf.memory = V4L2_MEMORY_MMAP;
  235. buf.index = i;
  236. buf.memory = V4L2_MEMORY_MMAP;
  237. if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
  238. buf.m.planes = planes;
  239. buf.length = FMT_NUM_PLANES;
  240. }
  241. if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_QBUF, &buf)) {
  242. mpp_err_f("ERROR: VIDIOC_QBUF %d\n", i);
  243. camera_source_deinit(ctx);
  244. goto FAIL;
  245. }
  246. }
  247. // Start capturing
  248. if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_STREAMON, &type)) {
  249. mpp_err_f("ERROR: VIDIOC_STREAMON\n");
  250. camera_source_deinit(ctx);
  251. goto FAIL;
  252. }
  253. //skip some frames at start
  254. for (i = 0; i < ctx->bufcnt; i++ ) {
  255. RK_S32 idx = camera_source_get_frame(ctx);
  256. if (idx >= 0)
  257. camera_source_put_frame(ctx, idx);
  258. }
  259. return ctx;
  260. FAIL:
  261. camera_source_deinit(ctx);
  262. return NULL;
  263. }
  264. // Free a context to capture frames from <fname>.
  265. // Returns NULL on error.
  266. MPP_RET camera_source_deinit(CamSource *ctx)
  267. {
  268. struct v4l2_buffer buf;
  269. enum v4l2_buf_type type;
  270. RK_U32 i;
  271. if (NULL == ctx)
  272. return MPP_OK;
  273. if (ctx->fd < 0)
  274. return MPP_OK;
  275. // Stop capturing
  276. type = ctx->type;
  277. camera_source_ioctl(ctx->fd, VIDIOC_STREAMOFF, &type);
  278. // un-mmap() buffers
  279. for (i = 0 ; i < ctx->bufcnt; i++) {
  280. buf = (struct v4l2_buffer) {0};
  281. buf.type = type;
  282. buf.memory = V4L2_MEMORY_MMAP;
  283. buf.index = i;
  284. camera_source_ioctl(ctx->fd, VIDIOC_QUERYBUF, &buf);
  285. if (ctx->fbuf[buf.index].buffer) {
  286. mpp_buffer_put(ctx->fbuf[buf.index].buffer);
  287. }
  288. munmap(ctx->fbuf[buf.index].start, buf.length);
  289. }
  290. // Close v4l2 device
  291. close(ctx->fd);
  292. MPP_FREE(ctx);
  293. return MPP_OK;
  294. }
  295. // Returns a pointer to a captured frame and its meta-data. NOT thread-safe.
  296. RK_S32 camera_source_get_frame(CamSource *ctx)
  297. {
  298. struct v4l2_buffer buf;
  299. enum v4l2_buf_type type;
  300. type = ctx->type;
  301. buf = (struct v4l2_buffer) {0};
  302. buf.type = type;
  303. buf.memory = V4L2_MEMORY_MMAP;
  304. struct v4l2_plane planes[FMT_NUM_PLANES];
  305. if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
  306. buf.m.planes = planes;
  307. buf.length = FMT_NUM_PLANES;
  308. }
  309. if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_DQBUF, &buf)) {
  310. mpp_err_f("VIDIOC_DQBUF\n");
  311. return -1;
  312. }
  313. if (buf.index > ctx->bufcnt) {
  314. mpp_err_f("buffer index out of bounds\n");
  315. return -1;
  316. }
  317. if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type)
  318. buf.bytesused = buf.m.planes[0].bytesused;
  319. return buf.index;
  320. }
  321. // It's OK to capture into this framebuffer now
  322. MPP_RET camera_source_put_frame(CamSource *ctx, RK_S32 idx)
  323. {
  324. struct v4l2_buffer buf;
  325. enum v4l2_buf_type type;
  326. if (idx < 0)
  327. return MPP_OK;
  328. type = ctx->type;
  329. buf = (struct v4l2_buffer) {0};
  330. buf.type = type;
  331. buf.memory = V4L2_MEMORY_MMAP;
  332. buf.index = idx;
  333. struct v4l2_plane planes[FMT_NUM_PLANES];
  334. if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
  335. buf.m.planes = planes;
  336. buf.length = FMT_NUM_PLANES;
  337. }
  338. // Tell kernel it's ok to overwrite this frame
  339. if (-1 == camera_source_ioctl(ctx->fd, VIDIOC_QBUF, &buf)) {
  340. mpp_err_f("VIDIOC_QBUF\n");
  341. return MPP_OK;
  342. }
  343. return MPP_OK;
  344. }
  345. MppBuffer camera_frame_to_buf(CamSource *ctx, RK_S32 idx)
  346. {
  347. if (idx < 0)
  348. return NULL;
  349. return ctx->fbuf[idx].buffer;
  350. }