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, int probe)
65 struct v4l2_capability cap;
66 void *log_ctx = s->avctx;
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);
75 memset(&cap, 0, sizeof(cap));
76 ret = ioctl(s->fd, VIDIOC_QUERYCAP, &cap);
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");
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;
91 if (v4l2_splane_video(&cap)) {
92 s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
93 s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
97 return AVERROR(EINVAL);
100 static int v4l2_probe_driver(V4L2m2mContext *s)
102 void *log_ctx = s->avctx;
105 s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
107 return AVERROR(errno);
109 ret = v4l2_prepare_contexts(s, 1);
113 ret = ff_v4l2_context_get_format(&s->output, 1);
115 av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
119 ret = ff_v4l2_context_get_format(&s->capture, 1);
121 av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
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)));
136 static int v4l2_configure_contexts(V4L2m2mContext *s)
138 void *log_ctx = s->avctx;
140 struct v4l2_format ofmt, cfmt;
142 s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
144 return AVERROR(errno);
146 ret = v4l2_prepare_contexts(s, 0);
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));
160 ret = ff_v4l2_context_set_format(&s->output);
162 av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
166 ret = ff_v4l2_context_set_format(&s->capture);
168 av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
172 ret = ff_v4l2_context_init(&s->output);
174 av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
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);
182 av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
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)));
200 /******************************************************************************
204 ******************************************************************************/
205 int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s)
207 void *log_ctx = s->avctx;
210 av_log(log_ctx, AV_LOG_DEBUG, "reinit context\n");
213 ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
215 av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
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.
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);
225 ff_v4l2_context_release(&s->capture);
227 /* 3. get the new capture format */
228 ret = ff_v4l2_context_get_format(&s->capture, 0);
230 av_log(log_ctx, AV_LOG_ERROR, "query the new capture format\n");
234 /* 4. set the capture format */
235 ret = ff_v4l2_context_set_format(&s->capture);
237 av_log(log_ctx, AV_LOG_ERROR, "setting capture format\n");
241 /* 5. complete reinit */
248 int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *s)
250 void *log_ctx = s->avctx;
253 av_log(log_ctx, AV_LOG_DEBUG, "%s full reinit\n", s->devname);
255 /* wait for pending buffer references */
256 if (atomic_load(&s->refcount))
257 while(sem_wait(&s->refsync) == -1 && errno == EINTR);
259 ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
261 av_log(log_ctx, AV_LOG_ERROR, "output VIDIOC_STREAMOFF\n");
265 ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
267 av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
271 /* release and unmmap the buffers */
272 ff_v4l2_context_release(&s->output);
273 ff_v4l2_context_release(&s->capture);
275 /* start again now that we know the stream dimensions */
279 ret = ff_v4l2_context_get_format(&s->output, 0);
281 av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
285 ret = ff_v4l2_context_get_format(&s->capture, 0);
287 av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
291 ret = ff_v4l2_context_set_format(&s->output);
293 av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
297 ret = ff_v4l2_context_set_format(&s->capture);
299 av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
303 ret = ff_v4l2_context_init(&s->output);
305 av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
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);
313 av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
324 static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
326 V4L2m2mContext *s = (V4L2m2mContext*)context;
328 ff_v4l2_context_release(&s->capture);
329 sem_destroy(&s->refsync);
332 av_frame_free(&s->frame);
333 av_packet_unref(&s->buf_pkt);
338 int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv)
340 V4L2m2mContext *s = priv->context;
347 ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
349 av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
351 ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
353 av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
356 ff_v4l2_context_release(&s->output);
359 av_buffer_unref(&priv->context_ref);
364 int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv)
366 int ret = AVERROR(EINVAL);
367 struct dirent *entry;
370 V4L2m2mContext *s = priv->context;
372 dirp = opendir("/dev");
374 return AVERROR(errno);
376 for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
378 if (strncmp(entry->d_name, "video", 5))
381 snprintf(s->devname, sizeof(s->devname), "/dev/%s", entry->d_name);
382 av_log(s->avctx, AV_LOG_DEBUG, "probing device %s\n", s->devname);
383 ret = v4l2_probe_driver(s);
391 av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
392 memset(s->devname, 0, sizeof(s->devname));
397 av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", s->devname);
399 return v4l2_configure_contexts(s);
402 int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s)
404 *s = av_mallocz(sizeof(V4L2m2mContext));
406 return AVERROR(ENOMEM);
408 priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext),
409 &v4l2_m2m_destroy_context, NULL, 0);
410 if (!priv->context_ref) {
412 return AVERROR(ENOMEM);
415 /* assign the context */
420 priv->context->capture.num_buffers = priv->num_capture_buffers;
421 priv->context->output.num_buffers = priv->num_output_buffers;
422 priv->context->self_ref = priv->context_ref;
423 priv->context->fd = -1;
425 priv->context->frame = av_frame_alloc();
426 if (!priv->context->frame) {
427 av_buffer_unref(&priv->context_ref);
428 *s = NULL; /* freed when unreferencing context_ref */
429 return AVERROR(ENOMEM);