FFmpeg  4.4.6
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  void *log_ctx = s->avctx;
67  int ret;
68 
69  s->capture.done = s->output.done = 0;
70  s->capture.name = "capture";
71  s->output.name = "output";
72  atomic_init(&s->refcount, 0);
73  sem_init(&s->refsync, 0, 0);
74 
75  memset(&cap, 0, sizeof(cap));
76  ret = ioctl(s->fd, VIDIOC_QUERYCAP, &cap);
77  if (ret < 0)
78  return ret;
79 
80  av_log(log_ctx, probe ? AV_LOG_DEBUG : AV_LOG_INFO,
81  "driver '%s' on card '%s' in %s mode\n", cap.driver, cap.card,
82  v4l2_mplane_video(&cap) ? "mplane" :
83  v4l2_splane_video(&cap) ? "splane" : "unknown");
84 
85  if (v4l2_mplane_video(&cap)) {
86  s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
87  s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
88  return 0;
89  }
90 
91  if (v4l2_splane_video(&cap)) {
92  s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
93  s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
94  return 0;
95  }
96 
97  return AVERROR(EINVAL);
98 }
99 
101 {
102  void *log_ctx = s->avctx;
103  int ret;
104 
105  s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
106  if (s->fd < 0)
107  return AVERROR(errno);
108 
109  ret = v4l2_prepare_contexts(s, 1);
110  if (ret < 0)
111  goto done;
112 
113  ret = ff_v4l2_context_get_format(&s->output, 1);
114  if (ret) {
115  av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
116  goto done;
117  }
118 
119  ret = ff_v4l2_context_get_format(&s->capture, 1);
120  if (ret) {
121  av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
122  goto done;
123  }
124 
125 done:
126  if (close(s->fd) < 0) {
127  ret = AVERROR(errno);
128  av_log(log_ctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno)));
129  }
130 
131  s->fd = -1;
132 
133  return ret;
134 }
135 
137 {
138  void *log_ctx = s->avctx;
139  int ret;
140  struct v4l2_format ofmt, cfmt;
141 
142  s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
143  if (s->fd < 0)
144  return AVERROR(errno);
145 
146  ret = v4l2_prepare_contexts(s, 0);
147  if (ret < 0)
148  goto error;
149 
150  ofmt = s->output.format;
151  cfmt = s->capture.format;
152  av_log(log_ctx, AV_LOG_INFO, "requesting formats: output=%s capture=%s\n",
153  av_fourcc2str(V4L2_TYPE_IS_MULTIPLANAR(ofmt.type) ?
154  ofmt.fmt.pix_mp.pixelformat :
155  ofmt.fmt.pix.pixelformat),
156  av_fourcc2str(V4L2_TYPE_IS_MULTIPLANAR(cfmt.type) ?
157  cfmt.fmt.pix_mp.pixelformat :
158  cfmt.fmt.pix.pixelformat));
159 
160  ret = ff_v4l2_context_set_format(&s->output);
161  if (ret) {
162  av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
163  goto error;
164  }
165 
166  ret = ff_v4l2_context_set_format(&s->capture);
167  if (ret) {
168  av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
169  goto error;
170  }
171 
172  ret = ff_v4l2_context_init(&s->output);
173  if (ret) {
174  av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
175  goto error;
176  }
177 
178  /* decoder's buffers need to be updated at a later stage */
179  if (s->avctx && !av_codec_is_decoder(s->avctx->codec)) {
180  ret = ff_v4l2_context_init(&s->capture);
181  if (ret) {
182  av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
183  goto error;
184  }
185  }
186 
187  return 0;
188 
189 error:
190  if (close(s->fd) < 0) {
191  ret = AVERROR(errno);
192  av_log(log_ctx, AV_LOG_ERROR, "error closing %s (%s)\n",
193  s->devname, av_err2str(AVERROR(errno)));
194  }
195  s->fd = -1;
196 
197  return ret;
198 }
199 
200 /******************************************************************************
201  *
202  * V4L2 M2M Interface
203  *
204  ******************************************************************************/
206 {
207  void *log_ctx = s->avctx;
208  int ret;
209 
210  av_log(log_ctx, AV_LOG_DEBUG, "reinit context\n");
211 
212  /* 1. streamoff */
213  ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
214  if (ret)
215  av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
216 
217  /* 2. unmap the capture buffers (v4l2 and ffmpeg):
218  * we must wait for all references to be released before being allowed
219  * to queue new buffers.
220  */
221  av_log(log_ctx, AV_LOG_DEBUG, "waiting for user to release AVBufferRefs\n");
222  if (atomic_load(&s->refcount))
223  while(sem_wait(&s->refsync) == -1 && errno == EINTR);
224 
225  ff_v4l2_context_release(&s->capture);
226 
227  /* 3. get the new capture format */
228  ret = ff_v4l2_context_get_format(&s->capture, 0);
229  if (ret) {
230  av_log(log_ctx, AV_LOG_ERROR, "query the new capture format\n");
231  return ret;
232  }
233 
234  /* 4. set the capture format */
235  ret = ff_v4l2_context_set_format(&s->capture);
236  if (ret) {
237  av_log(log_ctx, AV_LOG_ERROR, "setting capture format\n");
238  return ret;
239  }
240 
241  /* 5. complete reinit */
242  s->draining = 0;
243  s->reinit = 0;
244 
245  return 0;
246 }
247 
249 {
250  void *log_ctx = s->avctx;
251  int ret;
252 
253  av_log(log_ctx, AV_LOG_DEBUG, "%s full reinit\n", s->devname);
254 
255  /* wait for pending buffer references */
256  if (atomic_load(&s->refcount))
257  while(sem_wait(&s->refsync) == -1 && errno == EINTR);
258 
259  ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
260  if (ret) {
261  av_log(log_ctx, AV_LOG_ERROR, "output VIDIOC_STREAMOFF\n");
262  goto error;
263  }
264 
265  ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
266  if (ret) {
267  av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
268  goto error;
269  }
270 
271  /* release and unmmap the buffers */
272  ff_v4l2_context_release(&s->output);
273  ff_v4l2_context_release(&s->capture);
274 
275  /* start again now that we know the stream dimensions */
276  s->draining = 0;
277  s->reinit = 0;
278 
279  ret = ff_v4l2_context_get_format(&s->output, 0);
280  if (ret) {
281  av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
282  goto error;
283  }
284 
285  ret = ff_v4l2_context_get_format(&s->capture, 0);
286  if (ret) {
287  av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
288  goto error;
289  }
290 
291  ret = ff_v4l2_context_set_format(&s->output);
292  if (ret) {
293  av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
294  goto error;
295  }
296 
297  ret = ff_v4l2_context_set_format(&s->capture);
298  if (ret) {
299  av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
300  goto error;
301  }
302 
303  ret = ff_v4l2_context_init(&s->output);
304  if (ret) {
305  av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
306  goto error;
307  }
308 
309  /* decoder's buffers need to be updated at a later stage */
310  if (s->avctx && !av_codec_is_decoder(s->avctx->codec)) {
311  ret = ff_v4l2_context_init(&s->capture);
312  if (ret) {
313  av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
314  goto error;
315  }
316  }
317 
318  return 0;
319 
320 error:
321  return ret;
322 }
323 
324 static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
325 {
326  V4L2m2mContext *s = (V4L2m2mContext*)context;
327 
328  ff_v4l2_context_release(&s->capture);
329  sem_destroy(&s->refsync);
330 
331  close(s->fd);
332  av_frame_unref(s->frame);
333  av_frame_free(&s->frame);
334  av_packet_unref(&s->buf_pkt);
335 
336  av_free(s);
337 }
338 
340 {
341  V4L2m2mContext *s = priv->context;
342  int ret;
343 
344  if (!s)
345  return 0;
346 
347  if (s->fd >= 0) {
348  ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
349  if (ret)
350  av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
351 
352  ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
353  if (ret)
354  av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
355  }
356 
357  ff_v4l2_context_release(&s->output);
358 
359  s->self_ref = NULL;
361 
362  return 0;
363 }
364 
366 {
367  int ret = AVERROR(EINVAL);
368  struct dirent *entry;
369  DIR *dirp;
370 
371  V4L2m2mContext *s = priv->context;
372 
373  dirp = opendir("/dev");
374  if (!dirp)
375  return AVERROR(errno);
376 
377  for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
378 
379  if (strncmp(entry->d_name, "video", 5))
380  continue;
381 
382  snprintf(s->devname, sizeof(s->devname), "/dev/%s", entry->d_name);
383  av_log(s->avctx, AV_LOG_DEBUG, "probing device %s\n", s->devname);
384  ret = v4l2_probe_driver(s);
385  if (!ret)
386  break;
387  }
388 
389  closedir(dirp);
390 
391  if (ret) {
392  av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
393  memset(s->devname, 0, sizeof(s->devname));
394 
395  return ret;
396  }
397 
398  av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", s->devname);
399 
400  return v4l2_configure_contexts(s);
401 }
402 
404 {
405  *s = av_mallocz(sizeof(V4L2m2mContext));
406  if (!*s)
407  return AVERROR(ENOMEM);
408 
409  priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext),
411  if (!priv->context_ref) {
412  av_freep(s);
413  return AVERROR(ENOMEM);
414  }
415 
416  /* assign the context */
417  priv->context = *s;
418  (*s)->priv = priv;
419 
420  /* populate it */
423  priv->context->self_ref = priv->context_ref;
424  priv->context->fd = -1;
425 
426  priv->context->frame = av_frame_alloc();
427  if (!priv->context->frame) {
429  *s = NULL; /* freed when unreferencing context_ref */
430  return AVERROR(ENOMEM);
431  }
432 
433  return 0;
434 }
static int probe(const AVProbeData *p)
Definition: act.c:36
uint8_t
Libavcodec external API header.
#define s(width, name)
Definition: cbs_vp9.c:257
#define NULL
Definition: coverity.c:32
#define atomic_load(object)
Definition: stdatomic.h:93
#define atomic_init(obj, value)
Definition: stdatomic.h:33
int av_codec_is_decoder(const AVCodec *codec)
Definition: utils.c:79
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:634
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
AVBufferRef * av_buffer_create(uint8_t *data, buffer_size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
#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 AVERROR(e)
Definition: error.h:43
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:553
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
#define av_fourcc2str(fourcc)
Definition: avutil.h:348
misc image utilities
common internal api header.
pixel format definitions
#define sem_wait(psem)
Definition: semaphore.h:27
#define sem_destroy(psem)
Definition: semaphore.h:29
#define sem_init
Definition: semaphore.h:40
#define snprintf
Definition: snprintf.h:34
int num_buffers
Readonly after init.
Definition: v4l2_context.h:82
V4L2Context output
Definition: v4l2_m2m.h:49
V4L2Context capture
Definition: v4l2_m2m.h:48
AVBufferRef * self_ref
Definition: v4l2_m2m.h:65
AVFrame * frame
Definition: v4l2_m2m.h:62
int num_capture_buffers
Definition: v4l2_m2m.h:78
V4L2m2mContext * context
Definition: v4l2_m2m.h:74
int num_output_buffers
Definition: v4l2_m2m.h:77
AVBufferRef * context_ref
Definition: v4l2_m2m.h:75
#define av_free(p)
#define av_freep(p)
#define av_log(a,...)
static void error(const char *err)
void ff_v4l2_context_release(V4L2Context *ctx)
Releases a V4L2Context.
Definition: v4l2_context.c:708
int ff_v4l2_context_get_format(V4L2Context *ctx, int probe)
Queries the driver for a valid v4l2 format and copies it to the context.
Definition: v4l2_context.c:676
int ff_v4l2_context_set_status(V4L2Context *ctx, uint32_t cmd)
Sets the status of a V4L2Context.
Definition: v4l2_context.c:572
int ff_v4l2_context_set_format(V4L2Context *ctx)
Sets the V4L2Context format in the v4l2 driver.
Definition: v4l2_context.c:703
int ff_v4l2_context_init(V4L2Context *ctx)
Initializes a V4L2Context.
Definition: v4l2_context.c:722
static int v4l2_configure_contexts(V4L2m2mContext *s)
Definition: v4l2_m2m.c:136
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:248
static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
Definition: v4l2_m2m.c:324
int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s)
Allocate a new context and references for a V4L2 M2M instance.
Definition: v4l2_m2m.c:403
static int v4l2_prepare_contexts(V4L2m2mContext *s, int probe)
Definition: v4l2_m2m.c:63
static int v4l2_splane_video(struct v4l2_capability *cap)
Definition: v4l2_m2m.c:39
int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv)
Probes the video nodes looking for the required codec capabilities.
Definition: v4l2_m2m.c:365
int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv)
Releases all the codec resources if all AVBufferRefs have been returned to the ctx.
Definition: v4l2_m2m.c:339
static int v4l2_mplane_video(struct v4l2_capability *cap)
Definition: v4l2_m2m.c:51
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:205
static int v4l2_probe_driver(V4L2m2mContext *s)
Definition: v4l2_m2m.c:100