diff --git a/patches/mfplat-streaming-support/0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch b/patches/mfplat-streaming-support/0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch new file mode 100644 index 00000000..aa6df9fa --- /dev/null +++ b/patches/mfplat-streaming-support/0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch @@ -0,0 +1,90 @@ +From d95656904e4d7d2c9a4006e90f123e28bbcdbb70 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Tue, 9 Mar 2021 16:53:09 -0500 +Subject: [PATCH 01/39] winegstreamer: Activate source pad in push mode if it + isn't activated in pull mode. + +Since our source pad is not part of any element, gstreamer won't end up activating it +directly through the state transition. Instead, if the downstream element doesn't +activate the source pad into pull mode during the transition to the READY state, +we activate our pad in push mode. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/wg_parser.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 0d59297a026..00ff02ef462 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -58,7 +58,7 @@ struct wg_parser + pthread_mutex_t mutex; + + pthread_cond_t init_cond; +- bool no_more_pads, has_duration, error; ++ bool no_more_pads, has_duration, error, pull_mode; + + pthread_cond_t read_cond, read_done_cond; + struct +@@ -1365,9 +1365,12 @@ static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode + GST_DEBUG("%s source pad for parser %p in %s mode.", + activate ? "Activating" : "Deactivating", parser, gst_pad_mode_get_name(mode)); + ++ parser->pull_mode = false; ++ + switch (mode) + { + case GST_PAD_MODE_PULL: ++ parser->pull_mode = activate; + return TRUE; + case GST_PAD_MODE_PUSH: + return activate_push(pad, activate); +@@ -1612,6 +1615,8 @@ static void CDECL wg_parser_disconnect(struct wg_parser *parser) + pthread_mutex_unlock(&parser->mutex); + + gst_element_set_state(parser->container, GST_STATE_NULL); ++ if (!parser->pull_mode) ++ gst_pad_set_active(parser->my_src, 0); + gst_pad_unlink(parser->my_src, parser->their_sink); + gst_object_unref(parser->my_src); + gst_object_unref(parser->their_sink); +@@ -1667,6 +1672,8 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + } + + gst_element_set_state(parser->container, GST_STATE_PAUSED); ++ if (!parser->pull_mode) ++ gst_pad_set_active(parser->my_src, 1); + ret = gst_element_get_state(parser->container, NULL, NULL, -1); + if (ret == GST_STATE_CHANGE_FAILURE) + { +@@ -1718,6 +1725,8 @@ static BOOL avi_parser_init_gst(struct wg_parser *parser) + } + + gst_element_set_state(parser->container, GST_STATE_PAUSED); ++ if (!parser->pull_mode) ++ gst_pad_set_active(parser->my_src, 1); + ret = gst_element_get_state(parser->container, NULL, NULL, -1); + if (ret == GST_STATE_CHANGE_FAILURE) + { +@@ -1772,6 +1781,8 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) + + gst_pad_set_active(stream->my_sink, 1); + gst_element_set_state(parser->container, GST_STATE_PAUSED); ++ if (!parser->pull_mode) ++ gst_pad_set_active(parser->my_src, 1); + ret = gst_element_get_state(parser->container, NULL, NULL, -1); + if (ret == GST_STATE_CHANGE_FAILURE) + { +@@ -1826,6 +1837,8 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) + + gst_pad_set_active(stream->my_sink, 1); + gst_element_set_state(parser->container, GST_STATE_PAUSED); ++ if (!parser->pull_mode) ++ gst_pad_set_active(parser->my_src, 1); + ret = gst_element_get_state(parser->container, NULL, NULL, -1); + if (ret == GST_STATE_CHANGE_FAILURE) + { +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0002-winegstreamer-Push-stream-start-and-segment-events-i.patch b/patches/mfplat-streaming-support/0002-winegstreamer-Push-stream-start-and-segment-events-i.patch new file mode 100644 index 00000000..f589f577 --- /dev/null +++ b/patches/mfplat-streaming-support/0002-winegstreamer-Push-stream-start-and-segment-events-i.patch @@ -0,0 +1,60 @@ +From 9ec96ab12a41323abb477922cd2401446bd95457 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 10 Mar 2021 10:43:03 -0500 +Subject: [PATCH 02/39] winegstreamer: Push stream-start and segment events in + push mode. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/wg_parser.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 00ff02ef462..c83afe4e195 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1286,6 +1286,7 @@ static void *push_data(void *arg) + { + struct wg_parser *parser = arg; + GstBuffer *buffer; ++ GstSegment *segment; + guint max_size; + + GST_DEBUG("Starting push thread."); +@@ -1298,6 +1299,12 @@ static void *push_data(void *arg) + + max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; + ++ gst_pad_push_event(parser->my_src, gst_event_new_stream_start("wg_stream")); ++ ++ segment = gst_segment_new(); ++ gst_segment_init(segment, GST_FORMAT_BYTES); ++ gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); ++ + for (;;) + { + ULONG size; +@@ -1432,6 +1439,7 @@ static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) + GstEvent *flush_event; + GstSeekFlags flags; + gint64 cur, stop; ++ GstSegment *seg; + guint32 seqnum; + gdouble rate; + +@@ -1465,7 +1473,12 @@ static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) + gst_event_set_seqnum(flush_event, seqnum); + gst_pad_push_event(parser->my_src, flush_event); + if (thread) ++ { + gst_pad_set_active(parser->my_src, 1); ++ seg = gst_segment_new(); ++ gst_segment_init(seg, GST_FORMAT_BYTES); ++ gst_pad_push_event(parser->my_src, gst_event_new_segment(seg)); ++ } + } + + return TRUE; +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0003-winegstreamer-Implement-Process-Input-Output-for-aud.patch b/patches/mfplat-streaming-support/0003-winegstreamer-Implement-Process-Input-Output-for-aud.patch deleted file mode 100644 index 54bee44b..00000000 --- a/patches/mfplat-streaming-support/0003-winegstreamer-Implement-Process-Input-Output-for-aud.patch +++ /dev/null @@ -1,407 +0,0 @@ -From: Derek Lesho -Subject: [PATCH resend 3/5] winegstreamer: Implement ::Process(Input/Output) for audio conversion transform. -Message-Id: <20210118193047.267366-3-dlesho@codeweavers.com> -Date: Mon, 18 Jan 2021 14:30:45 -0500 -In-Reply-To: <20210118193047.267366-1-dlesho@codeweavers.com> -References: <20210118193047.267366-1-dlesho@codeweavers.com> - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/audioconvert.c | 188 ++++++++++++++++++++++++++++-- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 69 +++++++++++ - 3 files changed, 250 insertions(+), 8 deletions(-) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 85f44dd8856..e16fc6f1a78 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -40,6 +40,8 @@ struct audio_converter - IMFMediaType *input_type; - IMFMediaType *output_type; - CRITICAL_SECTION cs; -+ BOOL inflight; -+ GstElement *container, *appsrc, *appsink; - }; - - static struct audio_converter *impl_audio_converter_from_IMFTransform(IMFTransform *iface) -@@ -85,6 +87,7 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) - { - transform->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&transform->cs); -+ gst_object_unref(transform->container); - heap_free(transform); - } - -@@ -295,6 +298,9 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id - - EnterCriticalSection(&converter->cs); - -+ converter->inflight = FALSE; -+ gst_element_set_state(converter->container, GST_STATE_READY); -+ - if (converter->input_type) - { - IMFMediaType_Release(converter->input_type); -@@ -326,14 +332,17 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id - if (!(input_caps = caps_from_mf_media_type(type))) - return MF_E_INVALIDTYPE; - -- gst_caps_unref(input_caps); -- - if (flags & MFT_SET_TYPE_TEST_ONLY) -+ { -+ gst_caps_unref(input_caps); - return S_OK; -+ } - - EnterCriticalSection(&converter->cs); - - hr = S_OK; -+ converter->inflight = FALSE; -+ gst_element_set_state(converter->container, GST_STATE_READY); - - if (!converter->input_type) - hr = MFCreateMediaType(&converter->input_type); -@@ -341,12 +350,18 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id - if (SUCCEEDED(hr)) - hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->input_type); - -+ g_object_set(converter->appsrc, "caps", input_caps, NULL); -+ gst_caps_unref(input_caps); -+ - if (FAILED(hr)) - { - IMFMediaType_Release(converter->input_type); - converter->input_type = NULL; - } - -+ if (converter->input_type && converter->output_type) -+ gst_element_set_state(converter->container, GST_STATE_PLAYING); -+ - LeaveCriticalSection(&converter->cs); - - return hr; -@@ -375,6 +390,9 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - - EnterCriticalSection(&converter->cs); - -+ converter->inflight = FALSE; -+ gst_element_set_state(converter->container, GST_STATE_READY); -+ - if (converter->output_type) - { - IMFMediaType_Release(converter->output_type); -@@ -406,14 +424,17 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - if (!(output_caps = caps_from_mf_media_type(type))) - return MF_E_INVALIDTYPE; - -- gst_caps_unref(output_caps); -- - if (flags & MFT_SET_TYPE_TEST_ONLY) -+ { -+ gst_caps_unref(output_caps); - return S_OK; -+ } - - EnterCriticalSection(&converter->cs); - - hr = S_OK; -+ converter->inflight = FALSE; -+ gst_element_set_state(converter->container, GST_STATE_READY); - - if (!converter->output_type) - hr = MFCreateMediaType(&converter->output_type); -@@ -421,12 +442,18 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - if (SUCCEEDED(hr)) - hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->output_type); - -+ g_object_set(converter->appsink, "caps", output_caps, NULL); -+ gst_caps_unref(output_caps); -+ - if (FAILED(hr)) - { - IMFMediaType_Release(converter->output_type); - converter->output_type = NULL; - } - -+ if (converter->input_type && converter->output_type) -+ gst_element_set_state(converter->container, GST_STATE_PLAYING); -+ - LeaveCriticalSection(&converter->cs); - - return hr; -@@ -538,17 +565,102 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME - - static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ GstBuffer *gst_buffer; -+ int ret; - -- return E_NOTIMPL; -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); -+ -+ TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ -+ if (flags) -+ WARN("Unsupported flags %#x\n", flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!converter->input_type || !converter->output_type) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ if (converter->inflight) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_NOTACCEPTING; -+ } -+ -+ if (!(gst_buffer = gst_buffer_from_mf_sample(sample))) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return E_FAIL; -+ } -+ -+ g_signal_emit_by_name(converter->appsrc, "push-buffer", gst_buffer, &ret); -+ gst_buffer_unref(gst_buffer); -+ if (ret != GST_FLOW_OK) -+ { -+ ERR("Couldn't push buffer ret, (%s)\n", gst_flow_get_name(ret)); -+ LeaveCriticalSection(&converter->cs); -+ return E_FAIL; -+ } -+ -+ converter->inflight = TRUE; -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - } - - static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ GstSample *sample; - -- return E_NOTIMPL; -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); -+ -+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ -+ if (flags) -+ WARN("Unsupported flags %#x\n", flags); -+ -+ if (!count) -+ return S_OK; -+ -+ if (count != 1) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (samples[0].dwStreamID != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!converter->input_type || !converter->output_type) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ if (!converter->inflight) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ g_signal_emit_by_name(converter->appsink, "pull-sample", &sample); -+ -+ converter->inflight = FALSE; -+ -+ samples[0].pSample = mf_sample_from_gst_buffer(gst_sample_get_buffer(sample)); -+ gst_sample_unref(sample); -+ samples[0].dwStatus = S_OK; -+ samples[0].pEvents = NULL; -+ *status = 0; -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - } - - static const IMFTransformVtbl audio_converter_vtbl = -@@ -583,6 +695,7 @@ static const IMFTransformVtbl audio_converter_vtbl = - - HRESULT audio_converter_create(REFIID riid, void **ret) - { -+ GstElement *audioconvert, *resampler; - struct audio_converter *object; - - TRACE("%s %p\n", debugstr_guid(riid), ret); -@@ -596,6 +709,65 @@ HRESULT audio_converter_create(REFIID riid, void **ret) - InitializeCriticalSection(&object->cs); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": audio_converter_lock"); - -+ object->container = gst_bin_new(NULL); -+ -+ if (!(object->appsrc = gst_element_factory_make("appsrc", NULL))) -+ { -+ ERR("Failed to create appsrc, are %u-bit Gstreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ gst_bin_add(GST_BIN(object->container), object->appsrc); -+ -+ if (!(audioconvert = gst_element_factory_make("audioconvert", NULL))) -+ { -+ ERR("Failed to create audioconvert, are %u-bit Gstreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ gst_bin_add(GST_BIN(object->container), audioconvert); -+ -+ if (!(resampler = gst_element_factory_make("audioresample", NULL))) -+ { -+ ERR("Failed to create audioresample, are %u-bit Gstreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ gst_bin_add(GST_BIN(object->container), resampler); -+ -+ if (!(object->appsink = gst_element_factory_make("appsink", NULL))) -+ { -+ ERR("Failed to create appsink, are %u-bit Gstreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ gst_bin_add(GST_BIN(object->container), object->appsink); -+ -+ if (!gst_element_link(object->appsrc, audioconvert)) -+ { -+ ERR("Failed to link appsrc to audioconvert\n"); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ -+ if (!gst_element_link(audioconvert, resampler)) -+ { -+ ERR("Failed to link audioconvert to resampler\n"); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ -+ if (!gst_element_link(resampler, object->appsink)) -+ { -+ ERR("Failed to link resampler to appsink\n"); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ - *ret = &object->IMFTransform_iface; - return S_OK; - } -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 9518f721504..14b6a011ac2 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -82,6 +82,7 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HI - IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) DECLSPEC_HIDDEN; - GstCaps *caps_from_mf_media_type(IMFMediaType *type) DECLSPEC_HIDDEN; - IMFSample *mf_sample_from_gst_buffer(GstBuffer *in) DECLSPEC_HIDDEN; -+GstBuffer *gst_buffer_from_mf_sample(IMFSample *in) DECLSPEC_HIDDEN; - - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index f300988fc5c..b2b5b247dac 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -865,3 +865,72 @@ done: - - return out; - } -+ -+GstBuffer *gst_buffer_from_mf_sample(IMFSample *mf_sample) -+{ -+ GstBuffer *out = gst_buffer_new(); -+ IMFMediaBuffer *mf_buffer = NULL; -+ LONGLONG duration, time; -+ DWORD buffer_count; -+ unsigned int i; -+ HRESULT hr; -+ -+ if (FAILED(hr = IMFSample_GetSampleDuration(mf_sample, &duration))) -+ goto fail; -+ -+ if (FAILED(hr = IMFSample_GetSampleTime(mf_sample, &time))) -+ goto fail; -+ -+ GST_BUFFER_DURATION(out) = duration; -+ GST_BUFFER_PTS(out) = time * 100; -+ -+ if (FAILED(hr = IMFSample_GetBufferCount(mf_sample, &buffer_count))) -+ goto fail; -+ -+ for (i = 0; i < buffer_count; i++) -+ { -+ DWORD buffer_size; -+ GstMapInfo map_info; -+ GstMemory *memory; -+ BYTE *buf_data; -+ -+ if (FAILED(hr = IMFSample_GetBufferByIndex(mf_sample, i, &mf_buffer))) -+ goto fail; -+ -+ if (FAILED(hr = IMFMediaBuffer_GetCurrentLength(mf_buffer, &buffer_size))) -+ goto fail; -+ -+ memory = gst_allocator_alloc(NULL, buffer_size, NULL); -+ gst_memory_resize(memory, 0, buffer_size); -+ -+ if (!gst_memory_map(memory, &map_info, GST_MAP_WRITE)) -+ { -+ hr = E_FAIL; -+ goto fail; -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(mf_buffer, &buf_data, NULL, NULL))) -+ goto fail; -+ -+ memcpy(map_info.data, buf_data, buffer_size); -+ -+ if (FAILED(hr = IMFMediaBuffer_Unlock(mf_buffer))) -+ goto fail; -+ -+ gst_memory_unmap(memory, &map_info); -+ -+ gst_buffer_append_memory(out, memory); -+ -+ IMFMediaBuffer_Release(mf_buffer); -+ mf_buffer = NULL; -+ } -+ -+ return out; -+ -+fail: -+ ERR("Failed to copy IMFSample to GstBuffer, hr = %#x\n", hr); -+ if (mf_buffer) -+ IMFMediaBuffer_Release(mf_buffer); -+ gst_buffer_unref(out); -+ return NULL; -+} - --- -2.30.0 - diff --git a/patches/mfplat-streaming-support/0003-winegstreamer-Introduce-H.264-decoder-transform.patch b/patches/mfplat-streaming-support/0003-winegstreamer-Introduce-H.264-decoder-transform.patch new file mode 100644 index 00000000..caa6c8ad --- /dev/null +++ b/patches/mfplat-streaming-support/0003-winegstreamer-Introduce-H.264-decoder-transform.patch @@ -0,0 +1,384 @@ +From 95db72178f4906d02785c707a46c8298f4c008d0 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 10 Mar 2021 13:09:51 -0500 +Subject: [PATCH 03/39] winegstreamer: Introduce H.264 decoder transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/Makefile.in | 1 + + dlls/winegstreamer/decode_transform.c | 301 +++++++++++++++++++ + dlls/winegstreamer/gst_private.h | 2 + + dlls/winegstreamer/mfplat.c | 1 + + dlls/winegstreamer/winegstreamer_classes.idl | 6 + + include/mfidl.idl | 1 + + 6 files changed, 312 insertions(+) + create mode 100644 dlls/winegstreamer/decode_transform.c + +diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in +index 4d5dece64b3..7459cccf7e4 100644 +--- a/dlls/winegstreamer/Makefile.in ++++ b/dlls/winegstreamer/Makefile.in +@@ -8,6 +8,7 @@ EXTRADLLFLAGS = -mno-cygwin + + C_SRCS = \ + audioconvert.c \ ++ decode_transform.c \ + main.c \ + media_source.c \ + mfplat.c \ +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +new file mode 100644 +index 00000000000..f5d4763bde4 +--- /dev/null ++++ b/dlls/winegstreamer/decode_transform.c +@@ -0,0 +1,301 @@ ++/* GStreamer Decoder Transform ++ * ++ * Copyright 2021 Derek Lesho ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "gst_private.h" ++ ++#include "mfapi.h" ++#include "mferror.h" ++#include "mfobjects.h" ++#include "mftransform.h" ++ ++#include "wine/debug.h" ++#include "wine/heap.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(mfplat); ++ ++struct mf_decoder ++{ ++ IMFTransform IMFTransform_iface; ++ LONG refcount; ++}; ++ ++static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) ++{ ++ return CONTAINING_RECORD(iface, struct mf_decoder, IMFTransform_iface); ++} ++ ++static HRESULT WINAPI mf_decoder_QueryInterface (IMFTransform *iface, REFIID riid, void **out) ++{ ++ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); ++ ++ if (IsEqualIID(riid, &IID_IMFTransform) || ++ IsEqualIID(riid, &IID_IUnknown)) ++ { ++ *out = iface; ++ IMFTransform_AddRef(iface); ++ return S_OK; ++ } ++ ++ WARN("Unsupported %s.\n", debugstr_guid(riid)); ++ *out = NULL; ++ return E_NOINTERFACE; ++} ++ ++static ULONG WINAPI mf_decoder_AddRef(IMFTransform *iface) ++{ ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ ULONG refcount = InterlockedIncrement(&decoder->refcount); ++ ++ TRACE("%p, refcount %u.\n", iface, refcount); ++ ++ return refcount; ++} ++ ++static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) ++{ ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ ULONG refcount = InterlockedDecrement(&decoder->refcount); ++ ++ TRACE("%p, refcount %u.\n", iface, refcount); ++ ++ if (!refcount) ++ { ++ heap_free(decoder); ++ } ++ ++ return refcount; ++} ++ ++static HRESULT WINAPI mf_decoder_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 = *input_maximum = *output_minimum = *output_maximum = 1; ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI mf_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) ++{ ++ TRACE("%p %p %p.\n", iface, inputs, outputs); ++ ++ *inputs = *outputs = 1; ++ ++ return S_OK; ++} ++ ++static HRESULT WINAPI mf_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, ++ DWORD output_size, DWORD *outputs) ++{ ++ TRACE("%p %u %p %u %p.\n", iface, input_size, inputs, output_size, outputs); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) ++{ ++ FIXME("%p %u %p.\n", iface, id, info); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) ++{ ++ FIXME("%p %u %p.\n", iface, id, info); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) ++{ ++ FIXME("%p, %p.\n", iface, attributes); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, ++ IMFAttributes **attributes) ++{ ++ FIXME("%p, %u, %p.\n", iface, id, attributes); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, ++ IMFAttributes **attributes) ++{ ++ FIXME("%p, %u, %p.\n", iface, id, attributes); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) ++{ ++ TRACE("%p, %u.\n", iface, id); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) ++{ ++ TRACE("%p, %u, %p.\n", iface, streams, ids); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, ++ IMFMediaType **type) ++{ ++ FIXME("%p, %u, %u, %p.\n", iface, id, index, type); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, ++ IMFMediaType **type) ++{ ++ FIXME("%p, %u, %u, %p.\n", iface, id, index, type); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) ++{ ++ FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) ++{ ++ FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) ++{ ++ FIXME("%p, %u, %p.\n", iface, id, type); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) ++{ ++ FIXME("%p, %u, %p.\n", iface, id, type); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) ++{ ++ FIXME("%p, %u, %p\n", iface, id, flags); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) ++{ ++ FIXME("%p, %p.\n", iface, flags); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_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 mf_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) ++{ ++ FIXME("%p, %u, %p.\n", iface, id, event); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) ++{ ++ FIXME("%p, %u %lu.\n", iface, message, param); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) ++{ ++ FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); ++ ++ return E_NOTIMPL; ++} ++ ++static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, ++ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) ++{ ++ FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); ++ ++ return E_NOTIMPL; ++} ++ ++static const IMFTransformVtbl mf_decoder_vtbl = ++{ ++ mf_decoder_QueryInterface, ++ mf_decoder_AddRef, ++ mf_decoder_Release, ++ mf_decoder_GetStreamLimits, ++ mf_decoder_GetStreamCount, ++ mf_decoder_GetStreamIDs, ++ mf_decoder_GetInputStreamInfo, ++ mf_decoder_GetOutputStreamInfo, ++ mf_decoder_GetAttributes, ++ mf_decoder_GetInputStreamAttributes, ++ mf_decoder_GetOutputStreamAttributes, ++ mf_decoder_DeleteInputStream, ++ mf_decoder_AddInputStreams, ++ mf_decoder_GetInputAvailableType, ++ mf_decoder_GetOutputAvailableType, ++ mf_decoder_SetInputType, ++ mf_decoder_SetOutputType, ++ mf_decoder_GetInputCurrentType, ++ mf_decoder_GetOutputCurrentType, ++ mf_decoder_GetInputStatus, ++ mf_decoder_GetOutputStatus, ++ mf_decoder_SetOutputBounds, ++ mf_decoder_ProcessEvent, ++ mf_decoder_ProcessMessage, ++ mf_decoder_ProcessInput, ++ mf_decoder_ProcessOutput, ++}; ++ ++HRESULT decode_transform_create(REFIID riid, void **obj) ++{ ++ struct mf_decoder *object; ++ ++ TRACE("%s, %p.\n", debugstr_guid(riid), obj); ++ ++ if (!(object = heap_alloc_zero(sizeof(*object)))) ++ return E_OUTOFMEMORY; ++ ++ object->IMFTransform_iface.lpVtbl = &mf_decoder_vtbl; ++ object->refcount = 1; ++ ++ *obj = &object->IMFTransform_iface; ++ return S_OK; ++} +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 55a62361966..cdf90d52025 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -219,4 +219,6 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HI + + HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; + ++HRESULT decode_transform_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; ++ + #endif /* __GST_PRIVATE_INCLUDED__ */ +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index dfa448afcfe..de679a62023 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -412,6 +412,7 @@ class_objects[] = + { &CLSID_VideoProcessorMFT, &video_processor_create }, + { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, + { &CLSID_WINEAudioConverter, &audio_converter_create }, ++ { &CLSID_CMSH264DecoderMFT, &decode_transform_create }, + }; + + HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) +diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl +index 072ec90eea4..064a6872c79 100644 +--- a/dlls/winegstreamer/winegstreamer_classes.idl ++++ b/dlls/winegstreamer/winegstreamer_classes.idl +@@ -67,3 +67,9 @@ coclass GStreamerByteStreamHandler {} + uuid(6a170414-aad9-4693-b806-3a0c47c570d6) + ] + coclass WINEAudioConverter { } ++ ++[ ++ threading(both), ++ uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d) ++] ++coclass CMSH264DecoderMFT { } +diff --git a/include/mfidl.idl b/include/mfidl.idl +index 76e0d0dfeb4..616271861aa 100644 +--- a/include/mfidl.idl ++++ b/include/mfidl.idl +@@ -1574,3 +1574,4 @@ cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, 0xba491365, + cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, 0xba491366, 0xbe50, 0x451e, 0x95, 0xab, 0x6d, 0x4a, 0xcc, 0xc7, 0xda, 0xd8);") + + cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") ++cpp_quote("EXTERN_GUID(CLSID_CMSH264DecoderMFT, 0x62ce7e72, 0x4c71, 0x4d20, 0xb1, 0x5d, 0x45, 0x28, 0x31, 0xa8, 0x7d, 0x9d);") +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch b/patches/mfplat-streaming-support/0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch new file mode 100644 index 00000000..12dc00f3 --- /dev/null +++ b/patches/mfplat-streaming-support/0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch @@ -0,0 +1,157 @@ +From 17dab7f1ec1e00c313fa9f9bdcd64847de83b785 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 10 Mar 2021 14:14:21 -0500 +Subject: [PATCH 04/39] winegstreamer: Implement ::GetInputAvailableType for + decode transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 60 +++++++++++++++++++++++++-- + dlls/winegstreamer/gst_private.h | 6 ++- + dlls/winegstreamer/mfplat.c | 7 +++- + 3 files changed, 67 insertions(+), 6 deletions(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index f5d4763bde4..55a0c1c6c9b 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -29,10 +29,33 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + ++const GUID *h264_input_types[] = {&MFVideoFormat_H264}; ++/* NV12 comes first https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order . thanks to @vitorhnn */ ++const GUID *h264_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_YUY2, &MFVideoFormat_YV12}; ++ ++static struct decoder_desc ++{ ++ const GUID *major_type; ++ const GUID **input_types; ++ unsigned int input_types_count; ++ const GUID **output_types; ++ unsigned int output_types_count; ++} decoder_descs[] = ++{ ++ { /* DECODER_TYPE_H264 */ ++ &MFMediaType_Video, ++ h264_input_types, ++ ARRAY_SIZE(h264_input_types), ++ h264_output_types, ++ ARRAY_SIZE(h264_output_types), ++ }, ++}; ++ + struct mf_decoder + { + IMFTransform IMFTransform_iface; + LONG refcount; ++ enum decoder_type type; + }; + + static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) +@@ -163,9 +186,36 @@ static HRESULT WINAPI mf_decoder_AddInputStreams(IMFTransform *iface, DWORD stre + static HRESULT WINAPI mf_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) + { +- FIXME("%p, %u, %u, %p.\n", iface, id, index, type); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ IMFMediaType *input_type; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %u, %p\n", decoder, id, index, type); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (index >= decoder_descs[decoder->type].input_types_count) ++ return MF_E_NO_MORE_TYPES; ++ ++ if (FAILED(hr = MFCreateMediaType(&input_type))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaType_SetGUID(input_type, &MF_MT_MAJOR_TYPE, decoder_descs[decoder->type].major_type))) ++ { ++ IMFMediaType_Release(input_type); ++ return hr; ++ } ++ ++ if (FAILED(hr = IMFMediaType_SetGUID(input_type, &MF_MT_SUBTYPE, decoder_descs[decoder->type].input_types[index]))) ++ { ++ IMFMediaType_Release(input_type); ++ return hr; ++ } ++ ++ *type = input_type; ++ ++ return S_OK; + } + + static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, +@@ -284,11 +334,11 @@ static const IMFTransformVtbl mf_decoder_vtbl = + mf_decoder_ProcessOutput, + }; + +-HRESULT decode_transform_create(REFIID riid, void **obj) ++HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) + { + struct mf_decoder *object; + +- TRACE("%s, %p.\n", debugstr_guid(riid), obj); ++ TRACE("%s, %p %u.\n", debugstr_guid(riid), obj, type); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; +@@ -296,6 +346,8 @@ HRESULT decode_transform_create(REFIID riid, void **obj) + object->IMFTransform_iface.lpVtbl = &mf_decoder_vtbl; + object->refcount = 1; + ++ object->type = type; ++ + *obj = &object->IMFTransform_iface; + return S_OK; + } +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index cdf90d52025..2d2ebbda61f 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -219,6 +219,10 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HI + + HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; + +-HRESULT decode_transform_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; ++enum decoder_type ++{ ++ DECODER_TYPE_H264, ++}; ++HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; + + #endif /* __GST_PRIVATE_INCLUDED__ */ +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index de679a62023..40bb7969fc3 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -402,6 +402,11 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a + + static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}}; + ++static HRESULT h264_decoder_create(REFIID riid, void **ret) ++{ ++ return decode_transform_create(riid, ret, DECODER_TYPE_H264); ++} ++ + static const struct class_object + { + const GUID *clsid; +@@ -412,7 +417,7 @@ class_objects[] = + { &CLSID_VideoProcessorMFT, &video_processor_create }, + { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, + { &CLSID_WINEAudioConverter, &audio_converter_create }, +- { &CLSID_CMSH264DecoderMFT, &decode_transform_create }, ++ { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, + }; + + HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch b/patches/mfplat-streaming-support/0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch new file mode 100644 index 00000000..67445515 --- /dev/null +++ b/patches/mfplat-streaming-support/0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch @@ -0,0 +1,57 @@ +From 5842d8b762b85ff36de01d672e81d3e6eab9c554 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 10 Mar 2021 14:23:09 -0500 +Subject: [PATCH 05/39] winegstreamer: Implement ::GetOutputAvailableType for + decode transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 31 +++++++++++++++++++++++++-- + 1 file changed, 29 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index 55a0c1c6c9b..3c71fddd67c 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -221,9 +221,36 @@ static HRESULT WINAPI mf_decoder_GetInputAvailableType(IMFTransform *iface, DWOR + static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) + { +- FIXME("%p, %u, %u, %p.\n", iface, id, index, type); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ IMFMediaType *output_type; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %u, %p\n", decoder, id, index, type); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (index >= decoder_descs[decoder->type].output_types_count) ++ return MF_E_NO_MORE_TYPES; ++ ++ if (FAILED(hr = MFCreateMediaType(&output_type))) ++ return hr; ++ ++ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_MAJOR_TYPE, decoder_descs[decoder->type].major_type))) ++ { ++ IMFMediaType_Release(output_type); ++ return hr; ++ } ++ ++ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_SUBTYPE, decoder_descs[decoder->type].output_types[index]))) ++ { ++ IMFMediaType_Release(output_type); ++ return hr; ++ } ++ ++ *type = output_type; ++ ++ return S_OK; + } + + static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch b/patches/mfplat-streaming-support/0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch new file mode 100644 index 00000000..41a29cd8 --- /dev/null +++ b/patches/mfplat-streaming-support/0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch @@ -0,0 +1,305 @@ +From 6d41356d8849c741c93e6eaab81784a8be515aa5 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 11 Mar 2021 12:33:02 -0500 +Subject: [PATCH 06/39] winegstreamer: Implement ::SetInputType for decode + transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 80 ++++++++++++++++++++++++++- + dlls/winegstreamer/gst_private.h | 10 ++++ + dlls/winegstreamer/mfplat.c | 17 +++++- + dlls/winegstreamer/quartz_parser.c | 1 + + dlls/winegstreamer/wg_parser.c | 76 +++++++++++++++++++++++++ + 5 files changed, 180 insertions(+), 4 deletions(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index 3c71fddd67c..f709ef32fc1 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -56,6 +56,8 @@ struct mf_decoder + IMFTransform IMFTransform_iface; + LONG refcount; + enum decoder_type type; ++ IMFMediaType *input_type; ++ CRITICAL_SECTION cs; + }; + + static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) +@@ -99,6 +101,14 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) + + if (!refcount) + { ++ if (decoder->input_type) ++ { ++ IMFMediaType_Release(decoder->input_type); ++ decoder->input_type = NULL; ++ } ++ ++ DeleteCriticalSection(&decoder->cs); ++ + heap_free(decoder); + } + +@@ -255,9 +265,73 @@ static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWO + + static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) + { +- FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ struct wg_format input_format; ++ GUID major_type, subtype; ++ unsigned int i; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %p, %#x.\n", decoder, id, type, flags); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (!type) ++ { ++ if (flags & MFT_SET_TYPE_TEST_ONLY) ++ return S_OK; ++ ++ EnterCriticalSection(&decoder->cs); ++ ++ if (decoder->input_type) ++ { ++ IMFMediaType_Release(decoder->input_type); ++ decoder->input_type = NULL; ++ } ++ ++ LeaveCriticalSection(&decoder->cs); ++ ++ return S_OK; ++ } ++ ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) ++ return MF_E_INVALIDTYPE; ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) ++ return MF_E_INVALIDTYPE; ++ ++ if (!(IsEqualGUID(&major_type, decoder_descs[decoder->type].major_type))) ++ return MF_E_INVALIDTYPE; ++ ++ for (i = 0; i < decoder_descs[decoder->type].input_types_count; i++) ++ { ++ if (IsEqualGUID(&subtype, decoder_descs[decoder->type].input_types[i])) ++ break; ++ if (i == decoder_descs[decoder->type].input_types_count) ++ return MF_E_INVALIDTYPE; ++ } ++ ++ mf_media_type_to_wg_format(type, &input_format); ++ if (!input_format.major_type) ++ return MF_E_INVALIDTYPE; ++ ++ if (flags & MFT_SET_TYPE_TEST_ONLY) ++ return S_OK; ++ ++ EnterCriticalSection(&decoder->cs); ++ ++ hr = S_OK; ++ ++ if (!decoder->input_type) ++ hr = MFCreateMediaType(&decoder->input_type); ++ ++ if (SUCCEEDED(hr) && FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes*) decoder->input_type))) ++ { ++ IMFMediaType_Release(decoder->input_type); ++ decoder->input_type = NULL; ++ } ++ ++ LeaveCriticalSection(&decoder->cs); ++ return hr; + } + + static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +@@ -375,6 +449,8 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) + + object->type = type; + ++ InitializeCriticalSection(&object->cs); ++ + *obj = &object->IMFTransform_iface; + return S_OK; + } +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 2d2ebbda61f..215cf4577d4 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -97,9 +97,19 @@ struct wg_format + WG_VIDEO_FORMAT_YVYU, + + WG_VIDEO_FORMAT_CINEPAK, ++ ++ WG_VIDEO_FORMAT_H264, + } format; + uint32_t width, height; + uint32_t fps_n, fps_d; ++ union ++ { ++ struct ++ { ++ uint32_t profile; ++ uint32_t level; ++ } h264; ++ } compressed; + } video; + struct + { +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index 40bb7969fc3..9a599358c61 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -533,6 +533,7 @@ video_formats[] = + {&MFVideoFormat_YUY2, WG_VIDEO_FORMAT_YUY2}, + {&MFVideoFormat_YV12, WG_VIDEO_FORMAT_YV12}, + {&MFVideoFormat_YVYU, WG_VIDEO_FORMAT_YVYU}, ++ {&MFVideoFormat_H264, WG_VIDEO_FORMAT_H264}, + }; + + static const struct +@@ -718,10 +719,22 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_forma + if (IsEqualGUID(&subtype, video_formats[i].subtype)) + { + format->u.video.format = video_formats[i].format; +- return; ++ break; + } + } +- FIXME("Unrecognized video subtype %s.\n", debugstr_guid(&subtype)); ++ if (i == ARRAY_SIZE(video_formats)) ++ FIXME("Unrecognized video subtype %s.\n", debugstr_guid(&subtype)); ++ ++ if (format->u.video.format == WG_VIDEO_FORMAT_H264) ++ { ++ UINT32 profile, level; ++ ++ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) ++ format->u.video.compressed.h264.profile = profile; ++ ++ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) ++ format->u.video.compressed.h264.level = level; ++ } + } + + void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) +diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c +index 5f9535659b4..4eceeae0757 100644 +--- a/dlls/winegstreamer/quartz_parser.c ++++ b/dlls/winegstreamer/quartz_parser.c +@@ -268,6 +268,7 @@ static unsigned int get_image_size(const struct wg_format *format) + return width * height * 3; + + case WG_VIDEO_FORMAT_UNKNOWN: ++ case WG_VIDEO_FORMAT_H264: + break; + } + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index c83afe4e195..e9689c01085 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -384,6 +384,22 @@ static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t + } + } + ++static void wg_set_caps_from_wg_format(GstCaps *caps, const struct wg_format *format) ++{ ++ switch (format->major_type) ++ { ++ case WG_MAJOR_TYPE_VIDEO: ++ { ++ gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); ++ gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); ++ gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); ++ break; ++ } ++ default: ++ break; ++ } ++} ++ + static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) + { + GstAudioChannelPosition positions[32]; +@@ -425,6 +441,65 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) + unsigned int i; + GstCaps *caps; + ++ /* compressed types */ ++ ++ if (format->u.video.format == WG_VIDEO_FORMAT_H264) ++ { ++ const char *profile; ++ const char *level; ++ ++ caps = gst_caps_new_empty_simple("video/x-h264"); ++ wg_set_caps_from_wg_format(caps, format); ++ ++ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); ++ gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL); ++ ++ switch (format->u.video.compressed.h264.profile) ++ { ++ case /* eAVEncH264VProfile_Main */ 77: profile = "main"; break; ++ case /* eAVEncH264VProfile_High */ 100: profile = "high"; break; ++ case /* eAVEncH264VProfile_444 */ 244: profile = "high-4:4:4"; break; ++ default: ++ ERR("Unrecognized H.264 profile attribute %u\n", format->u.video.compressed.h264.profile); ++ /* fallthrough */ ++ case 0: profile = NULL; ++ } ++ ++ switch (format->u.video.compressed.h264.level) ++ { ++ case /* eAVEncH264VLevel1 */ 10: level = "1"; break; ++ case /* eAVEncH264VLevel1_1 */ 11: level = "1.1"; break; ++ case /* eAVEncH264VLevel1_2 */ 12: level = "1.2"; break; ++ case /* eAVEncH264VLevel1_3 */ 13: level = "1.3"; break; ++ case /* eAVEncH264VLevel2 */ 20: level = "2"; break; ++ case /* eAVEncH264VLevel2_1 */ 21: level = "2.1"; break; ++ case /* eAVEncH264VLevel2_2 */ 22: level = "2.2"; break; ++ case /* eAVEncH264VLevel3 */ 30: level = "3"; break; ++ case /* eAVEncH264VLevel3_1 */ 31: level = "3.1"; break; ++ case /* eAVEncH264VLevel3_2 */ 32: level = "3.2"; break; ++ case /* eAVEncH264VLevel4 */ 40: level = "4"; break; ++ case /* eAVEncH264VLevel4_1 */ 41: level = "4.1"; break; ++ case /* eAVEncH264VLevel4_2 */ 42: level = "4.2"; break; ++ case /* eAVEncH264VLevel5 */ 50: level = "5"; break; ++ case /* eAVEncH264VLevel5_1 */ 51: level = "5.1"; break; ++ case /* eAVEncH264VLevel5_2 */ 52: level = "5.2"; break; ++ default: ++ ERR("Unrecognized H.264 level attribute %u\n", format->u.video.compressed.h264.level); ++ /* fallthrough */ ++ case 0: level = NULL; ++ } ++ ++ if (profile) ++ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); ++ ++ if (level) ++ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); ++ ++ return caps; ++ } ++ ++ /* uncompressed types */ ++ + if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) + return NULL; + +@@ -584,6 +659,7 @@ static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const + case WG_VIDEO_FORMAT_YVYU: + case WG_VIDEO_FORMAT_UNKNOWN: + case WG_VIDEO_FORMAT_CINEPAK: ++ case WG_VIDEO_FORMAT_H264: + gst_util_set_object_arg(G_OBJECT(stream->flip), "method", "none"); + break; + } +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch b/patches/mfplat-streaming-support/0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch new file mode 100644 index 00000000..8a679c90 --- /dev/null +++ b/patches/mfplat-streaming-support/0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch @@ -0,0 +1,116 @@ +From 8a60a8ea1f93394afae504330ad623e4e85170d6 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 11 Mar 2021 12:58:32 -0500 +Subject: [PATCH 07/39] winegstreamer: Implement ::SetOutputType for decode + transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 76 +++++++++++++++++++++++++-- + 1 file changed, 73 insertions(+), 3 deletions(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index f709ef32fc1..0848cb47c9d 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -56,7 +56,7 @@ struct mf_decoder + IMFTransform IMFTransform_iface; + LONG refcount; + enum decoder_type type; +- IMFMediaType *input_type; ++ IMFMediaType *input_type, *output_type; + CRITICAL_SECTION cs; + }; + +@@ -107,6 +107,12 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) + decoder->input_type = NULL; + } + ++ if (decoder->output_type) ++ { ++ IMFMediaType_Release(decoder->output_type); ++ decoder->output_type = NULL; ++ } ++ + DeleteCriticalSection(&decoder->cs); + + heap_free(decoder); +@@ -336,9 +342,73 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF + + static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) + { +- FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ struct wg_format output_format; ++ GUID major_type, subtype; ++ HRESULT hr; ++ unsigned int i; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %p, %#x.\n", decoder, id, type, flags); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (!type) ++ { ++ if (flags & MFT_SET_TYPE_TEST_ONLY) ++ return S_OK; ++ ++ EnterCriticalSection(&decoder->cs); ++ ++ if (decoder->output_type) ++ { ++ IMFMediaType_Release(decoder->output_type); ++ decoder->output_type = NULL; ++ } ++ ++ LeaveCriticalSection(&decoder->cs); ++ ++ return S_OK; ++ } ++ ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) ++ return MF_E_INVALIDTYPE; ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) ++ return MF_E_INVALIDTYPE; ++ ++ if (!(IsEqualGUID(&major_type, decoder_descs[decoder->type].major_type))) ++ return MF_E_INVALIDTYPE; ++ ++ for (i = 0; i < decoder_descs[decoder->type].output_types_count; i++) ++ { ++ if (IsEqualGUID(&subtype, decoder_descs[decoder->type].output_types[i])) ++ break; ++ if (i == decoder_descs[decoder->type].output_types_count) ++ return MF_E_INVALIDTYPE; ++ } ++ ++ mf_media_type_to_wg_format(type, &output_format); ++ if (!output_format.major_type) ++ return MF_E_INVALIDTYPE; ++ ++ if (flags & MFT_SET_TYPE_TEST_ONLY) ++ return S_OK; ++ ++ EnterCriticalSection(&decoder->cs); ++ ++ hr = S_OK; ++ ++ if (!decoder->output_type) ++ hr = MFCreateMediaType(&decoder->output_type); ++ ++ if (SUCCEEDED(hr) && FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes*) decoder->output_type))) ++ { ++ IMFMediaType_Release(decoder->output_type); ++ decoder->output_type = NULL; ++ } ++ ++ LeaveCriticalSection(&decoder->cs); ++ return hr; + } + + static HRESULT WINAPI mf_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch b/patches/mfplat-streaming-support/0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch new file mode 100644 index 00000000..78d23e6a --- /dev/null +++ b/patches/mfplat-streaming-support/0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch @@ -0,0 +1,106 @@ +From 7bb5efd92e23dfb1f734119000ec4866392f8d7c Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 11 Mar 2021 14:40:32 -0500 +Subject: [PATCH 08/39] winegstreamer: Implement ::Get(Input/Output)StreamInfo + for decode transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 61 +++++++++++++++++++++++++-- + 1 file changed, 57 insertions(+), 4 deletions(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index 0848cb47c9d..dadd161bcc9 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -58,6 +58,7 @@ struct mf_decoder + enum decoder_type type; + IMFMediaType *input_type, *output_type; + CRITICAL_SECTION cs; ++ BOOL video; + }; + + static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) +@@ -150,16 +151,67 @@ static HRESULT WINAPI mf_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_s + + static HRESULT WINAPI mf_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) + { +- FIXME("%p %u %p.\n", iface, id, info); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); + +- return E_NOTIMPL; ++ TRACE("%p %u %p\n", decoder, id, info); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF; ++ info->cbAlignment = 0; ++ info->cbSize = 0; ++ /* TODO: retrieve following fields from gstreamer */ ++ info->hnsMaxLatency = 0; ++ info->cbMaxLookahead = 0; ++ return S_OK; + } + + static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) + { +- FIXME("%p %u %p.\n", iface, id, info); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ MFT_OUTPUT_STREAM_INFO stream_info = {}; ++ GUID output_subtype; ++ UINT64 framesize; + +- return E_NOTIMPL; ++ TRACE("%p %u %p\n", decoder, id, info); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ EnterCriticalSection(&decoder->cs); ++ ++ if (!decoder->output_type) ++ { ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ } ++ ++ if (decoder->video) ++ { ++ stream_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | ++ MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES; ++ stream_info.cbSize = 0; ++ if (SUCCEEDED(IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &output_subtype)) && ++ SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &framesize))) ++ { ++ MFCalculateImageSize(&output_subtype, framesize >> 32, (UINT32) framesize, &stream_info.cbSize); ++ } ++ if (!stream_info.cbSize) ++ ERR("Failed to get desired output buffer size\n"); ++ } ++ else ++ { ++ stream_info.dwFlags = MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES; ++ stream_info.cbSize = 4; ++ } ++ stream_info.cbAlignment = 0; ++ ++ LeaveCriticalSection(&decoder->cs); ++ ++ *info = stream_info; ++ ++ return S_OK; + } + + static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +@@ -518,6 +570,7 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) + object->refcount = 1; + + object->type = type; ++ object->video = decoder_descs[type].major_type == &MFMediaType_Video; + + InitializeCriticalSection(&object->cs); + +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch b/patches/mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch new file mode 100644 index 00000000..d2cdfcf4 --- /dev/null +++ b/patches/mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch @@ -0,0 +1,869 @@ +From 431374b54bf2c58515c9bd56acf45d15f2fdf42d Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 16:40:46 -0400 +Subject: [PATCH 09/39] winegstreamer: Add push-mode path for wg_parser. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/gst_private.h | 28 +- + dlls/winegstreamer/media_source.c | 4 +- + dlls/winegstreamer/quartz_parser.c | 4 +- + dlls/winegstreamer/wg_parser.c | 426 +++++++++++++++++++++++++---- + 4 files changed, 408 insertions(+), 54 deletions(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 215cf4577d4..25694aae84d 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -136,6 +136,14 @@ struct wg_format + } u; + }; + ++struct wg_rect ++{ ++ uint32_t left; ++ uint32_t right; ++ uint32_t top; ++ uint32_t bottom; ++}; ++ + enum wg_parser_event_type + { + WG_PARSER_EVENT_NONE = 0, +@@ -165,6 +173,14 @@ struct wg_parser_event + }; + C_ASSERT(sizeof(struct wg_parser_event) == 40); + ++enum wg_read_result ++{ ++ WG_READ_SUCCESS, ++ WG_READ_FAILURE, ++ WG_READ_FLUSHING, ++ WG_READ_EOS, ++}; ++ + struct unix_funcs + { + struct wg_parser *(CDECL *wg_decodebin_parser_create)(void); +@@ -174,6 +190,8 @@ struct unix_funcs + void (CDECL *wg_parser_destroy)(struct wg_parser *parser); + + HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size); ++ HRESULT (CDECL *wg_parser_connect_unseekable)(struct wg_parser *parser, ++ const struct wg_format *in_format, uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures); + void (CDECL *wg_parser_disconnect)(struct wg_parser *parser); + + void (CDECL *wg_parser_begin_flush)(struct wg_parser *parser); +@@ -181,7 +199,11 @@ struct unix_funcs + + bool (CDECL *wg_parser_get_read_request)(struct wg_parser *parser, + void **data, uint64_t *offset, uint32_t *size); +- void (CDECL *wg_parser_complete_read_request)(struct wg_parser *parser, bool ret); ++ /* bytes_available indicates the actual size of the input packet, or 0 if the source source pad isn't aware of packets. ++ If this value is lower or equal to the requested buffer size, it signifies the number of valid bytes set, if this ++ value is higher than the requested buffer size, it means that a push mode pad should query for the rest of packet, ++ concatenate the result, then submit it downstream. */ ++ void (CDECL *wg_parser_complete_read_request)(struct wg_parser *parser, enum wg_read_result ret, uint32_t bytes_available); + + void (CDECL *wg_parser_set_unlimited_buffering)(struct wg_parser *parser); + +@@ -189,7 +211,7 @@ struct unix_funcs + struct wg_parser_stream *(CDECL *wg_parser_get_stream)(struct wg_parser *parser, uint32_t index); + + void (CDECL *wg_parser_stream_get_preferred_format)(struct wg_parser_stream *stream, struct wg_format *format); +- void (CDECL *wg_parser_stream_enable)(struct wg_parser_stream *stream, const struct wg_format *format); ++ void (CDECL *wg_parser_stream_enable)(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture); + void (CDECL *wg_parser_stream_disable)(struct wg_parser_stream *stream); + + bool (CDECL *wg_parser_stream_get_event)(struct wg_parser_stream *stream, struct wg_parser_event *event); +@@ -204,6 +226,8 @@ struct unix_funcs + /* start_pos and stop_pos are in 100-nanosecond units. */ + bool (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); ++ /* true: The stream has fully drained or has been flushed. false: An event is available. */ ++ bool (CDECL *wg_parser_stream_drain)(struct wg_parser_stream *stream); + }; + + extern const struct unix_funcs *unix_funcs; +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index 9c554c7c415..f658cc0a5fc 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -305,7 +305,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm + IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt); + + mf_media_type_to_wg_format(current_mt, &format); +- unix_funcs->wg_parser_stream_enable(stream->wg_stream, &format); ++ unix_funcs->wg_parser_stream_enable(stream->wg_stream, &format, NULL); + + IMFMediaType_Release(current_mt); + IMFMediaTypeHandler_Release(mth); +@@ -548,7 +548,7 @@ static DWORD CALLBACK read_thread(void *arg) + hr = IMFByteStream_Read(byte_stream, data, size, &ret_size); + if (SUCCEEDED(hr) && ret_size != size) + ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); +- unix_funcs->wg_parser_complete_read_request(source->wg_parser, SUCCEEDED(hr)); ++ unix_funcs->wg_parser_complete_read_request(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, ret_size); + } + + TRACE("Media source is shutting down; exiting.\n"); +diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c +index 4eceeae0757..1c68eba1872 100644 +--- a/dlls/winegstreamer/quartz_parser.c ++++ b/dlls/winegstreamer/quartz_parser.c +@@ -799,7 +799,7 @@ static DWORD CALLBACK read_thread(void *arg) + if (!unix_funcs->wg_parser_get_read_request(filter->wg_parser, &data, &offset, &size)) + continue; + hr = IAsyncReader_SyncRead(filter->reader, offset, size, data); +- unix_funcs->wg_parser_complete_read_request(filter->wg_parser, SUCCEEDED(hr)); ++ unix_funcs->wg_parser_complete_read_request(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, size); + } + + TRACE("Streaming stopped; exiting.\n"); +@@ -1447,7 +1447,7 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface, + + ret = amt_to_wg_format(&pin->pin.pin.mt, &format); + assert(ret); +- unix_funcs->wg_parser_stream_enable(pin->wg_stream, &format); ++ unix_funcs->wg_parser_stream_enable(pin->wg_stream, &format, NULL); + + /* We do need to drop any buffers that might have been sent with the old + * caps, but this will be handled in parser_init_stream(). */ +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index e9689c01085..9ca5abebfaf 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -44,7 +44,7 @@ struct wg_parser + BOOL (*init_gst)(struct wg_parser *parser); + + struct wg_parser_stream **streams; +- unsigned int stream_count; ++ unsigned int stream_count, expected_stream_count; + + GstElement *container, *decodebin; + GstBus *bus; +@@ -58,7 +58,7 @@ struct wg_parser + pthread_mutex_t mutex; + + pthread_cond_t init_cond; +- bool no_more_pads, has_duration, error, pull_mode; ++ bool no_more_pads, has_duration, error, pull_mode, seekable; + + pthread_cond_t read_cond, read_done_cond; + struct +@@ -67,10 +67,12 @@ struct wg_parser + uint64_t offset; + uint32_t size; + bool done; +- bool ret; ++ enum wg_read_result ret; + } read_request; + +- bool flushing, sink_connected; ++ bool flushing, sink_connected, draining; ++ ++ struct wg_format input_format; + }; + + struct wg_parser_stream +@@ -78,9 +80,10 @@ struct wg_parser_stream + struct wg_parser *parser; + + GstPad *their_src, *post_sink, *post_src, *my_sink; +- GstElement *flip; ++ GstElement *flip, *box; + GstSegment segment; + struct wg_format preferred_format, current_format; ++ struct wg_rect aperture; + + pthread_cond_t event_cond, event_empty_cond; + struct wg_parser_event event; +@@ -571,6 +574,9 @@ static void CDECL wg_parser_begin_flush(struct wg_parser *parser) + { + unsigned int i; + ++ if (!parser->seekable) ++ return; ++ + pthread_mutex_lock(&parser->mutex); + parser->flushing = true; + pthread_mutex_unlock(&parser->mutex); +@@ -584,6 +590,9 @@ static void CDECL wg_parser_begin_flush(struct wg_parser *parser) + + static void CDECL wg_parser_end_flush(struct wg_parser *parser) + { ++ if (!parser->seekable) ++ return; ++ + pthread_mutex_lock(&parser->mutex); + parser->flushing = false; + pthread_mutex_unlock(&parser->mutex); +@@ -594,7 +603,7 @@ static bool CDECL wg_parser_get_read_request(struct wg_parser *parser, + { + pthread_mutex_lock(&parser->mutex); + +- while (parser->sink_connected && !parser->read_request.data) ++ while (parser->sink_connected && (!parser->read_request.data || parser->read_request.done)) + pthread_cond_wait(&parser->read_cond, &parser->mutex); + + if (!parser->sink_connected) +@@ -611,14 +620,25 @@ static bool CDECL wg_parser_get_read_request(struct wg_parser *parser, + return true; + } + +-static void CDECL wg_parser_complete_read_request(struct wg_parser *parser, bool ret) ++static void CDECL wg_parser_complete_read_request(struct wg_parser *parser, enum wg_read_result ret, uint32_t bytes_available) + { + pthread_mutex_lock(&parser->mutex); +- parser->read_request.done = true; + parser->read_request.ret = ret; +- parser->read_request.data = NULL; +- pthread_mutex_unlock(&parser->mutex); ++ if (ret == WG_READ_SUCCESS && bytes_available < parser->read_request.size) ++ { ++ parser->read_request.offset += bytes_available; ++ parser->read_request.size -= bytes_available; ++ parser->read_request.data = (unsigned char *)parser->read_request.data + bytes_available; ++ } ++ else ++ { ++ parser->read_request.data = NULL; ++ /* reuse size parameter to indicate how many more bytes are left to write */ ++ parser->read_request.size = bytes_available; ++ } ++ parser->read_request.done = true; + pthread_cond_signal(&parser->read_done_cond); ++ pthread_mutex_unlock(&parser->mutex); + } + + static void CDECL wg_parser_set_unlimited_buffering(struct wg_parser *parser) +@@ -630,11 +650,15 @@ static void CDECL wg_parser_set_unlimited_buffering(struct wg_parser *parser) + + static void CDECL wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) + { +- *format = stream->preferred_format; ++ if (stream->has_caps) ++ *format = stream->preferred_format; + } + +-static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) ++static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture) + { ++ if (!stream->parser->seekable) ++ return; ++ + stream->current_format = *format; + stream->enabled = true; + +@@ -663,6 +687,18 @@ static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const + gst_util_set_object_arg(G_OBJECT(stream->flip), "method", "none"); + break; + } ++ ++ if (aperture) ++ { ++ if (aperture->left) ++ g_object_set(G_OBJECT(stream->box), "left", -aperture->left, NULL); ++ if (aperture->top) ++ g_object_set(G_OBJECT(stream->box), "top", -aperture->top, NULL); ++ if (aperture->right) ++ g_object_set(G_OBJECT(stream->box), "right", aperture->right - format->u.video.width, NULL); ++ if (aperture->bottom) ++ g_object_set(G_OBJECT(stream->box), "bottom", aperture->bottom - format->u.video.height, NULL); ++ } + } + + gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure()); +@@ -691,6 +727,11 @@ static bool CDECL wg_parser_stream_get_event(struct wg_parser_stream *stream, st + + *event = stream->event; + ++ /* Set to ensure that drain isn't called on an EOS stream, causing a lock-up ++ due to pull_data never being called again */ ++ if (stream->event.type == WG_PARSER_EVENT_EOS) ++ stream->eos = true; ++ + if (stream->event.type != WG_PARSER_EVENT_BUFFER) + { + stream->event.type = WG_PARSER_EVENT_NONE; +@@ -751,6 +792,9 @@ static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double + GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET; + GstSeekFlags flags = 0; + ++ if (!stream->parser->seekable) ++ return false; ++ + if (start_flags & AM_SEEKING_SeekToKeyFrame) + flags |= GST_SEEK_FLAG_KEY_UNIT; + if (start_flags & AM_SEEKING_Segment) +@@ -767,6 +811,43 @@ static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double + GST_FORMAT_TIME, flags, start_type, start_pos * 100, stop_type, stop_pos * 100)); + } + ++static bool CDECL wg_parser_stream_drain(struct wg_parser_stream *stream) ++{ ++ struct wg_parser *parser = stream->parser; ++ bool ret; ++ ++ pthread_mutex_lock(&parser->mutex); ++ ++ /* Sanity check making sure caller didn't try to drain an already-EOS or unselected stream. ++ There's no reason for a caller to do this, but it could be an accident in which case we ++ should indicate that the stream is drained instead of locking-up. */ ++ if (!stream->enabled || stream->eos) ++ { ++ pthread_mutex_unlock(&parser->mutex); ++ return true; ++ } ++ ++ parser->draining = true; ++ pthread_cond_signal(&parser->read_done_cond); ++ ++ /* We must wait for either an event to occur or the drain to complete. ++ Since drains are blocking, we assign this responsibility to the thread ++ pulling data, as the pipeline will not need to pull more data until ++ the drain completes. If one input buffer yields more than one output ++ buffer, the chain callback blocks on the wg_parser_stream_buffer_release ++ for the first buffer, which would never be called if the drain function ++ hadn't completed. */ ++ while (!parser->flushing && parser->draining && stream->event.type == WG_PARSER_EVENT_NONE) ++ pthread_cond_wait(&stream->event_cond, &parser->mutex); ++ ++ ret = stream->event.type == WG_PARSER_EVENT_NONE; ++ parser->draining = false; ++ ++ pthread_mutex_unlock(&stream->parser->mutex); ++ ++ return ret; ++} ++ + static void CDECL wg_parser_stream_notify_qos(struct wg_parser_stream *stream, + bool underflow, double proportion, int64_t diff, uint64_t timestamp) + { +@@ -1071,14 +1152,27 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + static struct wg_parser_stream *create_stream(struct wg_parser *parser) + { + struct wg_parser_stream *stream, **new_array; ++ unsigned int i; + char pad_name[19]; + +- if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams)))) +- return NULL; +- parser->streams = new_array; ++ for (i = 0; i < parser->expected_stream_count; i++) ++ { ++ if (!parser->streams[i]->parser) ++ { ++ stream = parser->streams[i]; ++ break; ++ } ++ } + +- if (!(stream = calloc(1, sizeof(*stream)))) +- return NULL; ++ if (i == parser->expected_stream_count) ++ { ++ if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams)))) ++ return NULL; ++ parser->streams = new_array; ++ ++ if (!(stream = calloc(1, sizeof(*stream)))) ++ return NULL; ++ } + + gst_segment_init(&stream->segment, GST_FORMAT_UNDEFINED); + +@@ -1118,7 +1212,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + + if (!strcmp(name, "video/x-raw")) + { +- GstElement *deinterlace, *vconv, *flip, *vconv2; ++ GstElement *deinterlace, *vconv, *flip, *videobox, *vconv2; + + /* DirectShow can express interlaced video, but downstream filters can't + * necessarily consume it. In particular, the video renderer can't. */ +@@ -1147,6 +1241,13 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + goto out; + } + ++ if (!(videobox = gst_element_factory_make("videobox", NULL))) ++ { ++ fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"base\" plugins installed?\n", ++ 8 * (int)sizeof(void *)); ++ goto out; ++ } ++ + /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert + * to do the final conversion. */ + if (!(vconv2 = gst_element_factory_make("videoconvert", NULL))) +@@ -1156,6 +1257,18 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + goto out; + } + ++ if (!parser->seekable) ++ { ++ if (stream->aperture.left) ++ g_object_set(G_OBJECT(videobox), "left", -stream->aperture.left, NULL); ++ if (stream->aperture.bottom) ++ g_object_set(G_OBJECT(videobox), "top", -stream->aperture.top, NULL); ++ if (stream->aperture.right) ++ g_object_set(G_OBJECT(videobox), "right", stream->aperture.right - stream->current_format.u.video.width, NULL); ++ if (stream->aperture.bottom) ++ g_object_set(G_OBJECT(videobox), "bottom", stream->aperture.bottom - stream->current_format.u.video.height, NULL); ++ } ++ + /* The bin takes ownership of these elements. */ + gst_bin_add(GST_BIN(parser->container), deinterlace); + gst_element_sync_state_with_parent(deinterlace); +@@ -1163,16 +1276,20 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + gst_element_sync_state_with_parent(vconv); + gst_bin_add(GST_BIN(parser->container), flip); + gst_element_sync_state_with_parent(flip); ++ gst_bin_add(GST_BIN(parser->container), videobox); ++ gst_element_sync_state_with_parent(videobox); + gst_bin_add(GST_BIN(parser->container), vconv2); + gst_element_sync_state_with_parent(vconv2); + + gst_element_link(deinterlace, vconv); + gst_element_link(vconv, flip); +- gst_element_link(flip, vconv2); ++ gst_element_link(flip, videobox); ++ gst_element_link(videobox, vconv2); + + stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); + stream->post_src = gst_element_get_static_pad(vconv2, "src"); + stream->flip = flip; ++ stream->box = videobox; + } + else if (!strcmp(name, "audio/x-raw")) + { +@@ -1260,23 +1377,25 @@ static void pad_removed_cb(GstElement *element, GstPad *pad, gpointer user) + g_free(name); + } + +-static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, +- guint64 offset, guint size, GstBuffer **buffer) ++static GstFlowReturn pull_data(struct wg_parser *parser, guint64 offset, guint size, guint *size_read, GstBuffer **buffer) + { +- struct wg_parser *parser = gst_pad_get_element_private(pad); + GstBuffer *new_buffer = NULL; ++ enum wg_read_result ret; + GstMapInfo map_info; +- bool ret; ++ unsigned int i; + +- GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", pad, offset, size, *buffer); ++ GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", parser->my_src, offset, size, *buffer); + + if (offset == GST_BUFFER_OFFSET_NONE) + offset = parser->next_pull_offset; + parser->next_pull_offset = offset + size; +- if (offset >= parser->file_size) +- return GST_FLOW_EOS; +- if (offset + size >= parser->file_size) +- size = parser->file_size - offset; ++ if (parser->seekable) ++ { ++ if (offset >= parser->file_size) ++ return GST_FLOW_EOS; ++ if (offset + size >= parser->file_size) ++ size = parser->file_size - offset; ++ } + + if (!*buffer) + *buffer = new_buffer = gst_buffer_new_and_alloc(size); +@@ -1285,6 +1404,14 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + + pthread_mutex_lock(&parser->mutex); + ++ if (parser->draining) ++ { ++ gst_pad_peer_query(parser->my_src, gst_query_new_drain()); ++ parser->draining = false; ++ for (i = 0; i < parser->stream_count; i++) ++ pthread_cond_signal(&parser->streams[i]->event_cond); ++ } ++ + assert(!parser->read_request.data); + parser->read_request.data = map_info.data; + parser->read_request.offset = offset; +@@ -1296,8 +1423,36 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + * the upstream pin to flush if necessary. We should never be blocked on + * read_thread() not running. */ + +- while (!parser->read_request.done) ++ while (!parser->read_request.done && !parser->draining) ++ { + pthread_cond_wait(&parser->read_done_cond, &parser->mutex); ++ if (parser->draining) ++ { ++ gst_pad_peer_query(parser->my_src, gst_query_new_drain()); ++ parser->draining = false; ++ for (i = 0; i < parser->stream_count; i++) ++ pthread_cond_signal(&parser->streams[i]->event_cond); ++ } ++ if (size != parser->read_request.size && parser->read_request.data) ++ { ++ if (size_read) ++ { ++ *size_read = size - parser->read_request.size; ++ parser->read_request.done = true; ++ break; ++ } ++ else ++ { ++ parser->read_request.done = false; ++ pthread_cond_signal(&parser->read_cond); ++ } ++ } ++ } ++ ++ parser->read_request.data = NULL; ++ ++ if (size_read && parser->read_request.size > size) ++ *size_read = parser->read_request.size; + + ret = parser->read_request.ret; + +@@ -1305,12 +1460,29 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + + gst_buffer_unmap(*buffer, &map_info); + ++ if (size_read) ++ size = min(*size_read, size); ++ ++ gst_buffer_set_size(*buffer, size); ++ + GST_LOG("Request returned %d.", ret); + +- if (!ret && new_buffer) ++ if (ret != WG_READ_SUCCESS && new_buffer) + gst_buffer_unref(new_buffer); + +- return ret ? GST_FLOW_OK : GST_FLOW_ERROR; ++ return ret == WG_READ_SUCCESS ? GST_FLOW_OK : ++ ret == WG_READ_FAILURE ? GST_FLOW_ERROR : ++ ret == WG_READ_FLUSHING ? GST_FLOW_FLUSHING : ++ ret == WG_READ_EOS ? GST_FLOW_EOS : ++ GST_FLOW_ERROR; ++} ++ ++static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, ++ guint64 offset, guint size, GstBuffer **buffer) ++{ ++ struct wg_parser *parser = gst_pad_get_element_private(pad); ++ ++ return pull_data(parser, offset, size, NULL, buffer); + } + + static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) +@@ -1329,7 +1501,7 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX); + return TRUE; + } +- else if (format == GST_FORMAT_BYTES) ++ else if (format == GST_FORMAT_BYTES && parser->seekable) + { + gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size); + return TRUE; +@@ -1343,15 +1515,42 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format)); + return FALSE; + } ++ if (!parser->seekable) ++ return FALSE; + gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size); + return TRUE; + + case GST_QUERY_SCHEDULING: +- gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); ++ gst_query_set_scheduling(query, parser->seekable ? GST_SCHEDULING_FLAG_SEEKABLE : GST_SCHEDULING_FLAG_SEQUENTIAL, 1, -1, 0); + gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); + gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL); + return TRUE; + ++ case GST_QUERY_CAPS: ++ { ++ GstCaps *caps, *filter, *temp; ++ ++ gst_query_parse_caps(query, &filter); ++ ++ if (parser->input_format.major_type) ++ caps = wg_format_to_caps(&parser->input_format); ++ else ++ caps = gst_caps_new_any(); ++ if (!caps) ++ return FALSE; ++ ++ if (filter) ++ { ++ temp = gst_caps_intersect(caps, filter); ++ gst_caps_unref(caps); ++ caps = temp; ++ } ++ ++ gst_query_set_caps_result(query, caps); ++ gst_caps_unref(caps); ++ return TRUE; ++ } ++ + default: + GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query)); + return FALSE; +@@ -1361,42 +1560,115 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) + static void *push_data(void *arg) + { + struct wg_parser *parser = arg; +- GstBuffer *buffer; ++ GstBuffer *last_buffer = NULL; ++ ULONG alloc_size = 16384; + GstSegment *segment; + guint max_size; + + GST_DEBUG("Starting push thread."); + +- if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL))) +- { +- GST_ERROR("Failed to allocate memory."); +- return NULL; +- } +- + max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; + + gst_pad_push_event(parser->my_src, gst_event_new_stream_start("wg_stream")); + ++ if (parser->input_format.major_type) ++ gst_pad_push_event(parser->my_src, gst_event_new_caps(wg_format_to_caps(&parser->input_format))); ++ + segment = gst_segment_new(); + gst_segment_init(segment, GST_FORMAT_BYTES); + gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); + ++ assert(!(GST_PAD_IS_FLUSHING(parser->my_src))); ++ + for (;;) + { ++ GstBuffer *buffer = NULL; ++ unsigned int i; + ULONG size; + int ret; + + if (parser->next_offset >= max_size) + break; +- size = min(16384, max_size - parser->next_offset); ++ size = min(alloc_size, max_size - parser->next_offset); + +- if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0) ++ ret = pull_data(parser, parser->next_offset, size, &size, &buffer); ++ ++ /* When we are in unseekable push mode, the pushing pad is responsible for handling flushing. */ ++ if (!parser->seekable && ret == GST_FLOW_FLUSHING) + { ++ if (last_buffer) ++ { ++ gst_buffer_unref(last_buffer); ++ last_buffer = NULL; ++ } ++ ++ gst_pad_push_event(parser->my_src, gst_event_new_seek(1.0f, ++ GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0)); ++ ++ continue; ++ } ++ ++ if (!parser->seekable && ret == GST_FLOW_EOS) ++ { ++ if (last_buffer) ++ { ++ gst_buffer_unref(last_buffer); ++ last_buffer = NULL; ++ } ++ ++ gst_pad_push_event(parser->my_src, gst_event_new_eos()); ++ pthread_mutex_lock(&parser->mutex); ++ for (i = 0; i < parser->stream_count; i++) ++ { ++ if (!parser->streams[i]->enabled) ++ continue; ++ while (!parser->streams[i]->flushing && !parser->streams[i]->eos) ++ pthread_cond_wait(&parser->streams[i]->event_empty_cond, &parser->mutex); ++ parser->streams[i]->eos = false; ++ } ++ ++ if (parser->flushing) ++ { ++ pthread_mutex_unlock(&parser->mutex); ++ continue; ++ } ++ ++ pthread_mutex_unlock(&parser->mutex); ++ ++ segment = gst_segment_new(); ++ gst_segment_init(segment, GST_FORMAT_BYTES); ++ gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); ++ ++ continue; ++ } ++ ++ if (ret < 0) ++ { ++ if (last_buffer) ++ { ++ gst_buffer_unref(last_buffer); ++ last_buffer = NULL; ++ } ++ + GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret)); + break; + } + +- parser->next_offset += size; ++ parser->next_offset += gst_buffer_get_size(buffer); ++ ++ if (last_buffer) ++ { ++ buffer = gst_buffer_append(last_buffer, buffer); ++ last_buffer = NULL; ++ assert(alloc_size >= size); ++ } ++ ++ if (size > gst_buffer_get_size(buffer)) ++ { ++ last_buffer = buffer; ++ alloc_size = (size + 0xfff) & ~0xfff; ++ continue; ++ } + + buffer->duration = buffer->pts = -1; + if ((ret = gst_pad_push(parser->my_src, buffer)) < 0) +@@ -1406,8 +1678,6 @@ static void *push_data(void *arg) + } + } + +- gst_buffer_unref(buffer); +- + gst_pad_push_event(parser->my_src, gst_event_new_eos()); + + GST_DEBUG("Stopping push thread."); +@@ -1423,6 +1693,12 @@ static gboolean activate_push(GstPad *pad, gboolean activate) + { + if (parser->push_thread) + { ++ pthread_mutex_lock(&parser->mutex); ++ parser->read_request.ret = WG_READ_FAILURE; ++ parser->read_request.data = NULL; ++ parser->read_request.done = true; ++ pthread_mutex_unlock(&parser->mutex); ++ pthread_cond_signal(&parser->read_done_cond); + pthread_join(parser->push_thread, NULL); + parser->push_thread = 0; + } +@@ -1608,13 +1884,11 @@ static LONGLONG query_duration(GstPad *pad) + return 0; + } + +-static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size) ++static HRESULT wg_parser_connect_inner(struct wg_parser *parser) + { + GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", + GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); +- unsigned int i; + +- parser->file_size = file_size; + parser->sink_connected = true; + + if (!parser->bus) +@@ -1636,6 +1910,20 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + parser->start_offset = parser->next_offset = parser->stop_offset = 0; + parser->next_pull_offset = 0; + ++ return S_OK; ++} ++ ++static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size) ++{ ++ unsigned int i; ++ HRESULT hr; ++ ++ parser->seekable = true; ++ parser->file_size = file_size; ++ ++ if ((hr = wg_parser_connect_inner(parser))) ++ return hr; ++ + if (!parser->init_gst(parser)) + return E_FAIL; + +@@ -1666,6 +1954,43 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + return S_OK; + } + ++static HRESULT CDECL wg_parser_connect_unseekable(struct wg_parser *parser, ++ const struct wg_format *in_format, uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures) ++{ ++ unsigned int i; ++ HRESULT hr; ++ ++ parser->seekable = false; ++ parser->flushing = false; ++ /* since typefind is not available here, we must have an input_format */ ++ parser->input_format = *in_format; ++ ++ if ((hr = wg_parser_connect_inner(parser))) ++ return hr; ++ ++ parser->stop_offset = -1; ++ ++ parser->expected_stream_count = stream_count; ++ parser->streams = calloc(stream_count, sizeof(*parser->streams)); ++ ++ for (i = 0; i < stream_count; i++) ++ { ++ parser->streams[i] = calloc(1, sizeof(*parser->streams[i])); ++ parser->streams[i]->current_format = out_formats[i]; ++ if (apertures) ++ parser->streams[i]->aperture = apertures[i]; ++ parser->streams[i]->enabled = true; ++ } ++ ++ if (!parser->init_gst(parser)) ++ return E_FAIL; ++ ++ if (parser->stream_count < parser->expected_stream_count) ++ return E_FAIL; ++ ++ return S_OK; ++} ++ + static void free_stream(struct wg_parser_stream *stream) + { + if (stream->their_src) +@@ -1740,6 +2065,9 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + return FALSE; + } + ++ if (parser->input_format.major_type) ++ g_object_set(G_OBJECT(element), "sink-caps", wg_format_to_caps(&parser->input_format), NULL); ++ + gst_bin_add(GST_BIN(parser->container), element); + parser->decodebin = element; + +@@ -2016,6 +2344,7 @@ static const struct unix_funcs funcs = + wg_parser_destroy, + + wg_parser_connect, ++ wg_parser_connect_unseekable, + wg_parser_disconnect, + + wg_parser_begin_flush, +@@ -2040,6 +2369,7 @@ static const struct unix_funcs funcs = + + wg_parser_stream_get_duration, + wg_parser_stream_seek, ++ wg_parser_stream_drain, + }; + + NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch b/patches/mfplat-streaming-support/0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch new file mode 100644 index 00000000..3cba1275 --- /dev/null +++ b/patches/mfplat-streaming-support/0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch @@ -0,0 +1,648 @@ +From 316e739c324ef33e31987f0d5abd7b28db21e89a Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 16:53:02 -0400 +Subject: [PATCH 10/39] winegstreamer: Implement ::Process(Input/Output) for + decoder transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 532 +++++++++++++++++++++++++- + 1 file changed, 526 insertions(+), 6 deletions(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index dadd161bcc9..c30780ba7ff 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -51,14 +51,47 @@ static struct decoder_desc + }, + }; + ++struct pipeline_event ++{ ++ enum ++ { ++ PIPELINE_EVENT_NONE, ++ PIPELINE_EVENT_PARSER_STARTED, ++ PIPELINE_EVENT_READ_REQUEST, ++ } type; ++ union ++ { ++ struct ++ { ++ struct wg_parser_stream *stream; ++ } parser_started; ++ } u; ++}; ++ + struct mf_decoder + { + IMFTransform IMFTransform_iface; + LONG refcount; + enum decoder_type type; + IMFMediaType *input_type, *output_type; +- CRITICAL_SECTION cs; +- BOOL video; ++ CRITICAL_SECTION cs, help_cs, event_cs; ++ CONDITION_VARIABLE help_cv, event_cv; ++ BOOL flushing, draining, eos, helper_thread_shutdown, video; ++ HANDLE helper_thread, read_thread; ++ uint64_t offset_tracker; ++ struct wg_parser *wg_parser; ++ struct wg_parser_stream *wg_stream; ++ ++ struct ++ { ++ enum ++ { ++ HELP_REQ_NONE, ++ HELP_REQ_START_PARSER, ++ } type; ++ } help_request; ++ ++ struct pipeline_event event; + }; + + static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) +@@ -114,7 +147,15 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) + decoder->output_type = NULL; + } + ++ if (decoder->wg_stream) ++ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ ++ if (decoder->wg_parser) ++ unix_funcs->wg_parser_destroy(decoder->wg_parser); ++ + DeleteCriticalSection(&decoder->cs); ++ DeleteCriticalSection(&decoder->help_cs); ++ DeleteCriticalSection(&decoder->event_cs); + + heap_free(decoder); + } +@@ -341,6 +382,12 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF + + EnterCriticalSection(&decoder->cs); + ++ if (decoder->wg_stream) ++ { ++ decoder->wg_stream = NULL; ++ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ } ++ + if (decoder->input_type) + { + IMFMediaType_Release(decoder->input_type); +@@ -379,6 +426,12 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF + + hr = S_OK; + ++ if (decoder->wg_stream) ++ { ++ decoder->wg_stream = NULL; ++ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ } ++ + if (!decoder->input_type) + hr = MFCreateMediaType(&decoder->input_type); + +@@ -388,6 +441,16 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF + decoder->input_type = NULL; + } + ++ if (decoder->input_type && decoder->output_type) ++ { ++ EnterCriticalSection(&decoder->help_cs); ++ while(decoder->help_request.type != HELP_REQ_NONE) ++ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE); ++ decoder->help_request.type = HELP_REQ_START_PARSER; ++ LeaveCriticalSection(&decoder->help_cs); ++ WakeAllConditionVariable(&decoder->help_cv); ++ } ++ + LeaveCriticalSection(&decoder->cs); + return hr; + } +@@ -412,6 +475,12 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM + + EnterCriticalSection(&decoder->cs); + ++ if (decoder->wg_stream) ++ { ++ decoder->wg_stream = NULL; ++ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ } ++ + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); +@@ -450,6 +519,12 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM + + hr = S_OK; + ++ if (decoder->wg_stream) ++ { ++ decoder->wg_stream = NULL; ++ unix_funcs->wg_parser_disconnect(decoder->wg_parser); ++ } ++ + if (!decoder->output_type) + hr = MFCreateMediaType(&decoder->output_type); + +@@ -459,6 +534,16 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM + decoder->output_type = NULL; + } + ++ if (decoder->input_type && decoder->output_type) ++ { ++ EnterCriticalSection(&decoder->help_cs); ++ while(decoder->help_request.type != HELP_REQ_NONE) ++ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE); ++ decoder->help_request.type = HELP_REQ_START_PARSER; ++ LeaveCriticalSection(&decoder->help_cs); ++ WakeAllConditionVariable(&decoder->help_cv); ++ } ++ + LeaveCriticalSection(&decoder->cs); + return hr; + } +@@ -505,6 +590,124 @@ static HRESULT WINAPI mf_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMF + return E_NOTIMPL; + } + ++static DWORD CALLBACK helper_thread_func(PVOID ctx) ++{ ++ struct mf_decoder *decoder = (struct mf_decoder *)ctx; ++ ++ for(;;) ++ { ++ EnterCriticalSection(&decoder->help_cs); ++ ++ while(!decoder->helper_thread_shutdown && decoder->help_request.type == HELP_REQ_NONE) ++ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE); ++ if (decoder->helper_thread_shutdown) ++ return 0; ++ ++ switch(decoder->help_request.type) ++ { ++ case HELP_REQ_START_PARSER: ++ { ++ struct wg_format input_format, output_format; ++ struct wg_rect wg_aperture = {0}; ++ MFVideoArea *aperture = NULL; ++ UINT32 aperture_size; ++ ++ decoder->help_request.type = HELP_REQ_NONE; ++ LeaveCriticalSection(&decoder->help_cs); ++ ++ mf_media_type_to_wg_format(decoder->input_type, &input_format); ++ mf_media_type_to_wg_format(decoder->output_type, &output_format); ++ ++ if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(decoder->output_type, ++ &MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8 **) &aperture, &aperture_size))) ++ { ++ TRACE("Decoded media's aperture: x: %u %u/65536, y: %u %u/65536, area: %u x %u\n", ++ aperture->OffsetX.value, aperture->OffsetX.fract, ++ aperture->OffsetY.value, aperture->OffsetY.fract, aperture->Area.cx, aperture->Area.cy); ++ ++ /* TODO: verify aperture params? */ ++ ++ wg_aperture.left = aperture->OffsetX.value; ++ wg_aperture.top = aperture->OffsetY.value; ++ wg_aperture.right = aperture->Area.cx; ++ wg_aperture.bottom = aperture->Area.cy; ++ ++ CoTaskMemFree(aperture); ++ } ++ ++ unix_funcs->wg_parser_connect_unseekable(decoder->wg_parser, ++ &input_format, 1, &output_format, aperture ? &wg_aperture : NULL); ++ ++ EnterCriticalSection(&decoder->event_cs); ++ while (decoder->event.type != PIPELINE_EVENT_NONE) ++ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); ++ ++ decoder->event.type = PIPELINE_EVENT_PARSER_STARTED; ++ decoder->event.u.parser_started.stream = unix_funcs->wg_parser_get_stream(decoder->wg_parser, 0); ++ ++ LeaveCriticalSection(&decoder->event_cs); ++ WakeAllConditionVariable(&decoder->event_cv); ++ ++ break; ++ } ++ default: ++ assert(0); ++ } ++ } ++} ++ ++/* We use a separate thread to wait for reads, as we may want to wait to WAIT_ANY ++ on a read and another event. */ ++static DWORD CALLBACK read_thread_func(PVOID ctx) ++{ ++ struct mf_decoder *decoder = (struct mf_decoder *)ctx; ++ void *data; ++ uint64_t offset; ++ uint32_t size; ++ ++ for (;;) ++ { ++ if (!unix_funcs->wg_parser_get_read_request(decoder->wg_parser, &data, &offset, &size)) ++ continue; ++ ++ if (decoder->helper_thread_shutdown) ++ break; ++ ++ EnterCriticalSection(&decoder->event_cs); ++ while (decoder->event.type != PIPELINE_EVENT_NONE) ++ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); ++ ++ decoder->event.type = PIPELINE_EVENT_READ_REQUEST; ++ WakeAllConditionVariable(&decoder->event_cv); ++ while (decoder->event.type == PIPELINE_EVENT_READ_REQUEST) ++ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); ++ LeaveCriticalSection(&decoder->event_cs); ++ } ++ ++ return 0; ++} ++ ++static struct pipeline_event get_pipeline_event(struct mf_decoder *decoder) ++{ ++ struct pipeline_event ret; ++ ++ EnterCriticalSection(&decoder->event_cs); ++ while(decoder->event.type == PIPELINE_EVENT_NONE) ++ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); ++ ++ ret = decoder->event; ++ ++ if (ret.type != PIPELINE_EVENT_READ_REQUEST) ++ { ++ decoder->event.type = PIPELINE_EVENT_NONE; ++ WakeAllConditionVariable(&decoder->event_cv); ++ } ++ ++ LeaveCriticalSection(&decoder->event_cs); ++ ++ return ret; ++} ++ + static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) + { + FIXME("%p, %u %lu.\n", iface, message, param); +@@ -514,17 +717,318 @@ static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE + + static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) + { +- FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ struct pipeline_event pip_event; ++ IMFMediaBuffer *buffer = NULL; ++ HRESULT hr = S_OK; ++ BYTE *buffer_data; ++ DWORD buffer_size; ++ uint32_t size = 0; ++ uint64_t offset; ++ void *data; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %p, %#x.\n", decoder, id, sample, flags); ++ ++ if (flags) ++ WARN("Unsupported flags %#x\n", flags); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ EnterCriticalSection(&decoder->cs); ++ ++ if (!decoder->input_type || !decoder->output_type) ++ { ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ } ++ ++ if (decoder->draining) ++ { ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_NOTACCEPTING; ++ } ++ ++ if (!decoder->wg_stream) ++ { ++ pip_event = get_pipeline_event(decoder); ++ ++ switch (pip_event.type) ++ { ++ case PIPELINE_EVENT_PARSER_STARTED: ++ decoder->wg_stream = pip_event.u.parser_started.stream; ++ break; ++ case PIPELINE_EVENT_READ_REQUEST: ++ break; ++ default: ++ assert(0); ++ } ++ } ++ ++ if (decoder->wg_stream && !unix_funcs->wg_parser_stream_drain(decoder->wg_stream)) ++ { ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_NOTACCEPTING; ++ } ++ ++ /* At this point, we either have a pre-init read request, or drained pipeline */ ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) ++ goto done; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size))) ++ goto done; ++ ++ pip_event = get_pipeline_event(decoder); ++ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); ++ ++ for(;;) ++ { ++ uint32_t copy_size; ++ ++ if (!unix_funcs->wg_parser_get_read_request(decoder->wg_parser, &data, &offset, &size)) ++ continue; ++ ++ copy_size = min(size, buffer_size); ++ ++ if (offset != decoder->offset_tracker) ++ { ++ ERR("A seek is needed, MFTs don't support this!\n"); ++ unix_funcs->wg_parser_complete_read_request(decoder->wg_parser, WG_READ_FAILURE, 0); ++ IMFMediaBuffer_Unlock(buffer); ++ hr = E_FAIL; ++ goto done; ++ } ++ ++ memcpy(data, buffer_data, copy_size); ++ ++ unix_funcs->wg_parser_complete_read_request(decoder->wg_parser, WG_READ_SUCCESS, buffer_size); ++ ++ decoder->offset_tracker += copy_size; ++ ++ if (buffer_size <= size) ++ break; ++ ++ buffer_data += copy_size; ++ buffer_size -= copy_size; ++ ++ WARN("Input sample split into multiple read requests\n"); ++ } ++ ++ EnterCriticalSection(&decoder->event_cs); ++ decoder->event.type = PIPELINE_EVENT_NONE; ++ LeaveCriticalSection(&decoder->event_cs); ++ WakeAllConditionVariable(&decoder->event_cv); ++ ++ IMFMediaBuffer_Unlock(buffer); ++ ++ done: ++ if (buffer) ++ IMFMediaBuffer_Release(buffer); ++ LeaveCriticalSection(&decoder->cs); ++ return hr; + } + + static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) + { +- FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ MFT_OUTPUT_DATA_BUFFER *relevant_buffer = NULL; ++ struct wg_parser_event event; ++ struct pipeline_event pip_event; ++ IMFMediaBuffer *buffer; ++ DWORD buffer_len; ++ unsigned int i; ++ BYTE *data; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); ++ ++ if (flags) ++ WARN("Unsupported flags %#x\n", flags); ++ ++ for (i = 0; i < count; i++) ++ { ++ MFT_OUTPUT_DATA_BUFFER *out_buffer = &samples[i]; ++ ++ if (out_buffer->dwStreamID != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (relevant_buffer) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ relevant_buffer = out_buffer; ++ } ++ ++ if (!relevant_buffer) ++ return S_OK; ++ ++ EnterCriticalSection(&decoder->cs); ++ ++ if (!decoder->input_type || !decoder->output_type) ++ { ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ } ++ ++ if (!decoder->wg_stream) ++ { ++ pip_event = get_pipeline_event(decoder); ++ ++ switch (pip_event.type) ++ { ++ case PIPELINE_EVENT_PARSER_STARTED: ++ decoder->wg_stream = pip_event.u.parser_started.stream; ++ break; ++ case PIPELINE_EVENT_READ_REQUEST: ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_TRANSFORM_NEED_MORE_INPUT; ++ default: ++ assert(0); ++ } ++ } ++ ++ if (unix_funcs->wg_parser_stream_drain(decoder->wg_stream)) ++ { ++ /* this would be unexpected, as we should get the EOS-event when a drain command completes. */ ++ //assert (!decoder->draining); ++ ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_TRANSFORM_NEED_MORE_INPUT; ++ } ++ ++ for (;;) ++ { ++ if (!unix_funcs->wg_parser_stream_get_event(decoder->wg_stream, &event)) ++ { ++ LeaveCriticalSection(&decoder->cs); ++ return E_FAIL; ++ } ++ ++ if (event.type == WG_PARSER_EVENT_BUFFER) ++ break; ++ ++ if (event.type == WG_PARSER_EVENT_EOS) ++ { ++ if (!decoder->draining) ++ { ++ LeaveCriticalSection(&decoder->cs); ++ WARN("Received EOS event while not draining\n"); ++ return E_FAIL; ++ } ++ decoder->draining = FALSE; ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_TRANSFORM_NEED_MORE_INPUT; ++ } ++ ++ assert(event.type != WG_PARSER_EVENT_NONE); ++ } ++ ++ if (relevant_buffer->pSample) ++ { ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(relevant_buffer->pSample, &buffer))) ++ { ++ ERR("Failed to get buffer from sample, hr %#x.\n", hr); ++ LeaveCriticalSection(&decoder->cs); ++ return hr; ++ } ++ } ++ else ++ { ++ if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) ++ { ++ ERR("Failed to create buffer, hr %#x.\n", hr); ++ LeaveCriticalSection(&decoder->cs); ++ return hr; ++ } ++ ++ if (FAILED(hr = MFCreateSample(&relevant_buffer->pSample))) ++ { ++ ERR("Failed to create sample, hr %#x.\n", hr); ++ LeaveCriticalSection(&decoder->cs); ++ IMFMediaBuffer_Release(buffer); ++ return hr; ++ } ++ ++ if (FAILED(hr = IMFSample_AddBuffer(relevant_buffer->pSample, buffer))) ++ { ++ ERR("Failed to add buffer, hr %#x.\n", hr); ++ goto out; ++ } ++ } ++ ++ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) ++ { ++ ERR("Failed to get buffer size, hr %#x.\n", hr); ++ goto out; ++ } ++ ++ if (buffer_len < event.u.buffer.size) ++ { ++ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", ++ buffer_len, event.u.buffer.size); ++ ++ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, buffer_len))) ++ { ++ ERR("Failed to set size, hr %#x.\n", hr); ++ goto out; ++ } ++ } ++ else if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) ++ { ++ ERR("Failed to set size, hr %#x.\n", hr); ++ goto out; ++ } ++ ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) ++ { ++ ERR("Failed to lock buffer, hr %#x.\n", hr); ++ goto out; ++ } ++ ++ if (!unix_funcs->wg_parser_stream_copy_buffer(decoder->wg_stream, data, 0, min(buffer_len, event.u.buffer.size))) ++ { ++ hr = E_FAIL; ++ goto out; ++ } ++ ++ if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) ++ { ++ ERR("Failed to unlock buffer, hr %#x.\n", hr); ++ goto out; ++ } ++ ++ if (FAILED(hr = IMFSample_SetSampleTime(relevant_buffer->pSample, event.u.buffer.pts))) ++ { ++ ERR("Failed to set sample time, hr %#x.\n", hr); ++ goto out; ++ } ++ ++ if (FAILED(hr = IMFSample_SetSampleDuration(relevant_buffer->pSample, event.u.buffer.duration))) ++ { ++ ERR("Failed to set sample duration, hr %#x.\n", hr); ++ goto out; ++ } ++ ++ relevant_buffer->dwStatus = 0; ++ relevant_buffer->pEvents = NULL; ++ *status = 0; ++ ++ out: ++ if (SUCCEEDED(hr)) ++ unix_funcs->wg_parser_stream_release_buffer(decoder->wg_stream); ++ LeaveCriticalSection(&decoder->cs); ++ ++ if (FAILED(hr)) ++ { ++ IMFSample_Release(relevant_buffer->pSample); ++ relevant_buffer->pSample = NULL; ++ } ++ ++ IMFMediaBuffer_Release(buffer); ++ ++ return hr; + } + + static const IMFTransformVtbl mf_decoder_vtbl = +@@ -560,6 +1064,7 @@ static const IMFTransformVtbl mf_decoder_vtbl = + HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) + { + struct mf_decoder *object; ++ struct wg_parser *parser; + + TRACE("%s, %p %u.\n", debugstr_guid(riid), obj, type); + +@@ -573,6 +1078,21 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) + object->video = decoder_descs[type].major_type == &MFMediaType_Video; + + InitializeCriticalSection(&object->cs); ++ InitializeCriticalSection(&object->help_cs); ++ InitializeCriticalSection(&object->event_cs); ++ InitializeConditionVariable(&object->help_cv); ++ InitializeConditionVariable(&object->event_cv); ++ ++ object->helper_thread = CreateThread(NULL, 0, helper_thread_func, object, 0, NULL); ++ object->read_thread = CreateThread(NULL, 0, read_thread_func, object, 0, NULL); ++ ++ if (!(parser = unix_funcs->wg_decodebin_parser_create())) ++ { ++ ERR("Failed to create Decoder MFT type %u: Unspecified GStreamer error\n", type); ++ IMFTransform_Release(&object->IMFTransform_iface); ++ return E_OUTOFMEMORY; ++ } ++ object->wg_parser = parser; + + *obj = &object->IMFTransform_iface; + return S_OK; +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0011-winegstreamer-Implement-GetOutputAvailableType-for-c.patch b/patches/mfplat-streaming-support/0011-winegstreamer-Implement-GetOutputAvailableType-for-c.patch deleted file mode 100644 index 83326c06..00000000 --- a/patches/mfplat-streaming-support/0011-winegstreamer-Implement-GetOutputAvailableType-for-c.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 64cfb2a80d7ebc22b12d8b6c1e41cf7a74e15d88 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 3 Dec 2020 14:45:32 -0500 -Subject: [PATCH] winegstreamer: Implement ::GetOutputAvailableType for color - conversion transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 48 +++++++++++++++++++++++++++++-- - 1 file changed, 46 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 5dd48188147..b80232e195b 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -217,12 +217,56 @@ static HRESULT WINAPI color_converter_GetInputAvailableType(IMFTransform *iface, - return S_OK; - } - -+static void copy_attr(IMFMediaType *target, IMFMediaType *source, const GUID *key) -+{ -+ PROPVARIANT val; -+ -+ if (SUCCEEDED(IMFAttributes_GetItem((IMFAttributes *)source, key, &val))) -+ { -+ IMFAttributes_SetItem((IMFAttributes* )target, key, &val); -+ } -+} -+ - static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ IMFMediaType *output_type; -+ HRESULT hr; - -- return E_NOTIMPL; -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ -+ TRACE("%p, %u, %u, %p.\n", iface, id, index, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (index >= ARRAY_SIZE(raw_types)) -+ return MF_E_NO_MORE_TYPES; -+ -+ if (FAILED(hr = MFCreateMediaType(&output_type))) -+ return hr; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!(converter->input_type)) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ IMFMediaType_CopyAllItems(converter->input_type, (IMFAttributes *)output_type); -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_SUBTYPE, raw_types[index]))) -+ { -+ IMFMediaType_Release(output_type); -+ return hr; -+ } -+ -+ *type = output_type; -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch b/patches/mfplat-streaming-support/0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch new file mode 100644 index 00000000..416fdc26 --- /dev/null +++ b/patches/mfplat-streaming-support/0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch @@ -0,0 +1,122 @@ +From 6da483d3feca1cd83a5fecdd5671fa8a0d10a2f8 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 16:54:03 -0400 +Subject: [PATCH 11/39] winestreamer: Implement ::ProcessMessage for decoder + transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 96 ++++++++++++++++++++++++++- + 1 file changed, 94 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index c30780ba7ff..04a07647de4 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -710,9 +710,101 @@ static struct pipeline_event get_pipeline_event(struct mf_decoder *decoder) + + static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) + { +- FIXME("%p, %u %lu.\n", iface, message, param); ++ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %x %lu.\n", decoder, message, param); ++ ++ EnterCriticalSection(&decoder->cs); ++ if (!decoder->input_type || !decoder->output_type) ++ { ++ LeaveCriticalSection(&decoder->cs); ++ return MF_E_TRANSFORM_TYPE_NOT_SET; ++ } ++ ++ hr = S_OK; ++ ++ switch (message) ++ { ++ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: ++ case MFT_MESSAGE_NOTIFY_START_OF_STREAM: ++ break; ++ case MFT_MESSAGE_NOTIFY_END_OF_STREAM: ++ { ++ if (param) ++ { ++ hr = MF_E_INVALIDSTREAMNUMBER; ++ break; ++ } ++ if (!decoder->wg_stream) ++ { ++ ERR("End-Of-Stream marked on a decoder MFT which hasn't finished initialization\n"); ++ hr = E_FAIL; ++ break; ++ } ++ ++ decoder->eos = TRUE; ++ break; ++ } ++ case MFT_MESSAGE_COMMAND_DRAIN: ++ { ++ struct pipeline_event pip_event; ++ ++ if (!decoder->wg_stream) ++ { ++ ERR("Drain requested on a decoder MFT which hasn't finished initialization\n"); ++ hr = E_FAIL; ++ break; ++ } ++ ++ pip_event = get_pipeline_event(decoder); ++ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); ++ ++ unix_funcs->wg_parser_complete_read_request(decoder->wg_parser, WG_READ_EOS, 0); ++ ++ EnterCriticalSection(&decoder->event_cs); ++ decoder->event.type = PIPELINE_EVENT_NONE; ++ LeaveCriticalSection(&decoder->event_cs); ++ WakeAllConditionVariable(&decoder->event_cv); ++ ++ decoder->draining = TRUE; ++ decoder->offset_tracker = 0; ++ break; ++ } ++ case MFT_MESSAGE_COMMAND_FLUSH: ++ { ++ struct pipeline_event pip_event; ++ ++ if (!decoder->wg_stream) ++ { ++ ERR("Flush requested on a decoder MFT which hasn't finished initialization\n"); ++ hr = E_FAIL; ++ break; ++ } ++ ++ pip_event = get_pipeline_event(decoder); ++ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); ++ ++ unix_funcs->wg_parser_complete_read_request(decoder->wg_parser, WG_READ_FLUSHING, 0); ++ ++ EnterCriticalSection(&decoder->event_cs); ++ decoder->event.type = PIPELINE_EVENT_NONE; ++ LeaveCriticalSection(&decoder->event_cs); ++ WakeAllConditionVariable(&decoder->event_cv); ++ ++ decoder->offset_tracker = 0; ++ break; ++ } ++ default: ++ { ++ ERR("Unhandled message type %x.\n", message); ++ hr = E_FAIL; ++ break; ++ } ++ } ++ ++ LeaveCriticalSection(&decoder->cs); ++ return hr; + } + + static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0012-winegstreamer-Implement-SetOutputType-for-color-conv.patch b/patches/mfplat-streaming-support/0012-winegstreamer-Implement-SetOutputType-for-color-conv.patch deleted file mode 100644 index cbf09d6c..00000000 --- a/patches/mfplat-streaming-support/0012-winegstreamer-Implement-SetOutputType-for-color-conv.patch +++ /dev/null @@ -1,103 +0,0 @@ -From f1714a949175290e9f01bd32fde1dacecfed7946 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 3 Dec 2020 14:55:41 -0500 -Subject: [PATCH] winegstreamer: Implement ::SetOutputType for color conversion - transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 70 ++++++++++++++++++++++++++++++- - 1 file changed, 68 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index b80232e195b..e7e84690738 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -53,6 +53,7 @@ struct color_converter - IMFTransform IMFTransform_iface; - LONG refcount; - IMFMediaType *input_type; -+ IMFMediaType *output_type; - CRITICAL_SECTION cs; - }; - -@@ -343,9 +344,74 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - - static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ GstCaps *output_caps; -+ unsigned int i; -+ HRESULT hr; - -- return E_NOTIMPL; -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ -+ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (type) -+ { -+ GUID major_type, subtype; -+ -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) -+ return MF_E_INVALIDTYPE; -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return MF_E_INVALIDTYPE; -+ -+ if (!(IsEqualGUID(&major_type, &MFMediaType_Video))) -+ return MF_E_INVALIDTYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(raw_types); i++) -+ { -+ if (IsEqualGUID(&subtype, raw_types[i])) -+ break; -+ } -+ -+ if (i == ARRAY_SIZE(raw_types)) -+ return MF_E_INVALIDTYPE; -+ -+ if (!(output_caps = caps_from_mf_media_type(type))) -+ return MF_E_INVALIDTYPE; -+ -+ gst_caps_unref(output_caps); -+ } -+ -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ hr = S_OK; -+ -+ if (type) -+ { -+ if (!converter->output_type) -+ hr = MFCreateMediaType(&converter->output_type); -+ -+ if (SUCCEEDED(hr)) -+ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->output_type); -+ -+ if (FAILED(hr)) -+ { -+ IMFMediaType_Release(converter->output_type); -+ converter->output_type = NULL; -+ } -+ } -+ else -+ { -+ IMFMediaType_Release(converter->output_type); -+ converter->output_type = NULL; -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return hr; - } - - static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch b/patches/mfplat-streaming-support/0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch new file mode 100644 index 00000000..8a422301 --- /dev/null +++ b/patches/mfplat-streaming-support/0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch @@ -0,0 +1,30 @@ +From 5c7b05aeb941b1fbd4a978894873438aa0e5b397 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 16:55:15 -0400 +Subject: [PATCH 12/39] winegstreamer: Semi-stub ::GetAttributes for decoder + transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index 04a07647de4..f0e8527631c 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -257,9 +257,9 @@ static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD + + static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) + { +- FIXME("%p, %p.\n", iface, attributes); ++ FIXME("%p, %p. semi-stub!\n", iface, attributes); + +- return E_NOTIMPL; ++ return MFCreateAttributes(attributes, 0); + } + + static HRESULT WINAPI mf_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0013-winegstreamer-Implement-Process-Input-Output-for-col.patch b/patches/mfplat-streaming-support/0013-winegstreamer-Implement-Process-Input-Output-for-col.patch deleted file mode 100644 index 53a010ee..00000000 --- a/patches/mfplat-streaming-support/0013-winegstreamer-Implement-Process-Input-Output-for-col.patch +++ /dev/null @@ -1,267 +0,0 @@ -From c94cfbf0ec1c10452c2cf1496f32eeefe5794cea Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 3 Dec 2020 15:22:20 -0500 -Subject: [PATCH] winegstreamer: Implement ::Process(Input/Output) for color - conversion transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 159 +++++++++++++++++++++++++++++- - 1 file changed, 154 insertions(+), 5 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index e7e84690738..b77f3358c52 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -55,6 +55,8 @@ struct color_converter - IMFMediaType *input_type; - IMFMediaType *output_type; - CRITICAL_SECTION cs; -+ BOOL inflight; -+ GstElement *container, *appsrc, *videoconvert, *appsink; - }; - - static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface) -@@ -100,6 +102,7 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) - { - transform->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&transform->cs); -+ gst_object_unref(transform->container); - heap_free(transform); - } - -@@ -307,7 +310,8 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - if (!(input_caps = caps_from_mf_media_type(type))) - return MF_E_INVALIDTYPE; - -- gst_caps_unref(input_caps); -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ gst_caps_unref(input_caps); - } - - if (flags & MFT_SET_TYPE_TEST_ONLY) -@@ -316,6 +320,7 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - EnterCriticalSection(&converter->cs); - - hr = S_OK; -+ gst_element_set_state(converter->container, GST_STATE_READY); - - if (type) - { -@@ -325,6 +330,9 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - if (SUCCEEDED(hr)) - hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->input_type); - -+ g_object_set(converter->appsrc, "caps", input_caps, NULL); -+ gst_caps_unref(input_caps); -+ - if (FAILED(hr)) - { - IMFMediaType_Release(converter->input_type); -@@ -337,6 +345,9 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - converter->input_type = NULL; - } - -+ if (converter->input_type && converter->output_type) -+ gst_element_set_state(converter->container, GST_STATE_PLAYING); -+ - LeaveCriticalSection(&converter->cs); - - return hr; -@@ -379,7 +390,8 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - if (!(output_caps = caps_from_mf_media_type(type))) - return MF_E_INVALIDTYPE; - -- gst_caps_unref(output_caps); -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ gst_caps_unref(output_caps); - } - - if (flags & MFT_SET_TYPE_TEST_ONLY) -@@ -388,6 +400,7 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - EnterCriticalSection(&converter->cs); - - hr = S_OK; -+ gst_element_set_state(converter->container, GST_STATE_READY); - - if (type) - { -@@ -397,6 +410,9 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - if (SUCCEEDED(hr)) - hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->output_type); - -+ g_object_set(converter->appsink, "caps", output_caps, NULL); -+ gst_caps_unref(output_caps); -+ - if (FAILED(hr)) - { - IMFMediaType_Release(converter->output_type); -@@ -409,6 +425,9 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - converter->output_type = NULL; - } - -+ if (converter->input_type && converter->output_type) -+ gst_element_set_state(converter->container, GST_STATE_PLAYING); -+ - LeaveCriticalSection(&converter->cs); - - return hr; -@@ -465,15 +484,102 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME - - static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ GstBuffer *gst_buffer; -+ int ret; - -- return E_NOTIMPL; -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ -+ TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ -+ if (flags) -+ WARN("Unsupported flags %#x\n", flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!converter->input_type || !converter->output_type) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ if (converter->inflight) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_NOTACCEPTING; -+ } -+ -+ if (!(gst_buffer = gst_buffer_from_mf_sample(sample))) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return E_FAIL; -+ } -+ -+ g_signal_emit_by_name(converter->appsrc, "push-buffer", gst_buffer, &ret); -+ gst_buffer_unref(gst_buffer); -+ if (ret != GST_FLOW_OK) -+ { -+ ERR("Couldn't push buffer ret = %d (%s)\n", ret, gst_flow_get_name(ret)); -+ LeaveCriticalSection(&converter->cs); -+ return E_FAIL; -+ } -+ -+ converter->inflight = TRUE; -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ GstSample *sample; -+ -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ -+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ -+ if (flags) -+ WARN("Unsupported flags %#x\n", flags); -+ -+ if (!count) -+ return S_OK; -+ -+ if (count != 1) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (samples[0].dwStreamID != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!converter->input_type || !converter->output_type) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ if (!converter->inflight) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ g_signal_emit_by_name(converter->appsink, "pull-sample", &sample); -+ -+ converter->inflight = FALSE; -+ -+ samples[0].pSample = mf_sample_from_gst_buffer(gst_sample_get_buffer(sample)); -+ gst_sample_unref(sample); -+ samples[0].dwStatus = S_OK; -+ samples[0].pEvents = NULL; -+ *status = 0; -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - - return E_NOTIMPL; - } -@@ -523,6 +629,49 @@ HRESULT color_converter_create(REFIID riid, void **ret) - InitializeCriticalSection(&object->cs); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); - -+ object->container = gst_bin_new(NULL); -+ -+ if (!(object->appsrc = gst_element_factory_make("appsrc", NULL))) -+ { -+ ERR("Failed to create appsrc, are %u-bit Gstreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ gst_bin_add(GST_BIN(object->container), object->appsrc); -+ -+ if (!(object->videoconvert = gst_element_factory_make("videoconvert", NULL))) -+ { -+ ERR("Failed to create videoconvert, are %u-bit Gstreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ gst_bin_add(GST_BIN(object->container), object->videoconvert); -+ -+ if (!(object->appsink = gst_element_factory_make("appsink", NULL))) -+ { -+ ERR("Failed to create appsink, are %u-bit Gstreamer \"base\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ gst_bin_add(GST_BIN(object->container), object->appsink); -+ -+ if (!gst_element_link(object->appsrc, object->videoconvert)) -+ { -+ ERR("Failed to link appsrc to videoconvert\n"); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ -+ if (!gst_element_link(object->videoconvert, object->appsink)) -+ { -+ ERR("Failed to link videoconvert to appsink\n"); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_FAIL; -+ } -+ - *ret = &object->IMFTransform_iface; - return S_OK; - } --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0013-winegstreamer-Register-the-H.264-decoder-transform.patch b/patches/mfplat-streaming-support/0013-winegstreamer-Register-the-H.264-decoder-transform.patch new file mode 100644 index 00000000..4a287bc9 --- /dev/null +++ b/patches/mfplat-streaming-support/0013-winegstreamer-Register-the-H.264-decoder-transform.patch @@ -0,0 +1,56 @@ +From 86f104e3b17755d2eecd6d46ea1c66875232e2bd Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 16:57:11 -0400 +Subject: [PATCH 13/39] winegstreamer: Register the H.264 decoder transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/mfplat.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index 9a599358c61..f015ecc3f47 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -453,6 +453,20 @@ static const GUID *audio_converter_supported_types[] = + &MFAudioFormat_Float, + }; + ++static WCHAR h264_decoderW[] = L"H.264 Decoder"; ++static const GUID *h264_decoder_input_types[] = ++{ ++ &MFVideoFormat_H264, ++}; ++static const GUID *h264_decoder_output_types[] = ++{ ++ &MFVideoFormat_NV12, ++ &MFVideoFormat_I420, ++ &MFVideoFormat_IYUV, ++ &MFVideoFormat_YUY2, ++ &MFVideoFormat_YV12, ++}; ++ + static const struct mft + { + const GUID *clsid; +@@ -478,6 +492,17 @@ mfts[] = + ARRAY_SIZE(audio_converter_supported_types), + audio_converter_supported_types, + }, ++ { ++ &CLSID_CMSH264DecoderMFT, ++ &MFT_CATEGORY_VIDEO_DECODER, ++ h264_decoderW, ++ MFT_ENUM_FLAG_SYNCMFT, ++ &MFMediaType_Video, ++ ARRAY_SIZE(h264_decoder_input_types), ++ h264_decoder_input_types, ++ ARRAY_SIZE(h264_decoder_output_types), ++ h264_decoder_output_types, ++ }, + }; + + HRESULT mfplat_DllRegisterServer(void) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0014-winegstreamer-Introduce-AAC-decoder-transform.patch b/patches/mfplat-streaming-support/0014-winegstreamer-Introduce-AAC-decoder-transform.patch new file mode 100644 index 00000000..9bbf7ccc --- /dev/null +++ b/patches/mfplat-streaming-support/0014-winegstreamer-Introduce-AAC-decoder-transform.patch @@ -0,0 +1,304 @@ +From 8c2af2c3be9a337c07638206ba9d0c4035fda36e Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 16:59:29 -0400 +Subject: [PATCH 14/39] winegstreamer: Introduce AAC decoder transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/decode_transform.c | 10 ++++ + dlls/winegstreamer/gst_private.h | 17 ++++++ + dlls/winegstreamer/mfplat.c | 63 +++++++++++++++++++- + dlls/winegstreamer/quartz_parser.c | 1 + + dlls/winegstreamer/wg_parser.c | 62 +++++++++++++++++++ + dlls/winegstreamer/winegstreamer_classes.idl | 6 ++ + include/mfidl.idl | 1 + + 7 files changed, 159 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c +index f0e8527631c..bb9bd6d6327 100644 +--- a/dlls/winegstreamer/decode_transform.c ++++ b/dlls/winegstreamer/decode_transform.c +@@ -33,6 +33,9 @@ const GUID *h264_input_types[] = {&MFVideoFormat_H264}; + /* NV12 comes first https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order . thanks to @vitorhnn */ + const GUID *h264_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_YUY2, &MFVideoFormat_YV12}; + ++const GUID *aac_input_types[] = {&MFAudioFormat_AAC}; ++const GUID *aac_output_types[] = {&MFAudioFormat_Float}; ++ + static struct decoder_desc + { + const GUID *major_type; +@@ -49,6 +52,13 @@ static struct decoder_desc + h264_output_types, + ARRAY_SIZE(h264_output_types), + }, ++ { /* DECODER_TYPE_AAC */ ++ &MFMediaType_Audio, ++ aac_input_types, ++ ARRAY_SIZE(aac_input_types), ++ aac_output_types, ++ ARRAY_SIZE(aac_output_types), ++ } + }; + + struct pipeline_event +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 25694aae84d..6407aff484c 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -127,11 +127,27 @@ struct wg_format + WG_AUDIO_FORMAT_MPEG1_LAYER1, + WG_AUDIO_FORMAT_MPEG1_LAYER2, + WG_AUDIO_FORMAT_MPEG1_LAYER3, ++ ++ WG_AUDIO_FORMAT_AAC, + } format; + + uint32_t channels; + uint32_t channel_mask; /* In WinMM format. */ + uint32_t rate; ++ ++ union ++ { ++ struct ++ { ++ uint32_t payload_type; ++ uint32_t indication; ++ /* The definition of this structure is found in ISO/IEC 14496-3, ++ which we don't have access to, so we'll just keep ++ the size set to the largest instance we've seen used. */ ++ unsigned char audio_specifc_config[2]; ++ uint32_t asp_size; ++ } aac; ++ } compressed; + } audio; + } u; + }; +@@ -256,6 +272,7 @@ HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; + enum decoder_type + { + DECODER_TYPE_H264, ++ DECODER_TYPE_AAC, + }; + HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; + +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index f015ecc3f47..f3d9fb61a66 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -407,6 +407,11 @@ static HRESULT h264_decoder_create(REFIID riid, void **ret) + return decode_transform_create(riid, ret, DECODER_TYPE_H264); + } + ++static HRESULT aac_decoder_create(REFIID riid, void **ret) ++{ ++ return decode_transform_create(riid, ret, DECODER_TYPE_AAC); ++} ++ + static const struct class_object + { + const GUID *clsid; +@@ -418,6 +423,7 @@ class_objects[] = + { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, + { &CLSID_WINEAudioConverter, &audio_converter_create }, + { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, ++ { &CLSID_CMSAACDecMFT, &aac_decoder_create }, + }; + + HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) +@@ -599,7 +605,8 @@ static IMFMediaType *mf_media_type_from_wg_format_audio(const struct wg_format * + IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, audio_formats[i].depth); + IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, format->u.audio.rate); + IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, format->u.audio.channels); +- IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, format->u.audio.channel_mask); ++ if (format->u.audio.channel_mask) ++ IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, format->u.audio.channel_mask); + + return type; + } +@@ -687,6 +694,8 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma + channel_mask = KSAUDIO_SPEAKER_MONO; + else if (channels == 2) + channel_mask = KSAUDIO_SPEAKER_STEREO; ++ else if IsEqualGUID(&subtype, &MFAudioFormat_AAC) ++ channel_mask = 0; + else + { + FIXME("Channel mask is not set.\n"); +@@ -699,6 +708,58 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma + format->u.audio.channel_mask = channel_mask; + format->u.audio.rate = rate; + ++ if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) ++ { ++ UINT32 payload_type, indication, user_data_size; ++ unsigned char *user_data; ++ ++ format->u.audio.format = WG_AUDIO_FORMAT_AAC; ++ ++ if (SUCCEEDED(IMFMediaType_GetBlobSize(type, &MF_MT_USER_DATA, &user_data_size))) ++ { ++ user_data = malloc(user_data_size); ++ if (SUCCEEDED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, user_data, user_data_size, NULL))) ++ { ++ struct { ++ WORD payload_type; ++ WORD indication; ++ WORD type; ++ WORD reserved1; ++ DWORD reserved2; ++ } *aac_info = (void *) user_data; ++ ++ format->u.audio.compressed.aac.payload_type = aac_info->payload_type; ++ format->u.audio.compressed.aac.indication = aac_info->indication; ++ ++ /* Audio specific config is stored at after HEAACWAVEINFO in MF_MT_USER_DATA ++ https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-heaacwaveformat */ ++ if (user_data_size > 12) ++ { ++ user_data += 12; ++ user_data_size -= 12; ++ ++ if (user_data_size > sizeof(format->u.audio.compressed.aac.audio_specifc_config)) ++ { ++ FIXME("Encountered Audio-Specific-Config with a size larger than we support %u\n", user_data_size); ++ user_data_size = sizeof(format->u.audio.compressed.aac.audio_specifc_config); ++ } ++ ++ memcpy(format->u.audio.compressed.aac.audio_specifc_config, user_data, user_data_size); ++ format->u.audio.compressed.aac.asp_size = user_data_size; ++ } ++ ++ } ++ } ++ ++ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &payload_type))) ++ format->u.audio.compressed.aac.payload_type = payload_type; ++ ++ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &indication))) ++ format->u.audio.compressed.aac.indication = indication; ++ ++ return; ++ } ++ + for (i = 0; i < ARRAY_SIZE(audio_formats); ++i) + { + if (IsEqualGUID(&subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) +diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c +index 1c68eba1872..b1e35521266 100644 +--- a/dlls/winegstreamer/quartz_parser.c ++++ b/dlls/winegstreamer/quartz_parser.c +@@ -100,6 +100,7 @@ static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format * + switch (format->u.audio.format) + { + case WG_AUDIO_FORMAT_UNKNOWN: ++ case WG_AUDIO_FORMAT_AAC: + return false; + + case WG_AUDIO_FORMAT_MPEG1_LAYER1: +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 9ca5abebfaf..2a982576ef5 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -398,6 +398,13 @@ static void wg_set_caps_from_wg_format(GstCaps *caps, const struct wg_format *fo + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); + break; + } ++ case WG_MAJOR_TYPE_AUDIO: ++ { ++ gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.audio.rate, NULL); ++ gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.audio.channels, NULL); ++ if (format->u.audio.channel_mask) ++ gst_caps_set_simple(caps, "channel-mask", G_TYPE_INT, format->u.audio.channel_mask, NULL); ++ } + default: + break; + } +@@ -409,6 +416,61 @@ static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) + GstAudioFormat audio_format; + GstAudioInfo info; + ++ /* compressed types */ ++ ++ if (format->u.audio.format == WG_AUDIO_FORMAT_AAC) ++ { ++ const char *profile, *level; ++ GstBuffer *audio_specific_config; ++ GstCaps *caps = gst_caps_new_empty_simple("audio/mpeg"); ++ wg_set_caps_from_wg_format(caps, format); ++ ++ gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); ++ ++ switch (format->u.audio.compressed.aac.payload_type) ++ { ++ case 0: ++ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); ++ break; ++ case 1: ++ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adts", NULL); ++ break; ++ case 2: ++ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adif", NULL); ++ break; ++ case 3: ++ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "loas", NULL); ++ break; ++ default: ++ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); ++ }; ++ ++ switch (format->u.audio.compressed.aac.indication) ++ { ++ case 0x29: profile = "lc"; level = "2"; break; ++ case 0x2A: profile = "lc"; level = "4"; break; ++ case 0x2B: profile = "lc"; level = "5"; break; ++ default: ++ FIXME("Unrecognized profile-level-indication %u\n", format->u.audio.compressed.aac.indication); ++ /* fallthrough */ ++ case 0x00: case 0xFE: profile = level = NULL; break; /* unspecified */ ++ } ++ ++ if (profile) ++ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); ++ if (level) ++ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); ++ ++ audio_specific_config = gst_buffer_new_allocate(NULL, format->u.audio.compressed.aac.asp_size, NULL); ++ gst_buffer_fill(audio_specific_config, 0, format->u.audio.compressed.aac.audio_specifc_config, format->u.audio.compressed.aac.asp_size); ++ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, audio_specific_config, NULL); ++ gst_buffer_unref(audio_specific_config); ++ ++ return caps; ++ } ++ ++ /* uncompressed_types */ ++ + if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN) + return NULL; + +diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl +index 064a6872c79..4c58d83403b 100644 +--- a/dlls/winegstreamer/winegstreamer_classes.idl ++++ b/dlls/winegstreamer/winegstreamer_classes.idl +@@ -73,3 +73,9 @@ coclass WINEAudioConverter { } + uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d) + ] + coclass CMSH264DecoderMFT { } ++ ++[ ++ threading(both), ++ uuid(32d186a7-218f-4c75-8876-dd77273a8999) ++] ++coclass CMSAACDecMFT { } +diff --git a/include/mfidl.idl b/include/mfidl.idl +index 616271861aa..dee81338b2b 100644 +--- a/include/mfidl.idl ++++ b/include/mfidl.idl +@@ -1575,3 +1575,4 @@ cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, 0xba491366, 0xb + + cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") + cpp_quote("EXTERN_GUID(CLSID_CMSH264DecoderMFT, 0x62ce7e72, 0x4c71, 0x4d20, 0xb1, 0x5d, 0x45, 0x28, 0x31, 0xa8, 0x7d, 0x9d);") ++cpp_quote("EXTERN_GUID(CLSID_CMSAACDecMFT, 0x32d186a7, 0x218f, 0x4c75, 0x88, 0x76, 0xdd, 0x77, 0x27, 0x3a, 0x89, 0x99);") +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0015-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch b/patches/mfplat-streaming-support/0015-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch deleted file mode 100644 index 34bafb06..00000000 --- a/patches/mfplat-streaming-support/0015-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch +++ /dev/null @@ -1,54 +0,0 @@ -From e8eef3f90da399a077f5853e2a399c7e27a6418e Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 3 Dec 2020 15:28:42 -0500 -Subject: [PATCH] winegstreamer: Implement ::Get(Input/Output)StreamInfo for - color conversion transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 23 +++++++++++++++++++---- - 1 file changed, 19 insertions(+), 4 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index c07ef22acc3..43b8dddeee7 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -138,16 +138,31 @@ static HRESULT WINAPI color_converter_GetStreamIDs(IMFTransform *iface, DWORD in - - static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) - { -- FIXME("%p %u %p.\n", iface, id, info); -+ TRACE("%p %u %p.\n", iface, id, info); - -- return E_NOTIMPL; -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF; -+ info->cbMaxLookahead = 0; -+ info->cbAlignment = 0; -+ info->hnsMaxLatency = 0; -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) - { -- FIXME("%p %u %p.\n", iface, id, info); -+ TRACE("%p %u %p.\n", iface, id, info); - -- return E_NOTIMPL; -+ 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 color_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch b/patches/mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch new file mode 100644 index 00000000..8f5a066e --- /dev/null +++ b/patches/mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch @@ -0,0 +1,53 @@ +From f1011219faa95c40cdcffda69c65dee5566b3b80 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 17:00:27 -0400 +Subject: [PATCH 15/39] winegstreamer: Register the AAC decoder transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/mfplat.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index f3d9fb61a66..28b45893b1b 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -473,6 +473,17 @@ static const GUID *h264_decoder_output_types[] = + &MFVideoFormat_YV12, + }; + ++static WCHAR aac_decoderW[] = L"AAC Decoder"; ++static const GUID *aac_decoder_input_types[] = ++{ ++ &MFAudioFormat_AAC, ++}; ++static const GUID *aac_decoder_output_types[] = ++{ ++ &MFAudioFormat_Float, ++ &MFAudioFormat_PCM, ++}; ++ + static const struct mft + { + const GUID *clsid; +@@ -509,6 +520,17 @@ mfts[] = + ARRAY_SIZE(h264_decoder_output_types), + h264_decoder_output_types, + }, ++ { ++ &CLSID_CMSAACDecMFT, ++ &MFT_CATEGORY_AUDIO_DECODER, ++ aac_decoderW, ++ MFT_ENUM_FLAG_SYNCMFT, ++ &MFMediaType_Audio, ++ ARRAY_SIZE(aac_decoder_input_types), ++ aac_decoder_input_types, ++ ARRAY_SIZE(aac_decoder_output_types), ++ aac_decoder_output_types, ++ }, + }; + + HRESULT mfplat_DllRegisterServer(void) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0016-winegstreamer-Implement-Get-Attributes-functions-for.patch b/patches/mfplat-streaming-support/0016-winegstreamer-Implement-Get-Attributes-functions-for.patch deleted file mode 100644 index 136edb41..00000000 --- a/patches/mfplat-streaming-support/0016-winegstreamer-Implement-Get-Attributes-functions-for.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 7bc3f13dd779e7b998a877012c83a8ca9e7aba4f Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 3 Dec 2020 15:37:10 -0500 -Subject: [PATCH] winegstreamer: Implement Get*Attributes functions for color - converter transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 37 +++++++++++++++++++++++++++---- - 1 file changed, 33 insertions(+), 4 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 43b8dddeee7..9e6ece796f3 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -52,6 +52,8 @@ struct color_converter - { - IMFTransform IMFTransform_iface; - LONG refcount; -+ IMFAttributes *attributes; -+ IMFAttributes *output_attributes; - IMFMediaType *input_type; - IMFMediaType *output_type; - CRITICAL_SECTION cs; -@@ -102,6 +104,10 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) - { - transform->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&transform->cs); -+ if (transform->attributes) -+ IMFAttributes_Release(transform->attributes); -+ if (transform->output_attributes) -+ IMFAttributes_Release(transform->output_attributes); - gst_object_unref(transform->container); - heap_free(transform); - } -@@ -167,9 +173,14 @@ static HRESULT WINAPI color_converter_GetOutputStreamInfo(IMFTransform *iface, D - - static HRESULT WINAPI color_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) - { -- FIXME("%p, %p.\n", iface, attributes); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); - -- return E_NOTIMPL; -+ TRACE("%p, %p.\n", iface, attributes); -+ -+ *attributes = converter->attributes; -+ IMFAttributes_AddRef(*attributes); -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -@@ -183,9 +194,14 @@ static HRESULT WINAPI color_converter_GetInputStreamAttributes(IMFTransform *ifa - static HRESULT WINAPI color_converter_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, - IMFAttributes **attributes) - { -- FIXME("%p, %u, %p.\n", iface, id, attributes); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); - -- return E_NOTIMPL; -+ TRACE("%p, %u, %p.\n", iface, id, attributes); -+ -+ *attributes = converter->output_attributes; -+ IMFAttributes_AddRef(*attributes); -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_DeleteInputStream(IMFTransform *iface, DWORD id) -@@ -639,6 +655,7 @@ static const IMFTransformVtbl color_converter_vtbl = - HRESULT color_converter_create(REFIID riid, void **ret) - { - struct color_converter *object; -+ HRESULT hr; - - TRACE("%s %p\n", debugstr_guid(riid), ret); - -@@ -651,6 +668,18 @@ HRESULT color_converter_create(REFIID riid, void **ret) - InitializeCriticalSection(&object->cs); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); - -+ if (FAILED(hr = MFCreateAttributes(&object->attributes, 0))) -+ { -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return hr; -+ } -+ -+ if (FAILED(hr = MFCreateAttributes(&object->output_attributes, 0))) -+ { -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return hr; -+ } -+ - object->container = gst_bin_new(NULL); - - if (!(object->appsrc = gst_element_factory_make("appsrc", NULL))) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch b/patches/mfplat-streaming-support/0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch new file mode 100644 index 00000000..2e950245 --- /dev/null +++ b/patches/mfplat-streaming-support/0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch @@ -0,0 +1,45 @@ +From 86115ed0d28a1abb007b0eedf0442dbdf2e2127d Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 17:00:51 -0400 +Subject: [PATCH 16/39] winegstreamer: Rename GStreamer objects to be more + generic. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/wg_parser.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 2a982576ef5..44d0c9b71f3 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1242,7 +1242,7 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) + pthread_cond_init(&stream->event_cond, NULL); + pthread_cond_init(&stream->event_empty_cond, NULL); + +- sprintf(pad_name, "qz_sink_%u", parser->stream_count); ++ sprintf(pad_name, "wine_sink_%u", parser->stream_count); + stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK); + gst_pad_set_element_private(stream->my_sink, stream); + gst_pad_set_chain_function(stream->my_sink, sink_chain_cb); +@@ -1948,7 +1948,7 @@ static LONGLONG query_duration(GstPad *pad) + + static HRESULT wg_parser_connect_inner(struct wg_parser *parser) + { +- GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", ++ GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", + GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); + + parser->sink_connected = true; +@@ -1962,7 +1962,7 @@ static HRESULT wg_parser_connect_inner(struct wg_parser *parser) + parser->container = gst_bin_new(NULL); + gst_element_set_bus(parser->container, parser->bus); + +- parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src"); ++ parser->my_src = gst_pad_new_from_static_template(&src_template, "wine-src"); + gst_pad_set_getrange_function(parser->my_src, src_getrange_cb); + gst_pad_set_query_function(parser->my_src, src_query_cb); + gst_pad_set_activatemode_function(parser->my_src, src_activate_mode_cb); +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0017-winegstreamer-Implement-Get-Input-Output-CurrentType.patch b/patches/mfplat-streaming-support/0017-winegstreamer-Implement-Get-Input-Output-CurrentType.patch deleted file mode 100644 index bd74691c..00000000 --- a/patches/mfplat-streaming-support/0017-winegstreamer-Implement-Get-Input-Output-CurrentType.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 54919766d0ad2cf17e8cc6a8783794312964677c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 3 Dec 2020 15:43:21 -0500 -Subject: [PATCH] winegstreamer: Implement Get(Input/Output)CurrentType - functions for color converter transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 58 ++++++++++++++++++++++++++++--- - 1 file changed, 54 insertions(+), 4 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 9e6ece796f3..c7b1fae393f 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -466,16 +466,66 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - - static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) - { -- FIXME("%p, %u, %p.\n", iface, id, type); -+ IMFMediaType *ret; -+ HRESULT hr; - -- return E_NOTIMPL; -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ -+ TRACE("%p, %u, %p.\n", converter, id, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (FAILED(hr = MFCreateMediaType(&ret))) -+ return hr; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->input_type) -+ hr = IMFMediaType_CopyAllItems(converter->input_type, (IMFAttributes *)ret); -+ else -+ hr = MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ if (SUCCEEDED(hr)) -+ *type = ret; -+ else -+ IMFMediaType_Release(ret); -+ -+ return hr; - } - - static HRESULT WINAPI color_converter_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) - { -- FIXME("%p, %u, %p.\n", iface, id, type); -+ IMFMediaType *ret; -+ HRESULT hr; - -- return E_NOTIMPL; -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ -+ TRACE("%p, %u, %p.\n", converter, id, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (FAILED(hr = MFCreateMediaType(&ret))) -+ return hr; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->output_type) -+ hr = IMFMediaType_CopyAllItems(converter->output_type, (IMFAttributes *)ret); -+ else -+ hr = MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ if (SUCCEEDED(hr)) -+ *type = ret; -+ else -+ IMFMediaType_Release(ret); -+ -+ return hr; - } - - static HRESULT WINAPI color_converter_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0017-winegstreamer-Report-streams-backwards-in-media-sour.patch b/patches/mfplat-streaming-support/0017-winegstreamer-Report-streams-backwards-in-media-sour.patch new file mode 100644 index 00000000..7a528829 --- /dev/null +++ b/patches/mfplat-streaming-support/0017-winegstreamer-Report-streams-backwards-in-media-sour.patch @@ -0,0 +1,27 @@ +From 2451bb53540b32568e404f8ed2399b8b2a58e64d Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Fri, 19 Mar 2021 17:01:54 -0400 +Subject: [PATCH 17/39] winegstreamer: Report streams backwards in media + source. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/media_source.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index f658cc0a5fc..b0c4220cc00 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -1363,7 +1363,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ + descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); + for (i = 0; i < object->stream_count; i++) + { +- IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]); ++ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[object->stream_count - 1 - i]); + } + + if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0018-winegstreamer-Implement-IMFMediaSource-Stop.patch b/patches/mfplat-streaming-support/0018-winegstreamer-Implement-IMFMediaSource-Stop.patch deleted file mode 100644 index a03adf39..00000000 --- a/patches/mfplat-streaming-support/0018-winegstreamer-Implement-IMFMediaSource-Stop.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 1472041682ce09e0e8bdda78ed0366fba6aa41a0 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 7 May 2020 13:09:47 -0500 -Subject: [PATCH] winegstreamer: Implement IMFMediaSource::Stop. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/media_source.c | 31 +++++++++++++++++++++++++++++-- - 1 file changed, 29 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 5c502cf3ed5..655e765fee7 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -64,6 +64,7 @@ struct media_stream - enum source_async_op - { - SOURCE_ASYNC_START, -+ SOURCE_ASYNC_STOP, - SOURCE_ASYNC_REQUEST_SAMPLE, - }; - -@@ -343,6 +344,24 @@ static void start_pipeline(struct media_source *source, struct source_async_comm - gst_element_set_state(source->container, GST_STATE_PLAYING); - } - -+static void stop_pipeline(struct media_source *source) -+{ -+ unsigned int i; -+ -+ gst_element_set_state(source->container, GST_STATE_PAUSED); -+ -+ for (i = 0; i < source->stream_count; i++) -+ { -+ struct media_stream *stream = source->streams[i]; -+ if (stream->state != STREAM_INACTIVE) -+ IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL); -+ } -+ -+ IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL); -+ -+ source->state = SOURCE_STOPPED; -+} -+ - static void dispatch_end_of_presentation(struct media_source *source) - { - PROPVARIANT empty = {.vt = VT_EMPTY}; -@@ -417,6 +436,9 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA - case SOURCE_ASYNC_START: - start_pipeline(source, command); - break; -+ case SOURCE_ASYNC_STOP: -+ stop_pipeline(source); -+ break; - case SOURCE_ASYNC_REQUEST_SAMPLE: - wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token); - break; -@@ -1087,13 +1109,18 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD - static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) - { - struct media_source *source = impl_from_IMFMediaSource(iface); -+ struct source_async_command *command; -+ HRESULT hr; - -- FIXME("(%p): stub\n", source); -+ TRACE("(%p)\n", source); - - if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; - -- return E_NOTIMPL; -+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command))) -+ hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); -+ -+ return hr; - } - - static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch b/patches/mfplat-streaming-support/0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch new file mode 100644 index 00000000..afe3bc04 --- /dev/null +++ b/patches/mfplat-streaming-support/0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch @@ -0,0 +1,528 @@ +From 6f1c7d5735bc793ccfc059c22071ee546db0133a Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 17 Mar 2021 14:07:52 -0400 +Subject: [PATCH 18/39] winegstreamer: Implement ::Process(Input/Output) for + audio conversion transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/audioconvert.c | 280 +++++++++++++++++++++++++++++- + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/wg_parser.c | 93 ++++++++++ + 3 files changed, 367 insertions(+), 7 deletions(-) + +diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c +index 33350fb3566..8405f3bedc5 100644 +--- a/dlls/winegstreamer/audioconvert.c ++++ b/dlls/winegstreamer/audioconvert.c +@@ -35,6 +35,10 @@ struct audio_converter + IMFMediaType *input_type; + IMFMediaType *output_type; + CRITICAL_SECTION cs; ++ BOOL buffer_inflight; ++ LONGLONG buffer_pts, buffer_dur; ++ struct wg_parser *parser; ++ struct wg_parser_stream *stream; + }; + + static struct audio_converter *impl_audio_converter_from_IMFTransform(IMFTransform *iface) +@@ -80,6 +84,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) + { + transform->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&transform->cs); ++ if (transform->stream) ++ unix_funcs->wg_parser_disconnect(transform->parser); ++ if (transform->parser) ++ unix_funcs->wg_parser_destroy(transform->parser); + free(transform); + } + +@@ -272,6 +280,7 @@ fail: + static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) + { + GUID major_type, subtype; ++ struct wg_format format; + DWORD unused; + HRESULT hr; + +@@ -291,6 +300,11 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id + + if (converter->input_type) + { ++ if (converter->stream) ++ { ++ unix_funcs->wg_parser_disconnect(converter->parser); ++ converter->stream = NULL; ++ } + IMFMediaType_Release(converter->input_type); + converter->input_type = NULL; + } +@@ -317,6 +331,10 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id + if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) + return MF_E_INVALIDTYPE; + ++ mf_media_type_to_wg_format(type, &format); ++ if (!format.major_type) ++ return MF_E_INVALIDTYPE; ++ + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + +@@ -336,6 +354,21 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id + converter->input_type = NULL; + } + ++ if (converter->stream) ++ { ++ unix_funcs->wg_parser_disconnect(converter->parser); ++ converter->stream = NULL; ++ } ++ ++ if (converter->input_type && converter->output_type) ++ { ++ struct wg_format output_format; ++ mf_media_type_to_wg_format(converter->output_type, &output_format); ++ ++ if (SUCCEEDED(hr = unix_funcs->wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL))) ++ converter->stream = unix_funcs->wg_parser_get_stream(converter->parser, 0); ++ } ++ + LeaveCriticalSection(&converter->cs); + + return hr; +@@ -345,6 +378,7 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i + { + struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); + GUID major_type, subtype; ++ struct wg_format format; + DWORD unused; + HRESULT hr; + +@@ -353,9 +387,6 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + +- if (!converter->input_type) +- return MF_E_TRANSFORM_TYPE_NOT_SET; +- + if (!type) + { + if (flags & MFT_SET_TYPE_TEST_ONLY) +@@ -365,6 +396,11 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i + + if (converter->output_type) + { ++ if (converter->stream) ++ { ++ unix_funcs->wg_parser_disconnect(converter->parser); ++ converter->stream = NULL; ++ } + IMFMediaType_Release(converter->output_type); + converter->output_type = NULL; + } +@@ -391,6 +427,10 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i + if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) + return MF_E_INVALIDTYPE; + ++ mf_media_type_to_wg_format(type, &format); ++ if (!format.major_type) ++ return MF_E_INVALIDTYPE; ++ + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + +@@ -410,6 +450,21 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i + converter->output_type = NULL; + } + ++ if (converter->stream) ++ { ++ unix_funcs->wg_parser_disconnect(converter->parser); ++ converter->stream = NULL; ++ } ++ ++ if (converter->input_type && converter->output_type) ++ { ++ struct wg_format input_format; ++ mf_media_type_to_wg_format(converter->input_type, &input_format); ++ ++ if (SUCCEEDED(hr = unix_funcs->wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL))) ++ converter->stream = unix_funcs->wg_parser_get_stream(converter->parser, 0); ++ } ++ + LeaveCriticalSection(&converter->cs); + + return hr; +@@ -521,17 +576,221 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME + + static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) + { +- FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); ++ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); ++ IMFMediaBuffer *buffer = NULL; ++ unsigned char *buffer_data; ++ DWORD buffer_size; ++ uint64_t offset; ++ uint32_t size; ++ void *data; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags); ++ ++ if (flags) ++ WARN("Unsupported flags %#x.\n", flags); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (!converter->stream) ++ { ++ hr = MF_E_TRANSFORM_TYPE_NOT_SET; ++ goto done; ++ } ++ ++ if (converter->buffer_inflight) ++ { ++ hr = MF_E_NOTACCEPTING; ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) ++ goto done; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size))) ++ goto done; ++ ++ for (;;) ++ { ++ if (!unix_funcs->wg_parser_get_read_request(converter->parser, &data, &offset, &size)) ++ continue; ++ ++ memcpy(data, buffer_data, min(buffer_size, size)); ++ ++ unix_funcs->wg_parser_complete_read_request(converter->parser, WG_READ_SUCCESS, buffer_size); ++ ++ if (buffer_size <= size) ++ break; ++ ++ buffer_data += size; ++ buffer_size -= size; ++ } ++ ++ IMFMediaBuffer_Unlock(buffer); ++ converter->buffer_inflight = TRUE; ++ if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) ++ converter->buffer_pts = -1; ++ if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur))) ++ converter->buffer_dur = -1; ++ ++done: ++ if (buffer) ++ IMFMediaBuffer_Release(buffer); ++ LeaveCriticalSection(&converter->cs); ++ return hr; + } + + static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) + { +- FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); ++ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); ++ IMFSample *allocated_sample = NULL; ++ IMFMediaBuffer *buffer = NULL; ++ struct wg_parser_event event; ++ unsigned char *buffer_data; ++ DWORD buffer_len; ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); ++ ++ if (flags) ++ WARN("Unsupported flags %#x.\n", flags); ++ ++ if (!count) ++ return S_OK; ++ ++ if (count != 1) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (samples[0].dwStreamID != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (!converter->stream) ++ { ++ hr = MF_E_TRANSFORM_TYPE_NOT_SET; ++ goto done; ++ } ++ ++ if (!converter->buffer_inflight) ++ { ++ hr = MF_E_TRANSFORM_NEED_MORE_INPUT; ++ goto done; ++ } ++ ++ for (;;) ++ { ++ unix_funcs->wg_parser_stream_get_event(converter->stream, &event); ++ ++ switch (event.type) ++ { ++ case WG_PARSER_EVENT_BUFFER: ++ break; ++ ++ case WG_PARSER_EVENT_SEGMENT: ++ continue; ++ ++ default: ++ WARN("Unexpected event, %u\n", event.type); ++ continue; ++ } ++ break; ++ } ++ ++ if (!samples[0].pSample) ++ { ++ if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) ++ { ++ ERR("Failed to create buffer, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (FAILED(hr = MFCreateSample(&allocated_sample))) ++ { ++ ERR("Failed to create sample, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ samples[0].pSample = allocated_sample; ++ ++ if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) ++ { ++ ERR("Failed to add buffer, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ IMFMediaBuffer_Release(buffer); ++ buffer = NULL; ++ } ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) ++ { ++ ERR("Failed to get buffer from sample, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) ++ { ++ ERR("Failed to get buffer size, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (buffer_len < event.u.buffer.size) ++ { ++ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", ++ buffer_len, event.u.buffer.size); ++ ++ hr = MF_E_BUFFERTOOSMALL; ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) ++ { ++ ERR("Failed to set size, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) ++ { ++ ERR("Failed to lock buffer hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (!unix_funcs->wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) ++ { ++ ERR("Failed to copy buffer.\n"); ++ IMFMediaBuffer_Unlock(buffer); ++ hr = E_FAIL; ++ goto done; ++ } ++ ++ IMFMediaBuffer_Unlock(buffer); ++ ++ unix_funcs->wg_parser_stream_release_buffer(converter->stream); ++ converter->buffer_inflight = FALSE; ++ ++ if (converter->buffer_pts != -1) ++ IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts); ++ if (converter->buffer_dur != -1) ++ IMFSample_SetSampleDuration(samples[0].pSample, converter->buffer_dur); ++ ++ samples[0].dwStatus = 0; ++ samples[0].pEvents = NULL; ++ ++ done: ++ if (buffer) ++ IMFMediaBuffer_Release(buffer); ++ if (allocated_sample && FAILED(hr)) ++ { ++ IMFSample_Release(allocated_sample); ++ samples[0].pSample = NULL; ++ } ++ LeaveCriticalSection(&converter->cs); ++ return hr; + } + + static const IMFTransformVtbl audio_converter_vtbl = +@@ -579,6 +838,13 @@ HRESULT audio_converter_create(REFIID riid, void **ret) + InitializeCriticalSection(&object->cs); + object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": audio_converter_lock"); + ++ if (!(object->parser = unix_funcs->wg_raw_media_converter_create())) ++ { ++ ERR("Failed to create audio converter due to GStreamer error.\n"); ++ IMFTransform_Release(&object->IMFTransform_iface); ++ return E_OUTOFMEMORY; ++ } ++ + *ret = &object->IMFTransform_iface; + return S_OK; + } +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 6407aff484c..ee6d19e74b6 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -203,6 +203,7 @@ struct unix_funcs + struct wg_parser *(CDECL *wg_avi_parser_create)(void); + struct wg_parser *(CDECL *wg_mpeg_audio_parser_create)(void); + struct wg_parser *(CDECL *wg_wave_parser_create)(void); ++ struct wg_parser *(CDECL *wg_raw_media_converter_create)(void); + void (CDECL *wg_parser_destroy)(struct wg_parser *parser); + + HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size); +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 44d0c9b71f3..6f4dd28082b 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -2328,6 +2328,89 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) + return TRUE; + } + ++static BOOL raw_media_converter_init_gst(struct wg_parser *parser) ++{ ++ BOOL video = parser->input_format.major_type == WG_MAJOR_TYPE_VIDEO; ++ struct wg_parser_stream *stream; ++ GstElement *convert, *resampler; ++ GstPad *their_src; ++ int ret; ++ ++ if (parser->seekable) ++ return FALSE; ++ ++ if (parser->expected_stream_count != 1) ++ return FALSE; ++ ++ if (video) ++ { ++ if (!(convert = gst_element_factory_make("videoconvert", NULL))) ++ { ++ ERR("Failed to create videoconvert; are %u-bit GStreamer \"base\" plugins installed?\n", ++ 8 * (int)sizeof(void*)); ++ return FALSE; ++ } ++ ++ gst_bin_add(GST_BIN(parser->container), convert); ++ ++ parser->their_sink = gst_element_get_static_pad(convert, "sink"); ++ their_src = gst_element_get_static_pad(convert, "src"); ++ } ++ else ++ { ++ if (!(convert = gst_element_factory_make("audioconvert", NULL))) ++ { ++ ERR("Failed to create audioconvert; are %u-bit GStreamer \"base\" plugins installed?\n", ++ 8 * (int)sizeof(void*)); ++ return FALSE; ++ } ++ ++ gst_bin_add(GST_BIN(parser->container), convert); ++ ++ if (!(resampler = gst_element_factory_make("audioresample", NULL))) ++ { ++ ERR("Failed to create audioresample; are %u-bit GStreamer \"base\" plugins installed?\n", ++ 8 * (int)sizeof(void*)); ++ return FALSE; ++ } ++ ++ gst_bin_add(GST_BIN(parser->container), resampler); ++ ++ gst_element_link(convert, resampler); ++ parser->their_sink = gst_element_get_static_pad(convert, "sink"); ++ their_src = gst_element_get_static_pad(resampler, "src"); ++ } ++ ++ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) ++ { ++ ERR("Failed to link sink pads, error %d.\n", ret); ++ return FALSE; ++ } ++ ++ if (!(stream = create_stream(parser))) ++ return FALSE; ++ ++ stream->their_src = their_src; ++ gst_object_ref(stream->their_src); ++ if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0) ++ { ++ ERR("Failed to link source pads, error %d.\n", ret); ++ return FALSE; ++ } ++ ++ gst_pad_set_active(stream->my_sink, 1); ++ gst_element_set_state(parser->container, GST_STATE_PAUSED); ++ gst_pad_set_active(parser->my_src, 1); ++ ret = gst_element_get_state(parser->container, NULL, NULL, -1); ++ if (ret == GST_STATE_CHANGE_FAILURE) ++ { ++ ERR("Failed to play stream.\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + static struct wg_parser *wg_parser_create(void) + { + struct wg_parser *parser; +@@ -2381,6 +2464,15 @@ static struct wg_parser * CDECL wg_wave_parser_create(void) + return parser; + } + ++static struct wg_parser * CDECL wg_raw_media_converter_create(void) ++{ ++ struct wg_parser *parser; ++ ++ if ((parser = wg_parser_create())) ++ parser->init_gst = raw_media_converter_init_gst; ++ return parser; ++} ++ + static void CDECL wg_parser_destroy(struct wg_parser *parser) + { + if (parser->bus) +@@ -2403,6 +2495,7 @@ static const struct unix_funcs funcs = + wg_avi_parser_create, + wg_mpeg_audio_parser_create, + wg_wave_parser_create, ++ wg_raw_media_converter_create, + wg_parser_destroy, + + wg_parser_connect, +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0004-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch b/patches/mfplat-streaming-support/0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch similarity index 51% rename from patches/mfplat-streaming-support/0004-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch rename to patches/mfplat-streaming-support/0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch index 82449920..b502d080 100644 --- a/patches/mfplat-streaming-support/0004-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch +++ b/patches/mfplat-streaming-support/0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch @@ -1,26 +1,28 @@ -From 13e0d5671caaeae69bde747e547a5bd4524dd2ff Mon Sep 17 00:00:00 2001 +From b3906f3a8faa32710b99a80e374bca70087c5c19 Mon Sep 17 00:00:00 2001 From: Derek Lesho -Date: Wed, 18 Nov 2020 14:32:27 -0600 -Subject: [PATCH] winegstreamer: Implement ::Get(Input/Output)StreamInfo for - audio conversion transform. +Date: Wed, 17 Mar 2021 15:12:20 -0400 +Subject: [PATCH 19/39] winegstreamer: Implement ::Get(Input/Output)StreamInfo + for audio conversion transform. Signed-off-by: Derek Lesho --- - dlls/winegstreamer/audioconvert.c | 23 +++++++++++++++++++---- - 1 file changed, 19 insertions(+), 4 deletions(-) + dlls/winegstreamer/audioconvert.c | 42 ++++++++++++++++++++++++++++--- + 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 631c57d6d55..d204d9582ba 100644 +index 8405f3bedc5..4ad64d58e47 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c -@@ -123,16 +123,31 @@ static HRESULT WINAPI audio_converter_GetStreamIDs(IMFTransform *iface, DWORD in +@@ -123,16 +123,50 @@ static HRESULT WINAPI audio_converter_GetStreamIDs(IMFTransform *iface, DWORD in static HRESULT WINAPI audio_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) { - FIXME("%p %u %p.\n", iface, id, info); -+ TRACE("%p %u %p.\n", iface, id, info); ++ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - return E_NOTIMPL; ++ TRACE("%p %u %p.\n", iface, id, info); ++ + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + @@ -28,6 +30,14 @@ index 631c57d6d55..d204d9582ba 100644 + info->cbMaxLookahead = 0; + info->cbAlignment = 0; + info->hnsMaxLatency = 0; ++ info->cbSize = 0; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (converter->input_type) ++ IMFMediaType_GetUINT32(converter->input_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &info->cbSize); ++ ++ LeaveCriticalSection(&converter->cs); + + return S_OK; } @@ -35,20 +45,29 @@ index 631c57d6d55..d204d9582ba 100644 static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { - FIXME("%p %u %p.\n", iface, id, info); -+ TRACE("%p %u %p.\n", iface, id, info); ++ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - return E_NOTIMPL; ++ TRACE("%p %u %p.\n", iface, id, info); ++ + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + -+ info->dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; -+ info->cbSize = 0; ++ info->dwFlags = MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES | MFT_OUTPUT_STREAM_WHOLE_SAMPLES; + info->cbAlignment = 0; ++ info->cbSize = 0; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (converter->output_type) ++ IMFMediaType_GetUINT32(converter->output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &info->cbSize); ++ ++ LeaveCriticalSection(&converter->cs); + + return S_OK; } static HRESULT WINAPI audio_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -- -2.29.2 +2.30.2 diff --git a/patches/mfplat-streaming-support/0020-mf-Add-invalid-connect-method-test.patch b/patches/mfplat-streaming-support/0020-mf-Add-invalid-connect-method-test.patch deleted file mode 100644 index 856b79e6..00000000 --- a/patches/mfplat-streaming-support/0020-mf-Add-invalid-connect-method-test.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 539f0ad63d83dd1f60a9a54063f3cb108d71f794 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 30 Nov 2020 11:56:48 -0500 -Subject: [PATCH] mf: Add invalid connect method test. - -Nikolay stripped out this test in his updated version of the patchset, which is fine. But I think it's useful to have it somewhere. - -Signed-off-by: Derek Lesho ---- - dlls/mf/tests/mf.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - -diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c -index 8272064466f..32ae84b837b 100644 ---- a/dlls/mf/tests/mf.c -+++ b/dlls/mf/tests/mf.c -@@ -1824,6 +1824,34 @@ static void test_topology_loader(void) - LOADER_TODO, - }, - -+ { -+ /* MP3 -> PCM */ -+ &MFMediaType_Audio, -+ { -+ { -+ { &MF_MT_SUBTYPE, WAVE_FORMAT_MPEGLAYER3 }, -+ { &MF_MT_AUDIO_NUM_CHANNELS, 2 }, -+ { &MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100 }, -+ { &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 16000 }, -+ { &MF_MT_AUDIO_BLOCK_ALIGNMENT, 1 }, -+ } -+ }, -+ { -+ { -+ { &MF_MT_SUBTYPE, WAVE_FORMAT_PCM }, -+ { &MF_MT_AUDIO_NUM_CHANNELS, 1 }, -+ { &MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100 }, -+ { &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100 }, -+ { &MF_MT_AUDIO_BLOCK_ALIGNMENT, 1 }, -+ { &MF_MT_AUDIO_BITS_PER_SAMPLE, 8 }, -+ } -+ }, -+ -+ MF_CONNECT_ALLOW_DECODER &~ MF_CONNECT_ALLOW_CONVERTER, -+ MF_E_INVALIDMEDIATYPE, -+ LOADER_TODO, -+ }, -+ - { - /* MP3 -> PCM */ - &MFMediaType_Audio, --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0005-winegstreamer-Implement-Get-Attributes-functions-for.patch b/patches/mfplat-streaming-support/0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch similarity index 62% rename from patches/mfplat-streaming-support/0005-winegstreamer-Implement-Get-Attributes-functions-for.patch rename to patches/mfplat-streaming-support/0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch index f89cf541..8897ea44 100644 --- a/patches/mfplat-streaming-support/0005-winegstreamer-Implement-Get-Attributes-functions-for.patch +++ b/patches/mfplat-streaming-support/0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch @@ -1,29 +1,27 @@ +From a7ae40f14dc926f02fca792b11b7374550dbd7ef Mon Sep 17 00:00:00 2001 From: Derek Lesho -Subject: [PATCH resend 5/5] winegstreamer: Semi-stub Get*Attributes functions for audio converter transform. -Message-Id: <20210118193047.267366-5-dlesho@codeweavers.com> -Date: Mon, 18 Jan 2021 14:30:47 -0500 -In-Reply-To: <20210118193047.267366-1-dlesho@codeweavers.com> -References: <20210118193047.267366-1-dlesho@codeweavers.com> +Date: Wed, 17 Mar 2021 15:19:32 -0400 +Subject: [PATCH 20/39] winegstreamer: Semi-stub Get*Attributes functions for + audio converter transform. Signed-off-by: Derek Lesho --- - dlls/winegstreamer/audioconvert.c | 37 +++++++++++++++++++++++++++---- - 1 file changed, 33 insertions(+), 4 deletions(-) + dlls/winegstreamer/audioconvert.c | 39 +++++++++++++++++++++++++++---- + 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index a95fc5506e7..2a5f87fec94 100644 +index 4ad64d58e47..43fe8b04e64 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c -@@ -37,6 +37,8 @@ struct audio_converter - { - IMFTransform IMFTransform_iface; - LONG refcount; -+ IMFAttributes *attributes; -+ IMFAttributes *output_attributes; - IMFMediaType *input_type; - IMFMediaType *output_type; - CRITICAL_SECTION cs; -@@ -87,6 +89,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) +@@ -39,6 +39,7 @@ struct audio_converter + LONGLONG buffer_pts, buffer_dur; + struct wg_parser *parser; + struct wg_parser_stream *stream; ++ IMFAttributes *attributes, *output_attributes; + }; + + static struct audio_converter *impl_audio_converter_from_IMFTransform(IMFTransform *iface) +@@ -84,6 +85,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) { transform->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&transform->cs); @@ -31,10 +29,10 @@ index a95fc5506e7..2a5f87fec94 100644 + IMFAttributes_Release(transform->attributes); + if (transform->output_attributes) + IMFAttributes_Release(transform->output_attributes); - gst_object_unref(transform->container); - heap_free(transform); - } -@@ -155,9 +161,14 @@ static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, D + if (transform->stream) + unix_funcs->wg_parser_disconnect(transform->parser); + if (transform->parser) +@@ -171,9 +176,14 @@ static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, D static HRESULT WINAPI audio_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) { @@ -51,7 +49,7 @@ index a95fc5506e7..2a5f87fec94 100644 } static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -@@ -171,9 +182,14 @@ static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *ifa +@@ -187,9 +197,17 @@ static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *ifa static HRESULT WINAPI audio_converter_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) { @@ -61,6 +59,9 @@ index a95fc5506e7..2a5f87fec94 100644 - return E_NOTIMPL; + TRACE("%p, %u, %p.\n", iface, id, attributes); + ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ + *attributes = converter->output_attributes; + IMFAttributes_AddRef(*attributes); + @@ -68,15 +69,15 @@ index a95fc5506e7..2a5f87fec94 100644 } static HRESULT WINAPI audio_converter_DeleteInputStream(IMFTransform *iface, DWORD id) -@@ -715,6 +731,7 @@ HRESULT audio_converter_create(REFIID riid, void **ret) +@@ -860,6 +878,7 @@ static const IMFTransformVtbl audio_converter_vtbl = + HRESULT audio_converter_create(REFIID riid, void **ret) { - GstElement *audioconvert, *resampler; struct audio_converter *object; + HRESULT hr; TRACE("%s %p\n", debugstr_guid(riid), ret); -@@ -727,6 +744,18 @@ HRESULT audio_converter_create(REFIID riid, void **ret) +@@ -872,6 +891,18 @@ HRESULT audio_converter_create(REFIID riid, void **ret) InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": audio_converter_lock"); @@ -92,10 +93,9 @@ index a95fc5506e7..2a5f87fec94 100644 + return hr; + } + - object->container = gst_bin_new(NULL); - - if (!(object->appsrc = gst_element_factory_make("appsrc", NULL))) - + if (!(object->parser = unix_funcs->wg_raw_media_converter_create())) + { + ERR("Failed to create audio converter due to GStreamer error.\n"); -- -2.30.0 +2.30.2 diff --git a/patches/mfplat-streaming-support/0021-Allow-for-compressed-types.patch b/patches/mfplat-streaming-support/0021-Allow-for-compressed-types.patch deleted file mode 100644 index 9825d30d..00000000 --- a/patches/mfplat-streaming-support/0021-Allow-for-compressed-types.patch +++ /dev/null @@ -1,71 +0,0 @@ -From dd7243f4ee9f7bee1019621c974f98737b760905 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 2 Dec 2020 17:12:22 -0500 -Subject: [PATCH] Allow for compressed types. - ---- - dlls/winegstreamer/mfplat.c | 28 ++++++++++++++++++---------- - 1 file changed, 18 insertions(+), 10 deletions(-) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index f4a0c5b00f0..8d2d8996f22 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -779,22 +779,20 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - { - DWORD rate = -1, channels = -1, channel_mask = -1; - -- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) -- { -- ERR("Sample rate not set.\n"); -- return NULL; -- } -- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels))) -- { -- ERR("Channel count not set.\n"); -- return NULL; -- } -+ IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate); -+ IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels); - IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, &channel_mask); - - if (IsEqualGUID(&subtype, &MFAudioFormat_Float)) - { - GstAudioInfo float_info; - -+ if (rate == -1 || channels == -1) -+ { -+ ERR("Incomplete media type.\n"); -+ return NULL; -+ } -+ - gst_audio_info_set_format(&float_info, GST_AUDIO_FORMAT_F32LE, rate, channels, NULL); - output = gst_audio_info_to_caps(&float_info); - } -@@ -804,6 +802,12 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - GstAudioInfo pcm_info; - DWORD bits_per_sample; - -+ if (rate == -1 || channels == -1) -+ { -+ ERR("Incomplete media type.\n"); -+ return NULL; -+ } -+ - if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample))) - { - pcm_format = gst_audio_format_build_integer(bits_per_sample > 8, G_LITTLE_ENDIAN, bits_per_sample, bits_per_sample); -@@ -823,6 +827,10 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - return NULL; - } - -+ if (rate != -1) -+ gst_caps_set_simple(output, "rate", G_TYPE_INT, rate, NULL); -+ if (channels != -1) -+ gst_caps_set_simple(output, "channels", G_TYPE_INT, channels, NULL); - if (channel_mask != -1) - gst_caps_set_simple(output, "channel-mask", GST_TYPE_BITMASK, (guint64) channel_mask, NULL); - --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0007-winegstreamer-Introduce-color-conversion-transform.patch b/patches/mfplat-streaming-support/0021-winegstreamer-Introduce-color-conversion-transform.patch similarity index 83% rename from patches/mfplat-streaming-support/0007-winegstreamer-Introduce-color-conversion-transform.patch rename to patches/mfplat-streaming-support/0021-winegstreamer-Introduce-color-conversion-transform.patch index 4faf6ba3..fafd0e0b 100644 --- a/patches/mfplat-streaming-support/0007-winegstreamer-Introduce-color-conversion-transform.patch +++ b/patches/mfplat-streaming-support/0021-winegstreamer-Introduce-color-conversion-transform.patch @@ -1,38 +1,39 @@ -From b5316e74275511a63372473cb6bb10b8f2f8d2e1 Mon Sep 17 00:00:00 2001 +From 08d022a3705763c3d1ab3ffc6700c702cc6aed7b Mon Sep 17 00:00:00 2001 From: Derek Lesho -Date: Tue, 1 Dec 2020 13:16:27 -0500 -Subject: [PATCH] winegstreamer: Introduce color conversion transform. +Date: Wed, 17 Mar 2021 15:35:20 -0400 +Subject: [PATCH 21/39] winegstreamer: Introduce color conversion transform. -Serves as a wrapper of videoconvert, and roughly fills the roll of Windows' CColorConverterDMO. +Serves as a wrapper of videoconvert, and exposes the CColorConverterDMO MFT interface. Signed-off-by: Derek Lesho --- dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/colorconvert.c | 302 +++++++++++++++++++ + dlls/winegstreamer/colorconvert.c | 298 +++++++++++++++++++ dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 3 + + dlls/winegstreamer/mfplat.c | 2 + dlls/winegstreamer/winegstreamer_classes.idl | 6 + - 5 files changed, 313 insertions(+) + include/wmcodecdsp.idl | 5 + + 6 files changed, 313 insertions(+) create mode 100644 dlls/winegstreamer/colorconvert.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 0b3229160b9..5395d6fd501 100644 +index 7459cccf7e4..ec688f4425b 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in -@@ -7,6 +7,7 @@ PARENTSRC = ../strmbase +@@ -8,6 +8,7 @@ EXTRADLLFLAGS = -mno-cygwin C_SRCS = \ audioconvert.c \ + colorconvert.c \ - filter.c \ - gst_cbs.c \ - gstdemux.c \ + decode_transform.c \ + main.c \ + media_source.c \ diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c new file mode 100644 -index 00000000000..8d0823fc0dc +index 00000000000..1f0d061a30c --- /dev/null +++ b/dlls/winegstreamer/colorconvert.c -@@ -0,0 +1,302 @@ +@@ -0,0 +1,298 @@ +/* GStreamer Color Converter + * + * Copyright 2020 Derek Lesho @@ -52,16 +53,12 @@ index 00000000000..8d0823fc0dc + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + -+#include "config.h" -+ +#include "gst_private.h" + +#include "mfapi.h" +#include "mferror.h" -+#include "mfidl.h" + +#include "wine/debug.h" -+#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + @@ -80,8 +77,8 @@ index 00000000000..8d0823fc0dc +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + -+ if (IsEqualIID(riid, &IID_IMFTransform) || -+ IsEqualIID(riid, &IID_IUnknown)) ++ if (IsEqualGUID(riid, &IID_IMFTransform) || ++ IsEqualGUID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFTransform_AddRef(iface); @@ -112,7 +109,7 @@ index 00000000000..8d0823fc0dc + + if (!refcount) + { -+ heap_free(transform); ++ free(transform); + } + + return refcount; @@ -326,7 +323,7 @@ index 00000000000..8d0823fc0dc + + TRACE("%s %p\n", debugstr_guid(riid), ret); + -+ if (!(object = heap_alloc_zero(sizeof(*object)))) ++ if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFTransform_iface.lpVtbl = &color_converter_vtbl; @@ -336,51 +333,64 @@ index 00000000000..8d0823fc0dc + return S_OK; +} diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 14b6a011ac2..075e0ce1f0f 100644 +index ee6d19e74b6..0827f70112f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h -@@ -87,5 +87,6 @@ GstBuffer *gst_buffer_from_mf_sample(IMFSample *in) DECLSPEC_HIDDEN; +@@ -269,6 +269,7 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) DE HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; +HRESULT color_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - #endif /* __GST_PRIVATE_INCLUDED__ */ + enum decoder_type + { diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 883084b2d89..288b79997cd 100644 +index 28b45893b1b..60e594b5d6c 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -407,6 +407,8 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a +@@ -22,6 +22,7 @@ + #include "mfapi.h" + #include "ks.h" + #include "ksmedia.h" ++#include "wmcodecdsp.h" - static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}}; + #include "wine/debug.h" -+static GUID CLSID_WINEColorConverter = {0x2be8b27f,0xcd60,0x4b8a,{0x95,0xae,0xd1,0x74,0xcc,0x5c,0xba,0xa7}}; -+ - static const struct class_object - { - const GUID *clsid; -@@ -417,6 +419,7 @@ class_objects[] = +@@ -422,6 +423,7 @@ class_objects[] = { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, { &CLSID_WINEAudioConverter, &audio_converter_create }, -+ { &CLSID_WINEColorConverter, &color_converter_create }, ++ { &CLSID_CColorConvertDMO, &color_converter_create }, + { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, + { &CLSID_CMSAACDecMFT, &aac_decoder_create }, }; - - HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index cf1fc69f38a..47c10a09cf0 100644 +index 4c58d83403b..093fca3521e 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -67,3 +67,9 @@ coclass GStreamerByteStreamHandler {} - uuid(6a170414-aad9-4693-b806-3a0c47c570d6) +@@ -79,3 +79,9 @@ coclass CMSH264DecoderMFT { } + uuid(32d186a7-218f-4c75-8876-dd77273a8999) ] - coclass WINEAudioConverter { } + coclass CMSAACDecMFT { } + +[ + threading(both), -+ uuid(2be8b27f-cd60-4b8a-95ae-d174cc5cbaa7) ++ uuid(98230571-0087-4204-b020-3282538e57d3) +] -+coclass WINEColorConverter { } ++coclass CColorConvertDMO { } +diff --git a/include/wmcodecdsp.idl b/include/wmcodecdsp.idl +index 61381bee6d4..87305422332 100644 +--- a/include/wmcodecdsp.idl ++++ b/include/wmcodecdsp.idl +@@ -30,3 +30,8 @@ coclass CMP3DecMediaObject {} + uuid(f447b69e-1884-4a7e-8055-346f74d6edb3) + ] + coclass CResamplerMediaObject {} ++ ++[ ++ uuid(98230571-0087-4204-b020-3282538e57d3) ++] ++coclass CColorConvertDMO {} -- -2.29.2 +2.30.2 diff --git a/patches/mfplat-streaming-support/0022-mf-session-Unconditionally-deliver-NULL-EOS-samples.patch b/patches/mfplat-streaming-support/0022-mf-session-Unconditionally-deliver-NULL-EOS-samples.patch deleted file mode 100644 index 0239d05c..00000000 --- a/patches/mfplat-streaming-support/0022-mf-session-Unconditionally-deliver-NULL-EOS-samples.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 3b4148fbc1338e6a202d852491eba1362c905bfc Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 14 Oct 2020 11:07:05 -0500 -Subject: [PATCH] mf/session: Unconditionally deliver NULL (EOS) samples. - -Signed-off-by: Derek Lesho ---- - dlls/mf/session.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/dlls/mf/session.c b/dlls/mf/session.c -index 1a7439a13c3..07e29cd013f 100644 ---- a/dlls/mf/session.c -+++ b/dlls/mf/session.c -@@ -2858,11 +2858,12 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop - LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples, - struct sample, entry) - { -- if (!topo_node->u.transform.outputs[i].requests) -+ if (!topo_node->u.transform.outputs[i].requests && sample_entry->sample) - break; - - session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample); -- topo_node->u.transform.outputs[i].requests--; -+ if (sample_entry->sample) -+ topo_node->u.transform.outputs[i].requests--; - - transform_release_sample(sample_entry); - } --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0008-winegstreamer-Register-the-color-conversion-transfor.patch b/patches/mfplat-streaming-support/0022-winegstreamer-Register-the-color-conversion-transfor.patch similarity index 59% rename from patches/mfplat-streaming-support/0008-winegstreamer-Register-the-color-conversion-transfor.patch rename to patches/mfplat-streaming-support/0022-winegstreamer-Register-the-color-conversion-transfor.patch index 4b485b2a..c9acbd89 100644 --- a/patches/mfplat-streaming-support/0008-winegstreamer-Register-the-color-conversion-transfor.patch +++ b/patches/mfplat-streaming-support/0022-winegstreamer-Register-the-color-conversion-transfor.patch @@ -1,23 +1,23 @@ -From 18799e737ff065a62ea1c92c9a684940053d9dfb Mon Sep 17 00:00:00 2001 +From 9ce58d1f3f2f7be32bc61ed29149ba32c154170a Mon Sep 17 00:00:00 2001 From: Derek Lesho -Date: Thu, 3 Dec 2020 12:45:48 -0500 -Subject: [PATCH] winegstreamer: Register the color conversion transform. +Date: Wed, 17 Mar 2021 15:37:17 -0400 +Subject: [PATCH 22/39] winegstreamer: Register the color conversion transform. Signed-off-by: Derek Lesho --- - dlls/winegstreamer/mfplat.c | 34 +++++++++++++++++++++++++++++++++- - 1 file changed, 33 insertions(+), 1 deletion(-) + dlls/winegstreamer/mfplat.c | 33 ++++++++++++++++++++++++++++++++- + 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 288b79997cd..1b19c43d991 100644 +index 60e594b5d6c..251ab021073 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c -@@ -455,6 +455,26 @@ static const GUID *audio_converter_supported_types[] = +@@ -461,6 +461,26 @@ static const GUID *audio_converter_supported_types[] = &MFAudioFormat_Float, }; -+static WCHAR color_converterW[] = {'C','o','l','o','r',' ','C','o','n','v','e','r','t','e','r',0}; -+const GUID *color_converter_supported_types[] = ++static WCHAR color_converterW[] = L"Color Converter"; ++static const GUID *color_converter_supported_types[] = +{ + &MFVideoFormat_RGB24, + &MFVideoFormat_RGB32, @@ -36,15 +36,15 @@ index 288b79997cd..1b19c43d991 100644 + &MFVideoFormat_YVYU, +}; + - static const struct mft + static WCHAR h264_decoderW[] = L"H.264 Decoder"; + static const GUID *h264_decoder_input_types[] = { - const GUID *clsid; -@@ -482,13 +502,25 @@ mfts[] = +@@ -511,6 +531,17 @@ mfts[] = + ARRAY_SIZE(audio_converter_supported_types), audio_converter_supported_types, - NULL }, + { -+ &CLSID_WINEColorConverter, ++ &CLSID_CColorConvertDMO, + &MFT_CATEGORY_VIDEO_EFFECT, + color_converterW, + MFT_ENUM_FLAG_SYNCMFT, @@ -53,11 +53,11 @@ index 288b79997cd..1b19c43d991 100644 + color_converter_supported_types, + ARRAY_SIZE(color_converter_supported_types), + color_converter_supported_types, -+ NULL + }, - }; - - HRESULT mfplat_DllRegisterServer(void) + { + &CLSID_CMSH264DecoderMFT, + &MFT_CATEGORY_VIDEO_DECODER, +@@ -539,7 +570,7 @@ HRESULT mfplat_DllRegisterServer(void) { unsigned int i, j; HRESULT hr; @@ -67,5 +67,5 @@ index 288b79997cd..1b19c43d991 100644 for (i = 0; i < ARRAY_SIZE(mfts); i++) { -- -2.29.2 +2.30.2 diff --git a/patches/mfplat-streaming-support/0023-mf-session-Request-more-samples-when-a-transform-nee.patch b/patches/mfplat-streaming-support/0023-mf-session-Request-more-samples-when-a-transform-nee.patch deleted file mode 100644 index acbff915..00000000 --- a/patches/mfplat-streaming-support/0023-mf-session-Request-more-samples-when-a-transform-nee.patch +++ /dev/null @@ -1,42 +0,0 @@ -From e1c9fe73263c2220be53482d195264832842279e Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 2 Apr 2020 15:42:18 -0500 -Subject: [PATCH] mf/session: Request more samples when a transform needs them. - -Signed-off-by: Derek Lesho ---- - dlls/mf/session.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/dlls/mf/session.c b/dlls/mf/session.c -index 07e29cd013f..5a08a2eb6c6 100644 ---- a/dlls/mf/session.c -+++ b/dlls/mf/session.c -@@ -2759,6 +2759,8 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, - return hr; - } - -+static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output); -+ - static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, - IMFSample *sample) - { -@@ -2834,7 +2836,14 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop - WARN("Drain command failed for transform, hr %#x.\n", hr); - } - -- transform_node_pull_samples(session, topo_node); -+ if (transform_node_pull_samples(session, topo_node) == MF_E_TRANSFORM_NEED_MORE_INPUT && !drain) -+ { -+ IMFTopologyNode *upstream_node; -+ DWORD upstream_output; -+ -+ if (SUCCEEDED(IMFTopologyNode_GetInput(node, input, &upstream_node, &upstream_output))) -+ session_request_sample_from_node(session, upstream_node, upstream_output); -+ } - - /* Remaining unprocessed input has been discarded, now queue markers for every output. */ - if (drain) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0009-winegstreamer-Implement-GetInputAvailableType-for-co.patch b/patches/mfplat-streaming-support/0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch similarity index 85% rename from patches/mfplat-streaming-support/0009-winegstreamer-Implement-GetInputAvailableType-for-co.patch rename to patches/mfplat-streaming-support/0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch index 672cdc62..027d567e 100644 --- a/patches/mfplat-streaming-support/0009-winegstreamer-Implement-GetInputAvailableType-for-co.patch +++ b/patches/mfplat-streaming-support/0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch @@ -1,8 +1,8 @@ -From 15b54cf08d296483e6d4c211eeae50db62f70804 Mon Sep 17 00:00:00 2001 +From 03498a3854a6a8fbe055354c1cde8c03119208dc Mon Sep 17 00:00:00 2001 From: Derek Lesho -Date: Thu, 3 Dec 2020 12:55:14 -0500 -Subject: [PATCH] winegstreamer: Implement ::GetInputAvailableType for color - conversion transform. +Date: Wed, 17 Mar 2021 15:41:33 -0400 +Subject: [PATCH 23/39] winegstreamer: Implement ::GetInputAvailableType for + color conversion transform. Signed-off-by: Derek Lesho --- @@ -10,10 +10,10 @@ Signed-off-by: Derek Lesho 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 8d0823fc0dc..9a1d2880234 100644 +index 1f0d061a30c..078782daaed 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c -@@ -30,6 +30,24 @@ +@@ -26,6 +26,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); @@ -38,7 +38,7 @@ index 8d0823fc0dc..9a1d2880234 100644 struct color_converter { IMFTransform IMFTransform_iface; -@@ -164,9 +182,35 @@ static HRESULT WINAPI color_converter_AddInputStreams(IMFTransform *iface, DWORD +@@ -160,9 +178,35 @@ static HRESULT WINAPI color_converter_AddInputStreams(IMFTransform *iface, DWORD static HRESULT WINAPI color_converter_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { @@ -77,5 +77,5 @@ index 8d0823fc0dc..9a1d2880234 100644 static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -- -2.29.2 +2.30.2 diff --git a/patches/mfplat-streaming-support/0024-HACK-Flush-decoder-when-changing-times.patch b/patches/mfplat-streaming-support/0024-HACK-Flush-decoder-when-changing-times.patch deleted file mode 100644 index cb672e38..00000000 --- a/patches/mfplat-streaming-support/0024-HACK-Flush-decoder-when-changing-times.patch +++ /dev/null @@ -1,27 +0,0 @@ -From b25ab6a73f44bdab1a4ce782a27a8b3f1213cf64 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 15 Oct 2020 12:18:10 -0500 -Subject: [PATCH] HACK: Flush decoder when changing times. - ---- - dlls/mf/session.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/mf/session.c b/dlls/mf/session.c -index 5a08a2eb6c6..a6bc7803390 100644 ---- a/dlls/mf/session.c -+++ b/dlls/mf/session.c -@@ -2326,7 +2326,10 @@ static void session_set_presentation_clock(struct media_session *session) - LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) - { - if (node->type == MF_TOPOLOGY_TRANSFORM_NODE) -+ { -+ IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0); - IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); -+ } - } - - if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET)) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0010-winegstreamer-Implement-SetInputType-for-color-conve.patch b/patches/mfplat-streaming-support/0024-winegstreamer-Implement-SetInputType-for-color-conve.patch similarity index 55% rename from patches/mfplat-streaming-support/0010-winegstreamer-Implement-SetInputType-for-color-conve.patch rename to patches/mfplat-streaming-support/0024-winegstreamer-Implement-SetInputType-for-color-conve.patch index cdcde8a6..51a0cfc0 100644 --- a/patches/mfplat-streaming-support/0010-winegstreamer-Implement-SetInputType-for-color-conve.patch +++ b/patches/mfplat-streaming-support/0024-winegstreamer-Implement-SetInputType-for-color-conve.patch @@ -1,19 +1,19 @@ -From 096a5070ac3ce917e6c8ae010e8e80c8ffbde3c4 Mon Sep 17 00:00:00 2001 +From 5c6e2cc11f047f728e8cb1100a7044398a1b5898 Mon Sep 17 00:00:00 2001 From: Derek Lesho -Date: Thu, 3 Dec 2020 14:34:07 -0500 -Subject: [PATCH] winegstreamer: Implement ::SetInputType for color conversion - transform. +Date: Wed, 17 Mar 2021 16:01:18 -0400 +Subject: [PATCH 24/39] winegstreamer: Implement ::SetInputType for color + conversion transform. Signed-off-by: Derek Lesho --- - dlls/winegstreamer/colorconvert.c | 76 ++++++++++++++++++++++++++++++- - 1 file changed, 74 insertions(+), 2 deletions(-) + dlls/winegstreamer/colorconvert.c | 75 ++++++++++++++++++++++++++++++- + 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 9a1d2880234..5dd48188147 100644 +index 078782daaed..06186ed7846 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c -@@ -52,6 +52,8 @@ struct color_converter +@@ -48,6 +48,8 @@ struct color_converter { IMFTransform IMFTransform_iface; LONG refcount; @@ -22,59 +22,66 @@ index 9a1d2880234..5dd48188147 100644 }; static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface) -@@ -95,6 +97,8 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) +@@ -91,6 +93,8 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) if (!refcount) { + transform->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&transform->cs); - heap_free(transform); + free(transform); } -@@ -223,9 +227,74 @@ static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface +@@ -219,9 +223,73 @@ static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ GstCaps *input_caps; ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ GUID major_type, subtype; + unsigned int i; + HRESULT hr; - return E_NOTIMPL; -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ + TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + -+ if (type) ++ if (!type) + { -+ GUID major_type, subtype; ++ if (flags & MFT_SET_TYPE_TEST_ONLY) ++ return S_OK; + -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) -+ return MF_E_INVALIDTYPE; -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return MF_E_INVALIDTYPE; ++ EnterCriticalSection(&converter->cs); + -+ if (!(IsEqualGUID(&major_type, &MFMediaType_Video))) -+ return MF_E_INVALIDTYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(raw_types); i++) ++ if (converter->input_type) + { -+ if (IsEqualGUID(&subtype, raw_types[i])) -+ break; ++ IMFMediaType_Release(converter->input_type); ++ converter->input_type = NULL; + } + -+ if (i == ARRAY_SIZE(raw_types)) -+ return MF_E_INVALIDTYPE; ++ LeaveCriticalSection(&converter->cs); + -+ if (!(input_caps = caps_from_mf_media_type(type))) -+ return MF_E_INVALIDTYPE; -+ -+ gst_caps_unref(input_caps); ++ return S_OK; + } + ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) ++ return MF_E_INVALIDTYPE; ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) ++ return MF_E_INVALIDTYPE; ++ ++ if (!IsEqualGUID(&major_type, &MFMediaType_Video)) ++ return MF_E_INVALIDTYPE; ++ ++ for (i = 0; i < ARRAY_SIZE(raw_types); i++) ++ { ++ if (IsEqualGUID(&subtype, raw_types[i])) ++ break; ++ } ++ ++ if (i == ARRAY_SIZE(raw_types)) ++ return MF_E_INVALIDTYPE; ++ + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + @@ -82,21 +89,13 @@ index 9a1d2880234..5dd48188147 100644 + + hr = S_OK; + -+ if (type) -+ { -+ if (!converter->input_type) -+ hr = MFCreateMediaType(&converter->input_type); ++ if (!converter->input_type) ++ hr = MFCreateMediaType(&converter->input_type); + -+ if (SUCCEEDED(hr)) -+ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->input_type); ++ if (SUCCEEDED(hr)) ++ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->input_type); + -+ if (FAILED(hr)) -+ { -+ IMFMediaType_Release(converter->input_type); -+ converter->input_type = NULL; -+ } -+ } -+ else ++ if (FAILED(hr)) + { + IMFMediaType_Release(converter->input_type); + converter->input_type = NULL; @@ -108,7 +107,7 @@ index 9a1d2880234..5dd48188147 100644 } static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -@@ -341,6 +410,9 @@ HRESULT color_converter_create(REFIID riid, void **ret) +@@ -337,6 +405,9 @@ HRESULT color_converter_create(REFIID riid, void **ret) object->IMFTransform_iface.lpVtbl = &color_converter_vtbl; object->refcount = 1; @@ -119,5 +118,5 @@ index 9a1d2880234..5dd48188147 100644 return S_OK; } -- -2.29.2 +2.30.2 diff --git a/patches/mfplat-streaming-support/0025-winegstreamer-Add-IMFSeekInfo-GetNearestKeyFrames-st.patch b/patches/mfplat-streaming-support/0025-winegstreamer-Add-IMFSeekInfo-GetNearestKeyFrames-st.patch deleted file mode 100644 index c5f33aa4..00000000 --- a/patches/mfplat-streaming-support/0025-winegstreamer-Add-IMFSeekInfo-GetNearestKeyFrames-st.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 8b681e5bd589b330790a0e887f5dbcd380e84a05 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 2 Nov 2020 09:56:54 -0600 -Subject: [PATCH] winegstreamer: Add IMFSeekInfo::GetNearestKeyFrames stub. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/media_source.c | 111 ++++++++++++++++++++++++++++++ - 1 file changed, 111 insertions(+) - -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 655e765fee7..a0bce3cfe9d 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -92,6 +92,8 @@ struct source_async_command - struct media_source - { - IMFMediaSource IMFMediaSource_iface; -+ IMFGetService IMFGetService_iface; -+ IMFSeekInfo IMFSeekInfo_iface; - IMFAsyncCallback async_commands_callback; - LONG ref; - DWORD async_commands_queue; -@@ -124,6 +126,16 @@ static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *ifac - return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); - } - -+static inline struct media_source *impl_from_IMFGetService(IMFGetService *iface) -+{ -+ return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface); -+} -+ -+static inline struct media_source *impl_from_IMFSeekInfo(IMFSeekInfo *iface) -+{ -+ return CONTAINING_RECORD(iface, struct media_source, IMFSeekInfo_iface); -+} -+ - static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface) - { - return CONTAINING_RECORD(iface, struct media_source, async_commands_callback); -@@ -978,6 +990,10 @@ static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID - { - *out = &source->IMFMediaSource_iface; - } -+ else if(IsEqualIID(riid, &IID_IMFGetService)) -+ { -+ *out = &source->IMFGetService_iface; -+ } - else - { - FIXME("(%s, %p)\n", debugstr_guid(riid), out); -@@ -1212,6 +1228,99 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = - media_source_Shutdown, - }; - -+static HRESULT WINAPI source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) -+{ -+ struct media_source *source = impl_from_IMFGetService(iface); -+ return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); -+} -+ -+static ULONG WINAPI source_get_service_AddRef(IMFGetService *iface) -+{ -+ struct media_source *source = impl_from_IMFGetService(iface); -+ return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); -+} -+ -+static ULONG WINAPI source_get_service_Release(IMFGetService *iface) -+{ -+ struct media_source *source = impl_from_IMFGetService(iface); -+ return IMFMediaSource_Release(&source->IMFMediaSource_iface); -+} -+ -+static HRESULT WINAPI source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) -+{ -+ struct media_source *source = impl_from_IMFGetService(iface); -+ -+ TRACE("(%p)->(%s, %s, %p)\n", source, debugstr_guid(service), debugstr_guid(riid), obj); -+ -+ if (source->state == SOURCE_SHUTDOWN) -+ return MF_E_SHUTDOWN; -+ -+ *obj = NULL; -+ -+ if (IsEqualIID(service, &MF_SCRUBBING_SERVICE)) -+ { -+ if (IsEqualIID(riid, &IID_IMFSeekInfo)) -+ { -+ *obj = &source->IMFSeekInfo_iface; -+ } -+ } -+ -+ if (*obj) -+ IUnknown_AddRef((IUnknown*) *obj); -+ -+ return *obj ? S_OK : E_NOINTERFACE; -+} -+ -+static const IMFGetServiceVtbl IMFGetService_vtbl = -+{ -+ source_get_service_QueryInterface, -+ source_get_service_AddRef, -+ source_get_service_Release, -+ source_get_service_GetService, -+}; -+ -+static HRESULT WINAPI source_seek_info_QueryInterface(IMFSeekInfo *iface, REFIID riid, void **obj) -+{ -+ struct media_source *source = impl_from_IMFSeekInfo(iface); -+ return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); -+} -+ -+static ULONG WINAPI source_seek_info_AddRef(IMFSeekInfo *iface) -+{ -+ struct media_source *source = impl_from_IMFSeekInfo(iface); -+ return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); -+} -+ -+static ULONG WINAPI source_seek_info_Release(IMFSeekInfo *iface) -+{ -+ struct media_source *source = impl_from_IMFSeekInfo(iface); -+ return IMFMediaSource_Release(&source->IMFMediaSource_iface); -+} -+ -+static HRESULT WINAPI source_seek_info_GetNearestKeyFrames(IMFSeekInfo *iface, const GUID *format, -+ const PROPVARIANT *position, PROPVARIANT *prev_frame, PROPVARIANT *next_frame) -+{ -+ struct media_source *source = impl_from_IMFSeekInfo(iface); -+ -+ FIXME("(%p)->(%s, %p, %p, %p) - semi-stub\n", source, debugstr_guid(format), position, prev_frame, next_frame); -+ -+ if (source->state == SOURCE_SHUTDOWN) -+ return MF_E_SHUTDOWN; -+ -+ PropVariantCopy(prev_frame, position); -+ PropVariantCopy(next_frame, position); -+ -+ return S_OK; -+} -+ -+static const IMFSeekInfoVtbl IMFSeekInfo_vtbl = -+{ -+ source_seek_info_QueryInterface, -+ source_seek_info_AddRef, -+ source_seek_info_Release, -+ source_seek_info_GetNearestKeyFrames, -+}; -+ - static void stream_added(GstElement *element, GstPad *pad, gpointer user) - { - struct media_source *source = user; -@@ -1283,6 +1392,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - return E_OUTOFMEMORY; - - object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; -+ object->IMFGetService_iface.lpVtbl = &IMFGetService_vtbl; -+ object->IMFSeekInfo_iface.lpVtbl = &IMFSeekInfo_vtbl; - object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl; - object->ref = 1; - object->byte_stream = bytestream; --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch b/patches/mfplat-streaming-support/0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch new file mode 100644 index 00000000..58fb15f2 --- /dev/null +++ b/patches/mfplat-streaming-support/0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch @@ -0,0 +1,64 @@ +From 70de073ef2395952f425411ef794e7238730ab52 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 17 Mar 2021 16:04:31 -0400 +Subject: [PATCH 25/39] winegstreamer: Implement ::GetOutputAvailableType for + color conversion transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/colorconvert.c | 38 +++++++++++++++++++++++++++++-- + 1 file changed, 36 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c +index 06186ed7846..6d7064a4482 100644 +--- a/dlls/winegstreamer/colorconvert.c ++++ b/dlls/winegstreamer/colorconvert.c +@@ -216,9 +216,43 @@ static HRESULT WINAPI color_converter_GetInputAvailableType(IMFTransform *iface, + static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) + { +- FIXME("%p, %u, %u, %p.\n", iface, id, index, type); ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ IMFMediaType *ret; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %u, %p.\n", iface, id, index, type); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (index >= ARRAY_SIZE(raw_types)) ++ return MF_E_NO_MORE_TYPES; ++ ++ if (FAILED(hr = MFCreateMediaType(&ret))) ++ return hr; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (converter->input_type) ++ IMFMediaType_CopyAllItems(converter->input_type, (IMFAttributes *) ret); ++ ++ LeaveCriticalSection(&converter->cs); ++ ++ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) ++ { ++ IMFMediaType_Release(ret); ++ return hr; ++ } ++ ++ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_SUBTYPE, raw_types[index]))) ++ { ++ IMFMediaType_Release(ret); ++ return hr; ++ } ++ ++ *type = ret; ++ ++ return S_OK; + } + + static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0026-winegstreamer-Fixup-raw-audio-caps-to-be-compatible-.patch b/patches/mfplat-streaming-support/0026-winegstreamer-Fixup-raw-audio-caps-to-be-compatible-.patch deleted file mode 100644 index 344ea71e..00000000 --- a/patches/mfplat-streaming-support/0026-winegstreamer-Fixup-raw-audio-caps-to-be-compatible-.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 18dea0ccadf90b4ac523dc1073c3870fdd6bcf6a Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 6 Nov 2020 10:06:23 -0600 -Subject: [PATCH] winegstreamer: Fixup raw audio caps to be compatible with - IMFMediaType. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/media_source.c | 7 +++- - dlls/winegstreamer/mfplat.c | 57 +++++++++++++++++++++++++++++++ - 3 files changed, 64 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 075e0ce1f0f..dcf76554b6d 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -79,6 +79,7 @@ extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) - extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN; - - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; -+GstCaps *make_mf_compatible_caps(GstCaps *caps) DECLSPEC_HIDDEN; - IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) DECLSPEC_HIDDEN; - GstCaps *caps_from_mf_media_type(IMFMediaType *type) DECLSPEC_HIDDEN; - IMFSample *mf_sample_from_gst_buffer(GstBuffer *in) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index a0bce3cfe9d..5f3457e50b0 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -891,15 +891,20 @@ fail: - - static HRESULT media_stream_init_desc(struct media_stream *stream) - { -- GstCaps *current_caps = gst_pad_get_current_caps(stream->their_src); -+ GstCaps *base_caps = gst_pad_get_current_caps(stream->their_src); - IMFMediaTypeHandler *type_handler = NULL; - IMFMediaType **stream_types = NULL; - IMFMediaType *stream_type = NULL; -+ GstCaps *current_caps = make_mf_compatible_caps(base_caps); - DWORD type_count = 0; - const gchar *major_type; - unsigned int i; - HRESULT hr; - -+ gst_caps_unref(base_caps); -+ if (!current_caps) -+ return E_FAIL; -+ - major_type = gst_structure_get_name(gst_caps_get_structure(current_caps, 0)); - - if (!strcmp(major_type, "video/x-raw")) -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 8d2d8996f22..a2873907437 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -710,6 +710,63 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - return media_type; - } - -+GstCaps *make_mf_compatible_caps(GstCaps *caps) -+{ -+ GstCaps *ret; -+ IMFMediaType *media_type; -+ GstStructure *structure; -+ const char *mime_type; -+ -+ if (gst_caps_get_size(caps) != 1) -+ return NULL; -+ -+ /* Optimization: Don't copy caps if no transformation is needed */ -+ if ((media_type = mf_media_type_from_caps(caps))) -+ { -+ IMFMediaType_Release(media_type); -+ return gst_caps_ref(caps); -+ } -+ -+ ret = gst_caps_copy(caps); -+ structure = gst_caps_get_structure(ret, 0); -+ mime_type = gst_structure_get_name(structure); -+ -+ if (!strcmp(mime_type, "audio/x-raw")) -+ { -+ const char *format; -+ if ((format = gst_structure_get_string(structure, "format"))) -+ { -+ char type; -+ unsigned int bits_per_sample; -+ char endian[2]; -+ char new_format[6]; -+ -+ if (strlen(format) <= 5 && (sscanf(format, "%c%u%2c", &type, &bits_per_sample, endian) >= 2)) -+ { -+ if (type == 'U' || type == 'S') -+ type = bits_per_sample == 8 ? 'U' : 'S'; -+ -+ if (endian[0] == 'B') -+ endian[0] = 'L'; -+ -+ sprintf(new_format, "%c%u%.2s", type, bits_per_sample, bits_per_sample > 8 ? endian : 0); -+ gst_caps_set_simple(caps, "format", G_TYPE_STRING, new_format, NULL); -+ } -+ } -+ } -+ -+ if ((media_type = mf_media_type_from_caps(ret))) -+ IMFMediaType_Release(media_type); -+ -+ if (!media_type) -+ { -+ gst_caps_unref(ret); -+ return NULL; -+ } -+ -+ return ret; -+} -+ - GstCaps *caps_from_mf_media_type(IMFMediaType *type) - { - GUID major_type; --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch b/patches/mfplat-streaming-support/0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch new file mode 100644 index 00000000..d2b2ad57 --- /dev/null +++ b/patches/mfplat-streaming-support/0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch @@ -0,0 +1,153 @@ +From d044e2fb2a690340a0011a8527592e7a90db2faa Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 17 Mar 2021 16:26:28 -0400 +Subject: [PATCH 26/39] winegstreamer: Implement ::SetOutputType for color + conversion transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/colorconvert.c | 99 ++++++++++++++++++++++++++++++- + 1 file changed, 97 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c +index 6d7064a4482..e001c6c827e 100644 +--- a/dlls/winegstreamer/colorconvert.c ++++ b/dlls/winegstreamer/colorconvert.c +@@ -49,6 +49,7 @@ struct color_converter + IMFTransform IMFTransform_iface; + LONG refcount; + IMFMediaType *input_type; ++ IMFMediaType *output_type; + CRITICAL_SECTION cs; + }; + +@@ -95,6 +96,8 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) + { + transform->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&transform->cs); ++ if (transform->output_type) ++ IMFMediaType_Release(transform->output_type); + free(transform); + } + +@@ -258,6 +261,7 @@ static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface + static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) + { + struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ UINT64 input_framesize, output_framesize; + GUID major_type, subtype; + unsigned int i; + HRESULT hr; +@@ -302,6 +306,19 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id + if (i == ARRAY_SIZE(raw_types)) + return MF_E_INVALIDTYPE; + ++ EnterCriticalSection(&converter->cs); ++ ++ if(converter->output_type ++ && SUCCEEDED(IMFMediaType_GetUINT64(converter->output_type, &MF_MT_FRAME_SIZE, &output_framesize)) ++ && SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &input_framesize)) ++ && input_framesize != output_framesize) ++ { ++ LeaveCriticalSection(&converter->cs); ++ return MF_E_INVALIDTYPE; ++ } ++ ++ LeaveCriticalSection(&converter->cs); ++ + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + +@@ -328,9 +345,87 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id + + static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) + { +- FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ UINT64 input_framesize, output_framesize; ++ GUID major_type, subtype; ++ unsigned int i; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (!type) ++ { ++ if (flags & MFT_SET_TYPE_TEST_ONLY) ++ return S_OK; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (converter->output_type) ++ { ++ IMFMediaType_Release(converter->output_type); ++ converter->output_type = NULL; ++ } ++ ++ LeaveCriticalSection(&converter->cs); ++ ++ return S_OK; ++ } ++ ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) ++ return MF_E_INVALIDTYPE; ++ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) ++ return MF_E_INVALIDTYPE; ++ ++ if (!IsEqualGUID(&major_type, &MFMediaType_Video)) ++ return MF_E_INVALIDTYPE; ++ ++ for (i = 0; i < ARRAY_SIZE(raw_types); i++) ++ { ++ if (IsEqualGUID(&subtype, raw_types[i])) ++ break; ++ } ++ ++ if (i == ARRAY_SIZE(raw_types)) ++ return MF_E_INVALIDTYPE; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if(converter->input_type ++ && SUCCEEDED(IMFMediaType_GetUINT64(converter->input_type, &MF_MT_FRAME_SIZE, &input_framesize)) ++ && SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &output_framesize)) ++ && input_framesize != output_framesize) ++ { ++ LeaveCriticalSection(&converter->cs); ++ return MF_E_INVALIDTYPE; ++ } ++ ++ LeaveCriticalSection(&converter->cs); ++ ++ if (flags & MFT_SET_TYPE_TEST_ONLY) ++ return S_OK; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ hr = S_OK; ++ ++ if (!converter->output_type) ++ hr = MFCreateMediaType(&converter->output_type); ++ ++ if (SUCCEEDED(hr)) ++ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->output_type); ++ ++ if (FAILED(hr)) ++ { ++ IMFMediaType_Release(converter->output_type); ++ converter->output_type = NULL; ++ } ++ ++ LeaveCriticalSection(&converter->cs); ++ ++ return S_OK; + } + + static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0027-winegstreamer-Implement-Process-Input-Output-for-col.patch b/patches/mfplat-streaming-support/0027-winegstreamer-Implement-Process-Input-Output-for-col.patch new file mode 100644 index 00000000..f8cbce13 --- /dev/null +++ b/patches/mfplat-streaming-support/0027-winegstreamer-Implement-Process-Input-Output-for-col.patch @@ -0,0 +1,390 @@ +From 93e4d5996b5abedef39d4667363f42cabaaa8705 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 17 Mar 2021 16:49:13 -0400 +Subject: [PATCH 27/39] winegstreamer: Implement ::Process(Input/Output) for + color conversion transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/colorconvert.c | 279 +++++++++++++++++++++++++++++- + 1 file changed, 274 insertions(+), 5 deletions(-) + +diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c +index e001c6c827e..a543b9d77af 100644 +--- a/dlls/winegstreamer/colorconvert.c ++++ b/dlls/winegstreamer/colorconvert.c +@@ -51,6 +51,10 @@ struct color_converter + IMFMediaType *input_type; + IMFMediaType *output_type; + CRITICAL_SECTION cs; ++ BOOL buffer_inflight; ++ LONGLONG buffer_pts, buffer_dur; ++ struct wg_parser *parser; ++ struct wg_parser_stream *stream; + }; + + static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface) +@@ -98,6 +102,10 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) + DeleteCriticalSection(&transform->cs); + if (transform->output_type) + IMFMediaType_Release(transform->output_type); ++ if (transform->stream) ++ unix_funcs->wg_parser_disconnect(transform->parser); ++ if (transform->parser) ++ unix_funcs->wg_parser_destroy(transform->parser); + free(transform); + } + +@@ -263,6 +271,7 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id + struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); + UINT64 input_framesize, output_framesize; + GUID major_type, subtype; ++ struct wg_format format; + unsigned int i; + HRESULT hr; + +@@ -280,6 +289,11 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id + + if (converter->input_type) + { ++ if (converter->stream) ++ { ++ unix_funcs->wg_parser_disconnect(converter->parser); ++ converter->stream = NULL; ++ } + IMFMediaType_Release(converter->input_type); + converter->input_type = NULL; + } +@@ -319,6 +333,10 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id + + LeaveCriticalSection(&converter->cs); + ++ mf_media_type_to_wg_format(type, &format); ++ if (!format.major_type) ++ return MF_E_INVALIDTYPE; ++ + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + +@@ -338,6 +356,21 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id + converter->input_type = NULL; + } + ++ if (converter->stream) ++ { ++ unix_funcs->wg_parser_disconnect(converter->parser); ++ converter->stream = NULL; ++ } ++ ++ if (converter->input_type && converter->output_type) ++ { ++ struct wg_format output_format; ++ mf_media_type_to_wg_format(converter->output_type, &output_format); ++ ++ if (SUCCEEDED(hr = unix_funcs->wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL))) ++ converter->stream = unix_funcs->wg_parser_get_stream(converter->parser, 0); ++ } ++ + LeaveCriticalSection(&converter->cs); + + return hr; +@@ -348,6 +381,7 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i + struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); + UINT64 input_framesize, output_framesize; + GUID major_type, subtype; ++ struct wg_format format; + unsigned int i; + HRESULT hr; + +@@ -365,6 +399,11 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i + + if (converter->output_type) + { ++ if (converter->stream) ++ { ++ unix_funcs->wg_parser_disconnect(converter->parser); ++ converter->stream = NULL; ++ } + IMFMediaType_Release(converter->output_type); + converter->output_type = NULL; + } +@@ -404,6 +443,10 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i + + LeaveCriticalSection(&converter->cs); + ++ mf_media_type_to_wg_format(type, &format); ++ if (!format.major_type) ++ return MF_E_INVALIDTYPE; ++ + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + +@@ -423,9 +466,24 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i + converter->output_type = NULL; + } + ++ if (converter->stream) ++ { ++ unix_funcs->wg_parser_disconnect(converter->parser); ++ converter->stream = NULL; ++ } ++ ++ if (converter->input_type && converter->output_type) ++ { ++ struct wg_format input_format; ++ mf_media_type_to_wg_format(converter->input_type, &input_format); ++ ++ if (SUCCEEDED(hr = unix_funcs->wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL))) ++ converter->stream = unix_funcs->wg_parser_get_stream(converter->parser, 0); ++ } ++ + LeaveCriticalSection(&converter->cs); + +- return S_OK; ++ return hr; + } + + static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +@@ -479,17 +537,221 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME + + static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) + { +- FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ IMFMediaBuffer *buffer = NULL; ++ unsigned char *buffer_data; ++ DWORD buffer_size; ++ uint64_t offset; ++ uint32_t size; ++ void *data; ++ HRESULT hr; + +- return E_NOTIMPL; ++ TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags); ++ ++ if (flags) ++ WARN("Unsupported flags %#x.\n", flags); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (!converter->stream) ++ { ++ hr = MF_E_TRANSFORM_TYPE_NOT_SET; ++ goto done; ++ } ++ ++ if (converter->buffer_inflight) ++ { ++ hr = MF_E_NOTACCEPTING; ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) ++ goto done; ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size))) ++ goto done; ++ ++ for (;;) ++ { ++ if (!unix_funcs->wg_parser_get_read_request(converter->parser, &data, &offset, &size)) ++ continue; ++ ++ memcpy(data, buffer_data, min(buffer_size, size)); ++ ++ unix_funcs->wg_parser_complete_read_request(converter->parser, WG_READ_SUCCESS, buffer_size); ++ ++ if (buffer_size <= size) ++ break; ++ ++ buffer_data += size; ++ buffer_size -= size; ++ } ++ ++ IMFMediaBuffer_Unlock(buffer); ++ converter->buffer_inflight = TRUE; ++ if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) ++ converter->buffer_pts = -1; ++ if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur))) ++ converter->buffer_dur = -1; ++ ++done: ++ if (buffer) ++ IMFMediaBuffer_Release(buffer); ++ LeaveCriticalSection(&converter->cs); ++ return hr; + } + + static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) + { +- FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ IMFSample *allocated_sample = NULL; ++ IMFMediaBuffer *buffer = NULL; ++ struct wg_parser_event event; ++ unsigned char *buffer_data; ++ DWORD buffer_len; ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); ++ ++ if (flags) ++ WARN("Unsupported flags %#x.\n", flags); ++ ++ if (!count) ++ return S_OK; ++ ++ if (count != 1) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ if (samples[0].dwStreamID != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (!converter->stream) ++ { ++ hr = MF_E_TRANSFORM_TYPE_NOT_SET; ++ goto done; ++ } ++ ++ if (!converter->buffer_inflight) ++ { ++ hr = MF_E_TRANSFORM_NEED_MORE_INPUT; ++ goto done; ++ } ++ ++ for (;;) ++ { ++ unix_funcs->wg_parser_stream_get_event(converter->stream, &event); ++ ++ switch (event.type) ++ { ++ case WG_PARSER_EVENT_BUFFER: ++ break; ++ ++ case WG_PARSER_EVENT_SEGMENT: ++ continue; ++ ++ default: ++ WARN("Unexpected event, %u\n", event.type); ++ continue; ++ } ++ break; ++ } ++ ++ if (!samples[0].pSample) ++ { ++ if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) ++ { ++ ERR("Failed to create buffer, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (FAILED(hr = MFCreateSample(&allocated_sample))) ++ { ++ ERR("Failed to create sample, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ samples[0].pSample = allocated_sample; ++ ++ if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) ++ { ++ ERR("Failed to add buffer, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ IMFMediaBuffer_Release(buffer); ++ buffer = NULL; ++ } ++ ++ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) ++ { ++ ERR("Failed to get buffer from sample, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) ++ { ++ ERR("Failed to get buffer size, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (buffer_len < event.u.buffer.size) ++ { ++ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", ++ buffer_len, event.u.buffer.size); ++ ++ hr = MF_E_BUFFERTOOSMALL; ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) ++ { ++ ERR("Failed to set size, hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) ++ { ++ ERR("Failed to lock buffer hr %#x.\n", hr); ++ goto done; ++ } ++ ++ if (!unix_funcs->wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) ++ { ++ ERR("Failed to copy buffer.\n"); ++ IMFMediaBuffer_Unlock(buffer); ++ hr = E_FAIL; ++ goto done; ++ } ++ ++ IMFMediaBuffer_Unlock(buffer); ++ ++ unix_funcs->wg_parser_stream_release_buffer(converter->stream); ++ converter->buffer_inflight = FALSE; ++ ++ if (converter->buffer_pts != -1) ++ IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts); ++ if (converter->buffer_dur != -1) ++ IMFSample_SetSampleDuration(samples[0].pSample, converter->buffer_dur); ++ ++ samples[0].dwStatus = 0; ++ samples[0].pEvents = NULL; ++ ++ done: ++ if (buffer) ++ IMFMediaBuffer_Release(buffer); ++ if (FAILED(hr) && allocated_sample) ++ { ++ IMFSample_Release(allocated_sample); ++ samples[0].pSample = NULL; ++ } ++ LeaveCriticalSection(&converter->cs); ++ return hr; + } + + static const IMFTransformVtbl color_converter_vtbl = +@@ -537,6 +799,13 @@ HRESULT color_converter_create(REFIID riid, void **ret) + InitializeCriticalSection(&object->cs); + object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); + ++ if (!(object->parser = unix_funcs->wg_raw_media_converter_create())) ++ { ++ ERR("Failed to create video converter due to GStreamer error.\n"); ++ IMFTransform_Release(&object->IMFTransform_iface); ++ return E_OUTOFMEMORY; ++ } ++ + *ret = &object->IMFTransform_iface; + return S_OK; + } +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0027-winegstreamer-Set-MF_PD_MIME_TYPE-on-source-s-presen.patch b/patches/mfplat-streaming-support/0027-winegstreamer-Set-MF_PD_MIME_TYPE-on-source-s-presen.patch deleted file mode 100644 index f6292614..00000000 --- a/patches/mfplat-streaming-support/0027-winegstreamer-Set-MF_PD_MIME_TYPE-on-source-s-presen.patch +++ /dev/null @@ -1,45 +0,0 @@ -From fe0175d8676cbd15ddeac07876e726ef76eef7b5 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 2 Nov 2020 10:18:27 -0600 -Subject: [PATCH] winegstreamer: Set MF_PD_MIME_TYPE on source's presentation - descriptor. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/media_source.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 5f3457e50b0..1bbbb2ffd81 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -1377,6 +1377,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - GST_STATIC_PAD_TEMPLATE("mf_src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); - - IMFStreamDescriptor **descriptors = NULL; -+ IMFAttributes *byte_stream_attributes; - struct media_source *object; - gint64 total_pres_time = 0; - DWORD bytestream_caps; -@@ -1520,6 +1521,18 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - if (object->stream_count) - IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time / 100); - -+ if (SUCCEEDED(IMFByteStream_QueryInterface(object->byte_stream, &IID_IMFAttributes, (void **)&byte_stream_attributes))) -+ { -+ WCHAR *mimeW = NULL; -+ DWORD length; -+ if (SUCCEEDED(IMFAttributes_GetAllocatedString(byte_stream_attributes, &MF_BYTESTREAM_CONTENT_TYPE, &mimeW, &length))) -+ { -+ IMFPresentationDescriptor_SetString(object->pres_desc, &MF_PD_MIME_TYPE, mimeW); -+ CoTaskMemFree(mimeW); -+ } -+ IMFAttributes_Release(byte_stream_attributes); -+ } -+ - object->state = SOURCE_STOPPED; - - *out_media_source = object; --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0014-winegstreamer-Implement-ProcessMessage-for-color-con.patch b/patches/mfplat-streaming-support/0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch similarity index 68% rename from patches/mfplat-streaming-support/0014-winegstreamer-Implement-ProcessMessage-for-color-con.patch rename to patches/mfplat-streaming-support/0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch index ec2d4be9..c4fc15bc 100644 --- a/patches/mfplat-streaming-support/0014-winegstreamer-Implement-ProcessMessage-for-color-con.patch +++ b/patches/mfplat-streaming-support/0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch @@ -1,19 +1,19 @@ -From d68df1b4131caa500cea5c4241be3c55b2728d4c Mon Sep 17 00:00:00 2001 +From ebb43b337b5733e4b3530b4b04fcda0afa517852 Mon Sep 17 00:00:00 2001 From: Derek Lesho -Date: Thu, 3 Dec 2020 16:02:20 -0500 -Subject: [PATCH] winegstreamer: Implement ::ProcessMessage for color +Date: Wed, 17 Mar 2021 16:50:47 -0400 +Subject: [PATCH 28/39] winegstreamer: Implement ::ProcessMessage for color conversion MFT. Signed-off-by: Derek Lesho --- - dlls/winegstreamer/colorconvert.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) + dlls/winegstreamer/colorconvert.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index b77f3358c52..c07ef22acc3 100644 +index a543b9d77af..8d2f7a7d643 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c -@@ -477,9 +477,16 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id +@@ -530,9 +530,17 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { @@ -23,6 +23,7 @@ index b77f3358c52..c07ef22acc3 100644 - return E_NOTIMPL; + switch(message) + { ++ case MFT_MESSAGE_COMMAND_FLUSH: + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + return S_OK; + default: @@ -33,5 +34,5 @@ index b77f3358c52..c07ef22acc3 100644 static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -- -2.29.2 +2.30.2 diff --git a/patches/mfplat-streaming-support/0028-winegstreamer-Insert-parser-into-pipeline-to-rectify.patch b/patches/mfplat-streaming-support/0028-winegstreamer-Insert-parser-into-pipeline-to-rectify.patch deleted file mode 100644 index 33b8eadd..00000000 --- a/patches/mfplat-streaming-support/0028-winegstreamer-Insert-parser-into-pipeline-to-rectify.patch +++ /dev/null @@ -1,141 +0,0 @@ -From 7bb33ab950fe2fdddcd5e7409827be982044f813 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 15 Sep 2020 14:25:26 -0500 -Subject: [PATCH] winegstreamer: Insert parser into pipeline to rectify type - differences. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/media_source.c | 95 ++++++++++++++++++++++++++++++- - 1 file changed, 92 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 1bbbb2ffd81..aecf4f27375 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -791,8 +791,17 @@ static const IMFMediaStreamVtbl media_stream_vtbl = - media_stream_RequestSample - }; - --/* Setup a chain of elements which should hopefully allow transformations to any IMFMediaType -- the user throws at us through gstreamer's caps negotiation. */ -+/* There are two paths this function can take. -+ 1) In the first path, we are acting as a real media source, purely demuxing the input data, -+ in whichever format it may be in, and passing it along. However, there can be different ways -+ to interpret the same streams. Subtypes in MF usually carry an implicit meaning, so we define -+ what caps an IMFMediaType corresponds to in mfplat.c, and insert a parser between decodebin -+ and the appsink, which usually can resolve these differences. As an example, MFVideoFormat_H264 -+ implies stream-format=byte-stream, and inserting h264parse can transform stream-format=avc -+ into stream-format=byte-stream. -+ 2) In the second path, we are dealing with x-raw output from decodebin. In this case, we just -+ have to setup a chain of elements which should hopefully allow transformations to any IMFMediaType -+ the user throws at us through gstreamer's caps negotiation.*/ - static HRESULT media_stream_connect_to_sink(struct media_stream *stream) - { - GstCaps *source_caps = gst_pad_query_caps(stream->their_src, NULL); -@@ -832,7 +841,68 @@ static HRESULT media_stream_connect_to_sink(struct media_stream *stream) - } - else - { -- stream->my_sink = gst_element_get_static_pad(stream->appsink, "sink"); -+ GstElement *parser = NULL; -+ GstCaps *target_caps; -+ -+ assert(gst_caps_is_fixed(source_caps)); -+ -+ if (!(target_caps = make_mf_compatible_caps(source_caps))) -+ { -+ gst_caps_unref(source_caps); -+ return E_FAIL; -+ } -+ -+ g_object_set(stream->appsink, "caps", target_caps, NULL); -+ -+ if (!(gst_caps_is_equal(source_caps, target_caps))) -+ { -+ GList *parser_list_one, *parser_list_two; -+ GstElementFactory *parser_factory; -+ -+ parser_list_one = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_PARSER, 1); -+ -+ parser_list_two = gst_element_factory_list_filter(parser_list_one, source_caps, GST_PAD_SINK, 0); -+ gst_plugin_feature_list_free(parser_list_one); -+ parser_list_one = parser_list_two; -+ -+ parser_list_two = gst_element_factory_list_filter(parser_list_one, target_caps, GST_PAD_SRC, 0); -+ gst_plugin_feature_list_free(parser_list_one); -+ parser_list_one = parser_list_two; -+ gst_caps_unref(target_caps); -+ -+ if (!(g_list_length(parser_list_one))) -+ { -+ gst_plugin_feature_list_free(parser_list_one); -+ ERR("Failed to find parser for stream\n"); -+ gst_caps_unref(source_caps); -+ return E_FAIL; -+ } -+ -+ parser_factory = g_list_first(parser_list_one)->data; -+ TRACE("Found parser %s.\n", GST_ELEMENT_NAME(parser_factory)); -+ -+ parser = gst_element_factory_create(parser_factory, NULL); -+ -+ gst_plugin_feature_list_free(parser_list_one); -+ -+ if (!parser) -+ { -+ gst_caps_unref(source_caps); -+ return E_FAIL; -+ } -+ -+ gst_bin_add(GST_BIN(stream->parent_source->container), parser); -+ -+ assert(gst_element_link(parser, stream->appsink)); -+ -+ gst_element_sync_state_with_parent(parser); -+ } -+ else -+ { -+ gst_caps_unref(target_caps); -+ } -+ -+ stream->my_sink = gst_element_get_static_pad(parser ? parser : stream->appsink, "sink"); - } - - if (gst_pad_link(stream->their_src, stream->my_sink) != GST_PAD_LINK_OK) -@@ -1326,6 +1396,23 @@ static const IMFSeekInfoVtbl IMFSeekInfo_vtbl = - source_seek_info_GetNearestKeyFrames, - }; - -+/* If this callback is extended to use any significant win32 APIs, a wrapper function -+ should be added */ -+gboolean stream_found(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer user) -+{ -+ GstCaps *target_caps; -+ -+ /* if the stream can be converted into an MF compatible type, we'll go that route -+ otherwise, we'll rely on decodebin for the whole process */ -+ -+ if ((target_caps = make_mf_compatible_caps(caps))) -+ { -+ gst_caps_unref(target_caps); -+ return FALSE; -+ } -+ return TRUE; -+} -+ - static void stream_added(GstElement *element, GstPad *pad, gpointer user) - { - struct media_source *source = user; -@@ -1445,6 +1532,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - - gst_bin_add(GST_BIN(object->container), object->decodebin); - -+ if(!GetEnvironmentVariableA("MF_DECODE_IN_SOURCE", NULL, 0)) -+ g_signal_connect(object->decodebin, "autoplug-continue", G_CALLBACK(stream_found), object); - g_signal_connect(object->decodebin, "pad-added", G_CALLBACK(mf_src_stream_added_wrapper), object); - g_signal_connect(object->decodebin, "pad-removed", G_CALLBACK(mf_src_stream_removed_wrapper), object); - g_signal_connect(object->decodebin, "no-more-pads", G_CALLBACK(mf_src_no_more_pads_wrapper), object); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch b/patches/mfplat-streaming-support/0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch new file mode 100644 index 00000000..6e3da01a --- /dev/null +++ b/patches/mfplat-streaming-support/0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch @@ -0,0 +1,95 @@ +From 5a5376981522aba2a5a6f7facb44373584488c7f Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 17 Mar 2021 17:01:11 -0400 +Subject: [PATCH 29/39] winegstreamer: Implement ::Get(Input/Output)StreamInfo + for color conversion transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/colorconvert.c | 64 +++++++++++++++++++++++++++++-- + 1 file changed, 60 insertions(+), 4 deletions(-) + +diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c +index 8d2f7a7d643..6f3723b2b1e 100644 +--- a/dlls/winegstreamer/colorconvert.c ++++ b/dlls/winegstreamer/colorconvert.c +@@ -141,16 +141,72 @@ static HRESULT WINAPI color_converter_GetStreamIDs(IMFTransform *iface, DWORD in + + static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) + { +- FIXME("%p %u %p.\n", iface, id, info); ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ UINT64 framesize; ++ GUID subtype; + +- return E_NOTIMPL; ++ TRACE("%p %u %p.\n", iface, id, info); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; ++ info->cbMaxLookahead = 0; ++ info->cbAlignment = 0; ++ info->hnsMaxLatency = 0; ++ info->cbSize = 0; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (converter->input_type) ++ { ++ if (SUCCEEDED(IMFMediaType_GetGUID(converter->input_type, &MF_MT_SUBTYPE, &subtype)) && ++ SUCCEEDED(IMFMediaType_GetUINT64(converter->input_type, &MF_MT_FRAME_SIZE, &framesize))) ++ { ++ MFCalculateImageSize(&subtype, framesize >> 32, (UINT32) framesize, &info->cbSize); ++ } ++ ++ if (!info->cbSize) ++ WARN("Failed to get desired input buffer size, the non-provided sample path will likely break\n"); ++ } ++ ++ LeaveCriticalSection(&converter->cs); ++ ++ return S_OK; + } + + static HRESULT WINAPI color_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) + { +- FIXME("%p %u %p.\n", iface, id, info); ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ UINT64 framesize; ++ GUID subtype; + +- return E_NOTIMPL; ++ TRACE("%p %u %p.\n", iface, id, info); ++ ++ if (id != 0) ++ return MF_E_INVALIDSTREAMNUMBER; ++ ++ info->dwFlags = MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES | MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER; ++ info->cbAlignment = 0; ++ info->cbSize = 0; ++ ++ EnterCriticalSection(&converter->cs); ++ ++ if (converter->output_type) ++ { ++ if (SUCCEEDED(IMFMediaType_GetGUID(converter->output_type, &MF_MT_SUBTYPE, &subtype)) && ++ SUCCEEDED(IMFMediaType_GetUINT64(converter->output_type, &MF_MT_FRAME_SIZE, &framesize))) ++ { ++ MFCalculateImageSize(&subtype, framesize >> 32, (UINT32) framesize, &info->cbSize); ++ } ++ ++ if (!info->cbSize) ++ WARN("Failed to get desired output buffer size, the non-provided sample path will likely break\n"); ++ } ++ ++ LeaveCriticalSection(&converter->cs); ++ ++ return S_OK; + } + + static HRESULT WINAPI color_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0029-winegstreamer-Translate-H.264-caps-to-attributes.patch b/patches/mfplat-streaming-support/0029-winegstreamer-Translate-H.264-caps-to-attributes.patch deleted file mode 100644 index 1841380b..00000000 --- a/patches/mfplat-streaming-support/0029-winegstreamer-Translate-H.264-caps-to-attributes.patch +++ /dev/null @@ -1,113 +0,0 @@ -From d95e8d8349b884800066c9af1ea9a7c7492ca02c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 24 Mar 2020 16:00:26 -0500 -Subject: [PATCH] winegstreamer: Translate H.264 caps to attributes. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 75 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 75 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index a2873907437..afce3d9831a 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -26,6 +26,7 @@ - #include "gst_private.h" - #include "mfapi.h" - #include "mfidl.h" -+#include "codecapi.h" - - #include "wine/debug.h" - #include "wine/heap.h" -@@ -629,6 +630,74 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - } - } - } -+ else if (!(strcmp(mime_type, "video/x-h264"))) -+ { -+ const char *profile, *level; -+ -+ /* validation */ -+ if (strcmp(gst_structure_get_string(info, "stream-format"), "byte-stream")) -+ return NULL; -+ if (strcmp(gst_structure_get_string(info, "alignment"), "au")) -+ return NULL; -+ if (gst_structure_get_value(info, "codec-data")) -+ return NULL; -+ -+ /* conversion */ -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_H264); -+ IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, TRUE); -+ -+ if ((profile = gst_structure_get_string(info, "profile"))) -+ { -+ if (!(strcmp(profile, "main"))) -+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_Main); -+ else if (!(strcmp(profile, "high"))) -+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_High); -+ else if (!(strcmp(profile, "high-4:4:4"))) -+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_444); -+ else -+ FIXME("Unrecognized profile %s\n", profile); -+ } -+ if ((level = gst_structure_get_string(info, "level"))) -+ { -+ unsigned int i; -+ -+ const static struct -+ { -+ const char *name; -+ enum eAVEncH264VLevel val; -+ } levels[] = -+ { -+ {"1", eAVEncH264VLevel1}, -+ {"1.1", eAVEncH264VLevel1_1}, -+ {"1.2", eAVEncH264VLevel1_2}, -+ {"1.3", eAVEncH264VLevel1_3}, -+ {"2", eAVEncH264VLevel2}, -+ {"2.1", eAVEncH264VLevel2_1}, -+ {"2.2", eAVEncH264VLevel2_2}, -+ {"3", eAVEncH264VLevel3}, -+ {"3.1", eAVEncH264VLevel3_1}, -+ {"3.2", eAVEncH264VLevel3_2}, -+ {"4", eAVEncH264VLevel4}, -+ {"4.1", eAVEncH264VLevel4_1}, -+ {"4.2", eAVEncH264VLevel4_2}, -+ {"5", eAVEncH264VLevel5}, -+ {"5.1", eAVEncH264VLevel5_1}, -+ {"5.2", eAVEncH264VLevel5_2}, -+ }; -+ for (i = 0 ; i < ARRAY_SIZE(levels); i++) -+ { -+ if (!(strcmp(level, levels[i].name))) -+ { -+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_LEVEL, levels[i].val); -+ break; -+ } -+ } -+ if (i == ARRAY_SIZE(levels)) -+ { -+ FIXME("Unrecognized level %s", level); -+ } -+ } -+ } - else - { - FIXME("Unrecognized video format %s\n", mime_type); -@@ -754,6 +823,12 @@ GstCaps *make_mf_compatible_caps(GstCaps *caps) - } - } - } -+ else if (!strcmp(mime_type, "video/x-h264")) -+ { -+ gst_caps_set_simple(ret, "stream-format", G_TYPE_STRING, "byte-stream", NULL); -+ gst_caps_set_simple(ret, "alignment", G_TYPE_STRING, "au", NULL); -+ gst_structure_remove_field(structure, "codec_data"); -+ } - - if ((media_type = mf_media_type_from_caps(ret))) - IMFMediaType_Release(media_type); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch b/patches/mfplat-streaming-support/0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch new file mode 100644 index 00000000..663363f0 --- /dev/null +++ b/patches/mfplat-streaming-support/0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch @@ -0,0 +1,28 @@ +From e602bc2817910624da0da383933889871e61c0f7 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 18 Mar 2021 13:53:42 -0400 +Subject: [PATCH 30/39] mf/topology: Forward failure from ::SetOutputType when + resolving topology. + +Signed-off-by: Derek Lesho +--- + dlls/mf/topology.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c +index f97c0cc75d3..34459912fb0 100644 +--- a/dlls/mf/topology.c ++++ b/dlls/mf/topology.c +@@ -2122,8 +2122,7 @@ static HRESULT connect_to_sink(struct transform_output_type *output_type, struct + hr = IMFMediaTypeHandler_SetCurrentMediaType(context->sink_handler, output_type->type); + if (SUCCEEDED(hr)) + hr = IMFTransform_SetOutputType(output_type->transform, 0, output_type->type, 0); +- +- return S_OK; ++ return hr; + } + + static HRESULT connect_to_converter(struct transform_output_type *output_type, struct connect_context *context) +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0030-winegstreamer-Translate-WMV-caps-to-attributes.patch b/patches/mfplat-streaming-support/0030-winegstreamer-Translate-WMV-caps-to-attributes.patch deleted file mode 100644 index 83cecf5e..00000000 --- a/patches/mfplat-streaming-support/0030-winegstreamer-Translate-WMV-caps-to-attributes.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 10dcfecc84651a4c2a270960c585c735ff09ec1c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 24 Mar 2020 16:01:20 -0500 -Subject: [PATCH] winegstreamer: Translate WMV caps to attributes. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 51 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 51 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index afce3d9831a..6906fd3faeb 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -564,6 +564,24 @@ uncompressed_video_formats[] = - {&MFVideoFormat_RGB555, GST_VIDEO_FORMAT_BGR15}, - }; - -+static void codec_data_to_user_data(GstStructure *structure, IMFMediaType *type) -+{ -+ const GValue *codec_data; -+ -+ if ((codec_data = gst_structure_get_value(structure, "codec_data"))) -+ { -+ GstBuffer *codec_data_buffer = gst_value_get_buffer(codec_data); -+ if (codec_data_buffer) -+ { -+ gsize codec_data_size = gst_buffer_get_size(codec_data_buffer); -+ gpointer codec_data_raw = heap_alloc(codec_data_size); -+ gst_buffer_extract(codec_data_buffer, 0, codec_data_raw, codec_data_size); -+ IMFMediaType_SetBlob(type, &MF_MT_USER_DATA, codec_data_raw, codec_data_size); -+ heap_free(codec_data_raw); -+ } -+ } -+} -+ - /* returns NULL if doesn't match exactly */ - IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - { -@@ -698,6 +716,39 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - } - } - } -+ else if (!(strcmp(mime_type, "video/x-wmv"))) -+ { -+ gint wmv_version; -+ const char *format; -+ -+ if (gst_structure_get_int(info, "wmvversion", &wmv_version)) -+ { -+ switch (wmv_version) -+ { -+ case 1: -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WMV1); -+ break; -+ case 2: -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WMV2); -+ break; -+ case 3: -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WMV3); -+ break; -+ default: -+ FIXME("Unrecognized wmvversion %d\n", wmv_version); -+ } -+ } -+ -+ if ((format = gst_structure_get_string(info, "format"))) -+ { -+ if (!(strcmp(format, "WVC1"))) -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WVC1); -+ else -+ FIXME("Unrecognized format %s\n", format); -+ } -+ -+ codec_data_to_user_data(info, media_type); -+ } - else - { - FIXME("Unrecognized video format %s\n", mime_type); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0031-winegstreamer-Handle-flush-command-in-audio-converst.patch b/patches/mfplat-streaming-support/0031-winegstreamer-Handle-flush-command-in-audio-converst.patch new file mode 100644 index 00000000..57a521b0 --- /dev/null +++ b/patches/mfplat-streaming-support/0031-winegstreamer-Handle-flush-command-in-audio-converst.patch @@ -0,0 +1,26 @@ +From 2268b0ad8fbe8473f936b0fa0e09d9e072443853 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 18 Mar 2021 14:53:49 -0400 +Subject: [PATCH 31/39] winegstreamer: Handle flush command in audio + converstion transform. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/audioconvert.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c +index 43fe8b04e64..1584fefe577 100644 +--- a/dlls/winegstreamer/audioconvert.c ++++ b/dlls/winegstreamer/audioconvert.c +@@ -618,6 +618,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME + + switch(message) + { ++ case MFT_MESSAGE_COMMAND_FLUSH: + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + return S_OK; + default: +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0031-winegstreamer-Translate-AAC-caps-to-attributes.patch b/patches/mfplat-streaming-support/0031-winegstreamer-Translate-AAC-caps-to-attributes.patch deleted file mode 100644 index 9074f05a..00000000 --- a/patches/mfplat-streaming-support/0031-winegstreamer-Translate-AAC-caps-to-attributes.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 90d881fc889fdaedc7e44c0bee5e54634c0d065c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 24 Mar 2020 16:02:27 -0500 -Subject: [PATCH] winegstreamer: Translate AAC caps to attributes. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 108 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 108 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 6906fd3faeb..66048f359e5 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -564,6 +564,15 @@ uncompressed_video_formats[] = - {&MFVideoFormat_RGB555, GST_VIDEO_FORMAT_BGR15}, - }; - -+struct aac_user_data -+{ -+ WORD payload_type; -+ WORD profile_level_indication; -+ WORD struct_type; -+ WORD reserved; -+ /* audio-specific-config is stored here */ -+}; -+ - static void codec_data_to_user_data(GstStructure *structure, IMFMediaType *type) - { - const GValue *codec_data; -@@ -814,6 +823,105 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - - IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, depth); - } -+ else if (!(strcmp(mime_type, "audio/mpeg"))) -+ { -+ int mpeg_version = -1; -+ -+ IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, TRUE); -+ -+ if (!(gst_structure_get_int(info, "mpegversion", &mpeg_version))) -+ ERR("Failed to get mpegversion\n"); -+ switch (mpeg_version) -+ { -+ case 2: -+ case 4: -+ { -+ const char *format, *profile, *level; -+ DWORD profile_level_indication = 0; -+ const GValue *codec_data; -+ DWORD asc_size = 0; -+ struct aac_user_data *user_data = NULL; -+ -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_AAC); -+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 16); -+ -+ codec_data = gst_structure_get_value(info, "codec_data"); -+ if (codec_data) -+ { -+ GstBuffer *codec_data_buffer = gst_value_get_buffer(codec_data); -+ if (codec_data_buffer) -+ { -+ if ((asc_size = gst_buffer_get_size(codec_data_buffer)) >= 2) -+ { -+ user_data = heap_alloc_zero(sizeof(*user_data)+asc_size); -+ gst_buffer_extract(codec_data_buffer, 0, (gpointer)(user_data + 1), asc_size); -+ } -+ else -+ ERR("Unexpected buffer size\n"); -+ } -+ else -+ ERR("codec_data not a buffer\n"); -+ } -+ else -+ ERR("codec_data not found\n"); -+ if (!user_data) -+ user_data = heap_alloc_zero(sizeof(*user_data)); -+ -+ if ((format = gst_structure_get_string(info, "stream-format"))) -+ { -+ DWORD payload_type = -1; -+ if (!(strcmp(format, "raw"))) -+ payload_type = 0; -+ else if (!(strcmp(format, "adts"))) -+ payload_type = 1; -+ else if (!(strcmp(format, "adif"))) -+ payload_type = 2; -+ else if (!(strcmp(format, "loas"))) -+ payload_type = 3; -+ else -+ FIXME("Unrecognized stream-format\n"); -+ if (payload_type != -1) -+ { -+ IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_PAYLOAD_TYPE, payload_type); -+ user_data->payload_type = payload_type; -+ } -+ } -+ else -+ { -+ ERR("Stream format not present\n"); -+ } -+ -+ profile = gst_structure_get_string(info, "profile"); -+ level = gst_structure_get_string(info, "level"); -+ /* Data from http://archive.is/whp6P#45% */ -+ if (profile && level) -+ { -+ if (!(strcmp(profile, "lc")) && !(strcmp(level, "2"))) -+ profile_level_indication = 0x29; -+ else if (!(strcmp(profile, "lc")) && !(strcmp(level, "4"))) -+ profile_level_indication = 0x2A; -+ else if (!(strcmp(profile, "lc")) && !(strcmp(level, "5"))) -+ profile_level_indication = 0x2B; -+ else -+ FIXME("Unhandled profile/level combo\n"); -+ } -+ else -+ ERR("Profile or level not present\n"); -+ -+ if (profile_level_indication) -+ { -+ IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, profile_level_indication); -+ user_data->profile_level_indication = profile_level_indication; -+ } -+ -+ IMFMediaType_SetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)user_data, sizeof(*user_data) + asc_size); -+ heap_free(user_data); -+ break; -+ } -+ default: -+ FIXME("Unhandled mpegversion %d\n", mpeg_version); -+ } -+ } - else - { - FIXME("Unrecognized audio format %s\n", mime_type); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0048-Report-streams-backwards-and-only-select-one-of-each.patch b/patches/mfplat-streaming-support/0032-winegstreamer-In-the-default-configuration-select-on.patch similarity index 56% rename from patches/mfplat-streaming-support/0048-Report-streams-backwards-and-only-select-one-of-each.patch rename to patches/mfplat-streaming-support/0032-winegstreamer-In-the-default-configuration-select-on.patch index 7c20f408..4801827c 100644 --- a/patches/mfplat-streaming-support/0048-Report-streams-backwards-and-only-select-one-of-each.patch +++ b/patches/mfplat-streaming-support/0032-winegstreamer-In-the-default-configuration-select-on.patch @@ -1,33 +1,26 @@ -From cda7c0339af6bf5c4d903ef844844ca0d4332d73 Mon Sep 17 00:00:00 2001 +From baebd866b835a054f00121d577e45c08edcde25c Mon Sep 17 00:00:00 2001 From: Derek Lesho -Date: Tue, 5 May 2020 15:35:16 -0500 -Subject: [PATCH] Report streams backwards and only select one of each stream - type. +Date: Fri, 4 Dec 2020 16:17:11 -0500 +Subject: [PATCH 32/39] winegstreamer: In the default configuration, select one + stream of each major type. --- - dlls/winegstreamer/media_source.c | 24 ++++++++++++++++++++++-- - 1 file changed, 22 insertions(+), 2 deletions(-) + dlls/winegstreamer/media_source.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 2156e07a13c..fd7f1a7f55e 100644 +index b0c4220cc00..2d1a628cba0 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c -@@ -1486,6 +1486,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - GstStaticPadTemplate src_template = - GST_STATIC_PAD_TEMPLATE("mf_src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); +@@ -1273,6 +1273,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = + static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) + { + BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; - IMFAttributes *byte_stream_attributes; struct media_source *object; -@@ -1600,15 +1601,34 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - descriptors = heap_alloc(object->stream_count * sizeof(IMFStreamDescriptor*)); - for (i = 0; i < object->stream_count; i++) - { -- IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]); -+ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[object->stream_count - 1 - i]); - } - + UINT64 total_pres_time = 0; +@@ -1369,9 +1370,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) goto fail; @@ -56,7 +49,7 @@ index 2156e07a13c..fd7f1a7f55e 100644 + IMFMediaTypeHandler_Release(handler); IMFStreamDescriptor_Release(descriptors[i]); } - heap_free(descriptors); + free(descriptors); -- -2.29.2 +2.30.2 diff --git a/patches/mfplat-streaming-support/0032-winegstreamer-Translate-MPEG-4-Section-2-caps-to-att.patch b/patches/mfplat-streaming-support/0032-winegstreamer-Translate-MPEG-4-Section-2-caps-to-att.patch deleted file mode 100644 index c66c1a4a..00000000 --- a/patches/mfplat-streaming-support/0032-winegstreamer-Translate-MPEG-4-Section-2-caps-to-att.patch +++ /dev/null @@ -1,40 +0,0 @@ -From c4955ec1798428fe9941cdbb9fed146f3d29dbe2 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 25 Mar 2020 13:36:19 -0500 -Subject: [PATCH] winegstreamer: Translate MPEG-4 Section-2 caps to attributes. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 66048f359e5..090952e7d2b 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -758,6 +758,22 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - - codec_data_to_user_data(info, media_type); - } -+ else if (!(strcmp(mime_type, "video/mpeg"))) -+ { -+ gint mpegversion; -+ if (gst_structure_get_int(info, "mpegversion", &mpegversion)) -+ { -+ if (mpegversion == 4) -+ { -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_M4S2); -+ IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, TRUE); -+ -+ codec_data_to_user_data(info, media_type); -+ } -+ else -+ FIXME("Unrecognized mpeg version %d\n", mpegversion); -+ } -+ } - else - { - FIXME("Unrecognized video format %s\n", mime_type); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch b/patches/mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch new file mode 100644 index 00000000..62394e6f --- /dev/null +++ b/patches/mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch @@ -0,0 +1,131 @@ +From 2ba70d161799850a073a43c658707fb1682a042f Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 18 Mar 2021 15:25:17 -0400 +Subject: [PATCH 33/39] winegstreamer: Implement MF_SD_LANGUAGE. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/gst_private.h | 1 + + dlls/winegstreamer/media_source.c | 20 +++++++++++++++++++- + dlls/winegstreamer/wg_parser.c | 27 +++++++++++++++++++++++++++ + 3 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 0827f70112f..f616b8a5d9d 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -240,6 +240,7 @@ struct unix_funcs + + /* Returns the duration in 100-nanosecond units. */ + uint64_t (CDECL *wg_parser_stream_get_duration)(struct wg_parser_stream *stream); ++ char * (CDECL *wg_parser_stream_get_language)(struct wg_parser_stream *stream); + /* start_pos and stop_pos are in 100-nanosecond units. */ + bool (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index 2d1a628cba0..eaf4b9b6815 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -1364,7 +1364,25 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ + descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); + for (i = 0; i < object->stream_count; i++) + { +- IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[object->stream_count - 1 - i]); ++ IMFStreamDescriptor **descriptor = &descriptors[object->stream_count - 1 - i]; ++ DWORD language_len; ++ WCHAR *languageW; ++ char *language; ++ ++ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, descriptor); ++ ++ if ((language = unix_funcs->wg_parser_stream_get_language(object->streams[i]->wg_stream))) ++ { ++ if ((language_len = MultiByteToWideChar(CP_UTF8, 0, language, -1, NULL, 0))) ++ { ++ languageW = malloc(language_len * sizeof(WCHAR)); ++ if (MultiByteToWideChar(CP_UTF8, 0, language, -1, languageW, language_len)) ++ { ++ IMFStreamDescriptor_SetString(*descriptor, &MF_SD_LANGUAGE, languageW); ++ } ++ free(languageW); ++ } ++ } + } + + if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 6f4dd28082b..534db931d8b 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -93,6 +93,7 @@ struct wg_parser_stream + bool flushing, eos, enabled, has_caps; + + uint64_t duration; ++ gchar *language_code; + }; + + static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) +@@ -848,6 +849,11 @@ static uint64_t CDECL wg_parser_stream_get_duration(struct wg_parser_stream *str + return stream->duration; + } + ++static char * CDECL wg_parser_stream_get_language(struct wg_parser_stream *stream) ++{ ++ return stream->language_code; ++} ++ + static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) + { +@@ -1946,6 +1952,22 @@ static LONGLONG query_duration(GstPad *pad) + return 0; + } + ++static gchar *query_language(GstPad *pad) ++{ ++ GstTagList *tag_list; ++ GstEvent *tag_event; ++ gchar *ret = NULL; ++ ++ if ((tag_event = gst_pad_get_sticky_event(pad, GST_EVENT_TAG, 0))) ++ { ++ gst_event_parse_tag(tag_event, &tag_list); ++ gst_tag_list_get_string(tag_list, "language-code", &ret); ++ gst_event_unref(tag_event); ++ } ++ ++ return ret; ++} ++ + static HRESULT wg_parser_connect_inner(struct wg_parser *parser) + { + GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", +@@ -1995,6 +2017,7 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + { + struct wg_parser_stream *stream = parser->streams[i]; + ++ stream->language_code = query_language(stream->their_src); + while (!stream->has_caps && !parser->error) + pthread_cond_wait(&parser->init_cond, &parser->mutex); + if (parser->error) +@@ -2074,6 +2097,9 @@ static void free_stream(struct wg_parser_stream *stream) + pthread_cond_destroy(&stream->event_cond); + pthread_cond_destroy(&stream->event_empty_cond); + ++ if (stream->language_code) ++ g_free(stream->language_code); ++ + free(stream); + } + +@@ -2523,6 +2549,7 @@ static const struct unix_funcs funcs = + wg_parser_stream_notify_qos, + + wg_parser_stream_get_duration, ++ wg_parser_stream_get_language, + wg_parser_stream_seek, + wg_parser_stream_drain, + }; +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0033-winegstreamer-Translate-WMA-caps-to-attributes.patch b/patches/mfplat-streaming-support/0033-winegstreamer-Translate-WMA-caps-to-attributes.patch deleted file mode 100644 index 21b6a354..00000000 --- a/patches/mfplat-streaming-support/0033-winegstreamer-Translate-WMA-caps-to-attributes.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 56ac324cb533bde61e25bc86a29440aec7111764 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 12 May 2020 17:05:41 -0500 -Subject: [PATCH] winegstreamer: Translate WMA caps to attributes. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 090952e7d2b..b2f8f0b83c1 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -938,6 +938,30 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - FIXME("Unhandled mpegversion %d\n", mpeg_version); - } - } -+ else if (!(strcmp(mime_type, "audio/x-wma"))) -+ { -+ gint wma_version, block_align; -+ -+ if (gst_structure_get_int(info, "wmaversion", &wma_version)) -+ { -+ switch (wma_version) -+ { -+ case 2: -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_WMAudioV8); -+ break; -+ case 3: -+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_WMAudioV9); -+ break; -+ default: -+ FIXME("Unrecognized wmaversion %d\n", wma_version); -+ } -+ } -+ -+ if (gst_structure_get_int(info, "block_align", &block_align)) -+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_align); -+ -+ codec_data_to_user_data(info, media_type); -+ } - else - { - FIXME("Unrecognized audio format %s\n", mime_type); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0034-winegstreamer-Only-require-videobox-element-for-pars.patch b/patches/mfplat-streaming-support/0034-winegstreamer-Only-require-videobox-element-for-pars.patch new file mode 100644 index 00000000..3466ef72 --- /dev/null +++ b/patches/mfplat-streaming-support/0034-winegstreamer-Only-require-videobox-element-for-pars.patch @@ -0,0 +1,93 @@ +From 97f4a9b38ee49706edb3c52b93dd86509665361c Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 18 Mar 2021 16:20:50 -0400 +Subject: [PATCH 34/39] winegstreamer: Only require videobox element for parser + when needed. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/wg_parser.c | 42 ++++++++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 10 deletions(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 534db931d8b..afd69ea6891 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -753,6 +753,15 @@ static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const + + if (aperture) + { ++ if (!stream->box && (stream->aperture.left || stream->aperture.top || ++ (stream->aperture.right && stream->aperture.right != stream->current_format.u.video.width) || ++ (stream->aperture.bottom && stream->aperture.bottom != stream->current_format.u.video.height))) ++ { ++ fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"good\" plugins installed?\n", ++ 8 * (int)sizeof(void *)); ++ return; ++ } ++ + if (aperture->left) + g_object_set(G_OBJECT(stream->box), "left", -aperture->left, NULL); + if (aperture->top) +@@ -1309,12 +1318,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + goto out; + } + +- if (!(videobox = gst_element_factory_make("videobox", NULL))) +- { +- fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"base\" plugins installed?\n", +- 8 * (int)sizeof(void *)); +- goto out; +- } ++ videobox = gst_element_factory_make("videobox", NULL); + + /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert + * to do the final conversion. */ +@@ -1327,6 +1331,14 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + + if (!parser->seekable) + { ++ if (!videobox && (stream->aperture.left || stream->aperture.top || ++ (stream->aperture.right && stream->aperture.right != stream->current_format.u.video.width) || ++ (stream->aperture.bottom && stream->aperture.bottom != stream->current_format.u.video.height))) ++ { ++ fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"good\" plugins installed?\n", ++ 8 * (int)sizeof(void *)); ++ goto out; ++ } + if (stream->aperture.left) + g_object_set(G_OBJECT(videobox), "left", -stream->aperture.left, NULL); + if (stream->aperture.bottom) +@@ -1344,15 +1356,25 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + gst_element_sync_state_with_parent(vconv); + gst_bin_add(GST_BIN(parser->container), flip); + gst_element_sync_state_with_parent(flip); +- gst_bin_add(GST_BIN(parser->container), videobox); +- gst_element_sync_state_with_parent(videobox); ++ if (videobox) ++ { ++ gst_bin_add(GST_BIN(parser->container), videobox); ++ gst_element_sync_state_with_parent(videobox); ++ } + gst_bin_add(GST_BIN(parser->container), vconv2); + gst_element_sync_state_with_parent(vconv2); + + gst_element_link(deinterlace, vconv); + gst_element_link(vconv, flip); +- gst_element_link(flip, videobox); +- gst_element_link(videobox, vconv2); ++ if (videobox) ++ { ++ gst_element_link(flip, videobox); ++ gst_element_link(videobox, vconv2); ++ } ++ else ++ { ++ gst_element_link(flip, vconv2); ++ } + + stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); + stream->post_src = gst_element_get_static_pad(vconv2, "src"); +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0034-winegstreamer-Translate-H.264-attributes-to-caps.patch b/patches/mfplat-streaming-support/0034-winegstreamer-Translate-H.264-attributes-to-caps.patch deleted file mode 100644 index 3973bae1..00000000 --- a/patches/mfplat-streaming-support/0034-winegstreamer-Translate-H.264-attributes-to-caps.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 6ace23bd172cb48c7e326fd3013624a73cdf8c10 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 24 Mar 2020 16:18:40 -0500 -Subject: [PATCH] winegstreamer: Translate H.264 attributes to caps. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 90 +++++++++++++++++++++++++++++-------- - 1 file changed, 71 insertions(+), 19 deletions(-) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index b2f8f0b83c1..e02f0dfbc5c 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -1056,10 +1056,6 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - { - UINT64 frame_rate = 0, frame_size = 0; - DWORD width, height; -- GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; -- GUID subtype_base; -- GstVideoInfo info; -- unsigned int i; - - if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) - return NULL; -@@ -1068,28 +1064,84 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - - output = gst_caps_new_empty_simple("video/x-raw"); - -- for (i = 0; i < ARRAY_SIZE(uncompressed_video_formats); i++) -+ if (IsEqualGUID(&subtype, &MFVideoFormat_H264)) - { -- if (IsEqualGUID(uncompressed_video_formats[i].subtype, &subtype)) -+ enum eAVEncH264VProfile h264_profile; -+ enum eAVEncH264VLevel h264_level; -+ output = gst_caps_new_empty_simple("video/x-h264"); -+ gst_caps_set_simple(output, "stream-format", G_TYPE_STRING, "byte-stream", NULL); -+ gst_caps_set_simple(output, "alignment", G_TYPE_STRING, "au", NULL); -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &h264_profile))) -+ { -+ const char *profile = NULL; -+ switch (h264_profile) -+ { -+ case eAVEncH264VProfile_Main: profile = "main"; break; -+ case eAVEncH264VProfile_High: profile = "high"; break; -+ case eAVEncH264VProfile_444: profile = "high-4:4:4"; break; -+ default: FIXME("Unknown profile %u\n", h264_profile); -+ } -+ if (profile) -+ gst_caps_set_simple(output, "profile", G_TYPE_STRING, profile, NULL); -+ } -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &h264_level))) - { -- format = uncompressed_video_formats[i].format; -- break; -+ const char *level = NULL; -+ switch (h264_level) -+ { -+ case eAVEncH264VLevel1: level = "1"; break; -+ case eAVEncH264VLevel1_1: level = "1.1"; break; -+ case eAVEncH264VLevel1_2: level = "1.2"; break; -+ case eAVEncH264VLevel1_3: level = "1.3"; break; -+ case eAVEncH264VLevel2: level = "2"; break; -+ case eAVEncH264VLevel2_1: level = "2.1"; break; -+ case eAVEncH264VLevel2_2: level = "2.2"; break; -+ case eAVEncH264VLevel3: level = "3"; break; -+ case eAVEncH264VLevel3_1: level = "3.1"; break; -+ case eAVEncH264VLevel3_2: level = "3.2"; break; -+ case eAVEncH264VLevel4: level = "4"; break; -+ case eAVEncH264VLevel4_1: level = "4.1"; break; -+ case eAVEncH264VLevel4_2: level = "4.2"; break; -+ case eAVEncH264VLevel5: level = "5"; break; -+ case eAVEncH264VLevel5_1: level = "5.1"; break; -+ case eAVEncH264VLevel5_2: level = "5.2"; break; -+ default: FIXME("Unknown level %u\n", h264_level); -+ } -+ if (level) -+ gst_caps_set_simple(output, "level", G_TYPE_STRING, level, NULL); - } - } -+ else -+ { -+ GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; -+ GUID subtype_base; -+ GstVideoInfo info; -+ unsigned int i; - -- subtype_base = subtype; -- subtype_base.Data1 = 0; -- if (format == GST_VIDEO_FORMAT_UNKNOWN && IsEqualGUID(&MFVideoFormat_Base, &subtype_base)) -- format = gst_video_format_from_fourcc(subtype.Data1); -+ for (i = 0; i < ARRAY_SIZE(uncompressed_video_formats); i++) -+ { -+ if (IsEqualGUID(uncompressed_video_formats[i].subtype, &subtype)) -+ { -+ format = uncompressed_video_formats[i].format; -+ break; -+ } -+ } - -- if (format == GST_VIDEO_FORMAT_UNKNOWN) -- { -- FIXME("Unrecognized format %s\n", debugstr_guid(&subtype)); -- return NULL; -- } -+ subtype_base = subtype; -+ subtype_base.Data1 = 0; -+ if (format == GST_VIDEO_FORMAT_UNKNOWN && IsEqualGUID(&MFVideoFormat_Base, &subtype_base)) -+ format = gst_video_format_from_fourcc(subtype.Data1); - -- gst_video_info_set_format(&info, format, width, height); -- output = gst_video_info_to_caps(&info); -+ if (format == GST_VIDEO_FORMAT_UNKNOWN) -+ { -+ FIXME("Unrecognized format %s\n", debugstr_guid(&subtype)); -+ return NULL; -+ } -+ -+ gst_video_info_set_format(&info, format, width, height); -+ output = gst_video_info_to_caps(&info); -+ } - - if (frame_size) - { --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0035-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch b/patches/mfplat-streaming-support/0035-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch new file mode 100644 index 00000000..ec768624 --- /dev/null +++ b/patches/mfplat-streaming-support/0035-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch @@ -0,0 +1,64 @@ +From 1301b70733c9d5256b5f8352e9bbd6a3578ba590 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Thu, 18 Mar 2021 16:54:44 -0400 +Subject: [PATCH 35/39] mfplat: Stub out MFCreateDXGIDeviceManager, to avoid + the d3d path. + +--- + dlls/mfplat/main.c | 32 +++++++++++++++++++------------- + 1 file changed, 19 insertions(+), 13 deletions(-) + +diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c +index 5406ceb5063..764d825a102 100644 +--- a/dlls/mfplat/main.c ++++ b/dlls/mfplat/main.c +@@ -8881,27 +8881,33 @@ static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl = + HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager) + { + struct dxgi_device_manager *object; ++ const char *sgi = getenv("SteamGameId"); + + TRACE("%p, %p.\n", token, manager); + +- if (!token || !manager) +- return E_POINTER; ++ if (sgi && (!strcmp(sgi,"1113560"))) ++ { ++ if (!token || !manager) ++ return E_POINTER; + +- if (!(object = calloc(1, sizeof(*object)))) +- return E_OUTOFMEMORY; ++ if (!(object = calloc(1, sizeof(*object)))) ++ return E_OUTOFMEMORY; + +- object->IMFDXGIDeviceManager_iface.lpVtbl = &dxgi_device_manager_vtbl; +- object->refcount = 1; +- object->token = GetTickCount(); +- InitializeCriticalSection(&object->cs); +- InitializeConditionVariable(&object->lock); ++ object->IMFDXGIDeviceManager_iface.lpVtbl = &dxgi_device_manager_vtbl; ++ object->refcount = 1; ++ object->token = GetTickCount(); ++ InitializeCriticalSection(&object->cs); ++ InitializeConditionVariable(&object->lock); + +- TRACE("Created device manager: %p, token: %u.\n", object, object->token); ++ TRACE("Created device manager: %p, token: %u.\n", object, object->token); + +- *token = object->token; +- *manager = &object->IMFDXGIDeviceManager_iface; ++ *token = object->token; ++ *manager = &object->IMFDXGIDeviceManager_iface; + +- return S_OK; ++ return S_OK; ++ } else { ++ return E_NOTIMPL; ++ } + } + + /*********************************************************************** +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0035-winegstreamer-Translate-WMV-attributes-to-caps.patch b/patches/mfplat-streaming-support/0035-winegstreamer-Translate-WMV-attributes-to-caps.patch deleted file mode 100644 index 8c2975b6..00000000 --- a/patches/mfplat-streaming-support/0035-winegstreamer-Translate-WMV-attributes-to-caps.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 5f71506e9482e475bb636a4d3738734afe004443 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 24 Mar 2020 16:20:17 -0500 -Subject: [PATCH] winegstreamer: Translate WMV attributes to caps. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 51 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 51 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index e02f0dfbc5c..2456d633c6c 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -1041,6 +1041,21 @@ GstCaps *make_mf_compatible_caps(GstCaps *caps) - return ret; - } - -+static void user_data_to_codec_data(IMFMediaType *type, GstCaps *caps) -+{ -+ BYTE *user_data; -+ DWORD user_data_size; -+ -+ if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, &user_data, &user_data_size))) -+ { -+ GstBuffer *codec_data_buffer = gst_buffer_new_allocate(NULL, user_data_size, NULL); -+ gst_buffer_fill(codec_data_buffer, 0, user_data, user_data_size); -+ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, codec_data_buffer, NULL); -+ gst_buffer_unref(codec_data_buffer); -+ CoTaskMemFree(user_data); -+ } -+} -+ - GstCaps *caps_from_mf_media_type(IMFMediaType *type) - { - GUID major_type; -@@ -1112,6 +1127,42 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - gst_caps_set_simple(output, "level", G_TYPE_STRING, level, NULL); - } - } -+ else if (IsEqualGUID(&subtype, &MFVideoFormat_WMV1)) -+ { -+ output = gst_caps_new_empty_simple("video/x-wmv"); -+ gst_caps_set_simple(output, "format", G_TYPE_STRING, "WMV1", NULL); -+ -+ gst_caps_set_simple(output, "wmvversion", G_TYPE_INT, 1, NULL); -+ -+ user_data_to_codec_data(type, output); -+ } -+ else if (IsEqualGUID(&subtype, &MFVideoFormat_WMV2)) -+ { -+ output = gst_caps_new_empty_simple("video/x-wmv"); -+ gst_caps_set_simple(output, "format", G_TYPE_STRING, "WMV2", NULL); -+ -+ gst_caps_set_simple(output, "wmvversion", G_TYPE_INT, 2, NULL); -+ -+ user_data_to_codec_data(type, output); -+ } -+ else if (IsEqualGUID(&subtype, &MFVideoFormat_WMV3)) -+ { -+ output = gst_caps_new_empty_simple("video/x-wmv"); -+ gst_caps_set_simple(output, "format", G_TYPE_STRING, "WMV3", NULL); -+ -+ gst_caps_set_simple(output, "wmvversion", G_TYPE_INT, 3, NULL); -+ -+ user_data_to_codec_data(type, output); -+ } -+ else if (IsEqualGUID(&subtype, &MFVideoFormat_WVC1)) -+ { -+ output = gst_caps_new_empty_simple("video/x-wmv"); -+ gst_caps_set_simple(output, "format", G_TYPE_STRING, "WVC1", NULL); -+ -+ gst_caps_set_simple(output, "wmvversion", G_TYPE_INT, 3, NULL); -+ -+ user_data_to_codec_data(type, output); -+ } - else - { - GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0036-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch b/patches/mfplat-streaming-support/0036-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch new file mode 100644 index 00000000..df5a31ee --- /dev/null +++ b/patches/mfplat-streaming-support/0036-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch @@ -0,0 +1,30 @@ +From ac8e72e266b60cf5dcef5ecf256ee3c99d6c9f53 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Mon, 22 Mar 2021 15:50:29 -0400 +Subject: [PATCH 36/39] winegstreamer: Don't rely on max_size in unseekable + parser. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/wg_parser.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index afd69ea6891..8e98ea08611 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1677,9 +1677,9 @@ static void *push_data(void *arg) + ULONG size; + int ret; + +- if (parser->next_offset >= max_size) ++ if (parser->seekable && parser->next_offset >= max_size) + break; +- size = min(alloc_size, max_size - parser->next_offset); ++ size = parser->seekable ? min(alloc_size, max_size - parser->next_offset) : alloc_size; + + ret = pull_data(parser, parser->next_offset, size, &size, &buffer); + +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0036-winegstreamer-Translate-AAC-attributes-to-caps.patch b/patches/mfplat-streaming-support/0036-winegstreamer-Translate-AAC-attributes-to-caps.patch deleted file mode 100644 index 1cba7371..00000000 --- a/patches/mfplat-streaming-support/0036-winegstreamer-Translate-AAC-attributes-to-caps.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 09b135accfd48e079d6a2a3862e647b66b872b15 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 21 Apr 2020 10:31:02 -0500 -Subject: [PATCH] winegstreamer: Translate AAC attributes to caps. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 66 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 66 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 2456d633c6c..b1f83f4fa6c 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -1255,6 +1255,72 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - return NULL; - } - } -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) -+ { -+ DWORD payload_type, indication; -+ struct aac_user_data *user_data; -+ UINT32 user_data_size; -+ output = gst_caps_new_empty_simple("audio/mpeg"); -+ -+ /* Unsure of how to differentiate between mpegversion 2 and 4 */ -+ gst_caps_set_simple(output, "mpegversion", G_TYPE_INT, 4, NULL); -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &payload_type))) -+ { -+ switch (payload_type) -+ { -+ case 0: -+ gst_caps_set_simple(output, "stream-format", G_TYPE_STRING, "raw", NULL); -+ break; -+ case 1: -+ gst_caps_set_simple(output, "stream-format", G_TYPE_STRING, "adts", NULL); -+ break; -+ case 2: -+ gst_caps_set_simple(output, "stream-format", G_TYPE_STRING, "adif", NULL); -+ break; -+ case 3: -+ gst_caps_set_simple(output, "stream-format", G_TYPE_STRING, "loas", NULL); -+ break; -+ default: -+ gst_caps_set_simple(output, "stream-format", G_TYPE_STRING, "raw", NULL); -+ } -+ } -+ else -+ gst_caps_set_simple(output, "stream-format", G_TYPE_STRING, "raw", NULL); -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &indication))) -+ { -+ const char *profile, *level; -+ switch (indication) -+ { -+ case 0x29: profile = "lc"; level = "2"; break; -+ case 0x2A: profile = "lc"; level = "4"; break; -+ case 0x2B: profile = "lc"; level = "5"; break; -+ default: -+ { -+ profile = level = NULL; -+ FIXME("Unrecognized profile-level-indication %u\n", indication); -+ } -+ } -+ if (profile) -+ gst_caps_set_simple(output, "profile", G_TYPE_STRING, profile, NULL); -+ if (level) -+ gst_caps_set_simple(output, "level", G_TYPE_STRING, level, NULL); -+ } -+ -+ if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, (BYTE **) &user_data, &user_data_size))) -+ { -+ if (user_data_size > sizeof(*user_data)) -+ { -+ GstBuffer *audio_specific_config = gst_buffer_new_allocate(NULL, user_data_size - sizeof(*user_data), NULL); -+ gst_buffer_fill(audio_specific_config, 0, user_data + 1, user_data_size - sizeof(*user_data)); -+ -+ gst_caps_set_simple(output, "codec_data", GST_TYPE_BUFFER, audio_specific_config, NULL); -+ gst_buffer_unref(audio_specific_config); -+ } -+ CoTaskMemFree(user_data); -+ } -+ } - else - { - FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype)); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0037-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch b/patches/mfplat-streaming-support/0037-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch new file mode 100644 index 00000000..c34b72e1 --- /dev/null +++ b/patches/mfplat-streaming-support/0037-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch @@ -0,0 +1,98 @@ +From 3666bd0c7cd99b5ae00f8f6fca83f316a9df398c Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Mon, 22 Mar 2021 15:50:51 -0400 +Subject: [PATCH 37/39] winegstreamer: Implement MFT_MESSAGE_COMMAND_FLUSH for + media converters. + +Signed-off-by: Derek Lesho +--- + dlls/winegstreamer/audioconvert.c | 20 ++++++++++++++++++++ + dlls/winegstreamer/colorconvert.c | 23 +++++++++++++++++++++++ + 2 files changed, 43 insertions(+) + +diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c +index 1584fefe577..df471122b9e 100644 +--- a/dlls/winegstreamer/audioconvert.c ++++ b/dlls/winegstreamer/audioconvert.c +@@ -614,11 +614,31 @@ static HRESULT WINAPI audio_converter_ProcessEvent(IMFTransform *iface, DWORD id + + static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) + { ++ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); ++ struct wg_parser_event event; ++ + TRACE("%p, %u %lu.\n", iface, message, param); + + switch(message) + { + case MFT_MESSAGE_COMMAND_FLUSH: ++ { ++ EnterCriticalSection(&converter->cs); ++ if (!converter->buffer_inflight) ++ { ++ LeaveCriticalSection(&converter->cs); ++ return S_OK; ++ } ++ ++ while (event.type != WG_PARSER_EVENT_BUFFER) ++ unix_funcs->wg_parser_stream_get_event(converter->stream, &event); ++ ++ unix_funcs->wg_parser_stream_release_buffer(converter->stream); ++ converter->buffer_inflight = FALSE; ++ ++ LeaveCriticalSection(&converter->cs); ++ return S_OK; ++ } + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + return S_OK; + default: +diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c +index 6f3723b2b1e..947ef9adacb 100644 +--- a/dlls/winegstreamer/colorconvert.c ++++ b/dlls/winegstreamer/colorconvert.c +@@ -586,11 +586,31 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id + + static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) + { ++ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); ++ struct wg_parser_event event; ++ + TRACE("%p, %u %lu.\n", iface, message, param); + + switch(message) + { + case MFT_MESSAGE_COMMAND_FLUSH: ++ { ++ EnterCriticalSection(&converter->cs); ++ if (!converter->buffer_inflight) ++ { ++ LeaveCriticalSection(&converter->cs); ++ return S_OK; ++ } ++ ++ while (event.type != WG_PARSER_EVENT_BUFFER) ++ unix_funcs->wg_parser_stream_get_event(converter->stream, &event); ++ ++ unix_funcs->wg_parser_stream_release_buffer(converter->stream); ++ converter->buffer_inflight = FALSE; ++ ++ LeaveCriticalSection(&converter->cs); ++ return S_OK; ++ } + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + return S_OK; + default: +@@ -641,7 +661,10 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id + for (;;) + { + if (!unix_funcs->wg_parser_get_read_request(converter->parser, &data, &offset, &size)) ++ { ++ TRACE("sink unconnected\n"); + continue; ++ } + + memcpy(data, buffer_data, min(buffer_size, size)); + +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0037-winegstreamer-Translate-MPEG-4-Section-2-attributes-.patch b/patches/mfplat-streaming-support/0037-winegstreamer-Translate-MPEG-4-Section-2-attributes-.patch deleted file mode 100644 index a36690c9..00000000 --- a/patches/mfplat-streaming-support/0037-winegstreamer-Translate-MPEG-4-Section-2-attributes-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 9638f311e7d31f5e4aa80e173c31396d774afb75 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 11 May 2020 16:03:09 -0500 -Subject: [PATCH] winegstreamer: Translate MPEG-4 Section-2 attributes to caps. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index b1f83f4fa6c..8906e472766 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -1163,6 +1163,14 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - - user_data_to_codec_data(type, output); - } -+ else if (IsEqualGUID(&subtype, &MFVideoFormat_M4S2)) -+ { -+ output = gst_caps_new_empty_simple("video/mpeg"); -+ gst_caps_set_simple(output, "mpegversion", G_TYPE_INT, 4, NULL); -+ gst_caps_set_simple(output, "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); -+ -+ user_data_to_codec_data(type, output); -+ } - else - { - GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0038-mfreadwrite-Unset-seeking-flag-also-on-SourceStarted.patch b/patches/mfplat-streaming-support/0038-mfreadwrite-Unset-seeking-flag-also-on-SourceStarted.patch new file mode 100644 index 00000000..24946537 --- /dev/null +++ b/patches/mfplat-streaming-support/0038-mfreadwrite-Unset-seeking-flag-also-on-SourceStarted.patch @@ -0,0 +1,120 @@ +From a3c6815e44291b10a7756c8821e820b71be91fc6 Mon Sep 17 00:00:00 2001 +From: Giovanni Mascellani +Date: Mon, 22 Mar 2021 15:59:49 +0100 +Subject: [PATCH 38/39] mfreadwrite: Unset seeking flag also on SourceStarted + and SourceStopped. + +Signed-off-by: Giovanni Mascellani +Signed-off-by: Nikolay Sivov +Signed-off-by: Alexandre Julliard +--- + dlls/mfplat/buffer.c | 18 ++++++++++++++++-- + dlls/mfreadwrite/tests/mfplat.c | 6 ++++++ + dlls/winegstreamer/main.c | 1 + + 3 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c +index c1829043e1b..96eb02b3a61 100644 +--- a/dlls/mfplat/buffer.c ++++ b/dlls/mfplat/buffer.c +@@ -68,6 +68,7 @@ struct buffer + ID3D11Texture2D *texture; + unsigned int sub_resource_idx; + ID3D11Texture2D *rb_texture; ++ DXGI_FORMAT rb_texture_format; + D3D11_MAPPED_SUBRESOURCE map_desc; + struct attributes attributes; + } dxgi_surface; +@@ -890,6 +891,7 @@ static HRESULT dxgi_surface_buffer_create_readback_texture(struct buffer *buffer + texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + texture_desc.MiscFlags = 0; + texture_desc.MipLevels = 1; ++ buffer->dxgi_surface.rb_texture_format = texture_desc.Format; + if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &buffer->dxgi_surface.rb_texture))) + WARN("Failed to create readback texture, hr %#x.\n", hr); + +@@ -947,6 +949,7 @@ static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat + { + struct buffer *buffer = impl_from_IMFMediaBuffer(iface); + HRESULT hr = S_OK; ++ DWORD lines; + + TRACE("%p, %p, %p, %p.\n", iface, data, max_length, current_length); + +@@ -967,8 +970,13 @@ static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat + hr = dxgi_surface_buffer_map(buffer); + if (SUCCEEDED(hr)) + { ++ if (buffer->dxgi_surface.rb_texture_format == DXGI_FORMAT_NV12) ++ lines = buffer->_2d.height * 3 / 2; ++ else ++ lines = buffer->_2d.height; ++ + copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->dxgi_surface.map_desc.pData, +- buffer->dxgi_surface.map_desc.RowPitch, buffer->_2d.width, buffer->_2d.height); ++ buffer->dxgi_surface.map_desc.RowPitch, buffer->_2d.width, lines); + } + } + } +@@ -992,6 +1000,7 @@ static HRESULT WINAPI dxgi_surface_buffer_Unlock(IMFMediaBuffer *iface) + { + struct buffer *buffer = impl_from_IMFMediaBuffer(iface); + HRESULT hr = S_OK; ++ DWORD lines; + + TRACE("%p.\n", iface); + +@@ -1001,8 +1010,13 @@ static HRESULT WINAPI dxgi_surface_buffer_Unlock(IMFMediaBuffer *iface) + hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); + else if (!--buffer->_2d.locks) + { ++ if (buffer->dxgi_surface.rb_texture_format == DXGI_FORMAT_NV12) ++ lines = buffer->_2d.height * 3 / 2; ++ else ++ lines = buffer->_2d.height; ++ + copy_image(buffer, buffer->dxgi_surface.map_desc.pData, buffer->dxgi_surface.map_desc.RowPitch, +- buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height); ++ buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, lines); + dxgi_surface_buffer_unmap(buffer); + + free(buffer->_2d.linear_buffer); +diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c +index e3ff7f6e7aa..ba821df2190 100644 +--- a/dlls/mfreadwrite/tests/mfplat.c ++++ b/dlls/mfreadwrite/tests/mfplat.c +@@ -508,6 +508,7 @@ static IMFMediaSource *create_test_source(int stream_count) + { + struct test_source *source; + int i; ++ PROPVARIANT pos; + + source = heap_alloc_zero(sizeof(*source)); + source->IMFMediaSource_iface.lpVtbl = &test_source_vtbl; +@@ -924,6 +925,11 @@ static void test_source_reader_from_media_source(void) + hr = IMFSourceReader_SetCurrentPosition(reader, &GUID_NULL, &pos); + ok(hr == S_OK, "Failed to seek to beginning of stream, hr %#x.\n", hr); + ++ pos.vt = VT_I8; ++ pos.hVal.QuadPart = 0; ++ hr = IMFSourceReader_SetCurrentPosition(reader, &GUID_NULL, &pos); ++ ok(hr == S_OK, "Failed to seek to beginning of stream, hr %#x.\n", hr); ++ + hr = IMFSourceReader_ReadSample(reader, MF_SOURCE_READER_ANY_STREAM, 0, &actual_index, &stream_flags, + ×tamp, &sample); + ok(hr == S_OK, "Failed to get a sample, hr %#x.\n", hr); +diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c +index 16fd6147ddf..f6206fa5e2b 100644 +--- a/dlls/winegstreamer/main.c ++++ b/dlls/winegstreamer/main.c +@@ -39,6 +39,7 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) + { + DisableThreadLibraryCalls(instance); + __wine_init_unix_lib(instance, reason, NULL, &unix_funcs); ++ init_gstreamer(); + } + return TRUE; + } +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0038-winegstreamer-Translate-WMA-attributes-to-caps.patch b/patches/mfplat-streaming-support/0038-winegstreamer-Translate-WMA-attributes-to-caps.patch deleted file mode 100644 index e0dac18c..00000000 --- a/patches/mfplat-streaming-support/0038-winegstreamer-Translate-WMA-attributes-to-caps.patch +++ /dev/null @@ -1,39 +0,0 @@ -From e16c1d7b27467663a90eb23863d8110627ec3ad1 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 12 May 2020 17:05:59 -0500 -Subject: [PATCH] winegstreamer: Translate WMA attributes to caps. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 8906e472766..bf3486d2be8 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -1329,6 +1329,21 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - CoTaskMemFree(user_data); - } - } -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || -+ IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8)) -+ { -+ DWORD block_align; -+ -+ output = gst_caps_new_empty_simple("audio/x-wma"); -+ -+ gst_caps_set_simple(output, "wmaversion", G_TYPE_INT, -+ IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) ? 3 : 2, NULL); -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_align))) -+ gst_caps_set_simple(output, "block_align", G_TYPE_INT, block_align, NULL); -+ -+ user_data_to_codec_data(type, output); -+ } - else - { - FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype)); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0039-tools-Add-support-for-multiple-parent-directories.patch b/patches/mfplat-streaming-support/0039-tools-Add-support-for-multiple-parent-directories.patch deleted file mode 100644 index 7e62bd7a..00000000 --- a/patches/mfplat-streaming-support/0039-tools-Add-support-for-multiple-parent-directories.patch +++ /dev/null @@ -1,167 +0,0 @@ -From dd690ffa7c0a3b2a067f0f2fc1ec7f99cfc9d343 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 29 Jan 2020 15:37:39 -0600 -Subject: [PATCH] tools: Add support for multiple parent directories. - -Signed-off-by: Derek Lesho ---- - tools/make_makefiles | 45 +++++++++++++++++++++++++++----------------- - tools/makedep.c | 26 +++++++++++++++++-------- - 2 files changed, 46 insertions(+), 25 deletions(-) - -diff --git a/tools/make_makefiles b/tools/make_makefiles -index 2d3c14cb2ec..cb4a808244d 100755 ---- a/tools/make_makefiles -+++ b/tools/make_makefiles -@@ -229,14 +229,14 @@ sub parse_makefile($) - { - die "Configure substitution is not allowed in $file" unless $file eq "Makefile"; - } -- if (/^\s*(MODULE|IMPORTLIB|TESTDLL|PARENTSRC|APPMODE|EXTRADLLFLAGS)\s*=\s*(.*)/) -+ if (/^\s*(MODULE|IMPORTLIB|TESTDLL|APPMODE|EXTRADLLFLAGS)\s*=\s*(.*)/) - { - my $var = $1; - $make{$var} = $2; - next; - } - my $source_vars_regexp = join "|", @source_vars; -- if (/^\s*($source_vars_regexp|PROGRAMS|EXTRA_TARGETS|EXTRA_OBJS|INSTALL_LIB|INSTALL_DEV)\s*=\s*(.*)/) -+ if (/^\s*($source_vars_regexp|PROGRAMS|EXTRA_TARGETS|EXTRA_OBJS|INSTALL_LIB|INSTALL_DEV|PARENTSRC)\s*=\s*(.*)/) - { - my $var = $1; - my @list = split(/\s+/, $2); -@@ -291,19 +291,27 @@ sub get_makedep_flags($) - return %flags; - } - --sub get_parent_makefile($) -+sub get_parent_makefiles($) - { - my $file = shift; - my %make = %{$makefiles{$file}}; -- my $reldir = $make{"PARENTSRC"} || ""; -- return "" unless $reldir; -- (my $path = $file) =~ s/\/Makefile$/\//; -- while ($reldir =~ /^\.\.\//) -+ my $pointer = $make{"PARENTSRC"} || (); -+ return () unless $pointer; -+ my @reldirs = @{$pointer}; -+ my @makefiles = (); -+ foreach my $reldir (@reldirs) - { -- $reldir =~ s/^\.\.\///; -- $path =~ s/[^\/]+\/$//; -+ my $length = @reldirs; -+ (my $path = $file) =~ s/\/Makefile$/\//; -+ while ($reldir =~ /^\.\.\//) -+ { -+ $reldir =~ s/^\.\.\///; -+ $path =~ s/[^\/]+\/$//; -+ } -+ push @makefiles, "$path$reldir/Makefile"; - } -- return "$path$reldir/Makefile"; -+ -+ return @makefiles - } - - # preserve shared source files that are listed in the existing makefile -@@ -404,13 +412,16 @@ sub assign_sources_to_makefiles(@) - foreach my $file (@makefiles) - { - my $make = $makefiles{$file}; -- my $parent = get_parent_makefile( $file ); -- next unless $parent; -- preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "C_SRCS" ); -- preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "RC_SRCS" ); -- preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "IDL_SRCS" ); -- preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "LEX_SRCS" ); -- preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "BISON_SRCS" ); -+ my @parents = get_parent_makefiles( $file ); -+ next unless @parents; -+ foreach my $parent (@parents) -+ { -+ preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "C_SRCS" ); -+ preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "RC_SRCS" ); -+ preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "IDL_SRCS" ); -+ preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "LEX_SRCS" ); -+ preserve_shared_source_files( $makefiles{$file}, $makefiles{$parent}, "BISON_SRCS" ); -+ } - } - } - -diff --git a/tools/makedep.c b/tools/makedep.c -index d892b7e9541..688487ffd82 100644 ---- a/tools/makedep.c -+++ b/tools/makedep.c -@@ -190,11 +190,11 @@ struct makefile - struct strarray install_dev; - struct strarray extra_targets; - struct strarray extra_imports; -+ struct strarray parent_dirs; - struct list sources; - struct list includes; - const char *src_dir; - const char *obj_dir; -- const char *parent_dir; - const char *module; - const char *testdll; - const char *sharedlib; -@@ -1388,14 +1388,21 @@ static struct file *open_local_file( const struct makefile *make, const char *pa - { - char *src_path = src_dir_path( make, path ); - struct file *ret = load_file( src_path ); -+ unsigned int i; - -- /* if not found, try parent dir */ -- if (!ret && make->parent_dir) -+ /* if not found, try parent dirs */ -+ for (i = 0; !ret && i < make->parent_dirs.count; i++) - { -+ char *new_path; -+ - free( src_path ); -- path = strmake( "%s/%s", make->parent_dir, path ); -- src_path = src_dir_path( make, path ); -+ new_path = strmake( "%s/%s", make->parent_dirs.str[i], path ); -+ src_path = src_dir_path( make, new_path ); - ret = load_file( src_path ); -+ if (ret) -+ path = new_path; -+ else -+ free(new_path); - } - - if (ret) *filename = src_path; -@@ -4158,13 +4165,13 @@ static void load_sources( struct makefile *make ) - strarray_set_value( &make->vars, "top_srcdir", root_src_dir_path( "" )); - strarray_set_value( &make->vars, "srcdir", src_dir_path( make, "" )); - -- make->parent_dir = get_expanded_make_variable( make, "PARENTSRC" ); - make->module = get_expanded_make_variable( make, "MODULE" ); - make->testdll = get_expanded_make_variable( make, "TESTDLL" ); - make->sharedlib = get_expanded_make_variable( make, "SHAREDLIB" ); - make->staticlib = get_expanded_make_variable( make, "STATICLIB" ); - make->importlib = get_expanded_make_variable( make, "IMPORTLIB" ); - -+ make->parent_dirs = get_expanded_make_var_array( make, "PARENTSRC" ); - make->programs = get_expanded_make_var_array( make, "PROGRAMS" ); - make->scripts = get_expanded_make_var_array( make, "SCRIPTS" ); - make->imports = get_expanded_make_var_array( make, "IMPORTS" ); -@@ -4209,8 +4216,11 @@ static void load_sources( struct makefile *make ) - strarray_add( &make->include_args, strmake( "-I%s", obj_dir_path( make, "" ))); - if (make->src_dir) - strarray_add( &make->include_args, strmake( "-I%s", make->src_dir )); -- if (make->parent_dir) -- strarray_add( &make->include_args, strmake( "-I%s", src_dir_path( make, make->parent_dir ))); -+ if (make->parent_dirs.count) -+ { -+ for (i = 0; i < make->parent_dirs.count; i++) -+ strarray_add( &make->include_args, strmake( "-I%s", src_dir_path( make, make->parent_dirs.str[i] ))); -+ } - strarray_add( &make->include_args, "-Iinclude" ); - if (root_src_dir) strarray_add( &make->include_args, strmake( "-I%s", root_src_dir_path( "include" ))); - --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0039-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch b/patches/mfplat-streaming-support/0039-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch new file mode 100644 index 00000000..74c976cf --- /dev/null +++ b/patches/mfplat-streaming-support/0039-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch @@ -0,0 +1,44 @@ +From 9113e5421fd865f783f2bb3101336491fc92404d Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Sun, 20 Jun 2021 14:46:57 +1000 +Subject: [PATCH] winegstreamer: Default Frame size if one isn't available + +Stop crash when loading steam +--- + dlls/winegstreamer/mfplat.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c +index 251ab021073..19fd2596a47 100644 +--- a/dlls/winegstreamer/mfplat.c ++++ b/dlls/winegstreamer/mfplat.c +@@ -837,18 +837,19 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_forma + FIXME("Subtype is not set.\n"); + return; + } +- if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) +- { +- FIXME("Frame size is not set.\n"); +- return; +- } + + format->major_type = WG_MAJOR_TYPE_VIDEO; +- format->u.video.width = (UINT32)(frame_size >> 32); +- format->u.video.height = (UINT32)frame_size; ++ format->u.video.width = 0; ++ format->u.video.height = 0; + format->u.video.fps_n = 1; + format->u.video.fps_d = 1; + ++ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)) && (UINT32)frame_size) ++ { ++ format->u.video.width = (UINT32)(frame_size >> 32); ++ format->u.video.height = (UINT32)frame_size; ++ } ++ + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) + { + format->u.video.fps_n = (UINT32)(frame_rate >> 32); +-- +2.30.2 + diff --git a/patches/mfplat-streaming-support/0040-mf-Introduce-handler-helper.patch b/patches/mfplat-streaming-support/0040-mf-Introduce-handler-helper.patch deleted file mode 100644 index a04ff9d2..00000000 --- a/patches/mfplat-streaming-support/0040-mf-Introduce-handler-helper.patch +++ /dev/null @@ -1,1369 +0,0 @@ -From ef2efb4cb317917e4269ea42b322be7f48ac7682 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 29 Jan 2020 15:30:49 -0600 -Subject: [PATCH] mf: Introduce handler helper. - -Signed-off-by: Derek Lesho ---- - dlls/mf/Makefile.in | 1 + - dlls/mf/handler.c | 360 ++++++++++++++++++++++++++++ - dlls/mf/handler.h | 30 +++ - dlls/mf/main.c | 373 ++++-------------------------- - dlls/winegstreamer/Makefile.in | 3 +- - dlls/winegstreamer/media_source.c | 334 ++------------------------ - 6 files changed, 447 insertions(+), 654 deletions(-) - create mode 100644 dlls/mf/handler.c - create mode 100644 dlls/mf/handler.h - -diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in -index cd50a849b7c..67a7e8a79b6 100644 ---- a/dlls/mf/Makefile.in -+++ b/dlls/mf/Makefile.in -@@ -8,6 +8,7 @@ EXTRADLLFLAGS = -mno-cygwin - C_SRCS = \ - copier.c \ - evr.c \ -+ handler.c \ - main.c \ - samplegrabber.c \ - sar.c \ -diff --git a/dlls/mf/handler.c b/dlls/mf/handler.c -new file mode 100644 -index 00000000000..da40049377e ---- /dev/null -+++ b/dlls/mf/handler.c -@@ -0,0 +1,360 @@ -+#include -+ -+#define COBJMACROS -+ -+#include "windef.h" -+#include "winbase.h" -+#include "mfidl.h" -+ -+#include "mfapi.h" -+#include "mferror.h" -+ -+#include "handler.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+#include "wine/list.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -+ -+struct create_object_context -+{ -+ IUnknown IUnknown_iface; -+ LONG refcount; -+ -+ IPropertyStore *props; -+ IMFByteStream *stream; -+ WCHAR *url; -+ DWORD flags; -+}; -+ -+struct handler_result -+{ -+ struct list entry; -+ IMFAsyncResult *result; -+ MF_OBJECT_TYPE obj_type; -+ IUnknown *object; -+}; -+ -+static struct create_object_context *impl_from_IUnknown(IUnknown *iface) -+{ -+ return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface); -+} -+ -+static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj) -+{ -+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); -+ -+ if (IsEqualIID(riid, &IID_IUnknown)) -+ { -+ *obj = iface; -+ IUnknown_AddRef(iface); -+ return S_OK; -+ } -+ -+ WARN("Unsupported %s.\n", debugstr_guid(riid)); -+ *obj = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI create_object_context_AddRef(IUnknown *iface) -+{ -+ struct create_object_context *context = impl_from_IUnknown(iface); -+ ULONG refcount = InterlockedIncrement(&context->refcount); -+ -+ TRACE("%p, refcount %u.\n", iface, refcount); -+ -+ return refcount; -+} -+ -+static ULONG WINAPI create_object_context_Release(IUnknown *iface) -+{ -+ struct create_object_context *context = impl_from_IUnknown(iface); -+ ULONG refcount = InterlockedDecrement(&context->refcount); -+ -+ TRACE("%p, refcount %u.\n", iface, refcount); -+ -+ if (!refcount) -+ { -+ if (context->props) -+ IPropertyStore_Release(context->props); -+ if (context->stream) -+ IMFByteStream_Release(context->stream); -+ if (context->url) -+ heap_free(context->url); -+ heap_free(context); -+ } -+ -+ return refcount; -+} -+ -+static const IUnknownVtbl create_object_context_vtbl = -+{ -+ create_object_context_QueryInterface, -+ create_object_context_AddRef, -+ create_object_context_Release, -+}; -+ -+/* Start async methods */ -+static struct handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) -+{ -+ return CONTAINING_RECORD(iface, struct handler, IMFAsyncCallback_iface); -+} -+ -+static HRESULT WINAPI handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) -+{ -+ if (IsEqualIID(riid, &IID_IMFAsyncCallback) || -+ IsEqualIID(riid, &IID_IUnknown)) -+ { -+ *obj = iface; -+ IMFAsyncCallback_AddRef(iface); -+ return S_OK; -+ } -+ -+ WARN("Unsupported %s.\n", debugstr_guid(riid)); -+ *obj = NULL; -+ return E_NOINTERFACE; -+} -+ -+/* lifetime not managed with COM */ -+static ULONG WINAPI handler_callback_AddRef(IMFAsyncCallback *iface) -+{ -+ return 2; -+} -+ -+static ULONG WINAPI handler_callback_Release(IMFAsyncCallback *iface) -+{ -+ return 1; -+} -+ -+static HRESULT WINAPI handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -+{ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -+{ -+ struct handler *handler = impl_from_IMFAsyncCallback(iface); -+ struct handler_result *handler_result; -+ MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID; -+ IUnknown *object = NULL, *context_object; -+ struct create_object_context *context; -+ IMFAsyncResult *caller; -+ HRESULT hr; -+ -+ caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); -+ -+ if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) -+ { -+ WARN("Expected context set for callee result.\n"); -+ return hr; -+ } -+ -+ context = impl_from_IUnknown(context_object); -+ -+ hr = handler->create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type); -+ -+ handler_result = heap_alloc(sizeof(*handler_result)); -+ if (handler_result) -+ { -+ handler_result->result = caller; -+ IMFAsyncResult_AddRef(handler_result->result); -+ handler_result->obj_type = obj_type; -+ handler_result->object = object; -+ -+ EnterCriticalSection(&handler->cs); -+ list_add_tail(&handler->results, &handler_result->entry); -+ LeaveCriticalSection(&handler->cs); -+ } -+ else -+ { -+ if (object) -+ IUnknown_Release(object); -+ hr = E_OUTOFMEMORY; -+ } -+ -+ IUnknown_Release(&context->IUnknown_iface); -+ -+ IMFAsyncResult_SetStatus(caller, hr); -+ MFInvokeCallback(caller); -+ -+ return S_OK; -+} -+ -+static const IMFAsyncCallbackVtbl handler_callback_vtbl = -+{ -+ handler_callback_QueryInterface, -+ handler_callback_AddRef, -+ handler_callback_Release, -+ handler_callback_GetParameters, -+ handler_callback_Invoke, -+}; -+ -+/* Start handler helpers */ -+ -+static WCHAR *heap_strdupW(const WCHAR *str) -+{ -+ WCHAR *ret = NULL; -+ -+ if (str) -+ { -+ unsigned int size; -+ -+ size = (lstrlenW(str) + 1) * sizeof(WCHAR); -+ ret = heap_alloc(size); -+ if (ret) -+ memcpy(ret, str, size); -+ } -+ -+ return ret; -+} -+ -+HRESULT handler_begin_create_object(struct handler *handler, IMFByteStream *stream, -+ const WCHAR *url, DWORD flags, IPropertyStore *props, IUnknown **cancel_cookie, -+ IMFAsyncCallback *callback, IUnknown *state) -+{ -+ struct create_object_context *context; -+ IMFAsyncResult *caller, *item; -+ HRESULT hr; -+ -+ if (cancel_cookie) -+ *cancel_cookie = NULL; -+ -+ if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) -+ return hr; -+ -+ context = heap_alloc(sizeof(*context)); -+ if (!context) -+ { -+ IMFAsyncResult_Release(caller); -+ return E_OUTOFMEMORY; -+ } -+ -+ context->IUnknown_iface.lpVtbl = &create_object_context_vtbl; -+ context->refcount = 1; -+ context->props = props; -+ if (context->props) -+ IPropertyStore_AddRef(context->props); -+ context->flags = flags; -+ context->stream = stream; -+ if (context->stream) -+ IMFByteStream_AddRef(context->stream); -+ if (url) -+ context->url = heap_strdupW(url); -+ if (!context->url && !context->stream) -+ { -+ IMFAsyncResult_Release(caller); -+ IUnknown_Release(&context->IUnknown_iface); -+ return E_OUTOFMEMORY; -+ } -+ -+ hr = MFCreateAsyncResult(&context->IUnknown_iface, &handler->IMFAsyncCallback_iface, (IUnknown *)caller, &item); -+ IUnknown_Release(&context->IUnknown_iface); -+ if (SUCCEEDED(hr)) -+ { -+ if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) -+ { -+ if (cancel_cookie) -+ { -+ *cancel_cookie = (IUnknown *)caller; -+ IUnknown_AddRef(*cancel_cookie); -+ } -+ } -+ -+ IMFAsyncResult_Release(item); -+ } -+ IMFAsyncResult_Release(caller); -+ -+ return hr; -+} -+ -+HRESULT handler_end_create_object(struct handler *handler, IMFAsyncResult *result, -+ MF_OBJECT_TYPE *obj_type, IUnknown **object) -+{ -+ struct handler_result *found = NULL, *cur; -+ HRESULT hr; -+ -+ EnterCriticalSection(&handler->cs); -+ -+ LIST_FOR_EACH_ENTRY(cur, &handler->results, struct handler_result, entry) -+ { -+ if (result == cur->result) -+ { -+ list_remove(&cur->entry); -+ found = cur; -+ break; -+ } -+ } -+ -+ LeaveCriticalSection(&handler->cs); -+ -+ if (found) -+ { -+ *obj_type = found->obj_type; -+ *object = found->object; -+ hr = IMFAsyncResult_GetStatus(found->result); -+ IMFAsyncResult_Release(found->result); -+ heap_free(found); -+ } -+ else -+ { -+ *obj_type = MF_OBJECT_INVALID; -+ *object = NULL; -+ hr = MF_E_UNEXPECTED; -+ } -+ -+ return hr; -+} -+ -+HRESULT handler_cancel_object_creation(struct handler *handler, IUnknown *cancel_cookie) -+{ -+ struct handler_result *found = NULL, *cur; -+ -+ EnterCriticalSection(&handler->cs); -+ -+ LIST_FOR_EACH_ENTRY(cur, &handler->results, struct handler_result, entry) -+ { -+ if (cancel_cookie == (IUnknown *)cur->result) -+ { -+ list_remove(&cur->entry); -+ found = cur; -+ break; -+ } -+ } -+ -+ LeaveCriticalSection(&handler->cs); -+ -+ if (found) -+ { -+ IMFAsyncResult_Release(found->result); -+ if (found->object) -+ IUnknown_Release(found->object); -+ heap_free(found); -+ } -+ -+ return found ? S_OK : MF_E_UNEXPECTED; -+} -+ -+void handler_construct(struct handler *handler, p_create_object_callback create_object_callback) -+{ -+ handler->IMFAsyncCallback_iface.lpVtbl = &handler_callback_vtbl; -+ handler->create_object = create_object_callback; -+ -+ list_init(&handler->results); -+ InitializeCriticalSection(&handler->cs); -+} -+ -+void handler_destruct(struct handler *handler) -+{ -+ struct handler_result *result, *next; -+ -+ LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct handler_result, entry) -+ { -+ list_remove(&result->entry); -+ IMFAsyncResult_Release(result->result); -+ if (result->object) -+ IUnknown_Release(result->object); -+ heap_free(result); -+ } -+ DeleteCriticalSection(&handler->cs); -+} -\ No newline at end of file -diff --git a/dlls/mf/handler.h b/dlls/mf/handler.h -new file mode 100644 -index 00000000000..fbebd26e8d0 ---- /dev/null -+++ b/dlls/mf/handler.h -@@ -0,0 +1,30 @@ -+#include "windef.h" -+ -+#include "mfidl.h" -+#include "mfapi.h" -+#include "mfobjects.h" -+ -+#include "wine/list.h" -+ -+/* helper sub-object that handles ansyncronous nature of handlers */ -+ -+struct handler; -+typedef HRESULT (*p_create_object_callback)(struct handler *handler, WCHAR *url, IMFByteStream *stream, DWORD flags, IPropertyStore *props, -+ IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type); -+ -+struct handler -+{ -+ IMFAsyncCallback IMFAsyncCallback_iface; -+ struct list results; -+ CRITICAL_SECTION cs; -+ p_create_object_callback create_object; -+}; -+ -+void handler_construct(struct handler *handler, p_create_object_callback create_object_callback); -+void handler_destruct(struct handler *handler); -+HRESULT handler_begin_create_object(struct handler *handler, IMFByteStream *stream, -+ const WCHAR *url, DWORD flags, IPropertyStore *props, IUnknown **cancel_cookie, -+ IMFAsyncCallback *callback, IUnknown *state); -+HRESULT handler_end_create_object(struct handler *handler, IMFAsyncResult *result, -+ MF_OBJECT_TYPE *obj_type, IUnknown **object); -+HRESULT handler_cancel_object_creation(struct handler *handler, IUnknown *cancel_cookie); -\ No newline at end of file -diff --git a/dlls/mf/main.c b/dlls/mf/main.c -index 2caf50c54e0..cf58c899843 100644 ---- a/dlls/mf/main.c -+++ b/dlls/mf/main.c -@@ -27,6 +27,7 @@ - #include "rpcproxy.h" - - #include "mf_private.h" -+#include "handler.h" - - #include "wine/debug.h" - #include "wine/heap.h" -@@ -550,22 +551,12 @@ static const IClassFactoryVtbl class_factory_vtbl = - class_factory_LockServer, - }; - --struct file_scheme_handler_result --{ -- struct list entry; -- IMFAsyncResult *result; -- MF_OBJECT_TYPE obj_type; -- IUnknown *object; --}; -- - struct file_scheme_handler - { - IMFSchemeHandler IMFSchemeHandler_iface; -- IMFAsyncCallback IMFAsyncCallback_iface; - LONG refcount; - IMFSourceResolver *resolver; -- struct list results; -- CRITICAL_SECTION cs; -+ struct handler handler; - }; - - static struct file_scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface) -@@ -573,11 +564,6 @@ static struct file_scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler * - return CONTAINING_RECORD(iface, struct file_scheme_handler, IMFSchemeHandler_iface); - } - --static struct file_scheme_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) --{ -- return CONTAINING_RECORD(iface, struct file_scheme_handler, IMFAsyncCallback_iface); --} -- - static HRESULT WINAPI file_scheme_handler_QueryInterface(IMFSchemeHandler *iface, REFIID riid, void **obj) - { - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); -@@ -607,242 +593,45 @@ static ULONG WINAPI file_scheme_handler_AddRef(IMFSchemeHandler *iface) - - static ULONG WINAPI file_scheme_handler_Release(IMFSchemeHandler *iface) - { -- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); -- ULONG refcount = InterlockedDecrement(&handler->refcount); -- struct file_scheme_handler_result *result, *next; -+ struct file_scheme_handler *this = impl_from_IMFSchemeHandler(iface); -+ ULONG refcount = InterlockedDecrement(&this->refcount); - - TRACE("%p, refcount %u.\n", iface, refcount); - - if (!refcount) - { -- LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct file_scheme_handler_result, entry) -- { -- list_remove(&result->entry); -- IMFAsyncResult_Release(result->result); -- if (result->object) -- IUnknown_Release(result->object); -- heap_free(result); -- } -- DeleteCriticalSection(&handler->cs); -- if (handler->resolver) -- IMFSourceResolver_Release(handler->resolver); -- heap_free(handler); -+ if (this->resolver) -+ IMFSourceResolver_Release(this->resolver); -+ handler_destruct(&this->handler); - } - - return refcount; - } - --struct create_object_context --{ -- IUnknown IUnknown_iface; -- LONG refcount; -- -- IPropertyStore *props; -- WCHAR *url; -- DWORD flags; --}; -- --static struct create_object_context *impl_from_IUnknown(IUnknown *iface) --{ -- return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface); --} -- --static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj) --{ -- TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); -- -- if (IsEqualIID(riid, &IID_IUnknown)) -- { -- *obj = iface; -- IUnknown_AddRef(iface); -- return S_OK; -- } -- -- WARN("Unsupported %s.\n", debugstr_guid(riid)); -- *obj = NULL; -- return E_NOINTERFACE; --} -- --static ULONG WINAPI create_object_context_AddRef(IUnknown *iface) --{ -- struct create_object_context *context = impl_from_IUnknown(iface); -- ULONG refcount = InterlockedIncrement(&context->refcount); -- -- TRACE("%p, refcount %u.\n", iface, refcount); -- -- return refcount; --} -- --static ULONG WINAPI create_object_context_Release(IUnknown *iface) --{ -- struct create_object_context *context = impl_from_IUnknown(iface); -- ULONG refcount = InterlockedDecrement(&context->refcount); -- -- TRACE("%p, refcount %u.\n", iface, refcount); -- -- if (!refcount) -- { -- if (context->props) -- IPropertyStore_Release(context->props); -- heap_free(context->url); -- heap_free(context); -- } -- -- return refcount; --} -- --static const IUnknownVtbl create_object_context_vtbl = --{ -- create_object_context_QueryInterface, -- create_object_context_AddRef, -- create_object_context_Release, --}; -- --static WCHAR *heap_strdupW(const WCHAR *str) --{ -- WCHAR *ret = NULL; -- -- if (str) -- { -- unsigned int size; -- -- size = (lstrlenW(str) + 1) * sizeof(WCHAR); -- ret = heap_alloc(size); -- if (ret) -- memcpy(ret, str, size); -- } -- -- return ret; --} -- - static HRESULT WINAPI file_scheme_handler_BeginCreateObject(IMFSchemeHandler *iface, const WCHAR *url, DWORD flags, - IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) - { -- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); -- struct create_object_context *context; -- IMFAsyncResult *caller, *item; -- HRESULT hr; -+ struct file_scheme_handler *this = impl_from_IMFSchemeHandler(iface); - - TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); -- -- if (cancel_cookie) -- *cancel_cookie = NULL; -- -- if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) -- return hr; -- -- context = heap_alloc(sizeof(*context)); -- if (!context) -- { -- IMFAsyncResult_Release(caller); -- return E_OUTOFMEMORY; -- } -- -- context->IUnknown_iface.lpVtbl = &create_object_context_vtbl; -- context->refcount = 1; -- context->props = props; -- if (context->props) -- IPropertyStore_AddRef(context->props); -- context->flags = flags; -- context->url = heap_strdupW(url); -- if (!context->url) -- { -- IMFAsyncResult_Release(caller); -- IUnknown_Release(&context->IUnknown_iface); -- return E_OUTOFMEMORY; -- } -- -- hr = MFCreateAsyncResult(&context->IUnknown_iface, &handler->IMFAsyncCallback_iface, (IUnknown *)caller, &item); -- IUnknown_Release(&context->IUnknown_iface); -- if (SUCCEEDED(hr)) -- { -- if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) -- { -- if (cancel_cookie) -- { -- *cancel_cookie = (IUnknown *)caller; -- IUnknown_AddRef(*cancel_cookie); -- } -- } -- -- IMFAsyncResult_Release(item); -- } -- IMFAsyncResult_Release(caller); -- -- return hr; -+ return handler_begin_create_object(&this->handler, NULL, url, flags, props, cancel_cookie, callback, state); - } - - static HRESULT WINAPI file_scheme_handler_EndCreateObject(IMFSchemeHandler *iface, IMFAsyncResult *result, - MF_OBJECT_TYPE *obj_type, IUnknown **object) - { -- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); -- struct file_scheme_handler_result *found = NULL, *cur; -- HRESULT hr; -+ struct file_scheme_handler *this = impl_from_IMFSchemeHandler(iface); - - TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); -- -- EnterCriticalSection(&handler->cs); -- -- LIST_FOR_EACH_ENTRY(cur, &handler->results, struct file_scheme_handler_result, entry) -- { -- if (result == cur->result) -- { -- list_remove(&cur->entry); -- found = cur; -- break; -- } -- } -- -- LeaveCriticalSection(&handler->cs); -- -- if (found) -- { -- *obj_type = found->obj_type; -- *object = found->object; -- hr = IMFAsyncResult_GetStatus(found->result); -- IMFAsyncResult_Release(found->result); -- heap_free(found); -- } -- else -- { -- *obj_type = MF_OBJECT_INVALID; -- *object = NULL; -- hr = MF_E_UNEXPECTED; -- } -- -- return hr; -+ return handler_end_create_object(&this->handler, result, obj_type, object); - } - - static HRESULT WINAPI file_scheme_handler_CancelObjectCreation(IMFSchemeHandler *iface, IUnknown *cancel_cookie) - { -- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); -- struct file_scheme_handler_result *found = NULL, *cur; -+ struct file_scheme_handler *this = impl_from_IMFSchemeHandler(iface); - - TRACE("%p, %p.\n", iface, cancel_cookie); -- -- EnterCriticalSection(&handler->cs); -- -- LIST_FOR_EACH_ENTRY(cur, &handler->results, struct file_scheme_handler_result, entry) -- { -- if (cancel_cookie == (IUnknown *)cur->result) -- { -- list_remove(&cur->entry); -- found = cur; -- break; -- } -- } -- -- LeaveCriticalSection(&handler->cs); -- -- if (found) -- { -- IMFAsyncResult_Release(found->result); -- if (found->object) -- IUnknown_Release(found->object); -- heap_free(found); -- } -- -- return found ? S_OK : MF_E_UNEXPECTED; -+ return handler_cancel_object_creation(&this->handler, cancel_cookie); - } - - static const IMFSchemeHandlerVtbl file_scheme_handler_vtbl = -@@ -855,38 +644,6 @@ static const IMFSchemeHandlerVtbl file_scheme_handler_vtbl = - file_scheme_handler_CancelObjectCreation, - }; - --static HRESULT WINAPI file_scheme_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) --{ -- if (IsEqualIID(riid, &IID_IMFAsyncCallback) || -- IsEqualIID(riid, &IID_IUnknown)) -- { -- *obj = iface; -- IMFAsyncCallback_AddRef(iface); -- return S_OK; -- } -- -- WARN("Unsupported %s.\n", debugstr_guid(riid)); -- *obj = NULL; -- return E_NOINTERFACE; --} -- --static ULONG WINAPI file_scheme_handler_callback_AddRef(IMFAsyncCallback *iface) --{ -- struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); -- return IMFSchemeHandler_AddRef(&handler->IMFSchemeHandler_iface); --} -- --static ULONG WINAPI file_scheme_handler_callback_Release(IMFAsyncCallback *iface) --{ -- struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); -- return IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); --} -- --static HRESULT WINAPI file_scheme_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) --{ -- return E_NOTIMPL; --} -- - static HRESULT file_scheme_handler_get_resolver(struct file_scheme_handler *handler, IMFSourceResolver **resolver) - { - HRESULT hr; -@@ -908,111 +665,63 @@ static HRESULT file_scheme_handler_get_resolver(struct file_scheme_handler *hand - return S_OK; - } - --static HRESULT WINAPI file_scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -+static HRESULT file_scheme_handler_create_object(struct handler *handler, WCHAR *url, IMFByteStream *stream, DWORD flags, -+ IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type) - { - static const WCHAR schemeW[] = {'f','i','l','e',':','/','/'}; -- struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); -- struct file_scheme_handler_result *handler_result; -- MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID; -- IUnknown *object = NULL, *context_object; -- struct create_object_context *context; -+ HRESULT hr = S_OK; -+ WCHAR *path; -+ IMFByteStream *file_byte_stream; -+ struct file_scheme_handler *this = CONTAINING_RECORD(handler, struct file_scheme_handler, handler); - IMFSourceResolver *resolver; -- IMFAsyncResult *caller; -- IMFByteStream *stream; -- const WCHAR *url; -- HRESULT hr; -- -- caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); -- -- if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) -- { -- WARN("Expected context set for callee result.\n"); -- return hr; -- } -- -- context = impl_from_IUnknown(context_object); - - /* Strip from scheme, MFCreateFile() won't be expecting it. */ -- url = context->url; -- if (!wcsnicmp(context->url, schemeW, ARRAY_SIZE(schemeW))) -- url += ARRAY_SIZE(schemeW); -+ path = url; -+ if (!wcsnicmp(url, schemeW, ARRAY_SIZE(schemeW))) -+ path += ARRAY_SIZE(schemeW); - -- hr = MFCreateFile(context->flags & MF_RESOLUTION_WRITE ? MF_ACCESSMODE_READWRITE : MF_ACCESSMODE_READ, -- MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, url, &stream); -+ hr = MFCreateFile(flags & MF_RESOLUTION_WRITE ? MF_ACCESSMODE_READWRITE : MF_ACCESSMODE_READ, -+ MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, path, &file_byte_stream); - if (SUCCEEDED(hr)) - { -- if (context->flags & MF_RESOLUTION_MEDIASOURCE) -+ if (flags & MF_RESOLUTION_MEDIASOURCE) - { -- if (SUCCEEDED(hr = file_scheme_handler_get_resolver(handler, &resolver))) -+ if (SUCCEEDED(hr = file_scheme_handler_get_resolver(this, &resolver))) - { -- hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, context->url, context->flags, -- context->props, &obj_type, &object); -+ hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, file_byte_stream, url, flags, -+ props, out_obj_type, out_object); - IMFSourceResolver_Release(resolver); -- IMFByteStream_Release(stream); -+ IMFByteStream_Release(file_byte_stream); - } - } - else - { -- object = (IUnknown *)stream; -- obj_type = MF_OBJECT_BYTESTREAM; -+ *out_object = (IUnknown *)file_byte_stream; -+ *out_obj_type = MF_OBJECT_BYTESTREAM; - } - } - -- handler_result = heap_alloc(sizeof(*handler_result)); -- if (handler_result) -- { -- handler_result->result = caller; -- IMFAsyncResult_AddRef(handler_result->result); -- handler_result->obj_type = obj_type; -- handler_result->object = object; -- -- EnterCriticalSection(&handler->cs); -- list_add_tail(&handler->results, &handler_result->entry); -- LeaveCriticalSection(&handler->cs); -- } -- else -- { -- if (object) -- IUnknown_Release(object); -- hr = E_OUTOFMEMORY; -- } -- -- IUnknown_Release(&context->IUnknown_iface); -- -- IMFAsyncResult_SetStatus(caller, hr); -- MFInvokeCallback(caller); -- -- return S_OK; -+ return hr; - } - --static const IMFAsyncCallbackVtbl file_scheme_handler_callback_vtbl = --{ -- file_scheme_handler_callback_QueryInterface, -- file_scheme_handler_callback_AddRef, -- file_scheme_handler_callback_Release, -- file_scheme_handler_callback_GetParameters, -- file_scheme_handler_callback_Invoke, --}; -- - static HRESULT file_scheme_handler_construct(REFIID riid, void **obj) - { -- struct file_scheme_handler *handler; -+ struct file_scheme_handler *this; - HRESULT hr; - - TRACE("%s, %p.\n", debugstr_guid(riid), obj); - -- handler = heap_alloc_zero(sizeof(*handler)); -- if (!handler) -+ this = heap_alloc_zero(sizeof(*this)); -+ if (!this) - return E_OUTOFMEMORY; - -- handler->IMFSchemeHandler_iface.lpVtbl = &file_scheme_handler_vtbl; -- handler->IMFAsyncCallback_iface.lpVtbl = &file_scheme_handler_callback_vtbl; -- handler->refcount = 1; -- list_init(&handler->results); -- InitializeCriticalSection(&handler->cs); -+ handler_construct(&this->handler, file_scheme_handler_create_object); -+ -+ this->IMFSchemeHandler_iface.lpVtbl = &file_scheme_handler_vtbl; -+ this->refcount = 1; - -- hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj); -- IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); -+ hr = IMFSchemeHandler_QueryInterface(&this->IMFSchemeHandler_iface, riid, obj); -+ IMFSchemeHandler_Release(&this->IMFSchemeHandler_iface); - - return hr; - } -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 5395d6fd501..4f6b428f067 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -3,7 +3,7 @@ IMPORTS = strmiids uuid ole32 mfuuid - DELAYIMPORTS = mfplat - EXTRAINCL = $(GSTREAMER_CFLAGS) - EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) --PARENTSRC = ../strmbase -+PARENTSRC = ../strmbase ../mf - - C_SRCS = \ - audioconvert.c \ -@@ -11,6 +11,7 @@ C_SRCS = \ - filter.c \ - gst_cbs.c \ - gstdemux.c \ -+ handler.c \ - main.c \ - media_source.c \ - mediatype.c \ -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index aecf4f27375..5f46f7d575a 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -23,6 +23,7 @@ - - #include "gst_private.h" - #include "gst_cbs.h" -+#include "handler.h" - - #include - #include -@@ -1635,21 +1636,11 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - return hr; - } - --struct winegstreamer_stream_handler_result --{ -- struct list entry; -- IMFAsyncResult *result; -- MF_OBJECT_TYPE obj_type; -- IUnknown *object; --}; -- - struct winegstreamer_stream_handler - { - IMFByteStreamHandler IMFByteStreamHandler_iface; -- IMFAsyncCallback IMFAsyncCallback_iface; - LONG refcount; -- struct list results; -- CRITICAL_SECTION cs; -+ struct handler handler; - }; - - static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) -@@ -1657,11 +1648,6 @@ static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFBy - return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface); - } - --static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) --{ -- return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface); --} -- - static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj) - { - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); -@@ -1691,247 +1677,44 @@ static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *if - - static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface) - { -- struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); -- ULONG refcount = InterlockedDecrement(&handler->refcount); -- struct winegstreamer_stream_handler_result *result, *next; -- -- TRACE("%p, refcount %u.\n", iface, refcount); -- -- if (!refcount) -- { -- LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry) -- { -- list_remove(&result->entry); -- IMFAsyncResult_Release(result->result); -- if (result->object) -- IUnknown_Release(result->object); -- heap_free(result); -- } -- DeleteCriticalSection(&handler->cs); -- heap_free(handler); -- } -- -- return refcount; --} -- --struct create_object_context --{ -- IUnknown IUnknown_iface; -- LONG refcount; -- -- IPropertyStore *props; -- IMFByteStream *stream; -- WCHAR *url; -- DWORD flags; --}; -- --static struct create_object_context *impl_from_IUnknown(IUnknown *iface) --{ -- return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface); --} -- --static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj) --{ -- TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); -- -- if (IsEqualIID(riid, &IID_IUnknown)) -- { -- *obj = iface; -- IUnknown_AddRef(iface); -- return S_OK; -- } -- -- WARN("Unsupported %s.\n", debugstr_guid(riid)); -- *obj = NULL; -- return E_NOINTERFACE; --} -- --static ULONG WINAPI create_object_context_AddRef(IUnknown *iface) --{ -- struct create_object_context *context = impl_from_IUnknown(iface); -- ULONG refcount = InterlockedIncrement(&context->refcount); -- -- TRACE("%p, refcount %u.\n", iface, refcount); -- -- return refcount; --} -- --static ULONG WINAPI create_object_context_Release(IUnknown *iface) --{ -- struct create_object_context *context = impl_from_IUnknown(iface); -- ULONG refcount = InterlockedDecrement(&context->refcount); -+ struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); -+ ULONG refcount = InterlockedDecrement(&this->refcount); - - TRACE("%p, refcount %u.\n", iface, refcount); - - if (!refcount) - { -- if (context->props) -- IPropertyStore_Release(context->props); -- if (context->stream) -- IMFByteStream_Release(context->stream); -- heap_free(context->url); -- heap_free(context); -+ handler_destruct(&this->handler); -+ heap_free(this); - } - - return refcount; - } - --static const IUnknownVtbl create_object_context_vtbl = --{ -- create_object_context_QueryInterface, -- create_object_context_AddRef, -- create_object_context_Release, --}; -- --static WCHAR *heap_strdupW(const WCHAR *str) --{ -- WCHAR *ret = NULL; -- -- if (str) -- { -- unsigned int size; -- -- size = (lstrlenW(str) + 1) * sizeof(WCHAR); -- ret = heap_alloc(size); -- if (ret) -- memcpy(ret, str, size); -- } -- -- return ret; --} -- - static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags, - IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) - { - struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); -- struct create_object_context *context; -- IMFAsyncResult *caller, *item; -- HRESULT hr; - - TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); -- -- if (cancel_cookie) -- *cancel_cookie = NULL; -- -- if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) -- return hr; -- -- context = heap_alloc(sizeof(*context)); -- if (!context) -- { -- IMFAsyncResult_Release(caller); -- return E_OUTOFMEMORY; -- } -- -- context->IUnknown_iface.lpVtbl = &create_object_context_vtbl; -- context->refcount = 1; -- context->props = props; -- if (context->props) -- IPropertyStore_AddRef(context->props); -- context->flags = flags; -- context->stream = stream; -- if (context->stream) -- IMFByteStream_AddRef(context->stream); -- if (url) -- context->url = heap_strdupW(url); -- if (!context->stream) -- { -- IMFAsyncResult_Release(caller); -- IUnknown_Release(&context->IUnknown_iface); -- return E_OUTOFMEMORY; -- } -- -- hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item); -- IUnknown_Release(&context->IUnknown_iface); -- if (SUCCEEDED(hr)) -- { -- if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) -- { -- if (cancel_cookie) -- { -- *cancel_cookie = (IUnknown *)caller; -- IUnknown_AddRef(*cancel_cookie); -- } -- } -- -- IMFAsyncResult_Release(item); -- } -- IMFAsyncResult_Release(caller); -- -- return hr; -+ return handler_begin_create_object(&this->handler, stream, url, flags, props, cancel_cookie, callback, state); - } - - static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, - MF_OBJECT_TYPE *obj_type, IUnknown **object) - { - struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); -- struct winegstreamer_stream_handler_result *found = NULL, *cur; -- HRESULT hr; - - TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); -- -- EnterCriticalSection(&this->cs); -- -- LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry) -- { -- if (result == cur->result) -- { -- list_remove(&cur->entry); -- found = cur; -- break; -- } -- } -- -- LeaveCriticalSection(&this->cs); -- -- if (found) -- { -- *obj_type = found->obj_type; -- *object = found->object; -- hr = IMFAsyncResult_GetStatus(found->result); -- IMFAsyncResult_Release(found->result); -- heap_free(found); -- } -- else -- { -- *obj_type = MF_OBJECT_INVALID; -- *object = NULL; -- hr = MF_E_UNEXPECTED; -- } -- -- return hr; -+ return handler_end_create_object(&this->handler, result, obj_type, object); - } - - static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) - { - struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); -- struct winegstreamer_stream_handler_result *found = NULL, *cur; - - TRACE("%p, %p.\n", iface, cancel_cookie); -- -- EnterCriticalSection(&this->cs); -- -- LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry) -- { -- if (cancel_cookie == (IUnknown *)cur->result) -- { -- list_remove(&cur->entry); -- found = cur; -- break; -- } -- } -- -- LeaveCriticalSection(&this->cs); -- -- if (found) -- { -- IMFAsyncResult_Release(found->result); -- if (found->object) -- IUnknown_Release(found->object); -- heap_free(found); -- } -- -- return found ? S_OK : MF_E_UNEXPECTED; -+ return handler_cancel_object_creation(&this->handler, cancel_cookie); - } - - static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) -@@ -1951,47 +1734,16 @@ static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl = - winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution, - }; - --static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) --{ -- if (IsEqualIID(riid, &IID_IMFAsyncCallback) || -- IsEqualIID(riid, &IID_IUnknown)) -- { -- *obj = iface; -- IMFAsyncCallback_AddRef(iface); -- return S_OK; -- } -- -- WARN("Unsupported %s.\n", debugstr_guid(riid)); -- *obj = NULL; -- return E_NOINTERFACE; --} -- --static ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface) --{ -- struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); -- return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface); --} -- --static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface) --{ -- struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); -- return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); --} -- --static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) --{ -- return E_NOTIMPL; --} -- --static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags, -+static HRESULT winegstreamer_stream_handler_create_object(struct handler *handler, WCHAR *url, IMFByteStream *stream, DWORD flags, - IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type) - { -- TRACE("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type); -+ TRACE("(%p %s %p %u %p %p %p)\n", handler, debugstr_w(url), stream, flags, props, out_object, out_obj_type); - - if (flags & MF_RESOLUTION_MEDIASOURCE) - { - HRESULT hr; - struct media_source *new_source; -+ struct winegstreamer_stream_handler *This = CONTAINING_RECORD(handler, struct winegstreamer_stream_handler, handler); - - if (FAILED(hr = media_source_constructor(stream, &new_source))) - return hr; -@@ -2010,64 +1762,6 @@ static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_s - } - } - --static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) --{ -- struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); -- struct winegstreamer_stream_handler_result *handler_result; -- MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID; -- IUnknown *object = NULL, *context_object; -- struct create_object_context *context; -- IMFAsyncResult *caller; -- HRESULT hr; -- -- caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); -- -- if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) -- { -- WARN("Expected context set for callee result.\n"); -- return hr; -- } -- -- context = impl_from_IUnknown(context_object); -- -- hr = winegstreamer_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type); -- -- handler_result = heap_alloc(sizeof(*handler_result)); -- if (handler_result) -- { -- handler_result->result = caller; -- IMFAsyncResult_AddRef(handler_result->result); -- handler_result->obj_type = obj_type; -- handler_result->object = object; -- -- EnterCriticalSection(&handler->cs); -- list_add_tail(&handler->results, &handler_result->entry); -- LeaveCriticalSection(&handler->cs); -- } -- else -- { -- if (object) -- IUnknown_Release(object); -- hr = E_OUTOFMEMORY; -- } -- -- IUnknown_Release(&context->IUnknown_iface); -- -- IMFAsyncResult_SetStatus(caller, hr); -- MFInvokeCallback(caller); -- -- return S_OK; --} -- --static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl = --{ -- winegstreamer_stream_handler_callback_QueryInterface, -- winegstreamer_stream_handler_callback_AddRef, -- winegstreamer_stream_handler_callback_Release, -- winegstreamer_stream_handler_callback_GetParameters, -- winegstreamer_stream_handler_callback_Invoke, --}; -- - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) - { - struct winegstreamer_stream_handler *this; -@@ -2079,11 +1773,9 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) - if (!this) - return E_OUTOFMEMORY; - -- list_init(&this->results); -- InitializeCriticalSection(&this->cs); -+ handler_construct(&this->handler, winegstreamer_stream_handler_create_object); - - this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl; -- this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl; - this->refcount = 1; - - hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj); --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0041-winegstreamer-Implement-decoder-MFT-on-gstreamer.patch b/patches/mfplat-streaming-support/0041-winegstreamer-Implement-decoder-MFT-on-gstreamer.patch deleted file mode 100644 index 85ee41f8..00000000 --- a/patches/mfplat-streaming-support/0041-winegstreamer-Implement-decoder-MFT-on-gstreamer.patch +++ /dev/null @@ -1,1649 +0,0 @@ -From 32a148c4f8b2c62c7c227b17e8fba2a7aac8ae62 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 16 Mar 2020 12:09:39 -0500 -Subject: [PATCH] winegstreamer: Implement decoder MFT on gstreamer. - ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/gst_cbs.c | 65 + - dlls/winegstreamer/gst_cbs.h | 23 + - dlls/winegstreamer/gst_private.h | 7 + - dlls/winegstreamer/mf_decode.c | 1320 ++++++++++++++++++ - dlls/winegstreamer/mfplat.c | 63 +- - dlls/winegstreamer/winegstreamer_classes.idl | 12 + - include/mfidl.idl | 2 + - 8 files changed, 1492 insertions(+), 1 deletion(-) - create mode 100644 dlls/winegstreamer/mf_decode.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 4f6b428f067..81c670c17e4 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -15,6 +15,7 @@ C_SRCS = \ - main.c \ - media_source.c \ - mediatype.c \ -+ mf_decode.c \ - mfplat.c \ - pin.c \ - qualitycontrol.c \ -diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c -index 90c34b1cb39..cfa3a0f566d 100644 ---- a/dlls/winegstreamer/gst_cbs.c -+++ b/dlls/winegstreamer/gst_cbs.c -@@ -51,6 +51,8 @@ static void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user) - perform_cb_gstdemux(cbdata); - else if (cbdata->type < MEDIA_SOURCE_MAX) - perform_cb_media_source(cbdata); -+ else if (cbdata->type < MF_DECODE_MAX) -+ perform_cb_mf_decode(cbdata); - - pthread_mutex_lock(&cbdata->lock); - cbdata->finished = 1; -@@ -260,3 +262,66 @@ void mf_src_no_more_pads_wrapper(GstElement *element, gpointer user) - - call_cb(&cbdata); - } -+ -+gboolean activate_push_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) -+{ -+ struct cb_data cbdata = { ACTIVATE_PUSH_MODE }; -+ -+ cbdata.u.activate_mode_data.pad = pad; -+ cbdata.u.activate_mode_data.parent = parent; -+ cbdata.u.activate_mode_data.mode = mode; -+ cbdata.u.activate_mode_data.activate = activate; -+ -+ call_cb(&cbdata); -+ -+ return cbdata.u.query_function_data.ret; -+} -+ -+gboolean query_input_src_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) -+{ -+ struct cb_data cbdata = { QUERY_INPUT_SRC }; -+ -+ cbdata.u.query_function_data.pad = pad; -+ cbdata.u.query_function_data.parent = parent; -+ cbdata.u.query_function_data.query = query; -+ -+ call_cb(&cbdata); -+ -+ return cbdata.u.query_function_data.ret; -+} -+ -+GstBusSyncReply watch_decoder_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) -+{ -+ struct cb_data cbdata = { WATCH_DECODER_BUS }; -+ -+ cbdata.u.watch_bus_data.bus = bus; -+ cbdata.u.watch_bus_data.msg = message; -+ cbdata.u.watch_bus_data.user = user; -+ -+ call_cb(&cbdata); -+ -+ return cbdata.u.watch_bus_data.ret; -+} -+ -+void decoder_pad_added_wrapper(GstElement *element, GstPad *pad, gpointer user) -+{ -+ struct cb_data cbdata = { DECODER_PAD_ADDED }; -+ -+ cbdata.u.pad_added_data.element = element; -+ cbdata.u.pad_added_data.pad = pad; -+ cbdata.u.pad_added_data.user = user; -+ -+ call_cb(&cbdata); -+} -+ -+GstFlowReturn decoder_new_sample_wrapper(GstElement *appsink, gpointer user) -+{ -+ struct cb_data cbdata = {DECODER_NEW_SAMPLE}; -+ -+ cbdata.u.new_sample_data.appsink = appsink; -+ cbdata.u.new_sample_data.user = user; -+ -+ call_cb(&cbdata); -+ -+ return cbdata.u.new_sample_data.ret; -+} -diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h -index cbd9a630885..64b037ffed0 100644 ---- a/dlls/winegstreamer/gst_cbs.h -+++ b/dlls/winegstreamer/gst_cbs.h -@@ -42,6 +42,12 @@ enum CB_TYPE { - MF_SRC_STREAM_REMOVED, - MF_SRC_NO_MORE_PADS, - MEDIA_SOURCE_MAX, -+ ACTIVATE_PUSH_MODE, -+ QUERY_INPUT_SRC, -+ DECODER_NEW_SAMPLE, -+ WATCH_DECODER_BUS, -+ DECODER_PAD_ADDED, -+ MF_DECODE_MAX, - }; - - struct cb_data { -@@ -100,6 +106,17 @@ struct cb_data { - GstQuery *query; - gboolean ret; - } query_sink_data; -+ struct chain_data { -+ GstPad *pad; -+ GstObject *parent; -+ GstBuffer *buffer; -+ GstFlowReturn ret; -+ } chain_data; -+ struct new_sample_data { -+ GstElement *appsink; -+ gpointer user; -+ GstFlowReturn ret; -+ } new_sample_data; - } u; - - int finished; -@@ -111,6 +128,7 @@ struct cb_data { - void mark_wine_thread(void) DECLSPEC_HIDDEN; - void perform_cb_gstdemux(struct cb_data *data) DECLSPEC_HIDDEN; - void perform_cb_media_source(struct cb_data *data) DECLSPEC_HIDDEN; -+void perform_cb_mf_decode(struct cb_data *data) DECLSPEC_HIDDEN; - - void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN; - GstFlowReturn got_data_wrapper(GstPad *pad, GstObject *parent, GstBuffer *buf) DECLSPEC_HIDDEN; -@@ -124,5 +142,10 @@ GstBusSyncReply mf_src_bus_watch_wrapper(GstBus *bus, GstMessage *message, gpoin - void mf_src_stream_added_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN; - void mf_src_stream_removed_wrapper(GstElement *element, GstPad *pad, gpointer user) DECLSPEC_HIDDEN; - void mf_src_no_more_pads_wrapper(GstElement *element, gpointer user) DECLSPEC_HIDDEN; -+gboolean activate_push_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN; -+gboolean query_input_src_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN; -+GstBusSyncReply watch_decoder_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) DECLSPEC_HIDDEN; -+GstFlowReturn decoder_new_sample_wrapper(GstElement *appsink, gpointer user) DECLSPEC_HIDDEN; -+void decoder_pad_added_wrapper(GstElement *element, GstPad *Pad, gpointer user) DECLSPEC_HIDDEN; - - #endif -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 7000cb48a52..8494b34be98 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -77,6 +77,7 @@ BOOL init_gstreamer(void) DECLSPEC_HIDDEN; - - void start_dispatch_thread(void) DECLSPEC_HIDDEN; - -+extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN; - extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN; - extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN; - -@@ -87,6 +88,12 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) DECLSPEC_HIDDEN; - IMFSample *mf_sample_from_gst_buffer(GstBuffer *in) DECLSPEC_HIDDEN; - GstBuffer *gst_buffer_from_mf_sample(IMFSample *in) DECLSPEC_HIDDEN; - -+enum decoder_type -+{ -+ DECODER_TYPE_H264, -+ DECODER_TYPE_AAC, -+}; -+HRESULT generic_decoder_construct(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; - - HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c -new file mode 100644 -index 00000000000..7055ffa54fc ---- /dev/null -+++ b/dlls/winegstreamer/mf_decode.c -@@ -0,0 +1,1320 @@ -+#include "config.h" -+ -+#include -+ -+#include "gst_private.h" -+#include "gst_cbs.h" -+ -+#include -+ -+#define COBJMACROS -+#define NONAMELESSUNION -+ -+#include "mfapi.h" -+#include "mferror.h" -+#include "mfobjects.h" -+#include "mftransform.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -+ -+/* keep in sync with mfplat.c's mft registrations */ -+ -+const GUID *h264_input_types[] = {&MFVideoFormat_H264}; -+/* NV12 comes first https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order. thanks to @vitorhnn */ -+const GUID *h264_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_YUY2, &MFVideoFormat_YV12}; -+ -+const GUID *aac_input_types[] = {&MFAudioFormat_AAC}; -+const GUID *aac_output_types[] = {&MFAudioFormat_Float}; -+ -+static struct decoder_desc -+{ -+ const GUID *major_type; -+ const GUID **input_types; -+ unsigned int input_types_count; -+ const GUID **output_types; -+ unsigned int output_types_count; -+} decoder_descs[] = -+{ -+ { /* DECODER_TYPE_H264 */ -+ &MFMediaType_Video, -+ h264_input_types, -+ ARRAY_SIZE(h264_input_types), -+ h264_output_types, -+ ARRAY_SIZE(h264_output_types), -+ }, -+ { /* DECODER_TYPE_AAC */ -+ &MFMediaType_Audio, -+ aac_input_types, -+ ARRAY_SIZE(aac_input_types), -+ aac_output_types, -+ ARRAY_SIZE(aac_output_types), -+ } -+}; -+ -+struct mf_decoder -+{ -+ IMFTransform IMFTransform_iface; -+ IMFAsyncCallback process_message_callback; -+ LONG refcount; -+ enum decoder_type type; -+ BOOL video; -+ IMFMediaType *input_type, *output_type; -+ BOOL valid_state; -+ GstBus *bus; -+ GstElement *container; -+ GstElement *parser, *decoder, *post_process_start, *videobox, *appsink; -+ GstPad *input_src, *their_sink; -+ unsigned int output_counter; -+ BOOL flushing, draining; -+ CRITICAL_SECTION state_cs; -+ CONDITION_VARIABLE state_cv; -+ DWORD message_queue; -+}; -+ -+static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) -+{ -+ return CONTAINING_RECORD(iface, struct mf_decoder, IMFTransform_iface); -+} -+ -+static struct mf_decoder *impl_from_message_callback_IMFAsyncCallback(IMFAsyncCallback *iface) -+{ -+ return CONTAINING_RECORD(iface, struct mf_decoder, process_message_callback); -+} -+ -+static HRESULT WINAPI mf_decoder_QueryInterface (IMFTransform *iface, REFIID riid, void **out) -+{ -+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); -+ -+ if (IsEqualIID(riid, &IID_IMFTransform) || -+ IsEqualIID(riid, &IID_IUnknown)) -+ { -+ *out = iface; -+ IMFTransform_AddRef(iface); -+ return S_OK; -+ } -+ -+ WARN("Unsupported %s.\n", debugstr_guid(riid)); -+ *out = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI mf_decoder_AddRef(IMFTransform *iface) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ ULONG refcount = InterlockedIncrement(&decoder->refcount); -+ -+ TRACE("%p, refcount %u.\n", iface, refcount); -+ -+ return refcount; -+} -+ -+static void mf_decoder_destroy(struct mf_decoder *decoder); -+static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ ULONG refcount = InterlockedDecrement(&decoder->refcount); -+ -+ TRACE("%p, refcount %u.\n", iface, refcount); -+ -+ if (!refcount) -+ { -+ mf_decoder_destroy(decoder); -+ } -+ -+ return refcount; -+} -+ -+static HRESULT WINAPI mf_decoder_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 = *input_maximum = *output_minimum = *output_maximum = 1; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI mf_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -+{ -+ TRACE("%p %p %p.\n", iface, inputs, outputs); -+ -+ *inputs = *outputs = 1; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI mf_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, -+ DWORD output_size, DWORD *outputs) -+{ -+ TRACE("%p %u %p %u %p.\n", iface, input_size, inputs, output_size, outputs); -+ -+ return E_NOTIMPL; -+} -+ -+ -+static HRESULT WINAPI mf_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ -+ TRACE("%p %u %p\n", decoder, id, info); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ /* If we create a wrapped GstBuffer, remove MFT_INPUT_STREAM_DOES_NOT_ADDREF */ -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF; -+ info->cbMaxLookahead = 0; -+ info->cbAlignment = 0; -+ /* this is incorrect */ -+ info->hnsMaxLatency = 0; -+ return S_OK; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ MFT_OUTPUT_STREAM_INFO stream_info = {}; -+ -+ TRACE("%p %u %p\n", decoder, id, info); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ stream_info.dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; -+ stream_info.cbSize = 0; -+ stream_info.cbAlignment = 0; -+ -+ *info = stream_info; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -+{ -+ FIXME("%p, %p. semi-stub!\n", iface, attributes); -+ -+ return MFCreateAttributes(attributes, 0); -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("%p, %u, %p. stub!\n", iface, id, attributes); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("%p, %u, %p. stub!\n", iface, id, attributes); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) -+{ -+ FIXME("%p, %u. stub!\n", iface, id); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -+{ -+ FIXME("%p, %u, %p. stub!\n", iface, streams, ids); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ IMFMediaType *input_type; -+ HRESULT hr; -+ -+ TRACE("%p, %u, %u, %p\n", decoder, id, index, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (index >= decoder_descs[decoder->type].input_types_count) -+ return MF_E_NO_MORE_TYPES; -+ -+ if (FAILED(hr = MFCreateMediaType(&input_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(input_type, &MF_MT_MAJOR_TYPE, decoder_descs[decoder->type].major_type))) -+ { -+ IMFMediaType_Release(input_type); -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(input_type, &MF_MT_SUBTYPE, decoder_descs[decoder->type].input_types[index]))) -+ { -+ IMFMediaType_Release(input_type); -+ return hr; -+ } -+ -+ *type = input_type; -+ -+ return S_OK; -+} -+ -+static void copy_attr(IMFMediaType *target, IMFMediaType *source, const GUID *key) -+{ -+ PROPVARIANT val; -+ -+ if (SUCCEEDED(IMFAttributes_GetItem((IMFAttributes *)source, key, &val))) -+ { -+ IMFAttributes_SetItem((IMFAttributes* )target, key, &val); -+ } -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ IMFMediaType *output_type; -+ HRESULT hr; -+ -+ TRACE("%p, %u, %u, %p\n", decoder, id, index, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (!(decoder->input_type)) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (index >= decoder_descs[decoder->type].output_types_count) -+ return MF_E_NO_MORE_TYPES; -+ -+ if (FAILED(hr = MFCreateMediaType(&output_type))) -+ return hr; -+ -+ copy_attr(output_type, decoder->input_type, &MF_MT_FRAME_SIZE); -+ copy_attr(output_type, decoder->input_type, &MF_MT_FRAME_RATE); -+ copy_attr(output_type, decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS); -+ copy_attr(output_type, decoder->input_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND); -+ -+ IMFMediaType_SetUINT32(output_type, &MF_MT_COMPRESSED, FALSE); -+ IMFMediaType_SetUINT32(output_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_MAJOR_TYPE, decoder_descs[decoder->type].major_type))) -+ { -+ IMFMediaType_Release(output_type); -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_SUBTYPE, decoder_descs[decoder->type].output_types[index]))) -+ { -+ IMFMediaType_Release(output_type); -+ return hr; -+ } -+ -+ *type = output_type; -+ -+ return S_OK; -+} -+ -+static gboolean activate_push_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) -+{ -+ TRACE("%s mft input pad in %s mode.\n", -+ activate ? "Activating" : "Deactivating", gst_pad_mode_get_name(mode)); -+ -+ switch (mode) { -+ case GST_PAD_MODE_PUSH: -+ return TRUE; -+ default: -+ return FALSE; -+ } -+} -+ -+static gboolean query_input_src(GstPad *pad, GstObject *parent, GstQuery *query) -+{ -+ struct mf_decoder *decoder = gst_pad_get_element_private(pad); -+ -+ TRACE("GStreamer queries MFT Input Pad %p for %s\n", decoder, GST_QUERY_TYPE_NAME(query)); -+ -+ switch (GST_QUERY_TYPE(query)) -+ { -+ case GST_QUERY_CAPS: -+ { -+ gst_query_set_caps_result(query, caps_from_mf_media_type(decoder->input_type)); -+ return TRUE; -+ } -+ case GST_QUERY_SCHEDULING: -+ { -+ gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); -+ return TRUE; -+ } -+ case GST_QUERY_SEEKING: -+ { -+ GstFormat format; -+ gboolean seekable; -+ gint64 segment_start, segment_end; -+ -+ gst_query_parse_seeking(query, &format, &seekable, &segment_start, &segment_end); -+ gst_query_set_seeking(query, format, 0, segment_start, segment_end); -+ return TRUE; -+ } -+ case GST_QUERY_DURATION: -+ { -+ return FALSE; -+ } -+ case GST_QUERY_LATENCY: -+ { -+ return FALSE; -+ } -+ default: -+ { -+ ERR("Unhandled query type %s on MFT Input Pad %p\n", GST_QUERY_TYPE_NAME(query), decoder); -+ return gst_pad_query_default (pad, parent, query); -+ } -+ } -+} -+ -+static GstFlowReturn decoder_new_sample(GstElement *appsink, gpointer user) -+{ -+ struct mf_decoder *decoder = (struct mf_decoder *) user; -+ -+ TRACE("new sample decoder=%p appsink=%p\n", decoder, appsink); -+ -+ if (decoder->flushing) -+ { -+ GstSample *sample; -+ g_signal_emit_by_name(decoder->appsink, "pull-sample", &sample); -+ gst_sample_unref(sample); -+ return GST_FLOW_OK; -+ } -+ -+ decoder->output_counter++; -+ -+ return GST_FLOW_OK; -+} -+ -+static BOOL find_decoder_from_caps(GstCaps *input_caps, GstElement **decoder, GstElement **parser) -+{ -+ GList *decoder_list_one, *decoder_list_two; -+ GList *parser_list_one, *parser_list_two; -+ GList *walk; -+ BOOL ret = TRUE; -+ -+ TRACE("input caps: %s\n", gst_caps_to_string(input_caps)); -+ -+ decoder_list_one = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER, 1); -+ decoder_list_two = gst_element_factory_list_filter(decoder_list_one, input_caps, GST_PAD_SINK, 0); -+ gst_plugin_feature_list_free(decoder_list_one); -+ decoder_list_one = decoder_list_two; -+ if (g_list_length(decoder_list_one) && -+ (*decoder = gst_element_factory_create(g_list_first(decoder_list_one)->data, NULL))) -+ { -+ TRACE("Found decoder %s\n", GST_ELEMENT_NAME(g_list_first(decoder_list_one)->data)); -+ gst_plugin_feature_list_free(decoder_list_one); -+ return TRUE; -+ } -+ gst_plugin_feature_list_free(decoder_list_one); -+ -+ parser_list_one = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_PARSER, 1); -+ parser_list_two = gst_element_factory_list_filter(parser_list_one, input_caps, GST_PAD_SINK, 0); -+ gst_plugin_feature_list_free(parser_list_one); -+ parser_list_one = parser_list_two; -+ -+ for (walk = (GList *) parser_list_one; walk; walk = g_list_next(walk)) -+ { -+ GstElementFactory *parser_factory = walk->data; -+ const GList *templates, *walk_templ; -+ -+ templates = gst_element_factory_get_static_pad_templates(parser_factory); -+ -+ for (walk_templ = (GList *)templates; walk_templ; walk_templ = g_list_next(walk_templ)) -+ { -+ GstStaticPadTemplate *templ = walk_templ->data; -+ GstCaps *templ_caps; -+ -+ if (templ->direction != GST_PAD_SRC) -+ continue; -+ -+ templ_caps = gst_static_pad_template_get_caps(templ); -+ -+ TRACE("Matching parser src caps %s to decoder.\n", gst_caps_to_string(templ_caps)); -+ -+ decoder_list_one = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER, 1); -+ decoder_list_two = gst_element_factory_list_filter(decoder_list_one, templ_caps, GST_PAD_SINK, 0); -+ gst_plugin_feature_list_free(decoder_list_one); -+ decoder_list_one = decoder_list_two; -+ gst_caps_unref(templ_caps); -+ -+ if (!(g_list_length(decoder_list_one))) -+ continue; -+ -+ if (!(*parser = gst_element_factory_create(parser_factory, NULL))) -+ { -+ gst_plugin_feature_list_free(decoder_list_one); -+ ERR("Failed to create parser\n"); -+ ret = FALSE; -+ goto done; -+ } -+ -+ if (!(*decoder = gst_element_factory_create(g_list_first(decoder_list_one)->data, NULL))) -+ { -+ gst_plugin_feature_list_free(decoder_list_one); -+ ERR("Failed to create decoder\n"); -+ ret = FALSE; -+ goto done; -+ } -+ -+ TRACE("Found decoder %s parser %s\n", -+ GST_ELEMENT_NAME(g_list_first(decoder_list_one)->data), GST_ELEMENT_NAME(parser_factory)); -+ gst_plugin_feature_list_free(decoder_list_one); -+ -+ goto done; -+ } -+ } -+ -+ done: -+ gst_plugin_feature_list_free(parser_list_one); -+ return ret; -+} -+ -+static void decoder_update_pipeline(struct mf_decoder *decoder) -+{ -+ GstCaps *input_caps = NULL; -+ RECT target_size = {0}; -+ MFVideoArea *aperture; -+ UINT32 aperture_size; -+ GstSegment *segment; -+ -+ decoder->valid_state = FALSE; -+ -+ /* tear down current pipeline */ -+ gst_element_set_state(decoder->container, GST_STATE_READY); -+ if (gst_element_get_state(decoder->container, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE) -+ { -+ ERR("Failed to stop container\n"); -+ } -+ -+ g_object_set(decoder->appsink, "caps", gst_caps_new_empty(), NULL); -+ -+ if (decoder->input_src) -+ { -+ gst_pad_unlink(decoder->input_src, decoder->their_sink); -+ gst_object_unref(G_OBJECT(decoder->input_src)); -+ decoder->input_src = NULL; -+ } -+ -+ if (decoder->their_sink) -+ { -+ gst_object_unref(G_OBJECT(decoder->their_sink)); -+ decoder->their_sink = NULL; -+ } -+ -+ if (decoder->parser) -+ { -+ gst_element_unlink(decoder->parser, decoder->decoder); -+ gst_bin_remove(GST_BIN(decoder->container), decoder->parser); -+ decoder->parser = NULL; -+ } -+ if (decoder->decoder) -+ { -+ gst_element_unlink(decoder->decoder, decoder->post_process_start); -+ gst_bin_remove(GST_BIN(decoder->container), decoder->decoder); -+ decoder->decoder = NULL; -+ } -+ -+ /* we can only have a valid state if an input and output type is present */ -+ if (!decoder->input_type || !decoder->output_type) -+ return; -+ -+ /* We do leave a lot of unfreed objects here when we failure, -+ but it will be cleaned up on the next call */ -+ -+ input_caps = caps_from_mf_media_type(decoder->input_type); -+ -+ if (!(decoder->input_src = gst_pad_new_from_template(gst_pad_template_new( -+ "mf_src", -+ GST_PAD_SRC, -+ GST_PAD_ALWAYS, -+ input_caps -+ ), "input_src"))) -+ { -+ ERR("Failed to create input source\n"); -+ goto done; -+ } -+ -+ gst_pad_set_activatemode_function(decoder->input_src, activate_push_mode_wrapper); -+ gst_pad_set_query_function(decoder->input_src, query_input_src_wrapper); -+ gst_pad_set_element_private(decoder->input_src, decoder); -+ -+ if (!(find_decoder_from_caps(input_caps, &decoder->decoder, &decoder->parser))) -+ { -+ goto done; -+ } -+ -+ gst_bin_add(GST_BIN(decoder->container), decoder->decoder); -+ if (decoder->parser) -+ { -+ gst_bin_add(GST_BIN(decoder->container), decoder->parser); -+ } -+ -+ if (!(decoder->their_sink = gst_element_get_static_pad(decoder->parser ? decoder->parser : decoder->decoder, "sink"))) -+ { -+ goto done; -+ } -+ -+ if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(decoder->output_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8 **) &aperture, &aperture_size))) -+ { -+ UINT64 frame_size; -+ -+ TRACE("x: %u %u/65536, y: %u %u/65536, area: %u x %u\n", aperture->OffsetX.value, aperture->OffsetX.fract, -+ aperture->OffsetY.value, aperture->OffsetY.fract, aperture->Area.cx, aperture->Area.cy); -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size))) -+ { -+ DWORD width = frame_size >> 32; -+ DWORD height = frame_size; -+ -+ target_size.left = -aperture->OffsetX.value; -+ target_size.top = -aperture->OffsetY.value; -+ target_size.right = aperture->Area.cx - width; -+ target_size.bottom = aperture->Area.cy - height; -+ } -+ else -+ ERR("missing frame size\n"); -+ -+ CoTaskMemFree(aperture); -+ } -+ -+ if (decoder->videobox) -+ { -+ g_object_set(decoder->videobox, "top", target_size.top, NULL); -+ g_object_set(decoder->videobox, "bottom", target_size.bottom, NULL); -+ g_object_set(decoder->videobox, "left", target_size.left, NULL); -+ g_object_set(decoder->videobox, "right", target_size.right, NULL); -+ } -+ -+ g_object_set(decoder->appsink, "caps", caps_from_mf_media_type(decoder->output_type), NULL); -+ -+ if (gst_pad_link(decoder->input_src, decoder->their_sink) != GST_PAD_LINK_OK) -+ { -+ ERR("Failed to link input source to decoder sink\n"); -+ return; -+ } -+ -+ if (decoder->parser && !(gst_element_link(decoder->parser, decoder->decoder))) -+ { -+ ERR("Failed to link parser to decoder\n"); -+ goto done; -+ } -+ -+ if (!(gst_element_link(decoder->decoder, decoder->post_process_start))) -+ { -+ ERR("Failed to link decoder to first element in post processing chain\n"); -+ goto done; -+ } -+ -+ gst_element_set_state(decoder->container, GST_STATE_PLAYING); -+ -+ gst_pad_set_active(decoder->input_src, 1); -+ gst_pad_push_event(decoder->input_src, gst_event_new_stream_start("decoder-stream")); -+ gst_pad_push_event(decoder->input_src, gst_event_new_caps(caps_from_mf_media_type(decoder->input_type))); -+ segment = gst_segment_new(); -+ gst_segment_init(segment, GST_FORMAT_TIME); -+ gst_pad_push_event(decoder->input_src, gst_event_new_segment(segment)); -+ -+ gst_element_get_state(decoder->container, NULL, NULL, -1); -+ -+ decoder->valid_state = TRUE; -+ done: -+ if (input_caps) -+ gst_caps_unref(input_caps); -+ return; -+} -+ -+static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ HRESULT hr = S_OK; -+ -+ TRACE("%p, %u, %p, %#x\n", decoder, id, type, flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (type) -+ { -+ GUID major_type, subtype; -+ UINT64 unused; -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) -+ return hr; -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (!(IsEqualGUID(&major_type, decoder_descs[decoder->type].major_type))) -+ return MF_E_INVALIDTYPE; -+ -+ if (decoder->video) -+ { -+ if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &unused))) -+ return hr; -+ } -+ -+ for (unsigned int i = 0; i < decoder_descs[decoder->type].input_types_count; i++) -+ { -+ if (IsEqualGUID(&subtype, decoder_descs[decoder->type].input_types[i])) -+ break; -+ if (i == decoder_descs[decoder->type].input_types_count) -+ return MF_E_INVALIDTYPE; -+ } -+ } -+ -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ { -+ return S_OK; -+ } -+ -+ EnterCriticalSection(&decoder->state_cs); -+ -+ if (type) -+ { -+ if (!decoder->input_type) -+ if (FAILED(hr = MFCreateMediaType(&decoder->input_type))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes*) decoder->input_type))) -+ goto done; -+ } -+ else if (decoder->input_type) -+ { -+ IMFMediaType_Release(decoder->input_type); -+ decoder->input_type = NULL; -+ } -+ -+ decoder_update_pipeline(decoder); -+ -+ done: -+ LeaveCriticalSection(&decoder->state_cs); -+ WakeAllConditionVariable(&decoder->state_cv); -+ return hr; -+} -+ -+static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ HRESULT hr = S_OK; -+ -+ TRACE("%p, %u, %p, %#x\n", decoder, id, type, flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (type) -+ { -+ GUID major_type, subtype; -+ UINT64 unused; -+ -+ /* validate the type */ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) -+ return MF_E_INVALIDTYPE; -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return MF_E_INVALIDTYPE; -+ -+ if (!(IsEqualGUID(&major_type, decoder_descs[decoder->type].major_type))) -+ return MF_E_INVALIDTYPE; -+ -+ if (decoder->video) -+ { -+ if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &unused))) -+ return MF_E_INVALIDTYPE; -+ } -+ -+ for (unsigned int i = 0; i < decoder_descs[decoder->type].output_types_count; i++) -+ { -+ if (IsEqualGUID(&subtype, decoder_descs[decoder->type].output_types[i])) -+ break; -+ if (i == decoder_descs[decoder->type].output_types_count) -+ return MF_E_INVALIDTYPE; -+ } -+ } -+ -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ { -+ return S_OK; -+ } -+ -+ EnterCriticalSection(&decoder->state_cs); -+ if (type) -+ { -+ if (!decoder->output_type) -+ if (FAILED(hr = MFCreateMediaType(&decoder->output_type))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes*) decoder->output_type))) -+ goto done; -+ } -+ else if (decoder->output_type) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ -+ decoder_update_pipeline(decoder); -+ -+ done: -+ LeaveCriticalSection(&decoder->state_cs); -+ WakeAllConditionVariable(&decoder->state_cv); -+ return hr; -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("%p, %u, %p. stub!\n", iface, id, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("%p, %u, %p. stub!\n", iface, id, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ -+ TRACE("%p, %u, %p\n", decoder, id, flags); -+ -+ *flags = decoder->output_counter ? MFT_INPUT_STATUS_ACCEPT_DATA : 0; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ -+ TRACE("%p, %p.\n", decoder, flags); -+ -+ *flags = decoder->output_counter ? MFT_OUTPUT_STATUS_SAMPLE_READY : 0; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI mf_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -+{ -+ FIXME("%p, %s, %s. stub!\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -+{ -+ FIXME("%p, %u, %p. stub!\n", iface, id, event); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI decoder_process_message_callback_QueryInterface(IMFAsyncCallback *iface, -+ REFIID riid, void **obj) -+{ -+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); -+ -+ if (IsEqualIID(riid, &IID_IMFAsyncCallback) || -+ IsEqualIID(riid, &IID_IUnknown)) -+ { -+ *obj = iface; -+ IMFAsyncCallback_AddRef(iface); -+ return S_OK; -+ } -+ -+ WARN("Unsupported %s.\n", debugstr_guid(riid)); -+ *obj = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI decoder_process_message_callback_AddRef(IMFAsyncCallback *iface) -+{ -+ struct mf_decoder *decoder = impl_from_message_callback_IMFAsyncCallback(iface); -+ return IMFTransform_AddRef(&decoder->IMFTransform_iface); -+} -+ -+static ULONG WINAPI decoder_process_message_callback_Release(IMFAsyncCallback *iface) -+{ -+ struct mf_decoder *decoder = impl_from_message_callback_IMFAsyncCallback(iface); -+ return IMFTransform_Release(&decoder->IMFTransform_iface); -+} -+ -+static HRESULT WINAPI decoder_process_message_callback_GetParameters(IMFAsyncCallback *iface, -+ DWORD *flags, DWORD *queue) -+{ -+ return E_NOTIMPL; -+} -+ -+const GUID WINE_MFT_MESSAGE_TYPE = {0xd09998bf, 0x102f, 0x4efa, {0x8f,0x84,0x06,0x1f,0xa4,0x10,0xf2,0x64}}; -+ -+static HRESULT WINAPI decoder_process_message_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -+{ -+ struct mf_decoder *decoder = impl_from_message_callback_IMFAsyncCallback(iface); -+ IUnknown *state; -+ IMFAttributes *async_param; -+ MFT_MESSAGE_TYPE message_type; -+ HRESULT hr; -+ -+ state = IMFAsyncResult_GetStateNoAddRef(result); -+ if (!state) -+ return E_FAIL; -+ if (FAILED(hr = IUnknown_QueryInterface(state, &IID_IMFAttributes, (void **)&async_param))) -+ return hr; -+ if (FAILED(hr = IMFAttributes_GetUINT32(async_param, &WINE_MFT_MESSAGE_TYPE, &message_type))) -+ { -+ IMFAttributes_Release(async_param); -+ return hr; -+ } -+ IMFAttributes_Release(async_param); -+ -+ switch (message_type) -+ { -+ case MFT_MESSAGE_COMMAND_DRAIN: -+ { -+ GstSegment *segment = gst_segment_new(); -+ gst_segment_init(segment, GST_FORMAT_TIME); -+ -+ EnterCriticalSection(&decoder->state_cs); -+ decoder->draining = TRUE; -+ WakeAllConditionVariable(&decoder->state_cv); -+ LeaveCriticalSection(&decoder->state_cs); -+ gst_pad_push_event(decoder->input_src, gst_event_new_eos()); -+ -+ EnterCriticalSection(&decoder->state_cs); -+ while(decoder->draining) -+ SleepConditionVariableCS(&decoder->state_cv, &decoder->state_cs, INFINITE); -+ gst_pad_push_event(decoder->input_src, gst_event_new_flush_stop(0)); -+ gst_pad_push_event(decoder->input_src, gst_event_new_segment(segment)); -+ LeaveCriticalSection(&decoder->state_cs); -+ return S_OK; -+ } -+ default: -+ return E_FAIL; -+ } -+} -+ -+static const IMFAsyncCallbackVtbl process_message_callback_vtbl = -+{ -+ decoder_process_message_callback_QueryInterface, -+ decoder_process_message_callback_AddRef, -+ decoder_process_message_callback_Release, -+ decoder_process_message_callback_GetParameters, -+ decoder_process_message_callback_Invoke, -+}; -+ -+static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ IMFAttributes *async_param; -+ HRESULT hr; -+ -+ TRACE("%p, %x %lu.\n", decoder, message, param); -+ -+ if (FAILED(hr = MFCreateAttributes(&async_param, 1))) -+ return hr; -+ -+ switch (message) -+ { -+ case MFT_MESSAGE_COMMAND_FLUSH: -+ { -+ GstSegment *segment = gst_segment_new(); -+ gst_segment_init(segment, GST_FORMAT_TIME); -+ -+ EnterCriticalSection(&decoder->state_cs); -+ decoder->flushing = TRUE; -+ -+ while (decoder->output_counter) -+ { -+ GstSample *sample; -+ g_signal_emit_by_name(decoder->appsink, "pull-sample", &sample); -+ gst_sample_unref(sample); -+ decoder->output_counter--; -+ } -+ -+ gst_pad_push_event(decoder->input_src, gst_event_new_flush_start()); -+ gst_pad_push_event(decoder->input_src, gst_event_new_flush_stop(0)); -+ gst_pad_push_event(decoder->input_src, gst_event_new_segment(segment)); -+ gst_element_set_state(decoder->container, GST_STATE_PLAYING); -+ -+ decoder->flushing = FALSE; -+ decoder->draining = FALSE; -+ LeaveCriticalSection(&decoder->state_cs); -+ -+ hr = S_OK; -+ break; -+ } -+ case MFT_MESSAGE_COMMAND_DRAIN: -+ { -+ if (decoder->draining) -+ { -+ hr = S_OK; -+ break; -+ } -+ -+ IMFAttributes_SetUINT32(async_param, &WINE_MFT_MESSAGE_TYPE, message); -+ -+ EnterCriticalSection(&decoder->state_cs); -+ MFPutWorkItem(decoder->message_queue, &decoder->process_message_callback, (IUnknown *)async_param); -+ while (!decoder->draining) -+ SleepConditionVariableCS(&decoder->state_cv, &decoder->state_cs, INFINITE); -+ LeaveCriticalSection(&decoder->state_cs); -+ -+ hr = S_OK; -+ break; -+ } -+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: -+ { -+ hr = S_OK; -+ break; -+ } -+ default: -+ { -+ WARN("Unhandled message type %x.\n", message); -+ hr = E_FAIL; -+ break; -+ } -+ } -+ -+ IMFAttributes_Release(async_param); -+ return hr; -+} -+ -+static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ GstBuffer *gst_buffer; -+ GstFlowReturn ret; -+ HRESULT hr = S_OK; -+ GstQuery *drain; -+ -+ TRACE("%p, %u, %p, %#x\n", decoder, id, sample, flags); -+ -+ if (flags) -+ WARN("Unsupported flags %#x\n", flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (!decoder->valid_state) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ EnterCriticalSection(&decoder->state_cs); -+ -+ drain = gst_query_new_drain(); -+ gst_pad_peer_query(decoder->input_src, drain); -+ -+ if (decoder->output_counter || decoder->draining) -+ { -+ hr = MF_E_NOTACCEPTING; -+ goto done; -+ } -+ -+ if (!(gst_buffer = gst_buffer_from_mf_sample(sample))) -+ { -+ hr = E_FAIL; -+ goto done; -+ } -+ -+ ret = gst_pad_push(decoder->input_src, gst_buffer); -+ if (ret != GST_FLOW_OK) -+ { -+ ERR("Couldn't process input ret = %d\n", ret); -+ hr = E_FAIL; -+ goto done; -+ } -+ -+ done: -+ LeaveCriticalSection(&decoder->state_cs); -+ return hr; -+} -+ -+static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ MFT_OUTPUT_DATA_BUFFER *relevant_buffer = NULL; -+ GstSample *buffer; -+ -+ TRACE("%p, %#x, %u, %p, %p,\n", iface, flags, count, samples, status); -+ -+ if (flags) -+ WARN("Unsupported flags %#x\n", flags); -+ -+ if (!decoder->valid_state) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ for (unsigned int i = 0; i < count; i++) -+ { -+ MFT_OUTPUT_DATA_BUFFER *out_buffer = &samples[i]; -+ -+ if (out_buffer->dwStreamID != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (relevant_buffer) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ relevant_buffer = out_buffer; -+ } -+ -+ if (!relevant_buffer) -+ return S_OK; -+ -+ EnterCriticalSection(&decoder->state_cs); -+ -+ if (!decoder->output_counter && !decoder->draining) -+ { -+ LeaveCriticalSection(&decoder->state_cs); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ TRACE("%u\n", decoder->output_counter); -+ -+ g_signal_emit_by_name(decoder->appsink, "pull-sample", &buffer); -+ if (decoder->draining && !buffer) -+ { -+ decoder->output_counter = 0; -+ decoder->draining = FALSE; -+ LeaveCriticalSection(&decoder->state_cs); -+ WakeAllConditionVariable(&decoder->state_cv); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ decoder->output_counter--; -+ -+ LeaveCriticalSection(&decoder->state_cs); -+ -+ relevant_buffer->pSample = mf_sample_from_gst_buffer(gst_sample_get_buffer(buffer)); -+ gst_sample_unref(buffer); -+ relevant_buffer->dwStatus = S_OK; -+ relevant_buffer->pEvents = NULL; -+ *status = 0; -+ return S_OK; -+} -+ -+static const IMFTransformVtbl mf_decoder_vtbl = -+{ -+ mf_decoder_QueryInterface, -+ mf_decoder_AddRef, -+ mf_decoder_Release, -+ mf_decoder_GetStreamLimits, -+ mf_decoder_GetStreamCount, -+ mf_decoder_GetStreamIDs, -+ mf_decoder_GetInputStreamInfo, -+ mf_decoder_GetOutputStreamInfo, -+ mf_decoder_GetAttributes, -+ mf_decoder_GetInputStreamAttributes, -+ mf_decoder_GetOutputStreamAttributes, -+ mf_decoder_DeleteInputStream, -+ mf_decoder_AddInputStreams, -+ mf_decoder_GetInputAvailableType, -+ mf_decoder_GetOutputAvailableType, -+ mf_decoder_SetInputType, -+ mf_decoder_SetOutputType, -+ mf_decoder_GetInputCurrentType, -+ mf_decoder_GetOutputCurrentType, -+ mf_decoder_GetInputStatus, -+ mf_decoder_GetOutputStatus, -+ mf_decoder_SetOutputBounds, -+ mf_decoder_ProcessEvent, -+ mf_decoder_ProcessMessage, -+ mf_decoder_ProcessInput, -+ mf_decoder_ProcessOutput, -+}; -+ -+GstBusSyncReply watch_decoder_bus(GstBus *bus, GstMessage *message, gpointer user_data) -+{ -+ struct mf_decoder *decoder = user_data; -+ GError *err = NULL; -+ gchar *dbg_info = NULL; -+ -+ TRACE("decoder %p message type %s\n", decoder, GST_MESSAGE_TYPE_NAME(message)); -+ -+ switch (message->type) -+ { -+ case GST_MESSAGE_ERROR: -+ gst_message_parse_error(message, &err, &dbg_info); -+ ERR("%s: %s\n", GST_OBJECT_NAME(message->src), err->message); -+ ERR("%s\n", dbg_info); -+ g_error_free(err); -+ g_free(dbg_info); -+ break; -+ case GST_MESSAGE_WARNING: -+ gst_message_parse_warning(message, &err, &dbg_info); -+ WARN("%s: %s\n", GST_OBJECT_NAME(message->src), err->message); -+ WARN("%s\n", dbg_info); -+ g_error_free(err); -+ g_free(dbg_info); -+ break; -+ case GST_MESSAGE_EOS: -+ break; -+ default: -+ break; -+ } -+ -+ return GST_BUS_DROP; -+} -+ -+static void mf_decoder_destroy(struct mf_decoder *decoder) -+{ -+ if (decoder->input_type) -+ { -+ IMFMediaType_Release(decoder->input_type); -+ decoder->input_type = NULL; -+ } -+ -+ if (decoder->output_type) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ -+ decoder_update_pipeline(decoder); -+ -+ if (decoder->their_sink) -+ gst_object_unref(G_OBJECT(decoder->their_sink)); -+ -+ if (decoder->container) -+ gst_object_unref(G_OBJECT(decoder->container)); -+ -+ if (decoder->bus) -+ gst_object_unref(G_OBJECT(decoder->bus)); -+ -+ DeleteCriticalSection(&decoder->state_cs); -+ -+ MFUnlockWorkQueue(decoder->message_queue); -+ -+ heap_free(decoder); -+} -+ -+HRESULT generic_decoder_construct(REFIID riid, void **obj, enum decoder_type type) -+{ -+ struct mf_decoder *object; -+ GstElement *converter; -+ HRESULT hr = S_OK; -+ -+ TRACE("%s, %p %u.\n", debugstr_guid(riid), obj, type); -+ -+ if (!(object = heap_alloc_zero(sizeof(*object)))) -+ return E_OUTOFMEMORY; -+ object->type = type; -+ object->video = decoder_descs[type].major_type == &MFMediaType_Video; -+ MFAllocateWorkQueue(&object->message_queue); -+ -+ InitializeCriticalSection(&object->state_cs); -+ InitializeConditionVariable(&object->state_cv); -+ -+ object->container = gst_bin_new(NULL); -+ object->bus = gst_bus_new(); -+ gst_bus_set_sync_handler(object->bus, watch_decoder_bus_wrapper, object, NULL); -+ gst_element_set_bus(object->container, object->bus); -+ -+ if (object->video) -+ { -+ if (!(object->videobox = gst_element_factory_make("videobox", NULL))) -+ { -+ ERR("Failed to create videobox\n"); -+ hr = E_FAIL; -+ goto fail; -+ } -+ gst_bin_add(GST_BIN(object->container), object->videobox); -+ } -+ -+ if (!(converter = gst_element_factory_make(object->video ? "videoconvert" : "audioconvert", NULL))) -+ { -+ ERR("Failed to create converter\n"); -+ hr = E_FAIL; -+ goto fail; -+ } -+ gst_bin_add(GST_BIN(object->container), converter); -+ -+ if (!(object->appsink = gst_element_factory_make("appsink", NULL))) -+ { -+ ERR("Failed to create appsink\n"); -+ hr = E_FAIL; -+ goto fail; -+ } -+ gst_bin_add(GST_BIN(object->container), object->appsink); -+ -+ g_object_set(object->appsink, "emit-signals", TRUE, NULL); -+ g_object_set(object->appsink, "sync", FALSE, NULL); -+ g_object_set(object->appsink, "async", FALSE, NULL); -+ g_signal_connect(object->appsink, "new-sample", G_CALLBACK(decoder_new_sample_wrapper), object); -+ -+ -+ if (object->videobox) -+ { -+ if (!(gst_element_link(object->videobox, converter))) -+ { -+ ERR("Failed to link videobox to converter\n"); -+ hr = E_FAIL; -+ goto fail; -+ } -+ } -+ -+ if (!(gst_element_link(converter, object->appsink))) -+ { -+ ERR("Failed to link converter appsink"); -+ hr = E_FAIL; -+ goto fail; -+ } -+ -+ object->post_process_start = object->videobox ? object->videobox : converter; -+ -+ object->process_message_callback.lpVtbl = &process_message_callback_vtbl; -+ -+ object->IMFTransform_iface.lpVtbl = &mf_decoder_vtbl; -+ object->refcount = 1; -+ -+ *obj = object; -+ return S_OK; -+ -+ fail: -+ ERR("Failed to create Decoder MFT type %u, hr = %#x\n", type, hr); -+ mf_decoder_destroy(object); -+ return hr; -+} -+ -+void perform_cb_mf_decode(struct cb_data *cbdata) -+{ -+ switch (cbdata->type) -+ { -+ case ACTIVATE_PUSH_MODE: -+ { -+ struct activate_mode_data *data = &cbdata->u.activate_mode_data; -+ cbdata->u.activate_mode_data.ret = activate_push_mode(data->pad, data->parent, data->mode, data->activate); -+ break; -+ } -+ case QUERY_INPUT_SRC: -+ { -+ struct query_function_data *data = &cbdata->u.query_function_data; -+ cbdata->u.query_function_data.ret = query_input_src(data->pad, data->parent, data->query); -+ break; -+ } -+ case DECODER_NEW_SAMPLE: -+ { -+ struct new_sample_data *data = &cbdata->u.new_sample_data; -+ cbdata->u.new_sample_data.ret = decoder_new_sample(data->appsink, data->user); -+ break; -+ } -+ case WATCH_DECODER_BUS: -+ { -+ struct watch_bus_data *data = &cbdata->u.watch_bus_data; -+ cbdata->u.watch_bus_data.ret = watch_decoder_bus(data->bus, data->msg, data->user); -+ break; -+ } -+ default: -+ { -+ ERR("Wrong callback forwarder called\n"); -+ return; -+ } -+ } -+} -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 72fd31eb052..77859cb277f 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -410,6 +410,16 @@ static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x0 - - static GUID CLSID_WINEColorConverter = {0x2be8b27f,0xcd60,0x4b8a,{0x95,0xae,0xd1,0x74,0xcc,0x5c,0xba,0xa7}}; - -+static HRESULT h264_decoder_create(REFIID riid, void **ret) -+{ -+ return generic_decoder_construct(riid, ret, DECODER_TYPE_H264); -+} -+ -+static HRESULT aac_decoder_create(REFIID riid, void **ret) -+{ -+ return generic_decoder_construct(riid, ret, DECODER_TYPE_AAC); -+} -+ - static const struct class_object - { - const GUID *clsid; -@@ -421,6 +431,8 @@ class_objects[] = - { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, - { &CLSID_WINEAudioConverter, &audio_converter_create }, - { &CLSID_WINEColorConverter, &color_converter_create }, -+ { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, -+ { &CLSID_CMSAACDecMFT, &aac_decoder_create }, - }; - - HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) -@@ -476,6 +488,32 @@ const GUID *color_converter_supported_types[] = - &MFVideoFormat_YVYU, - }; - -+static WCHAR h264decoderW[] = {'H','.','2','6','4',' ','D','e','c','o','d','e','r',0}; -+const GUID *h264_decoder_input_types[] = -+{ -+ &MFVideoFormat_H264, -+}; -+const GUID *h264_decoder_output_types[] = -+{ -+ &MFVideoFormat_NV12, -+ &MFVideoFormat_I420, -+ &MFVideoFormat_IYUV, -+ &MFVideoFormat_YUY2, -+ &MFVideoFormat_YV12, -+}; -+ -+static WCHAR aacdecoderW[] = {'A','A','C',' ','D','e','c','o','d','e','r',0}; -+const GUID *aac_decoder_input_types[] = -+{ -+ &MFAudioFormat_AAC, -+}; -+ -+const GUID *aac_decoder_output_types[] = -+{ -+ &MFAudioFormat_Float, -+ &MFAudioFormat_PCM, -+}; -+ - static const struct mft - { - const GUID *clsid; -@@ -515,6 +553,30 @@ mfts[] = - color_converter_supported_types, - NULL - }, -+ { -+ &CLSID_CMSH264DecoderMFT, -+ &MFT_CATEGORY_VIDEO_DECODER, -+ h264decoderW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Video, -+ ARRAY_SIZE(h264_decoder_input_types), -+ h264_decoder_input_types, -+ ARRAY_SIZE(h264_decoder_output_types), -+ h264_decoder_output_types, -+ NULL -+ }, -+ { -+ &CLSID_CMSAACDecMFT, -+ &MFT_CATEGORY_AUDIO_DECODER, -+ aacdecoderW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Audio, -+ ARRAY_SIZE(aac_decoder_input_types), -+ aac_decoder_input_types, -+ ARRAY_SIZE(aac_decoder_output_types), -+ aac_decoder_output_types, -+ NULL -+ }, - }; - - HRESULT mfplat_DllRegisterServer(void) -@@ -568,7 +630,6 @@ struct aac_user_data - { - WORD payload_type; - WORD profile_level_indication; -- WORD struct_type; - WORD reserved; - /* audio-specific-config is stored here */ - }; -diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 1b203815330..05365e5e298 100644 ---- a/dlls/winegstreamer/winegstreamer_classes.idl -+++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -73,3 +73,15 @@ coclass WINEAudioConverter { } - uuid(2be8b27f-cd60-4b8a-95ae-d174cc5cbaa7) - ] - coclass WINEColorConverter { } -+ -+[ -+ threading(both), -+ uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d) -+] -+coclass CMSH264DecoderMFT { } -+ -+[ -+ threading(both), -+ uuid(32d186a7-218f-4c75-8876-dd77273a8999) -+] -+coclass CMSAACDecMFT { } -diff --git a/include/mfidl.idl b/include/mfidl.idl -index dd5de8d0d2f..4023c3a62d2 100644 ---- a/include/mfidl.idl -+++ b/include/mfidl.idl -@@ -1306,3 +1306,5 @@ cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, 0xba491365, - cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, 0xba491366, 0xbe50, 0x451e, 0x95, 0xab, 0x6d, 0x4a, 0xcc, 0xc7, 0xda, 0xd8);") - - cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") -+cpp_quote("EXTERN_GUID(CLSID_CMSH264DecoderMFT, 0x62ce7e72, 0x4c71, 0x4d20, 0xb1, 0x5d, 0x45, 0x28, 0x31, 0xa8, 0x7d, 0x9d);") -+cpp_quote("EXTERN_GUID(CLSID_CMSAACDecMFT, 0x32d186a7, 0x218f, 0x4c75, 0x88, 0x76, 0xdd, 0x77, 0x27, 0x3a, 0x89, 0x99);") --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0042-mfreadwrite-Select-all-streams-when-creating-a-sourc.patch b/patches/mfplat-streaming-support/0042-mfreadwrite-Select-all-streams-when-creating-a-sourc.patch deleted file mode 100644 index 43615c72..00000000 --- a/patches/mfplat-streaming-support/0042-mfreadwrite-Select-all-streams-when-creating-a-sourc.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 7fa665fa4360cf8656c30683c84280c1751850c0 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 23 Mar 2020 11:55:41 -0500 -Subject: [PATCH] mfreadwrite: Select all streams when creating a source - reader. - ---- - dlls/mfreadwrite/reader.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c -index 85aec9aaedc..77ce301d8be 100644 ---- a/dlls/mfreadwrite/reader.c -+++ b/dlls/mfreadwrite/reader.c -@@ -2138,6 +2138,10 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri - break; - - object->streams[i].index = i; -+ -+ hr = IMFPresentationDescriptor_SelectStream(object->descriptor, i); -+ if (FAILED(hr)) -+ break; - } - - if (FAILED(hr)) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0043-Miscellaneous.patch b/patches/mfplat-streaming-support/0043-Miscellaneous.patch deleted file mode 100644 index c335f168..00000000 --- a/patches/mfplat-streaming-support/0043-Miscellaneous.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 2cc1a2009879fec87340b1818111f3cea6fe2442 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 2 Nov 2020 09:58:09 -0600 -Subject: [PATCH] Miscellaneous - ---- - dlls/mfreadwrite/reader.c | 12 +++++++++++- - dlls/winegstreamer/gst_cbs.c | 20 +++++++++----------- - dlls/winegstreamer/gst_cbs.h | 1 - - dlls/winegstreamer/media_source.c | 24 +++++++++++++++++++++++- - 4 files changed, 43 insertions(+), 14 deletions(-) - -diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c -index 77ce301d8be..9fdef9a8c9c 100644 ---- a/dlls/mfreadwrite/reader.c -+++ b/dlls/mfreadwrite/reader.c -@@ -1584,6 +1584,7 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea - { - MFT_REGISTER_TYPE_INFO in_type, out_type; - CLSID *clsids, mft_clsid, category; -+ BOOL decoder_found = FALSE; - unsigned int i = 0, count; - IMFMediaType *input_type; - HRESULT hr; -@@ -1630,12 +1631,21 @@ static HRESULT source_reader_create_decoder_for_stream(struct source_reader *rea - } - - } -+ else if (!decoder_found) -+ { -+ /* see if there are other decoders for this stream */ -+ if (SUCCEEDED(MFTEnum(category, 0, &in_type, NULL, NULL, &clsids, &count)) && count) -+ { -+ decoder_found = TRUE; -+ CoTaskMemFree(clsids); -+ } -+ } - } - - IMFMediaType_Release(input_type); - } - -- return MF_E_TOPO_CODEC_NOT_FOUND; -+ return decoder_found ? MF_E_INVALIDREQUEST : MF_E_TOPO_CODEC_NOT_FOUND; - } - - static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWORD index, DWORD *reserved, -diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c -index 261a5b9f4ce..81692fdf919 100644 ---- a/dlls/winegstreamer/gst_cbs.c -+++ b/dlls/winegstreamer/gst_cbs.c -@@ -18,6 +18,9 @@ - - #include "config.h" - -+#include -+#include -+ - #include - - #include "objbase.h" -@@ -53,6 +56,12 @@ static void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user) - perform_cb_media_source(cbdata); - else if (cbdata->type < MF_DECODE_MAX) - perform_cb_mf_decode(cbdata); -+ else -+ { -+ fprintf(stderr, "No handler registered for callback\n"); -+ assert(0); -+ } -+ - - pthread_mutex_lock(&cbdata->lock); - cbdata->finished = 1; -@@ -447,17 +456,6 @@ GstBusSyncReply watch_decoder_bus_wrapper(GstBus *bus, GstMessage *message, gpoi - return cbdata.u.watch_bus_data.ret; - } - --void decoder_pad_added_wrapper(GstElement *element, GstPad *pad, gpointer user) --{ -- struct cb_data cbdata = { DECODER_PAD_ADDED }; -- -- cbdata.u.pad_added_data.element = element; -- cbdata.u.pad_added_data.pad = pad; -- cbdata.u.pad_added_data.user = user; -- -- call_cb(&cbdata); --} -- - GstFlowReturn decoder_new_sample_wrapper(GstElement *appsink, gpointer user) - { - struct cb_data cbdata = {DECODER_NEW_SAMPLE}; -diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h -index 6659aedefa5..825b46d13bb 100644 ---- a/dlls/winegstreamer/gst_cbs.h -+++ b/dlls/winegstreamer/gst_cbs.h -@@ -194,6 +194,5 @@ gboolean activate_push_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode m - gboolean query_input_src_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN; - GstBusSyncReply watch_decoder_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) DECLSPEC_HIDDEN; - GstFlowReturn decoder_new_sample_wrapper(GstElement *appsink, gpointer user) DECLSPEC_HIDDEN; --void decoder_pad_added_wrapper(GstElement *element, GstPad *Pad, gpointer user) DECLSPEC_HIDDEN; - - #endif -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 5f46f7d575a..2156e07a13c 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -554,6 +554,11 @@ static gboolean bytestream_query(GstPad *pad, GstObject *parent, GstQuery *query - gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL); - return TRUE; - } -+ case GST_QUERY_LATENCY: -+ { -+ gst_query_set_latency(query, FALSE, 0, 0); -+ return TRUE; -+ } - default: - { - WARN("Unhandled query type %s\n", GST_QUERY_TYPE_NAME(query)); -@@ -616,6 +621,23 @@ GstBusSyncReply bus_watch(GstBus *bus, GstMessage *message, gpointer user) - g_error_free(err); - g_free(dbg_info); - break; -+ case GST_MESSAGE_TAG: -+ { -+ GstTagList *tag_list; -+ gchar *printable; -+ gst_message_parse_tag(message, &tag_list); -+ if (tag_list) -+ { -+ printable = gst_tag_list_to_string(tag_list); -+ if (printable) -+ { -+ TRACE("tag test: %s\n", debugstr_a(printable)); -+ g_free(printable); -+ } -+ } -+ -+ break; -+ } - default: - break; - } -@@ -1154,7 +1176,7 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO - if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; - -- *characteristics = MFMEDIASOURCE_CAN_SEEK; -+ *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE; - - return S_OK; - } --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0044-WMV.patch b/patches/mfplat-streaming-support/0044-WMV.patch deleted file mode 100644 index 77754183..00000000 --- a/patches/mfplat-streaming-support/0044-WMV.patch +++ /dev/null @@ -1,153 +0,0 @@ -From c918862beea585aa413d3a629e5818a762d1568f Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 25 Mar 2020 19:07:11 -0500 -Subject: [PATCH] WMV - ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mf_decode.c | 10 +++++ - dlls/winegstreamer/mfplat.c | 40 ++++++++++++++++++++ - dlls/winegstreamer/winegstreamer_classes.idl | 6 +++ - include/mfidl.idl | 2 + - 5 files changed, 59 insertions(+) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 019cce5fad5..02343fa676e 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -90,6 +90,7 @@ enum decoder_type - { - DECODER_TYPE_H264, - DECODER_TYPE_AAC, -+ DECODER_TYPE_WMV, - }; - HRESULT generic_decoder_construct(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c -index 7055ffa54fc..3625382c573 100644 ---- a/dlls/winegstreamer/mf_decode.c -+++ b/dlls/winegstreamer/mf_decode.c -@@ -29,6 +29,9 @@ const GUID *h264_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_I420, &MF - const GUID *aac_input_types[] = {&MFAudioFormat_AAC}; - const GUID *aac_output_types[] = {&MFAudioFormat_Float}; - -+const GUID *wmv_input_types[] = {&MFVideoFormat_WMV3, &MFVideoFormat_WVC1}; -+const GUID *wmv_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_YV12, &MFVideoFormat_YUY2, &MFVideoFormat_UYVY, &MFVideoFormat_YVYU, &MFVideoFormat_NV11, &MFVideoFormat_RGB32, &MFVideoFormat_RGB24, &MFVideoFormat_RGB555, &MFVideoFormat_RGB8}; -+ - static struct decoder_desc - { - const GUID *major_type; -@@ -51,6 +54,13 @@ static struct decoder_desc - ARRAY_SIZE(aac_input_types), - aac_output_types, - ARRAY_SIZE(aac_output_types), -+ }, -+ { /* DECODER_TYPE_WMV */ -+ &MFMediaType_Video, -+ wmv_input_types, -+ ARRAY_SIZE(wmv_input_types), -+ wmv_output_types, -+ ARRAY_SIZE(wmv_output_types), - } - }; - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index b604f6df066..2fb730ff4c0 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -420,6 +420,10 @@ static HRESULT aac_decoder_create(REFIID riid, void **ret) - return generic_decoder_construct(riid, ret, DECODER_TYPE_AAC); - } - -+static HRESULT wmv_decoder_create(REFIID riid, void **ret) -+{ -+ return generic_decoder_construct(riid, ret, DECODER_TYPE_WMV); -+} - static const struct class_object - { - const GUID *clsid; -@@ -433,6 +437,7 @@ class_objects[] = - { &CLSID_WINEColorConverter, &color_converter_create }, - { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, - { &CLSID_CMSAACDecMFT, &aac_decoder_create }, -+ { &CLSID_CWMVDecMediaObject, &wmv_decoder_create }, - }; - - HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) -@@ -514,6 +519,29 @@ const GUID *aac_decoder_output_types[] = - &MFAudioFormat_PCM, - }; - -+static WCHAR wmvdecoderW[] = {'W','M','V','i','d','e','o',' ','D','e','c','o','d','e','r',' ','M','F','T',0}; -+ -+const GUID *wmv_decoder_input_types[] = -+{ -+ &MFVideoFormat_WMV3, -+ &MFVideoFormat_WVC1, -+}; -+ -+const GUID *wmv_decoder_output_types[] = -+{ -+ &MFVideoFormat_NV12, -+ &MFVideoFormat_YV12, -+ &MFVideoFormat_YUY2, -+ &MFVideoFormat_UYVY, -+ &MFVideoFormat_YVYU, -+ &MFVideoFormat_NV11, -+ &MFVideoFormat_RGB32, -+ &MFVideoFormat_RGB24, -+ &MFVideoFormat_RGB565, -+ &MFVideoFormat_RGB555, -+ &MFVideoFormat_RGB8, -+}; -+ - static const struct mft - { - const GUID *clsid; -@@ -577,6 +605,18 @@ mfts[] = - aac_decoder_output_types, - NULL - }, -+ { -+ &CLSID_CWMVDecMediaObject, -+ &MFT_CATEGORY_VIDEO_DECODER, -+ wmvdecoderW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Video, -+ ARRAY_SIZE(wmv_decoder_input_types), -+ wmv_decoder_input_types, -+ ARRAY_SIZE(wmv_decoder_output_types), -+ wmv_decoder_output_types, -+ NULL -+ }, - }; - - HRESULT mfplat_DllRegisterServer(void) -diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index fe8649c690c..3b29bbfc36d 100644 ---- a/dlls/winegstreamer/winegstreamer_classes.idl -+++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -85,3 +85,9 @@ coclass CMSH264DecoderMFT { } - uuid(32d186a7-218f-4c75-8876-dd77273a8999) - ] - coclass CMSAACDecMFT { } -+ -+[ -+ threading(both), -+ uuid(82d353df-90bd-4382-8bc2-3f6192b76e34) -+] -+coclass CLSID_CWMVDecMediaObject {} -diff --git a/include/mfidl.idl b/include/mfidl.idl -index 4023c3a62d2..7cb027b156a 100644 ---- a/include/mfidl.idl -+++ b/include/mfidl.idl -@@ -1308,3 +1308,5 @@ cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, 0xba491366, 0xb - cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") - cpp_quote("EXTERN_GUID(CLSID_CMSH264DecoderMFT, 0x62ce7e72, 0x4c71, 0x4d20, 0xb1, 0x5d, 0x45, 0x28, 0x31, 0xa8, 0x7d, 0x9d);") - cpp_quote("EXTERN_GUID(CLSID_CMSAACDecMFT, 0x32d186a7, 0x218f, 0x4c75, 0x88, 0x76, 0xdd, 0x77, 0x27, 0x3a, 0x89, 0x99);") -+cpp_quote("EXTERN_GUID(CLSID_ASFByteStreamHandler, 0x41457294, 0x644c, 0x4298, 0xa2, 0x8a, 0xbd, 0x69, 0xf2, 0xc0, 0xcf, 0x3b);") -+cpp_quote("EXTERN_GUID(CLSID_CWMVDecMediaObject, 0x82d353df, 0x90bd, 0x4382, 0x8b, 0xc2, 0x3f, 0x61, 0x92, 0xb7, 0x6e, 0x34);") -\ No newline at end of file --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0045-Expose-PCM-output-type-on-AAC-decoder.patch b/patches/mfplat-streaming-support/0045-Expose-PCM-output-type-on-AAC-decoder.patch deleted file mode 100644 index c2395a78..00000000 --- a/patches/mfplat-streaming-support/0045-Expose-PCM-output-type-on-AAC-decoder.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 8b1429c51559a4cb5685cfcf11302f0b8a6e9f14 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 3 Apr 2020 11:12:33 -0500 -Subject: [PATCH] Expose PCM output type on AAC decoder. - ---- - dlls/winegstreamer/mf_decode.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c -index 3625382c573..c188d08c57f 100644 ---- a/dlls/winegstreamer/mf_decode.c -+++ b/dlls/winegstreamer/mf_decode.c -@@ -27,7 +27,7 @@ const GUID *h264_input_types[] = {&MFVideoFormat_H264}; - const GUID *h264_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_YUY2, &MFVideoFormat_YV12}; - - const GUID *aac_input_types[] = {&MFAudioFormat_AAC}; --const GUID *aac_output_types[] = {&MFAudioFormat_Float}; -+const GUID *aac_output_types[] = {&MFAudioFormat_Float, &MFAudioFormat_PCM}; - - const GUID *wmv_input_types[] = {&MFVideoFormat_WMV3, &MFVideoFormat_WVC1}; - const GUID *wmv_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_YV12, &MFVideoFormat_YUY2, &MFVideoFormat_UYVY, &MFVideoFormat_YVYU, &MFVideoFormat_NV11, &MFVideoFormat_RGB32, &MFVideoFormat_RGB24, &MFVideoFormat_RGB555, &MFVideoFormat_RGB8}; --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0049-winegstreamer-Introduce-MPEG-4-Section-2-video-decod.patch b/patches/mfplat-streaming-support/0049-winegstreamer-Introduce-MPEG-4-Section-2-video-decod.patch deleted file mode 100644 index b99ed4f8..00000000 --- a/patches/mfplat-streaming-support/0049-winegstreamer-Introduce-MPEG-4-Section-2-video-decod.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 32e2cc5815a0f2836ba22f42e2eb7930289a18db Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 11 May 2020 16:05:50 -0500 -Subject: [PATCH] winegstreamer: Introduce MPEG-4 Section-2 video decoder. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mf_decode.c | 10 ++++++ - dlls/winegstreamer/mfplat.c | 35 ++++++++++++++++++++ - dlls/winegstreamer/winegstreamer_classes.idl | 6 ++++ - include/mfidl.idl | 1 + - 5 files changed, 53 insertions(+) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 02343fa676e..1c6530d2f38 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -91,6 +91,7 @@ enum decoder_type - DECODER_TYPE_H264, - DECODER_TYPE_AAC, - DECODER_TYPE_WMV, -+ DECODER_TYPE_M4S2, - }; - HRESULT generic_decoder_construct(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c -index c188d08c57f..b5220bc3332 100644 ---- a/dlls/winegstreamer/mf_decode.c -+++ b/dlls/winegstreamer/mf_decode.c -@@ -32,6 +32,9 @@ const GUID *aac_output_types[] = {&MFAudioFormat_Float, &MFAudioFormat_PCM}; - const GUID *wmv_input_types[] = {&MFVideoFormat_WMV3, &MFVideoFormat_WVC1}; - const GUID *wmv_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_YV12, &MFVideoFormat_YUY2, &MFVideoFormat_UYVY, &MFVideoFormat_YVYU, &MFVideoFormat_NV11, &MFVideoFormat_RGB32, &MFVideoFormat_RGB24, &MFVideoFormat_RGB555, &MFVideoFormat_RGB8}; - -+const GUID *m4s2_input_types[] = {&MFVideoFormat_MPEG2}; -+const GUID *m4s2_output_types[] = {&MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_NV12, &MFVideoFormat_YUY2, &MFVideoFormat_YV12}; -+ - static struct decoder_desc - { - const GUID *major_type; -@@ -61,6 +64,13 @@ static struct decoder_desc - ARRAY_SIZE(wmv_input_types), - wmv_output_types, - ARRAY_SIZE(wmv_output_types), -+ }, -+ { /* DECODER_TYPE_M4S2 */ -+ &MFMediaType_Video, -+ m4s2_input_types, -+ ARRAY_SIZE(m4s2_input_types), -+ m4s2_output_types, -+ ARRAY_SIZE(m4s2_output_types), - } - }; - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 2fb730ff4c0..e5227340fd2 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -424,6 +424,12 @@ static HRESULT wmv_decoder_create(REFIID riid, void **ret) - { - return generic_decoder_construct(riid, ret, DECODER_TYPE_WMV); - } -+ -+static HRESULT m4s2_decoder_create(REFIID riid, void **ret) -+{ -+ return generic_decoder_construct(riid, ret, DECODER_TYPE_M4S2); -+} -+ - static const struct class_object - { - const GUID *clsid; -@@ -438,6 +444,7 @@ class_objects[] = - { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, - { &CLSID_CMSAACDecMFT, &aac_decoder_create }, - { &CLSID_CWMVDecMediaObject, &wmv_decoder_create }, -+ { &CLSID_CMpeg4sDecMFT, m4s2_decoder_create }, - }; - - HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) -@@ -542,6 +549,22 @@ const GUID *wmv_decoder_output_types[] = - &MFVideoFormat_RGB8, - }; - -+static WCHAR m4s2decoderW[] = {'M','p','e','g','4','s',' ','D','e','c','o','d','e','r',' ','M','F','T',0}; -+ -+const GUID *m4s2_decoder_input_types[] = -+{ -+ &MFVideoFormat_M4S2, -+}; -+ -+const GUID *m4s2_decoder_output_types[] = -+{ -+ &MFVideoFormat_I420, -+ &MFVideoFormat_IYUV, -+ &MFVideoFormat_NV12, -+ &MFVideoFormat_YUY2, -+ &MFVideoFormat_YV12, -+}; -+ - static const struct mft - { - const GUID *clsid; -@@ -617,6 +640,18 @@ mfts[] = - wmv_decoder_output_types, - NULL - }, -+ { -+ &CLSID_CMpeg4sDecMFT, -+ &MFT_CATEGORY_VIDEO_DECODER, -+ m4s2decoderW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Video, -+ ARRAY_SIZE(m4s2_decoder_input_types), -+ m4s2_decoder_input_types, -+ ARRAY_SIZE(m4s2_decoder_output_types), -+ m4s2_decoder_output_types, -+ NULL -+ }, - }; - - HRESULT mfplat_DllRegisterServer(void) -diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 3b29bbfc36d..2382a884069 100644 ---- a/dlls/winegstreamer/winegstreamer_classes.idl -+++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -86,6 +86,12 @@ coclass CMSH264DecoderMFT { } - ] - coclass CMSAACDecMFT { } - -+[ -+ threading(both), -+ uuid(5686a0d9-fe39-409f-9dff-3fdbc849f9f5) -+] -+coclass CMpeg4sDecMFT { } -+ - [ - threading(both), - uuid(82d353df-90bd-4382-8bc2-3f6192b76e34) -diff --git a/include/mfidl.idl b/include/mfidl.idl -index 7cb027b156a..926f593b3bc 100644 ---- a/include/mfidl.idl -+++ b/include/mfidl.idl -@@ -1308,5 +1308,6 @@ cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, 0xba491366, 0xb - cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") - cpp_quote("EXTERN_GUID(CLSID_CMSH264DecoderMFT, 0x62ce7e72, 0x4c71, 0x4d20, 0xb1, 0x5d, 0x45, 0x28, 0x31, 0xa8, 0x7d, 0x9d);") - cpp_quote("EXTERN_GUID(CLSID_CMSAACDecMFT, 0x32d186a7, 0x218f, 0x4c75, 0x88, 0x76, 0xdd, 0x77, 0x27, 0x3a, 0x89, 0x99);") -+cpp_quote("EXTERN_GUID(CLSID_CMpeg4sDecMFT, 0x5686a0d9, 0xfe39, 0x409f, 0x9d, 0xff, 0x3f, 0xdb, 0xc8, 0x49, 0xf9, 0xf5);") - cpp_quote("EXTERN_GUID(CLSID_ASFByteStreamHandler, 0x41457294, 0x644c, 0x4298, 0xa2, 0x8a, 0xbd, 0x69, 0xf2, 0xc0, 0xcf, 0x3b);") - cpp_quote("EXTERN_GUID(CLSID_CWMVDecMediaObject, 0x82d353df, 0x90bd, 0x4382, 0x8b, 0xc2, 0x3f, 0x61, 0x92, 0xb7, 0x6e, 0x34);") -\ No newline at end of file --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0050-winegstreamer-Introduce-WMA-audio-decoder.patch b/patches/mfplat-streaming-support/0050-winegstreamer-Introduce-WMA-audio-decoder.patch deleted file mode 100644 index ac12a432..00000000 --- a/patches/mfplat-streaming-support/0050-winegstreamer-Introduce-WMA-audio-decoder.patch +++ /dev/null @@ -1,148 +0,0 @@ -From 1d5e925925e63fe244964b26cf6128ede0776a06 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 12 May 2020 16:50:41 -0500 -Subject: [PATCH] winegstreamer: Introduce WMA audio decoder. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mf_decode.c | 10 ++++++ - dlls/winegstreamer/mfplat.c | 32 ++++++++++++++++++++ - dlls/winegstreamer/winegstreamer_classes.idl | 6 ++++ - include/mfidl.idl | 3 +- - 5 files changed, 51 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 1c6530d2f38..81fc9b5ce14 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -91,6 +91,7 @@ enum decoder_type - DECODER_TYPE_H264, - DECODER_TYPE_AAC, - DECODER_TYPE_WMV, -+ DECODER_TYPE_WMA, - DECODER_TYPE_M4S2, - }; - HRESULT generic_decoder_construct(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c -index b5220bc3332..9b10cfd9e4a 100644 ---- a/dlls/winegstreamer/mf_decode.c -+++ b/dlls/winegstreamer/mf_decode.c -@@ -32,6 +32,9 @@ const GUID *aac_output_types[] = {&MFAudioFormat_Float, &MFAudioFormat_PCM}; - const GUID *wmv_input_types[] = {&MFVideoFormat_WMV3, &MFVideoFormat_WVC1}; - const GUID *wmv_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_YV12, &MFVideoFormat_YUY2, &MFVideoFormat_UYVY, &MFVideoFormat_YVYU, &MFVideoFormat_NV11, &MFVideoFormat_RGB32, &MFVideoFormat_RGB24, &MFVideoFormat_RGB555, &MFVideoFormat_RGB8}; - -+const GUID *wma_input_types[] = {&MFAudioFormat_WMAudioV8, &MFAudioFormat_WMAudioV9}; -+const GUID *wma_output_types[] = {&MFAudioFormat_Float, &MFAudioFormat_PCM}; -+ - const GUID *m4s2_input_types[] = {&MFVideoFormat_MPEG2}; - const GUID *m4s2_output_types[] = {&MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_NV12, &MFVideoFormat_YUY2, &MFVideoFormat_YV12}; - -@@ -65,6 +68,13 @@ static struct decoder_desc - wmv_output_types, - ARRAY_SIZE(wmv_output_types), - }, -+ { /* DECODER_TYPE_WMA */ -+ &MFMediaType_Audio, -+ wma_input_types, -+ ARRAY_SIZE(wma_input_types), -+ wma_output_types, -+ ARRAY_SIZE(wma_output_types), -+ }, - { /* DECODER_TYPE_M4S2 */ - &MFMediaType_Video, - m4s2_input_types, -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index e5227340fd2..8f770f94bf8 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -425,6 +425,11 @@ static HRESULT wmv_decoder_create(REFIID riid, void **ret) - return generic_decoder_construct(riid, ret, DECODER_TYPE_WMV); - } - -+static HRESULT wma_decoder_create(REFIID riid, void **ret) -+{ -+ return generic_decoder_construct(riid, ret, DECODER_TYPE_WMA); -+} -+ - static HRESULT m4s2_decoder_create(REFIID riid, void **ret) - { - return generic_decoder_construct(riid, ret, DECODER_TYPE_M4S2); -@@ -444,6 +449,7 @@ class_objects[] = - { &CLSID_CMSH264DecoderMFT, &h264_decoder_create }, - { &CLSID_CMSAACDecMFT, &aac_decoder_create }, - { &CLSID_CWMVDecMediaObject, &wmv_decoder_create }, -+ { &CLSID_CWMADecMediaObject, &wma_decoder_create }, - { &CLSID_CMpeg4sDecMFT, m4s2_decoder_create }, - }; - -@@ -549,6 +555,20 @@ const GUID *wmv_decoder_output_types[] = - &MFVideoFormat_RGB8, - }; - -+static WCHAR wmadecoderW[] = {'W','M','A','u','d','i','o',' ','D','e','c','o','d','e','r',' ','M','F','T',0}; -+ -+const GUID *wma_decoder_input_types[] = -+{ -+ &MFAudioFormat_WMAudioV8, -+ &MFAudioFormat_WMAudioV9, -+}; -+ -+const GUID *wma_decoder_output_types[] = -+{ -+ &MFAudioFormat_Float, -+ &MFAudioFormat_PCM, -+}; -+ - static WCHAR m4s2decoderW[] = {'M','p','e','g','4','s',' ','D','e','c','o','d','e','r',' ','M','F','T',0}; - - const GUID *m4s2_decoder_input_types[] = -@@ -640,6 +660,18 @@ mfts[] = - wmv_decoder_output_types, - NULL - }, -+ { -+ &CLSID_CWMADecMediaObject, -+ &MFT_CATEGORY_AUDIO_DECODER, -+ wmadecoderW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Audio, -+ ARRAY_SIZE(wma_decoder_input_types), -+ wma_decoder_input_types, -+ ARRAY_SIZE(wma_decoder_output_types), -+ wma_decoder_output_types, -+ NULL -+ }, - { - &CLSID_CMpeg4sDecMFT, - &MFT_CATEGORY_VIDEO_DECODER, -diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 2382a884069..3aa85dfdab3 100644 ---- a/dlls/winegstreamer/winegstreamer_classes.idl -+++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -97,3 +97,9 @@ coclass CMpeg4sDecMFT { } - uuid(82d353df-90bd-4382-8bc2-3f6192b76e34) - ] - coclass CLSID_CWMVDecMediaObject {} -+ -+[ -+ threading(both), -+ uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a) -+] -+coclass CLSID_CWMADecMediaObject {} -diff --git a/include/mfidl.idl b/include/mfidl.idl -index 926f593b3bc..ca469846458 100644 ---- a/include/mfidl.idl -+++ b/include/mfidl.idl -@@ -1310,4 +1310,5 @@ cpp_quote("EXTERN_GUID(CLSID_CMSH264DecoderMFT, 0x62ce7e72, 0x4c71, 0x4d20, 0xb1 - cpp_quote("EXTERN_GUID(CLSID_CMSAACDecMFT, 0x32d186a7, 0x218f, 0x4c75, 0x88, 0x76, 0xdd, 0x77, 0x27, 0x3a, 0x89, 0x99);") - cpp_quote("EXTERN_GUID(CLSID_CMpeg4sDecMFT, 0x5686a0d9, 0xfe39, 0x409f, 0x9d, 0xff, 0x3f, 0xdb, 0xc8, 0x49, 0xf9, 0xf5);") - cpp_quote("EXTERN_GUID(CLSID_ASFByteStreamHandler, 0x41457294, 0x644c, 0x4298, 0xa2, 0x8a, 0xbd, 0x69, 0xf2, 0xc0, 0xcf, 0x3b);") --cpp_quote("EXTERN_GUID(CLSID_CWMVDecMediaObject, 0x82d353df, 0x90bd, 0x4382, 0x8b, 0xc2, 0x3f, 0x61, 0x92, 0xb7, 0x6e, 0x34);") -\ No newline at end of file -+cpp_quote("EXTERN_GUID(CLSID_CWMVDecMediaObject, 0x82d353df, 0x90bd, 0x4382, 0x8b, 0xc2, 0x3f, 0x61, 0x92, 0xb7, 0x6e, 0x34);") -+cpp_quote("EXTERN_GUID(CLSID_CWMADecMediaObject, 0x2eeb4adf, 0x4578, 0x4d10, 0xbc, 0xa7, 0xbb, 0x95, 0x5f, 0x56, 0x32, 0x0a);") -\ No newline at end of file --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0051-winegstreamer-Implement-MF_SD_LANGUAGE.patch b/patches/mfplat-streaming-support/0051-winegstreamer-Implement-MF_SD_LANGUAGE.patch deleted file mode 100644 index 9b8af7e8..00000000 --- a/patches/mfplat-streaming-support/0051-winegstreamer-Implement-MF_SD_LANGUAGE.patch +++ /dev/null @@ -1,65 +0,0 @@ -From f85db2dd85e074dcb3373d711a937c00c3a5bc73 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 11 Aug 2020 13:41:15 -0500 -Subject: [PATCH] winegstreamer: Implement MF_SD_LANGUAGE. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/media_source.c | 32 ++++++++++++++++++++++++++++--- - 1 file changed, 29 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index fd7f1a7f55e..2c6b82c43b4 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -1636,11 +1636,12 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - - for (i = 0; i < object->stream_count; i++) - { -+ struct media_stream *stream = object->streams[i]; - gint64 stream_pres_time; -- if (gst_pad_query_duration(object->streams[i]->their_src, GST_FORMAT_TIME, &stream_pres_time)) -- { -- TRACE("Stream %u has duration %llu\n", i, (unsigned long long int) stream_pres_time); -+ GstEvent *tag_event; - -+ if (gst_pad_query_duration(stream->their_src, GST_FORMAT_TIME, &stream_pres_time)) -+ { - if (stream_pres_time > total_pres_time) - total_pres_time = stream_pres_time; - } -@@ -1648,6 +1649,31 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - { - WARN("Unable to get presentation time of stream %u\n", i); - } -+ -+ tag_event = gst_pad_get_sticky_event(stream->their_src, GST_EVENT_TAG, 0); -+ if (tag_event) -+ { -+ GstTagList *tag_list; -+ gchar *language_code = NULL; -+ -+ gst_event_parse_tag(tag_event, &tag_list); -+ -+ gst_tag_list_get_string(tag_list, "language-code", &language_code); -+ if (language_code) -+ { -+ DWORD char_count = MultiByteToWideChar(CP_UTF8, 0, language_code, -1, NULL, 0); -+ if (char_count) -+ { -+ WCHAR *language_codeW = heap_alloc(char_count * sizeof(WCHAR)); -+ MultiByteToWideChar(CP_UTF8, 0, language_code, -1, language_codeW, char_count); -+ IMFStreamDescriptor_SetString(stream->descriptor, &MF_SD_LANGUAGE, language_codeW); -+ heap_free(language_codeW); -+ } -+ g_free(language_code); -+ } -+ -+ gst_event_unref(tag_event); -+ } - } - - if (object->stream_count) --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0052-winegstreamer-Force-audio-mpeg-to-decode-in-source.patch b/patches/mfplat-streaming-support/0052-winegstreamer-Force-audio-mpeg-to-decode-in-source.patch deleted file mode 100644 index dfce3e82..00000000 --- a/patches/mfplat-streaming-support/0052-winegstreamer-Force-audio-mpeg-to-decode-in-source.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 94a318fdf7083bcb8142a7b869ce9de1f9e1b0a3 Mon Sep 17 00:00:00 2001 -From: Thomas Crider -Date: Fri, 18 Dec 2020 14:01:29 -0500 -Subject: [PATCH] winegstreamer: Force audio/mpeg to decode in source - -Currently AAC audio does not transform correctly when done manually, however forcing mfplat -to perform the decode in source via MF_DECODE_IN_SOURCE as it does with raw audio works properly. - -Fixes various game audio freezes/hangs including Borderlands 3, Seven: Enhanced Edition ---- - dlls/winegstreamer/mfplat.c | 101 +----------------------------------- - 1 file changed, 1 insertion(+), 100 deletions(-) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index e77c1d49e9a..ce0766beb12 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -967,7 +967,7 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - if (gst_structure_get_int(info, "bitrate", &bitrate)) - IMFMediaType_SetUINT32(media_type, &MF_MT_AVG_BITRATE, bitrate); - -- if (!strcmp(mime_type, "audio/x-raw")) -+ if (!strcmp(mime_type, "audio/x-raw") || !(strcmp(mime_type, "audio/mpeg"))) - { - GstAudioInfo audio_info; - DWORD depth; -@@ -1008,105 +1008,6 @@ IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) - - IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, depth); - } -- else if (!(strcmp(mime_type, "audio/mpeg"))) -- { -- int mpeg_version = -1; -- -- IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, TRUE); -- -- if (!(gst_structure_get_int(info, "mpegversion", &mpeg_version))) -- ERR("Failed to get mpegversion\n"); -- switch (mpeg_version) -- { -- case 2: -- case 4: -- { -- const char *format, *profile, *level; -- DWORD profile_level_indication = 0; -- const GValue *codec_data; -- DWORD asc_size = 0; -- struct aac_user_data *user_data = NULL; -- -- IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_AAC); -- IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 16); -- -- codec_data = gst_structure_get_value(info, "codec_data"); -- if (codec_data) -- { -- GstBuffer *codec_data_buffer = gst_value_get_buffer(codec_data); -- if (codec_data_buffer) -- { -- if ((asc_size = gst_buffer_get_size(codec_data_buffer)) >= 2) -- { -- user_data = heap_alloc_zero(sizeof(*user_data)+asc_size); -- gst_buffer_extract(codec_data_buffer, 0, (gpointer)(user_data + 1), asc_size); -- } -- else -- ERR("Unexpected buffer size\n"); -- } -- else -- ERR("codec_data not a buffer\n"); -- } -- else -- ERR("codec_data not found\n"); -- if (!user_data) -- user_data = heap_alloc_zero(sizeof(*user_data)); -- -- if ((format = gst_structure_get_string(info, "stream-format"))) -- { -- DWORD payload_type = -1; -- if (!(strcmp(format, "raw"))) -- payload_type = 0; -- else if (!(strcmp(format, "adts"))) -- payload_type = 1; -- else if (!(strcmp(format, "adif"))) -- payload_type = 2; -- else if (!(strcmp(format, "loas"))) -- payload_type = 3; -- else -- FIXME("Unrecognized stream-format\n"); -- if (payload_type != -1) -- { -- IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_PAYLOAD_TYPE, payload_type); -- user_data->payload_type = payload_type; -- } -- } -- else -- { -- ERR("Stream format not present\n"); -- } -- -- profile = gst_structure_get_string(info, "profile"); -- level = gst_structure_get_string(info, "level"); -- /* Data from http://archive.is/whp6P#45% */ -- if (profile && level) -- { -- if (!(strcmp(profile, "lc")) && !(strcmp(level, "2"))) -- profile_level_indication = 0x29; -- else if (!(strcmp(profile, "lc")) && !(strcmp(level, "4"))) -- profile_level_indication = 0x2A; -- else if (!(strcmp(profile, "lc")) && !(strcmp(level, "5"))) -- profile_level_indication = 0x2B; -- else -- FIXME("Unhandled profile/level combo\n"); -- } -- else -- ERR("Profile or level not present\n"); -- -- if (profile_level_indication) -- { -- IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, profile_level_indication); -- user_data->profile_level_indication = profile_level_indication; -- } -- -- IMFMediaType_SetBlob(media_type, &MF_MT_USER_DATA, (BYTE *)user_data, sizeof(*user_data) + asc_size); -- heap_free(user_data); -- break; -- } -- default: -- FIXME("Unhandled mpegversion %d\n", mpeg_version); -- } -- } - else if (!(strcmp(mime_type, "audio/x-wma"))) - { - gint wma_version, block_align; --- -2.29.2 - diff --git a/patches/mfplat-streaming-support/0060-winegstreamer-Support-eAVEncH264VProfile_Constrained.patch b/patches/mfplat-streaming-support/0060-winegstreamer-Support-eAVEncH264VProfile_Constrained.patch deleted file mode 100644 index 953634ff..00000000 --- a/patches/mfplat-streaming-support/0060-winegstreamer-Support-eAVEncH264VProfile_Constrained.patch +++ /dev/null @@ -1,35 +0,0 @@ -From e8cf102151b0fdcd5ccf54ad207e1256e3725b3c Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sun, 30 Aug 2020 12:37:59 +1000 -Subject: [PATCH] winegstreamer: Support eAVEncH264VProfile_ConstrainedBase - media type - -Game: American Fugitive ---- - dlls/winegstreamer/mfplat.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 21d44c498b8..7e482b77863 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -835,6 +835,8 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps) - IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_High); - else if (!(strcmp(profile, "high-4:4:4"))) - IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_444); -+ else if (!(strcmp(profile, "constrained-baseline"))) -+ IMFMediaType_SetUINT32(media_type, &MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_ConstrainedBase); - else - FIXME("Unrecognized profile %s\n", profile); - } -@@ -1274,6 +1276,7 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type) - case eAVEncH264VProfile_Main: profile = "main"; break; - case eAVEncH264VProfile_High: profile = "high"; break; - case eAVEncH264VProfile_444: profile = "high-4:4:4"; break; -+ case eAVEncH264VProfile_ConstrainedBase: profile = "constrained-baseline"; break; - default: FIXME("Unknown profile %u\n", h264_profile); - } - if (profile) --- -2.28.0 - diff --git a/patches/mfplat-streaming-support/definition b/patches/mfplat-streaming-support/definition index e6d0f574..00ba0f55 100644 --- a/patches/mfplat-streaming-support/definition +++ b/patches/mfplat-streaming-support/definition @@ -1,3 +1 @@ Fixes: [49692] Multiple applications need a Media Foundation media source implementation -# Will need to be rewritten after winegstreamer is converted. -Disabled: true diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index b617d99b..30e1d9fb 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -138,6 +138,7 @@ patch_enable_all () enable_krnl386_exe16_Invalid_Console_Handles="$1" enable_libs_Unicode_Collation="$1" enable_loader_KeyboardLayouts="$1" + enable_mfplat_streaming_support="$1" enable_mmsystem_dll16_MIDIHDR_Refcount="$1" enable_mountmgr_DosDevices="$1" enable_mscoree_CorValidateImage="$1" @@ -459,6 +460,9 @@ patch_enable () loader-KeyboardLayouts) enable_loader_KeyboardLayouts="$2" ;; + mfplat-streaming-support) + enable_mfplat_streaming_support="$2" + ;; mmsystem.dll16-MIDIHDR_Refcount) enable_mmsystem_dll16_MIDIHDR_Refcount="$2" ;; @@ -2446,6 +2450,60 @@ if test "$enable_loader_KeyboardLayouts" -eq 1; then patch_apply loader-KeyboardLayouts/0002-user32-Improve-GetKeyboardLayoutList.patch fi +# Patchset mfplat-streaming-support +# | +# | This patchset fixes the following Wine bugs: +# | * [#49692] Multiple applications need a Media Foundation media source implementation +# | +# | Modified files: +# | * dlls/mf/topology.c, dlls/mfplat/buffer.c, dlls/mfplat/main.c, dlls/mfreadwrite/tests/mfplat.c, +# | dlls/winegstreamer/Makefile.in, dlls/winegstreamer/audioconvert.c, dlls/winegstreamer/colorconvert.c, +# | dlls/winegstreamer/decode_transform.c, dlls/winegstreamer/gst_private.h, dlls/winegstreamer/main.c, +# | dlls/winegstreamer/media_source.c, dlls/winegstreamer/mfplat.c, dlls/winegstreamer/quartz_parser.c, +# | dlls/winegstreamer/wg_parser.c, dlls/winegstreamer/winegstreamer_classes.idl, include/mfidl.idl, include/wmcodecdsp.idl +# | +if test "$enable_mfplat_streaming_support" -eq 1; then + patch_apply mfplat-streaming-support/0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch + patch_apply mfplat-streaming-support/0002-winegstreamer-Push-stream-start-and-segment-events-i.patch + patch_apply mfplat-streaming-support/0003-winegstreamer-Introduce-H.264-decoder-transform.patch + patch_apply mfplat-streaming-support/0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch + patch_apply mfplat-streaming-support/0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch + patch_apply mfplat-streaming-support/0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch + patch_apply mfplat-streaming-support/0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch + patch_apply mfplat-streaming-support/0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch + patch_apply mfplat-streaming-support/0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch + patch_apply mfplat-streaming-support/0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch + patch_apply mfplat-streaming-support/0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch + patch_apply mfplat-streaming-support/0013-winegstreamer-Register-the-H.264-decoder-transform.patch + patch_apply mfplat-streaming-support/0014-winegstreamer-Introduce-AAC-decoder-transform.patch + patch_apply mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch + patch_apply mfplat-streaming-support/0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch + patch_apply mfplat-streaming-support/0017-winegstreamer-Report-streams-backwards-in-media-sour.patch + patch_apply mfplat-streaming-support/0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch + patch_apply mfplat-streaming-support/0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch + patch_apply mfplat-streaming-support/0021-winegstreamer-Introduce-color-conversion-transform.patch + patch_apply mfplat-streaming-support/0022-winegstreamer-Register-the-color-conversion-transfor.patch + patch_apply mfplat-streaming-support/0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch + patch_apply mfplat-streaming-support/0024-winegstreamer-Implement-SetInputType-for-color-conve.patch + patch_apply mfplat-streaming-support/0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch + patch_apply mfplat-streaming-support/0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch + patch_apply mfplat-streaming-support/0027-winegstreamer-Implement-Process-Input-Output-for-col.patch + patch_apply mfplat-streaming-support/0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch + patch_apply mfplat-streaming-support/0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch + patch_apply mfplat-streaming-support/0031-winegstreamer-Handle-flush-command-in-audio-converst.patch + patch_apply mfplat-streaming-support/0032-winegstreamer-In-the-default-configuration-select-on.patch + patch_apply mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch + patch_apply mfplat-streaming-support/0034-winegstreamer-Only-require-videobox-element-for-pars.patch + patch_apply mfplat-streaming-support/0035-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch + patch_apply mfplat-streaming-support/0036-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch + patch_apply mfplat-streaming-support/0037-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch + patch_apply mfplat-streaming-support/0038-mfreadwrite-Unset-seeking-flag-also-on-SourceStarted.patch + patch_apply mfplat-streaming-support/0039-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch +fi + # Patchset mmsystem.dll16-MIDIHDR_Refcount # | # | This patchset fixes the following Wine bugs: