gstreamer/gst-libs/gst/vaapi/gstvaapisurface_drm.c
He Junyan e54671d4b3 libs,plugin: break surface-bufferproxy circular reference
The bufferproxy may reference the surface and the surface may also
reference the bufferproxy, producing a circular reference, which might
lead to serious resource leak problems.

Now make the relationship clearer, the bufferproxy's references is
transfered to surface, while bufferproxy just keeps the surface's
address without increasing its reference count.

The surface can be created through a bufferproxy like in
gst_vaapi_surface_new_with_dma_buf_handle(), and the surface might
get its bufferproxy via gst_vaapi_surface_get_dma_buf_handle(). In
both cases the surface holds a bufferproxy's reference.
2020-04-04 14:22:04 +02:00

215 lines
6.6 KiB
C

/*
* gstvaapisurface_drm.c - VA surface abstraction (DRM interop)
*
* Copyright (C) 2014 Intel Corporation
* Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "sysdeps.h"
#include "gstvaapisurface_drm.h"
#include "gstvaapisurface_priv.h"
#include "gstvaapiimage_priv.h"
#include "gstvaapibufferproxy_priv.h"
static GstVaapiBufferProxy *
gst_vaapi_surface_get_drm_buf_handle (GstVaapiSurface * surface, guint type)
{
GstVaapiBufferProxy *proxy;
GstVaapiImage *image;
image = gst_vaapi_surface_derive_image (surface);
if (!image)
goto error_derive_image;
/* The proxy takes ownership if the image, even creation failure. */
proxy =
gst_vaapi_buffer_proxy_new_from_surface (GST_MINI_OBJECT_CAST (surface),
image->internal_image.buf, type, (GDestroyNotify) gst_vaapi_image_unref,
image);
if (!proxy)
goto error_alloc_export_buffer;
return proxy;
/* ERRORS */
error_derive_image:
{
GST_ERROR ("failed to extract image handle from surface");
return NULL;
}
error_alloc_export_buffer:
{
GST_ERROR ("failed to allocate export buffer proxy");
return NULL;
}
}
/**
* gst_vaapi_surface_peek_dma_buf_handle:
* @surface: a #GstVaapiSurface
*
* If the underlying VA driver implementation supports it, this
* function allows for returning a suitable dma_buf (DRM) buffer
* handle as a #GstVaapiBufferProxy instance. The returned buffer
* proxy does not increase the ref of underlying buffer proxy.
*
* Return value: the underlying buffer as a #GstVaapiBufferProxy
* instance.
*/
GstVaapiBufferProxy *
gst_vaapi_surface_peek_dma_buf_handle (GstVaapiSurface * surface)
{
GstVaapiBufferProxy *buf_proxy;
g_return_val_if_fail (surface != NULL, NULL);
if (surface->extbuf_proxy)
return surface->extbuf_proxy;
buf_proxy = gst_vaapi_surface_get_drm_buf_handle (surface,
GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF);
if (buf_proxy) {
gst_vaapi_surface_set_buffer_proxy (surface, buf_proxy);
gst_vaapi_buffer_proxy_unref (buf_proxy);
}
return buf_proxy;
}
/**
* gst_vaapi_surface_peek_gem_buf_handle:
* @surface: a #GstVaapiSurface
*
* If the underlying VA driver implementation supports it, this
* function allows for returning a suitable GEM buffer handle as a
* #GstVaapiBufferProxy instance. The returned buffer proxy does
* not increase the ref of underlying buffer proxy.
*
* Return value: the underlying buffer as a #GstVaapiBufferProxy
* instance.
*/
GstVaapiBufferProxy *
gst_vaapi_surface_peek_gem_buf_handle (GstVaapiSurface * surface)
{
GstVaapiBufferProxy *buf_proxy;
g_return_val_if_fail (surface != NULL, NULL);
if (surface->extbuf_proxy)
return surface->extbuf_proxy;
buf_proxy = gst_vaapi_surface_get_drm_buf_handle (surface,
GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF);
if (buf_proxy) {
gst_vaapi_surface_set_buffer_proxy (surface, buf_proxy);
gst_vaapi_buffer_proxy_unref (buf_proxy);
}
return buf_proxy;
}
static void
fill_video_info (GstVideoInfo * vip, GstVideoFormat format, guint width,
guint height, gsize offset[GST_VIDEO_MAX_PLANES],
gint stride[GST_VIDEO_MAX_PLANES])
{
guint i;
gst_video_info_set_format (vip, format, width, height);
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); i++) {
GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = offset[i];
GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = stride[i];
}
}
/**
* gst_vaapi_surface_new_with_dma_buf_handle:
* @display: a #GstVaapiDisplay
* @fd: the DRM PRIME file descriptor
* @size: the underlying DRM buffer size
* @format: the desired surface format
* @width: the desired surface width in pixels
* @height: the desired surface height in pixels
* @offset: the offsets to each plane
* @stride: the pitches for each plane
*
* Creates a new #GstVaapiSurface with an external DRM PRIME file
* descriptor. The newly created VA surfaces owns the supplied buffer
* handle.
*
* Return value: the newly allocated #GstVaapiSurface object, or %NULL
* if creation from DRM PRIME fd failed, or is not supported
*/
GstVaapiSurface *
gst_vaapi_surface_new_with_dma_buf_handle (GstVaapiDisplay * display, gint fd,
GstVideoInfo * vi)
{
GstVaapiBufferProxy *proxy;
GstVaapiSurface *surface;
proxy = gst_vaapi_buffer_proxy_new ((gintptr) fd,
GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF, GST_VIDEO_INFO_SIZE (vi), NULL,
NULL);
if (!proxy)
return NULL;
surface = gst_vaapi_surface_new_from_buffer_proxy (display, proxy, vi);
/* Surface holds proxy's reference */
gst_vaapi_buffer_proxy_unref (proxy);
return surface;
}
/**
* gst_vaapi_surface_new_with_gem_buf_handle:
* @display: a #GstVaapiDisplay
* @name: the DRM GEM buffer name
* @size: the underlying DRM buffer size
* @format: the desired surface format
* @width: the desired surface width in pixels
* @height: the desired surface height in pixels
* @offset: the offsets to each plane
* @stride: the pitches for each plane
*
* Creates a new #GstVaapiSurface with an external DRM GEM buffer
* name. The newly created VA surfaces owns the supplied buffer
* handle.
*
* Return value: the newly allocated #GstVaapiSurface object, or %NULL
* if creation from GEM @name failed, or is not supported
*/
GstVaapiSurface *
gst_vaapi_surface_new_with_gem_buf_handle (GstVaapiDisplay * display,
guint32 name, guint size, GstVideoFormat format, guint width, guint height,
gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES])
{
GstVaapiBufferProxy *proxy;
GstVaapiSurface *surface;
GstVideoInfo vi;
proxy = gst_vaapi_buffer_proxy_new ((guintptr) name,
GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF, size, NULL, NULL);
if (!proxy)
return NULL;
fill_video_info (&vi, format, width, height, offset, stride);
surface = gst_vaapi_surface_new_from_buffer_proxy (display, proxy, &vi);
/* Surface holds proxy's reference */
gst_vaapi_buffer_proxy_unref (proxy);
return surface;
}