From: Carlos Rafael Giani Date: Wed, 28 Mar 2018 18:53:08 +0000 (+0200) Subject: Update GStreamer patch to be applicable against version 1.14.0 X-Git-Url: https://code.ossystems.io/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F89%2F19189%2F1;p=meta-freescale.git Update GStreamer patch to be applicable against version 1.14.0 Change-Id: Idaa2bb32ed11c13366c567b36b0706820e1c3490 Signed-off-by: Carlos Rafael Giani --- diff --git a/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0001-gstgl-Fix-sanity-check-in-gst_gl_memory_setup_buffer.patch b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0001-gstgl-Fix-sanity-check-in-gst_gl_memory_setup_buffer.patch new file mode 100644 index 00000000..4735d254 --- /dev/null +++ b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0001-gstgl-Fix-sanity-check-in-gst_gl_memory_setup_buffer.patch @@ -0,0 +1,28 @@ +From daa3278503beb6b8ba74b4362622c5e65110708a Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Wed, 7 Jun 2017 18:00:08 +0200 +Subject: [PATCH 1/2] gstgl: Fix sanity check in gst_gl_memory_setup_buffer() + +--- + gst-libs/gst/gl/gstglmemory.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/gst-libs/gst/gl/gstglmemory.c b/gst-libs/gst/gl/gstglmemory.c +index 76d703418..24c2350b8 100644 +--- a/gst-libs/gst/gl/gstglmemory.c ++++ b/gst-libs/gst/gl/gstglmemory.c +@@ -1456,8 +1456,10 @@ gst_gl_memory_setup_buffer (GstGLMemoryAllocator * allocator, + else + views = 1; + ++ /* Sanity check for the code below; either, there are no wrapped pointers, ++ * or there are at least as many pointers as there are memory blocks */ + g_return_val_if_fail (!wrapped_data +- || views * n_mem != n_wrapped_pointers, FALSE); ++ || n_mem >= n_wrapped_pointers, FALSE); + + for (v = 0; v < views; v++) { + for (i = 0; i < n_mem; i++) { +-- +2.14.1 + diff --git a/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0002-gl-egl-Add-gst_egl_image_from_dmabuf_direct-function.patch b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0002-gl-egl-Add-gst_egl_image_from_dmabuf_direct-function.patch new file mode 100644 index 00000000..50631fac --- /dev/null +++ b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0002-gl-egl-Add-gst_egl_image_from_dmabuf_direct-function.patch @@ -0,0 +1,347 @@ +From 56c58831b61cdb79f61f2f68c32854646241326b Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Wed, 28 Mar 2018 00:47:33 +0200 +Subject: [PATCH 2/2] gl/egl: Add gst_egl_image_from_dmabuf_direct() function + +This also renames the existing gst_egl_image_from_dmabuf() to clarify the +difference between the two + +https://bugzilla.gnome.org/show_bug.cgi?id=783521 +--- + docs/libs/gst-plugins-base-libs-sections.txt | 3 +- + gst-libs/gst/gl/egl/gsteglimage.c | 238 ++++++++++++++++++++++++++- + gst-libs/gst/gl/egl/gsteglimage.h | 8 +- + 3 files changed, 239 insertions(+), 10 deletions(-) + +diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt +index c2c528a76..3c4dfdf61 100644 +--- a/docs/libs/gst-plugins-base-libs-sections.txt ++++ b/docs/libs/gst-plugins-base-libs-sections.txt +@@ -3853,7 +3853,8 @@ GstGLBaseFilterPrivate +
+ gsteglimage + GstEGLImage +-gst_egl_image_from_dmabuf ++gst_egl_image_from_dmabuf_as_rgba_plane ++gst_egl_image_from_dmabuf_direct + gst_egl_image_from_texture + gst_egl_image_get_image + gst_egl_image_new_wrapped +diff --git a/gst-libs/gst/gl/egl/gsteglimage.c b/gst-libs/gst/gl/egl/gsteglimage.c +index fdd603807..9f4a018fc 100644 +--- a/gst-libs/gst/gl/egl/gsteglimage.c ++++ b/gst-libs/gst/gl/egl/gsteglimage.c +@@ -29,9 +29,9 @@ + * + * #GstEGLImage represents and holds an #EGLImage handle. + * +- * A #GstEGLImage can be created from a dmabuf with gst_egl_image_from_dmabuf() +- * or #GstGLMemoryEGL provides a #GstAllocator to allocate #EGLImage's bound to +- * and OpenGL texture. ++ * A #GstEGLImage can be created from a dmabuf with gst_egl_image_from_dmabuf_direct() ++ * or gst_egl_image_from_dmabuf_as_rgba_plane(), or #GstGLMemoryEGL provides a ++ * #GstAllocator to allocate #EGLImage's bound to and OpenGL texture. + */ + + #ifdef HAVE_CONFIG_H +@@ -344,12 +344,12 @@ gst_egl_image_from_texture (GstGLContext * context, GstGLMemory * gl_mem, + /* + * GStreamer format descriptions differ from DRM formats as the representation + * is relative to a register, hence in native endianness. To reduce the driver +- * requirement, we only import with a subset of texture formats and use ++ * requirement, we only import with a subset of RGBA texture formats and use + * shaders to convert. This way we avoid having to use external texture + * target. + */ + static int +-_drm_fourcc_from_info (GstVideoInfo * info, int plane) ++_drm_rgba_fourcc_from_info (GstVideoInfo * info, int plane) + { + GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info); + #if G_BYTE_ORDER == G_LITTLE_ENDIAN +@@ -410,19 +410,113 @@ _drm_fourcc_from_info (GstVideoInfo * info, int plane) + return -1; + } + } ++ ++/* ++ * Variant of _drm_rgba_fourcc_from_info() that is used in case the GPU can ++ * handle YUV formats directly (by using internal shaders, or hardwired ++ * YUV->RGB conversion matrices etc.) ++ */ ++static int ++_drm_direct_fourcc_from_info (GstVideoInfo * info) ++{ ++ GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info); ++ ++ GST_DEBUG ("Getting DRM fourcc for %s", gst_video_format_to_string (format)); ++ ++ switch (format) { ++ case GST_VIDEO_FORMAT_YUY2: ++ return DRM_FORMAT_YUYV; ++ ++ case GST_VIDEO_FORMAT_YVYU: ++ return DRM_FORMAT_YVYU; ++ ++ case GST_VIDEO_FORMAT_UYVY: ++ return DRM_FORMAT_UYVY; ++ ++ case GST_VIDEO_FORMAT_VYUY: ++ return DRM_FORMAT_VYUY; ++ ++ case GST_VIDEO_FORMAT_AYUV: ++ return DRM_FORMAT_AYUV; ++ ++ case GST_VIDEO_FORMAT_NV12: ++ return DRM_FORMAT_NV12; ++ ++ case GST_VIDEO_FORMAT_NV21: ++ return DRM_FORMAT_NV21; ++ ++ case GST_VIDEO_FORMAT_NV16: ++ return DRM_FORMAT_NV16; ++ ++ case GST_VIDEO_FORMAT_NV61: ++ return DRM_FORMAT_NV61; ++ ++ case GST_VIDEO_FORMAT_NV24: ++ return DRM_FORMAT_NV24; ++ ++ case GST_VIDEO_FORMAT_YUV9: ++ return DRM_FORMAT_YUV410; ++ ++ case GST_VIDEO_FORMAT_YVU9: ++ return DRM_FORMAT_YVU410; ++ ++ case GST_VIDEO_FORMAT_Y41B: ++ return DRM_FORMAT_YUV411; ++ ++ case GST_VIDEO_FORMAT_I420: ++ return DRM_FORMAT_YUV420; ++ ++ case GST_VIDEO_FORMAT_YV12: ++ return DRM_FORMAT_YVU420; ++ ++ case GST_VIDEO_FORMAT_Y42B: ++ return DRM_FORMAT_YUV422; ++ ++ case GST_VIDEO_FORMAT_Y444: ++ return DRM_FORMAT_YUV444; ++ ++ case GST_VIDEO_FORMAT_RGB16: ++ case GST_VIDEO_FORMAT_BGR16: ++ case GST_VIDEO_FORMAT_RGB: ++ case GST_VIDEO_FORMAT_BGR: ++ case GST_VIDEO_FORMAT_RGBA: ++ case GST_VIDEO_FORMAT_RGBx: ++ case GST_VIDEO_FORMAT_BGRA: ++ case GST_VIDEO_FORMAT_BGRx: ++ case GST_VIDEO_FORMAT_ARGB: ++ case GST_VIDEO_FORMAT_xRGB: ++ case GST_VIDEO_FORMAT_ABGR: ++ case GST_VIDEO_FORMAT_xBGR: ++ case GST_VIDEO_FORMAT_GRAY8: ++ /* Use _drm_rgba_fourcc_from_info() as fallback for RGB formats */ ++ return _drm_rgba_fourcc_from_info (info, 0); ++ ++ default: ++ GST_ERROR ("Unsupported format for DMABuf."); ++ return -1; ++ } ++} + + /** +- * gst_egl_image_from_dmabuf: ++ * gst_egl_image_from_dmabuf_as_rgba_plane: + * @context: a #GstGLContext (must be an EGL context) + * @dmabuf: the DMA-Buf file descriptor + * @in_info: the #GstVideoInfo in @dmabuf + * @plane: the plane in @in_info to create and #GstEGLImage for + * @offset: the byte-offset in the data + * ++ * Creates an EGL image that imports the dmabuf FD. The dmabuf data ++ * is passed as RGBA data. Shaders later take this "RGBA" data and ++ * convert it from its true format (described by in_info) to actual ++ * RGBA output. For example, with I420, three EGL images are created, ++ * one for each plane, each EGL image with a single-channel R format. ++ * With NV12, two EGL images are created, one with R format, one ++ * with RG format etc. ++ * + * Returns: a #GstEGLImage wrapping @dmabuf or %NULL on failure + */ + GstEGLImage * +-gst_egl_image_from_dmabuf (GstGLContext * context, ++gst_egl_image_from_dmabuf_as_rgba_plane (GstGLContext * context, + gint dmabuf, GstVideoInfo * in_info, gint plane, gsize offset) + { + GstGLFormat format; +@@ -432,7 +526,7 @@ gst_egl_image_from_dmabuf (GstGLContext * context, + gint fourcc; + gint i; + +- fourcc = _drm_fourcc_from_info (in_info, plane); ++ fourcc = _drm_rgba_fourcc_from_info (in_info, plane); + format = gst_gl_format_from_video_info (context, in_info, plane); + + GST_DEBUG ("fourcc %.4s (%d) plane %d (%dx%d)", +@@ -470,6 +564,134 @@ gst_egl_image_from_dmabuf (GstGLContext * context, + (GstEGLImageDestroyNotify) _destroy_egl_image); + } + ++/** ++ * gst_egl_image_from_dmabuf_direct: ++ * @context: a #GstGLContext (must be an EGL context) ++ * @buffer: the #GstBuffer containing DMA-Buf memory ++ * @in_info: the #GstVideoInfo in @dmabuf ++ * ++ * Creates an EGL image that imports the dmabuf FD. The dmabuf data ++ * is passed directly as the format described in in_info. This is ++ * useful if the hardware is capable of performing color space conversions ++ * internally. The appropriate DRM format is picked, and the EGL image ++ * is created with this DRM format. ++ * ++ * Another notable difference to gst_egl_image_from_dmabuf_as_rgba_plane() ++ * is that this function creates one EGL image for all planes, not just one. ++ * ++ * Returns: a #GstEGLImage wrapping @dmabuf or %NULL on failure ++ */ ++GstEGLImage * ++gst_egl_image_from_dmabuf_direct (GstGLContext * context, ++ GstBuffer * buffer, GstVideoInfo * in_info) ++{ ++#define MAX_NUM_DMA_BUF_PLANES (3) ++ ++ guint mems_idx[MAX_NUM_DMA_BUF_PLANES]; ++ gsize mems_skip[MAX_NUM_DMA_BUF_PLANES]; ++ GstMemory *mems[MAX_NUM_DMA_BUF_PLANES]; ++ EGLImageKHR img; ++ guint n_planes = GST_VIDEO_INFO_N_PLANES (in_info); ++ gint fourcc = _drm_direct_fourcc_from_info (in_info); ++ gint i; ++ ++ /* Explanation of array length: ++ * - 6 plane independent values are at the start (width, height, format FourCC) ++ * - 6 values per plane, and there are up to MAX_NUM_DMA_BUF_PLANES planes ++ * - 1 extra value for the EGL_NONE sentinel ++ */ ++ guintptr attribs[6 + 6 * (MAX_NUM_DMA_BUF_PLANES) + 1] = { ++ EGL_WIDTH, GST_VIDEO_INFO_WIDTH (in_info), ++ EGL_HEIGHT, GST_VIDEO_INFO_HEIGHT (in_info), ++ EGL_LINUX_DRM_FOURCC_EXT, fourcc ++ }; ++ ++ static const EGLint egl_dmabuf_plane_fd_attr[MAX_NUM_DMA_BUF_PLANES] = { ++ EGL_DMA_BUF_PLANE0_FD_EXT, ++ EGL_DMA_BUF_PLANE1_FD_EXT, ++ EGL_DMA_BUF_PLANE2_FD_EXT, ++ }; ++ static const EGLint egl_dmabuf_plane_offset_attr[MAX_NUM_DMA_BUF_PLANES] = { ++ EGL_DMA_BUF_PLANE0_OFFSET_EXT, ++ EGL_DMA_BUF_PLANE1_OFFSET_EXT, ++ EGL_DMA_BUF_PLANE2_OFFSET_EXT, ++ }; ++ static const EGLint egl_dmabuf_plane_pitch_attr[MAX_NUM_DMA_BUF_PLANES] = { ++ EGL_DMA_BUF_PLANE0_PITCH_EXT, ++ EGL_DMA_BUF_PLANE1_PITCH_EXT, ++ EGL_DMA_BUF_PLANE2_PITCH_EXT, ++ }; ++ ++ /* Make sure we never set up more than MAX_NUM_DMA_BUF_PLANES planes */ ++ if (G_UNLIKELY (n_planes > MAX_NUM_DMA_BUF_PLANES)) ++ n_planes = MAX_NUM_DMA_BUF_PLANES; ++ ++ GST_DEBUG ("Setting up EGL image attributes for %u plane(s)", n_planes); ++ ++ for (i = 0; i < n_planes; i++) { ++ guint plane_size; ++ guint length; ++ gsize offset, stride; ++ gint fd; ++ ++ plane_size = gst_gl_get_plane_data_size (in_info, NULL, i); ++ ++ /* In the buffer, find the memory block that corresponds to the current plane, ++ * and note down the offset (which is needed for the EGLImage) and the index ++ * of the memory block */ ++ if (!gst_buffer_find_memory (buffer, in_info->offset[i], plane_size, ++ &mems_idx[i], &length, &mems_skip[i])) { ++ GST_DEBUG ("Couldn't find memory for plane %d", i); ++ return NULL; ++ } ++ ++ /* We can't have more then one dmabuf per plane */ ++ if (length != 1) { ++ GST_DEBUG ++ ("There are multiple dmabufs for plane %d, which is unsupported", i); ++ return NULL; ++ } ++ ++ /* Get a pointer to the memory block we found earlier */ ++ mems[i] = gst_buffer_peek_memory (buffer, mems_idx[i]); ++ ++ /* And all memory found must be dmabuf */ ++ if (!gst_is_dmabuf_memory (mems[i])) { ++ GST_DEBUG ("Plane %d memory isn't dmabuf", i); ++ return NULL; ++ } ++ ++ fd = gst_dmabuf_memory_get_fd (mems[i]); ++ offset = mems[i]->offset + mems_skip[i]; ++ stride = GST_VIDEO_INFO_PLANE_STRIDE (in_info, i); ++ ++ /* Set up configuration for the i-th plane */ ++ attribs[6 + 6 * i + 0] = egl_dmabuf_plane_fd_attr[i]; ++ attribs[6 + 6 * i + 1] = fd; ++ attribs[6 + 6 * i + 2] = egl_dmabuf_plane_offset_attr[i]; ++ attribs[6 + 6 * i + 3] = offset; ++ attribs[6 + 6 * i + 4] = egl_dmabuf_plane_pitch_attr[i]; ++ attribs[6 + 6 * i + 5] = stride; ++ ++ GST_DEBUG ("Plane %d has FD %d offset %" G_GSIZE_FORMAT " stride %" ++ G_GSIZE_FORMAT, i, fd, offset, stride); ++ } ++ ++ /* Add the EGL_NONE sentinel */ ++ attribs[6 + 6 * n_planes] = EGL_NONE; ++ ++ img = _gst_egl_image_create (context, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); ++ if (!img) { ++ GST_WARNING ("eglCreateImage failed: %s", ++ gst_egl_get_error_string (eglGetError ())); ++ return NULL; ++ } ++ ++ /* TODO: RGBA or RGB? */ ++ return gst_egl_image_new_wrapped (context, img, GST_GL_RGB, NULL, ++ (GstEGLImageDestroyNotify) _destroy_egl_image); ++} ++ + gboolean + gst_egl_image_export_dmabuf (GstEGLImage * image, int *fd, gint * stride, + gsize * offset) +diff --git a/gst-libs/gst/gl/egl/gsteglimage.h b/gst-libs/gst/gl/egl/gsteglimage.h +index aaebceccf..5a75bc4f9 100644 +--- a/gst-libs/gst/gl/egl/gsteglimage.h ++++ b/gst-libs/gst/gl/egl/gsteglimage.h +@@ -83,11 +83,17 @@ GstEGLImage * gst_egl_image_from_texture (GstGLContext * + guintptr * attribs); + #if GST_GL_HAVE_DMABUF + GST_GL_API +-GstEGLImage * gst_egl_image_from_dmabuf (GstGLContext * context, ++GstEGLImage * gst_egl_image_from_dmabuf_as_rgba_plane (GstGLContext * context, + gint dmabuf, + GstVideoInfo * in_info, + gint plane, + gsize offset); ++ ++GST_GL_API ++GstEGLImage * gst_egl_image_from_dmabuf_direct (GstGLContext * context, ++ GstBuffer * buffer, ++ GstVideoInfo * in_info); ++ + GST_GL_API + gboolean gst_egl_image_export_dmabuf (GstEGLImage *image, int *fd, gint *stride, gsize *offset); + #endif +-- +2.14.1 + diff --git a/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0003-gstgl-Add-direct-DMABUF-uploader-WIP.patch b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0003-gstgl-Add-direct-DMABUF-uploader-WIP.patch new file mode 100644 index 00000000..f93eccc0 --- /dev/null +++ b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0003-gstgl-Add-direct-DMABUF-uploader-WIP.patch @@ -0,0 +1,378 @@ +From 6136bc631e5e875ed6b75d994564dd5fd09c7bf3 Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Wed, 7 Jun 2017 18:23:52 +0200 +Subject: [PATCH] gstgl: Add direct DMABUF uploader [WIP] + +This is the first, work-in-progress version of a new "direct" DMABUF +uploader. The idea is that some GPUs (like the Vivante series) can actually +perform the YUV->RGB conversion internally, so no custom conversion shaders +are needed. To make use of this feature, we need an additional uploader +that can import DMABUF FDs and also directly pass the pixel format, +relying on the GPU to do the conversion. + +This patch is incomplete for these reasons: +- It is currently unknown how to determine if the GPU can handle these + conversions +- Currently it is not possible to probe for what EGLImage DMABUF input + formats the GPU can handle +- The EGLImage cache is there, but cannot be used, because some drivers + like etnaviv keep a cached copy of the texture inside, and it is + currently not clear how to let etnaviv know that the cache has to be + flushed once the associated DMABUF gets a new video frame +--- + gst-libs/gst/gl/gstglupload.c | 290 +++++++++++++++++++++++++++++++++++++----- + 1 file changed, 256 insertions(+), 34 deletions(-) + +diff --git a/gst-libs/gst/gl/gstglupload.c b/gst-libs/gst/gl/gstglupload.c +index feaf2f68e..28abc898d 100644 +--- a/gst-libs/gst/gl/gstglupload.c ++++ b/gst-libs/gst/gl/gstglupload.c +@@ -36,6 +36,7 @@ + + #if GST_GL_HAVE_DMABUF + #include ++#include + #endif + + #if GST_GL_HAVE_VIV_DIRECTVIV +@@ -480,7 +481,256 @@ static const UploadMethod _gl_memory_upload = { + &_gl_memory_upload_free + }; + ++ + #if GST_GL_HAVE_DMABUF ++ ++ ++static GQuark ++_eglimage_quark (gint plane) ++{ ++ static GQuark quark[4] = { 0 }; ++ static const gchar *quark_str[] = { ++ "GstGLDMABufEGLImage0", ++ "GstGLDMABufEGLImage1", ++ "GstGLDMABufEGLImage2", ++ "GstGLDMABufEGLImage3", ++ }; ++ ++ if (!quark[plane]) ++ quark[plane] = g_quark_from_static_string (quark_str[plane]); ++ ++ return quark[plane]; ++} ++ ++static GstEGLImage * ++_get_cached_eglimage (GstMiniObject * mobj, gint plane) ++{ ++ return gst_mini_object_get_qdata (mobj, _eglimage_quark (plane)); ++} ++ ++static void ++_set_cached_eglimage (GstMiniObject * mobj, GstEGLImage * eglimage, gint plane) ++{ ++ return gst_mini_object_set_qdata (mobj, ++ _eglimage_quark (plane), eglimage, (GDestroyNotify) gst_egl_image_unref); ++} ++ ++/* TODO: the normal and direct dmabuf uploader share a lot of code. ++ * Perhaps they can be merged. */ ++struct DirectDmabufUpload ++{ ++ GstGLUpload *upload; ++ ++ GstEGLImage *eglimage; ++ GstBuffer *outbuf; ++ GstGLVideoAllocationParams *params; ++}; ++ ++/* TODO add format probing (requires EGL_EXT_image_dma_buf_import_modifiers) ++ * Currently this list is just hardcoded */ ++#define GST_GL_DIRECT_DMABUF_FORMAT "{YUY2, NV12, I420}" ++ ++static GstStaticCaps _direct_dma_buf_upload_caps = ++GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_DIRECT_DMABUF_FORMAT)); ++ ++static gpointer ++_direct_dma_buf_upload_new (GstGLUpload * upload) ++{ ++ struct DirectDmabufUpload *dmabuf = g_new0 (struct DirectDmabufUpload, 1); ++ dmabuf->upload = upload; ++ return dmabuf; ++} ++ ++static GstCaps * ++_direct_dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context, ++ GstPadDirection direction, GstCaps * caps) ++{ ++ GstCapsFeatures *passthrough = ++ gst_caps_features_from_string ++ (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION); ++ GstCaps *ret; ++ ++ if (direction == GST_PAD_SINK) { ++ GstCaps *tmp; ++ ++ ret = ++ _set_caps_features_with_passthrough (caps, ++ GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough); ++ ++ gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL); ++ tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D); ++ gst_caps_unref (ret); ++ ret = tmp; ++ } else { ++ GstCaps *tmp; ++ tmp = gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES ++ (GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, GST_GL_DIRECT_DMABUF_FORMAT)); ++ ret = ++ _set_caps_features_with_passthrough (tmp, ++ GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, passthrough); ++ gst_caps_unref (tmp); ++ } ++ ++ gst_caps_features_free (passthrough); ++ return ret; ++} ++ ++static gboolean ++_direct_dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, ++ GstCaps * in_caps, GstCaps * out_caps) ++{ ++ struct DirectDmabufUpload *dmabuf = impl; ++ GstVideoInfo *in_info = &dmabuf->upload->priv->in_info; ++ guint n_planes = GST_VIDEO_INFO_N_PLANES (in_info); ++ GstVideoMeta *meta; ++ guint n_mem; ++ guint i; ++ ++ n_mem = gst_buffer_n_memory (buffer); ++ meta = gst_buffer_get_video_meta (buffer); ++ ++ /* dmabuf upload is only supported with EGL contexts. */ ++ if (gst_gl_context_get_gl_platform (dmabuf->upload->context) != ++ GST_GL_PLATFORM_EGL) ++ return FALSE; ++ ++ if (!gst_gl_context_check_feature (dmabuf->upload->context, ++ "EGL_KHR_image_base")) ++ return FALSE; ++ ++ /* This will eliminate most non-dmabuf out there */ ++ if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (buffer, 0))) ++ return FALSE; ++ ++ /* We cannot have multiple dmabuf per plane */ ++ if (n_mem > n_planes) ++ return FALSE; ++ ++ /* Update video info based on video meta */ ++ if (meta) { ++ in_info->width = meta->width; ++ in_info->height = meta->height; ++ ++ for (i = 0; i < meta->n_planes; i++) { ++ in_info->offset[i] = meta->offset[i]; ++ in_info->stride[i] = meta->stride[i]; ++ } ++ } ++ ++ if (dmabuf->params) ++ gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params); ++ if (!(dmabuf->params = ++ gst_gl_video_allocation_params_new_wrapped_gl_handle (dmabuf-> ++ upload->context, NULL, &dmabuf->upload->priv->out_info, -1, NULL, ++ GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, NULL, ++ NULL, NULL))) ++ return FALSE; ++ ++ /* Now create an EGLImage for each dmabufs */ ++ { ++ /* check if one is cached */ ++ dmabuf->eglimage = _get_cached_eglimage (GST_MINI_OBJECT (buffer), 0); ++ /* TODO: This is a hack that effectively disables caching. ++ * Currently it is not possible to inform some GPU drivers (like etnaviv) ++ * that they should invalidate whatever texture-related cache they have, ++ * so even if the associated dmabuf changes, the texture doesn't.. So, as ++ * a workaround, were disable caching here and force the reinitialization ++ * of EGLImages. Fix the texture cache updates and then remove the #if ++ * block below. */ ++#if 1 ++ dmabuf->eglimage = NULL; ++#endif ++ ++ if (!dmabuf->eglimage) { ++ /* otherwise create one and cache it */ ++ ++ dmabuf->eglimage = ++ gst_egl_image_from_dmabuf_direct (dmabuf->upload->context, ++ buffer, in_info); ++ ++ if (!dmabuf->eglimage) ++ return FALSE; ++ ++ _set_cached_eglimage (GST_MINI_OBJECT (buffer), dmabuf->eglimage, 0); ++ } ++ ++ GST_TRACE ("Got GstEGLImage %p", (gpointer) (dmabuf->eglimage)); ++ } ++ ++ return TRUE; ++} ++ ++static void ++_direct_dma_buf_upload_propose_allocation (gpointer impl, ++ GstQuery * decide_query, GstQuery * query) ++{ ++ /* nothing to do for now. */ ++} ++ ++static void ++_direct_dma_buf_upload_perform_gl_thread (GstGLContext * context, ++ struct DirectDmabufUpload *dmabuf) ++{ ++ GstGLMemoryAllocator *allocator; ++ gpointer ptr; ++ ++ allocator = ++ GST_GL_MEMORY_ALLOCATOR (gst_allocator_find ++ (GST_GL_MEMORY_EGL_ALLOCATOR_NAME)); ++ ++ /* FIXME: buffer pool */ ++ dmabuf->outbuf = gst_buffer_new (); ++ ptr = (gpointer *) dmabuf->eglimage; ++ gst_gl_memory_setup_buffer (allocator, dmabuf->outbuf, dmabuf->params, NULL, ++ &ptr, 1); ++ gst_object_unref (allocator); ++} ++ ++static GstGLUploadReturn ++_direct_dma_buf_upload_perform (gpointer impl, GstBuffer * buffer, ++ GstBuffer ** outbuf) ++{ ++ struct DirectDmabufUpload *dmabuf = impl; ++ ++ gst_gl_context_thread_add (dmabuf->upload->context, ++ (GstGLContextThreadFunc) _direct_dma_buf_upload_perform_gl_thread, ++ dmabuf); ++ ++ if (!dmabuf->outbuf) ++ return GST_GL_UPLOAD_ERROR; ++ ++ gst_buffer_add_parent_buffer_meta (dmabuf->outbuf, buffer); ++ ++ *outbuf = dmabuf->outbuf; ++ dmabuf->outbuf = NULL; ++ ++ return GST_GL_UPLOAD_DONE; ++} ++ ++static void ++_direct_dma_buf_upload_free (gpointer impl) ++{ ++ struct DirectDmabufUpload *dmabuf = impl; ++ ++ if (dmabuf->params) ++ gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params); ++ ++ g_free (impl); ++} ++ ++static const UploadMethod _direct_dma_buf_upload = { ++ "DirectDmabuf", ++ 0, ++ &_direct_dma_buf_upload_caps, ++ &_direct_dma_buf_upload_new, ++ &_direct_dma_buf_upload_transform_caps, ++ &_direct_dma_buf_upload_accept, ++ &_direct_dma_buf_upload_propose_allocation, ++ &_direct_dma_buf_upload_perform, ++ &_direct_dma_buf_upload_free ++}; ++ ++ + struct DmabufUpload + { + GstGLUpload *upload; +@@ -543,37 +793,6 @@ _dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context, + return ret; + } + +-static GQuark +-_eglimage_quark (gint plane) +-{ +- static GQuark quark[4] = { 0 }; +- static const gchar *quark_str[] = { +- "GstGLDMABufEGLImage0", +- "GstGLDMABufEGLImage1", +- "GstGLDMABufEGLImage2", +- "GstGLDMABufEGLImage3", +- }; +- +- if (!quark[plane]) +- quark[plane] = g_quark_from_static_string (quark_str[plane]); +- +- return quark[plane]; +-} +- +-static GstEGLImage * +-_get_cached_eglimage (GstMemory * mem, gint plane) +-{ +- return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), +- _eglimage_quark (plane)); +-} +- +-static void +-_set_cached_eglimage (GstMemory * mem, GstEGLImage * eglimage, gint plane) +-{ +- return gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), +- _eglimage_quark (plane), eglimage, (GDestroyNotify) gst_egl_image_unref); +-} +- + static gboolean + _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps, + GstCaps * out_caps) +@@ -652,20 +871,20 @@ _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps, + /* Now create an EGLImage for each dmabufs */ + for (i = 0; i < n_planes; i++) { + /* check if one is cached */ +- dmabuf->eglimage[i] = _get_cached_eglimage (mems[i], i); ++ dmabuf->eglimage[i] = _get_cached_eglimage (GST_MINI_OBJECT (mems[i]), i); + if (dmabuf->eglimage[i]) + continue; + + /* otherwise create one and cache it */ + dmabuf->eglimage[i] = +- gst_egl_image_from_dmabuf (dmabuf->upload->context, ++ gst_egl_image_from_dmabuf_as_rgba_plane (dmabuf->upload->context, + gst_dmabuf_memory_get_fd (mems[i]), in_info, i, + mems[i]->offset + mems_skip[i]); + + if (!dmabuf->eglimage[i]) + return FALSE; + +- _set_cached_eglimage (mems[i], dmabuf->eglimage[i], i); ++ _set_cached_eglimage (GST_MINI_OBJECT (mems[i]), dmabuf->eglimage[i], i); + } + + return TRUE; +@@ -737,8 +956,10 @@ static const UploadMethod _dma_buf_upload = { + &_dma_buf_upload_free + }; + ++ + #endif /* GST_GL_HAVE_DMABUF */ + ++ + struct GLUploadMeta + { + GstGLUpload *upload; +@@ -1523,6 +1744,7 @@ static const UploadMethod _directviv_upload = { + + static const UploadMethod *upload_methods[] = { &_gl_memory_upload, + #if GST_GL_HAVE_DMABUF ++ &_direct_dma_buf_upload, + &_dma_buf_upload, + #endif + #if GST_GL_HAVE_VIV_DIRECTVIV +-- +2.14.1 + diff --git a/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base_1.14.%.bbappend b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base_1.14.%.bbappend new file mode 100644 index 00000000..d39cdd6d --- /dev/null +++ b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base_1.14.%.bbappend @@ -0,0 +1,12 @@ +PACKAGECONFIG_GL_imxgpu2d = "${@bb.utils.contains('DISTRO_FEATURES', 'opengl x11', 'opengl', '', d)}" +PACKAGECONFIG_GL_imxgpu3d = "${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'gles2', '', d)}" + +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +PACKAGECONFIG_GL_mainline-bsp = "${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'gles2', '', d)}" + +SRC_URI_append = " \ + file://0001-gstgl-Fix-sanity-check-in-gst_gl_memory_setup_buffer.patch \ + file://0002-gl-egl-Add-gst_egl_image_from_dmabuf_direct-function.patch \ + file://0003-gstgl-Add-direct-DMABUF-uploader-WIP.patch \ +" diff --git a/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good/0008-qmlglsink-Retain-the-previous-frame-to-avoid-flicker.patch b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good/0008-qmlglsink-Retain-the-previous-frame-to-avoid-flicker.patch new file mode 100644 index 00000000..2dc3b12d --- /dev/null +++ b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good/0008-qmlglsink-Retain-the-previous-frame-to-avoid-flicker.patch @@ -0,0 +1,66 @@ +From 8272d5c9e32d2ae26ce28dcbf9a7962bc18f2338 Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Thu, 10 Aug 2017 11:29:41 +0200 +Subject: [PATCH] qmlglsink: Retain the previous frame to avoid flickering + artifacts + +With some GstGL uploaders - especially the ones based on DMABUF - it is +possible that flickering artifacts can occur with qmlglsink. This happens +because upstream writes into the dmabuf at the same time when the frame +in that dmabuf is being painted on screen. By retaining the gstbuffer for +one more frame, this is avoided, since the gstbuffer is not released back +into the upstream dmabuf buffer pool until the frame is drawn. + +https://bugzilla.gnome.org/show_bug.cgi?id=786133 +--- + ext/qt/gstqsgtexture.cc | 7 +++++++ + ext/qt/gstqsgtexture.h | 1 + + 2 files changed, 8 insertions(+) + +diff --git a/ext/qt/gstqsgtexture.cc b/ext/qt/gstqsgtexture.cc +index 7391806..46d73bb 100644 +--- a/ext/qt/gstqsgtexture.cc ++++ b/ext/qt/gstqsgtexture.cc +@@ -46,6 +46,7 @@ GstQSGTexture::GstQSGTexture () + + gst_video_info_init (&this->v_info); + this->buffer_ = NULL; ++ this->previous_buffer_ = NULL; + this->qt_context_ = NULL; + this->sync_buffer_ = gst_buffer_new (); + this->dummy_tex_id_ = 0; +@@ -54,6 +55,7 @@ GstQSGTexture::GstQSGTexture () + GstQSGTexture::~GstQSGTexture () + { + gst_buffer_replace (&this->buffer_, NULL); ++ gst_buffer_replace (&this->previous_buffer_, NULL); + gst_buffer_replace (&this->sync_buffer_, NULL); + if (this->dummy_tex_id_ && QOpenGLContext::currentContext ()) { + QOpenGLContext::currentContext ()->functions ()->glDeleteTextures (1, +@@ -75,6 +77,11 @@ gboolean + GstQSGTexture::setBuffer (GstBuffer * buffer) + { + GST_LOG ("%p setBuffer %" GST_PTR_FORMAT, this, buffer); ++ ++ /* Retain the current buffer for one frame to prevent ++ * releasing the buffer while it is being drawn */ ++ gst_buffer_replace (&this->previous_buffer_, this->buffer_); ++ + /* FIXME: update more state here */ + if (!gst_buffer_replace (&this->buffer_, buffer)) + return FALSE; +diff --git a/ext/qt/gstqsgtexture.h b/ext/qt/gstqsgtexture.h +index fdabe93..d2685f8 100644 +--- a/ext/qt/gstqsgtexture.h ++++ b/ext/qt/gstqsgtexture.h +@@ -48,6 +48,7 @@ public: + + private: + GstBuffer * buffer_; ++ GstBuffer * previous_buffer_; + GstBuffer * sync_buffer_; + GstGLContext * qt_context_; + GstMemory * mem_; +-- +2.7.4 + diff --git a/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good_1.14.%.bbappend b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good_1.14.%.bbappend new file mode 100644 index 00000000..6f44d02a --- /dev/null +++ b/recipes-multimedia/gstreamer/gstreamer1.0-plugins-good_1.14.%.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI_append = " \ + file://0001-v4l2videodec-Hack-to-make-sure-DMABUF-is-the-default.patch \ + file://0008-qmlglsink-Retain-the-previous-frame-to-avoid-flicker.patch \ +"