mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-29 21:21:12 +00:00
gleglimage: cache EGL images per DmabufUpload
Do not store cached EGL images in GstMemory QData. Instead, use a per-DmabufUpload GHashTable to store cache entries with a weak reference to the GstMemory. This allows two glupload elements on separate tee branches to have their own EGL image cache. For this pipeline: gst-launch-1.0 v4l2src ! tee name=t \ t. ! queue ! glupload ! fakesink t. ! queue ! glupload ! fakesink this gets rid of the occasional critical error message: GStreamer-CRITICAL **: 08:26:33.194: gst_mini_object_unref: assertion 'GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) > 0' failed Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3880>
This commit is contained in:
parent
3943503fc1
commit
485c8ef4b5
1 changed files with 131 additions and 38 deletions
|
@ -486,11 +486,24 @@ static const UploadMethod _gl_memory_upload = {
|
|||
};
|
||||
|
||||
#if GST_GL_HAVE_DMABUF
|
||||
typedef struct _GstEGLImageCacheEntry
|
||||
{
|
||||
GstEGLImage *eglimage[GST_VIDEO_MAX_PLANES];
|
||||
} GstEGLImageCacheEntry;
|
||||
|
||||
typedef struct _GstEGLImageCache
|
||||
{
|
||||
gint ref_count;
|
||||
GHashTable *hash_table; /* for GstMemory -> GstEGLImageCacheEntry lookup */
|
||||
GMutex lock; /* protects hash_table */
|
||||
} GstEGLImageCache;
|
||||
|
||||
struct DmabufUpload
|
||||
{
|
||||
GstGLUpload *upload;
|
||||
|
||||
GstEGLImage *eglimage[GST_VIDEO_MAX_PLANES];
|
||||
GstEGLImageCache *eglimage_cache;
|
||||
GstGLFormat formats[GST_VIDEO_MAX_PLANES];
|
||||
GstBuffer *outbuf;
|
||||
GstGLVideoAllocationParams *params;
|
||||
|
@ -503,6 +516,111 @@ struct DmabufUpload
|
|||
gpointer out_caps;
|
||||
};
|
||||
|
||||
static void
|
||||
gst_egl_image_cache_ref (GstEGLImageCache * cache)
|
||||
{
|
||||
g_atomic_int_inc (&cache->ref_count);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_egl_image_cache_unref (GstEGLImageCache * cache)
|
||||
{
|
||||
if (g_atomic_int_dec_and_test (&cache->ref_count)) {
|
||||
g_hash_table_unref (cache->hash_table);
|
||||
g_mutex_clear (&cache->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_egl_image_cache_entry_remove (GstEGLImageCache * cache, GstMiniObject * mem)
|
||||
{
|
||||
g_mutex_lock (&cache->lock);
|
||||
g_hash_table_remove (cache->hash_table, mem);
|
||||
g_mutex_unlock (&cache->lock);
|
||||
gst_egl_image_cache_unref (cache);
|
||||
}
|
||||
|
||||
static GstEGLImageCacheEntry *
|
||||
gst_egl_image_cache_entry_new (GstEGLImageCache * cache, GstMemory * mem)
|
||||
{
|
||||
GstEGLImageCacheEntry *cache_entry;
|
||||
|
||||
cache_entry = g_new0 (GstEGLImageCacheEntry, 1);
|
||||
gst_egl_image_cache_ref (cache);
|
||||
gst_mini_object_weak_ref (GST_MINI_OBJECT (mem),
|
||||
(GstMiniObjectNotify) gst_egl_image_cache_entry_remove, cache);
|
||||
g_mutex_lock (&cache->lock);
|
||||
g_hash_table_insert (cache->hash_table, mem, cache_entry);
|
||||
g_mutex_unlock (&cache->lock);
|
||||
|
||||
return cache_entry;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_egl_image_cache_entry_free (GstEGLImageCacheEntry * cache_entry)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
|
||||
if (cache_entry->eglimage[i])
|
||||
gst_egl_image_unref (cache_entry->eglimage[i]);
|
||||
}
|
||||
g_free (cache_entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up a cache_entry for mem if mem is different from previous_mem.
|
||||
* If mem is the same as previous_mem, the costly lookup is skipped and the
|
||||
* provided (previous) cache_entry is used instead.
|
||||
*
|
||||
* Returns the cached eglimage for the given plane from the cache_entry, or
|
||||
* NULL. previous_mem is set to mem.
|
||||
*/
|
||||
static GstEGLImage *
|
||||
gst_egl_image_cache_lookup (GstEGLImageCache * cache, GstMemory * mem,
|
||||
gint plane, GstMemory ** previous_mem, GstEGLImageCacheEntry ** cache_entry)
|
||||
{
|
||||
if (mem != *previous_mem) {
|
||||
g_mutex_lock (&cache->lock);
|
||||
*cache_entry = g_hash_table_lookup (cache->hash_table, mem);
|
||||
g_mutex_unlock (&cache->lock);
|
||||
*previous_mem = mem;
|
||||
}
|
||||
|
||||
if (*cache_entry)
|
||||
return (*cache_entry)->eglimage[plane];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new cache_entry for mem if no cache_entry is provided.
|
||||
* Stores the eglimage for the given plane in the cache_entry.
|
||||
*/
|
||||
static void
|
||||
gst_egl_image_cache_store (GstEGLImageCache * cache, GstMemory * mem,
|
||||
gint plane, GstEGLImage * eglimage, GstEGLImageCacheEntry ** cache_entry)
|
||||
{
|
||||
if (!(*cache_entry))
|
||||
*cache_entry = gst_egl_image_cache_entry_new (cache, mem);
|
||||
(*cache_entry)->eglimage[plane] = eglimage;
|
||||
}
|
||||
|
||||
static GstEGLImageCache *
|
||||
gst_egl_image_cache_new (void)
|
||||
{
|
||||
GstEGLImageCache *cache;
|
||||
|
||||
cache = g_new0 (GstEGLImageCache, 1);
|
||||
cache->ref_count = 1;
|
||||
|
||||
cache->hash_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, (GDestroyNotify) gst_egl_image_cache_entry_free);
|
||||
g_mutex_init (&cache->lock);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static GstStaticCaps _dma_buf_upload_caps =
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
|
||||
(GST_CAPS_FEATURE_MEMORY_DMABUF,
|
||||
|
@ -514,6 +632,7 @@ _dma_buf_upload_new (GstGLUpload * upload)
|
|||
{
|
||||
struct DmabufUpload *dmabuf = g_new0 (struct DmabufUpload, 1);
|
||||
dmabuf->upload = upload;
|
||||
dmabuf->eglimage_cache = gst_egl_image_cache_new ();
|
||||
dmabuf->target = GST_GL_TEXTURE_TARGET_2D;
|
||||
return dmabuf;
|
||||
}
|
||||
|
@ -576,38 +695,6 @@ _dma_buf_upload_transform_caps (gpointer impl, GstGLContext * context,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static GQuark
|
||||
_eglimage_quark (gint plane)
|
||||
{
|
||||
static GQuark quark[5] = { 0 };
|
||||
static const gchar *quark_str[] = {
|
||||
"GstGLDMABufEGLImage0",
|
||||
"GstGLDMABufEGLImage1",
|
||||
"GstGLDMABufEGLImage2",
|
||||
"GstGLDMABufEGLImage3",
|
||||
"GstGLDMABufEGLImage",
|
||||
};
|
||||
|
||||
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)
|
||||
|
@ -619,6 +706,8 @@ _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
|
|||
GstVideoMeta *meta;
|
||||
guint n_mem;
|
||||
GstMemory *mems[GST_VIDEO_MAX_PLANES];
|
||||
GstMemory *previous_mem = NULL;
|
||||
GstEGLImageCacheEntry *cache_entry = NULL;
|
||||
gsize offset[GST_VIDEO_MAX_PLANES];
|
||||
gint fd[GST_VIDEO_MAX_PLANES];
|
||||
guint i;
|
||||
|
@ -745,12 +834,14 @@ _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
|
|||
} else
|
||||
dmabuf->n_mem = n_planes;
|
||||
|
||||
/* Now create an EGLImage for each dmabufs */
|
||||
/* Now create an EGLImage for each dmabuf */
|
||||
for (i = 0; i < dmabuf->n_mem; i++) {
|
||||
gint cache_id = dmabuf->direct ? 4 : i;
|
||||
|
||||
/* check if one is cached */
|
||||
dmabuf->eglimage[i] = _get_cached_eglimage (mems[i], cache_id);
|
||||
/*
|
||||
* Check if an EGLImage is cached. Remember the previous memory and cache
|
||||
* entry to avoid repeated lookups if all mems[i] point to the same memory.
|
||||
*/
|
||||
dmabuf->eglimage[i] = gst_egl_image_cache_lookup (dmabuf->eglimage_cache,
|
||||
mems[i], i, &previous_mem, &cache_entry);
|
||||
if (dmabuf->eglimage[i]) {
|
||||
dmabuf->formats[i] = dmabuf->eglimage[i]->format;
|
||||
continue;
|
||||
|
@ -770,7 +861,8 @@ _dma_buf_upload_accept (gpointer impl, GstBuffer * buffer, GstCaps * in_caps,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
_set_cached_eglimage (mems[i], dmabuf->eglimage[i], cache_id);
|
||||
gst_egl_image_cache_store (dmabuf->eglimage_cache, mems[i], i,
|
||||
dmabuf->eglimage[i], &cache_entry);
|
||||
dmabuf->formats[i] = dmabuf->eglimage[i]->format;
|
||||
}
|
||||
|
||||
|
@ -836,6 +928,7 @@ _dma_buf_upload_free (gpointer impl)
|
|||
|
||||
if (dmabuf->params)
|
||||
gst_gl_allocation_params_free ((GstGLAllocationParams *) dmabuf->params);
|
||||
gst_egl_image_cache_unref (dmabuf->eglimage_cache);
|
||||
|
||||
g_free (impl);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue