4 * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
5 * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
7 * This file is part of FFmpeg.
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.
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.
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
24 #include <linux/videodev2.h>
25 #include <sys/ioctl.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"
39 static inline int v4l2_splane_video(struct v4l2_capability *cap)
41 if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT) &&
42 cap->capabilities & V4L2_CAP_STREAMING)
45 if (cap->capabilities & V4L2_CAP_VIDEO_M2M)
51 static inline int v4l2_mplane_video(struct v4l2_capability *cap)
53 if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE) &&
54 cap->capabilities & V4L2_CAP_STREAMING)
57 if (cap->capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)
63 static int v4l2_prepare_contexts(V4L2m2mContext* s)
65 struct v4l2_capability cap;
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);
74 memset(&cap, 0, sizeof(cap));
75 ret = ioctl(s->fd, VIDIOC_QUERYCAP, &cap);
79 av_log(s->avctx, AV_LOG_INFO, "driver '%s' on card '%s'\n", cap.driver, cap.card);
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;
87 if (v4l2_splane_video(&cap)) {
88 s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
89 s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
93 return AVERROR(EINVAL);
96 static int v4l2_probe_driver(V4L2m2mContext* s)
100 s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
102 return AVERROR(errno);
104 ret = v4l2_prepare_contexts(s);
108 ret = ff_v4l2_context_get_format(&s->output);
110 av_log(s->avctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
114 ret = ff_v4l2_context_get_format(&s->capture);
116 av_log(s->avctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
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)));
131 static int v4l2_configure_contexts(V4L2m2mContext* s)
133 void *log_ctx = s->avctx;
136 s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
138 return AVERROR(errno);
140 ret = v4l2_prepare_contexts(s);
144 ret = ff_v4l2_context_set_format(&s->output);
146 av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
150 ret = ff_v4l2_context_set_format(&s->capture);
152 av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
156 ret = ff_v4l2_context_init(&s->output);
158 av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
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);
166 av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
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)));
184 /******************************************************************************
188 ******************************************************************************/
189 int ff_v4l2_m2m_codec_reinit(V4L2m2mContext* s)
193 av_log(s->avctx, AV_LOG_DEBUG, "reinit context\n");
196 ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
198 av_log(s->avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
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.
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);
208 ff_v4l2_context_release(&s->capture);
210 /* 3. get the new capture format */
211 ret = ff_v4l2_context_get_format(&s->capture);
213 av_log(s->avctx, AV_LOG_ERROR, "query the new capture format\n");
217 /* 4. set the capture format */
218 ret = ff_v4l2_context_set_format(&s->capture);
220 av_log(s->avctx, AV_LOG_ERROR, "setting capture format\n");
224 /* 5. complete reinit */
225 sem_destroy(&s->refsync);
226 sem_init(&s->refsync, 0, 0);
233 int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *s)
235 void *log_ctx = s->avctx;
238 av_log(log_ctx, AV_LOG_DEBUG, "%s full reinit\n", s->devname);
240 /* wait for pending buffer references */
241 if (atomic_load(&s->refcount))
242 while(sem_wait(&s->refsync) == -1 && errno == EINTR);
244 /* close the driver */
245 ff_v4l2_m2m_codec_end(s->avctx);
247 /* start again now that we know the stream dimensions */
251 s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
253 return AVERROR(errno);
255 ret = v4l2_prepare_contexts(s);
259 /* if a full re-init was requested - probe didn't run - we need to populate
260 * the format for each context
262 ret = ff_v4l2_context_get_format(&s->output);
264 av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
268 ret = ff_v4l2_context_get_format(&s->capture);
270 av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
274 ret = ff_v4l2_context_set_format(&s->output);
276 av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
280 ret = ff_v4l2_context_set_format(&s->capture);
282 av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
286 ret = ff_v4l2_context_init(&s->output);
288 av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
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);
296 av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
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)));
314 int ff_v4l2_m2m_codec_end(AVCodecContext *avctx)
316 V4L2m2mContext* s = avctx->priv_data;
319 ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
321 av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
323 ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
325 av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
327 ff_v4l2_context_release(&s->output);
329 if (atomic_load(&s->refcount))
330 av_log(avctx, AV_LOG_ERROR, "ff_v4l2m2m_codec_end leaving pending buffers\n");
332 ff_v4l2_context_release(&s->capture);
333 sem_destroy(&s->refsync);
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)));
344 int ff_v4l2_m2m_codec_init(AVCodecContext *avctx)
346 int ret = AVERROR(EINVAL);
347 struct dirent *entry;
351 V4L2m2mContext *s = avctx->priv_data;
354 dirp = opendir("/dev");
356 return AVERROR(errno);
358 for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
360 if (strncmp(entry->d_name, "video", 5))
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);
374 av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
375 memset(s->devname, 0, sizeof(s->devname));
380 av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", node);
382 return v4l2_configure_contexts(s);