Updated mfplat-streaming-support patchset

This commit is contained in:
Alistair Leslie-Hughes 2021-06-22 15:33:24 +10:00
parent 9c8608eea6
commit 9bf50b7e1f
80 changed files with 5564 additions and 6942 deletions

View File

@ -0,0 +1,90 @@
From d95656904e4d7d2c9a4006e90f123e28bbcdbb70 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,60 @@
From 9ec96ab12a41323abb477922cd2401446bd95457 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,407 +0,0 @@
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,384 @@
From 95db72178f4906d02785c707a46c8298f4c008d0 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 10 Mar 2021 13:09:51 -0500
Subject: [PATCH 03/39] winegstreamer: Introduce H.264 decoder transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,157 @@
From 17dab7f1ec1e00c313fa9f9bdcd64847de83b785 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 10 Mar 2021 14:14:21 -0500
Subject: [PATCH 04/39] winegstreamer: Implement ::GetInputAvailableType for
decode transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,57 @@
From 5842d8b762b85ff36de01d672e81d3e6eab9c554 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 10 Mar 2021 14:23:09 -0500
Subject: [PATCH 05/39] winegstreamer: Implement ::GetOutputAvailableType for
decode transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,305 @@
From 6d41356d8849c741c93e6eaab81784a8be515aa5 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 11 Mar 2021 12:33:02 -0500
Subject: [PATCH 06/39] winegstreamer: Implement ::SetInputType for decode
transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,116 @@
From 8a60a8ea1f93394afae504330ad623e4e85170d6 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 11 Mar 2021 12:58:32 -0500
Subject: [PATCH 07/39] winegstreamer: Implement ::SetOutputType for decode
transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,106 @@
From 7bb5efd92e23dfb1f734119000ec4866392f8d7c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,869 @@
From 431374b54bf2c58515c9bd56acf45d15f2fdf42d Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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, &current_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

View File

@ -0,0 +1,648 @@
From 316e739c324ef33e31987f0d5abd7b28db21e89a Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,77 +0,0 @@
From 64cfb2a80d7ebc22b12d8b6c1e41cf7a74e15d88 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 3 Dec 2020 14:45:32 -0500
Subject: [PATCH] winegstreamer: Implement ::GetOutputAvailableType for color
conversion transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,122 @@
From 6da483d3feca1cd83a5fecdd5671fa8a0d10a2f8 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 19 Mar 2021 16:54:03 -0400
Subject: [PATCH 11/39] winestreamer: Implement ::ProcessMessage for decoder
transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -1,103 +0,0 @@
From f1714a949175290e9f01bd32fde1dacecfed7946 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 3 Dec 2020 14:55:41 -0500
Subject: [PATCH] winegstreamer: Implement ::SetOutputType for color conversion
transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,30 @@
From 5c7b05aeb941b1fbd4a978894873438aa0e5b397 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,267 +0,0 @@
From c94cfbf0ec1c10452c2cf1496f32eeefe5794cea Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,56 @@
From 86f104e3b17755d2eecd6d46ea1c66875232e2bd Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,304 @@
From 8c2af2c3be9a337c07638206ba9d0c4035fda36e Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 19 Mar 2021 16:59:29 -0400
Subject: [PATCH 14/39] winegstreamer: Introduce AAC decoder transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -1,54 +0,0 @@
From e8eef3f90da399a077f5853e2a399c7e27a6418e Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,53 @@
From f1011219faa95c40cdcffda69c65dee5566b3b80 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 19 Mar 2021 17:00:27 -0400
Subject: [PATCH 15/39] winegstreamer: Register the AAC decoder transform.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -1,99 +0,0 @@
From 7bc3f13dd779e7b998a877012c83a8ca9e7aba4f Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,45 @@
From 86115ed0d28a1abb007b0eedf0442dbdf2e2127d Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,89 +0,0 @@
From 54919766d0ad2cf17e8cc6a8783794312964677c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,27 @@
From 2451bb53540b32568e404f8ed2399b8b2a58e64d Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,81 +0,0 @@
From 1472041682ce09e0e8bdda78ed0366fba6aa41a0 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 7 May 2020 13:09:47 -0500
Subject: [PATCH] winegstreamer: Implement IMFMediaSource::Stop.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,528 @@
From 6f1c7d5735bc793ccfc059c22071ee546db0133a Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -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 <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,54 +0,0 @@
From 539f0ad63d83dd1f60a9a54063f3cb108d71f794 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,29 +1,27 @@
From a7ae40f14dc926f02fca792b11b7374550dbd7ef Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,71 +0,0 @@
From dd7243f4ee9f7bee1019621c974f98737b760905 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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

View File

@ -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 <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,32 +0,0 @@
From 3b4148fbc1338e6a202d852491eba1362c905bfc Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 14 Oct 2020 11:07:05 -0500
Subject: [PATCH] mf/session: Unconditionally deliver NULL (EOS) samples.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -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 <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,42 +0,0 @@
From e1c9fe73263c2220be53482d195264832842279e Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -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 <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
@ -10,10 +10,10 @@ Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
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

View File

@ -1,27 +0,0 @@
From b25ab6a73f44bdab1a4ce782a27a8b3f1213cf64 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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

View File

