Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/presenter.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 335e5df2459..2102882e084 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -70,6 +70,7 @@ struct video_presenter IMediaEventSink *event_sink;
IDirect3DDeviceManager9 *device_manager; + IMFVideoSampleAllocator *allocator; struct streaming_thread thread; IMFMediaType *media_type; UINT reset_token; @@ -175,12 +176,13 @@ static void video_presenter_reset_media_type(struct video_presenter *presenter) IMFMediaType_Release(presenter->media_type); presenter->media_type = NULL;
- /* FIXME: release samples pool */ + IMFVideoSampleAllocator_UninitializeSampleAllocator(presenter->allocator); }
static HRESULT video_presenter_set_media_type(struct video_presenter *presenter, IMFMediaType *media_type) { unsigned int flags; + HRESULT hr;
if (!media_type) { @@ -193,12 +195,15 @@ static HRESULT video_presenter_set_media_type(struct video_presenter *presenter,
video_presenter_reset_media_type(presenter);
- /* FIXME: allocate samples pool */ - - presenter->media_type = media_type; - IMFMediaType_AddRef(presenter->media_type); + if (SUCCEEDED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(presenter->allocator, 3, media_type))) + { + presenter->media_type = media_type; + IMFMediaType_AddRef(presenter->media_type); + } + else + WARN("Failed to initialize sample allocator, hr %#x.\n", hr);
- return S_OK; + return hr; }
static HRESULT video_presenter_invalidate_media_type(struct video_presenter *presenter) @@ -220,7 +225,9 @@ static HRESULT video_presenter_invalidate_media_type(struct video_presenter *pre if (SUCCEEDED(hr)) hr = video_presenter_set_media_type(presenter, media_type);
- hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, 0); + if (SUCCEEDED(hr)) + hr = IMFTransform_SetOutputType(presenter->mixer, 0, media_type, 0); + IMFMediaType_Release(media_type);
if (SUCCEEDED(hr)) @@ -388,9 +395,12 @@ static ULONG WINAPI video_presenter_inner_Release(IUnknown *iface) { video_presenter_end_streaming(presenter); video_presenter_clear_container(presenter); + video_presenter_reset_media_type(presenter); DeleteCriticalSection(&presenter->cs); if (presenter->device_manager) IDirect3DDeviceManager9_Release(presenter->device_manager); + if (presenter->allocator) + IMFVideoSampleAllocator_Release(presenter->allocator); heap_free(presenter); }
@@ -1179,6 +1189,11 @@ static HRESULT video_presenter_init_d3d(struct video_presenter *presenter) if (FAILED(hr)) WARN("Failed to set new device for the manager, hr %#x.\n", hr);
+ if (SUCCEEDED(hr = MFCreateVideoSampleAllocator(&IID_IMFVideoSampleAllocator, (void **)&presenter->allocator))) + { + hr = IMFVideoSampleAllocator_SetDirectXManager(presenter->allocator, (IUnknown *)presenter->device_manager); + } + return hr; }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/presenter.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 2102882e084..8be3dd91aa7 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -40,6 +40,11 @@ enum presenter_state PRESENTER_STATE_PAUSED, };
+enum presenter_flags +{ + PRESENTER_MIXER_HAS_INPUT = 0x1, +}; + enum streaming_thread_message { EVRM_STOP = WM_USER, @@ -82,6 +87,7 @@ struct video_presenter SIZE native_ratio; unsigned int ar_mode; unsigned int state; + unsigned int flags; CRITICAL_SECTION cs; };
@@ -311,6 +317,50 @@ static HRESULT video_presenter_end_streaming(struct video_presenter *presenter) return S_OK; }
+static HRESULT video_presenter_process_input(struct video_presenter *presenter) +{ + MFT_OUTPUT_DATA_BUFFER buffer; + HRESULT hr = S_OK; + IMFSample *sample; + DWORD status; + + if (!presenter->media_type) + return S_OK; + + while (hr == S_OK) + { + if (!(presenter->flags & PRESENTER_MIXER_HAS_INPUT)) + break; + + if (FAILED(hr = IMFVideoSampleAllocator_AllocateSample(presenter->allocator, &sample))) + { + WARN("Failed to allocate a sample, hr %#x.\n", hr); + break; + } + + memset(&buffer, 0, sizeof(buffer)); + buffer.pSample = sample; + + if (FAILED(hr = IMFTransform_ProcessOutput(presenter->mixer, 0, 1, &buffer, &status))) + { + /* FIXME: failure path probably needs to handle some errors specifically */ + presenter->flags &= ~PRESENTER_MIXER_HAS_INPUT; + IMFSample_Release(sample); + break; + } + else + { + if (buffer.pEvents) + IMFCollection_Release(buffer.pEvents); + + /* FIXME: for now drop output sample back to the pool */ + IMFSample_Release(sample); + } + } + + return S_OK; +} + static HRESULT WINAPI video_presenter_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { struct video_presenter *presenter = impl_from_IUnknown(iface); @@ -511,6 +561,10 @@ static HRESULT WINAPI video_presenter_ProcessMessage(IMFVideoPresenter *iface, M case MFVP_MESSAGE_ENDSTREAMING: hr = video_presenter_end_streaming(presenter); break; + case MFVP_MESSAGE_PROCESSINPUTNOTIFY: + presenter->flags |= PRESENTER_MIXER_HAS_INPUT; + hr = video_presenter_process_input(presenter); + break; default: FIXME("Unsupported message %u.\n", message); hr = E_NOTIMPL;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/presenter.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 8be3dd91aa7..5bffa9af228 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -131,6 +131,13 @@ static struct video_presenter *impl_from_IMFVideoPositionMapper(IMFVideoPosition return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPositionMapper_iface); }
+static void video_presenter_notify_renderer(struct video_presenter *presenter, + LONG event, LONG_PTR param1, LONG_PTR param2) +{ + if (presenter->event_sink) + IMediaEventSink_Notify(presenter->event_sink, event, param1, param2); +} + static unsigned int get_gcd(unsigned int a, unsigned int b) { unsigned int m; @@ -329,6 +336,9 @@ static HRESULT video_presenter_process_input(struct video_presenter *presenter)
while (hr == S_OK) { + LONGLONG mixing_started, mixing_finished; + MFTIME systime; + if (!(presenter->flags & PRESENTER_MIXER_HAS_INPUT)) break;
@@ -341,6 +351,9 @@ static HRESULT video_presenter_process_input(struct video_presenter *presenter) memset(&buffer, 0, sizeof(buffer)); buffer.pSample = sample;
+ if (presenter->clock) + IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_started, &systime); + if (FAILED(hr = IMFTransform_ProcessOutput(presenter->mixer, 0, 1, &buffer, &status))) { /* FIXME: failure path probably needs to handle some errors specifically */ @@ -350,6 +363,15 @@ static HRESULT video_presenter_process_input(struct video_presenter *presenter) } else { + if (presenter->clock) + { + LONGLONG latency; + + IMFClock_GetCorrelatedTime(presenter->clock, 0, &mixing_finished, &systime); + latency = mixing_finished - mixing_started; + video_presenter_notify_renderer(presenter, EC_PROCESSING_LATENCY, (LONG_PTR)&latency, 0); + } + if (buffer.pEvents) IMFCollection_Release(buffer.pEvents);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/presenter.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+)
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 5bffa9af228..9bf4cda3725 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -66,6 +66,7 @@ struct video_presenter IMFRateSupport IMFRateSupport_iface; IMFGetService IMFGetService_iface; IMFVideoPositionMapper IMFVideoPositionMapper_iface; + IMFVideoSampleAllocatorNotify allocator_cb; IUnknown IUnknown_inner; IUnknown *outer_unk; LONG refcount; @@ -131,6 +132,11 @@ static struct video_presenter *impl_from_IMFVideoPositionMapper(IMFVideoPosition return CONTAINING_RECORD(iface, struct video_presenter, IMFVideoPositionMapper_iface); }
+static struct video_presenter *impl_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface) +{ + return CONTAINING_RECORD(iface, struct video_presenter, allocator_cb); +} + static void video_presenter_notify_renderer(struct video_presenter *presenter, LONG event, LONG_PTR param1, LONG_PTR param2) { @@ -183,6 +189,18 @@ static void video_presenter_get_native_video_size(struct video_presenter *presen IMFMediaType_Release(media_type); }
+/* It is important this is called to reset callback too to break circular referencing, + when allocator keeps a reference of its container, that created it. */ +static void video_presenter_set_allocator_callback(struct video_presenter *presenter, + IMFVideoSampleAllocatorNotify *notify_cb) +{ + IMFVideoSampleAllocatorCallback *cb; + + IMFVideoSampleAllocator_QueryInterface(presenter->allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&cb); + IMFVideoSampleAllocatorCallback_SetCallback(cb, notify_cb); + IMFVideoSampleAllocatorCallback_Release(cb); +} + static void video_presenter_reset_media_type(struct video_presenter *presenter) { if (presenter->media_type) @@ -190,6 +208,7 @@ static void video_presenter_reset_media_type(struct video_presenter *presenter) presenter->media_type = NULL;
IMFVideoSampleAllocator_UninitializeSampleAllocator(presenter->allocator); + video_presenter_set_allocator_callback(presenter, NULL); }
static HRESULT video_presenter_set_media_type(struct video_presenter *presenter, IMFMediaType *media_type) @@ -298,6 +317,8 @@ static HRESULT video_presenter_start_streaming(struct video_presenter *presenter return E_FAIL; }
+ video_presenter_set_allocator_callback(presenter, &presenter->allocator_cb); + WaitForSingleObject(presenter->thread.ready_event, INFINITE); CloseHandle(presenter->thread.ready_event); presenter->thread.ready_event = NULL; @@ -320,6 +341,7 @@ static HRESULT video_presenter_end_streaming(struct video_presenter *presenter) TRACE("Terminated streaming thread tid %#x.\n", presenter->thread.tid);
memset(&presenter->thread, 0, sizeof(presenter->thread)); + video_presenter_set_allocator_callback(presenter, NULL);
return S_OK; } @@ -1222,6 +1244,47 @@ static const IMFVideoPositionMapperVtbl video_presenter_position_mapper_vtbl = video_presenter_position_mapper_MapOutputCoordinateToInputStream, };
+static HRESULT WINAPI video_presenter_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface, + REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFVideoSampleAllocatorNotify_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI video_presenter_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface) +{ + struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface); + return IMFVideoPresenter_AddRef(&presenter->IMFVideoPresenter_iface); +} + +static ULONG WINAPI video_presenter_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface) +{ + struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface); + return IMFVideoPresenter_Release(&presenter->IMFVideoPresenter_iface); +} + +static HRESULT WINAPI video_presenter_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface) +{ + return E_NOTIMPL; +} + +static const IMFVideoSampleAllocatorNotifyVtbl video_presenter_allocator_cb_vtbl = +{ + video_presenter_allocator_cb_QueryInterface, + video_presenter_allocator_cb_AddRef, + video_presenter_allocator_cb_Release, + video_presenter_allocator_cb_NotifyRelease, +}; + HRESULT WINAPI MFCreateVideoPresenter(IUnknown *owner, REFIID riid_device, REFIID riid, void **obj) { TRACE("%p, %s, %s, %p.\n", owner, debugstr_guid(riid_device), debugstr_guid(riid), obj); @@ -1290,6 +1353,7 @@ HRESULT evr_presenter_create(IUnknown *outer, void **out) object->IMFRateSupport_iface.lpVtbl = &video_presenter_rate_support_vtbl; object->IMFGetService_iface.lpVtbl = &video_presenter_getservice_vtbl; object->IMFVideoPositionMapper_iface.lpVtbl = &video_presenter_position_mapper_vtbl; + object->allocator_cb.lpVtbl = &video_presenter_allocator_cb_vtbl; object->IUnknown_inner.lpVtbl = &video_presenter_inner_vtbl; object->outer_unk = outer ? outer : &object->IUnknown_inner; object->refcount = 1;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/evr/sample.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c index 729f279fafe..a44e3ef45c6 100644 --- a/dlls/evr/sample.c +++ b/dlls/evr/sample.c @@ -815,6 +815,9 @@ static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback
IUnknown_Release(sample);
+ if (allocator->callback) + IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback); + LeaveCriticalSection(&allocator->cs);
return S_OK;