d3dvideosink: use thread pool to handle events from hidden window event queue

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.
This commit is contained in:
Aaron Boxer 2019-12-07 14:51:28 -06:00
parent 027eb5ef20
commit eff0117b5a
2 changed files with 59 additions and 10 deletions

View 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);

View 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 { \