Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/mfplat/sample.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index 8ef80eb5f24..527f44fd8fd 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -1214,13 +1214,9 @@ static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocator IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager); if (allocator->dxgi_device_manager) IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager); - allocator->d3d9_device_manager = NULL; - allocator->dxgi_device_manager = NULL;
- if (dxgi_device_manager) - allocator->dxgi_device_manager = dxgi_device_manager; - else if (d3d9_device_manager) - allocator->d3d9_device_manager = d3d9_device_manager; + allocator->d3d9_device_manager = d3d9_device_manager; + allocator->dxgi_device_manager = dxgi_device_manager;
LeaveCriticalSection(&allocator->cs);
On Windows media sources typically produce compressed data, so the source reader automatically adds a transform to decompress it. On Wine media sources already care about decompressing data, so there is no need for a transform. However, some applications expect it anyway (e.g., to edit transform attributes) and fail if it's not present.
Therefore, this patch adds a trivial passthrough transform implementation to please such programs.
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/mfreadwrite/reader.c | 487 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 487 insertions(+)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index bdf2e7f5a6f..2aaaf013da1 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -251,6 +251,461 @@ static ULONG source_reader_release(struct source_reader *reader) return refcount; }
+struct passthrough_transform +{ + IMFTransform IMFTransform_iface; + LONG refcount; + IMFMediaType *type; + IMFAttributes *attributes; + IMFAttributes *input_attributes; + IMFAttributes *output_attributes; + IMFSample *sample; +}; + +static inline struct passthrough_transform *impl_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct passthrough_transform, IMFTransform_iface); +} + +static HRESULT WINAPI passthrough_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **out) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IMFTransform)) + { + *out = &transform->IMFTransform_iface; + } + else + { + FIXME("(%s, %p)\n", debugstr_guid(riid), out); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI passthrough_transform_AddRef(IMFTransform *iface) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&transform->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI passthrough_transform_Release(IMFTransform *iface) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&transform->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + if (transform->type) + IMFMediaType_Release(transform->type); + IMFAttributes_Release(transform->attributes); + IMFAttributes_Release(transform->input_attributes); + IMFAttributes_Release(transform->output_attributes); + if (transform->sample) + IMFSample_Release(transform->sample); + } + + return refcount; +} +static HRESULT WINAPI passthrough_transform_GetStreamLimits(IMFTransform *iface, + DWORD *input_minimum, DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum); + + *input_minimum = 1; + *input_maximum = 1; + *output_minimum = 1; + *output_maximum = 1; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + TRACE("%p, %p, %p.\n", iface, inputs, outputs); + + *inputs = 1; + *outputs = 1; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetStreamIDs(IMFTransform *iface, + DWORD input_size, DWORD *inputs, DWORD output_size, DWORD *outputs) +{ + TRACE("%p, %ld, %p, %ld, %p.\n", iface, input_size, inputs, output_size, outputs); + + if (input_size < 1 || output_size < 1) + return MF_E_BUFFERTOOSMALL; + + inputs[0] = 0; + outputs[0] = 0; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + TRACE("%p, %ld, %p.\n", iface, id, info); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + info->hnsMaxLatency = 0; + info->dwFlags = MFT_INPUT_STREAM_PROCESSES_IN_PLACE; + info->cbSize = 0; + info->cbMaxLookahead = 0; + info->cbAlignment = 0; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + TRACE("%p, %ld, %p.\n", iface, id, info); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + info->dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + info->cbSize = 0; + info->cbAlignment = 0; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %p.\n", iface, attributes); + + IMFAttributes_AddRef(transform->attributes); + + *attributes = transform->attributes; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, attributes); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + IMFAttributes_AddRef(transform->input_attributes); + + *attributes = transform->input_attributes; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, attributes); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + IMFAttributes_AddRef(transform->output_attributes); + + *attributes = transform->output_attributes; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + TRACE("%p, %ld.\n", iface, id); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + TRACE("%p, %ld, %p.\n", iface, streams, ids); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) +{ + TRACE("%p, %ld, %ld, %p.\n", iface, id, index, type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %ld, %p.\n", iface, id, index, type); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (index != 0) + return MF_E_NO_MORE_TYPES; + + if (!transform->type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = transform->type; + IMFMediaType_AddRef(*type); + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p, %ld.\n", iface, id, type, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (!(flags & MFT_SET_TYPE_TEST_ONLY)) + { + if (transform->type) + IMFMediaType_Release(transform->type); + transform->type = type; + IMFMediaType_AddRef(type); + } + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + DWORD cmp_flags; + HRESULT hr; + + TRACE("%p, %ld, %p, %ld.\n", iface, id, type, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (!transform->type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + hr = IMFMediaType_IsEqual(transform->type, type, &cmp_flags); + if (FAILED(hr)) + return hr; + + if (!(cmp_flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)) + return MF_E_INVALIDMEDIATYPE; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, type); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (!transform->type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = transform->type; + IMFMediaType_AddRef(*type); + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, type); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (!transform->type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = transform->type; + IMFMediaType_AddRef(*type); + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + *flags = transform->sample ? 0 : MFT_INPUT_STATUS_ACCEPT_DATA; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %p.\n", iface, flags); + + *flags = transform->sample ? MFT_OUTPUT_STATUS_SAMPLE_READY : 0; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("%p, %ld, %p.\n", iface, id, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("%p, %u, %Iu.\n", iface, message, param); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p, %ld.\n", iface, id, sample, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (transform->sample) + return MF_E_NOTACCEPTING; + + transform->sample = sample; + IMFSample_AddRef(sample); + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + unsigned int i; + + TRACE("%p, %ld, %ld, %p, %p.\n", iface, flags, count, samples, status); + + if (!transform->sample) + return MF_E_TRANSFORM_NEED_MORE_INPUT; + + if (samples[0].dwStreamID != 0) + return MF_E_INVALIDSTREAMNUMBER; + + samples[0].pSample = transform->sample; + transform->sample = NULL; + + for (i = 1; i < count; ++i) + samples[i].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; + + *status = 0; + + return S_OK; +} + +static const IMFTransformVtbl passthrough_transform_vtbl = { + passthrough_transform_QueryInterface, + passthrough_transform_AddRef, + passthrough_transform_Release, + passthrough_transform_GetStreamLimits, + passthrough_transform_GetStreamCount, + passthrough_transform_GetStreamIDs, + passthrough_transform_GetInputStreamInfo, + passthrough_transform_GetOutputStreamInfo, + passthrough_transform_GetAttributes, + passthrough_transform_GetInputStreamAttributes, + passthrough_transform_GetOutputStreamAttributes, + passthrough_transform_DeleteInputStream, + passthrough_transform_AddInputStreams, + passthrough_transform_GetInputAvailableType, + passthrough_transform_GetOutputAvailableType, + passthrough_transform_SetInputType, + passthrough_transform_SetOutputType, + passthrough_transform_GetInputCurrentType, + passthrough_transform_GetOutputCurrentType, + passthrough_transform_GetInputStatus, + passthrough_transform_GetOutputStatus, + passthrough_transform_SetOutputBounds, + passthrough_transform_ProcessEvent, + passthrough_transform_ProcessMessage, + passthrough_transform_ProcessInput, + passthrough_transform_ProcessOutput, +}; + +static HRESULT create_passthrough_transform(IMFTransform **transform) +{ + struct passthrough_transform *obj; + HRESULT hr; + + if (!(obj = calloc(1, sizeof(*obj)))) + return E_OUTOFMEMORY; + + obj->IMFTransform_iface.lpVtbl = &passthrough_transform_vtbl; + obj->refcount = 1; + + hr = MFCreateAttributes(&obj->attributes, 0); + if (SUCCEEDED(hr)) + hr = MFCreateAttributes(&obj->input_attributes, 0); + if (SUCCEEDED(hr)) + hr = MFCreateAttributes(&obj->output_attributes, 0); + + if (SUCCEEDED(hr)) + { + *transform = &obj->IMFTransform_iface; + } + else + { + if (obj->attributes) + IMFAttributes_Release(obj->attributes); + if (obj->input_attributes) + IMFAttributes_Release(obj->input_attributes); + if (obj->output_attributes) + IMFAttributes_Release(obj->output_attributes); + free(obj); + } + + return hr; +} + static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -1774,6 +2229,36 @@ static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWO return MF_E_TOPO_CODEC_NOT_FOUND; }
+static HRESULT source_reader_add_passthrough_transform(struct source_reader *reader, DWORD index, IMFMediaType *type) +{ + IMFTransform *transform; + HRESULT hr; + + if (FAILED(hr = create_passthrough_transform(&transform))) + return hr; + + if (FAILED(hr = IMFTransform_SetInputType(transform, 0, type, 0))) + { + WARN("Failed to set decoder input type, hr %#lx.\n", hr); + IMFTransform_Release(transform); + return hr; + } + + if (FAILED(hr = IMFTransform_SetOutputType(transform, 0, type, 0))) + { + WARN("Failed to set decoder input type, hr %#lx.\n", hr); + IMFTransform_Release(transform); + return hr; + } + + if (reader->streams[index].decoder.transform) + IMFTransform_Release(reader->streams[index].decoder.transform); + reader->streams[index].decoder.transform = transform; + reader->streams[index].decoder.min_buffer_size = 0; + + return S_OK; +} + static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { MFT_REGISTER_TYPE_INFO in_type, out_type; @@ -1862,6 +2347,8 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO hr = source_reader_set_compatible_media_type(reader, index, type); if (hr == S_FALSE) hr = source_reader_create_decoder_for_stream(reader, index, type); + else if (hr == S_OK) + hr = source_reader_add_passthrough_transform(reader, index, reader->streams[index].current); if (SUCCEEDED(hr)) hr = source_reader_setup_sample_allocator(reader, index);
On 3/18/22 16:27, Giovanni Mascellani wrote:
On Windows media sources typically produce compressed data, so the source reader automatically adds a transform to decompress it. On Wine media sources already care about decompressing data, so there is no need for a transform. However, some applications expect it anyway (e.g., to edit transform attributes) and fail if it's not present.
Therefore, this patch adds a trivial passthrough transform implementation to please such programs.
This is obviously bad, being a hack.
static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { MFT_REGISTER_TYPE_INFO in_type, out_type; @@ -1862,6 +2347,8 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO hr = source_reader_set_compatible_media_type(reader, index, type); if (hr == S_FALSE) hr = source_reader_create_decoder_for_stream(reader, index, type);
- else if (hr == S_OK)
hr = source_reader_add_passthrough_transform(reader, index, reader->streams[index].current); if (SUCCEEDED(hr)) hr = source_reader_setup_sample_allocator(reader, index);
I'd like this to keep working as close to how it should be as possible, and being able to use wine's module on Windows too for testing.
What happens on Windows, when you set current media type to compressed type that source provides, or if some source provides raw output as winegstreamer does? What should happen to e.g. WAV streams? Why should it get a dummy transform in such cases?
I understand why this would be necessary for compatibility, but we should narrow down the impact of this hack first, using it only for winegstreamer source, and only when appropriate. Dummy transform code also should be moved to winegstreamer, because that's where the need for such hack comes from.
Some applications set the output attribute MF_SA_D3D11_SHARED_WITHOUT_MUTEX on the source reader's transform, seemingly expecting that it will be picked up by IMFVideoSampleAllocatorEx::InitializeSampleAllocator(), so that the generated samples will be shareable.
With this commit we try to emulate the same behavior.
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- I am not completely sure that this is what's happening on Windows, but unfortunately I see it rather hard to check. In principle I can create a custom test transform with a custom IMFAttributes object and then trace the calls to it, but it seems a lot of work for a rather fragile result. --- dlls/mfreadwrite/reader.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 2aaaf013da1..2ff56f6e978 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2120,6 +2120,7 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index) { struct media_stream *stream = &reader->streams[index]; + IMFAttributes *attributes = NULL; IMFVideoSampleAllocatorCallback *callback; GUID major = { 0 }; HRESULT hr; @@ -2147,7 +2148,16 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; }
- if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8, NULL, stream->current))) + if (stream->decoder.transform) + { + if (FAILED(hr = IMFTransform_GetOutputStreamAttributes(stream->decoder.transform, 0, &attributes))) + { + WARN("Failed to get output stream attributes, hr %#x.\n", hr); + return hr; + } + } + + if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8, attributes, stream->current))) WARN("Failed to initialize sample allocator, hr %#lx.\n", hr);
if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream->allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&callback)))
Currently the source reader creates a sample allocator as soon as SetCurrentMediaType() is called. However on Windows if the output attribute MF_SA_D3D11_SHARED_WITHOUT_MUTEX is set on the transform after SetCurrentMediaType() is called, but before ReadSample() is called, the sample allocator will generate shareable samples.
In order to emulate the same behavior, we defer creating the sample allocator to the first ReadSample() call, so the most updated attributes are picked up.
With this and the previous two patches, some video playback bugs are solved for some games (e.g. Trailmakers, Rustler, TOHU and others) when using DXVK (wined3d doesn't currently support shared resources, so there is no way to check with it).
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- Again, it's not easy to check that this is what's really happening on Windows. OTOH, AFAIK, neither we know that the sample allocator is created in SetCurrentMediaType(). --- dlls/mfreadwrite/reader.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 2ff56f6e978..7ae9f88c4c4 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1696,6 +1696,8 @@ static HRESULT source_reader_flush(struct source_reader *reader, unsigned int in return hr; }
+static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index); + static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); @@ -1725,7 +1727,15 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb { stream = &reader->streams[stream_index];
- if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status, + if (!stream->allocator) + { + hr = source_reader_setup_sample_allocator(reader, stream_index); + + if (FAILED(hr)) + WARN("Failed to setup the sample allocator, hr %#x.\n", hr); + } + + if (SUCCEEDED(hr) && !(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status, &stream_index, &stream_flags, ×tamp, &sample))) { stream->requests++; @@ -2359,8 +2369,12 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO hr = source_reader_create_decoder_for_stream(reader, index, type); else if (hr == S_OK) hr = source_reader_add_passthrough_transform(reader, index, reader->streams[index].current); - if (SUCCEEDED(hr)) - hr = source_reader_setup_sample_allocator(reader, index); + + if (reader->streams[index].allocator) + { + IMFVideoSampleAllocatorEx_Release(reader->streams[index].allocator); + reader->streams[index].allocator = NULL; + }
LeaveCriticalSection(&reader->cs);
@@ -2454,7 +2468,15 @@ static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD ind
stream = &reader->streams[stream_index];
- if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags, + if (!stream->allocator) + { + hr = source_reader_setup_sample_allocator(reader, stream_index); + + if (FAILED(hr)) + WARN("Failed to setup the sample allocator, hr %#x.\n", hr); + } + + if (SUCCEEDED(hr) && !source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags, timestamp, sample)) { while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS)
Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- This test doesn't work with Wine because Wine doesn't support shareable resources, but it works with DXVK.
Also, it doesn't work on the testbot, possibly because of the testbot's D3D drivers. However, it runs fine on my Windows 10 machine.
For both these reasons, I am not sure this commit is appropriate for Wine, but I am providing it anyway in case it is useful for reviewers. --- dlls/mfreadwrite/tests/Makefile.in | 2 +- dlls/mfreadwrite/tests/mfplat.c | 141 +++++++++++++++++++++++++++++ dlls/mfreadwrite/tests/resource.rc | 2 + dlls/mfreadwrite/tests/test.mp4 | Bin 0 -> 1846 bytes 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 dlls/mfreadwrite/tests/test.mp4
diff --git a/dlls/mfreadwrite/tests/Makefile.in b/dlls/mfreadwrite/tests/Makefile.in index c7476c14c6b..765f3c49932 100644 --- a/dlls/mfreadwrite/tests/Makefile.in +++ b/dlls/mfreadwrite/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mfreadwrite.dll -IMPORTS = ole32 user32 d3d9 dxva2 mfplat mfreadwrite mfuuid +IMPORTS = ole32 user32 d3d9 dxva2 mfplat mfreadwrite mfuuid d3d11 dxguid
C_SRCS = \ mfplat.c diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index fcf642859d5..929224a66cb 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -38,6 +38,8 @@ DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); #include "mferror.h" #include "mfreadwrite.h" #include "d3d9.h" +#include "d3d11.h" +#include "dxgi.h" #include "dxva2api.h"
#include "wine/test.h" @@ -1225,6 +1227,144 @@ done: DestroyWindow(window); }
+static WCHAR *load_resource(const WCHAR *name) +{ + static WCHAR pathW[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(ARRAY_SIZE(pathW), pathW); + lstrcatW(pathW, name); + + file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", + wine_dbgstr_w(pathW), GetLastError()); + + res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); + ok(res != 0, "couldn't find resource\n"); + ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), + &written, NULL); + ok(written == SizeofResource(GetModuleHandleA(NULL), res), + "couldn't write resource\n" ); + CloseHandle(file); + + return pathW; +} + +static void test_reader_dxgi(void) +{ + IMFDXGIDeviceManager *device_manager; + ID3D11Device *device; + IMFAttributes *attributes, *output_attributes; + IMFSourceReader *reader; + HRESULT hr; + UINT token; + DWORD stream_idx, flags; + LONGLONG timestamp; + IMFSample *sample; + IMFMediaType *media_type; + WCHAR *filename; + IMFMediaBuffer *buffer; + IMFDXGIBuffer *dxgi_buffer; + IDXGIResource *dxgi_resource; + IMFTransform *transform; + + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL); + ok(hr == S_OK, "Cannot create D3D11 device, hr %#x.\n", hr); + + if (hr != S_OK) + { + skip("Failed to create a D3D11 device, skipping tests.\n"); + return; + } + + hr = MFCreateDXGIDeviceManager(&token, &device_manager); + ok(hr == S_OK, "Cannot create DXGI device manager, hr %#x.\n", hr); + + hr = IMFDXGIDeviceManager_ResetDevice(device_manager, (IUnknown *)device, token); + ok(hr == S_OK, "Cannot reset device, hr %#x.\n", hr); + + hr = MFCreateAttributes(&attributes, 1); + ok(hr == S_OK, "Failed to create attributes object, hr %#x.\n", hr); + + hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, (IUnknown *)device_manager); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFAttributes_SetUINT32(attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + filename = load_resource(L"test.mp4"); + hr = MFCreateSourceReaderFromURL(filename, attributes, &reader); + ok(hr == S_OK, "Failed to create source reader, hr %#x.\n", hr); + + IMFAttributes_Release(attributes); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_ARGB32); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = IMFSourceReader_SetStreamSelection(reader, MF_SOURCE_READER_ALL_STREAMS, FALSE); + ok(hr == S_OK, "Failed to select first video stream, hr %#x.\n", hr); + hr = IMFSourceReader_SetStreamSelection(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE); + ok(hr == S_OK, "Failed to select first video stream, hr %#x.\n", hr); + + hr = IMFSourceReader_SetCurrentMediaType(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type); + ok(hr == S_OK, "Failed to select current media type, hr %#x.\n", hr); + + IMFMediaType_Release(media_type); + + hr = IMFSourceReader_GetServiceForStream(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, &GUID_NULL, &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Failed to get transform, hr %#x.\n", hr); + + hr = IMFTransform_GetOutputStreamAttributes(transform, 0, &output_attributes); + ok(hr == S_OK, "Failed to get output stream attributes, hr %#x.\n", hr); + + hr = IMFAttributes_SetUINT32(output_attributes, &MF_SA_D3D11_USAGE, D3D11_USAGE_DEFAULT); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFAttributes_SetUINT32(output_attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + IMFAttributes_Release(output_attributes); + IMFTransform_Release(transform); + + hr = IMFSourceReader_ReadSample(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &stream_idx, &flags, ×tamp, &sample); + ok(hr == S_OK, "Failed to read sample, hr %#x.\n", hr); + + hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer); + ok(hr == S_OK, "Failed to convert sample to contiguous buffer, hr %#x.\n", hr); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer); + ok(hr == S_OK, "Failed to query DXGI buffer, hr %#x.\n", hr); + + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_IDXGIResource, (void **)&dxgi_resource); + todo_wine ok(hr == S_OK, "Failed to get the DXGI buffer resource, hr %#x.\n", hr); + if (hr == S_OK) + { + HANDLE handle; + + hr = IDXGIResource_GetSharedHandle(dxgi_resource, &handle); + ok(hr == S_OK, "Failed to get shared handle, hr %#x.\n", hr); + ok(handle != NULL, "Got NULL shared handle.\n"); + + IDXGIResource_Release(dxgi_resource); + } + + IMFDXGIBuffer_Release(dxgi_buffer); + IMFMediaBuffer_Release(buffer); + IMFSample_Release(sample); + IMFSourceReader_Release(reader); + + IMFDXGIDeviceManager_Release(device_manager); + ID3D11Device_Release(device); +} + START_TEST(mfplat) { HRESULT hr; @@ -1238,6 +1378,7 @@ START_TEST(mfplat) test_source_reader(); test_source_reader_from_media_source(); test_reader_d3d9(); + test_reader_dxgi();
hr = MFShutdown(); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); diff --git a/dlls/mfreadwrite/tests/resource.rc b/dlls/mfreadwrite/tests/resource.rc index f54212a8c8f..9d7cf12249d 100644 --- a/dlls/mfreadwrite/tests/resource.rc +++ b/dlls/mfreadwrite/tests/resource.rc @@ -20,3 +20,5 @@
/* @makedep: test.wav */ test.wav RCDATA test.wav +/* @makedep: test.mp4 */ +test.mp4 RCDATA test.mp4 diff --git a/dlls/mfreadwrite/tests/test.mp4 b/dlls/mfreadwrite/tests/test.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..ebfce3031f5460b4c955cda4cc40eb9e71640db9 GIT binary patch literal 1846 zcmah~O=w(I6uy&asi7LhC=nvuYLqTAllNxQ$q#+tBnBh4po>;f;d$r2J9)2pf4T2w zGE)UzsJL*UAO*X~&Yy^gAm~ckg$tnzaU%vSGzg*yN_XkPjNf@PNv5gbfqTz){_nZ> z%p1lSZ<ux(WJ$!>03(i77ENhK>6FbFJKE4nF*f*8<Ou_xFOJ;V>3sIf;ve7swzc%l z#fhK!)}w#@-6~h7c#+FQD{faUt}B*pbLpvBF<XIQsRW0~GtVwQRh;6ra|`hFl!Rd+ zN!y`n7+$ulO0jH}Ehv3s(z(gW_4V~qGw@Urinx^M<w>ei@=X-NCrM3^#MvB|qAsLk zbFCUqg?p+VCUV8G=d3x4i&%v1OgUDoGH11HyTT*o_^QRTwK~u=PqQ{cvAf!H?2?5b zY&;5D%5y2BjR;qZcv(4il}leIk#G@ebE8!l1{u&yYsQlXK(0oPg(C>>LJ}*dY){}4 z8X_}pnymyWd2|!3rf$+`WXd?jGB>_P1SJZSWJUN8+yh+}1`=o4Q&>FKc?}sv!q7Q_ z*eD$eI6+?z*R*K6GKo@QAWK}4(ISYE0*+dcPeY4HWw@-mo3?=i&nW{7Po&gE-K_^A zqauM;d0*=)SoTdFwj@=tyPTx3c9khYS5zCho$^Vm2i+)$A@WSBSjjcxOj&eHE$B+M z%6x=t>F&2nb}b#L8$7DxUa2hzPPtOD_$oEySS3u=YD$T7E?Q1?7K+TM)S2Qzibujg z;0=*Wtm6IYHQ5`OV6NVIlTCMaw+DAdet7lfyXUVxr#^n*>ib_O58fEQ@l0nJK6lkF zjfV@b?`}R$BVXH?Z@twS`;l;ALzwx?$FFy>JP*7LJY2ivKmBRV|M2utx3l{}5vrlu z#@mbcO-$|wenf%fj3l2>;Pr0cCIUkQKHu409K}!Tt0+mDFojXm_rUvT@OQ=v@38{* zKJBdn47V5=d!pa>c07Qe@in~03QRAXmAvL)pIa{*>K>*;b^f#N2?Wt%Y+QLJ10Pdi zhEGRM$Uu4T=$(1sY~%$379M$rdoM#h!p?q|#}$1q)H%XNAB8<k{2YBGmPG7@ihKqb z#-sr-(v0$?{l^~ny0$S7vq-@pvL9R1A@AbCmCV#bVDN13LCEJz`YwVK_2=wrPN3~2 zKw3n%dvx^&`)H>Fp^B^v1&<ANw%J3=;Gb`uxv8!^iOHaQ8f4#}TDtf`fgSPx{PpT1 zSN_@Ap$zw?B1^%k3at_RaC(<K{~BYo*l1?*2LQ}{hUjiUBj}4BhG;MT6?xzbKhmRk z&PnW-NhCSX1^$2bJkJ<v$~-cU&Fl8+uv4&I=-G%tKkyUy-B`!^*8RZu9FozCOrRs8 zUM#Honr8&~i;>DXAUobaKo~kL(v;qKpNc_uN*~)a2_<|O|96yxlCsmH**G~<ny!{? G%la1p5|z~e
literal 0 HcmV?d00001
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110727
Your paranoid android.
=== w8 (32 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w8adm (32 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w864 (32 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064v1507 (32 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064v1809 (32 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064 (32 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064_tsign (32 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w10pro64 (32 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w864 (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064v1507 (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064v1809 (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064 (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064_2qxl (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w1064_tsign (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w10pro64 (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w10pro64_ar (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w10pro64_he (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w10pro64_ja (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== w10pro64_zh_CN (64 bit report) ===
mfreadwrite: mfplat.c:1354: Test failed: Got NULL shared handle.
=== debian11 (32 bit report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
Report validation errors: mfreadwrite:mfplat prints too much data (37277 bytes)
=== debian11 (32 bit Arabic:Morocco report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
=== debian11 (32 bit German report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
=== debian11 (32 bit French report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
=== debian11 (32 bit Hebrew:Israel report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
=== debian11 (32 bit Hindi:India report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
=== debian11 (32 bit Japanese:Japan report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
=== debian11 (32 bit Chinese:China report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
=== debian11 (32 bit WoW report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
Report validation errors: mfreadwrite:mfplat prints too much data (37285 bytes)
=== debian11 (64 bit WoW report) ===
mfreadwrite: mfplat.c:1319: Test failed: Failed to select current media type, hr 0xc00d5212. mfplat.c:1324: Test failed: Failed to get transform, hr 0x80004002. Unhandled exception: page fault on execute access to 0x0000000000000000 in 64-bit code (0x0000000000000000).
Report validation errors: mfreadwrite:mfplat prints too much data (47408 bytes)
On 3/18/22 16:27, Giovanni Mascellani wrote:
allocator->d3d9_device_manager = NULL;
allocator->dxgi_device_manager = NULL;
if (dxgi_device_manager)
allocator->dxgi_device_manager = dxgi_device_manager;
else if (d3d9_device_manager)
allocator->d3d9_device_manager = d3d9_device_manager;
allocator->d3d9_device_manager = d3d9_device_manager;
allocator->dxgi_device_manager = dxgi_device_manager;
LeaveCriticalSection(&allocator->cs);
I don't see a point in changing this. The way it's done now makes it clear that only one object is set.