h264-v4l2m2m: Select matching pixel format

h264-v4l2m2m
Andri Yngvason 2024-03-16 16:01:20 +00:00
parent 8c4c2cfa5c
commit ddf023fd3a
1 changed files with 85 additions and 2 deletions

View File

@ -1,6 +1,7 @@
#include "h264-encoder.h" #include "h264-encoder.h"
#include "neatvnc.h" #include "neatvnc.h"
#include "fb.h" #include "fb.h"
#include "pixels.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
@ -9,6 +10,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <drm_fourcc.h>
#include <gbm.h> #include <gbm.h>
#include <aml.h> #include <aml.h>
@ -97,12 +99,93 @@ static bool any_src_buf_is_taken(struct h264_encoder_v4l2m2m* self)
return result; return result;
} }
static int u32_cmp(const void* pa, const void* pb)
{
const uint32_t *a = pa;
const uint32_t *b = pb;
return *a < *b ? -1 : *a > *b;
}
static size_t get_supported_formats(struct h264_encoder_v4l2m2m* self,
uint32_t* formats, size_t max_len)
{
size_t i = 0;
for (;; ++i) {
struct v4l2_fmtdesc desc = {
.index = i,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
};
int rc = ioctl(self->fd, VIDIOC_ENUM_FMT, &desc);
if (rc < 0)
break;
nvnc_trace("Got pixel format: %s", desc.description);
formats[i] = desc.pixelformat;
}
qsort(formats, i, sizeof(*formats), u32_cmp);
return i;
}
static bool have_v4l2_format(const uint32_t* formats, size_t n_formats,
uint32_t format)
{
return bsearch(&format, formats, n_formats, sizeof(format), u32_cmp);
}
static uint32_t v4l2_format_from_drm(const uint32_t* formats,
size_t n_formats, uint32_t drm_format)
{
#define TRY_FORMAT(f) \
if (have_v4l2_format(formats, n_formats, f)) \
return f
switch (drm_format) {
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBA8888:
TRY_FORMAT(V4L2_PIX_FMT_RGBX32);
TRY_FORMAT(V4L2_PIX_FMT_RGBA32);
break;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
TRY_FORMAT(V4L2_PIX_FMT_XRGB32);
TRY_FORMAT(V4L2_PIX_FMT_ARGB32);
TRY_FORMAT(V4L2_PIX_FMT_RGB32);
break;
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRA8888:
TRY_FORMAT(V4L2_PIX_FMT_XBGR32);
TRY_FORMAT(V4L2_PIX_FMT_ABGR32);
TRY_FORMAT(V4L2_PIX_FMT_BGR32);
break;
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
TRY_FORMAT(V4L2_PIX_FMT_BGRX32);
TRY_FORMAT(V4L2_PIX_FMT_BGRA32);
break;
// TODO: More formats
}
return 0;
#undef TRY_FORMAT
}
static int set_src_fmt(struct h264_encoder_v4l2m2m* self) static int set_src_fmt(struct h264_encoder_v4l2m2m* self)
{ {
int rc; int rc;
// TODO: Derive the correct format uint32_t supported_formats[256];
uint32_t format = V4L2_PIX_FMT_RGBA32; size_t n_formats = get_supported_formats(self, supported_formats,
ARRAY_LENGTH(supported_formats));
uint32_t format = v4l2_format_from_drm(supported_formats, n_formats,
self->format);
if (!format) {
nvnc_log(NVNC_LOG_DEBUG, "Failed to find a proper pixel format");
return -1;
}
struct v4l2_format fmt = { struct v4l2_format fmt = {
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,