PeterBee97 commented on code in PR #18745:
URL: https://github.com/apache/nuttx/pull/18745#discussion_r3098456445


##########
arch/sim/src/sim/posix/sim_host_v4l2.c:
##########
@@ -84,27 +88,239 @@ static int host_video_ioctl(int fd, int request, void *arg)
   return r;
 }
 
+static bool host_video_is_capture_device(const char *host_video_dev_path)
+{
+  struct v4l2_capability cap;
+  int fd;
+  bool available = false;
+
+  fd = open(host_video_dev_path, O_RDWR | O_NONBLOCK);
+  if (fd < 0)
+    {
+      fd = open(host_video_dev_path, O_RDONLY | O_NONBLOCK);
+      if (fd < 0)
+        {
+          return false;
+        }
+    }
+
+  memset(&cap, 0, sizeof(cap));
+  if (host_video_ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0)
+    {
+      uint32_t capabilities = cap.device_caps != 0 ? cap.device_caps :
+                              cap.capabilities;
+
+      if ((capabilities & V4L2_CAP_VIDEO_CAPTURE) != 0)
+        {
+          available = true;
+        }
+    }
+
+  close(fd);
+  return available;
+}
+
+static int host_video_get_device_path_by_index(const char *dirpath,
+                                               int index,
+                                               char *devpath,
+                                               size_t devpathlen)
+{
+  DIR *dir;
+  struct dirent *entry;
+  int count = 0;
+
+  dir = opendir(dirpath);
+  if (dir == NULL)
+    {
+      return -errno;
+    }
+
+  while ((entry = readdir(dir)) != NULL)
+    {
+      char path[PATH_MAX];
+
+      if (strncmp(entry->d_name, "video", 5) != 0)
+        {
+          continue;
+        }
+
+      if (snprintf(path, sizeof(path), "/dev/%s", entry->d_name) >=
+          (int)sizeof(path))
+        {
+          continue;
+        }
+
+      if (!host_video_is_capture_device(path))
+        {
+          continue;
+        }
+
+      if (count == index)
+        {
+          if (snprintf(devpath, devpathlen, "%s", path) >= devpathlen)
+            {
+              closedir(dir);
+              return -ENAMETOOLONG;
+            }
+
+          closedir(dir);
+          return 0;
+        }
+
+      count++;
+    }
+
+  closedir(dir);
+  return -ENODEV;
+}
+
+static int host_video_count_devices_in_dir(const char *dirpath)
+{
+  DIR *dir;
+  struct dirent *entry;
+  int count = 0;
+
+  dir = opendir(dirpath);
+  if (dir == NULL)
+    {
+      return -errno;
+    }
+
+  while ((entry = readdir(dir)) != NULL)
+    {
+      char devpath[PATH_MAX];
+
+      if (strncmp(entry->d_name, "video", 5) != 0)
+        {
+          continue;
+        }
+
+      if (snprintf(devpath, sizeof(devpath), "/dev/%s", entry->d_name) >=
+          (int)sizeof(devpath))
+        {
+          continue;
+        }
+
+      if (host_video_is_capture_device(devpath))
+        {
+          count++;
+        }
+    }
+
+  closedir(dir);
+  return count;
+}
+
+static int host_video_resolve_device_path(const char *host_video_dev_path,
+                                          char *resolved_path,
+                                          size_t resolved_path_len)
+{
+  const char *name;
+  char *endptr;
+  long index;
+  int ret;
+
+  name = strrchr(host_video_dev_path, '/');
+  name = name != NULL ? name + 1 : host_video_dev_path;
+
+  if (strncmp(name, "video", 5) != 0)
+    {
+      if (snprintf(resolved_path, resolved_path_len, "%s",
+                   host_video_dev_path) >= (int)resolved_path_len)
+        {
+          return -ENAMETOOLONG;
+        }
+
+      return 0;
+    }
+
+  index = strtol(name + 5, &endptr, 10);
+  if (endptr == name + 5 || *endptr != '\0' || index < 0 ||
+      index > INT_MAX)
+    {
+      return -EINVAL;
+    }
+
+  ret = host_video_get_device_path_by_index("/sys/class/video4linux", index,
+                                            resolved_path,
+                                            resolved_path_len);
+  if (ret == -ENOENT || ret == -ENODEV || ret == -EINVAL)
+    {
+      ret = host_video_get_device_path_by_index("/dev", index,
+                                                resolved_path,
+                                                resolved_path_len);
+    }
+
+  if (ret < 0)
+    {
+      WARN("failed to resolve %s to host capture device: %d",
+           host_video_dev_path, ret);
+    }
+
+  return ret;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
+int host_video_get_device_count(void)
+{
+  int count;
+
+  count = host_video_count_devices_in_dir("/sys/class/video4linux");
+  if (count >= 0)
+    {
+      return count;
+    }
+
+  count = host_video_count_devices_in_dir("/dev");
+  if (count >= 0)
+    {
+      return count;
+    }
+
+  return 0;
+}
+
 bool host_video_is_available(const char *host_video_dev_path)
 {
-  return access(host_video_dev_path, F_OK) == 0;
+  char resolved_path[PATH_MAX];
+  int ret;
+
+  ret = host_video_resolve_device_path(host_video_dev_path, resolved_path,

Review Comment:
   Because I wanted to filter-out non-capture video device. For now I have two 
cameras connected, but 4 video devices under /dev in host. I intentionally 
mapped /dev/video0 and /dev/video2 on host to /dev/video0 and /dev/video1 in 
NuttX. Is this behavior desired or do you prefer mapping directly?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to