From: Charlotte Pabst <cpabst(a)codeweavers.com> --- dlls/mfsrcsnk/media_source.c | 68 ++++++++++++++++++++++++++++----- dlls/mfsrcsnk/tests/Makefile.in | 2 +- dlls/mfsrcsnk/tests/mfsrcsnk.c | 52 +++++++++++++++++++------ 3 files changed, 100 insertions(+), 22 deletions(-) diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 0d5dd098db1..947c4bc2305 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -276,6 +276,7 @@ struct media_stream { IMFMediaStream IMFMediaStream_iface; IMFAsyncCallback async_request_iface; + IMFAsyncCallback async_update_thin_iface; LONG refcount; IMFMediaSource *source; @@ -286,6 +287,8 @@ struct media_stream BOOL active; BOOL eos; + BOOL thin; + BOOL pending_thin; }; struct media_source @@ -307,6 +310,7 @@ struct media_source IMFByteStream *stream; WCHAR *url; float rate; + BOOL thin; struct winedmo_demuxer winedmo_demuxer; struct winedmo_stream winedmo_stream; @@ -693,6 +697,18 @@ static HRESULT media_source_send_eos(struct media_source *source, struct media_s return S_OK; } +static void media_stream_update_thin(struct media_stream *stream) +{ + PROPVARIANT param; + if (stream->pending_thin != stream->thin) + { + stream->thin = stream->pending_thin; + param.vt = VT_INT; + param.iVal = stream->thin; + queue_media_event_value(stream->queue, MEStreamThinMode, ¶m); + } +} + static HRESULT media_source_read(struct media_source *source) { IMFSample *sample; @@ -702,18 +718,37 @@ static HRESULT media_source_read(struct media_source *source) if (source->state != SOURCE_RUNNING) return S_OK; - if (FAILED(hr = demuxer_read_sample(source->winedmo_demuxer, &index, &sample)) && hr != MF_E_END_OF_STREAM) + while (SUCCEEDED(hr = demuxer_read_sample(source->winedmo_demuxer, &index, &sample))) { - WARN("Failed to read stream %u data, hr %#lx\n", index, hr); - return hr; + struct media_stream *stream = source->streams[index]; + BOOL thin = stream->pending_thin || stream->thin; + BOOL keyframe; + + if (!thin) + break; + if (FAILED(IMFSample_GetUINT32( sample, &MFSampleExtension_CleanPoint, (UINT32*)&keyframe ))) + keyframe = FALSE; + if (keyframe != stream->pending_thin) + media_stream_update_thin(stream); + if (keyframe) + break; + IMFSample_Release(sample); } if (hr == MF_E_END_OF_STREAM) { for (i = 0; i < source->stream_count; i++) + { + media_stream_update_thin(source->streams[i]); media_source_send_eos(source, source->streams[i]); + } return S_OK; } + else if (FAILED(hr)) + { + WARN("Failed to read stream %u data, hr %#lx\n", index, hr); + return hr; + } if ((hr = media_source_send_sample(source, index, sample)) == S_FALSE) queue_media_source_read(source); @@ -893,6 +928,19 @@ static HRESULT media_stream_async_request(struct media_stream *stream, IMFAsyncR DEFINE_MF_ASYNC_CALLBACK(media_stream, async_request, IMFMediaStream_iface) +static HRESULT media_stream_async_update_thin(struct media_stream *stream, IMFAsyncResult *result) +{ + struct media_source *source = media_source_from_IMFMediaSource(stream->source); + + EnterCriticalSection(&source->cs); + stream->pending_thin = source->thin; + LeaveCriticalSection(&source->cs); + + return S_OK; +} + +DEFINE_MF_ASYNC_CALLBACK(media_stream, async_update_thin, IMFMediaStream_iface) + static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) { struct media_stream *stream = media_stream_from_IMFMediaStream(iface); @@ -909,8 +957,11 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown hr = MF_E_MEDIA_SOURCE_WRONGSTATE; else if (stream->eos) hr = MF_E_END_OF_STREAM; - else + else { + if (stream->pending_thin != source->thin) + MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &stream->async_update_thin_iface, NULL); hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &stream->async_request_iface, token); + } LeaveCriticalSection(&source->cs); @@ -943,6 +994,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor * object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; object->async_request_iface.lpVtbl = &media_stream_async_request_vtbl; + object->async_update_thin_iface.lpVtbl = &media_stream_async_update_thin_vtbl; object->refcount = 1; if (FAILED(hr = MFCreateEventQueue(&object->queue))) @@ -1115,6 +1167,7 @@ static HRESULT media_source_async_setrate(struct media_source *source, IMFAsyncR EnterCriticalSection(&source->cs); source->rate = params->rate; + source->thin = params->thin; LeaveCriticalSection(&source->cs); return IMFMediaEventQueue_QueueEventParamVar(source->queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); @@ -1132,8 +1185,6 @@ static HRESULT WINAPI media_source_IMFRateControl_SetRate(IMFRateControl *iface, if (rate < 0.0f) return MF_E_REVERSE_UNSUPPORTED; - if (thin) - return MF_E_THINNING_UNSUPPORTED; if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) return hr; @@ -1153,11 +1204,10 @@ static HRESULT WINAPI media_source_IMFRateControl_GetRate(IMFRateControl *iface, TRACE("source %p, thin %p, rate %p\n", source, thin, rate); - if (thin) - *thin = FALSE; - EnterCriticalSection(&source->cs); *rate = source->rate; + if (thin) + *thin = source->thin; LeaveCriticalSection(&source->cs); return S_OK; diff --git a/dlls/mfsrcsnk/tests/Makefile.in b/dlls/mfsrcsnk/tests/Makefile.in index 89889d6f723..14a59177549 100644 --- a/dlls/mfsrcsnk/tests/Makefile.in +++ b/dlls/mfsrcsnk/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mfsrcsnk.dll -IMPORTS = ole32 mfsrcsnk mfplat mf uuid mfuuid +IMPORTS = advapi32 ole32 mfsrcsnk mfplat mf uuid mfuuid SOURCES = \ mfsrcsnk.c \ diff --git a/dlls/mfsrcsnk/tests/mfsrcsnk.c b/dlls/mfsrcsnk/tests/mfsrcsnk.c index ec5af46b6ba..a69d3b2c10a 100644 --- a/dlls/mfsrcsnk/tests/mfsrcsnk.c +++ b/dlls/mfsrcsnk/tests/mfsrcsnk.c @@ -30,6 +30,28 @@ #include "wine/test.h" +static BOOL source_is_gstreamer = FALSE; +static BOOL source_is_winedmo = FALSE; + +#define todo_gstreamer todo_if(source_is_gstreamer) +#define todo_gstreamer_if(is_todo) todo_if((is_todo) && source_is_gstreamer) + +#define todo_winedmo todo_if(source_is_winedmo) +#define todo_winedmo_if(is_todo) todo_if((is_todo) && source_is_winedmo) + +static BOOL use_gst_byte_stream_handler(void) +{ + BOOL result; + DWORD size = sizeof(result); + + /* @@ Wine registry key: HKCU\Software\Wine\MediaFoundation */ + if (!RegGetValueW( HKEY_CURRENT_USER, L"Software\\Wine\\MediaFoundation", L"DisableGstByteStreamHandler", + RRF_RT_REG_DWORD, NULL, &result, &size )) + return !result; + + return TRUE; +} + static const char *debugstr_time(LONGLONG time) { ULONGLONG abstime = time >= 0 ? time : -time; @@ -626,11 +648,11 @@ static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL t hr = MFGetService((IUnknown *)source, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFRateControl_SetRate(rate_control, thin, rate); - todo_wine_if(thin && hr == MF_E_THINNING_UNSUPPORTED) + todo_gstreamer_if(thin && hr == MF_E_THINNING_UNSUPPORTED) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(source, source_callback, MESourceRateChanged, 100, &value); - todo_wine_if(thin) + todo_gstreamer_if(thin) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); todo_wine ok(value.vt == VT_R4, "got vt %u\n", value.vt); @@ -639,7 +661,7 @@ static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL t hr = IMFMediaStream_RequestSample(stream, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (!winetest_platform_is_wine) + if (!source_is_gstreamer) { hr = wait_media_event(stream, callback, MEStreamThinMode, 100, &value); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -654,7 +676,7 @@ static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL t ok(value.vt == VT_UNKNOWN, "got vt %u\n", value.vt); hr = IMFSample_GetSampleTime((IMFSample *)value.punkVal, &time); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine + todo_gstreamer ok(time == expect_times[2], "Unexpected time %s.\n", debugstr_time(time)); hr = IMFSample_GetSampleDuration((IMFSample *)value.punkVal, &time); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -677,7 +699,7 @@ static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL t ok(value.vt == VT_UNKNOWN, "got vt %u\n", value.vt); hr = IMFSample_GetSampleTime((IMFSample *)value.punkVal, &time); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine + todo_gstreamer ok(time == (thin ? expect_times_thin[2 * i] : expect_times[2 * i]), "Unexpected time %s.\n", debugstr_time(time)); hr = IMFSample_GetSampleDuration((IMFSample *)value.punkVal, &time); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -699,7 +721,7 @@ static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL t ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFRateControl_SetRate(rate_control, !thin, rate+0.5); - todo_wine_if(!thin && hr == MF_E_THINNING_UNSUPPORTED) + todo_gstreamer_if(!thin && hr == MF_E_THINNING_UNSUPPORTED) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaStream_RequestSample(stream, NULL); @@ -721,7 +743,7 @@ static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL t PropVariantClear(&value); hr = wait_media_event(source, source_callback, MESourceRateChanged, 100, &value); - todo_wine_if(!thin && hr == MF_E_NO_EVENTS_AVAILABLE) + todo_gstreamer_if(!thin && hr == MF_E_NO_EVENTS_AVAILABLE) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); @@ -748,7 +770,7 @@ static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL t hr = IMFMediaStream_RequestSample(stream, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } - if (!winetest_platform_is_wine) + if (!source_is_gstreamer) { hr = wait_media_event(stream, callback, MEStreamThinMode, 1000, &value); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -759,19 +781,19 @@ static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL t /* switch back to previous mode */ hr = IMFRateControl_SetRate(rate_control, thin, rate+0.5); - todo_wine_if(thin && hr == MF_E_THINNING_UNSUPPORTED) + todo_gstreamer_if(thin && hr == MF_E_THINNING_UNSUPPORTED) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(source, source_callback, MESourceRateChanged, 100, &value); - todo_wine_if(thin && hr == MF_E_NO_EVENTS_AVAILABLE) + todo_gstreamer_if(thin && hr == MF_E_NO_EVENTS_AVAILABLE) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IMFMediaStream_RequestSample(stream, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (!winetest_platform_is_wine) + if (!source_is_gstreamer) { hr = wait_media_event(stream, callback, MEStreamThinMode, 1000, &value); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } - if (thin && !winetest_platform_is_wine) + if (thin && !source_is_gstreamer) { hr = wait_media_event(stream, callback, MEEndOfStream, 100, &value); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -830,6 +852,12 @@ START_TEST(mfsrcsnk) { HRESULT hr; + if (winetest_platform_is_wine) + { + source_is_gstreamer = use_gst_byte_stream_handler(); + source_is_winedmo = !source_is_gstreamer; + } + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8505