Draw overlays to dma-bufs imported as EGLImage textures if supported
This significantly reduces texture upload times (typically < 1 ms).
Change-Id: I4ea6c8a5d2d5baae8d85dbd0905dc2ee57b57e48
diff --git a/plugins/gstglsvgoverlay.c b/plugins/gstglsvgoverlay.c
index 7dceb68..f7dadb6 100644
--- a/plugins/gstglsvgoverlay.c
+++ b/plugins/gstglsvgoverlay.c
@@ -20,9 +20,12 @@
#endif
#include <cairo.h>
+#include <libdrm/drm_fourcc.h>
#include <librsvg/rsvg.h>
+#include <gst/allocators/gstdmabuf.h>
#include <gst/gl/gstglfuncs.h>
+
#include "gstglsvgoverlay.h"
#define GST_CAT_DEFAULT gst_gl_svg_overlay_debug
@@ -35,15 +38,26 @@
G_DEFINE_TYPE_WITH_CODE (GstGLSvgOverlay, gst_gl_svg_overlay,
GST_TYPE_GL_FILTER, DEBUG_INIT);
+#define USING_OPENGL3(context) (gst_gl_context_check_gl_version(context, \
+ GST_GL_API_OPENGL3, 3, 1))
+#define USING_GLES2(context) (gst_gl_context_check_gl_version (context, \
+ GST_GL_API_GLES2, 2, 0))
+#define USING_GLES3(context) (gst_gl_context_check_gl_version (context, \
+ GST_GL_API_GLES2, 3, 0))
+
enum
{
PROP_0,
PROP_DATA,
PROP_SVG,
PROP_SYNC,
+ PROP_ION,
};
#define DEFAULT_PROP_SYNC TRUE
+#define DEFAULT_PROP_ION TRUE
+
+#define QNAME "GstGLSvgOverlayImage"
static void gst_gl_svg_overlay_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
@@ -97,6 +111,11 @@
"available.",
DEFAULT_PROP_SYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ION,
+ g_param_spec_boolean ("ion", "ion",
+ "Use the ION allocator for overlays if available.",
+ DEFAULT_PROP_ION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
gst_element_class_set_metadata (GST_ELEMENT_CLASS (klass),
"OpenGL SVG overlay",
"Filter/Effect/Video",
@@ -120,7 +139,7 @@
GST_GL_BASE_FILTER_CLASS (klass)->gl_set_caps =
gst_gl_svg_overlay_gl_set_caps;
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
- GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2;
+ GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_svg_overlay_filter_texture;
}
@@ -130,16 +149,27 @@
{
GST_DEBUG_OBJECT (overlay, "init");
overlay->sync = DEFAULT_PROP_SYNC;
+ overlay->use_ion = DEFAULT_PROP_ION;
overlay->num_tasks = 0;
overlay->started = FALSE;
overlay->shader = NULL;
overlay->thread_pool = NULL;
+ overlay->buffer_pool = NULL;
overlay->svg_queue = NULL;
overlay->gl_queue = NULL;
overlay->next_pts = 0;
overlay->current = NULL;
g_mutex_init (&overlay->mutex);
g_cond_init (&overlay->cond);
+
+ /* ION allocator is in the "coral" plugin, load it. */
+ gst_object_unref (gst_plugin_load_by_name ("coral"));
+ overlay->ion_allocator = gst_allocator_find ("ion");
+ if (overlay->ion_allocator) {
+ GST_INFO_OBJECT (overlay, "Have ION allocator");
+ } else {
+ GST_INFO_OBJECT (overlay, "ION allocator not present/usable");
+ }
}
static void
@@ -149,6 +179,16 @@
GST_DEBUG_OBJECT (overlay, "finalize");
+ if (overlay->ion_allocator) {
+ gst_object_unref (overlay->ion_allocator);
+ overlay->ion_allocator = NULL;
+ }
+ if (overlay->buffer_pool) {
+ gst_buffer_pool_set_active (overlay->buffer_pool, FALSE);
+ gst_object_unref (overlay->buffer_pool);
+ overlay->buffer_pool = NULL;
+ }
+
g_mutex_clear (&overlay->mutex);
g_cond_clear (&overlay->cond);
@@ -172,6 +212,9 @@
overlay->sync = g_value_get_boolean (value);
g_mutex_unlock (&overlay->mutex);
break;
+ case PROP_ION:
+ overlay->use_ion = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -189,13 +232,169 @@
g_mutex_lock (&overlay->mutex);
g_value_set_boolean (value, overlay->sync);
g_mutex_unlock (&overlay->mutex);
- break;
+ break;
+ case PROP_ION:
+ g_value_set_boolean (value, overlay->use_ion);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+static void
+_free_egl_image_texture_gl (GstGLContext * context, gpointer data)
+{
+ EglImageTexture *tex = (EglImageTexture *) data;
+ const GstGLFuncs *gl = context->gl_vtable;
+
+ if (!tex || !tex->tex) {
+ return;
+ }
+
+ gl->DeleteTextures (1, &tex->tex);
+ tex->tex = 0;
+}
+
+static void
+_free_egl_image_texture (gpointer data)
+{
+ EglImageTexture *tex = (EglImageTexture *) data;
+ EGLBoolean (*_eglDestroyImage) (EGLDisplay dpy, EGLImageKHR image);
+ GstGLDisplayEGL *gst_egl_display;
+ EGLDisplay egl_display;
+ GstGLSvgOverlay *overlay = tex->overlay;
+ GstGLContext *context = overlay->context;
+
+ gst_gl_context_thread_add (context, _free_egl_image_texture_gl, tex);
+
+ gst_egl_display = gst_gl_display_egl_from_gl_display (context->display);
+ egl_display = (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (
+ gst_egl_display));
+ gst_object_unref (gst_egl_display);
+
+ _eglDestroyImage = gst_gl_context_get_proc_address (context,
+ "eglDestroyImage");
+ if (!_eglDestroyImage) {
+ _eglDestroyImage = gst_gl_context_get_proc_address (context,
+ "eglDestroyImageKHR");
+ if (!_eglDestroyImage) {
+ g_free (tex);
+ GST_ERROR_OBJECT (overlay, "eglDestroyImage not exposed");
+ return;
+ }
+ }
+
+ if (!_eglDestroyImage (egl_display, tex->image)) {
+ GST_ERROR_OBJECT (overlay, "free %p failed", tex);
+ }
+
+ g_free (tex);
+}
+
+static EglImageTexture *
+_get_cached_egl_image_texture (GstGLSvgOverlay * overlay, GstBuffer * buf) {
+ EglImageTexture *tex = (EglImageTexture *) gst_mini_object_get_qdata (
+ GST_MINI_OBJECT (buf), g_quark_from_static_string (QNAME));
+ return tex;
+}
+
+static void
+_create_egl_image_texture_gl (GstGLContext * context, gpointer data)
+{
+ EglImageTexture *tex = (EglImageTexture *) data;
+ GstGLSvgOverlay *overlay = tex->overlay;
+ const GstGLFuncs *gl = context->gl_vtable;
+
+ g_assert (!tex->tex);
+ gl->GenTextures (1, &tex->tex);
+ gl->BindTexture (GL_TEXTURE_2D, tex->tex);
+ gl->TexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl->TexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gl->EGLImageTargetTexture2D (GL_TEXTURE_2D, tex->image);
+}
+
+static EglImageTexture *
+_create_egl_image_texture (GstGLSvgOverlay * overlay, GstBuffer * buf) {
+ /* EglImageTexture is cached in GstBuffer qdata. */
+ EglImageTexture *tex;
+ EGLImageKHR *image;
+ EGLDisplay egl_display;
+ GstGLDisplayEGL *gst_egl_display;
+ GstMemory *mem;
+ gint atti = 0, fourcc, i, fd;
+ guintptr attribs[16];
+ EGLImageKHR (*_eglCreateImage) (EGLDisplay dpy, EGLContext ctx,
+ EGLenum target, EGLClientBuffer buffer, const EGLint * attribs);
+ GstGLContext *context = overlay->context;
+
+ tex = _get_cached_egl_image_texture (overlay, buf);
+ if (tex) {
+ return tex;
+ }
+
+ mem = gst_buffer_peek_memory (buf, 0);
+ g_assert (gst_is_dmabuf_memory (mem));
+ fd = gst_dmabuf_memory_get_fd (mem);
+
+ gst_egl_display = gst_gl_display_egl_from_gl_display (context->display);
+ egl_display = (EGLDisplay) gst_gl_display_get_handle (GST_GL_DISPLAY (
+ gst_egl_display));
+ gst_object_unref (gst_egl_display);
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ fourcc = DRM_FORMAT_ARGB8888;
+#else
+ fourcc = DRM_FORMAT_ABGR8888;
+#endif
+
+ _eglCreateImage = gst_gl_context_get_proc_address (context,
+ "eglCreateImage");
+ if (!_eglCreateImage) {
+ _eglCreateImage = gst_gl_context_get_proc_address (context,
+ "eglCreateImageKHR");
+ }
+ g_assert (_eglCreateImage);
+
+ GST_DEBUG_OBJECT (overlay, "create image fd=%d w=%d h=%d s=%d", fd,
+ GST_VIDEO_INFO_WIDTH (&overlay->info),
+ GST_VIDEO_INFO_HEIGHT (&overlay->info),
+ GST_VIDEO_INFO_PLANE_STRIDE (&overlay->info, 0));
+
+ attribs[atti++] = EGL_WIDTH;
+ attribs[atti++] = GST_VIDEO_INFO_WIDTH (&overlay->info);
+ attribs[atti++] = EGL_HEIGHT;
+ attribs[atti++] = GST_VIDEO_INFO_HEIGHT (&overlay->info);
+ attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+ attribs[atti++] = fourcc;
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+ attribs[atti++] = fd;
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+ attribs[atti++] = 0;
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+ attribs[atti++] = GST_VIDEO_INFO_PLANE_STRIDE (&overlay->info, 0);
+ attribs[atti] = EGL_NONE;
+
+ image = _eglCreateImage (egl_display, EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT, NULL, (const EGLint *) attribs);
+ GST_DEBUG_OBJECT (overlay, "eglCreateImage %p", image);
+ g_assert (image != EGL_NO_IMAGE_KHR);
+
+ tex = g_malloc0 (sizeof (EglImageTexture));
+ tex->overlay = overlay;
+ tex->image = image;
+
+ GST_DEBUG_OBJECT (overlay, "set buf %p tex %p", buf, tex);
+ gst_mini_object_set_qdata (GST_MINI_OBJECT (buf),
+ g_quark_from_static_string (QNAME), tex, _free_egl_image_texture);
+
+ gst_gl_context_thread_add (context, _create_egl_image_texture_gl, tex);
+
+ return tex;
+}
+
static gint _task_data_compare (gconstpointer a, gconstpointer b,
gpointer user_data)
{
@@ -258,9 +457,10 @@
}
_task_data_unmap (tdata);
- gst_buffer_replace (&tdata->buf, NULL);
gst_gl_context_thread_add (tdata->overlay->context, _task_data_free_gl,
tdata);
+
+ gst_buffer_replace (&tdata->buf, NULL);
g_free (tdata->svg);
g_free (tdata);
}
@@ -270,16 +470,20 @@
{
TaskData * tdata = data;
GstGLSvgOverlay *overlay = tdata->overlay;
- GstGLFilter *filter = GST_GL_FILTER (overlay);
const GstGLFuncs *gl = context->gl_vtable;
/* TODO: handle non packed stride */
/* TODO: TexImage2D in a separate derived gl context */
+ g_assert (!tdata->egl_tex);
+
+ /* Copy pixels to GPU. */
gl->GenTextures (1, &tdata->tex);
gl->BindTexture (GL_TEXTURE_2D, tdata->tex);
- gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, overlay->width, overlay->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, tdata->map.data);
+ gl->TexImage2D(GL_TEXTURE_2D, 0, overlay->internal_format,
+ GST_VIDEO_INFO_WIDTH (&overlay->info),
+ GST_VIDEO_INFO_HEIGHT (&overlay->info),
+ 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, tdata->map.data);
gl->GenerateMipmap (GL_TEXTURE_2D);
}
@@ -298,12 +502,11 @@
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
- g_mutex_lock (&overlay->mutex);
+ g_mutex_lock (&overlay->mutex);
overlay->svg_queue = g_queue_new ();
overlay->gl_queue = g_queue_new ();
overlay->thread_pool = g_thread_pool_new (gst_gl_svg_overlay_task,
overlay, g_get_num_processors (), FALSE, NULL);
- overlay->started = TRUE;
g_mutex_unlock (&overlay->mutex);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
@@ -321,6 +524,11 @@
overlay->gl_queue = NULL;
_task_data_free (overlay->current);
overlay->current = NULL;
+ if (overlay->buffer_pool) {
+ gst_buffer_pool_set_active (overlay->buffer_pool, FALSE);
+ gst_object_unref (overlay->buffer_pool);
+ overlay->buffer_pool = NULL;
+ }
g_mutex_unlock (&overlay->mutex);
break;
default:
@@ -347,6 +555,30 @@
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (overlay->shader, "a_texcoord");
+ if (USING_GLES2 (overlay->context) || USING_GLES3 (overlay->context)) {
+ gboolean bgra = gst_gl_context_check_feature (overlay->context,
+ "GL_EXT_texture_format_BGRA8888");
+ if (bgra) {
+ GST_DEBUG_OBJECT (overlay, "GL_EXT_texture_format_BGRA8888 supported");
+ } else {
+ GST_ERROR_OBJECT (overlay, "GL_EXT_texture_format_BGRA8888 unsupported");
+ return FALSE;
+ }
+
+ overlay->internal_format = GL_BGRA_EXT;
+ } else if (USING_OPENGL3 (overlay->context)) {
+ /* BGRA8888 supported */
+ overlay->internal_format = GL_RGBA;
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (overlay->use_ion && overlay->ion_allocator) {
+ /* TODO: Init check the dma-buf import being supported. */
+ } else {
+ overlay->use_ion = FALSE;
+ }
+
return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter);
}
@@ -376,24 +608,69 @@
{
GstGLFilter *filter = GST_GL_FILTER (base_filter);
GstGLSvgOverlay *overlay = GST_GL_SVG_OVERLAY (base_filter);
+ GstStructure *config;
+ GstCaps *caps;
+ gsize size;
gboolean ret;
ret = GST_GL_BASE_FILTER_CLASS (parent_class)->gl_set_caps (base_filter,
incaps, outcaps);
- overlay->width = GST_VIDEO_INFO_WIDTH (&filter->out_info);
- overlay->height = GST_VIDEO_INFO_HEIGHT (&filter->out_info);
- overlay->stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
- overlay->width);
+ if (!ret) {
+ GST_ERROR_OBJECT (filter, "GstGLBaseFilter failed to start");
+ return ret;
+ }
- GST_DEBUG_OBJECT (filter, "%ux%u px, stride %u bytes", overlay->width,
- overlay->height, overlay->stride);
+ caps = gst_caps_new_simple("video/x-raw",
+ "format", G_TYPE_STRING, "BGRA",
+ "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH (&filter->out_info),
+ "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+ "framerate", GST_TYPE_FRACTION, 0, 1,
+ NULL);
+ gst_video_info_from_caps (&overlay->info, caps);
+ GST_VIDEO_INFO_PLANE_STRIDE (&overlay->info, 0) =
+ cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
+ GST_VIDEO_INFO_WIDTH (&overlay->info));
- if (overlay->stride != overlay->width * 4) {
+ if (GST_VIDEO_INFO_PLANE_STRIDE (&overlay->info, 0) != GST_VIDEO_INFO_WIDTH (
+ &overlay->info) * 4) {
/* TODO: stride */
GST_ERROR_OBJECT (overlay, "Unsupported stride");
+ gst_caps_unref (caps);
return FALSE;
}
+ size = GST_VIDEO_INFO_PLANE_STRIDE (&overlay->info, 0) *
+ GST_VIDEO_INFO_HEIGHT (&overlay->info);
+
+ g_mutex_lock (&overlay->mutex);
+
+ if (overlay->buffer_pool) {
+ gst_buffer_pool_set_active (overlay->buffer_pool, FALSE);
+ gst_object_unref (overlay->buffer_pool);
+ }
+ GST_INFO_OBJECT (overlay, "New pool with max %u buffers ion=%d",
+ g_get_num_processors (), overlay->use_ion);
+ overlay->buffer_pool = gst_buffer_pool_new ();
+ config = gst_buffer_pool_get_config (overlay->buffer_pool);
+ gst_buffer_pool_config_set_params (config, caps, size, 0,
+ g_get_num_processors ());
+ if (overlay->ion_allocator && overlay->use_ion) {
+ gst_buffer_pool_config_set_allocator (config, overlay->ion_allocator, NULL);
+ }
+ ret = gst_buffer_pool_set_config (overlay->buffer_pool, config);
+ g_assert (ret);
+ ret = gst_buffer_pool_set_active (overlay->buffer_pool, TRUE);
+ g_assert (ret);
+ gst_caps_unref (caps);
+
+ overlay->started = TRUE;
+
+ g_mutex_unlock (&overlay->mutex);
+
+ GST_DEBUG_OBJECT (filter, "%ux%u px, stride %u bytes",
+ GST_VIDEO_INFO_WIDTH (&overlay->info),
+ GST_VIDEO_INFO_HEIGHT (&overlay->info),
+ GST_VIDEO_INFO_PLANE_STRIDE (&overlay->info, 0));
return ret;
}
@@ -451,12 +728,19 @@
tdata = data;
if (tdata->op == OP_ALLOC) {
- /* TODO: Buffer pool. */
- const gsize size = GST_VIDEO_INFO_WIDTH (&filter->out_info) *
- GST_VIDEO_INFO_HEIGHT (&filter->out_info) * 4; /* BGRA 4 bpp. */
- tdata->buf = gst_buffer_new_allocate (NULL, size, NULL);
+ GstBufferPool *pool;
+ GstFlowReturn ret;
+
+ g_mutex_lock (&overlay->mutex);
+ pool = overlay->buffer_pool;
+ g_mutex_unlock (&overlay->mutex);
+
+ g_assert (gst_buffer_pool_is_active (pool));
+
+ ret = gst_buffer_pool_acquire_buffer (pool, &tdata->buf, NULL);
+ g_assert (ret == GST_FLOW_OK);
+
tdata->op = OP_DRAW;
- LOG_ELAPSED ("alloc");
TASK_DONE(tdata);
}
@@ -471,7 +755,9 @@
memset (tdata->map.data, 0, tdata->map.size);
surface = cairo_image_surface_create_for_data (tdata->map.data,
- CAIRO_FORMAT_ARGB32, overlay->width, overlay->height, overlay->stride);
+ CAIRO_FORMAT_ARGB32, GST_VIDEO_INFO_WIDTH (&overlay->info),
+ GST_VIDEO_INFO_HEIGHT (&overlay->info),
+ GST_VIDEO_INFO_PLANE_STRIDE (&overlay->info, 0));
g_assert (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS);
cairo = cairo_create (surface);
g_assert (cairo_status (cairo) == CAIRO_STATUS_SUCCESS);
@@ -497,10 +783,22 @@
}
if (tdata->op == OP_UPLOAD) {
- gst_gl_context_thread_add (tdata->overlay->context, _task_data_upload_gl,
- tdata);
- _task_data_unmap (tdata);
- gst_buffer_replace (&tdata->buf, NULL);
+ gboolean dma = overlay->use_ion && gst_is_dmabuf_memory (
+ gst_buffer_peek_memory (tdata->buf, 0));
+ if (dma) {
+ /* Unmap to flush CPU cache. */
+ _task_data_unmap (tdata);
+ g_assert (!tdata->egl_tex);
+ tdata->egl_tex = _create_egl_image_texture (overlay, tdata->buf);
+ g_assert (tdata->egl_tex);
+ } else {
+ /* Copy pixels to GPU, unmap and free buffer. */
+ gst_gl_context_thread_add (tdata->overlay->context, _task_data_upload_gl,
+ tdata);
+ _task_data_unmap (tdata);
+ gst_buffer_replace (&tdata->buf, NULL);
+ }
+
tdata->op = OP_READY;
g_mutex_lock (&overlay->mutex);
@@ -573,10 +871,10 @@
if (!overlay->started) {
GST_WARNING_OBJECT (overlay, "Wrong state, dropping SVG overlay");
g_mutex_unlock (&overlay->mutex);
-
+ return FALSE;
}
- tdata = g_malloc0 (sizeof(TaskData));
+ tdata = g_malloc0 (sizeof (TaskData));
tdata->overlay = overlay;
tdata->op = OP_ALLOC;
tdata->svg = g_strdup (svg);
@@ -648,7 +946,11 @@
tex_id = gst_gl_memory_get_texture_id (in_tex);
if (overlay->current) {
- o_tex_id = overlay->current->tex;
+ if (overlay->current->egl_tex) {
+ o_tex_id = overlay->current->egl_tex->tex;
+ } else {
+ o_tex_id = overlay->current->tex;
+ }
}
g_return_val_if_fail (overlay->shader, FALSE);
diff --git a/plugins/gstglsvgoverlay.h b/plugins/gstglsvgoverlay.h
index 796107b..5e71d49 100644
--- a/plugins/gstglsvgoverlay.h
+++ b/plugins/gstglsvgoverlay.h
@@ -19,6 +19,8 @@
#include <gst/gst.h>
+#include <gst/gl/egl/gstegl.h>
+#include "gst/gl/egl/gstgldisplay_egl.h"
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
@@ -33,6 +35,7 @@
typedef struct _GstGLSvgOverlay GstGLSvgOverlay;
typedef struct _GstGLSvgOverlayClass GstGLSvgOverlayClass;
typedef struct _TaskData TaskData;
+typedef struct _EglImageTexture EglImageTexture;
struct _GstGLSvgOverlay
{
@@ -43,6 +46,9 @@
GCond cond;
GstGLShader *shader;
GThreadPool *thread_pool;
+ GstBufferPool *buffer_pool;
+ GstAllocator *ion_allocator;
+ gboolean use_ion;
GQueue *svg_queue;
GQueue *gl_queue;
GstClockTime next_pts;
@@ -50,9 +56,8 @@
TaskData *current;
gboolean sync;
gboolean started;
- guint width;
- guint height;
- guint stride;
+ gint internal_format;
+ GstVideoInfo info;
};
struct _GstGLSvgOverlayClass
@@ -69,6 +74,12 @@
OP_READY,
};
+struct _EglImageTexture {
+ GstGLSvgOverlay *overlay;
+ EGLImageKHR *image;
+ guint tex;
+};
+
struct _TaskData {
GstGLSvgOverlay *overlay;
enum TaskOp op;
@@ -76,6 +87,7 @@
GstClockTime pts;
GstBuffer *buf;
GstMapInfo map;
+ EglImageTexture *egl_tex;
guint tex;
};