HYL_OK3568_LINUX/buildroot/package/gstreamer1/gst1-plugins-base/0007-HACK-xvimagesink-Support-dma-buffer-rendering.patch
2025-05-10 21:49:39 +08:00

581 lines
18 KiB
Diff

From 7f63060162edc2aee11f727acf5c764b24f3587a Mon Sep 17 00:00:00 2001
From: Jeffy Chen <jeffy.chen@rock-chips.com>
Date: Wed, 3 Jul 2019 19:54:36 +0800
Subject: [PATCH 07/14] HACK: xvimagesink: Support dma buffer rendering
Send dma buffer to xv port when it supports dma port attributes.
Change-Id: I69d94ffb700eb95af83799cdd5cde476d2930f92
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
sys/xvimage/meson.build | 4 +-
sys/xvimage/xvcontext.c | 71 +++++++++-
sys/xvimage/xvcontext.h | 20 +++
sys/xvimage/xvimagesink.c | 270 ++++++++++++++++++++++++++++++++++++--
sys/xvimage/xvimagesink.h | 10 ++
5 files changed, 361 insertions(+), 14 deletions(-)
diff --git a/sys/xvimage/meson.build b/sys/xvimage/meson.build
index ce84ed0..2873c9b 100644
--- a/sys/xvimage/meson.build
+++ b/sys/xvimage/meson.build
@@ -12,6 +12,8 @@ if cc.has_argument ('-Wno-deprecated-declarations')
no_warn_args += '-Wno-deprecated-declarations'
endif
+libdrm_dep = dependency('libdrm')
+
xvideo_dep = dependency('xv', required : get_option('xvideo'))
if xvideo_dep.found()
@@ -19,7 +21,7 @@ if xvideo_dep.found()
xvimage_sources,
c_args : gst_plugins_base_args + no_warn_args,
include_directories: [configinc, libsinc],
- dependencies : [video_dep, gst_base_dep, gst_dep, x11_dep, xshm_dep, xvideo_dep, xi_dep, libm],
+ dependencies : [video_dep, gst_base_dep, gst_dep, x11_dep, xshm_dep, xvideo_dep, xi_dep, libdrm_dep, libm, allocators_dep],
install : true,
install_dir : plugins_install_dir,
)
diff --git a/sys/xvimage/xvcontext.c b/sys/xvimage/xvcontext.c
index 75bebd9..975c3a9 100644
--- a/sys/xvimage/xvcontext.c
+++ b/sys/xvimage/xvcontext.c
@@ -105,7 +105,7 @@ gst_lookup_xv_port_from_adaptor (GstXvContext * context,
the port via XvGrabPort */
static GstCaps *
gst_xvcontext_get_xv_support (GstXvContext * context,
- const GstXvContextConfig * config, GError ** error)
+ GstXvContextConfig * config, GError ** error)
{
gint i;
XvAdaptorInfo *adaptors;
@@ -158,9 +158,11 @@ gst_xvcontext_get_xv_support (GstXvContext * context,
if (!context->xv_port_id)
goto no_ports;
+ config->dma_client_id = context->xv_port_id;
+
/* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
{
- int count, todo = 4;
+ int count, todo = 7;
XvAttribute *const attr = XvQueryPortAttributes (context->disp,
context->xv_port_id, &count);
static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
@@ -168,6 +170,9 @@ gst_xvcontext_get_xv_support (GstXvContext * context,
static const char colorkey[] = "XV_COLORKEY";
static const char iturbt709[] = "XV_ITURBT_709";
static const char *xv_colorspace = "XV_COLORSPACE";
+ static const char dma_client_id[] = XV_DMA_CLIENT_PROP;
+ static const char dma_drm_fourcc[] = XV_DMA_DRM_FOURCC_PROP;
+ static const char dma_drm_afbc[] = XV_DMA_DRM_AFBC_PROP;
GST_DEBUG ("Checking %d Xv port attributes", count);
@@ -176,6 +181,7 @@ gst_xvcontext_get_xv_support (GstXvContext * context,
context->have_colorkey = FALSE;
context->have_iturbt709 = FALSE;
context->have_xvcolorspace = FALSE;
+ context->have_dma_client = FALSE;
for (i = 0; ((i < count) && todo); i++) {
GST_DEBUG ("Got attribute %s", attr[i].name);
@@ -247,6 +253,19 @@ gst_xvcontext_get_xv_support (GstXvContext * context,
} else if (!strcmp (attr[i].name, xv_colorspace)) {
context->have_xvcolorspace = TRUE;
todo--;
+ } else if (!strcmp (attr[i].name, dma_client_id)) {
+ const Atom atom = XInternAtom (context->disp, dma_client_id, False);
+
+ XvSetPortAttribute (context->disp, context->xv_port_id, atom,
+ config->dma_client_id);
+ todo--;
+ context->have_dma_client = TRUE;
+ } else if (!strcmp (attr[i].name, dma_drm_fourcc)) {
+ todo--;
+ context->have_dma_drm_fourcc = TRUE;
+ } else if (!strcmp (attr[i].name, dma_drm_afbc)) {
+ todo--;
+ context->have_dma_drm_afbc = TRUE;
}
}
@@ -361,6 +380,50 @@ gst_xvcontext_get_xv_support (GstXvContext * context,
if (gst_caps_is_empty (caps))
goto no_caps;
+ if (context->have_dma_drm_afbc) {
+ GstCaps *format_caps;
+
+ format_caps = gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, "NV12",
+ "width", GST_TYPE_INT_RANGE, 1, max_w,
+ "height", GST_TYPE_INT_RANGE, 1, max_h,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+ gst_caps_set_simple (format_caps, "arm-afbc", G_TYPE_INT, 1, NULL);
+ gst_caps_append (caps, format_caps);
+ }
+
+ if (context->have_dma_drm_fourcc) {
+ GstCaps *format_caps;
+
+ format_caps = gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, "NV16",
+ "width", GST_TYPE_INT_RANGE, 1, max_w,
+ "height", GST_TYPE_INT_RANGE, 1, max_h,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+ if (context->have_dma_drm_afbc) {
+ gst_caps_ref (format_caps);
+ gst_caps_append (caps, format_caps);
+
+ gst_caps_set_simple (format_caps, "arm-afbc", G_TYPE_INT, 1, NULL);
+ }
+ gst_caps_append (caps, format_caps);
+
+ format_caps = gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, "NV12_10LE40",
+ "width", GST_TYPE_INT_RANGE, 1, max_w,
+ "height", GST_TYPE_INT_RANGE, 1, max_h,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+ if (context->have_dma_drm_afbc) {
+ gst_caps_ref (format_caps);
+ gst_caps_append (caps, format_caps);
+
+ gst_caps_set_simple (format_caps, "arm-afbc", G_TYPE_INT, 1, NULL);
+ }
+ gst_caps_append (caps, format_caps);
+ }
+
+ GST_DEBUG ("Final caps caps: %" GST_PTR_FORMAT, caps);
+
return caps;
/* ERRORS */
@@ -920,6 +983,10 @@ gst_xvcontext_get_format_from_info (GstXvContext * context,
{
GList *list = NULL;
+ /* HACK: Use NV12 format for fake formats */
+ if (context->drm_fourcc != -1)
+ return DRM_FORMAT_NV12;
+
list = context->formats_list;
while (list) {
diff --git a/sys/xvimage/xvcontext.h b/sys/xvimage/xvcontext.h
index ea5424d..e515fcc 100644
--- a/sys/xvimage/xvcontext.h
+++ b/sys/xvimage/xvcontext.h
@@ -42,6 +42,19 @@
#include <gst/video/video.h>
+#include <libdrm/drm_fourcc.h>
+
+#define XV_DMA_CLIENT_PROP "XV_DMA_CLIENT_ID"
+#define XV_DMA_VER_STRIDE_PROP "XV_DMA_VER_STRIDE"
+#define XV_DMA_HOR_STRIDE_PROP "XV_DMA_HOR_STRIDE"
+#define XV_DMA_DRM_FOURCC_PROP "XV_DMA_DRM_FOURCC"
+#define XV_DMA_DRM_AFBC_PROP "XV_DMA_DRM_AFBC"
+#define XV_DMA_CLIENT_PATH "/tmp/.xv_dma_client"
+
+#ifndef DRM_FORMAT_NV12_10
+#define DRM_FORMAT_NV12_10 fourcc_code('N', 'A', '1', '2')
+#endif
+
G_BEGIN_DECLS
typedef struct _GstXvContextConfig GstXvContextConfig;
@@ -70,6 +83,8 @@ struct _GstXvContextConfig
gint hue;
gint saturation;
gboolean cb_changed;
+
+ guint dma_client_id;
};
/**
@@ -167,6 +182,11 @@ struct _GstXvContext
gboolean have_double_buffer;
gboolean have_iturbt709;
gboolean have_xvcolorspace;
+ gboolean have_dma_client;
+ gboolean have_dma_drm_fourcc;
+ gboolean have_dma_drm_afbc;
+
+ guint32 drm_fourcc;
GList *formats_list;
diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c
index e9fcb6c..44c98a9 100644
--- a/sys/xvimage/xvimagesink.c
+++ b/sys/xvimage/xvimagesink.c
@@ -121,6 +121,7 @@
#include <gst/video/colorbalance.h>
/* Helper functions */
#include <gst/video/gstvideometa.h>
+#include <gst/allocators/gstdmabuf.h>
/* Object header */
#include "xvimagesink.h"
@@ -137,6 +138,11 @@
#include <X11/extensions/XInput2.h>
#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
GST_DEBUG_CATEGORY_EXTERN (gst_debug_xv_context);
GST_DEBUG_CATEGORY_EXTERN (gst_debug_xv_image_pool);
GST_DEBUG_CATEGORY (gst_debug_xv_image_sink);
@@ -235,6 +241,173 @@ GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (xvimagesink, "xvimagesink",
/* */
/* ============================================================= */
+static void
+gst_xv_image_sink_check_dma_client (GstXvImageSink * xvimagesink)
+{
+ GstXvContext *context = xvimagesink->context;
+ Atom prop_atom;
+ int xv_value = 0;
+
+ if (!context->have_dma_client)
+ return;
+
+ g_mutex_lock (&context->lock);
+ prop_atom = XInternAtom (context->disp, XV_DMA_CLIENT_PROP, True);
+ if (prop_atom != None) {
+ XvGetPortAttribute (context->disp, context->xv_port_id,
+ prop_atom, &xv_value);
+ }
+ g_mutex_unlock (&context->lock);
+
+ context->have_dma_client = xv_value > 0;
+}
+
+static void
+gst_xv_image_sink_flush_dma_client (GstXvImageSink * xvimagesink)
+{
+ GstXvContext *context = xvimagesink->context;
+ Atom prop_atom;
+ int xv_value;
+
+ if (!context->have_dma_client)
+ return;
+
+ g_mutex_lock (&context->lock);
+ prop_atom = XInternAtom (context->disp, XV_DMA_CLIENT_PROP, True);
+ if (prop_atom != None) {
+ XvSetPortAttribute (context->disp, context->xv_port_id,
+ prop_atom, xvimagesink->config.dma_client_id);
+ XvGetPortAttribute (context->disp, context->xv_port_id,
+ prop_atom, &xv_value);
+ }
+ g_mutex_unlock (&context->lock);
+}
+
+static void
+gst_xv_image_sink_disable_dma_client (GstXvImageSink * xvimagesink)
+{
+ GstXvContext *context = xvimagesink->context;
+ Atom prop_atom;
+
+ if (!context->have_dma_client)
+ return;
+
+ g_mutex_lock (&context->lock);
+ prop_atom = XInternAtom (context->disp, XV_DMA_CLIENT_PROP, True);
+ if (prop_atom != None) {
+ XvSetPortAttribute (context->disp, context->xv_port_id, prop_atom, 0);
+ }
+ g_mutex_unlock (&context->lock);
+
+ context->have_dma_client = FALSE;
+}
+
+static gboolean
+gst_xv_image_sink_send_dma_params (GstXvImageSink * xvimagesink,
+ gint hor_stride, gint ver_stride, gboolean afbc)
+{
+ GstXvContext *context = xvimagesink->context;
+ Atom prop_atom;
+ gboolean error = FALSE;
+
+ if (!context->have_dma_client)
+ return FALSE;
+
+ g_mutex_lock (&context->lock);
+ prop_atom = XInternAtom (context->disp, XV_DMA_HOR_STRIDE_PROP, True);
+ if (prop_atom != None) {
+ XvSetPortAttribute (context->disp, context->xv_port_id,
+ prop_atom, hor_stride);
+ } else {
+ error = TRUE;
+ }
+ prop_atom = XInternAtom (context->disp, XV_DMA_VER_STRIDE_PROP, True);
+ if (prop_atom != None) {
+ XvSetPortAttribute (context->disp, context->xv_port_id,
+ prop_atom, ver_stride);
+ } else {
+ error = TRUE;
+ }
+ prop_atom = XInternAtom (context->disp, XV_DMA_DRM_FOURCC_PROP, True);
+ if (prop_atom != None) {
+ XvSetPortAttribute (context->disp, context->xv_port_id,
+ prop_atom, context->drm_fourcc);
+ }
+ prop_atom = XInternAtom (context->disp, XV_DMA_DRM_AFBC_PROP, True);
+ if (prop_atom != None) {
+ XvSetPortAttribute (context->disp, context->xv_port_id, prop_atom, afbc);
+ }
+ g_mutex_unlock (&context->lock);
+
+ if (error == TRUE) {
+ gst_xv_image_sink_disable_dma_client (xvimagesink);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_xv_image_sink_send_dma_fd (GstXvImageSink * xvimagesink, gint dma_fd)
+{
+ GstXvContext *context = xvimagesink->context;
+ struct sockaddr_un addr;
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *header;
+ gchar buf[CMSG_SPACE (sizeof (int))];
+ gint socket_fd;
+
+ if (!context->have_dma_client)
+ return FALSE;
+
+ gst_xv_image_sink_flush_dma_client (xvimagesink);
+
+ socket_fd = socket (PF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0)
+ goto failed;
+
+ addr.sun_family = AF_LOCAL;
+ snprintf (addr.sun_path, sizeof (addr.sun_path),
+ XV_DMA_CLIENT_PATH ".%d", xvimagesink->config.dma_client_id);
+ addr.sun_path[sizeof (addr.sun_path) - 1] = '\0';
+
+ if (connect (socket_fd, (struct sockaddr *) &addr, sizeof (addr)) < 0)
+ goto failed;
+
+ iov.iov_base = buf;
+ iov.iov_len = 1;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof (buf);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ header = CMSG_FIRSTHDR (&msg);
+ header->cmsg_level = SOL_SOCKET;
+ header->cmsg_type = SCM_RIGHTS;
+
+ header->cmsg_len = CMSG_LEN (sizeof (int));
+ *((int *) CMSG_DATA (header)) = dma_fd;
+ sendmsg (socket_fd, &msg, 0);
+
+ /* Send am empty msg at the end */
+ header->cmsg_len = CMSG_LEN (0);
+ sendmsg (socket_fd, &msg, 0);
+
+ close (socket_fd);
+ return TRUE;
+
+failed:
+ gst_xv_image_sink_disable_dma_client (xvimagesink);
+
+ if (socket_fd >= 0)
+ close (socket_fd);
+
+ return FALSE;
+}
/* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
* if no window was available */
@@ -322,6 +495,13 @@ gst_xv_image_sink_xvimage_put (GstXvImageSink * xvimagesink,
memcpy (&result, &xwindow->render_rect, sizeof (GstVideoRectangle));
}
+ if (gst_buffer_n_memory (xvimage) > 1) {
+ GstMemory *dma_mem = gst_buffer_peek_memory (xvimage, 1);
+ gint dma_fd = gst_dmabuf_memory_get_fd (dma_mem);
+ if (dma_fd >= 0)
+ gst_xv_image_sink_send_dma_fd (xvimagesink, dma_fd);
+ }
+
gst_xvimage_memory_render (mem, &src, xwindow, &result, draw_border);
g_mutex_unlock (&xvimagesink->flow_lock);
@@ -844,6 +1024,27 @@ config_failed:
}
}
+static gboolean
+gst_xv_video_info_from_caps (GstVideoInfo * info, const GstCaps * caps)
+{
+ GstStructure *s;
+ gint value;
+
+ if (!gst_video_info_from_caps (info, caps))
+ return FALSE;
+
+ /* parse AFBC from caps */
+ s = gst_caps_get_structure (caps, 0);
+ if (gst_structure_get_int (s, "arm-afbc", &value)) {
+ if (value)
+ GST_VIDEO_INFO_SET_AFBC (info);
+ else
+ GST_VIDEO_INFO_UNSET_AFBC (info);
+ }
+
+ return TRUE;
+}
+
static gboolean
gst_xv_image_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
{
@@ -866,7 +1067,7 @@ gst_xv_image_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
if (!gst_caps_can_intersect (context->caps, caps))
goto incompatible_caps;
- if (!gst_video_info_from_caps (&info, caps))
+ if (!gst_xv_video_info_from_caps (&info, caps))
goto invalid_format;
xvimagesink->fps_n = info.fps_n;
@@ -976,6 +1177,20 @@ gst_xv_image_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
gst_object_unref (oldpool);
}
+ context->drm_fourcc = -1;
+
+ if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_NV12_10LE40) {
+ if (!context->have_dma_drm_fourcc)
+ return FALSE;
+
+ context->drm_fourcc = DRM_FORMAT_NV12_10;
+ } else if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_NV16) {
+ if (!context->have_dma_drm_fourcc)
+ return FALSE;
+
+ context->drm_fourcc = DRM_FORMAT_NV16;
+ }
+
return TRUE;
/* ERRORS */
@@ -1128,6 +1343,47 @@ gst_xv_image_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
if (res != GST_FLOW_OK)
goto no_buffer;
+ if ((crop_meta = gst_buffer_get_video_crop_meta (buf))) {
+ GstVideoCropMeta *dmeta = gst_buffer_add_video_crop_meta (to_put);
+
+ dmeta->x = crop_meta->x;
+ dmeta->y = crop_meta->y;
+ dmeta->width = crop_meta->width;
+ dmeta->height = crop_meta->height;
+ }
+
+ mem = gst_buffer_peek_memory (buf, 0);
+ gst_xv_image_sink_check_dma_client (xvimagesink);
+ if (gst_is_dmabuf_memory (mem) && xvimagesink->context->have_dma_client) {
+ GstVideoMeta *vmeta = gst_buffer_get_video_meta (buf);
+ gint hor_stride, ver_stride;
+
+ /* If this buffer is dmabuf and the xserver supports dma_client, we will
+ send the dmabuf fd directly */
+ GST_LOG_OBJECT (xvimagesink, "buffer %p is dmabuf, will send dmabuf fd",
+ buf);
+
+ /* Stash the dmabuf in index 1 */
+ gst_buffer_insert_memory (to_put, 1, gst_buffer_get_memory (buf, 0));
+
+ /* Try to send dmabuf params */
+ if (vmeta) {
+ hor_stride = vmeta->stride[0];
+ ver_stride = vmeta->height;
+
+ if (vmeta->n_planes > 1)
+ ver_stride = vmeta->offset[1] / hor_stride;
+ } else {
+ hor_stride = xvimagesink->info.width;
+ ver_stride = xvimagesink->info.height;
+ }
+
+ if (gst_xv_image_sink_send_dma_params (xvimagesink,
+ hor_stride, ver_stride,
+ GST_VIDEO_INFO_IS_AFBC (&xvimagesink->info)))
+ goto put_image;
+ }
+
GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
"slow copy buffer %p into bufferpool buffer %p", buf, to_put);
@@ -1143,17 +1399,9 @@ gst_xv_image_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
gst_video_frame_unmap (&dest);
gst_video_frame_unmap (&src);
-
- if ((crop_meta = gst_buffer_get_video_crop_meta (buf))) {
- GstVideoCropMeta *dmeta = gst_buffer_add_video_crop_meta (to_put);
-
- dmeta->x = crop_meta->x;
- dmeta->y = crop_meta->y;
- dmeta->width = crop_meta->width;
- dmeta->height = crop_meta->height;
- }
}
+put_image:
if (!gst_xv_image_sink_xvimage_put (xvimagesink, to_put))
goto no_window;
@@ -1242,7 +1490,7 @@ gst_xv_image_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
if (caps == NULL)
goto no_caps;
- if (!gst_video_info_from_caps (&info, caps))
+ if (!gst_xv_video_info_from_caps (&info, caps))
goto invalid_caps;
/* the normal size of a frame */
diff --git a/sys/xvimage/xvimagesink.h b/sys/xvimage/xvimagesink.h
index 6f5ffa1..35a3081 100644
--- a/sys/xvimage/xvimagesink.h
+++ b/sys/xvimage/xvimagesink.h
@@ -25,6 +25,16 @@
/* Helper functions */
#include <gst/video/video.h>
+#ifndef GST_VIDEO_FLAG_ARM_AFBC
+#define GST_VIDEO_FLAG_ARM_AFBC (1UL << 31)
+#define GST_VIDEO_INFO_SET_AFBC(i) \
+ GST_VIDEO_INFO_FLAG_SET (i, GST_VIDEO_FLAG_ARM_AFBC)
+#define GST_VIDEO_INFO_UNSET_AFBC(i) \
+ GST_VIDEO_INFO_FLAG_UNSET (i, GST_VIDEO_FLAG_ARM_AFBC)
+#define GST_VIDEO_INFO_IS_AFBC(i) \
+ GST_VIDEO_INFO_FLAG_IS_SET (i, GST_VIDEO_FLAG_ARM_AFBC)
+#endif
+
G_BEGIN_DECLS
#define GST_TYPE_XV_IMAGE_SINK \
(gst_xv_image_sink_get_type())
--
2.20.1