Nikolay Sivov : evr/sample: Use separate thread for tracking notifications.

Alexandre Julliard julliard at winehq.org
Fri Nov 6 14:15:24 CST 2020


Module: wine
Branch: master
Commit: 2865d4216e58f552cfa122efed6fcb4e58d89753
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=2865d4216e58f552cfa122efed6fcb4e58d89753

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Fri Nov  6 18:15:26 2020 +0300

evr/sample: Use separate thread for tracking notifications.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/evr/sample.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 275 insertions(+), 5 deletions(-)

diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c
index 39520cb6020..729f279fafe 100644
--- a/dlls/evr/sample.c
+++ b/dlls/evr/sample.c
@@ -103,6 +103,276 @@ static struct surface_buffer *impl_from_IMFGetService(IMFGetService *iface)
     return CONTAINING_RECORD(iface, struct surface_buffer, IMFGetService_iface);
 }
 
+struct tracked_async_result
+{
+    MFASYNCRESULT result;
+    LONG refcount;
+    IUnknown *object;
+    IUnknown *state;
+};
+
+static struct tracked_async_result *impl_from_IMFAsyncResult(IMFAsyncResult *iface)
+{
+    return CONTAINING_RECORD(iface, struct tracked_async_result, result.AsyncResult);
+}
+
+static HRESULT WINAPI tracked_async_result_QueryInterface(IMFAsyncResult *iface, REFIID riid, void **obj)
+{
+    TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+    if (IsEqualIID(riid, &IID_IMFAsyncResult) ||
+            IsEqualIID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        IMFAsyncResult_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+    WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI tracked_async_result_AddRef(IMFAsyncResult *iface)
+{
+    struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
+    ULONG refcount = InterlockedIncrement(&result->refcount);
+
+    TRACE("%p, %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI tracked_async_result_Release(IMFAsyncResult *iface)
+{
+    struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
+    ULONG refcount = InterlockedDecrement(&result->refcount);
+
+    TRACE("%p, %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        if (result->result.pCallback)
+            IMFAsyncCallback_Release(result->result.pCallback);
+        if (result->object)
+            IUnknown_Release(result->object);
+        if (result->state)
+            IUnknown_Release(result->state);
+        heap_free(result);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI tracked_async_result_GetState(IMFAsyncResult *iface, IUnknown **state)
+{
+    struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p, %p.\n", iface, state);
+
+    if (!result->state)
+        return E_POINTER;
+
+    *state = result->state;
+    IUnknown_AddRef(*state);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI tracked_async_result_GetStatus(IMFAsyncResult *iface)
+{
+    struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p.\n", iface);
+
+    return result->result.hrStatusResult;
+}
+
+static HRESULT WINAPI tracked_async_result_SetStatus(IMFAsyncResult *iface, HRESULT status)
+{
+    struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p, %#x.\n", iface, status);
+
+    result->result.hrStatusResult = status;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI tracked_async_result_GetObject(IMFAsyncResult *iface, IUnknown **object)
+{
+    struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p, %p.\n", iface, object);
+
+    if (!result->object)
+        return E_POINTER;
+
+    *object = result->object;
+    IUnknown_AddRef(*object);
+
+    return S_OK;
+}
+
+static IUnknown * WINAPI tracked_async_result_GetStateNoAddRef(IMFAsyncResult *iface)
+{
+    struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
+
+    TRACE("%p.\n", iface);
+
+    return result->state;
+}
+
+static const IMFAsyncResultVtbl tracked_async_result_vtbl =
+{
+    tracked_async_result_QueryInterface,
+    tracked_async_result_AddRef,
+    tracked_async_result_Release,
+    tracked_async_result_GetState,
+    tracked_async_result_GetStatus,
+    tracked_async_result_SetStatus,
+    tracked_async_result_GetObject,
+    tracked_async_result_GetStateNoAddRef,
+};
+
+static HRESULT create_async_result(IUnknown *object, IMFAsyncCallback *callback,
+        IUnknown *state, IMFAsyncResult **out)
+{
+    struct tracked_async_result *result;
+
+    result = heap_alloc_zero(sizeof(*result));
+    if (!result)
+        return E_OUTOFMEMORY;
+
+    result->result.AsyncResult.lpVtbl = &tracked_async_result_vtbl;
+    result->refcount = 1;
+    result->object = object;
+    if (result->object)
+        IUnknown_AddRef(result->object);
+    result->result.pCallback = callback;
+    if (result->result.pCallback)
+        IMFAsyncCallback_AddRef(result->result.pCallback);
+    result->state = state;
+    if (result->state)
+        IUnknown_AddRef(result->state);
+
+    *out = &result->result.AsyncResult;
+
+    return S_OK;
+}
+
+struct tracking_thread
+{
+    HANDLE hthread;
+    DWORD tid;
+    LONG refcount;
+};
+static struct tracking_thread tracking_thread;
+
+static CRITICAL_SECTION tracking_thread_cs = { NULL, -1, 0, 0, 0, 0 };
+
+enum tracking_thread_message
+{
+    TRACKM_STOP = WM_USER,
+    TRACKM_INVOKE = WM_USER + 1,
+};
+
+static DWORD CALLBACK tracking_thread_proc(void *arg)
+{
+    HANDLE ready_event = arg;
+    BOOL stop_thread = FALSE;
+    IMFAsyncResult *result;
+    MFASYNCRESULT *data;
+    MSG msg;
+
+    PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+    SetEvent(ready_event);
+
+    while (!stop_thread)
+    {
+        MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE, QS_POSTMESSAGE);
+
+        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+        {
+            switch (msg.message)
+            {
+                case TRACKM_INVOKE:
+                    result = (IMFAsyncResult *)msg.lParam;
+                    data = (MFASYNCRESULT *)result;
+                    if (data->pCallback)
+                        IMFAsyncCallback_Invoke(data->pCallback, result);
+                    IMFAsyncResult_Release(result);
+                    break;
+
+                case TRACKM_STOP:
+                    stop_thread = TRUE;
+                    break;
+
+                default:
+                    ;
+            }
+        }
+    }
+
+    TRACE("Tracking thread exiting.\n");
+
+    return 0;
+}
+
+static void video_sample_create_tracking_thread(void)
+{
+    EnterCriticalSection(&tracking_thread_cs);
+
+    if (++tracking_thread.refcount == 1)
+    {
+        HANDLE ready_event;
+
+        ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+        if (!(tracking_thread.hthread = CreateThread(NULL, 0, tracking_thread_proc,
+                ready_event, 0, &tracking_thread.tid)))
+        {
+            WARN("Failed to create sample tracking thread.\n");
+            CloseHandle(ready_event);
+            return;
+        }
+
+        WaitForSingleObject(ready_event, INFINITE);
+        CloseHandle(ready_event);
+
+        TRACE("Create tracking thread %#x.\n", tracking_thread.tid);
+    }
+
+    LeaveCriticalSection(&tracking_thread_cs);
+}
+
+static void video_sample_stop_tracking_thread(void)
+{
+    EnterCriticalSection(&tracking_thread_cs);
+
+    if (!--tracking_thread.refcount)
+    {
+        PostThreadMessageW(tracking_thread.tid, TRACKM_STOP, 0, 0);
+        CloseHandle(tracking_thread.hthread);
+        memset(&tracking_thread, 0, sizeof(tracking_thread));
+    }
+
+    LeaveCriticalSection(&tracking_thread_cs);
+}
+
+static void video_sample_tracking_thread_invoke(IMFAsyncResult *result)
+{
+    if (!tracking_thread.tid)
+    {
+        WARN("Sample tracking thread is not initialized.\n");
+        return;
+    }
+
+    IMFAsyncResult_AddRef(result);
+    PostThreadMessageW(tracking_thread.tid, TRACKM_INVOKE, 0, (LPARAM)result);
+}
+
 struct sample_allocator
 {
     IMFVideoSampleAllocator IMFVideoSampleAllocator_iface;
@@ -628,14 +898,11 @@ static ULONG WINAPI video_sample_Release(IMFSample *iface)
 {
     struct video_sample *sample = impl_from_IMFSample(iface);
     ULONG refcount;
-    HRESULT hr;
 
     IMFSample_LockStore(sample->sample);
     if (sample->tracked_result && sample->tracked_refcount == (sample->refcount - 1))
     {
-        /* Call could fail if queue system is not initialized, it's not critical. */
-        if (FAILED(hr = MFInvokeCallback(sample->tracked_result)))
-            WARN("Failed to invoke tracking callback, hr %#x.\n", hr);
+        video_sample_tracking_thread_invoke(sample->tracked_result);
         IMFAsyncResult_Release(sample->tracked_result);
         sample->tracked_result = NULL;
         sample->tracked_refcount = 0;
@@ -648,6 +915,7 @@ static ULONG WINAPI video_sample_Release(IMFSample *iface)
 
     if (!refcount)
     {
+        video_sample_stop_tracking_thread();
         if (sample->sample)
             IMFSample_Release(sample->sample);
         heap_free(sample);
@@ -1132,7 +1400,7 @@ static HRESULT WINAPI tracked_video_sample_SetAllocator(IMFTrackedSample *iface,
         hr = MF_E_NOTACCEPTING;
     else
     {
-        if (SUCCEEDED(hr = MFCreateAsyncResult((IUnknown *)iface, sample_allocator, state, &sample->tracked_result)))
+        if (SUCCEEDED(hr = create_async_result((IUnknown *)iface, sample_allocator, state, &sample->tracked_result)))
         {
             /* Account for additional refcount brought by 'state' object. This threshold is used
                on Release() to invoke tracker callback.  */
@@ -1428,6 +1696,8 @@ HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *surface, IMFSample **sam
     if (buffer)
         IMFSample_AddBuffer(object->sample, buffer);
 
+    video_sample_create_tracking_thread();
+
     *sample = &object->IMFSample_iface;
 
     return S_OK;




More information about the wine-cvs mailing list