[PATCH v5 0/13] MR9489: Draft: mf: Fix seeking within sample grabber.
This fixes seeking within sample grabber by matching Windows functionality. -- v5: mf: Request new sample before processing markers. mf: Remove no longer used sample_count and samples array. mf: Ensure we always have four requests outstanding/satisfied. mf: Always queue a sample unless stopped. mf: Keep count of samples queued. mf: Make flushing on sample grabber largely a no-op. mf/tests: Test sample grabber pause and resume. mf/tests: Check contents of sample collection. mf/tests: Test seek with sample grabber whilst ignoring clock. mf/tests: Test samplegrabber flush then seek. mf/tests: Check StreamSinkMarker event. mf/tests: Test sample grabber {Set,Cancel}Timer. mf/tests: Add test for sample grabber seek. https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/mf.c | 191 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 0c0590ed195..56cef1c9b10 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4189,6 +4189,196 @@ static void test_sample_grabber(void) IMFSampleGrabberSinkCallback_Release(grabber_callback); } +static void supply_samples(IMFStreamSink *stream, int num_samples) +{ + IMFMediaBuffer *buffer; + IMFSample *sample; + HRESULT hr; + int i; + + for (i = 0; i < num_samples; i++) + { + hr = MFCreateMemoryBuffer(360, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateSample(&sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFSample_AddBuffer(sample, buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFSample_SetSampleTime(sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFSample_SetSampleDuration(sample, 41667); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_ProcessSample(stream, sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFMediaBuffer_Release(buffer); + IMFSample_Release(sample); + } +} + +static int count_samples_requested(IMFStreamSink *stream) +{ + int samples_requested; + IMFMediaEvent *event; + MediaEventType met; + HRESULT hr; + + samples_requested = 0; + while (IMFStreamSink_GetEvent(stream, 0, &event) == S_OK) + { + hr = IMFMediaEvent_GetType(event, &met); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFMediaEvent_Release(event); + if (met == MEStreamSinkRequestSample) + samples_requested++; + else if (met == MEStreamSinkStarted) + break; + } + + return samples_requested; +} + +static void test_sample_grabber_seek(void) +{ + IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); + IMFPresentationTimeSource *time_source; + IMFPresentationClock *clock; + IMFMediaType *media_type; + IMFStreamSink *stream; + IMFActivate *activate; + int samples_requested; + IMFMediaSink *sink; + HRESULT hr; + ULONG ref; + + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + + EXPECT_REF(media_type, 1); + hr = MFCreateSampleGrabberSinkActivate(media_type, grabber_callback, &activate); + ok(hr == S_OK, "Failed to create grabber activate, hr %#lx.\n", hr); + EXPECT_REF(media_type, 2); + + ref = IMFMediaType_Release(media_type); + ok(ref == 1, "Release returned %ld\n", ref); + + hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&sink); + ok(hr == S_OK, "Failed to activate object, hr %#lx.\n", hr); + + ref = IMFActivate_Release(activate); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream); + ok(hr == S_OK, "Failed to get sink stream, hr %#lx.\n", hr); + + + /* Set clock. */ + hr = MFCreatePresentationClock(&clock); + ok(hr == S_OK, "Failed to create clock object, hr %#lx.\n", hr); + + hr = IMFMediaSink_SetPresentationClock(sink, clock); + ok(hr == S_OK, "Failed to set presentation clock, hr %#lx.\n", hr); + + hr = MFCreateSystemTimeSource(&time_source); + ok(hr == S_OK, "Failed to create time source, hr %#lx.\n", hr); + + hr = IMFPresentationClock_SetTimeSource(clock, time_source); + ok(hr == S_OK, "Failed to set time source, hr %#lx.\n", hr); + IMFPresentationTimeSource_Release(time_source); + + + /* test number of new sample requests on clock start */ + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek when in running state and 4 samples have been provided */ + supply_samples(stream, 4); + hr = IMFPresentationClock_Start(clock, 1234); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + todo_wine + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek when in running state and 3 samples have been provided */ + supply_samples(stream, 3); + hr = IMFPresentationClock_Start(clock, 1234); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + todo_wine + ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek whilst stopped */ + hr = IMFPresentationClock_Stop(clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + todo_wine + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek whilst paused and 3 samples provided */ + supply_samples(stream, 3); + + hr = IMFPresentationClock_Pause(clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + todo_wine + ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek whilst paused and no samples provided */ + hr = IMFPresentationClock_Pause(clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + todo_wine + ok(samples_requested == 0, "Unexpected number of samples requested %d\n", samples_requested); + + ref = IMFPresentationClock_Release(clock); + ok(ref == 2, "Release returned %ld\n", ref); + + /* required for the sink to be fully released */ + hr = IMFMediaSink_Shutdown(sink); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + ref = IMFMediaSink_Release(sink); + todo_wine + ok(ref == 0, "Release returned %ld\n", ref); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + IMFSampleGrabberSinkCallback_Release(grabber_callback); +} + static void test_sample_grabber_is_mediatype_supported(void) { IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); @@ -8454,6 +8644,7 @@ START_TEST(mf) test_MFShutdownObject(); test_presentation_clock(); test_sample_grabber(); + test_sample_grabber_seek(); test_sample_grabber_is_mediatype_supported(); test_sample_grabber_orientation(MFVideoFormat_RGB32); test_sample_grabber_orientation(MFVideoFormat_NV12); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/mf.c | 419 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 393 insertions(+), 26 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 56cef1c9b10..445cd403090 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4189,8 +4189,325 @@ static void test_sample_grabber(void) IMFSampleGrabberSinkCallback_Release(grabber_callback); } +struct timer_cancel +{ + IUnknown IUnknown_iface; + LONG refcount; + ULONG id; +}; + +static struct timer_cancel* impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct timer_cancel, IUnknown_iface); +} + +static WINAPI HRESULT unknown_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + } + else + { + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef(iface); + return S_OK; +} + +static WINAPI ULONG unknown_AddRef(IUnknown *iface) +{ + struct timer_cancel *tc = impl_from_IUnknown(iface); + return InterlockedIncrement(&tc->refcount); +} + +static WINAPI ULONG unknown_Release(IUnknown *iface) +{ + struct timer_cancel *tc = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&tc->refcount); + + if (!tc->refcount) + free(tc); + + return refcount; +} + +static IUnknownVtbl UnknownVtbl = +{ + unknown_QueryInterface, + unknown_AddRef, + unknown_Release, +}; + +static struct timer_cancel* create_timer_cancel(void) +{ + static ULONG id = 1; + + struct timer_cancel *tc = calloc(1, sizeof(*tc)); + tc->IUnknown_iface.lpVtbl = &UnknownVtbl; + tc->refcount = 1; + tc->id = id++; + + return tc; +} + +DEFINE_EXPECT(timer_SetTimer); +DEFINE_EXPECT(timer_CancelTimer); + +struct presentation_clock +{ + IMFPresentationClock IMFPresentationClock_iface; + IMFTimer IMFTimer_iface; + LONG refcount; + IMFClockStateSink *sample_grabber_clock_state_sink; + IMFAsyncResult *callback_result; + IUnknown *cancel_key; +}; + +static struct presentation_clock* impl_from_IMFTimer(IMFTimer *iface) +{ + return CONTAINING_RECORD(iface, struct presentation_clock, IMFTimer_iface); +} + +static WINAPI HRESULT timer_QueryInterface(IMFTimer *iface, REFIID riid, void **obj) +{ + struct presentation_clock* pc = impl_from_IMFTimer(iface); + return IMFPresentationClock_QueryInterface(&pc->IMFPresentationClock_iface, riid, obj); +} + +static WINAPI ULONG timer_AddRef(IMFTimer *iface) +{ + struct presentation_clock* pc = impl_from_IMFTimer(iface); + return IMFPresentationClock_AddRef(&pc->IMFPresentationClock_iface); +} + +static WINAPI ULONG timer_Release(IMFTimer *iface) +{ + struct presentation_clock* pc = impl_from_IMFTimer(iface); + return IMFPresentationClock_Release(&pc->IMFPresentationClock_iface); +} + +static HRESULT WINAPI timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time, + IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_key) +{ + struct presentation_clock* pc = impl_from_IMFTimer(iface); + struct timer_cancel *tc; + HRESULT hr; + + CHECK_EXPECT(timer_SetTimer); + + ok(flags == 0, "Unexpected flags value %#lx\n", flags); + ok(time == 0, "Unexpected time value %I64d\n", time); + ok(pc->callback_result == NULL, "Unexpected callback value %p\n", pc->callback_result); + ok(pc->cancel_key == NULL, "Unexpected cancel key %p\n", pc->cancel_key); + + hr = MFCreateAsyncResult(NULL, callback, state, &pc->callback_result); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + tc = create_timer_cancel(); + pc->cancel_key = *cancel_key = &tc->IUnknown_iface; + + return S_OK; +} + +static HRESULT WINAPI timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key) +{ + struct presentation_clock* pc = impl_from_IMFTimer(iface); + + todo_wine + CHECK_EXPECT(timer_CancelTimer); + ok(cancel_key == pc->cancel_key, "Unexpected cancel key %p\n", cancel_key); + + IMFAsyncResult_Release(pc->callback_result); + pc->callback_result = NULL; + pc->cancel_key = NULL; + + return S_OK; +} + +static IMFTimerVtbl MFTimerVtbl = +{ + timer_QueryInterface, + timer_AddRef, + timer_Release, + timer_SetTimer, + timer_CancelTimer, +}; + +static struct presentation_clock* impl_from_IMFPresentationClock(IMFPresentationClock *iface) +{ + return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface); +} + +static WINAPI HRESULT presentation_clock_QueryInterface(IMFPresentationClock *iface, REFIID riid, void **obj) +{ + struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); + + if (IsEqualIID(riid, &IID_IMFPresentationClock) || + IsEqualIID(riid, &IID_IMFClock) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + } + else if (IsEqualIID(riid, &IID_IMFTimer)) + { + *obj = &pc->IMFTimer_iface; + } + else + { + *obj = NULL; + return E_NOINTERFACE; + } + + IMFPresentationClock_AddRef(iface); + return S_OK; +} + +static WINAPI ULONG presentation_clock_AddRef(IMFPresentationClock *iface) +{ + struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); + return InterlockedIncrement(&pc->refcount); +} + +static WINAPI ULONG presentation_clock_Release(IMFPresentationClock *iface) +{ + struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); + ULONG refcount = InterlockedDecrement(&pc->refcount); + + if (!pc->refcount) + { + if (pc->sample_grabber_clock_state_sink) + IMFClockStateSink_Release(pc->sample_grabber_clock_state_sink); + if (pc->callback_result) + IMFAsyncResult_Release(pc->callback_result); + free(pc); + } + + return refcount; +} + +static WINAPI HRESULT presentation_clock_GetClockCharacteristics(IMFPresentationClock *iface, DWORD *flags) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_GetCorrelatedTime(IMFPresentationClock *iface, DWORD reserved, + LONGLONG *clock_time, MFTIME *system_time) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_GetContinuityKey(IMFPresentationClock *iface, DWORD *key) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_GetState(IMFPresentationClock *iface, DWORD reserved, MFCLOCK_STATE *state) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_GetProperties(IMFPresentationClock *iface, MFCLOCK_PROPERTIES *props) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_SetTimeSource(IMFPresentationClock *iface, + IMFPresentationTimeSource *time_source) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_GetTimeSource(IMFPresentationClock *iface, + IMFPresentationTimeSource **time_source) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_GetTime(IMFPresentationClock *iface, MFTIME *time) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink) +{ + struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); + + if (pc->sample_grabber_clock_state_sink) + IMFClockStateSink_Release(pc->sample_grabber_clock_state_sink); + + IMFClockStateSink_AddRef(pc->sample_grabber_clock_state_sink = state_sink); + + return S_OK; +} + +static WINAPI HRESULT presentation_clock_RemoveClockStateSink(IMFPresentationClock *iface, + IMFClockStateSink *state_sink) +{ + struct presentation_clock *pc = impl_from_IMFPresentationClock(iface); + + if (pc->sample_grabber_clock_state_sink == state_sink) + { + IMFClockStateSink_Release(state_sink); + pc->sample_grabber_clock_state_sink = NULL; + } + + return S_OK; +} + +static WINAPI HRESULT presentation_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_Stop(IMFPresentationClock *iface) +{ + return E_NOTIMPL; +} + +static WINAPI HRESULT presentation_clock_Pause(IMFPresentationClock *iface) +{ + return E_NOTIMPL; +} + +static IMFPresentationClockVtbl MFPresentationClockVtbl = +{ + presentation_clock_QueryInterface, + presentation_clock_AddRef, + presentation_clock_Release, + presentation_clock_GetClockCharacteristics, + presentation_clock_GetCorrelatedTime, + presentation_clock_GetContinuityKey, + presentation_clock_GetState, + presentation_clock_GetProperties, + presentation_clock_SetTimeSource, + presentation_clock_GetTimeSource, + presentation_clock_GetTime, + presentation_clock_AddClockStateSink, + presentation_clock_RemoveClockStateSink, + presentation_clock_Start, + presentation_clock_Stop, + presentation_clock_Pause, +}; + +static struct presentation_clock* create_presentation_clock(void) +{ + struct presentation_clock* pc = calloc(1, sizeof(*pc)); + + pc->IMFPresentationClock_iface.lpVtbl = &MFPresentationClockVtbl; + pc->IMFTimer_iface.lpVtbl = &MFTimerVtbl; + pc->refcount = 1; + + return pc; +} + +static MFTIME sample_pts = 0; + static void supply_samples(IMFStreamSink *stream, int num_samples) { + IMFMediaBuffer *buffer; IMFSample *sample; HRESULT hr; @@ -4207,9 +4524,11 @@ static void supply_samples(IMFStreamSink *stream, int num_samples) hr = IMFSample_AddBuffer(sample, buffer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFSample_SetSampleTime(sample, 0); + hr = IMFSample_SetSampleTime(sample, sample_pts); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + sample_pts += 41667; + hr = IMFSample_SetSampleDuration(sample, 41667); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -4247,7 +4566,8 @@ static int count_samples_requested(IMFStreamSink *stream) static void test_sample_grabber_seek(void) { IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); - IMFPresentationTimeSource *time_source; + struct presentation_clock *mock_clock; + IMFClockStateSink *clock_sink; IMFPresentationClock *clock; IMFMediaType *media_type; IMFStreamSink *stream; @@ -4257,7 +4577,6 @@ static void test_sample_grabber_seek(void) HRESULT hr; ULONG ref; - hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); @@ -4288,84 +4607,132 @@ static void test_sample_grabber_seek(void) /* Set clock. */ - hr = MFCreatePresentationClock(&clock); - ok(hr == S_OK, "Failed to create clock object, hr %#lx.\n", hr); + mock_clock = create_presentation_clock(); + clock = &mock_clock->IMFPresentationClock_iface; hr = IMFMediaSink_SetPresentationClock(sink, clock); ok(hr == S_OK, "Failed to set presentation clock, hr %#lx.\n", hr); - - hr = MFCreateSystemTimeSource(&time_source); - ok(hr == S_OK, "Failed to create time source, hr %#lx.\n", hr); - - hr = IMFPresentationClock_SetTimeSource(clock, time_source); - ok(hr == S_OK, "Failed to set time source, hr %#lx.\n", hr); - IMFPresentationTimeSource_Release(time_source); + ok(!!mock_clock->sample_grabber_clock_state_sink, "AddClockStateSink not called\n"); + clock_sink = mock_clock->sample_grabber_clock_state_sink; /* test number of new sample requests on clock start */ - hr = IMFPresentationClock_Start(clock, 0); + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek when in running state and 4 samples have been provided */ + sample_pts = 0; + SET_EXPECT(timer_SetTimer); supply_samples(stream, 4); - hr = IMFPresentationClock_Start(clock, 1234); + CHECK_CALLED(timer_SetTimer); + + SET_EXPECT(timer_CancelTimer); + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek when in running state and 3 samples have been provided */ + sample_pts = 0; + SET_EXPECT(timer_SetTimer); supply_samples(stream, 3); - hr = IMFPresentationClock_Start(clock, 1234); + todo_wine + CHECK_CALLED(timer_SetTimer); + + SET_EXPECT(timer_CancelTimer); + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); todo_wine ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst stopped */ - hr = IMFPresentationClock_Stop(clock); + hr = IMFClockStateSink_OnClockStop(clock_sink, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFPresentationClock_Start(clock, 0); + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst paused and 3 samples provided */ + sample_pts = 0; + SET_EXPECT(timer_SetTimer); supply_samples(stream, 3); + todo_wine + CHECK_CALLED(timer_SetTimer); - hr = IMFPresentationClock_Pause(clock); + hr = IMFClockStateSink_OnClockPause(clock_sink, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFPresentationClock_Start(clock, 0); + /* test over supply */ + supply_samples(stream, 6); + + SET_EXPECT(timer_CancelTimer); + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); - todo_wine - ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst paused and no samples provided */ - hr = IMFPresentationClock_Pause(clock); + hr = IMFClockStateSink_OnClockPause(clock_sink, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFPresentationClock_Start(clock, 0); + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 0, "Unexpected number of samples requested %d\n", samples_requested); + /* test sample received in the paused state with no samples queued */ + hr = IMFClockStateSink_OnClockPause(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + sample_pts = 0; + SET_EXPECT(timer_SetTimer); + supply_samples(stream, 4); + todo_wine + CHECK_CALLED(timer_SetTimer); + + hr = IMFClockStateSink_OnClockRestart(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + todo_wine + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* test sample received in the stopped state */ + SET_EXPECT(timer_CancelTimer); + hr = IMFClockStateSink_OnClockStop(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + CHECK_CALLED(timer_CancelTimer); + + supply_samples(stream, 4); + + hr = IMFClockStateSink_OnClockRestart(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* required for the sink to be fully released */ ref = IMFPresentationClock_Release(clock); ok(ref == 2, "Release returned %ld\n", ref); - /* required for the sink to be fully released */ hr = IMFMediaSink_Shutdown(sink); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/mf.c | 122 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 10 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 445cd403090..6a15e77ac41 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4255,6 +4255,9 @@ static struct timer_cancel* create_timer_cancel(void) DEFINE_EXPECT(timer_SetTimer); DEFINE_EXPECT(timer_CancelTimer); +DEFINE_EXPECT(MEStreamSinkMarker); + +static MFTIME sample_pts = 0, expected_pts = 0; struct presentation_clock { @@ -4264,6 +4267,7 @@ struct presentation_clock IMFClockStateSink *sample_grabber_clock_state_sink; IMFAsyncResult *callback_result; IUnknown *cancel_key; + HANDLE set_timer_event; }; static struct presentation_clock* impl_from_IMFTimer(IMFTimer *iface) @@ -4297,10 +4301,11 @@ static HRESULT WINAPI timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time HRESULT hr; CHECK_EXPECT(timer_SetTimer); + SetEvent(pc->set_timer_event); ok(flags == 0, "Unexpected flags value %#lx\n", flags); - ok(time == 0, "Unexpected time value %I64d\n", time); - ok(pc->callback_result == NULL, "Unexpected callback value %p\n", pc->callback_result); + ok(time == expected_pts, "Unexpected time value %I64d\n", time); + ok(pc->callback_result == NULL, "Unexpected callback result value %p\n", pc->callback_result); ok(pc->cancel_key == NULL, "Unexpected cancel key %p\n", pc->cancel_key); hr = MFCreateAsyncResult(NULL, callback, state, &pc->callback_result); @@ -4321,6 +4326,7 @@ static HRESULT WINAPI timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key) ok(cancel_key == pc->cancel_key, "Unexpected cancel key %p\n", cancel_key); IMFAsyncResult_Release(pc->callback_result); + pc->callback_result = NULL; pc->cancel_key = NULL; @@ -4382,6 +4388,7 @@ static WINAPI ULONG presentation_clock_Release(IMFPresentationClock *iface) IMFClockStateSink_Release(pc->sample_grabber_clock_state_sink); if (pc->callback_result) IMFAsyncResult_Release(pc->callback_result); + CloseHandle(pc->set_timer_event); free(pc); } @@ -4499,12 +4506,11 @@ static struct presentation_clock* create_presentation_clock(void) pc->IMFPresentationClock_iface.lpVtbl = &MFPresentationClockVtbl; pc->IMFTimer_iface.lpVtbl = &MFTimerVtbl; pc->refcount = 1; + pc->set_timer_event = CreateEventW(NULL, FALSE, FALSE, NULL); return pc; } -static MFTIME sample_pts = 0; - static void supply_samples(IMFStreamSink *stream, int num_samples) { @@ -4558,25 +4564,64 @@ static int count_samples_requested(IMFStreamSink *stream) samples_requested++; else if (met == MEStreamSinkStarted) break; + else if (met == MEStreamSinkMarker) + { + CHECK_EXPECT(MEStreamSinkMarker); + break; + } } return samples_requested; } +#define trigger_timer(mock_clock) _trigger_timer(__LINE__, mock_clock) + +static HRESULT _trigger_timer(int line, struct presentation_clock *mock_clock) +{ + HRESULT hr = E_FAIL; + + mock_clock->cancel_key = NULL; + + ok_(__FILE__, line)(!!mock_clock->callback_result, "Expected callback result to be set\n"); + + if (mock_clock->callback_result) + { + hr = MFInvokeCallback(mock_clock->callback_result); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFAsyncResult_Release(mock_clock->callback_result); + mock_clock->callback_result = NULL; + } + + return hr; +} + static void test_sample_grabber_seek(void) { - IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); + struct test_grabber_callback *grabber_callback_impl; + IMFSampleGrabberSinkCallback *grabber_callback; struct presentation_clock *mock_clock; IMFClockStateSink *clock_sink; IMFPresentationClock *clock; + IMFAsyncCallback *callback; IMFMediaType *media_type; IMFStreamSink *stream; IMFActivate *activate; int samples_requested; + PROPVARIANT propvar; IMFMediaSink *sink; HRESULT hr; ULONG ref; + PropVariantInit(&propvar); + callback = create_test_callback(TRUE); + + grabber_callback = create_test_grabber_callback(); + grabber_callback_impl = impl_from_IMFSampleGrabberSinkCallback(grabber_callback); + grabber_callback_impl->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!grabber_callback_impl->ready_event, "CreateEventW failed, error %lu\n", GetLastError()); + grabber_callback_impl->done_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!grabber_callback_impl->done_event, "CreateEventW failed, error %lu\n", GetLastError()); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); @@ -4642,9 +4687,31 @@ static void test_sample_grabber_seek(void) /* test number of new sample requests on seek when in running state and 3 samples have been provided */ sample_pts = 0; SET_EXPECT(timer_SetTimer); - supply_samples(stream, 3); + supply_samples(stream, 2); todo_wine CHECK_CALLED(timer_SetTimer); + /* this marker gets silently discarded on the next seek */ + hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_DEFAULT, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + supply_samples(stream, 1); + + ok(!!mock_clock->callback_result, "Expected callback result to be set\n"); + hr = trigger_timer(mock_clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = WaitForSingleObject(grabber_callback_impl->ready_event, 1000); + ok(hr == WAIT_OBJECT_0, "Unexpected hr %#lx.\n", hr); + + expected_pts = 41667; + ResetEvent(mock_clock->set_timer_event); + SET_EXPECT(timer_SetTimer); + SetEvent(grabber_callback_impl->done_event); + hr = gen_wait_media_event((IMFMediaEventGenerator*)stream, callback, MEStreamSinkRequestSample, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&propvar); + hr = WaitForSingleObject(mock_clock->set_timer_event, 1000); + ok(hr == WAIT_OBJECT_0, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(timer_SetTimer); SET_EXPECT(timer_CancelTimer); hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); @@ -4654,7 +4721,7 @@ static void test_sample_grabber_seek(void) samples_requested = count_samples_requested(stream); todo_wine - ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); + ok(samples_requested == 2, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst stopped */ hr = IMFClockStateSink_OnClockStop(clock_sink, 0); @@ -4667,11 +4734,43 @@ static void test_sample_grabber_seek(void) ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst paused and 3 samples provided */ - sample_pts = 0; + sample_pts = expected_pts = 0; SET_EXPECT(timer_SetTimer); - supply_samples(stream, 3); + supply_samples(stream, 1); todo_wine CHECK_CALLED(timer_SetTimer); + hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_DEFAULT, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + supply_samples(stream, 2); + + todo_wine + hr = trigger_timer(mock_clock); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = WaitForSingleObject(grabber_callback_impl->ready_event, 1000); + todo_wine + ok(hr == WAIT_OBJECT_0, "Unexpected hr %#lx.\n", hr); + + if (hr == WAIT_OBJECT_0) + { + expected_pts = 41667; + ResetEvent(mock_clock->set_timer_event); + SET_EXPECT(timer_SetTimer); + SetEvent(grabber_callback_impl->done_event); + + SET_EXPECT(MEStreamSinkMarker); + samples_requested = count_samples_requested(stream); + ok(samples_requested == 1, "Unexpected number of samples requested %d\n", samples_requested); + hr = WaitForSingleObject(mock_clock->set_timer_event, 1000); + ok(hr == WAIT_OBJECT_0, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(MEStreamSinkMarker); + CHECK_CALLED(timer_SetTimer); + } + else + { + skip("skipping MEStreamSinkMarker test\n"); + } hr = IMFClockStateSink_OnClockPause(clock_sink, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -4701,7 +4800,7 @@ static void test_sample_grabber_seek(void) hr = IMFClockStateSink_OnClockPause(clock_sink, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - sample_pts = 0; + expected_pts = sample_pts; SET_EXPECT(timer_SetTimer); supply_samples(stream, 4); todo_wine @@ -4740,6 +4839,9 @@ static void test_sample_grabber_seek(void) todo_wine ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFAsyncCallback_Release(callback); + ok(ref == 0, "Release returned %ld\n", ref); + hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/mf.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 6a15e77ac41..ecab3814192 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4300,12 +4300,16 @@ static HRESULT WINAPI timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time struct timer_cancel *tc; HRESULT hr; + todo_wine_if(time == 83334) CHECK_EXPECT(timer_SetTimer); SetEvent(pc->set_timer_event); ok(flags == 0, "Unexpected flags value %#lx\n", flags); + todo_wine_if(time == 83334) ok(time == expected_pts, "Unexpected time value %I64d\n", time); + todo_wine_if(time == 83334) ok(pc->callback_result == NULL, "Unexpected callback result value %p\n", pc->callback_result); + todo_wine_if(time == 83334) ok(pc->cancel_key == NULL, "Unexpected cancel key %p\n", pc->cancel_key); hr = MFCreateAsyncResult(NULL, callback, state, &pc->callback_result); @@ -4566,6 +4570,7 @@ static int count_samples_requested(IMFStreamSink *stream) break; else if (met == MEStreamSinkMarker) { + todo_wine CHECK_EXPECT(MEStreamSinkMarker); break; } @@ -4723,6 +4728,30 @@ static void test_sample_grabber_seek(void) todo_wine ok(samples_requested == 2, "Unexpected number of samples requested %d\n", samples_requested); + /* test number of new sample requests after a flush then seek */ + sample_pts = expected_pts = 0; + SET_EXPECT(timer_SetTimer); + supply_samples(stream, 2); + todo_wine + CHECK_CALLED(timer_SetTimer); + + /* there is no cancel timer, or sample requests during a flush */ + hr = IMFStreamSink_Flush(stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + supply_samples(stream, 1); + + /* only on seek */ + SET_EXPECT(timer_CancelTimer); + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + CHECK_CALLED(timer_CancelTimer); + + samples_requested = count_samples_requested(stream); + todo_wine + ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); + /* test number of new sample requests on seek whilst stopped */ hr = IMFClockStateSink_OnClockStop(clock_sink, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -4731,13 +4760,13 @@ static void test_sample_grabber_seek(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); + todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst paused and 3 samples provided */ sample_pts = expected_pts = 0; SET_EXPECT(timer_SetTimer); supply_samples(stream, 1); - todo_wine CHECK_CALLED(timer_SetTimer); hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_DEFAULT, NULL, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -4794,6 +4823,7 @@ static void test_sample_grabber_seek(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); + todo_wine ok(samples_requested == 0, "Unexpected number of samples requested %d\n", samples_requested); /* test sample received in the paused state with no samples queued */ @@ -4826,6 +4856,7 @@ static void test_sample_grabber_seek(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); + todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* required for the sink to be fully released */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/mf.c | 241 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 234 insertions(+), 7 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index ecab3814192..9181eed0753 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3105,6 +3105,8 @@ static void test_media_session_rate_control(void) ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); } +DEFINE_EXPECT(OnProcessSample); + struct test_grabber_callback { IMFSampleGrabberSinkCallback IMFSampleGrabberSinkCallback_iface; @@ -3113,6 +3115,8 @@ struct test_grabber_callback IMFCollection *samples; HANDLE ready_event; HANDLE done_event; + + BOOL do_event; }; static struct test_grabber_callback *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface) @@ -3204,7 +3208,7 @@ static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSink return S_OK; } - if (!grabber->ready_event) + if (!grabber->ready_event && grabber->do_event) return E_NOTIMPL; sample = create_sample(buffer, sample_size); @@ -3218,9 +3222,16 @@ static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSink IMFCollection_AddElement(grabber->samples, (IUnknown *)sample); IMFSample_Release(sample); - SetEvent(grabber->ready_event); - res = WaitForSingleObject(grabber->done_event, 1000); - ok(!res, "WaitForSingleObject returned %#lx\n", res); + if (grabber->do_event) + { + SetEvent(grabber->ready_event); + res = WaitForSingleObject(grabber->done_event, 1000); + ok(!res, "WaitForSingleObject returned %#lx\n", res); + } + else + { + CHECK_EXPECT2(OnProcessSample); + } return S_OK; } @@ -3257,6 +3268,7 @@ static IMFSampleGrabberSinkCallback *create_test_grabber_callback(void) grabber->refcount = 1; hr = MFCreateCollection(&grabber->samples); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + grabber->do_event = TRUE; return &grabber->IMFSampleGrabberSinkCallback_iface; } @@ -4550,7 +4562,10 @@ static void supply_samples(IMFStreamSink *stream, int num_samples) } } -static int count_samples_requested(IMFStreamSink *stream) +static BOOL ignore_clock = FALSE; + +#define count_samples_requested(stream) _count_samples_requested(__LINE__, stream) +static int _count_samples_requested(int line, IMFStreamSink *stream) { int samples_requested; IMFMediaEvent *event; @@ -4561,16 +4576,19 @@ static int count_samples_requested(IMFStreamSink *stream) while (IMFStreamSink_GetEvent(stream, 0, &event) == S_OK) { hr = IMFMediaEvent_GetType(event, &met); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFMediaEvent_Release(event); if (met == MEStreamSinkRequestSample) samples_requested++; else if (met == MEStreamSinkStarted) + { + ok_(__FILE__, line)(!expect_MEStreamSinkMarker, "Expected MEStreamSinkMarker, got MEStreamSinkStarted\n"); break; + } else if (met == MEStreamSinkMarker) { - todo_wine + todo_wine_if(!ignore_clock) CHECK_EXPECT(MEStreamSinkMarker); break; } @@ -4870,6 +4888,215 @@ static void test_sample_grabber_seek(void) todo_wine ok(ref == 0, "Release returned %ld\n", ref); + /* test with MF_SAMPLEGRABBERSINK_IGNORE_CLOCK */ + + ignore_clock = TRUE; + grabber_callback = create_test_grabber_callback(); + grabber_callback_impl = impl_from_IMFSampleGrabberSinkCallback(grabber_callback); + grabber_callback_impl->do_event = FALSE; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + + EXPECT_REF(media_type, 1); + hr = MFCreateSampleGrabberSinkActivate(media_type, grabber_callback, &activate); + ok(hr == S_OK, "Failed to create grabber activate, hr %#lx.\n", hr); + EXPECT_REF(media_type, 2); + + hr = IMFActivate_SetUINT32(activate, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + ref = IMFMediaType_Release(media_type); + ok(ref == 1, "Release returned %ld\n", ref); + + hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&sink); + ok(hr == S_OK, "Failed to activate object, hr %#lx.\n", hr); + + ref = IMFActivate_Release(activate); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream); + ok(hr == S_OK, "Failed to get sink stream, hr %#lx.\n", hr); + + + /* Set clock. */ + mock_clock = create_presentation_clock(); + clock = &mock_clock->IMFPresentationClock_iface; + + hr = IMFMediaSink_SetPresentationClock(sink, clock); + ok(hr == S_OK, "Failed to set presentation clock, hr %#lx.\n", hr); + ok(!!mock_clock->sample_grabber_clock_state_sink, "AddClockStateSink not called\n"); + clock_sink = mock_clock->sample_grabber_clock_state_sink; + + + /* test number of new sample requests on clock start */ + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek when in running state and 4 samples have been provided */ + sample_pts = 0; + SET_EXPECT(OnProcessSample); + supply_samples(stream, 4); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek when in running state and 3 samples have been provided */ + sample_pts = 0; + SET_EXPECT(OnProcessSample); + supply_samples(stream, 2); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_DEFAULT, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + SET_EXPECT(OnProcessSample); + supply_samples(stream, 1); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SET_EXPECT(MEStreamSinkMarker); + samples_requested = count_samples_requested(stream); + ok(samples_requested == 2, "Unexpected number of samples requested %d\n", samples_requested); + CHECK_CALLED(MEStreamSinkMarker); + CLEAR_CALLED(OnProcessSample); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 1, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests after a flush then seek */ + sample_pts = expected_pts = 0; + SET_EXPECT(OnProcessSample); + supply_samples(stream, 2); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + + /* there is no cancel timer, or sample requests during a flush */ + hr = IMFStreamSink_Flush(stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SET_EXPECT(OnProcessSample); + supply_samples(stream, 1); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + + /* only on seek */ + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek whilst stopped */ + hr = IMFClockStateSink_OnClockStop(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek whilst paused and 3 samples provided */ + sample_pts = expected_pts = 0; + SET_EXPECT(OnProcessSample); + supply_samples(stream, 3); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_DEFAULT, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + SET_EXPECT(OnProcessSample); + supply_samples(stream, 2); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + + SET_EXPECT(MEStreamSinkMarker); + samples_requested = count_samples_requested(stream); + ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); + CHECK_CALLED(MEStreamSinkMarker); + + hr = IMFClockStateSink_OnClockPause(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* test over supply */ + SET_EXPECT(OnProcessSample); + supply_samples(stream, 6); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 8, "Unexpected number of samples requested %d\n", samples_requested); + + /* test number of new sample requests on seek whilst paused and no samples provided */ + hr = IMFClockStateSink_OnClockPause(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 0, "Unexpected number of samples requested %d\n", samples_requested); + + /* test sample received in the paused state with no samples queued */ + hr = IMFClockStateSink_OnClockPause(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + expected_pts = sample_pts; + SET_EXPECT(OnProcessSample); + supply_samples(stream, 4); + CHECK_CALLED(OnProcessSample); + CLEAR_CALLED(OnProcessSample); + + hr = IMFClockStateSink_OnClockRestart(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + /* test sample received in the stopped state */ + hr = IMFClockStateSink_OnClockStop(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + supply_samples(stream, 4); + + hr = IMFClockStateSink_OnClockRestart(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + + ref = IMFPresentationClock_Release(clock); + ok(ref == 2, "Release returned %ld\n", ref); + + /* required for the sink to be fully released */ + hr = IMFMediaSink_Shutdown(sink); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + ref = IMFMediaSink_Release(sink); + todo_wine + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFAsyncCallback_Release(callback); ok(ref == 0, "Release returned %ld\n", ref); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/mf.c | 87 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 9181eed0753..7c40ad15a38 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3117,6 +3117,7 @@ struct test_grabber_callback HANDLE done_event; BOOL do_event; + BOOL need_sample_time; }; static struct test_grabber_callback *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface) @@ -3215,7 +3216,7 @@ static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSink hr = IMFSample_SetSampleFlags(sample, sample_flags); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); /* FIXME: sample time is inconsistent across windows versions, ignore it */ - hr = IMFSample_SetSampleTime(sample, 0); + hr = IMFSample_SetSampleTime(sample, grabber->need_sample_time ? sample_time : 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFSample_SetSampleDuration(sample, sample_duration); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -4632,8 +4633,47 @@ static void test_sample_grabber_seek(void) int samples_requested; PROPVARIANT propvar; IMFMediaSink *sink; + IMFSample *sample; + LONGLONG pts; + DWORD count; HRESULT hr; ULONG ref; + int i; + + static const LONGLONG use_clock_samples[] = + { + 0, + 0 + }; + + static const LONGLONG ignore_clock_samples[] = + { + 0, + 41667, + 83334, + 125001, + 0, + 41667, + 83334, + 0, + 41667, + 83334, + 0, + 41667, + 83334, + 125001, + 166668, + 208335, + 250002, + 291669, + 333336, + 375003, + 416670, + 458337, + 500004, + 541671, + 583338, + }; PropVariantInit(&propvar); callback = create_test_callback(TRUE); @@ -4644,6 +4684,7 @@ static void test_sample_grabber_seek(void) ok(!!grabber_callback_impl->ready_event, "CreateEventW failed, error %lu\n", GetLastError()); grabber_callback_impl->done_event = CreateEventW(NULL, FALSE, FALSE, NULL); ok(!!grabber_callback_impl->done_event, "CreateEventW failed, error %lu\n", GetLastError()); + grabber_callback_impl->need_sample_time = TRUE; hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); @@ -4877,6 +4918,29 @@ static void test_sample_grabber_seek(void) todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + /* check contents of collection */ + hr = IMFCollection_GetElementCount(grabber_callback_impl->samples, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(count == ARRAY_SIZE(use_clock_samples), "Unexpected total of samples delivered %ld\n", count); + + for (i = 0; i < ARRAY_SIZE(use_clock_samples); i++) + { + hr = IMFCollection_GetElement(grabber_callback_impl->samples, i, (IUnknown**)&sample); + todo_wine_if(i) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (hr == S_OK) + { + hr = IMFSample_GetSampleTime(sample, &pts); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(pts == use_clock_samples[i], "%d: Unexpected pts %I64d, expected %I64d\n", i, pts, use_clock_samples[i]); + + ref = IMFSample_Release(sample); + ok(ref == 1, "Release returned %ld\n", ref); + } + } + /* required for the sink to be fully released */ ref = IMFPresentationClock_Release(clock); ok(ref == 2, "Release returned %ld\n", ref); @@ -4894,6 +4958,7 @@ static void test_sample_grabber_seek(void) grabber_callback = create_test_grabber_callback(); grabber_callback_impl = impl_from_IMFSampleGrabberSinkCallback(grabber_callback); grabber_callback_impl->do_event = FALSE; + grabber_callback_impl->need_sample_time = TRUE; hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); @@ -5086,10 +5151,28 @@ static void test_sample_grabber_seek(void) samples_requested = count_samples_requested(stream); ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); + /* check contents of collection */ + hr = IMFCollection_GetElementCount(grabber_callback_impl->samples, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(count == ARRAY_SIZE(ignore_clock_samples), "Unexpected total of samples delivered %ld\n", count); + + for (i = 0; i < ARRAY_SIZE(ignore_clock_samples); i++) + { + hr = IMFCollection_GetElement(grabber_callback_impl->samples, i, (IUnknown**)&sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFSample_GetSampleTime(sample, &pts); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(pts == ignore_clock_samples[i], "%d: Unexpected pts %I64d, expected %I64d\n", i, pts, ignore_clock_samples[i]); + + ref = IMFSample_Release(sample); + ok(ref == 1, "Release returned %ld\n", ref); + } + + /* required for the sink to be fully released */ ref = IMFPresentationClock_Release(clock); ok(ref == 2, "Release returned %ld\n", ref); - /* required for the sink to be fully released */ hr = IMFMediaSink_Shutdown(sink); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/tests/mf.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 7c40ad15a38..4d495681fe6 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4902,13 +4902,33 @@ static void test_sample_grabber_seek(void) todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); - /* test sample received in the stopped state */ + /* test pause and resume with 4 samples queued */ + hr = IMFClockStateSink_OnClockPause(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFClockStateSink_OnClockRestart(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + samples_requested = count_samples_requested(stream); + ok(samples_requested == 0, "Unexpected number of samples requested %d\n", samples_requested); + + /* test pause and seek with 4 samples queued */ + hr = IMFClockStateSink_OnClockPause(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + SET_EXPECT(timer_CancelTimer); - hr = IMFClockStateSink_OnClockStop(clock_sink, 0); + hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234567); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); todo_wine CHECK_CALLED(timer_CancelTimer); + samples_requested = count_samples_requested(stream); + ok(samples_requested == 0, "Unexpected number of samples requested %d\n", samples_requested); + + /* test sample received in the stopped state */ + hr = IMFClockStateSink_OnClockStop(clock_sink, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + supply_samples(stream, 4); hr = IMFClockStateSink_OnClockRestart(clock_sink, 0); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> Testing on Windows seems to show a Flush on the sample grabber doesn't actually flush. --- dlls/mf/samplegrabber.c | 12 ------------ dlls/mf/tests/mf.c | 8 +------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index a8c797f25ed..3a1c53968db 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -520,7 +520,6 @@ static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MF static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface) { struct sample_grabber *grabber = impl_from_IMFStreamSink(iface); - struct scheduled_item *item, *next_item; HRESULT hr = S_OK; TRACE("%p.\n", iface); @@ -529,17 +528,6 @@ static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface) if (grabber->is_shut_down) hr = MF_E_STREAMSINK_REMOVED; - else - { - LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry) - { - /* Samples are discarded, markers are processed immediately. */ - if (item->type == ITEM_TYPE_MARKER) - sample_grabber_stream_report_marker(grabber, &item->u.marker.context, E_ABORT); - - stream_release_pending_item(item); - } - } LeaveCriticalSection(&grabber->cs); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 4d495681fe6..8a02212790b 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4313,16 +4313,12 @@ static HRESULT WINAPI timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time struct timer_cancel *tc; HRESULT hr; - todo_wine_if(time == 83334) CHECK_EXPECT(timer_SetTimer); SetEvent(pc->set_timer_event); ok(flags == 0, "Unexpected flags value %#lx\n", flags); - todo_wine_if(time == 83334) ok(time == expected_pts, "Unexpected time value %I64d\n", time); - todo_wine_if(time == 83334) ok(pc->callback_result == NULL, "Unexpected callback result value %p\n", pc->callback_result); - todo_wine_if(time == 83334) ok(pc->cancel_key == NULL, "Unexpected cancel key %p\n", pc->cancel_key); hr = MFCreateAsyncResult(NULL, callback, state, &pc->callback_result); @@ -4819,13 +4815,13 @@ static void test_sample_grabber_seek(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst paused and 3 samples provided */ sample_pts = expected_pts = 0; SET_EXPECT(timer_SetTimer); supply_samples(stream, 1); + todo_wine CHECK_CALLED(timer_SetTimer); hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_DEFAULT, NULL, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -4882,7 +4878,6 @@ static void test_sample_grabber_seek(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 0, "Unexpected number of samples requested %d\n", samples_requested); /* test sample received in the paused state with no samples queued */ @@ -4935,7 +4930,6 @@ static void test_sample_grabber_seek(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* check contents of collection */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/samplegrabber.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 3a1c53968db..160125e5910 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -91,6 +91,7 @@ struct sample_grabber CRITICAL_SECTION cs; UINT32 sample_count; IMFSample *samples[MAX_SAMPLE_QUEUE_LENGTH]; + byte samples_queued; }; static IMFSampleGrabberSinkCallback *sample_grabber_get_callback(const struct sample_grabber *sink) @@ -187,13 +188,14 @@ static ULONG WINAPI sample_grabber_stream_AddRef(IMFStreamSink *iface) return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface); } -static void stream_release_pending_item(struct scheduled_item *item) +static void stream_release_pending_item(struct sample_grabber *grabber, struct scheduled_item *item) { list_remove(&item->entry); switch (item->type) { case ITEM_TYPE_SAMPLE: IMFSample_Release(item->u.sample); + grabber->samples_queued--; break; case ITEM_TYPE_MARKER: PropVariantClear(&item->u.marker.context); @@ -398,13 +400,13 @@ static HRESULT stream_queue_sample(struct sample_grabber *grabber, IMFSample *sa item->u.sample = sample; IMFSample_AddRef(item->u.sample); list_init(&item->entry); - if (list_empty(&grabber->items)) + if (!grabber->samples_queued++) hr = stream_schedule_sample(grabber, item); if (SUCCEEDED(hr)) list_add_tail(&grabber->items, &item->entry); else - stream_release_pending_item(item); + stream_release_pending_item(grabber, item); return hr; } @@ -492,7 +494,7 @@ static HRESULT stream_place_marker(struct sample_grabber *grabber, MFSTREAMSINK_ if (SUCCEEDED(hr)) list_add_tail(&grabber->items, &item->entry); else - stream_release_pending_item(item); + stream_release_pending_item(grabber, item); return hr; } @@ -749,7 +751,7 @@ static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallba if (item->type == ITEM_TYPE_MARKER) { sample_grabber_stream_report_marker(grabber, &item->u.marker.context, S_OK); - stream_release_pending_item(item); + stream_release_pending_item(grabber, item); } else if (item->type == ITEM_TYPE_SAMPLE) { @@ -757,7 +759,7 @@ static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallba { if (FAILED(hr = sample_grabber_report_sample(grabber, item->u.sample, &sample_delivered))) WARN("Failed to report a sample, hr %#lx.\n", hr); - stream_release_pending_item(item); + stream_release_pending_item(grabber, item); sample_reported = TRUE; } else @@ -840,7 +842,7 @@ static void sample_grabber_release_pending_items(struct sample_grabber *grabber) LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry) { - stream_release_pending_item(item); + stream_release_pending_item(grabber, item); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> --- dlls/mf/samplegrabber.c | 10 +--------- dlls/mf/tests/mf.c | 1 + 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 160125e5910..88da642b25e 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -432,7 +432,7 @@ static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, if (grabber->is_shut_down) hr = MF_E_STREAMSINK_REMOVED; - else if (grabber->state == SINK_STATE_RUNNING || (grabber->state == SINK_STATE_PAUSED && grabber->ignore_clock)) + else if (grabber->state != SINK_STATE_STOPPED) { hr = IMFSample_GetSampleTime(sample, &sampletime); @@ -450,14 +450,6 @@ static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, hr = stream_queue_sample(grabber, sample); } } - else if (grabber->state == SINK_STATE_PAUSED) - { - if (grabber->sample_count < MAX_SAMPLE_QUEUE_LENGTH) - { - IMFSample_AddRef(sample); - grabber->samples[grabber->sample_count++] = sample; - } - } LeaveCriticalSection(&grabber->cs); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 8a02212790b..6089e4e77d6 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4868,6 +4868,7 @@ static void test_sample_grabber_seek(void) CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); + todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst paused and no samples provided */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> The total of: 1. unsatisfied sample requests made to MF; plus 2. samples queued (i.e. satisfied requests) should always equal 4. Thus, for example, if we flush 3 samples, we need to request 3 more. The stop state appears to flush all samples from sample grabber and all requests outstanding with MF. Hence, starting playback from the stop state always makes four new sample requests. Pause and resume always makes four new sample requests, but will also not flush the queue. This appears to be a Windows bug, as looping pause and resume can therefore result in samples being queued until we are OOM. --- dlls/mf/samplegrabber.c | 37 ++++++++++++----------- dlls/mf/tests/mf.c | 65 +++++++++++------------------------------ 2 files changed, 37 insertions(+), 65 deletions(-) diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 88da642b25e..4fc7428b4b7 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -91,7 +91,8 @@ struct sample_grabber CRITICAL_SECTION cs; UINT32 sample_count; IMFSample *samples[MAX_SAMPLE_QUEUE_LENGTH]; - byte samples_queued; + UINT64 samples_queued; + BYTE pending_sample_deliveries; }; static IMFSampleGrabberSinkCallback *sample_grabber_get_callback(const struct sample_grabber *sink) @@ -414,12 +415,13 @@ static HRESULT stream_queue_sample(struct sample_grabber *grabber, IMFSample *sa static void sample_grabber_stream_request_sample(struct sample_grabber *grabber) { IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL); + grabber->pending_sample_deliveries++; } static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample) { struct sample_grabber *grabber = impl_from_IMFStreamSink(iface); - BOOL sample_delivered; + BOOL sample_delivered = FALSE; LONGLONG sampletime; HRESULT hr = S_OK; @@ -434,6 +436,9 @@ static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, hr = MF_E_STREAMSINK_REMOVED; else if (grabber->state != SINK_STATE_STOPPED) { + if (grabber->pending_sample_deliveries) + grabber->pending_sample_deliveries--; + hr = IMFSample_GetSampleTime(sample, &sampletime); if (SUCCEEDED(hr)) @@ -1157,6 +1162,7 @@ static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sin [SINK_STATE_RUNNING] = MEStreamSinkStarted, }; BOOL do_callback = FALSE; + byte required_requests; HRESULT hr = S_OK; unsigned int i; @@ -1173,25 +1179,22 @@ static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sin sample_grabber_cancel_timer(grabber); release_samples(grabber); grabber->sample_count = MAX_SAMPLE_QUEUE_LENGTH; + sample_grabber_release_pending_items(grabber); + grabber->pending_sample_deliveries = 0; } - - if (state == SINK_STATE_RUNNING && grabber->state != SINK_STATE_RUNNING) + else if (state == SINK_STATE_RUNNING && + (grabber->state != SINK_STATE_RUNNING || offset != PRESENTATION_CURRENT_POSITION)) { - /* Every transition to running state sends a bunch requests to build up initial queue. */ - for (i = 0; i < grabber->sample_count; ++i) + if (offset != PRESENTATION_CURRENT_POSITION) { - if (grabber->state == SINK_STATE_PAUSED && offset == PRESENTATION_CURRENT_POSITION) - { - assert(grabber->samples[i]); - stream_queue_sample(grabber, grabber->samples[i]); - } - else - { - sample_grabber_stream_request_sample(grabber); - } + sample_grabber_cancel_timer(grabber); + sample_grabber_release_pending_items(grabber); } - release_samples(grabber); - grabber->sample_count = 0; + + required_requests = MAX_SAMPLE_QUEUE_LENGTH - grabber->pending_sample_deliveries; + + for (i = 0; i < required_requests; i++) + sample_grabber_stream_request_sample(grabber); } do_callback = state != grabber->state || state != SINK_STATE_PAUSED; diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 6089e4e77d6..5b5cec7f44e 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4334,7 +4334,6 @@ static HRESULT WINAPI timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key) { struct presentation_clock* pc = impl_from_IMFTimer(iface); - todo_wine CHECK_EXPECT(timer_CancelTimer); ok(cancel_key == pc->cancel_key, "Unexpected cancel key %p\n", cancel_key); @@ -4559,8 +4558,6 @@ static void supply_samples(IMFStreamSink *stream, int num_samples) } } -static BOOL ignore_clock = FALSE; - #define count_samples_requested(stream) _count_samples_requested(__LINE__, stream) static int _count_samples_requested(int line, IMFStreamSink *stream) { @@ -4585,7 +4582,6 @@ static int _count_samples_requested(int line, IMFStreamSink *stream) } else if (met == MEStreamSinkMarker) { - todo_wine_if(!ignore_clock) CHECK_EXPECT(MEStreamSinkMarker); break; } @@ -4737,18 +4733,15 @@ static void test_sample_grabber_seek(void) SET_EXPECT(timer_CancelTimer); hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek when in running state and 3 samples have been provided */ sample_pts = 0; SET_EXPECT(timer_SetTimer); supply_samples(stream, 2); - todo_wine CHECK_CALLED(timer_SetTimer); /* this marker gets silently discarded on the next seek */ hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_DEFAULT, NULL, NULL); @@ -4776,18 +4769,15 @@ static void test_sample_grabber_seek(void) SET_EXPECT(timer_CancelTimer); hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 2, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests after a flush then seek */ sample_pts = expected_pts = 0; SET_EXPECT(timer_SetTimer); supply_samples(stream, 2); - todo_wine CHECK_CALLED(timer_SetTimer); /* there is no cancel timer, or sample requests during a flush */ @@ -4800,11 +4790,9 @@ static void test_sample_grabber_seek(void) SET_EXPECT(timer_CancelTimer); hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 3, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst stopped */ @@ -4821,40 +4809,30 @@ static void test_sample_grabber_seek(void) sample_pts = expected_pts = 0; SET_EXPECT(timer_SetTimer); supply_samples(stream, 1); - todo_wine CHECK_CALLED(timer_SetTimer); hr = IMFStreamSink_PlaceMarker(stream, MFSTREAMSINK_MARKER_DEFAULT, NULL, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); supply_samples(stream, 2); - todo_wine hr = trigger_timer(mock_clock); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = WaitForSingleObject(grabber_callback_impl->ready_event, 1000); - todo_wine ok(hr == WAIT_OBJECT_0, "Unexpected hr %#lx.\n", hr); - if (hr == WAIT_OBJECT_0) - { - expected_pts = 41667; - ResetEvent(mock_clock->set_timer_event); - SET_EXPECT(timer_SetTimer); - SetEvent(grabber_callback_impl->done_event); + expected_pts = 41667; + ResetEvent(mock_clock->set_timer_event); + SET_EXPECT(timer_SetTimer); + SetEvent(grabber_callback_impl->done_event); - SET_EXPECT(MEStreamSinkMarker); - samples_requested = count_samples_requested(stream); - ok(samples_requested == 1, "Unexpected number of samples requested %d\n", samples_requested); - hr = WaitForSingleObject(mock_clock->set_timer_event, 1000); - ok(hr == WAIT_OBJECT_0, "Unexpected hr %#lx.\n", hr); - CHECK_CALLED(MEStreamSinkMarker); - CHECK_CALLED(timer_SetTimer); - } - else - { - skip("skipping MEStreamSinkMarker test\n"); - } + SET_EXPECT(MEStreamSinkMarker); + samples_requested = count_samples_requested(stream); + todo_wine + ok(samples_requested == 1, "Unexpected number of samples requested %d\n", samples_requested); + hr = WaitForSingleObject(mock_clock->set_timer_event, 1000); + ok(hr == WAIT_OBJECT_0, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(MEStreamSinkMarker); + CHECK_CALLED(timer_SetTimer); hr = IMFClockStateSink_OnClockPause(clock_sink, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -4888,14 +4866,12 @@ static void test_sample_grabber_seek(void) expected_pts = sample_pts; SET_EXPECT(timer_SetTimer); supply_samples(stream, 4); - todo_wine CHECK_CALLED(timer_SetTimer); hr = IMFClockStateSink_OnClockRestart(clock_sink, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test pause and resume with 4 samples queued */ @@ -4915,7 +4891,6 @@ static void test_sample_grabber_seek(void) SET_EXPECT(timer_CancelTimer); hr = IMFClockStateSink_OnClockStart(clock_sink, 0, 1234567); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); @@ -4936,24 +4911,19 @@ static void test_sample_grabber_seek(void) /* check contents of collection */ hr = IMFCollection_GetElementCount(grabber_callback_impl->samples, &count); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(count == ARRAY_SIZE(use_clock_samples), "Unexpected total of samples delivered %ld\n", count); for (i = 0; i < ARRAY_SIZE(use_clock_samples); i++) { hr = IMFCollection_GetElement(grabber_callback_impl->samples, i, (IUnknown**)&sample); - todo_wine_if(i) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - hr = IMFSample_GetSampleTime(sample, &pts); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(pts == use_clock_samples[i], "%d: Unexpected pts %I64d, expected %I64d\n", i, pts, use_clock_samples[i]); + hr = IMFSample_GetSampleTime(sample, &pts); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(pts == use_clock_samples[i], "%d: Unexpected pts %I64d, expected %I64d\n", i, pts, use_clock_samples[i]); - ref = IMFSample_Release(sample); - ok(ref == 1, "Release returned %ld\n", ref); - } + ref = IMFSample_Release(sample); + ok(ref == 1, "Release returned %ld\n", ref); } /* required for the sink to be fully released */ @@ -4969,7 +4939,6 @@ static void test_sample_grabber_seek(void) /* test with MF_SAMPLEGRABBERSINK_IGNORE_CLOCK */ - ignore_clock = TRUE; grabber_callback = create_test_grabber_callback(); grabber_callback_impl = impl_from_IMFSampleGrabberSinkCallback(grabber_callback); grabber_callback_impl->do_event = FALSE; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> All samples are now queued in the 'items' list. --- dlls/mf/samplegrabber.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 4fc7428b4b7..96ddfb63335 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -89,8 +89,6 @@ struct sample_grabber float rate; enum sink_state state; CRITICAL_SECTION cs; - UINT32 sample_count; - IMFSample *samples[MAX_SAMPLE_QUEUE_LENGTH]; UINT64 samples_queued; BYTE pending_sample_deliveries; }; @@ -843,20 +841,6 @@ static void sample_grabber_release_pending_items(struct sample_grabber *grabber) } } -static void release_samples(struct sample_grabber *grabber) -{ - unsigned int i; - - for (i = 0; i < MAX_SAMPLE_QUEUE_LENGTH; ++i) - { - if (grabber->samples[i]) - { - IMFSample_Release(grabber->samples[i]); - grabber->samples[i] = NULL; - } - } -} - static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface) { struct sample_grabber *grabber = impl_from_IMFMediaSink(iface); @@ -889,7 +873,6 @@ static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface) if (grabber->sample_attributes) IMFAttributes_Release(grabber->sample_attributes); sample_grabber_release_pending_items(grabber); - release_samples(grabber); DeleteCriticalSection(&grabber->cs); free(grabber); } @@ -1177,8 +1160,6 @@ static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sin if (state == SINK_STATE_STOPPED) { sample_grabber_cancel_timer(grabber); - release_samples(grabber); - grabber->sample_count = MAX_SAMPLE_QUEUE_LENGTH; sample_grabber_release_pending_items(grabber); grabber->pending_sample_deliveries = 0; } @@ -1502,7 +1483,6 @@ static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *use object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl; object->IMFMediaTypeHandler_iface.lpVtbl = &sample_grabber_stream_type_handler_vtbl; object->timer_callback.lpVtbl = &sample_grabber_stream_timer_callback_vtbl; - object->sample_count = MAX_SAMPLE_QUEUE_LENGTH; object->refcount = 1; object->rate = 1.0f; if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context->callback, &IID_IMFSampleGrabberSinkCallback2, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
From: Brendan McGrath <bmcgrath(a)codeweavers.com> This switches the order of the RequestSample and Marker events to match the order on Windows. --- dlls/mf/samplegrabber.c | 4 ++-- dlls/mf/tests/mf.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 96ddfb63335..750bb13a743 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -756,6 +756,8 @@ static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallba WARN("Failed to report a sample, hr %#lx.\n", hr); stream_release_pending_item(grabber, item); sample_reported = TRUE; + if (sample_delivered) + sample_grabber_stream_request_sample(grabber); } else { @@ -765,8 +767,6 @@ static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallba } } } - if (sample_delivered) - sample_grabber_stream_request_sample(grabber); LeaveCriticalSection(&grabber->cs); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 5b5cec7f44e..73606d9b716 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4827,7 +4827,6 @@ static void test_sample_grabber_seek(void) SET_EXPECT(MEStreamSinkMarker); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 1, "Unexpected number of samples requested %d\n", samples_requested); hr = WaitForSingleObject(mock_clock->set_timer_event, 1000); ok(hr == WAIT_OBJECT_0, "Unexpected hr %#lx.\n", hr); @@ -4846,7 +4845,6 @@ static void test_sample_grabber_seek(void) CHECK_CALLED(timer_CancelTimer); samples_requested = count_samples_requested(stream); - todo_wine ok(samples_requested == 4, "Unexpected number of samples requested %d\n", samples_requested); /* test number of new sample requests on seek whilst paused and no samples provided */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9489
participants (2)
-
Brendan McGrath -
Brendan McGrath (@redmcg)