hc
2023-05-26 a23f51ed7a39e452c1037343a84d7db1ca2c5bd7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
From bff26916cef9024b370a1960f5d2d18d3c050a52 Mon Sep 17 00:00:00 2001
From: "Randy Li (ayaka)" <ayaka@soulik.info>
Date: Tue, 15 Dec 2020 18:11:08 +0800
Subject: [PATCH 03/40] waylandsink: prevent frame callback being released
 twice
 
For those using context from the application which
would be the embedded video case, if the frame callback
is entering at the same time as window is finalizing,
a wayland proxy object would be destroyed twice, leading
the refcout less than zero in the second time, it can
throw an abort() in wayland.
 
For those top window case, which as a directly connection
to the compositor, they can stop the message queue then
the frame callback won't happen at the same time as the
window is finalizing. It doesn't think it would bother
them about this.
 
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1883>
(cherry picked from commit 0d746d1022c7f83bc297584cb4d456cae4697cbf)
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
 ext/wayland/gstwaylandsink.c | 25 ++++++++++++++++---------
 ext/wayland/gstwaylandsink.h |  2 ++
 ext/wayland/wlwindow.c       |  4 ----
 ext/wayland/wlwindow.h       |  1 -
 4 files changed, 18 insertions(+), 14 deletions(-)
 
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 47192df..1c74147 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -404,6 +404,14 @@ gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
           gst_wl_window_render (sink->window, NULL, NULL);
         }
       }
+
+      g_mutex_lock (&sink->render_lock);
+      if (sink->callback) {
+        wl_callback_destroy (sink->callback);
+        sink->callback = NULL;
+      }
+      sink->redraw_pending = FALSE;
+      g_mutex_unlock (&sink->render_lock);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
       g_mutex_lock (&sink->display_lock);
@@ -417,12 +425,9 @@ gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
        * to avoid requesting them again from the application if/when we are
        * restarted (GstVideoOverlay behaves like that in other sinks)
        */
-      if (sink->display && !sink->window) {     /* -> the window was toplevel */
+      if (sink->display && !sink->window)       /* -> the window was toplevel */
         g_clear_object (&sink->display);
-        g_mutex_lock (&sink->render_lock);
-        sink->redraw_pending = FALSE;
-        g_mutex_unlock (&sink->render_lock);
-      }
+
       g_mutex_unlock (&sink->display_lock);
       g_clear_object (&sink->pool);
       break;
@@ -637,10 +642,12 @@ frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
 
   g_mutex_lock (&sink->render_lock);
   sink->redraw_pending = FALSE;
-  sink->window->callback = NULL;
-  g_mutex_unlock (&sink->render_lock);
 
-  wl_callback_destroy (callback);
+  if (sink->callback) {
+    wl_callback_destroy (callback);
+    sink->callback = NULL;
+  }
+  g_mutex_unlock (&sink->render_lock);
 }
 
 static const struct wl_callback_listener frame_callback_listener = {
@@ -661,7 +668,7 @@ render_last_buffer (GstWaylandSink * sink, gboolean redraw)
 
   sink->redraw_pending = TRUE;
   callback = wl_surface_frame (surface);
-  sink->window->callback = callback;
+  sink->callback = callback;
   wl_callback_add_listener (callback, &frame_callback_listener, sink);
 
   if (G_UNLIKELY (sink->video_info_changed && !redraw)) {
diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h
index be92fe7..23a4ebd 100644
--- a/ext/wayland/gstwaylandsink.h
+++ b/ext/wayland/gstwaylandsink.h
@@ -67,6 +67,8 @@ struct _GstWaylandSink
   gboolean redraw_pending;
   GMutex render_lock;
   GstBuffer *last_buffer;
+
+  struct wl_callback *callback;
 };
 
 struct _GstWaylandSinkClass
diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c
index 2a09b93..66a05be 100644
--- a/ext/wayland/wlwindow.c
+++ b/ext/wayland/wlwindow.c
@@ -157,9 +157,6 @@ gst_wl_window_finalize (GObject * gobject)
 {
   GstWlWindow *self = GST_WL_WINDOW (gobject);
 
-  if (self->callback)
-    wl_callback_destroy (self->callback);
-
   if (self->wl_shell_surface)
     wl_shell_surface_destroy (self->wl_shell_surface);
 
@@ -200,7 +197,6 @@ gst_wl_window_new_internal (GstWlDisplay * display, GMutex * render_lock)
   window->render_lock = render_lock;
   g_cond_init (&window->configure_cond);
 
-  window->callback = NULL;
   window->area_surface = wl_compositor_create_surface (display->compositor);
   window->video_surface = wl_compositor_create_surface (display->compositor);
 
diff --git a/ext/wayland/wlwindow.h b/ext/wayland/wlwindow.h
index cecbda6..c3f0172 100644
--- a/ext/wayland/wlwindow.h
+++ b/ext/wayland/wlwindow.h
@@ -55,7 +55,6 @@ struct _GstWlWindow
   struct wl_shell_surface *wl_shell_surface;
   struct xdg_surface *xdg_surface;
   struct xdg_toplevel *xdg_toplevel;
-  struct wl_callback *callback;
   gboolean configured;
   GCond configure_cond;
   GMutex configure_mutex;
-- 
2.17.1