v4l2_m2m.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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'\n", cap.driver, cap.card);
  69. if (v4l2_mplane_video(&cap)) {
  70. s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
  71. s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
  72. return 0;
  73. }
  74. if (v4l2_splane_video(&cap)) {
  75. s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  76. s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
  77. return 0;
  78. }
  79. return AVERROR(EINVAL);
  80. }
  81. static int v4l2_probe_driver(V4L2m2mContext* s)
  82. {
  83. int ret;
  84. s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
  85. if (s->fd < 0)
  86. return AVERROR(errno);
  87. ret = v4l2_prepare_contexts(s);
  88. if (ret < 0)
  89. goto done;
  90. ret = ff_v4l2_context_get_format(&s->output);
  91. if (ret) {
  92. av_log(s->avctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
  93. goto done;
  94. }
  95. ret = ff_v4l2_context_get_format(&s->capture);
  96. if (ret) {
  97. av_log(s->avctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
  98. goto done;
  99. }
  100. done:
  101. if (close(s->fd) < 0) {
  102. ret = AVERROR(errno);
  103. av_log(s->avctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno)));
  104. }
  105. s->fd = -1;
  106. return ret;
  107. }
  108. static int v4l2_configure_contexts(V4L2m2mContext* s)
  109. {
  110. void *log_ctx = s->avctx;
  111. int ret;
  112. s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
  113. if (s->fd < 0)
  114. return AVERROR(errno);
  115. ret = v4l2_prepare_contexts(s);
  116. if (ret < 0)
  117. goto error;
  118. ret = ff_v4l2_context_set_format(&s->output);
  119. if (ret) {
  120. av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
  121. goto error;
  122. }
  123. ret = ff_v4l2_context_set_format(&s->capture);
  124. if (ret) {
  125. av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
  126. goto error;
  127. }
  128. ret = ff_v4l2_context_init(&s->output);
  129. if (ret) {
  130. av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
  131. goto error;
  132. }
  133. /* decoder's buffers need to be updated at a later stage */
  134. if (!av_codec_is_decoder(s->avctx->codec)) {
  135. ret = ff_v4l2_context_init(&s->capture);
  136. if (ret) {
  137. av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
  138. goto error;
  139. }
  140. }
  141. return 0;
  142. error:
  143. if (close(s->fd) < 0) {
  144. ret = AVERROR(errno);
  145. av_log(log_ctx, AV_LOG_ERROR, "error closing %s (%s)\n",
  146. s->devname, av_err2str(AVERROR(errno)));
  147. }
  148. s->fd = -1;
  149. return ret;
  150. }
  151. /******************************************************************************
  152. *
  153. * V4L2 M2M Interface
  154. *
  155. ******************************************************************************/
  156. int ff_v4l2_m2m_codec_reinit(V4L2m2mContext* s)
  157. {
  158. int ret;
  159. av_log(s->avctx, AV_LOG_DEBUG, "reinit context\n");
  160. /* 1. streamoff */
  161. ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
  162. if (ret)
  163. av_log(s->avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
  164. /* 2. unmap the capture buffers (v4l2 and ffmpeg):
  165. * we must wait for all references to be released before being allowed
  166. * to queue new buffers.
  167. */
  168. av_log(s->avctx, AV_LOG_DEBUG, "waiting for user to release AVBufferRefs\n");
  169. if (atomic_load(&s->refcount))
  170. while(sem_wait(&s->refsync) == -1 && errno == EINTR);
  171. ff_v4l2_context_release(&s->capture);
  172. /* 3. get the new capture format */
  173. ret = ff_v4l2_context_get_format(&s->capture);
  174. if (ret) {
  175. av_log(s->avctx, AV_LOG_ERROR, "query the new capture format\n");
  176. return ret;
  177. }
  178. /* 4. set the capture format */
  179. ret = ff_v4l2_context_set_format(&s->capture);
  180. if (ret) {
  181. av_log(s->avctx, AV_LOG_ERROR, "setting capture format\n");
  182. return ret;
  183. }
  184. /* 5. complete reinit */
  185. s->draining = 0;
  186. s->reinit = 0;
  187. return 0;
  188. }
  189. int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *s)
  190. {
  191. void *log_ctx = s->avctx;
  192. int ret;
  193. av_log(log_ctx, AV_LOG_DEBUG, "%s full reinit\n", s->devname);
  194. /* wait for pending buffer references */
  195. if (atomic_load(&s->refcount))
  196. while(sem_wait(&s->refsync) == -1 && errno == EINTR);
  197. ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
  198. if (ret) {
  199. av_log(s->avctx, AV_LOG_ERROR, "output VIDIOC_STREAMOFF\n");
  200. goto error;
  201. }
  202. ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
  203. if (ret) {
  204. av_log(s->avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
  205. goto error;
  206. }
  207. /* release and unmmap the buffers */
  208. ff_v4l2_context_release(&s->output);
  209. ff_v4l2_context_release(&s->capture);
  210. /* start again now that we know the stream dimensions */
  211. s->draining = 0;
  212. s->reinit = 0;
  213. ret = ff_v4l2_context_get_format(&s->output);
  214. if (ret) {
  215. av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
  216. goto error;
  217. }
  218. ret = ff_v4l2_context_get_format(&s->capture);
  219. if (ret) {
  220. av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
  221. goto error;
  222. }
  223. ret = ff_v4l2_context_set_format(&s->output);
  224. if (ret) {
  225. av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
  226. goto error;
  227. }
  228. ret = ff_v4l2_context_set_format(&s->capture);
  229. if (ret) {
  230. av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
  231. goto error;
  232. }
  233. ret = ff_v4l2_context_init(&s->output);
  234. if (ret) {
  235. av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
  236. goto error;
  237. }
  238. /* decoder's buffers need to be updated at a later stage */
  239. if (!av_codec_is_decoder(s->avctx->codec)) {
  240. ret = ff_v4l2_context_init(&s->capture);
  241. if (ret) {
  242. av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
  243. goto error;
  244. }
  245. }
  246. return 0;
  247. error:
  248. return ret;
  249. }
  250. static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
  251. {
  252. V4L2m2mContext *s = (V4L2m2mContext*)context;
  253. ff_v4l2_context_release(&s->capture);
  254. sem_destroy(&s->refsync);
  255. close(s->fd);
  256. av_free(s);
  257. }
  258. int ff_v4l2_m2m_codec_end(AVCodecContext *avctx)
  259. {
  260. V4L2m2mPriv *priv = avctx->priv_data;
  261. V4L2m2mContext* s = priv->context;
  262. int ret;
  263. ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
  264. if (ret)
  265. av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
  266. ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
  267. if (ret)
  268. av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
  269. ff_v4l2_context_release(&s->output);
  270. s->self_ref = NULL;
  271. av_buffer_unref(&priv->context_ref);
  272. return 0;
  273. }
  274. int ff_v4l2_m2m_codec_init(AVCodecContext *avctx)
  275. {
  276. int ret = AVERROR(EINVAL);
  277. struct dirent *entry;
  278. char node[PATH_MAX];
  279. DIR *dirp;
  280. V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
  281. s->avctx = avctx;
  282. dirp = opendir("/dev");
  283. if (!dirp)
  284. return AVERROR(errno);
  285. for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
  286. if (strncmp(entry->d_name, "video", 5))
  287. continue;
  288. snprintf(node, sizeof(node), "/dev/%s", entry->d_name);
  289. av_log(s->avctx, AV_LOG_DEBUG, "probing device %s\n", node);
  290. strncpy(s->devname, node, strlen(node) + 1);
  291. ret = v4l2_probe_driver(s);
  292. if (!ret)
  293. break;
  294. }
  295. closedir(dirp);
  296. if (ret) {
  297. av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
  298. memset(s->devname, 0, sizeof(s->devname));
  299. return ret;
  300. }
  301. av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", node);
  302. return v4l2_configure_contexts(s);
  303. }
  304. int ff_v4l2_m2m_create_context(AVCodecContext *avctx, V4L2m2mContext **s)
  305. {
  306. V4L2m2mPriv *priv = avctx->priv_data;
  307. *s = av_mallocz(sizeof(V4L2m2mContext));
  308. if (!*s)
  309. return AVERROR(ENOMEM);
  310. priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext),
  311. &v4l2_m2m_destroy_context, NULL, 0);
  312. if (!priv->context_ref) {
  313. av_freep(s);
  314. return AVERROR(ENOMEM);
  315. }
  316. /* assign the context */
  317. priv->context = *s;
  318. /* populate it */
  319. priv->context->capture.num_buffers = priv->num_capture_buffers;
  320. priv->context->output.num_buffers = priv->num_output_buffers;
  321. priv->context->self_ref = priv->context_ref;
  322. return 0;
  323. }