kmssink: remove dependency on libkms

libkms should not be used, because it imposes limitations on the DRM
API, especially regarding bpp and stride. Instead the DRM IOCTL should
be used directly.

Switch from libkms to the IOCTL interface. Set bpp and height for
framebuffer allocation to properly handle planar video formats.

https://bugzilla.gnome.org/show_bug.cgi?id=773473

Signed-off-by: Víctor Jáquez <vjaquez@igalia.com>
This commit is contained in:
Michael Tretter 2016-10-19 12:39:36 +02:00 committed by Víctor Manuel Jáquez Leal
parent ad661999ad
commit 12e82aac28
6 changed files with 160 additions and 56 deletions

View file

@ -2438,7 +2438,7 @@ dnl *** kms ***
translit(dnm, m, l) AM_CONDITIONAL(USE_KMS, true)
AG_GST_CHECK_FEATURE(KMS, [drm/kms libraries], kms, [
AG_GST_PKG_CHECK_MODULES(GST_ALLOCATORS, gstreamer-allocators-1.0)
PKG_CHECK_MODULES([KMS_DRM], [libdrm >= 2.4.55 libkms], HAVE_KMS=yes, HAVE_KMS=no)
PKG_CHECK_MODULES([KMS_DRM], [libdrm >= 2.4.55], HAVE_KMS=yes, HAVE_KMS=no)
])
dnl *** ladspa ***

View file

