]> code.ossystems Code Review - meta-freescale.git/commitdiff
Update GStreamer patch to be applicable against version 1.14.0 89/19189/1
authorCarlos Rafael Giani <dv7777@gmail.com>
Wed, 28 Mar 2018 18:53:08 +0000 (20:53 +0200)
committerCarlos Rafael Giani <dv7777@gmail.com>
Wed, 28 Mar 2018 18:53:24 +0000 (20:53 +0200)
Change-Id: Idaa2bb32ed11c13366c567b36b0706820e1c3490
Signed-off-by: Carlos Rafael Giani <dv7777@gmail.com>
recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0001-gstgl-Fix-sanity-check-in-gst_gl_memory_setup_buffer.patch [new file with mode: 0644]
recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0002-gl-egl-Add-gst_egl_image_from_dmabuf_direct-function.patch [new file with mode: 0644]
recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/0003-gstgl-Add-direct-DMABUF-uploader-WIP.patch [new file with mode: 0644]
recipes-multimedia/gstreamer/gstreamer1.0-plugins-base_1.14.%.bbappend [new file with mode: 0644]
recipes-multimedia/gstreamer/gstreamer1.0-plugins-good/0008-qmlglsink-Retain-the-previous-frame-to-avoid-flicker.patch [new file with mode: 0644]
recipes-multimedia/gstreamer/gstreamer1.0-plugins-good_1.14.%.bbappend [new file with mode: 0644]

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 (file)
index 0000000..4735d25
--- /dev/null
@@ -0,0 +1,28 @@
+From daa3278503beb6b8ba74b4362622c5e65110708a Mon Sep 17 00:00:00 2001
+From: Carlos Rafael Giani <dv@pseudoterminal.org>
+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 (file)
index 0000000..50631fa
--- /dev/null
@@ -0,0 +1,347 @@
+From 56c58831b61cdb79f61f2f68c32854646241326b Mon Sep 17 00:00:00 2001
+From: Carlos Rafael Giani <dv@pseudoterminal.org>
+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
+ <SECTION>
+ <FILE>gsteglimage</FILE>
+ <TITLE>GstEGLImage</TITLE>
+-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 (file)
index 0000000..f93eccc
--- /dev/null
@@ -0,0 +1,378 @@
+From 6136bc631e5e875ed6b75d994564dd5fd09c7bf3 Mon Sep 17 00:00:00 2001
+From: Carlos Rafael Giani <dv@pseudoterminal.org>
+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 <gst/allocators/gstdmabuf.h>
++#include <libdrm/drm_fourcc.h>
+ #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 (file)
index 0000000..d39cdd6
--- /dev/null
@@ -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 (file)
index 0000000..2dc3b12
--- /dev/null
@@ -0,0 +1,66 @@
+From 8272d5c9e32d2ae26ce28dcbf9a7962bc18f2338 Mon Sep 17 00:00:00 2001
+From: Carlos Rafael Giani <dv@pseudoterminal.org>
+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 (file)
index 0000000..6f44d02
--- /dev/null
@@ -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 \
+"