plugin: bufferpool: use hashmap to cache dmabuf mem-surface

The old way of refer memory by bufferproxy is not a good one, since it
make the logic error prone.

Now it is established a map between surface-bufferproxy and its GstMemory,
caching the memory bound by a surface looked for the specified surface.
This commit is contained in:
He Junyan 2020-03-15 22:07:31 +08:00 committed by Víctor Manuel Jáquez Leal
parent 7701844813
commit ce3bf2c2ae

View file

@ -47,6 +47,8 @@ struct _GstVaapiVideoBufferPoolPrivate
guint options; guint options;
guint use_dmabuf_memory:1; guint use_dmabuf_memory:1;
guint forced_video_meta:1; guint forced_video_meta:1;
/* Map between surface and GstMemory, only DMA */
GHashTable *dma_mem_map;
}; };
G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiVideoBufferPool, G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiVideoBufferPool,
@ -60,6 +62,8 @@ gst_vaapi_video_buffer_pool_finalize (GObject * object)
gst_vaapi_display_replace (&priv->display, NULL); gst_vaapi_display_replace (&priv->display, NULL);
g_clear_object (&priv->allocator); g_clear_object (&priv->allocator);
if (priv->dma_mem_map)
g_hash_table_destroy (priv->dma_mem_map);
G_OBJECT_CLASS (gst_vaapi_video_buffer_pool_parent_class)->finalize (object); G_OBJECT_CLASS (gst_vaapi_video_buffer_pool_parent_class)->finalize (object);
} }
@ -309,6 +313,58 @@ error_no_allocator:
} }
} }
static void
vaapi_buffer_pool_cache_dma_mem (GstVaapiVideoBufferPool * pool,
GstVaapiSurfaceProxy * proxy, GstMemory * mem)
{
GstVaapiVideoBufferPoolPrivate *const priv = pool->priv;
GstVaapiSurface *surface;
surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
g_assert (surface);
g_assert (gst_vaapi_surface_peek_buffer_proxy (surface));
if (!priv->dma_mem_map)
priv->dma_mem_map = g_hash_table_new_full (g_direct_hash,
g_direct_equal, NULL, (GDestroyNotify) gst_memory_unref);
if (!g_hash_table_contains (priv->dma_mem_map, surface)) {
g_hash_table_insert (priv->dma_mem_map, surface, gst_memory_ref (mem));
} else {
g_assert (g_hash_table_lookup (priv->dma_mem_map, surface) == mem);
}
}
static GstMemory *
vaapi_buffer_pool_lookup_dma_mem (GstVaapiVideoBufferPool * pool,
GstVaapiSurfaceProxy * proxy)
{
GstVaapiSurface *surface;
GstVaapiVideoBufferPoolPrivate *const priv = pool->priv;
GstVaapiBufferProxy *buf_proxy;
GstMemory *mem;
g_assert (priv->use_dmabuf_memory);
if (!priv->dma_mem_map)
return NULL;
surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
g_assert (surface);
buf_proxy = gst_vaapi_surface_peek_buffer_proxy (surface);
/* Have not exported yet */
if (!buf_proxy) {
g_assert (!g_hash_table_contains (priv->dma_mem_map, surface));
return NULL;
}
mem = g_hash_table_lookup (priv->dma_mem_map, surface);
g_assert (mem);
return gst_memory_ref (mem);
}
static GstFlowReturn static GstFlowReturn
gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool, gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool,
GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params) GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params)
@ -336,10 +392,23 @@ gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool,
if (priv_params && priv_params->proxy) if (priv_params && priv_params->proxy)
gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy); gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy);
if (priv->use_dmabuf_memory) if (priv->use_dmabuf_memory) {
mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); mem = NULL;
else if (priv_params && priv_params->proxy) {
mem = vaapi_buffer_pool_lookup_dma_mem (base_pool, priv_params->proxy);
if (!mem) {
mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta);
if (!mem)
goto error_create_memory;
vaapi_buffer_pool_cache_dma_mem (base_pool, priv_params->proxy, mem);
}
} else {
mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta);
}
} else {
mem = gst_vaapi_video_memory_new (priv->allocator, meta); mem = gst_vaapi_video_memory_new (priv->allocator, meta);
}
if (!mem) if (!mem)
goto error_create_memory; goto error_create_memory;
gst_vaapi_video_meta_replace (&meta, NULL); gst_vaapi_video_meta_replace (&meta, NULL);
@ -407,7 +476,6 @@ gst_vaapi_video_buffer_pool_acquire_buffer (GstBufferPool * pool,
GstMemory *mem; GstMemory *mem;
GstVaapiVideoMeta *meta; GstVaapiVideoMeta *meta;
GstVaapiSurface *surface; GstVaapiSurface *surface;
GstVaapiBufferProxy *dmabuf_proxy;
ret = ret =
GST_BUFFER_POOL_CLASS GST_BUFFER_POOL_CLASS
@ -420,15 +488,20 @@ gst_vaapi_video_buffer_pool_acquire_buffer (GstBufferPool * pool,
return ret; return ret;
} }
/* The point of the following dance is to attach the right GstMemory to the /* Some pool users, such as decode, needs to acquire a buffer for a
* current acquired buffer. Indeed this buffer can contain any of the * specified surface (via surface proxy). If not it is a DMABuf, we
* GstFdmemory since this buffer have been popped out from the buffer pool's * just replace the underlying surface proxy of buffer's
* FIFO. So there is no garantee that this matches the current surface. The * GstVaapiVideoMeta. But in DMABuf case, the thing is a little bit
* va decoder driver might not even use a FIFO. So there is no way to guess * more complicated:
* on the ordering. In short acquire_current_buffer on the va driver and on *
* the buffer pool return none matching data. So we have to manually attach * For DMABuf, GstMemory is-a GstFdMemory, which doesn't provide a
* the right GstFdMemory to the acquired GstBuffer. The right GstMemory is * way to change its FD, thus once created it's bound to a
* the one associated with the current surface. */ * surface. On the other side, for performace reason, when the
* buffer is released, the buffer and its memory are cached in the
* buffer pool, and at next acquire_buffer() may still reuse a
* buffer and its memory. But the pushed surface by the decoder may
* be different from the one popped by the pool, so we need to
* replace the buffer's memory with the correct one. */
g_assert (gst_buffer_n_memory (buffer) == 1); g_assert (gst_buffer_n_memory (buffer) == 1);
/* Update the underlying surface proxy */ /* Update the underlying surface proxy */
@ -439,30 +512,34 @@ gst_vaapi_video_buffer_pool_acquire_buffer (GstBufferPool * pool,
} }
gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy); gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy);
/* Find the cached memory associated with the given surface. */ mem = vaapi_buffer_pool_lookup_dma_mem (base_pool, priv_params->proxy);
surface = GST_VAAPI_SURFACE_PROXY_SURFACE (priv_params->proxy); if (mem) {
dmabuf_proxy = gst_vaapi_surface_peek_buffer_proxy (surface); if (mem == gst_buffer_peek_memory (buffer, 0)) {
if (dmabuf_proxy) { gst_memory_unref (mem);
mem = gst_vaapi_buffer_proxy_peek_mem (dmabuf_proxy); *out_buffer_ptr = buffer;
if (mem == gst_buffer_peek_memory (buffer, 0)) return GST_FLOW_OK;
mem = NULL; }
else
mem = gst_memory_ref (mem);
} else { } else {
/* The given surface has not been exported yet. */ /* Should be an unexported surface */
surface = GST_VAAPI_SURFACE_PROXY_SURFACE (priv_params->proxy);
g_assert (surface);
g_assert (gst_vaapi_surface_peek_buffer_proxy (surface) == NULL);
gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy);
mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta);
if (mem)
vaapi_buffer_pool_cache_dma_mem (base_pool, priv_params->proxy, mem);
} }
/* Attach the GstFdMemory to the output buffer. */
if (mem) { if (mem) {
GST_DEBUG_OBJECT (base_pool, "assigning memory %p to acquired buffer %p",
mem, buffer);
gst_buffer_replace_memory (buffer, 0, mem); gst_buffer_replace_memory (buffer, 0, mem);
gst_buffer_unset_flags (buffer, GST_BUFFER_FLAG_TAG_MEMORY); gst_buffer_unset_flags (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
*out_buffer_ptr = buffer;
return GST_FLOW_OK;
} else {
gst_buffer_unref (buffer);
*out_buffer_ptr = NULL;
return GST_FLOW_ERROR;
} }
*out_buffer_ptr = buffer;
return GST_FLOW_OK;
} }
static void static void
@ -523,6 +600,7 @@ static void
gst_vaapi_video_buffer_pool_init (GstVaapiVideoBufferPool * pool) gst_vaapi_video_buffer_pool_init (GstVaapiVideoBufferPool * pool)
{ {
pool->priv = gst_vaapi_video_buffer_pool_get_instance_private (pool); pool->priv = gst_vaapi_video_buffer_pool_get_instance_private (pool);
pool->priv->dma_mem_map = NULL;
} }
GstBufferPool * GstBufferPool *