quartz: Use a single message thread for all filter graphs.

This matches native, as the test shows, but was motivated by bug 50779, which
it may alleviate.
This commit is contained in:
Zebediah Figura 2022-11-17 20:03:17 -06:00 committed by Alexandre Julliard
parent c7a97b5d5d
commit 0ad6d68873
3 changed files with 61 additions and 30 deletions

View file

@ -42,6 +42,19 @@
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
DECLARE_CRITICAL_SECTION(message_cs);
struct filter_create_params
{
HRESULT hr;
IMoniker *moniker;
IBaseFilter *filter;
};
static HANDLE message_thread, message_thread_ret;
static DWORD message_thread_id;
static unsigned int message_thread_refcount;
struct media_event
{
struct list entry;
@ -132,9 +145,6 @@ struct filter_graph
IUnknown *pSite;
LONG version;
HANDLE message_thread, message_thread_ret;
DWORD message_thread_id;
/* Respectively: the last timestamp at which we started streaming, and the
* current offset within the stream. */
REFERENCE_TIME stream_start, stream_elapsed;
@ -142,6 +152,7 @@ struct filter_graph
LONGLONG current_pos;
unsigned int needs_async_run : 1;
unsigned int threaded : 1;
};
struct enum_filters
@ -465,14 +476,17 @@ static ULONG WINAPI FilterGraphInner_Release(IUnknown *iface)
flush_media_events(This);
CloseHandle(This->media_event_handle);
This->cs.DebugInfo->Spare[0] = 0;
if (This->message_thread)
EnterCriticalSection(&message_cs);
if (This->threaded && !--message_thread_refcount)
{
PostThreadMessageW(This->message_thread_id, WM_USER + 1, 0, 0);
WaitForSingleObject(This->message_thread, INFINITE);
CloseHandle(This->message_thread);
CloseHandle(This->message_thread_ret);
PostThreadMessageW(message_thread_id, WM_USER + 1, 0, 0);
WaitForSingleObject(message_thread, INFINITE);
CloseHandle(message_thread);
CloseHandle(message_thread_ret);
}
LeaveCriticalSection(&message_cs);
This->cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->event_cs);
DeleteCriticalSection(&This->cs);
free(This);
@ -1012,21 +1026,13 @@ static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
return hr;
}
struct filter_create_params
{
HRESULT hr;
IMoniker *moniker;
IBaseFilter *filter;
};
static DWORD WINAPI message_thread_run(void *ctx)
{
struct filter_graph *graph = ctx;
MSG msg;
/* Make sure we have a message queue. */
PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
SetEvent(graph->message_thread_ret);
SetEvent(message_thread_ret);
CoInitializeEx(NULL, COINIT_MULTITHREADED);
@ -1040,7 +1046,7 @@ static DWORD WINAPI message_thread_run(void *ctx)
params->hr = IMoniker_BindToObject(params->moniker, NULL, NULL,
&IID_IBaseFilter, (void **)&params->filter);
SetEvent(graph->message_thread_ret);
SetEvent(message_thread_ret);
}
else if (!msg.hwnd && msg.message == WM_USER + 1)
{
@ -1059,13 +1065,17 @@ static DWORD WINAPI message_thread_run(void *ctx)
static HRESULT create_filter(struct filter_graph *graph, IMoniker *moniker, IBaseFilter **filter)
{
if (graph->message_thread)
if (graph->threaded)
{
struct filter_create_params params;
params.moniker = moniker;
PostThreadMessageW(graph->message_thread_id, WM_USER, (WPARAM)&params, 0);
WaitForSingleObject(graph->message_thread_ret, INFINITE);
EnterCriticalSection(&message_cs);
PostThreadMessageW(message_thread_id, WM_USER, (WPARAM)&params, 0);
WaitForSingleObject(message_thread_ret, INFINITE);
LeaveCriticalSection(&message_cs);
*filter = params.filter;
return params.hr;
}
@ -5654,14 +5664,16 @@ static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL
object->name_index = 1;
object->timeformatseek = TIME_FORMAT_MEDIA_TIME;
if (threaded)
object->threaded = !!threaded;
EnterCriticalSection(&message_cs);
if (threaded && !message_thread_refcount++)
{
object->message_thread_ret = CreateEventW(NULL, FALSE, FALSE, NULL);
object->message_thread = CreateThread(NULL, 0, message_thread_run, object, 0, &object->message_thread_id);
WaitForSingleObject(object->message_thread_ret, INFINITE);
message_thread_ret = CreateEventW(NULL, FALSE, FALSE, NULL);
message_thread = CreateThread(NULL, 0, message_thread_run, object, 0, &message_thread_id);
WaitForSingleObject(message_thread_ret, INFINITE);
}
else
object->message_thread = NULL;
LeaveCriticalSection(&message_cs);
TRACE("Created %sthreaded filter graph %p.\n", threaded ? "" : "non-", object);
*out = &object->IUnknown_inner;

View file

@ -37,6 +37,13 @@
#include "wine/strmbase.h"
#include "wine/list.h"
#define DECLARE_CRITICAL_SECTION(cs) \
static CRITICAL_SECTION cs; \
static CRITICAL_SECTION_DEBUG cs##_debug = \
{ 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
static inline const char *debugstr_time(REFERENCE_TIME time)
{
ULONGLONG abstime = time >= 0 ? time : -time;

View file

@ -5213,10 +5213,11 @@ static void test_window_threading(void)
};
WCHAR *filename = load_resource(L"test.avi");
IFilterGraph2 *graph = create_graph();
HWND hwnd, hwnd2, parent;
IFilterGraph2 *graph2;
IVideoWindow *window;
HWND hwnd, parent;
DWORD tid, tid2;
HRESULT hr;
DWORD tid;
ULONG ref;
BOOL ret;
@ -5253,6 +5254,17 @@ static void test_window_threading(void)
ok(hr == S_OK, "Got hr %#lx.\n", hr);
IVideoWindow_Release(window);
ok(!(GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOPARENTNOTIFY), "Window has WS_EX_NOPARENTNOTIFY.\n");
graph2 = create_graph();
hr = IFilterGraph2_RenderFile(graph2, filename, NULL);
ok(hr == S_OK, "Got hr %#lx.\n", hr);
hwnd2 = get_renderer_hwnd(graph);
ok(!!hwnd2, "Failed to get renderer window.\n");
tid2 = GetWindowThreadProcessId(hwnd, NULL);
ok(tid2 == tid, "Expected thread to be shared.\n");
ref = IFilterGraph2_Release(graph2);
ok(!ref, "Got outstanding refcount %ld.\n", ref);
}
else
skip("Could not find renderer window.\n");