mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-01 22:21:13 +00:00
0fd76c2848
If the allocation function get called from multiple threads at the same time, multiple allocators may get created but only one get saved. Leading to other allocators to be leaked. Simply create it once in the instance initialization. Fixes: #2456 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6052>
752 lines
18 KiB
C
752 lines
18 KiB
C
/* GStreamer
|
|
*
|
|
* Copyright (C) 2023 Collabora
|
|
* Copyright (C) 2016 Igalia
|
|
*
|
|
* Authors:
|
|
* Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
|
|
* Javier Martin <javiermartin@by.com.es>
|
|
* Colin Kinloch <colin.kinloch@collabora.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstdrmdumb.h"
|
|
#include "gstdmabuf.h"
|
|
|
|
/**
|
|
* SECTION:gstdrmdumb
|
|
* @title: GstDRMDumbAllocator
|
|
* @short_description: Memory wrapper for Linux DRM Dumb memory
|
|
* @see_also: #GstMemory
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
|
|
#ifdef HAVE_LIBDRM
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
|
|
#include <drm.h>
|
|
#include <drm_fourcc.h>
|
|
#include <xf86drm.h>
|
|
#endif
|
|
|
|
#define GST_CAT_DEFAULT drmdumballocator_debug
|
|
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
|
|
|
#define GST_DRM_DUMB_MEMORY_TYPE "DRMDumbMemory"
|
|
|
|
typedef struct _GstDRMDumbMemory GstDRMDumbMemory;
|
|
struct _GstDRMDumbMemory
|
|
{
|
|
GstMemory parent;
|
|
|
|
gpointer ptr;
|
|
gsize size;
|
|
guint32 handle;
|
|
guint refs;
|
|
};
|
|
|
|
struct _GstDRMDumbAllocator
|
|
{
|
|
GstAllocator parent;
|
|
|
|
gint drm_fd;
|
|
gchar *drm_device_path;
|
|
|
|
/* protected by GstDRMDumbAllocator object lock */
|
|
GstAllocator *dmabuf_alloc;
|
|
};
|
|
|
|
#define parent_class gst_drm_dumb_allocator_parent_class
|
|
G_DEFINE_TYPE_WITH_CODE (GstDRMDumbAllocator, gst_drm_dumb_allocator,
|
|
GST_TYPE_ALLOCATOR,
|
|
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "drmdumballocator", 0,
|
|
"DRM dumb buffer allocator"));
|
|
enum
|
|
{
|
|
PROP_DRM_FD = 1,
|
|
PROP_DRM_DEVICE_PATH,
|
|
PROP_N,
|
|
};
|
|
|
|
static GParamSpec *g_props[PROP_N] = { NULL, };
|
|
|
|
/**
|
|
* gst_is_drm_dumb_memory:
|
|
* @mem: the memory to be checked
|
|
*
|
|
* Returns: %TRUE if @mem is DRM Dumb memory, otherwise %FALSE
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
gboolean
|
|
gst_is_drm_dumb_memory (GstMemory * mem)
|
|
{
|
|
return gst_memory_is_type (mem, GST_DRM_DUMB_MEMORY_TYPE);
|
|
}
|
|
|
|
/**
|
|
* gst_drm_dumb_memory_get_handle:
|
|
* @mem: the memory to get the handle from
|
|
*
|
|
* Return the DRM buffer object handle associated with @mem.
|
|
*
|
|
* Returns: the DRM buffer object handle associated with the memory, or 0.
|
|
* The handle is still owned by the GstMemory and cannot be used
|
|
* beyond the lifetime of this GstMemory unless it is being passed
|
|
* to DRM driver, which does handle a refcount internally.
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
guint32
|
|
gst_drm_dumb_memory_get_handle (GstMemory * mem)
|
|
{
|
|
if (!gst_is_drm_dumb_memory (mem))
|
|
return 0;
|
|
|
|
return ((GstDRMDumbMemory *) mem)->handle;
|
|
}
|
|
|
|
/**
|
|
* gst_drm_dumb_memory_export_dmabuf:
|
|
* @mem: the memory to export from
|
|
*
|
|
* Exports a DMABuf from the DRM Bumb buffer object. One can check if this
|
|
* feature is supported using gst_drm_dumb_allocator_has_prime_export();
|
|
*
|
|
* Returns: a #GstMemory from #GstDmaBufAllocator wrapping the exported dma-buf
|
|
* file descriptor.
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
GstMemory *
|
|
gst_drm_dumb_memory_export_dmabuf (GstMemory * mem)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
GstDRMDumbMemory *drmmem = (GstDRMDumbMemory *) mem;
|
|
GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (mem->allocator);
|
|
GstMemory *dmamem;
|
|
gint ret;
|
|
gint prime_fd;
|
|
|
|
ret = drmPrimeHandleToFD (alloc->drm_fd, drmmem->handle,
|
|
DRM_CLOEXEC | DRM_RDWR, &prime_fd);
|
|
if (ret)
|
|
goto export_fd_failed;
|
|
|
|
dmamem = gst_dmabuf_allocator_alloc (alloc->dmabuf_alloc, prime_fd,
|
|
gst_memory_get_sizes (mem, NULL, NULL));
|
|
|
|
GST_DEBUG_OBJECT (alloc, "Exported bo handle %d as %d", drmmem->handle,
|
|
prime_fd);
|
|
|
|
return dmamem;
|
|
|
|
/* ERRORS */
|
|
export_fd_failed:
|
|
{
|
|
GST_ERROR_OBJECT (alloc, "Failed to export bo handle %d: %s (%d)",
|
|
drmmem->handle, g_strerror (errno), ret);
|
|
return NULL;
|
|
}
|
|
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_LIBDRM
|
|
static 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:
|
|
case DRM_FORMAT_P010:
|
|
case DRM_FORMAT_P016:
|
|
ret = height * 3 / 2;
|
|
break;
|
|
case DRM_FORMAT_NV16:
|
|
case DRM_FORMAT_NV61:
|
|
ret = height * 2;
|
|
break;
|
|
case DRM_FORMAT_NV24:
|
|
ret = height * 3;
|
|
break;
|
|
default:
|
|
ret = height;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static guint32
|
|
gst_drm_bpp_from_drm (guint32 drm_fourcc)
|
|
{
|
|
guint32 bpp;
|
|
|
|
switch (drm_fourcc) {
|
|
case DRM_FORMAT_YUV420:
|
|
case DRM_FORMAT_YVU420:
|
|
case DRM_FORMAT_YUV422:
|
|
case DRM_FORMAT_NV12:
|
|
case DRM_FORMAT_NV21:
|
|
case DRM_FORMAT_NV16:
|
|
case DRM_FORMAT_NV61:
|
|
case DRM_FORMAT_NV24:
|
|
bpp = 8;
|
|
break;
|
|
case DRM_FORMAT_P010:
|
|
bpp = 10;
|
|
break;
|
|
case DRM_FORMAT_UYVY:
|
|
case DRM_FORMAT_YUYV:
|
|
case DRM_FORMAT_YVYU:
|
|
case DRM_FORMAT_P016:
|
|
case DRM_FORMAT_RGB565:
|
|
case DRM_FORMAT_BGR565:
|
|
bpp = 16;
|
|
break;
|
|
case DRM_FORMAT_BGR888:
|
|
case DRM_FORMAT_RGB888:
|
|
bpp = 24;
|
|
break;
|
|
default:
|
|
bpp = 32;
|
|
break;
|
|
}
|
|
|
|
return bpp;
|
|
}
|
|
|
|
static gboolean
|
|
check_drm_fd (GstDRMDumbAllocator * alloc)
|
|
{
|
|
return alloc->drm_fd > -1;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_open_device (GstDRMDumbAllocator * alloc,
|
|
const gchar * path)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
gint fd = -1;
|
|
|
|
/* Ignore default constructor call */
|
|
if (path == NULL)
|
|
return;
|
|
|
|
/* construct only */
|
|
g_assert (alloc->drm_fd == -1);
|
|
g_assert (alloc->drm_device_path == NULL);
|
|
|
|
fd = open (path, O_RDWR | O_CLOEXEC);
|
|
|
|
if (fd < 0) {
|
|
GST_WARNING_OBJECT (alloc, "Failed to open DRM device at %s", path);
|
|
return;
|
|
}
|
|
|
|
alloc->drm_device_path = g_strdup (path);
|
|
alloc->drm_fd = fd;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_set_fd (GstDRMDumbAllocator * alloc, gint fd)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
/* Ignore default constructor call */
|
|
if (fd == -1)
|
|
return;
|
|
|
|
/* construct only */
|
|
g_assert (alloc->drm_fd == -1);
|
|
g_assert (alloc->drm_device_path == NULL);
|
|
|
|
if (fd >= 0) {
|
|
alloc->drm_device_path = drmGetDeviceNameFromFd2 (fd);
|
|
if (!alloc->drm_device_path) {
|
|
GST_WARNING_OBJECT (alloc, "Failed to verify DRM fd.");
|
|
return;
|
|
}
|
|
|
|
GST_DEBUG_OBJECT (alloc, "Using external FD for %s",
|
|
alloc->drm_device_path);
|
|
|
|
alloc->drm_fd = dup (fd);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_memory_reset (GstDRMDumbAllocator * alloc,
|
|
GstDRMDumbMemory * mem)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
gint err;
|
|
struct drm_mode_destroy_dumb arg = { 0, };
|
|
|
|
if (!mem->size)
|
|
return;
|
|
|
|
if (!check_drm_fd (alloc))
|
|
return;
|
|
|
|
if (mem->ptr != NULL) {
|
|
GST_WARNING_OBJECT (alloc, "destroying mapped bo (refcount=%d)", mem->refs);
|
|
munmap (mem->ptr, mem->size);
|
|
mem->ptr = NULL;
|
|
}
|
|
|
|
arg.handle = mem->handle;
|
|
|
|
err = drmIoctl (alloc->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
|
|
if (err)
|
|
GST_WARNING_OBJECT (alloc,
|
|
"Failed to destroy dumb buffer object: %s %d",
|
|
g_strerror (errno), errno);
|
|
|
|
mem->handle = -1;
|
|
mem->size = 0;
|
|
#endif
|
|
}
|
|
|
|
static gboolean
|
|
gst_drm_dumb_allocator_memory_create (GstDRMDumbAllocator * alloc,
|
|
GstDRMDumbMemory * drmmem,
|
|
guint32 drm_fourcc, guint32 width, guint32 height, guint32 * out_pitch)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
gint ret;
|
|
struct drm_mode_create_dumb arg = { 0, };
|
|
|
|
if (drmmem->size)
|
|
return TRUE;
|
|
|
|
if (!check_drm_fd (alloc))
|
|
return FALSE;
|
|
|
|
arg.bpp = gst_drm_bpp_from_drm (drm_fourcc);
|
|
arg.width = width;
|
|
arg.height = gst_drm_height_from_drm (drm_fourcc, height);
|
|
|
|
ret = drmIoctl (alloc->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
|
|
if (ret)
|
|
goto create_failed;
|
|
|
|
if (!arg.pitch) {
|
|
GST_DEBUG_OBJECT (alloc,
|
|
"DRM dumb buffer pitch not set, no need to modify vinfo");
|
|
goto done;
|
|
}
|
|
|
|
GST_DEBUG_OBJECT (alloc,
|
|
"DRM dumb buffer pitch is set, vinfo modification required");
|
|
*out_pitch = arg.pitch;
|
|
|
|
done:
|
|
drmmem->handle = arg.handle;
|
|
/* will be used used as maxsize of GstMemory */
|
|
drmmem->size = arg.size;
|
|
|
|
return TRUE;
|
|
|
|
/* ERRORS */
|
|
create_failed:
|
|
{
|
|
GST_ERROR_OBJECT (alloc, "Failed to create buffer object: %s (%d)",
|
|
g_strerror (errno), errno);
|
|
return FALSE;
|
|
}
|
|
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_free (GstAllocator * base_alloc, GstMemory * mem)
|
|
{
|
|
GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (base_alloc);
|
|
GstDRMDumbMemory *drmmem;
|
|
|
|
drmmem = (GstDRMDumbMemory *) mem;
|
|
|
|
gst_drm_dumb_allocator_memory_reset (alloc, drmmem);
|
|
g_free (drmmem);
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_DRM_FD:
|
|
gst_drm_dumb_allocator_set_fd (alloc, g_value_get_int (value));
|
|
break;
|
|
case PROP_DRM_DEVICE_PATH:
|
|
gst_drm_dumb_allocator_open_device (alloc, g_value_get_string (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_get_property (GObject * object, guint prop_id,
|
|
GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_DRM_FD:
|
|
g_value_set_int (value, alloc->drm_fd);
|
|
break;
|
|
case PROP_DRM_DEVICE_PATH:
|
|
g_value_set_string (value, alloc->drm_device_path);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_finalize (GObject * obj)
|
|
{
|
|
GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (obj);
|
|
|
|
gst_object_unref (alloc->dmabuf_alloc);
|
|
|
|
g_free (alloc->drm_device_path);
|
|
alloc->drm_device_path = NULL;
|
|
|
|
#ifdef HAVE_LIBDRM
|
|
if (alloc->drm_fd >= 0) {
|
|
close (alloc->drm_fd);
|
|
alloc->drm_fd = -1;
|
|
}
|
|
#endif
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (obj);
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_class_init (GstDRMDumbAllocatorClass * klass)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GstAllocatorClass *allocator_class;
|
|
|
|
allocator_class = GST_ALLOCATOR_CLASS (klass);
|
|
gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
allocator_class->free = gst_drm_dumb_allocator_free;
|
|
|
|
gobject_class->set_property = gst_drm_dumb_allocator_set_property;
|
|
gobject_class->get_property = gst_drm_dumb_allocator_get_property;
|
|
gobject_class->finalize = gst_drm_dumb_allocator_finalize;
|
|
|
|
/**
|
|
* GstDRMDumbAllocator:drm-fd:
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
g_props[PROP_DRM_FD] = g_param_spec_int ("drm-fd", "DRM fd",
|
|
"DRM file descriptor", -1, G_MAXINT, -1,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
/**
|
|
* GstDRMDumbAllocator:drm-device-path: (type filename):
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
g_props[PROP_DRM_DEVICE_PATH] = g_param_spec_string ("drm-device-path",
|
|
"DRM device path", "DRM device path", NULL,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
g_object_class_install_properties (gobject_class, PROP_N, g_props);
|
|
}
|
|
|
|
static gpointer
|
|
gst_drm_dumb_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (mem->allocator);
|
|
GstDRMDumbMemory *drmmem;
|
|
gint err;
|
|
gpointer out;
|
|
struct drm_mode_map_dumb arg = { 0, };
|
|
|
|
|
|
if (!check_drm_fd (alloc))
|
|
return NULL;
|
|
|
|
drmmem = (GstDRMDumbMemory *) mem;
|
|
if (!drmmem->size)
|
|
return NULL;
|
|
|
|
/* Reuse existing buffer object mapping if possible */
|
|
if (drmmem->ptr != NULL) {
|
|
goto out;
|
|
}
|
|
|
|
arg.handle = drmmem->handle;
|
|
|
|
err = drmIoctl (alloc->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
|
|
if (err) {
|
|
GST_ERROR_OBJECT (alloc, "Failed to get offset of buffer object: %s %d",
|
|
g_strerror (errno), errno);
|
|
return NULL;
|
|
}
|
|
|
|
out = mmap (0, drmmem->size,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, alloc->drm_fd, arg.offset);
|
|
if (out == MAP_FAILED) {
|
|
GST_ERROR_OBJECT (alloc, "Failed to map dumb buffer object: %s %d",
|
|
g_strerror (errno), errno);
|
|
return NULL;
|
|
}
|
|
drmmem->ptr = out;
|
|
|
|
out:
|
|
g_atomic_int_inc (&drmmem->refs);
|
|
return drmmem->ptr;
|
|
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_memory_unmap (GstMemory * mem)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
GstDRMDumbMemory *drmmem;
|
|
|
|
if (!check_drm_fd ((GstDRMDumbAllocator *) mem->allocator))
|
|
return;
|
|
|
|
drmmem = (GstDRMDumbMemory *) mem;
|
|
if (!drmmem->size)
|
|
return;
|
|
|
|
if (g_atomic_int_dec_and_test (&drmmem->refs)) {
|
|
munmap (drmmem->ptr, drmmem->size);
|
|
drmmem->ptr = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
gst_drm_dumb_allocator_init (GstDRMDumbAllocator * alloc)
|
|
{
|
|
GstAllocator *base_alloc = GST_ALLOCATOR_CAST (alloc);
|
|
|
|
alloc->drm_fd = -1;
|
|
alloc->drm_device_path = NULL;
|
|
alloc->dmabuf_alloc = gst_dmabuf_allocator_new ();
|
|
|
|
base_alloc->mem_type = GST_DRM_DUMB_MEMORY_TYPE;
|
|
base_alloc->mem_map = gst_drm_dumb_memory_map;
|
|
base_alloc->mem_unmap = gst_drm_dumb_memory_unmap;
|
|
/* Use the default, fallback copy function */
|
|
|
|
GST_OBJECT_FLAG_SET (alloc, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
|
|
}
|
|
|
|
#ifdef HAVE_LIBDRM
|
|
static gboolean
|
|
check_cap (GstDRMDumbAllocator * alloc)
|
|
{
|
|
gint ret;
|
|
guint64 has_dumb = 0;
|
|
|
|
if (!alloc)
|
|
return FALSE;
|
|
|
|
if (!check_drm_fd (alloc))
|
|
return FALSE;
|
|
|
|
ret = drmGetCap (alloc->drm_fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
|
|
if (ret)
|
|
GST_WARNING_OBJECT (alloc, "could not get dumb buffer capability");
|
|
|
|
return !!(has_dumb);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* gst_drm_dumb_allocator_new_with_fd:
|
|
* @drm_fd: file descriptor of the DRM device
|
|
*
|
|
* Creates a new #GstDRMDumbAllocator for the specific file desciptor. This
|
|
* function can fail if the file descriptor is not a DRM device or if
|
|
* the DRM device does not support DUMB allocation.
|
|
*
|
|
* Returns: (transfer full) (nullable): a new DRM Dumb allocator. Use gst_object_unref()
|
|
* to release the allocator after usage.
|
|
*
|
|
* Since: 1.24
|
|
|
|
*/
|
|
GstAllocator *
|
|
gst_drm_dumb_allocator_new_with_fd (gint drm_fd)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
GstDRMDumbAllocator *alloc;
|
|
|
|
alloc = g_object_new (GST_TYPE_DRM_DUMB_ALLOCATOR, "drm-fd", drm_fd, NULL);
|
|
gst_object_ref_sink (alloc);
|
|
|
|
if (!check_drm_fd (alloc))
|
|
g_clear_object (&alloc);
|
|
|
|
if (!check_cap (alloc))
|
|
g_clear_object (&alloc);
|
|
|
|
return alloc ? GST_ALLOCATOR (alloc) : NULL;
|
|
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* gst_drm_dumb_allocator_new_with_device_path:
|
|
* @drm_device_path: (type filename): path to the DRM device to open
|
|
*
|
|
* Creates a new #GstDRMDumbAllocator for the specific device path. This
|
|
* function can fail if the path does not exist, is not a DRM device or if
|
|
* the DRM device doesnot support DUMB allocation.
|
|
*
|
|
* Returns: (transfer full) (nullable): a new DRM Dumb allocator. Use gst_object_unref()
|
|
* to release the allocator after usage.
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
GstAllocator *
|
|
gst_drm_dumb_allocator_new_with_device_path (const gchar * drm_device_path)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
GstDRMDumbAllocator *alloc;
|
|
|
|
alloc = g_object_new (GST_TYPE_DRM_DUMB_ALLOCATOR,
|
|
"drm-device-path", drm_device_path, NULL);
|
|
gst_object_ref_sink (alloc);
|
|
|
|
if (!check_drm_fd (alloc))
|
|
g_clear_object (&alloc);
|
|
|
|
if (!check_cap (alloc))
|
|
g_clear_object (&alloc);
|
|
|
|
return alloc ? GST_ALLOCATOR (alloc) : NULL;
|
|
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* gst_drm_dumb_allocator_alloc:
|
|
* @allocator: (type GstAllocators.DRMDumbAllocator): the allocator instance
|
|
* @drm_fourcc: the DRM format to allocate for
|
|
* @width: padded width for this allocation
|
|
* @height: padded height for this allocation
|
|
* @out_pitch: (out): the pitch as returned by the driver
|
|
*
|
|
* Allocated a DRM buffer object for the specific @drm_fourcc, @width and
|
|
* @height. Note that the DRM Dumb allocation interface is agnostic to the
|
|
* pixel format. This @drm_fourcc is converted into a bpp (bit-per-pixel)
|
|
* number and the height is scaled according to the sub-sampling.
|
|
*
|
|
* Returns: (transfer full): a new DRM Dumb #GstMemory. Use gst_memory_unref()
|
|
* to release the memory after usage.
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
GstMemory *
|
|
gst_drm_dumb_allocator_alloc (GstAllocator * base_alloc,
|
|
guint32 drm_fourcc, guint32 width, guint32 height, guint32 * out_pitch)
|
|
{
|
|
GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (base_alloc);
|
|
GstDRMDumbMemory *drmmem;
|
|
GstMemory *mem;
|
|
|
|
drmmem = g_new0 (GstDRMDumbMemory, 1);
|
|
mem = GST_MEMORY_CAST (drmmem);
|
|
|
|
if (!gst_drm_dumb_allocator_memory_create (alloc, drmmem,
|
|
drm_fourcc, width, height, out_pitch)) {
|
|
g_free (drmmem);
|
|
return NULL;
|
|
}
|
|
|
|
gst_memory_init (mem, 0, base_alloc, NULL, drmmem->size, 0, 0, drmmem->size);
|
|
return mem;
|
|
}
|
|
|
|
/**
|
|
* gst_drm_dumb_allocator_has_prime_export:
|
|
* @allocator: (type GstAllocators.DRMDumbAllocator): the #GstAllocator
|
|
*
|
|
* This function allow verifying if the driver support dma-buf exportation.
|
|
*
|
|
* Returns: %TRUE if the allocator support exporting dma-buf.
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
gboolean
|
|
gst_drm_dumb_allocator_has_prime_export (GstAllocator * base_alloc)
|
|
{
|
|
#ifdef HAVE_LIBDRM
|
|
GstDRMDumbAllocator *alloc = GST_DRM_DUMB_ALLOCATOR (base_alloc);
|
|
gint ret;
|
|
guint64 has_prime = 0;
|
|
|
|
if (!check_drm_fd (alloc))
|
|
return FALSE;
|
|
|
|
ret = drmGetCap (alloc->drm_fd, DRM_CAP_PRIME, &has_prime);
|
|
if (ret)
|
|
GST_WARNING_OBJECT (alloc, "could not get prime capability");
|
|
|
|
return !!(has_prime & DRM_PRIME_CAP_EXPORT);
|
|
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|