summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Olbrich <m.olbrich@pengutronix.de>2020-07-31 11:07:23 +0200
committerMichael Olbrich <m.olbrich@pengutronix.de>2020-07-31 14:02:34 +0200
commit887ba40e658cf8a02ce23af6e3f359eca5cda518 (patch)
treeb173f649c965d3b8a7cfe3b3aa8f1f3dfd1b4c77
parentd11ba513bb7f717c45a35dd742b02fe0b2f23383 (diff)
libs: window: wayland: destroy all wayland buffers during finalize
Some buffers and the associated FrameState state may still be pending at that point. If the wayland connection is shared, then messages for the buffer may still arrive. However, the associated event queue is already deleted. So the result is a crash. With a private connection the associated memory is leaked instead. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/merge_requests/342>
-rw-r--r--gst-libs/gst/vaapi/gstvaapiwindow_wayland.c48
1 files changed, 30 insertions, 18 deletions
diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c
index a7abe537..caf1dc63 100644
--- a/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c
+++ b/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c
@@ -61,6 +61,7 @@ struct _FrameState
GstVaapiWindow *window;
GstVaapiSurface *surface;
GstVaapiVideoPool *surface_pool;
+ struct wl_buffer *buffer;
struct wl_callback *callback;
gboolean done;
};
@@ -82,23 +83,6 @@ frame_state_new (GstVaapiWindow * window)
return frame;
}
-static void
-frame_state_free (FrameState * frame)
-{
- if (!frame)
- return;
-
- if (frame->surface) {
- if (frame->surface_pool)
- gst_vaapi_video_pool_put_object (frame->surface_pool, frame->surface);
- frame->surface = NULL;
- }
- gst_vaapi_video_pool_replace (&frame->surface_pool, NULL);
-
- g_clear_pointer (&frame->callback, wl_callback_destroy);
- g_slice_free (FrameState, frame);
-}
-
struct _GstVaapiWindowWaylandPrivate
{
struct xdg_surface *xdg_surface;
@@ -107,6 +91,7 @@ struct _GstVaapiWindowWaylandPrivate
struct wl_surface *surface;
struct wl_subsurface *video_subsurface;
struct wl_event_queue *event_queue;
+ GList *frames;
FrameState *last_frame;
GstPoll *poll;
GstPollFD pollfd;
@@ -156,6 +141,29 @@ enum
static guint signals[N_SIGNALS];
static void
+frame_state_free (FrameState * frame)
+{
+ GstVaapiWindowWaylandPrivate *priv;
+
+ if (!frame)
+ return;
+
+ priv = GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (frame->window);
+ priv->frames = g_list_remove (priv->frames, frame);
+
+ if (frame->surface) {
+ if (frame->surface_pool)
+ gst_vaapi_video_pool_put_object (frame->surface_pool, frame->surface);
+ frame->surface = NULL;
+ }
+ gst_vaapi_video_pool_replace (&frame->surface_pool, NULL);
+
+ g_clear_pointer (&frame->callback, wl_callback_destroy);
+ wl_buffer_destroy (frame->buffer);
+ g_slice_free (FrameState, frame);
+}
+
+static void
handle_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height, struct wl_array *states)
{
@@ -499,6 +507,9 @@ gst_vaapi_window_wayland_finalize (GObject * object)
if (priv->event_queue)
wl_display_roundtrip_queue (wl_display, priv->event_queue);
+ while (priv->frames)
+ frame_state_free ((FrameState *) priv->frames->data);
+
g_clear_pointer (&priv->xdg_surface, xdg_surface_destroy);
g_clear_pointer (&priv->wl_shell_surface, wl_shell_surface_destroy);
g_clear_pointer (&priv->video_subsurface, wl_subsurface_destroy);
@@ -581,7 +592,6 @@ frame_release_callback (void *data, struct wl_buffer *wl_buffer)
if (!frame->done)
if (!frame_done (frame))
GST_INFO ("cannot remove last frame because it didn't match or empty");
- wl_buffer_destroy (wl_buffer);
frame_state_free (frame);
}
@@ -971,8 +981,10 @@ gst_vaapi_window_wayland_render (GstVaapiWindow * window,
wl_proxy_set_queue ((struct wl_proxy *) buffer, priv->event_queue);
wl_buffer_add_listener (buffer, &frame_buffer_listener, frame);
+ frame->buffer = buffer;
frame->callback = wl_surface_frame (priv->surface);
wl_callback_add_listener (frame->callback, &frame_callback_listener, frame);
+ priv->frames = g_list_append (priv->frames, frame);
wl_surface_commit (priv->surface);
wl_display_flush (wl_display);