[PATCH 2/5] mfreadwrite/reader: Add a passthrough transform.
Giovanni Mascellani
gmascellani at codeweavers.com
Fri Mar 18 08:27:16 CDT 2022
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 at 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);
--
2.35.1
More information about the wine-devel
mailing list