FFmpeg
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  s->draining = 0;
226  s->reinit = 0;
227 
228  return 0;
229 }
230 
232 {
233  void *log_ctx = s->avctx;
234  int ret;
235 
236  av_log(log_ctx, AV_LOG_DEBUG, "%s full reinit\n", s->devname);
237 
238  /* wait for pending buffer references */
239  if (atomic_load(&s->refcount))
240  while(sem_wait(&s->refsync) == -1 && errno == EINTR);
241 
242  ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
243  if (ret) {
244  av_log(s->avctx, AV_LOG_ERROR, "output VIDIOC_STREAMOFF\n");
245  goto error;
246  }
247 
248  ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
249  if (ret) {
250  av_log(s->avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
251  goto error;
252  }
253 
254  /* release and unmmap the buffers */
257 
258  /* start again now that we know the stream dimensions */
259  s->draining = 0;
260  s->reinit = 0;
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  return ret;
305 }
306 
307 static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
308 {
309  V4L2m2mContext *s = (V4L2m2mContext*)context;
310 
312  sem_destroy(&s->refsync);
313 
314  close(s->fd);
315 
316  av_free(s);
317 }
318 
320 {
321  V4L2m2mPriv *priv = avctx->priv_data;
322  V4L2m2mContext* s = priv->context;
323  int ret;
324 
325  ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
326  if (ret)
327  av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
328 
329  ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
330  if (ret)
331  av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
332 
334 
335  s->self_ref = NULL;
337 
338  return 0;
339 }
340 
342 {
343  int ret = AVERROR(EINVAL);
344  struct dirent *entry;
345  char node[PATH_MAX];
346  DIR *dirp;
347 
348  V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
349  s->avctx = avctx;
350 
351  dirp = opendir("/dev");
352  if (!dirp)
353  return AVERROR(errno);
354 
355  for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
356 
357  if (strncmp(entry->d_name, "video", 5))
358  continue;
359 
360  snprintf(node, sizeof(node), "/dev/%s", entry->d_name);
361  av_log(s->avctx, AV_LOG_DEBUG, "probing device %s\n", node);
362  strncpy(s->devname, node, strlen(node) + 1);
363  ret = v4l2_probe_driver(s);
364  if (!ret)
365  break;
366  }
367 
368  closedir(dirp);
369 
370  if (ret) {
371  av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
372  memset(s->devname, 0, sizeof(s->devname));
373 
374  return ret;
375  }
376 
377  av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", node);
378 
379  return v4l2_configure_contexts(s);
380 }
381 
383 {
384  V4L2m2mPriv *priv = avctx->priv_data;
385 
386  *s = av_mallocz(sizeof(V4L2m2mContext));
387  if (!*s)
388  return AVERROR(ENOMEM);
389 
390  priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext),
392  if (!priv->context_ref) {
393  av_freep(s);
394  return AVERROR(ENOMEM);
395  }
396 
397  /* assign the context */
398  priv->context = *s;
399 
400  /* populate it */
403  priv->context->self_ref = priv->context_ref;
404 
405  return 0;
406 }
#define NULL
Definition: coverity.c:32
const struct AVCodec * codec
Definition: avcodec.h:1574
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:125
const char * name
context name.
Definition: v4l2_context.h:40
AVCodecContext * avctx
Definition: v4l2_m2m.h:52
misc image utilities
int ff_v4l2_context_init(V4L2Context *ctx)
Initializes a V4L2Context.
Definition: v4l2_context.c:661
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
void ff_v4l2_context_release(V4L2Context *ctx)
Releases a V4L2Context.
Definition: v4l2_context.c:646
int ff_v4l2_m2m_codec_init(AVCodecContext *avctx)
Probes the video nodes looking for the required codec capabilities.
Definition: v4l2_m2m.c:341
int ff_v4l2_context_set_format(V4L2Context *ctx)
Sets the V4L2Context format in the v4l2 driver.
Definition: v4l2_context.c:641
int av_codec_is_decoder(const AVCodec *codec)
Definition: utils.c:99
uint8_t
#define sem_init
Definition: semaphore.h:40
int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s)
Reinitializes the V4L2m2mContext when the driver cannot continue processing with the capture paramete...
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
int ff_v4l2_m2m_create_context(AVCodecContext *avctx, V4L2m2mContext **s)
Allocate a new context and references for a V4L2 M2M instance.
Definition: v4l2_m2m.c:382
static int v4l2_probe_driver(V4L2m2mContext *s)
Definition: v4l2_m2m.c:96
static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
Definition: v4l2_m2m.c:307
#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 AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
#define sem_destroy(psem)
Definition: semaphore.h:29
V4L2m2mContext * context
Definition: v4l2_m2m.h:68
AVBufferRef * av_buffer_create(uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:28
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:319
char devname[PATH_MAX]
Definition: v4l2_m2m.h:44
int num_output_buffers
Definition: v4l2_m2m.h:71
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
#define s(width, name)
Definition: cbs_vp9.c:257
static void error(const char *err)
int ff_v4l2_context_set_status(V4L2Context *ctx, uint32_t cmd)
Sets the status of a V4L2Context.
Definition: v4l2_context.c:510
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
V4L2Context capture
Definition: v4l2_m2m.h:48
Libavcodec external API header.
atomic_uint refcount
Definition: v4l2_m2m.h:54
main external API structure.
Definition: avcodec.h:1565
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 cannot continue processing with the any of the curre...
Definition: v4l2_m2m.c:231
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:49
common internal api header.
int num_capture_buffers
Definition: v4l2_m2m.h:72
AVBufferRef * self_ref
Definition: v4l2_m2m.h:61
void * priv_data
Definition: avcodec.h:1592
pixel format definitions
#define av_free(p)
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:614
#define sem_wait(psem)
Definition: semaphore.h:27
int num_buffers
Readonly after init.
Definition: v4l2_context.h:81
#define atomic_init(obj, value)
Definition: stdatomic.h:33
#define av_freep(p)
AVBufferRef * context_ref
Definition: v4l2_m2m.h:69
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option keep it simple and lowercase description are in without and describe what they for example set the foo of the bar offset is the offset of the field in your local context
sem_t refsync
Definition: v4l2_m2m.h:53
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