From 60d58038df5eb41f08598c8aa1d467bfea8729c9 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Fri, 27 Sep 2019 19:26:03 +0900 Subject: [PATCH] gst-play: Remove timer GSource from Win32 keyboard handler Use WaitForMultipleObjects to handle keyboard input only if pending keyboard input exists. --- tools/gst-play-kb.c | 107 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 16 deletions(-) diff --git a/tools/gst-play-kb.c b/tools/gst-play-kb.c index 31a765496b..8d08758945 100644 --- a/tools/gst-play-kb.c +++ b/tools/gst-play-kb.c @@ -134,21 +134,27 @@ gst_play_kb_set_key_handler (GstPlayKbFunc kb_func, gpointer user_data) #elif defined(G_OS_WIN32) -static GSource *source = NULL; +typedef struct +{ + GThread *thread; + HANDLE event_handle; + HANDLE console_handle; + gboolean closing; + GMutex lock; +} Win32KeyHandler; + +static Win32KeyHandler *win32_handler = NULL; static gboolean -gst_play_kb_source_cb (gpointer user_data) +gst_play_kb_source_cb (Win32KeyHandler * handler) { - HANDLE h_input = GetStdHandle (STD_INPUT_HANDLE); + HANDLE h_input = handler->console_handle; INPUT_RECORD buffer; DWORD n; if (PeekConsoleInput (h_input, &buffer, 1, &n) && n == 1) { ReadConsoleInput (h_input, &buffer, 1, &n); - if (!kb_callback) - return G_SOURCE_REMOVE; - if (buffer.EventType == KEY_EVENT && !buffer.Event.KeyEvent.bKeyDown) { gchar key_val[2] = { 0 }; @@ -173,7 +179,41 @@ gst_play_kb_source_cb (gpointer user_data) } } - return G_SOURCE_CONTINUE; + return G_SOURCE_REMOVE; +} + +static gpointer +gst_play_kb_win32_thread (gpointer user_data) +{ + Win32KeyHandler *handler = (Win32KeyHandler *) user_data; + HANDLE handles[2]; + + handles[0] = handler->event_handle; + handles[1] = handler->console_handle; + + if (!kb_callback) + return NULL; + + while (TRUE) { + DWORD ret = WaitForMultipleObjects (2, handles, FALSE, INFINITE); + + if (ret == WAIT_FAILED) { + GST_WARNING ("WaitForMultipleObject Failed"); + return NULL; + } + + g_mutex_lock (&handler->lock); + if (handler->closing) { + g_mutex_unlock (&handler->lock); + + return NULL; + } + g_mutex_unlock (&handler->lock); + + g_idle_add ((GSourceFunc) gst_play_kb_source_cb, handler); + } + + return NULL; } gboolean @@ -186,18 +226,53 @@ gst_play_kb_set_key_handler (GstPlayKbFunc kb_func, gpointer user_data) return FALSE; } - if (source) { - g_source_destroy (source); - g_source_unref (source); - source = NULL; + if (win32_handler) { + g_mutex_lock (&win32_handler->lock); + win32_handler->closing = TRUE; + g_mutex_unlock (&win32_handler->lock); + + SetEvent (win32_handler->event_handle); + g_thread_join (win32_handler->thread); + CloseHandle (win32_handler->event_handle); + + g_mutex_clear (&win32_handler->lock); + g_free (win32_handler); + win32_handler = NULL; } if (kb_func) { - /* check input per 50 ms */ - source = g_timeout_source_new (50); - g_source_set_callback (source, - (GSourceFunc) gst_play_kb_source_cb, NULL, NULL); - g_source_attach (source, NULL); + SECURITY_ATTRIBUTES sec_attrs; + + sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES); + sec_attrs.lpSecurityDescriptor = NULL; + sec_attrs.bInheritHandle = FALSE; + + win32_handler = g_new0 (Win32KeyHandler, 1); + + /* create cancellable event handle */ + win32_handler->event_handle = CreateEvent (&sec_attrs, TRUE, FALSE, NULL); + + if (!win32_handler->event_handle) { + GST_WARNING ("Couldn't create event handle"); + g_free (win32_handler); + win32_handler = NULL; + + return FALSE; + } + + win32_handler->console_handle = GetStdHandle (STD_INPUT_HANDLE); + if (!win32_handler->console_handle) { + GST_WARNING ("Couldn't get console handle"); + CloseHandle (win32_handler->event_handle); + g_free (win32_handler); + win32_handler = NULL; + + return FALSE; + } + + g_mutex_init (&win32_handler->lock); + win32_handler->thread = + g_thread_new ("gst-play-kb", gst_play_kb_win32_thread, win32_handler); } kb_callback = kb_func;