FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
v4l2_m2m.c
Go to the documentation of this file.
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 
24 #include <linux/videodev2.h>
25 #include <sys/ioctl.h>
26 #include <sys/mman.h>
27 #include <unistd.h>
28 #include <dirent.h>
29 #include <fcntl.h>
30 #include "libavcodec/avcodec.h"
31 #include "libavcodec/internal.h"
32 #include "libavutil/pixdesc.h"
33 #include "libavutil/imgutils.h"
34 #include "libavutil/pixfmt.h"
35 #include "v4l2_context.h"
36 #include "v4l2_fmt.h"
37 #include "v4l2_m2m.h"
38 
39 static inline int v4l2_splane_video(struct v4l2_capability *cap)
40 {
41  if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT) &&
42  cap->capabilities & V4L2_CAP_STREAMING)
43  return 1;
44 
45  if (cap->capabilities & V4L2_CAP_VIDEO_M2M)
46  return 1;
47 
48  return 0;
49 }
50 
51 static inline int v4l2_mplane_video(struct v4l2_capability *cap)
52 {
53  if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE) &&
54  cap->capabilities & V4L2_CAP_STREAMING)
55  return 1;
56 
57  if (cap->capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)
58  return 1;
59 
60  return 0;
61 }
62 
64 {
65  struct v4l2_capability cap;
66  int ret;
67 
68  s->capture.done = s->output.done = 0;
69  s->capture.name = "capture";
70  s->output.name = "output ";
71  atomic_init(&s->refcount, 0);
72  sem_init(&s->refsync, 0, 0);
73 
74  memset(&cap, 0, sizeof(cap));
75  ret = ioctl(s->fd, VIDIOC_QUERYCAP, &cap);
76  if (ret < 0)
77  return ret;
78 
79  av_log(s->avctx, AV_LOG_INFO, "driver '%s' on card '%s'\n", cap.driver, cap.card);
80 
81  if (v4l2_mplane_video(&cap)) {
82  s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
83  s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
84  return 0;
85  }
86 
87  if (v4l2_splane_video(&cap)) {
88  s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
89  s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
90  return 0;
91  }
92 
93  return AVERROR(EINVAL);
94 }
95 
97 {
98  int ret;
99 
100  s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
101  if (s->fd < 0)
102  return AVERROR(errno);
103 
104  ret = v4l2_prepare_contexts(s);
105  if (ret < 0)
106  goto done;
107 
109  if (ret) {
110  av_log(s->avctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
111  goto done;
112  }
113 
115  if (ret) {
116  av_log(s->avctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
117  goto done;
118  }
119 
120 done:
121  if (close(s->fd) < 0) {
122  ret = AVERROR(errno);
123  av_log(s->avctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno)));
124  }
125 
126  s->fd = -1;
127 
128  return ret;
129 }
130 
132 {
133  void *log_ctx = s->avctx;
134  int ret;
135 
136  s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
137  if (s->fd < 0)
138  return AVERROR(errno);
139 
140  ret = v4l2_prepare_contexts(s);
141  if (ret < 0)
142  goto error;
143 
145  if (ret) {
146  av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
147  goto error;
148  }
149 
151  if (ret) {
152  av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
153  goto error;
154  }
155 
156  ret = ff_v4l2_context_init(&s->output);
157  if (ret) {
158  av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
159  goto error;
160  }
161 
162  /* decoder's buffers need to be updated at a later stage */
163  if (!av_codec_is_decoder(s->avctx->codec)) {
164  ret = ff_v4l2_context_init(&s->capture);
165  if (ret) {
166  av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
167  goto error;
168  }
169  }
170 
171  return 0;
172 
173 error:
174  if (close(s->fd) < 0) {
175  ret = AVERROR(errno);
176  av_log(log_ctx, AV_LOG_ERROR, "error closing %s (%s)\n",
177  s->devname, av_err2str(AVERROR(errno)));
178  }
179  s->fd = -1;
180 
181  return ret;
182 }
183 
184 /******************************************************************************
185  *
186  * V4L2 M2M Interface
187  *
188  ******************************************************************************/
190 {
191  int ret;
192 
193  av_log(s->avctx, AV_LOG_DEBUG, "reinit context\n");
194 
195  /* 1. streamoff */
196  ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
197  if (ret)
198  av_log(s->avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
199 
200  /* 2. unmap the capture buffers (v4l2 and ffmpeg):
201  * we must wait for all references to be released before being allowed
202  * to queue new buffers.
203  */
204  av_log(s->avctx, AV_LOG_DEBUG, "waiting for user to release AVBufferRefs\n");
205  if (atomic_load(&s->refcount))
206  while(sem_wait(&s->refsync) == -1 && errno == EINTR);
207 
209 
210  /* 3. get the new capture format */
212  if (ret) {
213  av_log(s->avctx, AV_LOG_ERROR, "query the new capture format\n");
214  return ret;
215  }
216 
217  /* 4. set the capture format */
219  if (ret) {
220  av_log(s->avctx, AV_LOG_ERROR, "setting capture format\n");
221  return ret;
222  }
223 
224  /* 5. complete reinit */
225  sem_destroy(&s->refsync);
226  sem_init(&s->refsync, 0, 0);
227  s->draining = 0;
228  s->reinit = 0;
229 
230  return 0;
231 }
232 
234 {
235  void *log_ctx = s->avctx;
236  int ret;
237 
238  av_log(log_ctx, AV_LOG_DEBUG, "%s full reinit\n", s->devname);
239 
240  /* wait for pending buffer references */
241  if (atomic_load(&s->refcount))
242  while(sem_wait(&s->refsync) == -1 && errno == EINTR);
243 
244  /* close the driver */
246 
247  /* start again now that we know the stream dimensions */
248  s->draining = 0;
249  s->reinit = 0;
250 
251  s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
252  if (s->fd < 0)
253  return AVERROR(errno);
254 
255  ret = v4l2_prepare_contexts(s);
256  if (ret < 0)
257  goto error;
258 
259  /* if a full re-init was requested - probe didn't run - we need to populate
260  * the format for each context
261  */
263  if (ret) {
264  av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
265  goto error;
266  }
267 
269  if (ret) {
270  av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
271  goto error;
272  }
273 
275  if (ret) {
276  av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
277  goto error;
278  }
279 
281  if (ret) {
282  av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
283  goto error;
284  }
285 
286  ret = ff_v4l2_context_init(&s->output);
287  if (ret) {
288  av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
289  goto error;
290  }
291 
292  /* decoder's buffers need to be updated at a later stage */
293  if (!av_codec_is_decoder(s->avctx->codec)) {
294  ret = ff_v4l2_context_init(&s->capture);
295  if (ret) {
296  av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
297  goto error;
298  }
299  }
300 
301  return 0;
302 
303 error:
304  if (close(s->fd) < 0) {
305  ret = AVERROR(errno);
306  av_log(log_ctx, AV_LOG_ERROR, "error closing %s (%s)\n",
307  s->devname, av_err2str(AVERROR(errno)));
308  }
309  s->fd = -1;
310 
311  return ret;
312 }
313 
315 {
316  V4L2m2mContext* s = avctx->priv_data;
317  int ret;
318 
319  ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
320  if (ret)
321  av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
322 
323  ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
324  if (ret)
325  av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
326 
328 
329  if (atomic_load(&s->refcount))
330  av_log(avctx, AV_LOG_ERROR, "ff_v4l2m2m_codec_end leaving pending buffers\n");
331 
333  sem_destroy(&s->refsync);
334 
335  /* release the hardware */
336  if (close(s->fd) < 0 )
337  av_log(avctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno)));
338 
339  s->fd = -1;
340 
341  return 0;
342 }
343 
345 {
346  int ret = AVERROR(EINVAL);
347  struct dirent *entry;
348  char node[PATH_MAX];
349  DIR *dirp;
350 
351  V4L2m2mContext *s = avctx->priv_data;
352  s->avctx = avctx;
353 
354  dirp = opendir("/dev");
355  if (!dirp)
356  return AVERROR(errno);
357 
358  for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
359 
360  if (strncmp(entry->d_name, "video", 5))
361  continue;
362 
363  snprintf(node, sizeof(node), "/dev/%s", entry->d_name);
364  av_log(s->avctx, AV_LOG_DEBUG, "probing device %s\n", node);
365  strncpy(s->devname, node, strlen(node) + 1);
366  ret = v4l2_probe_driver(s);
367  if (!ret)
368  break;
369  }
370 
371  closedir(dirp);
372 
373  if (ret) {
374  av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
375  memset(s->devname, 0, sizeof(s->devname));
376 
377  return ret;
378  }
379 
380  av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", node);
381 
382  return v4l2_configure_contexts(s);
383 }
const struct AVCodec * codec
Definition: avcodec.h:1770
const char * s
Definition: avisynth_c.h:768
const char * name
context name.
Definition: v4l2_context.h:40
AVCodecContext * avctx
Definition: v4l2_m2m.h:57
misc image utilities
int ff_v4l2_context_init(V4L2Context *ctx)
Initializes a V4L2Context.
Definition: v4l2_context.c:642
void ff_v4l2_context_release(V4L2Context *ctx)
Releases a V4L2Context.
Definition: v4l2_context.c:627
int ff_v4l2_m2m_codec_init(AVCodecContext *avctx)
Probes the video nodes looking for the required codec capabilities.
Definition: v4l2_m2m.c:344
int ff_v4l2_context_set_format(V4L2Context *ctx)
Sets the V4L2Context format in the v4l2 driver.
Definition: v4l2_context.c:622
int av_codec_is_decoder(const AVCodec *codec)
Definition: utils.c:174
#define sem_init
Definition: semaphore.h:40
int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s)
Reinitializes the V4L2m2mContext when the driver cant continue processing with the capture parameters...
Definition: v4l2_m2m.c:189
#define av_log(a,...)
int done
Either no more buffers available or an unrecoverable error was notified by the V4L2 kernel driver: on...
Definition: v4l2_context.h:92
static int v4l2_probe_driver(V4L2m2mContext *s)
Definition: v4l2_m2m.c:96
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define atomic_load(object)
Definition: stdatomic.h:93
#define AVERROR(e)
Definition: error.h:43
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
#define sem_destroy(psem)
Definition: semaphore.h:29
int ff_v4l2_context_set_status(V4L2Context *ctx, int cmd)
Sets the status of a V4L2Context.
Definition: v4l2_context.c:487
int ff_v4l2_m2m_codec_end(AVCodecContext *avctx)
Releases all the codec resources if all AVBufferRefs have been returned to the ctx.
Definition: v4l2_m2m.c:314
char devname[PATH_MAX]
Definition: v4l2_m2m.h:46
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
static void error(const char *err)
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
V4L2Context capture
Definition: v4l2_m2m.h:50
Libavcodec external API header.
atomic_uint refcount
Definition: v4l2_m2m.h:54
main external API structure.
Definition: avcodec.h:1761
static int v4l2_prepare_contexts(V4L2m2mContext *s)
Definition: v4l2_m2m.c:63
int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *s)
Reinitializes the V4L2m2mContext when the driver cant continue processing with the any of the current...
Definition: v4l2_m2m.c:233
static int v4l2_configure_contexts(V4L2m2mContext *s)
Definition: v4l2_m2m.c:131
#define snprintf
Definition: snprintf.h:34
static int v4l2_splane_video(struct v4l2_capability *cap)
Definition: v4l2_m2m.c:39
V4L2Context output
Definition: v4l2_m2m.h:51
common internal api header.
void * priv_data
Definition: avcodec.h:1803
pixel format definitions
int ff_v4l2_context_get_format(V4L2Context *ctx)
Queries the driver for a valid v4l2 format and copies it to the context.
Definition: v4l2_context.c:595
#define sem_wait(psem)
Definition: semaphore.h:27
#define atomic_init(obj, value)
Definition: stdatomic.h:33
sem_t refsync
Definition: v4l2_m2m.h:58
enum v4l2_buf_type type
Type of this buffer context.
Definition: v4l2_context.h:47
static int v4l2_mplane_video(struct v4l2_capability *cap)
Definition: v4l2_m2m.c:51