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>
38
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
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;
68
69 s->capture.done =
s->output.done = 0;
70 s->capture.name =
"capture";
71 s->output.name =
"output";
74
75 memset(&cap, 0, sizeof(cap));
76 ret = ioctl(
s->fd, VIDIOC_QUERYCAP, &cap);
79
81 "driver '%s' on card '%s' in %s mode\n", cap.driver, cap.card,
84
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
92 s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
93 s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
94 return 0;
95 }
96
98 }
99
101 {
102 void *log_ctx =
s->avctx;
104
105 s->fd = open(
s->devname, O_RDWR | O_NONBLOCK, 0);
108
111 goto done;
112
116 goto done;
117 }
118
122 goto done;
123 }
124
125 done:
126 if (close(
s->fd) < 0) {
129 }
130
132
134 }
135
137 {
138 void *log_ctx =
s->avctx;
140 struct v4l2_format ofmt, cfmt;
141
142 s->fd = open(
s->devname, O_RDWR | O_NONBLOCK, 0);
145
149
150 ofmt =
s->output.format;
151 cfmt =
s->capture.format;
154 ofmt.fmt.pix_mp.pixelformat :
155 ofmt.fmt.pix.pixelformat),
157 cfmt.fmt.pix_mp.pixelformat :
158 cfmt.fmt.pix.pixelformat));
159
164 }
165
170 }
171
176 }
177
178 /* decoder's buffers need to be updated at a later stage */
184 }
185 }
186
187 return 0;
188
190 if (close(
s->fd) < 0) {
194 }
196
198 }
199
200 /******************************************************************************
201 *
202 * V4L2 M2M Interface
203 *
204 ******************************************************************************/
206 {
207 void *log_ctx =
s->avctx;
209
211
212 /* 1. streamoff */
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 */
223 while(
sem_wait(&
s->refsync) == -1 && errno == EINTR);
224
226
227 /* 3. get the new capture format */
232 }
233
234 /* 4. set the capture format */
239 }
240
241 /* 5. complete reinit */
244
245 return 0;
246 }
247
249 {
250 void *log_ctx =
s->avctx;
252
254
255 /* wait for pending buffer references */
257 while(
sem_wait(&
s->refsync) == -1 && errno == EINTR);
258
263 }
264
269 }
270
271 /* release and unmmap the buffers */
274
275 /* start again now that we know the stream dimensions */
278
283 }
284
289 }
290
295 }
296
301 }
302
307 }
308
309 /* decoder's buffers need to be updated at a later stage */
315 }
316 }
317
318 return 0;
319
322 }
323
325 {
327
330
335
337 }
338
340 {
343
345 return 0;
346
351
355 }
356
358
361
362 return 0;
363 }
364
366 {
368 struct dirent *entry;
369 DIR *dirp;
370
372
373 dirp = opendir("/dev");
374 if (!dirp)
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);
386 break;
387 }
388
389 closedir(dirp);
390
393 memset(
s->devname, 0,
sizeof(
s->devname));
394
396 }
397
399
401 }
402
404 {
408
414 }
415
416 /* assign the context */
418 (*s)->priv = priv;
419
420 /* populate it */
425
429 *
s =
NULL;
/* freed when unreferencing context_ref */
431 }
432
433 return 0;
434 }