h264-v4l2m2m: Scan for capable v4l2 device
parent
6d8645d6e9
commit
d28b2576e9
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
@ -514,6 +515,111 @@ static void h264_encoder_v4l2m2m_configure(struct h264_encoder_v4l2m2m* self)
|
||||||
ioctl(self->fd, VIDIOC_S_CTRL, &ctrl);
|
ioctl(self->fd, VIDIOC_S_CTRL, &ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool can_encode_to_h264(int fd)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (;; ++i) {
|
||||||
|
struct v4l2_fmtdesc desc = {
|
||||||
|
.index = i,
|
||||||
|
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
|
||||||
|
};
|
||||||
|
int rc = ioctl(fd, VIDIOC_ENUM_FMT, &desc);
|
||||||
|
if (rc < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (desc.pixelformat == V4L2_PIX_FMT_H264)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool can_handle_frame_size(int fd, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (;; ++i) {
|
||||||
|
struct v4l2_frmsizeenum size = {
|
||||||
|
.index = i,
|
||||||
|
.pixel_format = V4L2_PIX_FMT_H264,
|
||||||
|
};
|
||||||
|
int rc = ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size);
|
||||||
|
if (rc < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (size.type) {
|
||||||
|
case V4L2_FRMSIZE_TYPE_DISCRETE:
|
||||||
|
if (size.discrete.width == width &&
|
||||||
|
size.discrete.height == height)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
|
||||||
|
case V4L2_FRMSIZE_TYPE_STEPWISE:
|
||||||
|
if (size.stepwise.min_width <= width &&
|
||||||
|
width <= size.stepwise.max_width &&
|
||||||
|
size.stepwise.min_height <= height &&
|
||||||
|
height <= size.stepwise.max_height &&
|
||||||
|
(16 % size.stepwise.step_width) == 0 &&
|
||||||
|
(16 % size.stepwise.step_height) == 0)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_device_capable(int fd, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
struct v4l2_capability cap = { 0 };
|
||||||
|
int rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
|
||||||
|
if (rc < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32_t required_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
|
||||||
|
if ((cap.capabilities & required_caps) != required_caps)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!can_encode_to_h264(fd))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!can_handle_frame_size(fd, width, height))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_capable_device(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
DIR *dir = opendir("/dev");
|
||||||
|
assert(dir);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct dirent* entry = readdir(dir);
|
||||||
|
if (!entry)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (strncmp(entry->d_name, "video", 5) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char path[256];
|
||||||
|
snprintf(path, sizeof(path), "/dev/%s", entry->d_name);
|
||||||
|
fd = open(path, O_RDWR | O_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_device_capable(fd, width, height)) {
|
||||||
|
nvnc_log(NVNC_LOG_DEBUG, "Using v4l2m2m device: %s",
|
||||||
|
path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
static struct h264_encoder* h264_encoder_v4l2m2m_create(uint32_t width,
|
static struct h264_encoder* h264_encoder_v4l2m2m_create(uint32_t width,
|
||||||
uint32_t height, uint32_t format, int quality)
|
uint32_t height, uint32_t format, int quality)
|
||||||
{
|
{
|
||||||
|
@ -528,8 +634,7 @@ static struct h264_encoder* h264_encoder_v4l2m2m_create(uint32_t width,
|
||||||
self->format = format;
|
self->format = format;
|
||||||
self->quality = quality;
|
self->quality = quality;
|
||||||
|
|
||||||
// TODO: Find a device that supports the given config
|
self->fd = find_capable_device(width, height);
|
||||||
self->fd = open("/dev/video11", O_RDWR | O_CLOEXEC);
|
|
||||||
if (self->fd < 0)
|
if (self->fd < 0)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue