You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

421 lines
11KB

  1. /*
  2. * V4L mem2mem
  3. *
  4. * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
  5. * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
  6. *
  7. * This file is part of FFmpeg.
  8. *
  9. * FFmpeg is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2.1 of the License, or (at your option) any later version.
  13. *
  14. * FFmpeg is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with FFmpeg; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. */
  23. #include <linux/videodev2.h>
  24. #include <sys/ioctl.h>
  25. #include <sys/mman.h>
  26. #include <unistd.h>
  27. #include <dirent.h>
  28. #include <fcntl.h>
  29. #include "libavcodec/avcodec.h"
  30. #include "libavcodec/internal.h"
  31. #include "libavutil/pixdesc.h"
  32. #include "libavutil/imgutils.h"
  33. #include "libavutil/pixfmt.h"
  34. #include "v4l2_context.h"
  35. #include "v4l2_fmt.h"
  36. #include "v4l2_m2m.h"
  37. static inline int v4l2_splane_video(struct v4l2_capability *cap)
  38. {
  39. if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT) &&
  40. cap->capabilities & V4L2_CAP_STREAMING)
  41. return 1;
  42. if (cap->capabilities & V4L2_CAP_VIDEO_M2M)
  43. return 1;
  44. return 0;
  45. }
  46. static inline int v4l2_mplane_video(struct v4l2_capability *cap)
  47. {
  48. if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE) &&
  49. cap->capabilities & V4L2_CAP_STREAMING)
  50. return 1;
  51. if (cap->capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)
  52. return 1;
  53. return 0;
  54. }
  55. static int v4l2_prepare_contexts(V4L2m2mContext* s)
  56. {
  57. struct v4l2_capability cap;
  58. int ret;
  59. s->capture.done = s->output.done = 0;
  60. s->capture.name = "capture";
  61. s->output.name = "output";
  62. atomic_init(&s->refcount, 0);
  63. sem_init(&s->refsync, 0, 0);
  64. memset(&cap, 0, sizeof(cap));
  65. ret = ioctl(s->fd, VIDIOC_QUERYCAP, &cap);
  66. if (ret < 0)
  67. return ret;
  68. av_log(s->avctx, AV_LOG_INFO, "driver '%s' on card '%s' in %s mode\n", cap.driver, cap.card,
  69. v4l2_mplane_video(&cap) ? "mplane" :
  70. v4l2_splane_video(&cap) ? "splane" : "unknown");
  71. if (v4l2_mplane_video(&cap)) {
  72. s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
  73. s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
  74. return 0;
  75. }
  76. if (v4l2_splane_video(&cap)) {
  77. s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  78. s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
  79. return 0;
  80. }
  81. return AVERROR(EINVAL);
  82. }
  83. static int v4l2_probe_driver(V4L2m2mContext* s)
  84. {
  85. int ret;
  86. s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
  87. if (s->fd < 0)
  88. return AVERROR(errno);
  89. ret = v4l2_prepare_contexts(s);
  90. if (ret < 0)
  91. goto done;
  92. ret = ff_v4l2_context_get_format(&s->output);
  93. if (ret) {
  94. av_log(s->avctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
  95. goto done;
  96. }
  97. ret = ff_v4l2_context_get_format(&s->capture);
  98. if (ret) {
  99. av_log(s->avctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
  100. goto done;
  101. }
  102. done:
  103. if (close(s->fd) < 0) {
  104. ret = AVERROR(errno);
  105. av_log(s->avctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno)));
  106. }
  107. s->fd = -1;
  108. return ret;
  109. }
  110. static int v4l2_configure_contexts(V4L2m2mContext* s)
  111. {
  112. void *log_ctx = s->avctx;
  113. int ret;
  114. struct v4l2_format ofmt, cfmt;
  115. s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
  116. if (s->fd < 0)
  117. return AVERROR(errno);
  118. ret = v4l2_prepare_contexts(s);
  119. if (ret < 0)
  120. goto error;
  121. ofmt = s->output.format;
  122. cfmt = s->capture.format;
  123. av_log(log_ctx, AV_LOG_INFO, "requesting formats: output=%s capture=%s\n",
  124. av_fourcc2str(V4L2_TYPE_IS_MULTIPLANAR(ofmt.type) ?
  125. ofmt.fmt.pix_mp.pixelformat :
  126. ofmt.fmt.pix.pixelformat),
  127. av_fourcc2str(V4L2_TYPE_IS_MULTIPLANAR(cfmt.type) ?
  128. cfmt.fmt.pix_mp.pixelformat :
  129. cfmt.fmt.pix.pixelformat));
  130. ret = ff_v4l2_context_set_format(&s->output);
  131. if (ret) {
  132. av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
  133. goto error;
  134. }
  135. ret = ff_v4l2_context_set_format(&s->capture);
  136. if (ret) {
  137. av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
  138. goto error;
  139. }
  140. ret = ff_v4l2_context_init(&s->output);
  141. if (ret) {
  142. av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
  143. goto error;
  144. }
  145. /* decoder's buffers need to be updated at a later stage */
  146. if (!av_codec_is_decoder(s->avctx->codec)) {
  147. ret = ff_v4l2_context_init(&s->capture);
  148. if (ret) {
  149. av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
  150. goto error;
  151. }
  152. }
  153. return 0;
  154. error:
  155. if (close(s->fd) < 0) {
  156. ret = AVERROR(errno);
  157. av_log(log_ctx, AV_LOG_ERROR, "error closing %s (%s)\n",
  158. s->devname, av_err2str(AVERROR(errno)));
  159. }
  160. s->fd = -1;
  161. return ret;
  162. }
  163. /******************************************************************************
  164. *
  165. * V4L2 M2M Interface
  166. *
  167. ******************************************************************************/
  168. int ff_v4l2_m2m_codec_reinit(V4L2m2mContext* s)
  169. {
  170. int ret;
  171. av_log(s->avctx, AV_LOG_DEBUG, "reinit context\n");
  172. /* 1. streamoff */
  173. ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
  174. if (ret)
  175. av_log(s->avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
  176. /* 2. unmap the capture buffers (v4l2 and ffmpeg):
  177. * we must wait for all references to be released before being allowed
  178. * to queue new buffers.
  179. */
  180. av_log(s->avctx, AV_LOG_DEBUG, "waiting for user to release AVBufferRefs\n");
  181. if (atomic_load(&s->refcount))
  182. while(sem_wait(&s->refsync) == -1 && errno == EINTR);
  183. ff_v4l2_context_release(&s->capture);
  184. /* 3. get the new capture format */
  185. ret = ff_v4l2_context_get_format(&s->capture);
  186. if (ret) {
  187. av_log(s->avctx, AV_LOG_ERROR, "query the new capture format\n");
  188. return ret;
  189. }
  190. /* 4. set the capture format */
  191. ret = ff_v4l2_context_set_format(&s->capture);
  192. if (ret) {
  193. av_log(s->avctx, AV_LOG_ERROR, "setting capture format\n");
  194. return ret;
  195. }
  196. /* 5. complete reinit */
  197. s->draining = 0;
  198. s->reinit = 0;
  199. return 0;
  200. }
  201. int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *s)
  202. {
  203. void *log_ctx = s->avctx;
  204. int ret;
  205. av_log(log_ctx, AV_LOG_DEBUG, "%s full reinit\n", s->devname);
  206. /* wait for pending buffer references */
  207. if (atomic_load(&s->refcount))
  208. while(sem_wait(&s->refsync) == -1 && errno == EINTR);
  209. ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
  210. if (ret) {
  211. av_log(log_ctx, AV_LOG_ERROR, "output VIDIOC_STREAMOFF\n");
  212. goto error;
  213. }
  214. ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
  215. if (ret) {
  216. av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
  217. goto error;
  218. }
  219. /* release and unmmap the buffers */
  220. ff_v4l2_context_release(&s->output);
  221. ff_v4l2_context_release(&s->capture);
  222. /* start again now that we know the stream dimensions */
  223. s->draining = 0;
  224. s->reinit = 0;
  225. ret = ff_v4l2_context_get_format(&s->output);
  226. if (ret) {
  227. av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
  228. goto error;
  229. }
  230. ret = ff_v4l2_context_get_format(&s->capture);
  231. if (ret) {
  232. av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
  233. goto error;
  234. }
  235. ret = ff_v4l2_context_set_format(&s->output);
  236. if (ret) {
  237. av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
  238. goto error;
  239. }
  240. ret = ff_v4l2_context_set_format(&s->capture);
  241. if (ret) {
  242. av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
  243. goto error;
  244. }
  245. ret = ff_v4l2_context_init(&s->output);
  246. if (ret) {
  247. av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
  248. goto error;
  249. }
  250. /* decoder's buffers need to be updated at a later stage */
  251. if (!av_codec_is_decoder(s->avctx->codec)) {
  252. ret = ff_v4l2_context_init(&s->capture);
  253. if (ret) {
  254. av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
  255. goto error;
  256. }
  257. }
  258. return 0;
  259. error:
  260. return ret;
  261. }
  262. static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
  263. {
  264. V4L2m2mContext *s = (V4L2m2mContext*)context;
  265. ff_v4l2_context_release(&s->capture);
  266. sem_destroy(&s->refsync);
  267. close(s->fd);
  268. av_free(s);
  269. }
  270. int ff_v4l2_m2m_codec_end(AVCodecContext *avctx)
  271. {
  272. V4L2m2mPriv *priv = avctx->priv_data;
  273. V4L2m2mContext* s = priv->context;
  274. int ret;
  275. ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
  276. if (ret)
  277. av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
  278. ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
  279. if (ret)
  280. av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
  281. ff_v4l2_context_release(&s->output);
  282. s->self_ref = NULL;
  283. av_buffer_unref(&priv->context_ref);
  284. return 0;
  285. }
  286. int ff_v4l2_m2m_codec_init(AVCodecContext *avctx)
  287. {
  288. int ret = AVERROR(EINVAL);
  289. struct dirent *entry;
  290. char node[PATH_MAX];
  291. DIR *dirp;
  292. V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
  293. s->avctx = avctx;
  294. dirp = opendir("/dev");
  295. if (!dirp)
  296. return AVERROR(errno);
  297. for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
  298. if (strncmp(entry->d_name, "video", 5))
  299. continue;
  300. snprintf(node, sizeof(node), "/dev/%s", entry->d_name);
  301. av_log(s->avctx, AV_LOG_DEBUG, "probing device %s\n", node);
  302. strncpy(s->devname, node, strlen(node) + 1);
  303. ret = v4l2_probe_driver(s);
  304. if (!ret)
  305. break;
  306. }
  307. closedir(dirp);
  308. if (ret) {
  309. av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
  310. memset(s->devname, 0, sizeof(s->devname));
  311. return ret;
  312. }
  313. av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", node);
  314. return v4l2_configure_contexts(s);
  315. }
  316. int ff_v4l2_m2m_create_context(AVCodecContext *avctx, V4L2m2mContext **s)
  317. {
  318. V4L2m2mPriv *priv = avctx->priv_data;
  319. *s = av_mallocz(sizeof(V4L2m2mContext));
  320. if (!*s)
  321. return AVERROR(ENOMEM);
  322. priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext),
  323. &v4l2_m2m_destroy_context, NULL, 0);
  324. if (!priv->context_ref) {
  325. av_freep(s);
  326. return AVERROR(ENOMEM);
  327. }
  328. /* assign the context */
  329. priv->context = *s;
  330. /* populate it */
  331. priv->context->capture.num_buffers = priv->num_capture_buffers;
  332. priv->context->output.num_buffers = priv->num_output_buffers;
  333. priv->context->self_ref = priv->context_ref;
  334. priv->context->fd = -1;
  335. return 0;
  336. }