I'm not sure how could I test this behavior, right now the test I wrote works but there are times where it doesn't enter into the deadlock.
-- v4: evr: Remove process input handling from streaming thread. evr: Don't lock allocator in NotifyRelease call. evr: Create critical section for sample queue. evr: Release sample queue when streaming ends.
From: Santino Mazza smazza@codeweavers.com
--- dlls/evr/presenter.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 06592f8766e..97080717288 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -467,6 +467,18 @@ static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, return *sample != NULL; }
+ +static void video_presenter_sample_queue_free(struct video_presenter *presenter) +{ + struct sample_queue *queue = &presenter->thread.queue; + IMFSample *sample; + + while (video_presenter_sample_queue_pop(presenter, &sample)) + IMFSample_Release(sample); + + free(queue->samples); +} + static HRESULT video_presenter_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface) { IMFMediaBuffer *buffer; @@ -754,6 +766,7 @@ static HRESULT video_presenter_end_streaming(struct video_presenter *presenter)
if (presenter->thread.queue.last_presented) IMFSample_Release(presenter->thread.queue.last_presented); + video_presenter_sample_queue_free(presenter); memset(&presenter->thread, 0, sizeof(presenter->thread)); video_presenter_set_allocator_callback(presenter, NULL);
From: Santino Mazza smazza@codeweavers.com
--- dlls/evr/presenter.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 97080717288..00bc00fbf2b 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -66,6 +66,7 @@ struct sample_queue unsigned int front; unsigned int back; IMFSample *last_presented; + CRITICAL_SECTION cs; };
struct streaming_thread @@ -425,6 +426,7 @@ static HRESULT video_presenter_sample_queue_init(struct video_presenter *present
queue->size = presenter->allocator_capacity; queue->back = queue->size - 1; + InitializeCriticalSection(&queue->cs);
return S_OK; } @@ -435,7 +437,7 @@ static void video_presenter_sample_queue_push(struct video_presenter *presenter, struct sample_queue *queue = &presenter->thread.queue; unsigned int idx;
- EnterCriticalSection(&presenter->cs); + EnterCriticalSection(&queue->cs); if (queue->used != queue->size) { if (at_front) @@ -446,14 +448,14 @@ static void video_presenter_sample_queue_push(struct video_presenter *presenter, queue->used++; IMFSample_AddRef(sample); } - LeaveCriticalSection(&presenter->cs); + LeaveCriticalSection(&queue->cs); }
static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, IMFSample **sample) { struct sample_queue *queue = &presenter->thread.queue;
- EnterCriticalSection(&presenter->cs); + EnterCriticalSection(&queue->cs); if (queue->used) { *sample = queue->samples[queue->front]; @@ -462,7 +464,7 @@ static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, } else *sample = NULL; - LeaveCriticalSection(&presenter->cs); + LeaveCriticalSection(&queue->cs);
return *sample != NULL; } @@ -477,6 +479,7 @@ static void video_presenter_sample_queue_free(struct video_presenter *presenter) IMFSample_Release(sample);
free(queue->samples); + DeleteCriticalSection(&queue->cs); }
static HRESULT video_presenter_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface) @@ -527,12 +530,12 @@ static void video_presenter_sample_present(struct video_presenter *presenter, IM WARN("Failed to get a backbuffer, hr %#lx.\n", hr); }
- EnterCriticalSection(&presenter->cs); + EnterCriticalSection(&presenter->thread.queue.cs); if (presenter->thread.queue.last_presented) IMFSample_Release(presenter->thread.queue.last_presented); presenter->thread.queue.last_presented = sample; IMFSample_AddRef(presenter->thread.queue.last_presented); - LeaveCriticalSection(&presenter->cs); + LeaveCriticalSection(&presenter->thread.queue.cs);
IDirect3DSurface9_Release(surface); }
From: Santino Mazza smazza@codeweavers.com
--- dlls/evr/sample.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c index 6a1bbf564f5..c99ba3dd1b0 100644 --- a/dlls/evr/sample.c +++ b/dlls/evr/sample.c @@ -809,6 +809,7 @@ static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback struct queued_sample *iter; IUnknown *object = NULL; IMFSample *sample = NULL; + IMFVideoSampleAllocatorNotify *callback; HRESULT hr;
if (FAILED(IMFAsyncResult_GetObject(result, &object))) @@ -834,12 +835,13 @@ static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback }
IMFSample_Release(sample); - - if (allocator->callback) - IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback); + callback = allocator->callback;
LeaveCriticalSection(&allocator->cs);
+ if (callback) + IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback); + return S_OK; }
From: Santino Mazza smazza@codeweavers.com
--- dlls/evr/presenter.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 00bc00fbf2b..cd40e470830 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -55,7 +55,6 @@ enum streaming_thread_message { EVRM_STOP = WM_USER, EVRM_PRESENT = WM_USER + 1, - EVRM_PROCESS_INPUT = WM_USER + 2, };
struct sample_queue @@ -705,11 +704,6 @@ static DWORD CALLBACK video_presenter_streaming_thread(void *arg) } break;
- case EVRM_PROCESS_INPUT: - EnterCriticalSection(&presenter->cs); - video_presenter_process_input(presenter); - LeaveCriticalSection(&presenter->cs); - break; default: ; } @@ -1810,9 +1804,9 @@ static HRESULT WINAPI video_presenter_allocator_cb_NotifyRelease(IMFVideoSampleA { struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface);
- /* Release notification is executed under allocator lock, instead of processing samples here - notify streaming thread. */ - PostThreadMessageW(presenter->thread.tid, EVRM_PROCESS_INPUT, 0, 0); + EnterCriticalSection(&presenter->cs); + video_presenter_process_input(presenter); + LeaveCriticalSection(&presenter->cs);
return S_OK; }