From patchwork Wed Mar 31 11:49:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: 1160386205@qq.com X-Patchwork-Id: 26674 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id A549C44AB1B for ; Wed, 31 Mar 2021 22:51:37 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 8AC1E689E50; Wed, 31 Mar 2021 22:51:37 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from qq.com (out203-205-221-164.mail.qq.com [203.205.221.164]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EAB3F6805D1 for ; Wed, 31 Mar 2021 22:51:29 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qq.com; s=s201512; t=1617220286; bh=eCXGBFtPUa7d7Lu4IsBO+WQ/jHAJ7Td/SvrW7bff3V8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ieBGpSDaPePmLg3D+Rw3Nnz/Vue4PgRuWJ9pgpnjeKgJCXzPX0kU2PNr//OlcITtm cbEXmLqPWTvENCKIVxgMdSKhUTiYFfGEPbqVH0pwPBJTiCyNk9SIZEgcfAVT2rPSge TkDT20RLQibhtnJWXic6as3+T2SRDfLIFRfWSaio= Received: from localhost.localdomain ([61.241.193.187]) by newxmesmtplogicsvrszb7.qq.com (NewEsmtp) with SMTP id CB52DA9B; Thu, 01 Apr 2021 03:50:53 +0800 X-QQ-mid: xmsmtpt1617220255tr8gn0ln7 Message-ID: X-QQ-XMAILINFO: OHni7aYXUfmwI9uBzE1ZaRHIzXxmZgMSuL63YZSJ8BtZM+21nKoZEPbcq5uK9K SMHJeDeA7LAL5iVtuLX70yXoZRjsupQx18yls4N7GWb9/2aOceWjj//Yl5xCwyDspY9ImiWExH7q 2dvmohm0V/1wM8oygngRlczPNm5dLr1zk7PzrTI6JqRC0vkEVQW5uQzix5jKVeRqmVFKcmDJypgv hORLG5HoWpzXZFn8p8ppfWZxMitbzlpM0V8Jo366X5ej302bjS4gD720LQICPsbV+PXtq9RhpY1r Kj9fvjvI+KiG24OPMUNTKQlERIfRLytrDg1u2W+C9MhqJKQRC5feZH8pN0yyhRIvKzMXSdeMk2ns /fzCedr6k8fvn3c63Ap8OJXG7SyEsawfDWysSiWbq1t9Gbjwv9/pl4i0RGXGL1vo3YI7d4+ptlsF h4+k81ZxFMEVk1+nwtxhlJZBCuv89ueLgBCMhGyXlkGLHkHLmn6BRL/TdxG9pGmlTWh7qb4f2cU/ SZmjsm5RgHrcdDtI9GzNsO/NyQnJ6GhnViygsB0Xt+yD22/5hU/a0jKJasIptWovqlXXxgiCZ6t4 fcIp69UaMHOVMu6YQ/NWJs8nVRtBSy9xQu9FZGY1IsLbuHfOmnNzl8gMZYRIwSToL58oIxYL6B5u bK6n0P8Xc8s4e+wEPbREBnW1WG4cSLc6pkP7BCWBd7EJHoa+hztlTnLmFKnUBUv7d7upqq/gU0QV Bkjz84WnxV8FZLfcB8AnssiwhmNJ4ZQzIABDxLzMFn2BwTsrNTxHLqc45jHHWfN3M6LcYxW2G2jp YDi2E1/Xc5Cwu7EfZaH991oKQUSaMSGHC1FgIYLYmT3N3WulhXBLj7 From: 1160386205@qq.com To: ffmpeg-devel@ffmpeg.org Date: Wed, 31 Mar 2021 19:49:53 +0800 X-OQ-MSGID: <20210331114953.92-2-1160386205@qq.com> X-Mailer: git-send-email 2.30.0.windows.2 In-Reply-To: <20210331114953.92-1-1160386205@qq.com> References: <20210331114953.92-1-1160386205@qq.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/2] libavdevice/gdigrab: create a separate thread for handling window messages X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: He Yang <1160386205@qq.com> Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: He Yang <1160386205@qq.com> Windows message processing should start as soon as the window is created. otherwise, Windows may think ffmpeg is not responding. for example the window may got stucked (by clicking at it) in the previous code while ffmpeg is querying the user whether to overwrite the existing file or not. I move the window creation and message handling process to a separate thread to solve this probelm. Signed-off-by: He Yang <1160386205@qq.com> --- libavdevice/gdigrab.c | 105 +++++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 32 deletions(-) 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 +#include +#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();