diff --git a/libavdevice/gdigrab.c b/libavdevice/gdigrab.c
index e9d646999f..3abd20d899 100644
--- a/libavdevice/gdigrab.c
+++ b/libavdevice/gdigrab.c
@@ -33,7 +33,9 @@
 #include "libavutil/opt.h"
 #include "libavutil/time.h"
 #include <windows.h>
+#include <process.h>
 
+#define WM_REGION_WND_DESTROY (WM_USER + 1)
 /**
  * GDI Device Demuxer context
  */
@@ -61,7 +63,9 @@ struct gdigrab {
     void      *buffer;      /**< The buffer containing the bitmap image data */
     RECT       clip_rect;   /**< The subarea of the screen or window to clip */
 
-    HWND       region_hwnd; /**< Handle of the region border window */
+    HANDLE     hthread;            /**< Thread handle of the region border window */
+    HWND       region_hwnd;        /**< Handle of the region border window */
+    HANDLE     event_wnd_creation; /**< Event handle to notify CreateWindow has been called */
 
     int cursor_error_printed;
 };
@@ -104,23 +108,30 @@ gdigrab_region_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 
         EndPaint(hwnd, &ps);
         break;
+    case WM_REGION_WND_DESTROY:
+        DestroyWindow(hwnd);
+        break;
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
     default:
         return DefWindowProc(hwnd, msg, wparam, lparam);
     }
-    return 0;
+    return DefWindowProc(hwnd, msg, wparam, lparam);
 }
 
 /**
- * Initialize the region outline window.
+ * Owner thread of the region outline window.
  *
- * @param s1 The format context.
- * @param gdigrab gdigrab context.
- * @return 0 success, !0 failure
+ * @param arg gdigrab context.
+ * @return Thread exit code.
  */
-static int
-gdigrab_region_wnd_init(AVFormatContext *s1, struct gdigrab *gdigrab)
+static unsigned __stdcall
+gdigrab_region_wnd_thread(void *arg)
 {
     HWND hwnd;
+    MSG msg;
+    struct gdigrab *gdigrab = (struct gdigrab *)arg;
     RECT rect = gdigrab->clip_rect;
     HRGN region = NULL;
     HRGN region_interior = NULL;
@@ -139,9 +150,9 @@ gdigrab_region_wnd_init(AVFormatContext *s1, struct gdigrab *gdigrab)
             rect.right - rect.left, rect.bottom - rect.top,
             NULL, NULL, NULL, NULL);
     if (!hwnd) {
-        WIN32_API_ERROR("Could not create region display window");
         goto error;
     }
+    gdigrab->region_hwnd = hwnd;
 
     // Set the window transparency to 255 (opaque)
     SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA);
@@ -155,7 +166,6 @@ gdigrab_region_wnd_init(AVFormatContext *s1, struct gdigrab *gdigrab)
             rect.bottom - rect.top - REGION_WND_BORDER);
     CombineRgn(region, region, region_interior, RGN_DIFF);
     if (!SetWindowRgn(hwnd, region, FALSE)) {
-        WIN32_API_ERROR("Could not set window region");
         goto error;
     }
     // The "region" memory is now owned by the window
@@ -166,7 +176,12 @@ gdigrab_region_wnd_init(AVFormatContext *s1, struct gdigrab *gdigrab)
 
     ShowWindow(hwnd, SW_SHOW);
 
-    gdigrab->region_hwnd = hwnd;
+    SetEvent(gdigrab->event_wnd_creation);
+
+    // Message loop
+    while (GetMessage(&msg, 0, 0, 0)) {
+        DispatchMessage(&msg);
+    }
 
     return 0;
 
@@ -177,41 +192,71 @@ error:
         DeleteObject(region_interior);
     if (hwnd)
         DestroyWindow(hwnd);
+
+    gdigrab->region_hwnd = NULL;
+    SetEvent(gdigrab->event_wnd_creation);
     return 1;
 }
 
 /**
- * Cleanup/free the region outline window.
+ * Initialize the region outline window.
  *
  * @param s1 The format context.
  * @param gdigrab gdigrab context.
+ * @return 0 success, !0 failure
  */
-static void
-gdigrab_region_wnd_destroy(AVFormatContext *s1, struct gdigrab *gdigrab)
+static int
+gdigrab_region_wnd_init(AVFormatContext *s1, struct gdigrab *gdigrab)
 {
-    if (gdigrab->region_hwnd)
-        DestroyWindow(gdigrab->region_hwnd);
-    gdigrab->region_hwnd = NULL;
+    HANDLE hthread;
+    HANDLE hevent;
+
+    hevent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!hevent) {
+        WIN32_API_ERROR("Could not create event");
+        return 1;
+    }
+    gdigrab->event_wnd_creation = hevent;
+
+    hthread = (HANDLE)_beginthreadex(NULL, 0, gdigrab_region_wnd_thread, gdigrab, 0, NULL);
+    if (!hthread) {
+        WIN32_API_ERROR("Could not create thread for region display window");
+        CloseHandle(gdigrab->event_wnd_creation);
+        gdigrab->event_wnd_creation = hevent = NULL;
+        return 1;
+    }
+    gdigrab->hthread = hthread;
+
+    WaitForSingleObject(gdigrab->event_wnd_creation, INFINITE);
+    CloseHandle(gdigrab->event_wnd_creation);
+    gdigrab->event_wnd_creation = NULL;
+
+    if (!gdigrab->region_hwnd) {
+        WIN32_API_ERROR("Could not create window or set window region");
+        CloseHandle(gdigrab->hthread);
+        gdigrab->hthread = NULL;
+        return 1;
+    }
+    return 0;
 }
 
 /**
- * Process the Windows message queue.
- *
- * This is important to prevent Windows from thinking the window has become
- * unresponsive. As well, things like WM_PAINT (to actually draw the window
- * contents) are handled from the message queue context.
+ * Cleanup/free the region outline window.
  *
  * @param s1 The format context.
  * @param gdigrab gdigrab context.
  */
 static void
-gdigrab_region_wnd_update(AVFormatContext *s1, struct gdigrab *gdigrab)
+gdigrab_region_wnd_destroy(AVFormatContext *s1, struct gdigrab *gdigrab)
 {
-    HWND hwnd = gdigrab->region_hwnd;
-    MSG msg;
-
-    while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
-        DispatchMessage(&msg);
+    if (gdigrab->region_hwnd) {
+        SendMessage(gdigrab->region_hwnd, WM_REGION_WND_DESTROY, 0, 0);
+        gdigrab->region_hwnd = NULL;
+    }
+    if(gdigrab->hthread) {
+        WaitForSingleObject(gdigrab->hthread, INFINITE);
+        CloseHandle(gdigrab->hthread);
+        gdigrab->hthread = NULL;
     }
 }
 
@@ -548,10 +593,6 @@ static int gdigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
     /* Calculate the time of the next frame */
     time_frame += INT64_C(1000000);
 
-    /* Run Window message processing queue */
-    if (gdigrab->show_region)
-        gdigrab_region_wnd_update(s1, gdigrab);
-
     /* wait based on the frame rate */
     for (;;) {
         curtime = av_gettime_relative();