@ -27,9 +27,11 @@
#include "config.h"
#endif
#include <drm.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include "gstkmsallocator.h"
@ -40,10 +42,19 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_KMS_MEMORY_TYPE "KMSMemory"
struct kms_bo
{
void *ptr;
size_t size;
size_t offset;
size_t pitch;
unsigned handle;
unsigned int refs;
};
struct _GstKMSAllocatorPrivate
{
int fd;
struct kms_driver *driver;
};
#define parent_class gst_kms_allocator_parent_class
@ -75,45 +86,45 @@ gst_kms_memory_get_fb_id (GstMemory * mem)
}
static gboolean
ensure_kms_driver (GstKMSAllocator * alloc)
check_fd (GstKMSAllocator * alloc)
{
GstKMSAllocatorPrivate *priv;
int err;
priv = alloc->priv;
if (priv->driver)
return TRUE;
if (priv->fd < 0)
return FALSE;
err = kms_create (priv->fd, &priv->driver);
if (err) {
GST_ERROR_OBJECT (alloc, "Could not create KMS driver: %s",
strerror (-err));
return FALSE;
}
return TRUE;
return alloc->priv->fd > -1;
}
static void
gst_kms_allocator_memory_reset (GstKMSAllocator * allocator, GstKMSMemory * mem)
{
int err;
struct drm_mode_destroy_dumb arg = { 0, };
if (!check_fd (allocator))
return;
if (mem->fb_id) {
GST_DEBUG_OBJECT (allocator, "removing fb id %d", mem->fb_id);
drmModeRmFB (allocator->priv->fd, mem->fb_id);
mem->fb_id = 0;
}
if (!ensure_kms_driver (allocator))
if (!mem->bo)
return;
if (mem->bo) {
kms_bo_destroy (&mem->bo);
mem->bo = NULL;
if (mem->bo->ptr != NULL) {
GST_WARNING_OBJECT (allocator, "destroying mapped bo (refcount=%d)",
mem->bo->refs);
munmap (mem->bo->ptr, mem->bo->size);
mem->bo->ptr = NULL;
}
arg.handle = mem->bo->handle;
err = drmIoctl (allocator->priv->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
if (err)
GST_WARNING_OBJECT (allocator,
"Failed to destroy dumb buffer object: %s %d", strerror (errno), errno);
g_free (mem->bo);
mem->bo = NULL;
}
static gboolean
@ -121,26 +132,43 @@ gst_kms_allocator_memory_create (GstKMSAllocator * allocator,
GstKMSMemory * kmsmem, GstVideoInfo * vinfo)
{
gint ret;
guint attrs[] = {
KMS_WIDTH, GST_VIDEO_INFO_WIDTH (vinfo),
KMS_HEIGHT, GST_VIDEO_INFO_HEIGHT (vinfo),
KMS_TERMINATE_PROP_LIST,
};
struct drm_mode_create_dumb arg = { 0, };
guint32 fmt;
if (kmsmem->bo)
return TRUE;
if (!ensure_kms_driver (allocator))
if (!check_fd (allocator))
return FALSE;
ret = kms_bo_create (allocator->priv->driver, attrs, &kmsmem->bo);
if (ret) {
GST_ERROR_OBJECT (allocator, "Failed to create buffer object: %s (%d)",
strerror (-ret), ret);
kmsmem->bo = g_malloc0 (sizeof (*kmsmem->bo));
if (!kmsmem->bo)
return FALSE;
}
fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo));
arg.bpp = gst_drm_bpp_from_drm (fmt);
arg.width = GST_VIDEO_INFO_WIDTH (vinfo);
arg.height = gst_drm_height_from_drm (fmt, GST_VIDEO_INFO_HEIGHT (vinfo));
ret = drmIoctl (allocator->priv->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
if (ret)
goto create_failed;
kmsmem->bo->handle = arg.handle;
kmsmem->bo->size = arg.size;
kmsmem->bo->pitch = arg.pitch;
return TRUE;
/* ERRORS */
create_failed:
{
GST_ERROR_OBJECT (allocator, "Failed to create buffer object: %s (%d)",
strerror (-ret), ret);
g_free (kmsmem->bo);
kmsmem->bo = NULL;
return FALSE;
}
}
static void
@ -202,10 +230,7 @@ gst_kms_allocator_finalize (GObject * obj)
alloc = GST_KMS_ALLOCATOR (obj);
if (alloc->priv->driver)
kms_destroy (&alloc->priv->driver);
if (alloc->priv->fd > -1)
if (check_fd (alloc))
close (alloc->priv->fd);
G_OBJECT_CLASS (parent_class)->finalize (obj);
@ -237,24 +262,46 @@ static gpointer
gst_kms_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
{
GstKMSMemory *kmsmem;
GstKMSAllocator *alloc;
int err;
gpointer out;
struct drm_mode_map_dumb arg = { 0, };
if (!ensure_kms_driver ((GstKMSAllocator *) mem->allocator))
alloc = (GstKMSAllocator *) mem->allocator;
if (!check_fd (alloc))
return NULL;
kmsmem = (GstKMSMemory *) mem;
if (!kmsmem->bo)
return NULL;
out = NULL;
err = kms_bo_map (kmsmem->bo, &out);
/* Reuse existing buffer object mapping if possible */
if (kmsmem->bo->ptr != NULL) {
goto out;
}
arg.handle = kmsmem->bo->handle;
err = drmIoctl (alloc->priv->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
if (err) {
GST_ERROR ("could not map memory: %s %d", strerror (-err), err);
GST_ERROR_OBJECT (alloc, "Failed to get offset of buffer object: %s %d",
strerror (-err), err);
return NULL;
}
return out;
out = mmap (0, kmsmem->bo->size,
PROT_READ | PROT_WRITE, MAP_SHARED, alloc->priv->fd, arg.offset);
if (out == MAP_FAILED) {
GST_ERROR_OBJECT (alloc, "Failed to map dumb buffer object: %s %d",
strerror (errno), errno);
return NULL;
}
kmsmem->bo->ptr = out;
out:
g_atomic_int_inc (&kmsmem->bo->refs);
return kmsmem->bo->ptr;
}
static void
@ -262,12 +309,17 @@ gst_kms_memory_unmap (GstMemory * mem)
{
GstKMSMemory *kmsmem;
if (!ensure_kms_driver ((GstKMSAllocator *) mem->allocator))
if (!check_fd ((GstKMSAllocator *) mem->allocator))
return;
kmsmem = (GstKMSMemory *) mem;
if (kmsmem->bo)
kms_bo_unmap (kmsmem->bo);
if (!kmsmem->bo)
return;
if (g_atomic_int_dec_and_test (&kmsmem->bo->refs)) {
munmap (kmsmem->bo->ptr, kmsmem->bo->size);
kmsmem->bo->ptr = NULL;
}
}
static void
@ -315,7 +367,7 @@ gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
fmt = gst_drm_format_from_video (GST_VIDEO_INFO_FORMAT (vinfo));
if (kmsmem->bo) {
kms_bo_get_prop (kmsmem->bo, KMS_HANDLE, &bo_handles[0]);
bo_handles[0] = kmsmem->bo->handle;
for (i = 1; i < num_planes; i++)
bo_handles[i] = bo_handles[0];
@ -325,7 +377,7 @@ gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem,
* only do this for interleaved formats.
*/
if (num_planes == 1)
kms_bo_get_prop (kmsmem->bo, KMS_PITCH, &pitch);
pitch = kmsmem->bo->pitch;
} else {
for (i = 0; i < num_planes; i++)
bo_handles[i] = kmsmem->gem_handle[i];

View file

@ -28,7 +28,6 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <libkms.h>
G_BEGIN_DECLS
@ -50,6 +49,8 @@ typedef struct _GstKMSAllocatorClass GstKMSAllocatorClass;
typedef struct _GstKMSAllocatorPrivate GstKMSAllocatorPrivate;
typedef struct _GstKMSMemory GstKMSMemory;
struct kms_bo;
struct _GstKMSMemory
{
GstMemory parent;

View file

@ -93,6 +93,57 @@ gst_drm_format_from_video (GstVideoFormat fmt)
return 0;
}
guint32
gst_drm_bpp_from_drm (guint32 drmfmt)
{
guint32 bpp;
switch (drmfmt) {
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV16:
bpp = 8;
break;
case DRM_FORMAT_UYVY:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
bpp = 16;
break;
default:
bpp = 32;
break;
}
return bpp;
}
guint32
gst_drm_height_from_drm (guint32 drmfmt, guint32 height)
{
guint32 ret;
switch (drmfmt) {
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
ret = height * 3 / 2;
break;
case DRM_FORMAT_NV16:
ret = height * 2;
break;
default:
ret = height;
break;
}
return ret;
}
static GstStructure *
gst_video_format_to_structure (GstVideoFormat format)
{

View file

@ -32,6 +32,8 @@ G_BEGIN_DECLS
GstVideoFormat gst_video_format_from_drm (guint32 drmfmt);
guint32 gst_drm_format_from_video (GstVideoFormat fmt);
guint32 gst_drm_bpp_from_drm (guint32 drmfmt);
guint32 gst_drm_height_from_drm (guint32 drmfmt, guint32 height);
GstCaps * gst_kms_sink_caps_template_fill (void);
void gst_video_calculate_device_ratio (guint dev_width,
guint dev_height,

View file

@ -6,15 +6,13 @@ kmssink_sources = [
]
libdrm_dep = dependency('libdrm', version : '>= 2.4.55', required : false)
libkms_dep = dependency('libkms', required : false)
if libdrm_dep.found() and libkms_dep.found()
if libdrm_dep.found()
gstkmssink = library('gstkmssink',
kmssink_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc],
dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, libdrm_dep,
libkms_dep],
dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, libdrm_dep],
install : true,
install_dir : plugins_install_dir,
)