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