d3dvideosink: use thread pool to handle events from hidden window event queue
authorAaron Boxer <aaron.boxer@collabora.com>
Sat, 7 Dec 2019 20:51:28 +0000 (14:51 -0600)
committerAaron Boxer <aaron.boxer@collabora.com>
Wed, 18 Dec 2019 18:15:06 +0000 (13:15 -0500)
window event queue now does not lock on the class lock, so we can now shut
it down without releasing the class lock, thus avoiding a potential race when
stopping the sink.

sys/d3dvideosink/d3dhelpers.c
sys/d3dvideosink/d3dvideosink.h

index 80811aa..3e4bbcc 100644 (file)
@@ -57,6 +57,8 @@ static void d3d_class_notify_device_lost (GstD3DVideoSink * sink);
 static void d3d_class_display_device_destroy (GstD3DVideoSinkClass * klass);
 static gboolean d3d_class_display_device_create (GstD3DVideoSinkClass * klass,
     UINT adapter);
+static void d3d_class_hidden_window_message_queue (gpointer data,
+    gpointer user_data);
 
 static LRESULT APIENTRY d3d_wnd_proc_internal (HWND hWnd, UINT message,
     WPARAM wParam, LPARAM lParam);
@@ -72,6 +74,12 @@ static gint WM_D3DVIDEO_NOTIFY_DEVICE_LOST = 0;
 
 #define WM_QUIT_THREAD  WM_USER+0
 
+typedef struct
+{
+  gint window_message_id;
+  guint create_count;
+} GstD3DVideoSinkEvent;
+
 /* Helpers */
 
 #define ERROR_CHECK_HR(hr)                          \
@@ -2666,7 +2674,13 @@ static void
 d3d_class_notify_device_lost (GstD3DVideoSink * sink)
 {
   GstD3DVideoSinkClass *klass = GST_D3DVIDEOSINK_GET_CLASS (sink);
-  PostMessage (klass->d3d.hidden_window, WM_D3DVIDEO_NOTIFY_DEVICE_LOST, 0, 0);
+  GstD3DVideoSinkEvent *evt = g_new0 (GstD3DVideoSinkEvent, 1);
+
+  evt->window_message_id = IDT_DEVICE_RESET_TIMER;
+  evt->create_count = klass->create_count;
+  gst_element_call_async (GST_ELEMENT (klass),
+      (GstElementCallAsyncFunc) d3d_class_hidden_window_message_queue, evt,
+      g_free);
 }
 
 static void
@@ -2734,29 +2748,61 @@ end:
 
 /* Hidden Window Loop Thread */
 
+static void
+d3d_class_hidden_window_message_queue (gpointer data, gpointer user_data)
+{
+  guint id = 0;
+  GstD3DVideoSinkClass *klass = (GstD3DVideoSinkClass *) data;
+  GstD3DVideoSinkEvent *evt = (GstD3DVideoSinkEvent *) user_data;
+
+  if (!klass || !evt)
+    return;
+
+  switch (evt->window_message_id) {
+    case IDT_DEVICE_RESET_TIMER:
+      LOCK_CLASS (NULL, klass);
+      /* make sure this event does not originate from old class */
+      if (evt->create_count == klass->create_count)
+        d3d_class_reset_display_device (klass);
+      UNLOCK_CLASS (NULL, klass);
+      break;
+    default:
+      if (id == WM_D3DVIDEO_NOTIFY_DEVICE_LOST) {
+        LOCK_CLASS (NULL, klass);
+        /* make sure this event does not originate from old class */
+        if (evt->create_count == klass->create_count)
+          d3d_class_notify_device_lost_all (klass);
+        UNLOCK_CLASS (NULL, klass);
+      }
+      break;
+  }
+}
+
 static LRESULT APIENTRY
 D3DHiddenWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
+  GstD3DVideoSinkClass *klass =
+      (GstD3DVideoSinkClass *) GetWindowLongPtr (hWnd, GWLP_USERDATA);
+  GstD3DVideoSinkEvent *evt;
+
   switch (message) {
     case WM_TIMER:
       switch (wParam) {
         case IDT_DEVICE_RESET_TIMER:
-          d3d_class_reset_display_device ((GstD3DVideoSinkClass *)
-              GetWindowLongPtr (hWnd, GWLP_USERDATA));
+          evt = g_new0 (GstD3DVideoSinkEvent, 1);
+          evt->window_message_id = IDT_DEVICE_RESET_TIMER;
+          evt->create_count = klass->create_count;
+          gst_element_call_async (GST_ELEMENT (klass),
+              (GstElementCallAsyncFunc) d3d_class_hidden_window_message_queue,
+              evt, g_free);
           break;
-        default:;
       }
       return 0;
     case WM_DESTROY:
       PostQuitMessage (0);
       return 0;
     default:
-      /* non constants */
-      if (message == WM_D3DVIDEO_NOTIFY_DEVICE_LOST) {
-        d3d_class_notify_device_lost_all ((GstD3DVideoSinkClass *)
-            GetWindowLongPtr (hWnd, GWLP_USERDATA));
-        return 0;
-      }
+      break;
   }
 
   return DefWindowProc (hWnd, message, wParam, lParam);
index 67ac6c0..807f3be 100644 (file)
@@ -74,6 +74,9 @@ struct _GstD3DVideoSinkClass
   GstVideoSinkClass parent_class;
   GstD3DDataClass   d3d;
   GRecMutex   lock;
+  /* this count is incremented each time the sink is destroyed, so that
+   * old queue events can be ignored */
+  guint create_count;
 };
 
 #define LOCK_SINK(sink) G_STMT_START { \