|
13 | 13 | #include <drm_fourcc.h> |
14 | 14 | #include <cerrno> |
15 | 15 | #include <cstdio> |
| 16 | +#include <cstdlib> |
16 | 17 | #include <cstring> |
17 | 18 | #include <iostream> |
| 19 | +#include <set> |
| 20 | +#include <string> |
18 | 21 | #include <vector> |
19 | 22 |
|
20 | 23 | namespace { |
@@ -158,13 +161,83 @@ bool AllwinnerV4L2Display::setup_drm() { |
158 | 161 | return true; |
159 | 162 | } |
160 | 163 |
|
| 164 | +int AllwinnerV4L2Display::open_candidate_v4l2_device(const char* path) { |
| 165 | + if (!path) |
| 166 | + return -1; |
| 167 | + |
| 168 | + int fd = open(path, O_RDWR | O_NONBLOCK); |
| 169 | + if (fd < 0) |
| 170 | + return -1; |
| 171 | + |
| 172 | + struct v4l2_capability caps; |
| 173 | + memset(&caps, 0, sizeof(caps)); |
| 174 | + if (ioctl(fd, VIDIOC_QUERYCAP, &caps) < 0) { |
| 175 | + close(fd); |
| 176 | + return -1; |
| 177 | + } |
| 178 | + |
| 179 | + uint32_t capability_mask = caps.capabilities; |
| 180 | + if (capability_mask & V4L2_CAP_DEVICE_CAPS) |
| 181 | + capability_mask = caps.device_caps; |
| 182 | + |
| 183 | + bool streaming = capability_mask & V4L2_CAP_STREAMING; |
| 184 | + bool output = capability_mask & (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_OUTPUT); |
| 185 | + bool capture = capability_mask & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_CAPTURE); |
| 186 | + bool mem2mem = capability_mask & (V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_M2M); |
| 187 | + |
| 188 | + if (!streaming || !(mem2mem || (output && capture))) { |
| 189 | + close(fd); |
| 190 | + return -1; |
| 191 | + } |
| 192 | + |
| 193 | + m_v4l2_driver_name = reinterpret_cast<const char*>(caps.driver); |
| 194 | + return fd; |
| 195 | +} |
| 196 | + |
161 | 197 | bool AllwinnerV4L2Display::setup_v4l2() { |
162 | | - m_v4l2_fd = open("/dev/video0", O_RDWR | O_NONBLOCK); |
| 198 | + std::vector<std::string> candidates; |
| 199 | + std::set<std::string> seen; |
| 200 | + |
| 201 | + m_v4l2_driver_name.clear(); |
| 202 | + |
| 203 | + const char* override_device = getenv("FPVUE_V4L2_DEVICE"); |
| 204 | + if (override_device && override_device[0] != '\0') { |
| 205 | + candidates.emplace_back(override_device); |
| 206 | + seen.insert(candidates.back()); |
| 207 | + } |
| 208 | + |
| 209 | + for (int index = 0; index < 32; ++index) { |
| 210 | + char path[32]; |
| 211 | + snprintf(path, sizeof(path), "/dev/video%d", index); |
| 212 | + if (seen.insert(path).second) { |
| 213 | + candidates.emplace_back(path); |
| 214 | + } |
| 215 | + } |
| 216 | + |
| 217 | + for (const auto& device_path : candidates) { |
| 218 | + int fd = open_candidate_v4l2_device(device_path.c_str()); |
| 219 | + if (fd >= 0) { |
| 220 | + m_v4l2_fd = fd; |
| 221 | + m_v4l2_device_path = device_path; |
| 222 | + break; |
| 223 | + } |
| 224 | + } |
| 225 | + |
163 | 226 | if (m_v4l2_fd < 0) { |
| 227 | + if (override_device && override_device[0] != '\0') { |
| 228 | + std::cerr << "Failed to open V4L2 device override '" << override_device |
| 229 | + << "'." << std::endl; |
| 230 | + } |
164 | 231 | perror("open v4l2"); |
165 | 232 | return false; |
166 | 233 | } |
167 | 234 |
|
| 235 | + std::cout << "Using Cedar V4L2 decoder " << m_v4l2_device_path; |
| 236 | + if (!m_v4l2_driver_name.empty()) { |
| 237 | + std::cout << " (driver '" << m_v4l2_driver_name << "')"; |
| 238 | + } |
| 239 | + std::cout << "." << std::endl; |
| 240 | + |
168 | 241 | struct v4l2_format fmt; |
169 | 242 | memset(&fmt, 0, sizeof(fmt)); |
170 | 243 | fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
|
0 commit comments