1 /*
2 SPDX-FileCopyrightText: 2010 Jean-Baptiste Mardelle <jb@kdenlive.org>
3
4 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6
7 #include "v4lcapture.h"
8 #include "kdenlivesettings.h"
9
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 #include <fcntl.h>
14 #include <pthread.h>
15 #include <unistd.h>
16
17 #include <linux/videodev2.h>
18 #include <sys/ioctl.h>
19
20 V4lCaptureHandler::V4lCaptureHandler() = default;
21
22 // static
23
getDeviceName(const QString & input)24 QStringList V4lCaptureHandler::getDeviceName(const QString &input)
25 {
26
27 char *src = strdup(input.toUtf8().constData());
28 QString pixelformatdescription;
29 int fd = open(src, O_RDWR | O_NONBLOCK);
30 if (fd < 0) {
31 free(src);
32 return QStringList();
33 }
34 struct v4l2_capability cap
35 {
36 };
37
38 char *devName = nullptr;
39 int captureEnabled = 1;
40 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
41 fprintf(stderr, "Cannot get capabilities.");
42 // return nullptr;
43 } else {
44 devName = strdup(reinterpret_cast<char *>(cap.card));
45 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0u) {
46 // Device cannot capture
47 captureEnabled = 0;
48 }
49 }
50
51 if (captureEnabled != 0) {
52 struct v4l2_format format
53 {
54 };
55 memset(&format, 0, sizeof(format));
56 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
57
58 struct v4l2_fmtdesc fmt
59 {
60 };
61 memset(&fmt, 0, sizeof(fmt));
62 fmt.index = 0;
63 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
64
65 struct v4l2_frmsizeenum sizes
66 {
67 };
68 memset(&sizes, 0, sizeof(sizes));
69
70 struct v4l2_frmivalenum rates
71 {
72 };
73 memset(&rates, 0, sizeof(rates));
74 char value[200];
75
76 while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) != -1) {
77 if (pixelformatdescription.length() > 2000) {
78 break;
79 }
80 if (snprintf(value, sizeof(value), ">%c%c%c%c", fmt.pixelformat >> 0, fmt.pixelformat >> 8, fmt.pixelformat >> 16, fmt.pixelformat >> 24) > 0) {
81 pixelformatdescription.append(value);
82 }
83 fprintf(stderr, "detected format: %s: %c%c%c%c\n", fmt.description, fmt.pixelformat >> 0, fmt.pixelformat >> 8, fmt.pixelformat >> 16,
84 fmt.pixelformat >> 24);
85
86 sizes.pixel_format = fmt.pixelformat;
87 sizes.index = 0;
88 // Query supported frame size
89 while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &sizes) != -1) {
90 struct v4l2_frmsize_discrete image_size = sizes.discrete;
91 // Query supported frame rates
92 rates.index = 0;
93 rates.pixel_format = fmt.pixelformat;
94 rates.width = image_size.width;
95 rates.height = image_size.height;
96 if (pixelformatdescription.length() > 2000) {
97 break;
98 }
99 if (snprintf(value, sizeof(value), ":%dx%d=", image_size.width, image_size.height) > 0) {
100 pixelformatdescription.append(value);
101 }
102 fprintf(stderr, "Size: %dx%d: ", image_size.width, image_size.height);
103 while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &rates) != -1) {
104 if (pixelformatdescription.length() > 2000) {
105 break;
106 }
107 if (snprintf(value, sizeof(value), "%d/%d,", rates.discrete.denominator, rates.discrete.numerator) > 0) {
108 pixelformatdescription.append(value);
109 }
110 fprintf(stderr, "%d/%d, ", rates.discrete.numerator, rates.discrete.denominator);
111 rates.index++;
112 }
113 fprintf(stderr, "\n");
114 sizes.index++;
115 }
116 fmt.index++;
117 }
118 }
119 close(fd);
120 free(src);
121
122 QStringList result;
123 if (devName == nullptr) {
124 return result;
125 }
126 QString deviceName(devName);
127 free(devName);
128 result << (deviceName.isEmpty() ? input : deviceName) << pixelformatdescription;
129 return result;
130 }
131