@ -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 <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,163 +0,0 @@
From 8b681e5bd589b330790a0e887f5dbcd380e84a05 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 2 Nov 2020 09:56:54 -0600
Subject: [PATCH] winegstreamer: Add IMFSeekInfo::GetNearestKeyFrames stub.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,64 @@
From 70de073ef2395952f425411ef794e7238730ab52 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,122 +0,0 @@
From 18dea0ccadf90b4ac523dc1073c3870fdd6bcf6a Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,153 @@
From d044e2fb2a690340a0011a8527592e7a90db2faa Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,390 @@
From 93e4d5996b5abedef39d4667363f42cabaaa8705 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,45 +0,0 @@
From fe0175d8676cbd15ddeac07876e726ef76eef7b5 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -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 <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,141 +0,0 @@
From 7bb33ab950fe2fdddcd5e7409827be982044f813 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,95 @@
From 5a5376981522aba2a5a6f7facb44373584488c7f Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,113 +0,0 @@
From d95e8d8349b884800066c9af1ea9a7c7492ca02c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:00:26 -0500
Subject: [PATCH] winegstreamer: Translate H.264 caps to attributes.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,28 @@
From e602bc2817910624da0da383933889871e61c0f7 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,82 +0,0 @@
From 10dcfecc84651a4c2a270960c585c735ff09ec1c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:01:20 -0500
Subject: [PATCH] winegstreamer: Translate WMV caps to attributes.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,26 @@
From 2268b0ad8fbe8473f936b0fa0e09d9e072443853 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,139 +0,0 @@
From 90d881fc889fdaedc7e44c0bee5e54634c0d065c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:02:27 -0500
Subject: [PATCH] winegstreamer: Translate AAC caps to attributes.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -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 <dlesho@codeweavers.com>
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

View File

@ -1,40 +0,0 @@
From c4955ec1798428fe9941cdbb9fed146f3d29dbe2 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,131 @@
From 2ba70d161799850a073a43c658707fb1682a042f Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 18 Mar 2021 15:25:17 -0400
Subject: [PATCH 33/39] winegstreamer: Implement MF_SD_LANGUAGE.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -1,48 +0,0 @@
From 56ac324cb533bde61e25bc86a29440aec7111764 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 12 May 2020 17:05:41 -0500
Subject: [PATCH] winegstreamer: Translate WMA caps to attributes.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,93 @@
From 97f4a9b38ee49706edb3c52b93dd86509665361c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,128 +0,0 @@
From 6ace23bd172cb48c7e326fd3013624a73cdf8c10 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:18:40 -0500
Subject: [PATCH] winegstreamer: Translate H.264 attributes to caps.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,64 @@
From 1301b70733c9d5256b5f8352e9bbd6a3578ba590 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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

View File

@ -1,82 +0,0 @@
From 5f71506e9482e475bb636a4d3738734afe004443 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:20:17 -0500
Subject: [PATCH] winegstreamer: Translate WMV attributes to caps.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,30 @@
From ac8e72e266b60cf5dcef5ecf256ee3c99d6c9f53 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,90 +0,0 @@
From 09b135accfd48e079d6a2a3862e647b66b872b15 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 21 Apr 2020 10:31:02 -0500
Subject: [PATCH] winegstreamer: Translate AAC attributes to caps.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,98 @@
From 3666bd0c7cd99b5ae00f8f6fca83f316a9df398c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -1,32 +0,0 @@
From 9638f311e7d31f5e4aa80e173c31396d774afb75 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,120 @@
From a3c6815e44291b10a7756c8821e820b71be91fc6 Mon Sep 17 00:00:00 2001
From: Giovanni Mascellani <gmascellani@codeweavers.com>
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 <gmascellani@codeweavers.com>
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
---
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,
&timestamp, &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

View File

@ -1,39 +0,0 @@
From e16c1d7b27467663a90eb23863d8110627ec3ad1 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 12 May 2020 17:05:59 -0500
Subject: [PATCH] winegstreamer: Translate WMA attributes to caps.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -1,167 +0,0 @@
From dd690ffa7c0a3b2a067f0f2fc1ec7f99cfc9d343 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 29 Jan 2020 15:37:39 -0600
Subject: [PATCH] tools: Add support for multiple parent directories.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -0,0 +1,44 @@
From 9113e5421fd865f783f2bb3101336491fc92404d Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
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

View File

@ -1,28 +0,0 @@
From 7fa665fa4360cf8656c30683c84280c1751850c0 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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

View File

@ -1,155 +0,0 @@
From 2cc1a2009879fec87340b1818111f3cea6fe2442 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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 <stdio.h>
+#include <assert.h>
+
#include <gst/gst.h>
#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

View File

@ -1,153 +0,0 @@
From c918862beea585aa413d3a629e5818a762d1568f Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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

View File

@ -1,25 +0,0 @@
From 8b1429c51559a4cb5685cfcf11302f0b8a6e9f14 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
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

View File

@ -1,153 +0,0 @@
From 32e2cc5815a0f2836ba22f42e2eb7930289a18db Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 11 May 2020 16:05:50 -0500
Subject: [PATCH] winegstreamer: Introduce MPEG-4 Section-2 video decoder.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -1,148 +0,0 @@
From 1d5e925925e63fe244964b26cf6128ede0776a06 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 12 May 2020 16:50:41 -0500
Subject: [PATCH] winegstreamer: Introduce WMA audio decoder.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -1,65 +0,0 @@
From f85db2dd85e074dcb3373d711a937c00c3a5bc73 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 11 Aug 2020 13:41:15 -0500
Subject: [PATCH] winegstreamer: Implement MF_SD_LANGUAGE.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
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

View File

@ -1,135 +0,0 @@
From 94a318fdf7083bcb8142a7b869ce9de1f9e1b0a3 Mon Sep 17 00:00:00 2001
From: Thomas Crider <gloriouseggroll@gmail.com>
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

View File

@ -1,35 +0,0 @@
From e8cf102151b0fdcd5ccf54ad207e1256e3725b3c Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
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

View File

@ -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

View File

@ -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: