@@ -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();