hwcontext_vaapi: Only accept a render node when deriving from DRM device

If we are given a non-render node, try to find the matching render node and
fail if that isn't possible.

libva will not accept a non-render device which is not DRM master, because
it requires legacy DRM authentication to succeed in that case:
<https://github.com/intel/libva/blob/master/va/drm/va_drm.c#L68-L75>.  This
is annoying for kmsgrab because in most recording situations DRM master is
already held by something else (such as a windowing system), leading to
device derivation not working and forcing the user to create the target
VAAPI device separately.
This commit is contained in:
Mark Thompson 2020-02-16 20:59:54 +00:00
parent a7b92cb559
commit bc9b6358fb
1 changed files with 43 additions and 3 deletions

View File

@ -1631,6 +1631,7 @@ static int vaapi_device_derive(AVHWDeviceContext *ctx,
AVDRMDeviceContext *src_hwctx = src_ctx->hwctx; AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
VADisplay *display; VADisplay *display;
VAAPIDevicePriv *priv; VAAPIDevicePriv *priv;
int fd;
if (src_hwctx->fd < 0) { if (src_hwctx->fd < 0) {
av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated " av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
@ -1638,17 +1639,56 @@ static int vaapi_device_derive(AVHWDeviceContext *ctx,
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
#if CONFIG_LIBDRM
{
int node_type = drmGetNodeTypeFromFd(src_hwctx->fd);
char *render_node;
if (node_type < 0) {
av_log(ctx, AV_LOG_ERROR, "DRM instance fd does not appear "
"to refer to a DRM device.\n");
return AVERROR(EINVAL);
}
if (node_type == DRM_NODE_RENDER) {
fd = src_hwctx->fd;
} else {
render_node = drmGetRenderDeviceNameFromFd(src_hwctx->fd);
if (!render_node) {
av_log(ctx, AV_LOG_ERROR, "Failed to find a render node "
"matching the DRM device.\n");
return AVERROR(ENODEV);
}
fd = open(render_node, O_RDWR);
if (fd < 0) {
av_log(ctx, AV_LOG_ERROR, "Failed to open render node %s"
"matching the DRM device.\n", render_node);
free(render_node);
return AVERROR(errno);
}
av_log(ctx, AV_LOG_VERBOSE, "Using render node %s in place "
"of non-render DRM device.\n", render_node);
free(render_node);
}
}
#else
fd = src_hwctx->fd;
#endif
priv = av_mallocz(sizeof(*priv)); priv = av_mallocz(sizeof(*priv));
if (!priv) if (!priv)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
// Inherits the fd from the source context, which will close it. if (fd == src_hwctx->fd) {
// The fd is inherited from the source context and we are holding
// a reference to that, we don't want to close it from here.
priv->drm_fd = -1; priv->drm_fd = -1;
} else {
priv->drm_fd = fd;
}
ctx->user_opaque = priv; ctx->user_opaque = priv;
ctx->free = &vaapi_device_free; ctx->free = &vaapi_device_free;
display = vaGetDisplayDRM(src_hwctx->fd); display = vaGetDisplayDRM(fd);
if (!display) { if (!display) {
av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from " av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
"DRM device.\n"); "DRM device.\n");