linux-v4l2: Change search strategy for v4l2loopback devices

Instead of trying to open devices /dev/video<0-63> check /dev for
all /dev/videoX devices that are existent in the tree. This allows
finding devices with higher names than 63. E.g. /dev/video100 can
now be found and opened which previously failed.

_GNU_SOURCE #define is introduced for versionsort() which is a GNU
extension.

Fixes #4347.
This commit is contained in:
Florian Zwoch 2021-08-25 14:26:37 +02:00 committed by Georges Basile Stavracas Neto
parent fd500f15a3
commit 88aec3b43c

View File

@ -1,3 +1,5 @@
#define _GNU_SOURCE
#include <obs-module.h>
#include <util/dstr.h>
#include <util/platform.h>
@ -5,8 +7,7 @@
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#define MAX_DEVICES 64
#include <dirent.h>
struct virtualcam_data {
obs_output_t *output;
@ -109,7 +110,7 @@ static void *virtualcam_create(obs_data_t *settings, obs_output_t *output)
return vcam;
}
static bool try_connect(void *data, int device)
static bool try_connect(void *data, const char *device)
{
struct virtualcam_data *vcam = (struct virtualcam_data *)data;
struct v4l2_format format;
@ -121,12 +122,7 @@ static bool try_connect(void *data, int device)
vcam->frame_size = width * height * 2;
char new_device[16];
if (device < 0 || device >= MAX_DEVICES)
return false;
snprintf(new_device, 16, "/dev/video%d", device);
vcam->device = open(new_device, O_RDWR);
vcam->device = open(device, O_RDWR);
if (vcam->device < 0)
return false;
@ -172,24 +168,46 @@ static bool try_connect(void *data, int device)
return true;
}
static int scanfilter(const struct dirent *entry)
{
return !astrcmp_n(entry->d_name, "video", 5);
}
static bool virtualcam_start(void *data)
{
struct virtualcam_data *vcam = (struct virtualcam_data *)data;
struct dirent **list;
bool success = false;
int n;
if (!loopback_module_loaded()) {
if (loopback_module_load() != 0)
return false;
}
for (int i = 0; i < MAX_DEVICES; i++) {
if (!try_connect(vcam, i))
continue;
else
return true;
n = scandir("/dev", &list, scanfilter, versionsort);
if (n == -1)
return false;
for (int i = 0; i < n; i++) {
char device[32];
snprintf(device, 32, "/dev/%s", list[i]->d_name);
if (try_connect(vcam, device)) {
success = true;
break;
}
}
blog(LOG_WARNING, "Failed to start virtual camera");
return false;
while (n--)
free(list[n]);
free(list);
if (!success)
blog(LOG_WARNING, "Failed to start virtual camera");
return success;
}
static void virtualcam_stop(void *data, uint64_t ts)