Added mfplat-streaming-support patchset

This commit is contained in:
Alistair Leslie-Hughes 2020-08-11 10:22:11 +10:00
parent 32082f4d6f
commit af56d3821a
56 changed files with 12079 additions and 0 deletions

View File

@ -0,0 +1,246 @@
From ac9dd9bf46de1056dd26a3230bfd885d2962c8aa Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Tue, 11 Aug 2020 09:26:57 +1000
Subject: [PATCH 01/54] Revert "mf/topoloader: Add a structure for iterative
branch resolution."
This reverts commit e308d81a617632fe0fedd243952f79e8d9ec05b4.
---
dlls/mf/tests/mf.c | 9 +--
dlls/mf/topology.c | 138 +--------------------------------------------
2 files changed, 4 insertions(+), 143 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index f01385cc46..aa2c5199b9 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1400,7 +1400,6 @@ static void test_topology_loader(void)
IMFPresentationDescriptor *pd;
IMFSourceResolver *resolver;
IMFActivate *sink_activate;
- IMFStreamSink *stream_sink;
unsigned int count, value;
IMFMediaType *media_type;
IMFStreamDescriptor *sd;
@@ -1513,19 +1512,15 @@ todo_wine
hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
- hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
- ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
-
- hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink);
ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
- IMFStreamSink_Release(stream_sink);
-
hr = IMFTopology_GetCount(topology, &count);
ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr);
ok(count == 0, "Unexpected count %u.\n", count);
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+todo_wine
ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
ok(full_topology != topology, "Unexpected instance.\n");
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index 8032e438b7..840f1bd25f 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1935,41 +1935,17 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
struct topoloader_context
{
- IMFTopology *input_topology;
IMFTopology *output_topology;
- unsigned int marker;
GUID key;
};
-static IMFTopologyNode *topology_loader_get_node_for_marker(struct topoloader_context *context, TOPOID *id)
-{
- IMFTopologyNode *node;
- unsigned short i = 0;
- unsigned int value;
-
- while (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i++, &node)))
- {
- if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &context->key, &value)) && value == context->marker)
- {
- IMFTopologyNode_GetTopoNodeID(node, id);
- return node;
- }
- IMFTopologyNode_Release(node);
- }
-
- *id = 0;
- return NULL;
-}
-
static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node,
- IMFTopologyNode **ret, unsigned int marker)
+ unsigned int marker)
{
IMFTopologyNode *cloned_node;
MF_TOPOLOGY_TYPE node_type;
HRESULT hr;
- if (ret) *ret = NULL;
-
IMFTopologyNode_GetNodeType(node, &node_type);
if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node)))
@@ -1981,113 +1957,17 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM
if (SUCCEEDED(hr))
hr = IMFTopology_AddNode(context->output_topology, cloned_node);
- if (SUCCEEDED(hr) && ret)
- {
- *ret = cloned_node;
- IMFTopologyNode_AddRef(*ret);
- }
-
IMFTopologyNode_Release(cloned_node);
return hr;
}
-typedef HRESULT (*p_topology_loader_connect_func)(struct topoloader_context *context, IMFTopologyNode *upstream_node,
- unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index);
-
-static HRESULT topology_loader_connect_source_node(struct topoloader_context *context, IMFTopologyNode *upstream_node,
- unsigned int output_index, IMFTopologyNode *downstream_node, unsigned int input_index)
-{
- FIXME("Unimplemented.\n");
-
- return E_NOTIMPL;
-}
-
-static HRESULT topology_loader_resolve_branch(struct topoloader_context *context, IMFTopologyNode *upstream_node,
- unsigned int output_index, IMFTopologyNode *downstream_node, unsigned input_index)
-{
- static const p_topology_loader_connect_func connectors[MF_TOPOLOGY_TEE_NODE+1][MF_TOPOLOGY_TEE_NODE+1] =
- {
- /* OUTPUT */ { NULL },
- /* SOURCESTREAM */ { topology_loader_connect_source_node, NULL, NULL, NULL },
- /* TRANSFORM */ { NULL },
- /* TEE */ { NULL },
- };
- MF_TOPOLOGY_TYPE u_type, d_type;
- IMFTopologyNode *node;
- TOPOID id;
-
- /* Downstream node might have already been cloned. */
- IMFTopologyNode_GetTopoNodeID(downstream_node, &id);
- if (FAILED(IMFTopology_GetNodeByID(context->output_topology, id, &node)))
- topology_loader_clone_node(context, downstream_node, &node, context->marker + 1);
-
- IMFTopologyNode_ConnectOutput(upstream_node, output_index, node, input_index);
-
- IMFTopologyNode_GetNodeType(upstream_node, &u_type);
- IMFTopologyNode_GetNodeType(downstream_node, &d_type);
-
- if (!connectors[u_type][d_type])
- {
- WARN("Unsupported branch kind %d -> %d.\n", u_type, d_type);
- return E_FAIL;
- }
-
- return connectors[u_type][d_type](context, upstream_node, output_index, downstream_node, input_index);
-}
-
-static HRESULT topology_loader_resolve_nodes(struct topoloader_context *context, unsigned int *layer_size)
-{
- IMFTopologyNode *downstream_node, *node, *orig_node;
- unsigned int input_index, size = 0;
- MF_TOPOLOGY_TYPE node_type;
- HRESULT hr = S_OK;
- TOPOID id;
-
- while ((node = topology_loader_get_node_for_marker(context, &id)))
- {
- ++size;
-
- IMFTopology_GetNodeByID(context->input_topology, id, &orig_node);
-
- IMFTopologyNode_GetNodeType(node, &node_type);
- switch (node_type)
- {
- case MF_TOPOLOGY_SOURCESTREAM_NODE:
- if (FAILED(IMFTopologyNode_GetOutput(orig_node, 0, &downstream_node, &input_index)))
- {
- IMFTopology_RemoveNode(context->output_topology, node);
- continue;
- }
-
- hr = topology_loader_resolve_branch(context, node, 0, downstream_node, input_index);
- break;
- case MF_TOPOLOGY_TRANSFORM_NODE:
- case MF_TOPOLOGY_TEE_NODE:
- FIXME("Unsupported node type %d.\n", node_type);
- break;
- default:
- WARN("Unexpected node type %d.\n", node_type);
- }
-
- IMFTopologyNode_DeleteItem(node, &context->key);
-
- if (FAILED(hr))
- break;
- }
-
- *layer_size = size;
-
- return hr;
-}
-
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology,
IMFTopology **ret_topology, IMFTopology *current_topology)
{
struct topoloader_context context = { 0 };
IMFTopology *output_topology;
MF_TOPOLOGY_TYPE node_type;
- unsigned int layer_size;
IMFTopologyNode *node;
unsigned short i = 0;
IMFStreamSink *sink;
@@ -2136,7 +2016,6 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
if (FAILED(hr = MFCreateTopology(&output_topology)))
return hr;
- context.input_topology = input_topology;
context.output_topology = output_topology;
memset(&context.key, 0xff, sizeof(context.key));
@@ -2148,26 +2027,13 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
{
- if (FAILED(hr = topology_loader_clone_node(&context, node, NULL, 0)))
+ if (FAILED(hr = topology_loader_clone_node(&context, node, 0)))
WARN("Failed to clone source node, hr %#x.\n", hr);
}
IMFTopologyNode_Release(node);
}
- for (context.marker = 0;; ++context.marker)
- {
- if (FAILED(hr = topology_loader_resolve_nodes(&context, &layer_size)))
- {
- WARN("Failed to resolve for marker %u, hr %#x.\n", context.marker, hr);
- break;
- }
-
- /* Reached last marker value. */
- if (!layer_size)
- break;
- }
-
/* For now return original topology. */
*ret_topology = output_topology;
--
2.28.0

View File

@ -0,0 +1,104 @@
From f02867e2a1129f7aef4488db827fc52a6131b3d4 Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Tue, 11 Aug 2020 09:26:59 +1000
Subject: [PATCH 02/54] Revert "mf/topoloader: Clone source nodes as a first
layer of resulting topology."
This reverts commit 16d44b61d15193905ef40661bc1547cb45e7b019.
---
dlls/mf/topology.c | 61 +++-------------------------------------------
1 file changed, 4 insertions(+), 57 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index 840f1bd25f..8522f56969 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1933,40 +1933,9 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
return refcount;
}
-struct topoloader_context
-{
- IMFTopology *output_topology;
- GUID key;
-};
-
-static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node,
- unsigned int marker)
-{
- IMFTopologyNode *cloned_node;
- MF_TOPOLOGY_TYPE node_type;
- HRESULT hr;
-
- IMFTopologyNode_GetNodeType(node, &node_type);
-
- if (FAILED(hr = MFCreateTopologyNode(node_type, &cloned_node)))
- return hr;
-
- if (SUCCEEDED(hr = IMFTopologyNode_CloneFrom(cloned_node, node)))
- hr = IMFTopologyNode_SetUINT32(cloned_node, &context->key, marker);
-
- if (SUCCEEDED(hr))
- hr = IMFTopology_AddNode(context->output_topology, cloned_node);
-
- IMFTopologyNode_Release(cloned_node);
-
- return hr;
-}
-
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology,
- IMFTopology **ret_topology, IMFTopology *current_topology)
+ IMFTopology **output_topology, IMFTopology *current_topology)
{
- struct topoloader_context context = { 0 };
- IMFTopology *output_topology;
MF_TOPOLOGY_TYPE node_type;
IMFTopologyNode *node;
unsigned short i = 0;
@@ -1974,7 +1943,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
IUnknown *object;
HRESULT hr = E_FAIL;
- FIXME("%p, %p, %p, %p.\n", iface, input_topology, ret_topology, current_topology);
+ FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
if (current_topology)
FIXME("Current topology instance is ignored.\n");
@@ -2013,32 +1982,10 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
return hr;
}
- if (FAILED(hr = MFCreateTopology(&output_topology)))
+ if (FAILED(hr = MFCreateTopology(output_topology)))
return hr;
- context.output_topology = output_topology;
- memset(&context.key, 0xff, sizeof(context.key));
-
- /* Clone source nodes, use initial marker value. */
- i = 0;
- while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node)))
- {
- IMFTopologyNode_GetNodeType(node, &node_type);
-
- if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
- {
- if (FAILED(hr = topology_loader_clone_node(&context, node, 0)))
- WARN("Failed to clone source node, hr %#x.\n", hr);
- }
-
- IMFTopologyNode_Release(node);
- }
-
- /* For now return original topology. */
-
- *ret_topology = output_topology;
-
- return IMFTopology_CloneFrom(output_topology, input_topology);
+ return IMFTopology_CloneFrom(*output_topology, input_topology);
}
static const IMFTopoLoaderVtbl topologyloadervtbl =
--
2.28.0

View File

@ -0,0 +1,81 @@
From e42f00a2fd98ea18f76b2f8c874d86b27723c57d Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Tue, 11 Aug 2020 09:27:00 +1000
Subject: [PATCH 03/54] Revert "mf/topoloader: Switch to public interface for
initial topology validation."
This reverts commit 8e343024b577892bd4908304ded34b758579698d.
---
dlls/mf/topology.c | 36 ++++++++++++------------------------
1 file changed, 12 insertions(+), 24 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index 8522f56969..abe66c45fd 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1936,50 +1936,38 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology,
IMFTopology **output_topology, IMFTopology *current_topology)
{
- MF_TOPOLOGY_TYPE node_type;
- IMFTopologyNode *node;
- unsigned short i = 0;
+ struct topology *topology = unsafe_impl_from_IMFTopology(input_topology);
IMFStreamSink *sink;
- IUnknown *object;
- HRESULT hr = E_FAIL;
+ HRESULT hr;
+ size_t i;
FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
if (current_topology)
FIXME("Current topology instance is ignored.\n");
- /* Basic sanity checks for input topology:
-
- - source nodes must have stream descriptor set;
- - sink nodes must be resolved to stream sink objects;
- */
- while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node)))
+ for (i = 0; i < topology->nodes.count; ++i)
{
- IMFTopologyNode_GetNodeType(node, &node_type);
+ struct topology_node *node = topology->nodes.nodes[i];
- switch (node_type)
+ switch (node->node_type)
{
case MF_TOPOLOGY_OUTPUT_NODE:
- if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
+ if (node->object)
{
/* Sinks must be bound beforehand. */
- if (FAILED(IUnknown_QueryInterface(object, &IID_IMFStreamSink, (void **)&sink)))
- hr = MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
- else if (sink)
- IMFStreamSink_Release(sink);
- IUnknown_Release(object);
+ if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFStreamSink, (void **)&sink)))
+ return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
+ IMFStreamSink_Release(sink);
}
break;
case MF_TOPOLOGY_SOURCESTREAM_NODE:
- hr = IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL);
+ if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL)))
+ return hr;
break;
default:
;
}
-
- IMFTopologyNode_Release(node);
- if (FAILED(hr))
- return hr;
}
if (FAILED(hr = MFCreateTopology(output_topology)))
--
2.28.0

View File

@ -0,0 +1,50 @@
From a78920ed5d799815126b294c4ecf0b039cf5671c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Wed, 1 Apr 2020 16:11:05 -0500
Subject: [PATCH 04/54] mf/tests: Sink objects are stream sinks, not media
sinks.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
dlls/mf/tests/mf.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index aa2c5199b9..9e190388ee 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1400,6 +1400,7 @@ static void test_topology_loader(void)
IMFPresentationDescriptor *pd;
IMFSourceResolver *resolver;
IMFActivate *sink_activate;
+ IMFStreamSink *stream_sink;
unsigned int count, value;
IMFMediaType *media_type;
IMFStreamDescriptor *sd;
@@ -1512,7 +1513,10 @@ todo_wine
hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
- hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink);
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
+ ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr);
+
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
hr = IMFTopology_GetCount(topology, &count);
@@ -1520,7 +1524,6 @@ todo_wine
ok(count == 0, "Unexpected count %u.\n", count);
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
ok(full_topology != topology, "Unexpected instance.\n");
--
2.28.0

View File

@ -0,0 +1,499 @@
From dfb5190b00ce04f7ac0c811cb6350af37826015e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Wed, 1 Apr 2020 16:11:06 -0500
Subject: [PATCH 05/54] mf/tests: Add tests for the topology loader.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
dlls/mf/tests/mf.c | 435 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 433 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 9e190388ee..8691ef55c9 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1392,26 +1392,169 @@ static const IMFSampleGrabberSinkCallbackVtbl test_grabber_callback_vtbl =
test_grabber_callback_OnShutdown,
};
+static HRESULT WINAPI test_media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
+{
+ if (IsEqualIID(riid, &IID_IMFMediaSource) ||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = iface;
+ IUnknown_AddRef((IUnknown*)*out);
+ return S_OK;
+ }
+
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI test_media_source_AddRef(IMFMediaSource *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI test_media_source_Release(IMFMediaSource *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI test_media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
+ HRESULT hr, const PROPVARIANT *value)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
+{
+ HRESULT hr;
+
+ IMFPresentationDescriptor *pd;
+ IMFMediaType *mediatypes[3];
+ IMFStreamDescriptor *sd[2];
+
+ if (FAILED(hr = MFCreateMediaType(&mediatypes[0])))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[0], &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[0], &MF_MT_SUBTYPE, &MFVideoFormat_YUY2)))
+ return hr;
+ if (FAILED(hr = MFCreateMediaType(&mediatypes[1])))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[1], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[1], &MF_MT_SUBTYPE, &MFAudioFormat_MP3)))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_SAMPLES_PER_SECOND, 32000)))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_NUM_CHANNELS, 2)))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetUINT32(mediatypes[1], &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1)))
+ return hr;
+ if (FAILED(hr = MFCreateMediaType(&mediatypes[2])))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[2], &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
+ return hr;
+ if (FAILED(hr = IMFMediaType_SetGUID(mediatypes[2], &MF_MT_SUBTYPE, &MFAudioFormat_PCM)))
+ return hr;
+ if (FAILED(hr = MFCreateStreamDescriptor(0, 3, mediatypes, &sd[0])))
+ return hr;
+ if (FAILED(hr = MFCreateStreamDescriptor(1, 3, mediatypes, &sd[1])))
+ return hr;
+ if (FAILED(hr = MFCreatePresentationDescriptor(2, sd, &pd)))
+ return hr;
+ *descriptor = pd;
+
+ IMFMediaType_Release(mediatypes[0]);
+ IMFMediaType_Release(mediatypes[1]);
+ IMFMediaType_Release(mediatypes[2]);
+ IMFStreamDescriptor_Release(sd[0]);
+ IMFStreamDescriptor_Release(sd[1]);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI test_media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
+ const GUID *time_format, const PROPVARIANT *start_position)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_Stop(IMFMediaSource *iface)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_Pause(IMFMediaSource *iface)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_media_source_Shutdown(IMFMediaSource *iface)
+{
+ return S_OK;
+}
+
+static const IMFMediaSourceVtbl test_media_source_vtbl =
+{
+ test_media_source_QueryInterface,
+ test_media_source_AddRef,
+ test_media_source_Release,
+ test_media_source_GetEvent,
+ test_media_source_BeginGetEvent,
+ test_media_source_EndGetEvent,
+ test_media_source_QueueEvent,
+ test_media_source_GetCharacteristics,
+ test_media_source_CreatePresentationDescriptor,
+ test_media_source_Start,
+ test_media_source_Stop,
+ test_media_source_Pause,
+ test_media_source_Shutdown,
+};
+
static void test_topology_loader(void)
{
IMFSampleGrabberSinkCallback test_grabber_callback = { &test_grabber_callback_vtbl };
+ IMFMediaSource test_media_source = { &test_media_source_vtbl };
IMFTopology *topology, *topology2, *full_topology;
IMFTopologyNode *src_node, *sink_node;
+ IMFMediaType *media_type, *current_media_type;
IMFPresentationDescriptor *pd;
IMFSourceResolver *resolver;
IMFActivate *sink_activate;
IMFStreamSink *stream_sink;
unsigned int count, value;
- IMFMediaType *media_type;
+ IMFMediaTypeHandler *mth;
IMFStreamDescriptor *sd;
+ UINT32 enum_src, method;
MF_OBJECT_TYPE obj_type;
IMFMediaSource *source;
IMFTopoLoader *loader;
IMFByteStream *stream;
IMFAttributes *attr;
IMFMediaSink *sink;
+ WORD node_count;
WCHAR *filename;
BOOL selected;
+ DWORD flags;
HRESULT hr;
GUID guid;
@@ -1527,6 +1670,9 @@ todo_wine
ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
ok(full_topology != topology, "Unexpected instance.\n");
+ IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(node_count == 2, "Topology node count is %#x.\n", node_count);
+
hr = IMFTopology_GetCount(topology, &count);
ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr);
ok(count == 0, "Unexpected count %u.\n", count);
@@ -1553,10 +1699,295 @@ todo_wine {
IMFTopology_Release(topology2);
IMFTopology_Release(full_topology);
+ IMFByteStream_Release(stream);
+ IMFStreamDescriptor_Release(sd);
+
+ /* test with stream deselected */
+ IMFPresentationDescriptor_GetStreamDescriptorCount(pd, &count);
+ ok(count == 1, "Unexpected stream descriptor count.\n");
+ hr = IMFPresentationDescriptor_DeselectStream(pd, 0);
+ ok(hr == S_OK, "Failed to deselect stream, hr %#x.\n", hr);
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
+ IMFTopologyNode_Release(src_node);
+ hr = IMFTopology_GetNode(full_topology, 0, &src_node);
+ ok(hr == S_OK, "Failed to get full topology source node, hr %#x.\n", hr);
+ IMFPresentationDescriptor_Release(pd);
+ hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor, (void **)&pd);
+ ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr);
+ IMFStreamDescriptor_Release(sd);
+ IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
+ ok(!selected, "Stream should not be selected\n.");
+ IMFPresentationDescriptor_Release(pd);
+ IMFTopologyNode_Release(src_node);
+ IMFTopology_Release(full_topology);
+ IMFTopology_Release(topology);
IMFMediaSource_Release(source);
IMFSourceResolver_Release(resolver);
- IMFByteStream_Release(stream);
+
+ /* test source stream with various media types */
+ /* first, test default behavior; MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES not set */
+ hr = MFCreateTopology(&topology);
+ ok(hr == S_OK, "Failed to create topology, hr %#x.\n", hr);
+
+ hr = IMFMediaSource_CreatePresentationDescriptor(&test_media_source, &pd);
+ ok(hr == S_OK, "Failed to create descriptor, hr %#x.\n", hr);
+
+ hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd);
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
+
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, &media_type);
+ ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
+
+ hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node);
+ ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr);
+
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)&test_media_source);
+ ok(hr == S_OK, "Failed to set node source, hr %#x.\n", hr);
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
+ ok(hr == S_OK, "Failed to set node pd, hr %#x.\n", hr);
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
+ ok(hr == S_OK, "Failed to set node sd, hr %#x.\n", hr);
+
+ hr = IMFTopology_AddNode(topology, src_node);
+ ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr);
+
+ hr = MFCreateMediaType(&media_type);
+ ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr);
+
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+
+ hr = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate);
+ ok(hr == S_OK, "Failed to create grabber sink, hr %#x.\n", hr);
+ IMFMediaType_Release(media_type);
+
+ hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
+ ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
+ ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr);
+
+ hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node);
+ ok(hr == S_OK, "Failed to create output node, hr %#x.\n", hr);
+
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
+ ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
+
+ hr = IMFTopology_AddNode(topology, sink_node);
+ ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
+
+ hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
+ ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr);
+
+ hr = IMFTopology_GetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src);
+ ok(hr == MF_E_ATTRIBUTENOTFOUND, "Attribute should not be set\n.");
+ /* if no current media type set, loader uses first index exclusively */
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+todo_wine
+ /* when major types differ, error is MF_E_TOPO_CODEC_NOT_FOUND */
+ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 2, &media_type);
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
+
+ /* setting current media type overrides previous behavior; tries with it, and only with it */
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+ ok(node_count == 2, "Unexpected node count.\n");
+
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type);
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
+
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
+
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+todo_wine
+ ok(node_count == 3, "Unexpected node count.\n");
+
+ IMFTopology_Release(full_topology);
+
+ /* now test with MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES set on topology */
+ hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1);
+ ok(hr == S_OK, "Failed setting attribute\n.");
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 2, &media_type);
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
+
+ /* first, if MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES is not set on source */
+ IMFTopologyNode_GetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, &method);
+ ok(hr == S_OK, "Attribute should be set\n.");
+ IMFTopologyNode_SetUINT32(src_node, &MF_TOPONODE_CONNECT_METHOD, method & ~MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES);
+ ok(hr == S_OK, "Failed setting attribute %#x\n.", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
+
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+ ok(node_count == 2, "Unexpected node count.\n");
+ IMFTopologyNode_Release(src_node);
+ hr = IMFTopology_GetNode(full_topology, 0, &src_node);
+ ok(hr == S_OK, "Failed to get node, hr %#x.\n", hr);
+ IMFStreamDescriptor_Release(sd);
+ hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&sd);
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
+ IMFMediaTypeHandler_Release(mth);
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, &current_media_type);
+ ok(hr == S_OK, "Failed to get current media type, hr %#x.\n", hr);
+ hr = IMFMediaType_IsEqual(current_media_type, media_type, &flags);
+todo_wine {
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA, "Types should be equal.\n");
+}
+
+ IMFMediaType_Release(media_type);
+ IMFMediaType_Release(current_media_type);
+ IMFMediaTypeHandler_Release(mth);
+ IMFStreamSink_Release(stream_sink);
+ IMFMediaSink_Release(sink);
+ IMFActivate_Release(sink_activate);
+ IMFStreamDescriptor_Release(sd);
+
+ /* add second branch with a valid first branch */
+ hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 0);
+ ok(hr == S_OK, "Failed setting attribute\n.");
+ IMFTopologyNode_Release(src_node);
+ hr = IMFTopology_GetNode(topology, 0, &src_node);
+ ok(hr == S_OK, "Failed to get node, hr %#x.\n", hr);
+ hr = IMFTopologyNode_GetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&sd);
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type);
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
+
+ IMFTopology_Release(full_topology);
+
+ IMFStreamDescriptor_Release(sd);
+ hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 1, &selected, &sd);
+ ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr);
+
+ hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &mth);
+ ok(hr == S_OK, "Failed to get media type handler, hr %#x.\n", hr);
+ hr = IMFMediaTypeHandler_GetCurrentMediaType(mth, &media_type);
+ ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr);
+
+ IMFTopologyNode_Release(src_node);
+ hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node);
+ ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr);
+
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)&test_media_source);
+ ok(hr == S_OK, "Failed to set node source, hr %#x.\n", hr);
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd);
+ ok(hr == S_OK, "Failed to set node pd, hr %#x.\n", hr);
+ hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd);
+ ok(hr == S_OK, "Failed to set node sd, hr %#x.\n", hr);
+
+ hr = IMFTopology_AddNode(topology, src_node);
+ ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr);
+
+ hr = MFCreateMediaType(&media_type);
+ ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr);
+
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+ ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr);
+
+ hr = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate);
+ ok(hr == S_OK, "Failed to create grabber sink, hr %#x.\n", hr);
+ IMFMediaType_Release(media_type);
+
+ hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink);
+ ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr);
+
+ hr = IMFMediaSink_GetStreamSinkByIndex(sink, 0, &stream_sink);
+ ok(hr == S_OK, "Failed to get stream sink, hr %#x.\n", hr);
+
+ hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node);
+ ok(hr == S_OK, "Failed to create output node, hr %#x.\n", hr);
+
+ hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)stream_sink);
+ ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr);
+
+ hr = IMFTopology_AddNode(topology, sink_node);
+ ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
+
+ hr = IMFTopology_GetNodeCount(topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+ ok(node_count == 4, "Unexpected node count.\n");
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ /* unconnected nodes in partial topology are discarded */
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+todo_wine
+ ok(node_count == 3, "Unexpected node count %d.\n", node_count);
+
+ IMFTopology_Release(full_topology);
+
+ /* connect nodes for second branch */
+ hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
+ ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr);
+
+ /* all branches must have valid media types */
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+todo_wine
+ ok(hr == MF_E_TOPO_CODEC_NOT_FOUND, "Unexpected hr %#x.\n", hr);
+
+ /* set valid media type for second branch */
+ hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth, 1, &media_type);
+ ok(hr == S_OK, "Failed getting media type, hr %#x.\n", hr);
+
+ hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, media_type);
+ ok(hr == S_OK, "Failed setting current media type, hr %#x.\n", hr);
+
+ hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
+ ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr);
+
+ hr = IMFTopology_GetNodeCount(full_topology, &node_count);
+ ok(hr == S_OK, "Failed to get node count, hr %#x.\n", hr);
+todo_wine
+ ok(node_count == 6, "Unexpected node count %d.\n", node_count);
+
+ IMFTopology_Release(full_topology);
+ IMFMediaType_Release(media_type);
+ IMFTopologyNode_Release(src_node);
+ IMFTopologyNode_Release(sink_node);
+ IMFMediaTypeHandler_Release(mth);
+ IMFStreamSink_Release(stream_sink);
+ IMFMediaSink_Release(sink);
+ IMFActivate_Release(sink_activate);
+ IMFStreamDescriptor_Release(sd);
+
+ IMFPresentationDescriptor_Release(pd);
+ IMFTopology_Release(topology);
IMFTopoLoader_Release(loader);
hr = MFShutdown();
--
2.28.0

View File

@ -0,0 +1,419 @@
From 01329fe9741031c7ae7cbe74f7b79d5a92f5e52c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Wed, 1 Apr 2020 16:11:07 -0500
Subject: [PATCH 06/54] mf: Partially implement the topology loader.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
dlls/mf/tests/mf.c | 3 -
dlls/mf/topology.c | 337 ++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 321 insertions(+), 19 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 8691ef55c9..f4f72dda5e 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1572,7 +1572,6 @@ static void test_topology_loader(void)
/* Empty topology */
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = MFCreateSourceResolver(&resolver);
@@ -1617,7 +1616,6 @@ todo_wine
/* Source node only. */
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
/* Add grabber sink. */
@@ -1643,7 +1641,6 @@ todo_wine
ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr);
hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL);
-todo_wine
ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr);
hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0);
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index abe66c45fd..d4a59f7136 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1933,47 +1933,352 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface)
return refcount;
}
+static void topology_loader_add_branch(struct topology *topology, IMFTopologyNode *first, IMFTopologyNode *last)
+{
+ IMFTopology *full_topo = &topology->IMFTopology_iface;
+ IMFTopologyNode *in, *out;
+ DWORD index;
+
+ in = first;
+ IMFTopology_AddNode(full_topo, in);
+ while (SUCCEEDED(IMFTopologyNode_GetOutput(in, 0, &out, &index)))
+ {
+ IMFTopology_AddNode(full_topo, out);
+ in = out;
+ }
+}
+
+static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD method)
+{
+ IMFStreamSink *streamsink;
+ IMFMediaTypeHandler *mth;
+ HRESULT hr;
+
+ IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink);
+ IMFStreamSink_GetMediaTypeHandler(streamsink, &mth);
+ if (method == MF_CONNECT_DIRECT)
+ {
+ if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype)))
+ return hr;
+ hr = IMFTopologyNode_ConnectOutput(src, 0, sink, 0);
+ return hr;
+ }
+ else
+ {
+ IMFTopologyNode *node_dec, *node_conv;
+ GUID major_type, subtype, mft_category;
+ MFT_REGISTER_TYPE_INFO mft_typeinfo;
+ UINT32 flags = MFT_ENUM_FLAG_ALL;
+ IMFActivate **activates_decs;
+ UINT32 num_activates_decs;
+ int i, j;
+
+ IMFMediaType_GetGUID(mediatype, &MF_MT_MAJOR_TYPE, &major_type);
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+ mft_category = MFT_CATEGORY_AUDIO_DECODER;
+ else if (IsEqualGUID(&major_type, &MFMediaType_Video))
+ mft_category = MFT_CATEGORY_VIDEO_DECODER;
+ else
+ return MF_E_INVALIDMEDIATYPE;
+
+ IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype);
+ mft_typeinfo.guidMajorType = major_type;
+ mft_typeinfo.guidSubtype = subtype;
+ MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_decs, &num_activates_decs);
+
+ /* for getting converters later on */
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+ mft_category = MFT_CATEGORY_AUDIO_EFFECT;
+ else if (IsEqualGUID(&major_type, &MFMediaType_Video))
+ mft_category = MFT_CATEGORY_VIDEO_EFFECT;
+
+ /*
+ * Iterate over number of decoders.
+ * Try to set input type on decoder with source's output media type.
+ * If succeeds, iterate over decoder's output media types.
+ * Try to set input type on sink with decoder's output media type.
+ * If fails, iterate over number of converters.
+ * Try to set input type on converter with decoder's output media type.
+ * If succeeds, iterate over converters output media types.
+ * Try to set input type on sink with converter's output media type.
+ */
+ for (i = 0; i < num_activates_decs; i++)
+ {
+ IMFTransform *decoder;
+
+ IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder);
+ if (SUCCEEDED(hr = IMFTransform_SetInputType(decoder, 0, mediatype, 0)))
+ {
+ UINT32 num_activates_convs;
+ IMFActivate **activates_convs;
+ IMFMediaType *decoder_mtype;
+
+ int count = 0;
+ while (SUCCEEDED(IMFTransform_GetOutputAvailableType(decoder, 0, count++, &decoder_mtype)))
+ {
+ IMFTransform *converter;
+
+ /* succeeded with source -> decoder -> sink */
+ if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, decoder_mtype)))
+ {
+ MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
+ IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
+ IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
+ IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0);
+
+ IMFActivate_ShutdownObject(activates_convs[i]);
+ return S_OK;
+ }
+
+ IMFMediaType_GetGUID(decoder_mtype, &MF_MT_SUBTYPE, &subtype);
+ mft_typeinfo.guidSubtype = subtype;
+ MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_convs, &num_activates_convs);
+ for (j = 0; j < num_activates_convs; j++)
+ {
+ IMFMediaType *converter_mtype;
+
+ IMFActivate_ActivateObject(activates_convs[j], &IID_IMFTransform, (void **)&converter);
+ if (SUCCEEDED(IMFTransform_SetInputType(converter, 0, decoder_mtype, 0)))
+ {
+ int count = 0;
+ while (SUCCEEDED(IMFTransform_GetOutputAvailableType(converter, 0, count++, &converter_mtype)))
+ {
+ /* succeeded with source -> decoder -> converter -> sink */
+ if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, converter_mtype)))
+ {
+ MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
+ IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
+ MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_conv);
+ IMFTopologyNode_SetObject(node_conv, (IUnknown *)converter);
+ IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
+ IMFTopologyNode_ConnectOutput(node_dec, 0, node_conv, 0);
+ IMFTopologyNode_ConnectOutput(node_conv, 0, sink, 0);
+
+ IMFActivate_ShutdownObject(activates_convs[j]);
+ IMFActivate_ShutdownObject(activates_decs[i]);
+ return S_OK;
+ }
+ }
+ }
+ IMFActivate_ShutdownObject(activates_convs[j]);
+ }
+ }
+ }
+ IMFActivate_ShutdownObject(activates_decs[i]);
+ }
+ }
+ return E_FAIL;
+}
+
+static HRESULT topology_loader_resolve_partial_topology(struct topology_node *src, struct topology_node *sink, struct topology *topology, struct topology **full_topology)
+{
+ IMFMediaTypeHandler *mth_src, *mth_sink;
+ IMFTopologyNode *clone_src, *clone_sink;
+ UINT32 method, enum_src_types, streamid;
+ IMFMediaType **src_mediatypes;
+ IMFStreamDescriptor *desc;
+ IMFAttributes *attrs_src;
+ IMFStreamSink *strm_sink;
+ IMFMediaType *mtype_src;
+ DWORD num_media_types;
+ HRESULT hr;
+ int i;
+
+ attrs_src = src->attributes;
+ if (FAILED(hr = IMFAttributes_GetUnknown(attrs_src, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&desc)))
+ return hr;
+ strm_sink = (IMFStreamSink *)sink->object;
+
+ if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(desc, &mth_src)))
+ {
+ IMFStreamDescriptor_Release(desc);
+ return hr;
+ }
+ if (FAILED(hr = IMFStreamSink_GetMediaTypeHandler(strm_sink, &mth_sink)))
+ {
+ IMFStreamDescriptor_Release(desc);
+ IMFMediaTypeHandler_Release(mth_src);
+ return hr;
+ }
+
+ hr = IMFTopology_GetUINT32(&topology->IMFTopology_iface, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, &enum_src_types);
+
+ mtype_src = NULL;
+ if (FAILED(hr) || !enum_src_types)
+ {
+ num_media_types = 1;
+ enum_src_types = 0;
+ if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(mth_src, &mtype_src)))
+ if (FAILED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, 0, &mtype_src)))
+ {
+ IMFMediaTypeHandler_Release(mth_src);
+ IMFMediaTypeHandler_Release(mth_sink);
+ IMFStreamDescriptor_Release(desc);
+ return hr;
+ }
+ }
+ else
+ IMFMediaTypeHandler_GetMediaTypeCount(mth_src, &num_media_types);
+
+ src_mediatypes = heap_alloc(sizeof(IMFMediaType *) * num_media_types);
+
+ if (mtype_src)
+ src_mediatypes[0] = mtype_src;
+ else
+ for (i = 0; i < num_media_types; i++)
+ IMFMediaTypeHandler_GetMediaTypeByIndex(mth_src, i, &src_mediatypes[i]);
+
+
+ MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &clone_src);
+ MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &clone_sink);
+ IMFTopologyNode_CloneFrom(clone_src, &src->IMFTopologyNode_iface);
+ IMFTopologyNode_CloneFrom(clone_sink, &sink->IMFTopologyNode_iface);
+
+ if (FAILED(IMFTopologyNode_GetUINT32(clone_sink, &MF_TOPONODE_STREAMID, &streamid)))
+ IMFTopologyNode_SetUINT32(clone_sink, &MF_TOPONODE_STREAMID, 0);
+
+ if (enum_src_types)
+ {
+ hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method);
+ if (hr == S_OK && method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)
+ {
+ for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+ for (i = 0; i < num_media_types; i++)
+ if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
+ {
+ topology_loader_add_branch(*full_topology, clone_src, clone_sink);
+ heap_free(src_mediatypes);
+ return S_OK;
+ }
+ }
+ else
+ {
+ for (i = 0; i < num_media_types; i++)
+ for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+ if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
+ {
+ topology_loader_add_branch(*full_topology, clone_src, clone_sink);
+ heap_free(src_mediatypes);
+ return S_OK;
+ }
+ }
+ }
+ else
+ {
+ if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, MF_CONNECT_DIRECT)))
+ {
+ topology_loader_add_branch(*full_topology, clone_src, clone_sink);
+ heap_free(src_mediatypes);
+ return S_OK;
+ }
+ }
+
+ heap_free(src_mediatypes);
+ return MF_E_TOPO_UNSUPPORTED;
+}
+
static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology,
IMFTopology **output_topology, IMFTopology *current_topology)
{
struct topology *topology = unsafe_impl_from_IMFTopology(input_topology);
+ struct topology_node *(*node_pairs)[2];
+ int num_connections;
IMFStreamSink *sink;
HRESULT hr;
- size_t i;
+ int i, idx;
FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology);
if (current_topology)
FIXME("Current topology instance is ignored.\n");
+ if (!topology || topology->nodes.count < 2)
+ return MF_E_TOPO_UNSUPPORTED;
+
+ num_connections = 0;
+ for (i = 0; i < topology->nodes.count; i++)
+ {
+ struct topology_node *node = topology->nodes.nodes[i];
+
+ if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
+ {
+ if (node->outputs.count && node->outputs.streams->connection)
+ num_connections++;
+ }
+ }
+
+ if (!num_connections)
+ return MF_E_TOPO_UNSUPPORTED;
+
+ node_pairs = heap_alloc_zero(sizeof(struct topology_node *[2]) * num_connections);
+
+ idx = 0;
for (i = 0; i < topology->nodes.count; ++i)
{
struct topology_node *node = topology->nodes.nodes[i];
- switch (node->node_type)
+ if (node->node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
{
- case MF_TOPOLOGY_OUTPUT_NODE:
- if (node->object)
+ if (node->outputs.count && node->outputs.streams->connection)
+ {
+ node_pairs[idx][0] = node;
+ if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_TRANSFORM_NODE)
{
- /* Sinks must be bound beforehand. */
- if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFStreamSink, (void **)&sink)))
- return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
- IMFStreamSink_Release(sink);
+ struct topology_node *sink = node->outputs.streams->connection;
+
+ while (sink && sink->node_type != MF_TOPOLOGY_OUTPUT_NODE && sink->outputs.count)
+ sink = sink->outputs.streams->connection;
+ if (!sink || !sink->outputs.count)
+ {
+ FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n");
+ heap_free(node_pairs);
+ return MF_E_TOPO_UNSUPPORTED;
+ }
+ node_pairs[idx][1] = sink;
}
- break;
- case MF_TOPOLOGY_SOURCESTREAM_NODE:
- if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL)))
- return hr;
- break;
- default:
- ;
+ else if (node->outputs.streams->connection->node_type == MF_TOPOLOGY_OUTPUT_NODE)
+ node_pairs[idx][1] = node->outputs.streams->connection;
+ else {
+ FIXME("Tee nodes currently unhandled.\n");
+ heap_free(node_pairs);
+ return MF_E_TOPO_UNSUPPORTED;
+ }
+ idx++;
+ }
}
}
+ /* all sinks must be activated */
+ for (i = 0; i < num_connections; i++)
+ {
+ if (FAILED(IUnknown_QueryInterface(node_pairs[i][1]->object, &IID_IMFStreamSink, (void **)&sink)))
+ {
+ FIXME("Check for MF_CONNECT_AS_OPTIONAL and MF_CONNECT_AS_OPTIONAL_BRANCH flags.\n");
+ heap_free(node_pairs);
+ return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED;
+ }
+ IMFStreamSink_Release(sink);
+ }
+
if (FAILED(hr = MFCreateTopology(output_topology)))
return hr;
- return IMFTopology_CloneFrom(*output_topology, input_topology);
+ /* resolve each branch */
+ for (i = 0; i < num_connections; i++)
+ {
+ struct topology_node *src = node_pairs[i][0];
+ struct topology_node *sink = node_pairs[i][1];
+ struct topology *full_topology = unsafe_impl_from_IMFTopology(*output_topology);
+
+ if (FAILED(hr = topology_loader_resolve_partial_topology(src, sink, topology, &full_topology)))
+ {
+ heap_free(node_pairs);
+ return hr;
+ }
+ }
+
+ heap_free(node_pairs);
+ return S_OK;
}
static const IMFTopoLoaderVtbl topologyloadervtbl =
--
2.28.0

View File

@ -0,0 +1,878 @@
From 97478b5836fca83cbb536420bc76eceee68d664a Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 25 Mar 2020 10:03:52 -0500
Subject: [PATCH 07/54] Implement stub bytestream handler and source.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/mfplat/tests/mfplat.c | 9 +-
dlls/winegstreamer/Makefile.in | 1 +
dlls/winegstreamer/gst_private.h | 6 +
dlls/winegstreamer/media_source.c | 680 +++++++++++++++++++
dlls/winegstreamer/mfplat.c | 9 +
dlls/winegstreamer/winegstreamer.rgs | 32 +
dlls/winegstreamer/winegstreamer_classes.idl | 7 +
include/mfidl.idl | 1 +
8 files changed, 740 insertions(+), 5 deletions(-)
create mode 100644 dlls/winegstreamer/media_source.c
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 01749dd9ef..c9548c6b18 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -529,7 +529,10 @@ static void test_source_resolver(void)
ok(obj_type == MF_OBJECT_MEDIASOURCE, "got %d\n", obj_type);
hr = IMFMediaSource_CreatePresentationDescriptor(mediasource, &descriptor);
+todo_wine
ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr);
+ if (FAILED(hr))
+ goto skip_source_tests;
ok(descriptor != NULL, "got %p\n", descriptor);
hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, 0, &selected, &sd);
@@ -540,10 +543,7 @@ static void test_source_resolver(void)
IMFStreamDescriptor_Release(sd);
hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
-todo_wine
ok(hr == S_OK, "Failed to get stream major type, hr %#x.\n", hr);
- if (FAILED(hr))
- goto skip_source_tests;
/* Check major/minor type for the test media. */
ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected major type %s.\n", debugstr_guid(&guid));
@@ -624,6 +624,7 @@ todo_wine
get_event((IMFMediaEventGenerator *)mediasource, MEEndOfPresentation, NULL);
IMFMediaTypeHandler_Release(handler);
+ IMFPresentationDescriptor_Release(descriptor);
hr = IMFMediaSource_Shutdown(mediasource);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
@@ -632,8 +633,6 @@ todo_wine
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
skip_source_tests:
-
- IMFPresentationDescriptor_Release(descriptor);
IMFMediaSource_Release(mediasource);
IMFByteStream_Release(stream);
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in
index 337c1086e6..e578d194f7 100644
--- a/dlls/winegstreamer/Makefile.in
+++ b/dlls/winegstreamer/Makefile.in
@@ -10,6 +10,7 @@ C_SRCS = \
gst_cbs.c \
gstdemux.c \
main.c \
+ media_source.c \
mediatype.c \
mfplat.c \
pin.c \
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index e6fb841fc8..71ca429088 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -54,4 +54,10 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
+enum source_type
+{
+ SOURCE_TYPE_MPEG_4,
+};
+HRESULT container_stream_handler_construct(REFIID riid, void **obj, enum source_type);
+
#endif /* __GST_PRIVATE_INCLUDED__ */
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
new file mode 100644
index 0000000000..df28f54444
--- /dev/null
+++ b/dlls/winegstreamer/media_source.c
@@ -0,0 +1,680 @@
+#include "gst_private.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include "mfapi.h"
+#include "mferror.h"
+#include "mfidl.h"
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+#include "wine/list.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+struct media_source
+{
+ IMFMediaSource IMFMediaSource_iface;
+ LONG ref;
+ IMFMediaEventQueue *event_queue;
+};
+
+static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
+}
+
+static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("(%p)->(%s %p)\n", source, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFMediaSource) ||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = &source->IMFMediaSource_iface;
+ }
+ else
+ {
+ FIXME("(%s, %p)\n", debugstr_guid(riid), out);
+ *out = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+ ULONG ref = InterlockedIncrement(&source->ref);
+
+ TRACE("(%p) ref=%u\n", source, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+ ULONG ref = InterlockedDecrement(&source->ref);
+
+ TRACE("(%p) ref=%u\n", source, ref);
+
+ if (!ref)
+ {
+ heap_free(source);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("(%p)->(%#x, %p)\n", source, flags, event);
+
+ return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
+}
+
+static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("(%p)->(%p, %p)\n", source, callback, state);
+
+ return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
+}
+
+static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("(%p)->(%p, %p)\n", source, result, event);
+
+ return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
+}
+
+static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
+ HRESULT hr, const PROPVARIANT *value)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ TRACE("(%p)->(%d, %s, %#x, %p)\n", source, event_type, debugstr_guid(ext_type), hr, value);
+
+ return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
+}
+
+static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ FIXME("(%p)->(%p): stub\n", source, characteristics);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ FIXME("(%p)->(%p): stub\n", source, descriptor);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
+ const GUID *time_format, const PROPVARIANT *start_position)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ FIXME("(%p)->(%p, %p, %p): stub\n", source, descriptor, time_format, start_position);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ FIXME("(%p): stub\n", source);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ FIXME("(%p): stub\n", source);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT media_source_teardown(struct media_source *source)
+{
+ if (source->event_queue)
+ IMFMediaEventQueue_Release(source->event_queue);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
+{
+ struct media_source *source = impl_from_IMFMediaSource(iface);
+
+ FIXME("(%p): stub\n", source);
+
+ return E_NOTIMPL;
+}
+
+static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
+{
+ media_source_QueryInterface,
+ media_source_AddRef,
+ media_source_Release,
+ media_source_GetEvent,
+ media_source_BeginGetEvent,
+ media_source_EndGetEvent,
+ media_source_QueueEvent,
+ media_source_GetCharacteristics,
+ media_source_CreatePresentationDescriptor,
+ media_source_Start,
+ media_source_Stop,
+ media_source_Pause,
+ media_source_Shutdown,
+};
+
+static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_type type, struct media_source **out_media_source)
+{
+ struct media_source *object = heap_alloc_zero(sizeof(*object));
+ HRESULT hr;
+
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
+ goto fail;
+
+ object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
+ object->ref = 1;
+
+ *out_media_source = object;
+ return S_OK;
+
+ fail:
+ WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
+
+ media_source_teardown(object);
+ heap_free(object);
+ return hr;
+}
+
+/* IMFByteStreamHandler */
+
+struct container_stream_handler_result
+{
+ struct list entry;
+ IMFAsyncResult *result;
+ MF_OBJECT_TYPE obj_type;
+ IUnknown *object;
+};
+
+struct container_stream_handler
+{
+ IMFByteStreamHandler IMFByteStreamHandler_iface;
+ IMFAsyncCallback IMFAsyncCallback_iface;
+ LONG refcount;
+ enum source_type type;
+ struct list results;
+ CRITICAL_SECTION cs;
+};
+
+static struct container_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
+{
+ return CONTAINING_RECORD(iface, struct container_stream_handler, IMFByteStreamHandler_iface);
+}
+
+static struct container_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct container_stream_handler, IMFAsyncCallback_iface);
+}
+
+static HRESULT WINAPI container_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFByteStreamHandler_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI container_stream_handler_AddRef(IMFByteStreamHandler *iface)
+{
+ struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
+ ULONG refcount = InterlockedIncrement(&handler->refcount);
+
+ TRACE("%p, refcount %u.\n", handler, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI container_stream_handler_Release(IMFByteStreamHandler *iface)
+{
+ struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
+ ULONG refcount = InterlockedDecrement(&handler->refcount);
+ struct container_stream_handler_result *result, *next;
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct container_stream_handler_result, entry)
+ {
+ list_remove(&result->entry);
+ IMFAsyncResult_Release(result->result);
+ if (result->object)
+ IUnknown_Release(result->object);
+ heap_free(result);
+ }
+ DeleteCriticalSection(&handler->cs);
+ heap_free(handler);
+ }
+
+ return refcount;
+}
+
+struct create_object_context
+{
+ IUnknown IUnknown_iface;
+ LONG refcount;
+
+ IPropertyStore *props;
+ IMFByteStream *stream;
+ WCHAR *url;
+ DWORD flags;
+};
+
+static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
+{
+ return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
+}
+
+static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
+{
+ struct create_object_context *context = impl_from_IUnknown(iface);
+ ULONG refcount = InterlockedIncrement(&context->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI create_object_context_Release(IUnknown *iface)
+{
+ struct create_object_context *context = impl_from_IUnknown(iface);
+ ULONG refcount = InterlockedDecrement(&context->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ if (context->props)
+ IPropertyStore_Release(context->props);
+ if (context->stream)
+ IMFByteStream_Release(context->stream);
+ if (context->url)
+ heap_free(context->url);
+ heap_free(context);
+ }
+
+ return refcount;
+}
+
+static const IUnknownVtbl create_object_context_vtbl =
+{
+ create_object_context_QueryInterface,
+ create_object_context_AddRef,
+ create_object_context_Release,
+};
+
+static WCHAR *heap_strdupW(const WCHAR *str)
+{
+ WCHAR *ret = NULL;
+
+ if (str)
+ {
+ unsigned int size;
+
+ size = (lstrlenW(str) + 1) * sizeof(WCHAR);
+ ret = heap_alloc(size);
+ if (ret)
+ memcpy(ret, str, size);
+ }
+
+ return ret;
+}
+
+static HRESULT WINAPI container_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
+ IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
+{
+ struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
+ struct create_object_context *context;
+ IMFAsyncResult *caller, *item;
+ HRESULT hr;
+
+ TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
+
+ if (cancel_cookie)
+ *cancel_cookie = NULL;
+
+ if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
+ return hr;
+
+ context = heap_alloc(sizeof(*context));
+ if (!context)
+ {
+ IMFAsyncResult_Release(caller);
+ return E_OUTOFMEMORY;
+ }
+
+ context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
+ context->refcount = 1;
+ context->props = props;
+ if (context->props)
+ IPropertyStore_AddRef(context->props);
+ context->flags = flags;
+ context->stream = stream;
+ if (context->stream)
+ IMFByteStream_AddRef(context->stream);
+ if (url)
+ context->url = heap_strdupW(url);
+ if (!context->stream)
+ {
+ IMFAsyncResult_Release(caller);
+ IUnknown_Release(&context->IUnknown_iface);
+ return E_OUTOFMEMORY;
+ }
+
+ hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
+ IUnknown_Release(&context->IUnknown_iface);
+ if (SUCCEEDED(hr))
+ {
+ if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
+ {
+ if (cancel_cookie)
+ {
+ *cancel_cookie = (IUnknown *)caller;
+ IUnknown_AddRef(*cancel_cookie);
+ }
+ }
+
+ IMFAsyncResult_Release(item);
+ }
+ IMFAsyncResult_Release(caller);
+
+ return hr;
+}
+
+static HRESULT WINAPI container_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
+ MF_OBJECT_TYPE *obj_type, IUnknown **object)
+{
+ struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
+ struct container_stream_handler_result *found = NULL, *cur;
+ HRESULT hr;
+
+ TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
+
+ EnterCriticalSection(&this->cs);
+
+ LIST_FOR_EACH_ENTRY(cur, &this->results, struct container_stream_handler_result, entry)
+ {
+ if (result == cur->result)
+ {
+ list_remove(&cur->entry);
+ found = cur;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&this->cs);
+
+ if (found)
+ {
+ *obj_type = found->obj_type;
+ *object = found->object;
+ hr = IMFAsyncResult_GetStatus(found->result);
+ IMFAsyncResult_Release(found->result);
+ heap_free(found);
+ }
+ else
+ {
+ *obj_type = MF_OBJECT_INVALID;
+ *object = NULL;
+ hr = MF_E_UNEXPECTED;
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI container_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie)
+{
+ struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
+ struct container_stream_handler_result *found = NULL, *cur;
+
+ TRACE("%p, %p.\n", iface, cancel_cookie);
+
+ EnterCriticalSection(&this->cs);
+
+ LIST_FOR_EACH_ENTRY(cur, &this->results, struct container_stream_handler_result, entry)
+ {
+ if (cancel_cookie == (IUnknown *)cur->result)
+ {
+ list_remove(&cur->entry);
+ found = cur;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&this->cs);
+
+ if (found)
+ {
+ IMFAsyncResult_Release(found->result);
+ if (found->object)
+ IUnknown_Release(found->object);
+ heap_free(found);
+ }
+
+ return found ? S_OK : MF_E_UNEXPECTED;
+}
+
+static HRESULT WINAPI container_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
+{
+ FIXME("stub (%p %p)\n", iface, bytes);
+ return E_NOTIMPL;
+}
+
+static const IMFByteStreamHandlerVtbl container_stream_handler_vtbl =
+{
+ container_stream_handler_QueryInterface,
+ container_stream_handler_AddRef,
+ container_stream_handler_Release,
+ container_stream_handler_BeginCreateObject,
+ container_stream_handler_EndCreateObject,
+ container_stream_handler_CancelObjectCreation,
+ container_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
+};
+
+static HRESULT WINAPI container_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
+{
+ if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFAsyncCallback_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI container_stream_handler_callback_AddRef(IMFAsyncCallback *iface)
+{
+ struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
+ return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
+}
+
+static ULONG WINAPI container_stream_handler_callback_Release(IMFAsyncCallback *iface)
+{
+ struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
+ return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
+}
+
+static HRESULT WINAPI container_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT container_stream_handler_create_object(struct container_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags,
+ IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type)
+{
+ TRACE("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
+
+ if (flags & MF_RESOLUTION_MEDIASOURCE)
+ {
+ HRESULT hr;
+ struct media_source *new_source;
+
+ if (FAILED(hr = media_source_constructor(stream, This->type, &new_source)))
+ return hr;
+
+ TRACE("->(%p)\n", new_source);
+
+ *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
+ *out_obj_type = MF_OBJECT_MEDIASOURCE;
+
+ return S_OK;
+ }
+ else
+ {
+ FIXME("flags = %08x\n", flags);
+ return E_NOTIMPL;
+ }
+}
+
+static HRESULT WINAPI container_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+ struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
+ struct container_stream_handler_result *handler_result;
+ MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
+ IUnknown *object = NULL, *context_object;
+ struct create_object_context *context;
+ IMFAsyncResult *caller;
+ HRESULT hr;
+
+ caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
+
+ if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
+ {
+ WARN("Expected context set for callee result.\n");
+ return hr;
+ }
+
+ context = impl_from_IUnknown(context_object);
+
+ hr = container_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type);
+
+ handler_result = heap_alloc(sizeof(*handler_result));
+ if (handler_result)
+ {
+ handler_result->result = caller;
+ IMFAsyncResult_AddRef(handler_result->result);
+ handler_result->obj_type = obj_type;
+ handler_result->object = object;
+
+ EnterCriticalSection(&handler->cs);
+ list_add_tail(&handler->results, &handler_result->entry);
+ LeaveCriticalSection(&handler->cs);
+ }
+ else
+ {
+ if (object)
+ IUnknown_Release(object);
+ hr = E_OUTOFMEMORY;
+ }
+
+ IUnknown_Release(&context->IUnknown_iface);
+
+ IMFAsyncResult_SetStatus(caller, hr);
+ MFInvokeCallback(caller);
+
+ return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl container_stream_handler_callback_vtbl =
+{
+ container_stream_handler_callback_QueryInterface,
+ container_stream_handler_callback_AddRef,
+ container_stream_handler_callback_Release,
+ container_stream_handler_callback_GetParameters,
+ container_stream_handler_callback_Invoke,
+};
+
+HRESULT container_stream_handler_construct(REFIID riid, void **obj, enum source_type type)
+{
+ struct container_stream_handler *this;
+ HRESULT hr;
+
+ TRACE("%s, %p.\n", debugstr_guid(riid), obj);
+
+ this = heap_alloc_zero(sizeof(*this));
+ if (!this)
+ return E_OUTOFMEMORY;
+
+ list_init(&this->results);
+ InitializeCriticalSection(&this->cs);
+
+ this->type = type;
+ this->IMFByteStreamHandler_iface.lpVtbl = &container_stream_handler_vtbl;
+ this->IMFAsyncCallback_iface.lpVtbl = &container_stream_handler_callback_vtbl;
+ this->refcount = 1;
+
+ hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
+ IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
+
+ return hr;
+}
\ No newline at end of file
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 55b9b08876..16e55247de 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -398,6 +398,11 @@ failed:
return hr;
}
+static HRESULT mp4_stream_handler_create(REFIID riid, void **ret)
+{
+ return container_stream_handler_construct(riid, ret, SOURCE_TYPE_MPEG_4);
+}
+
static const struct class_object
{
const GUID *clsid;
@@ -406,6 +411,7 @@ static const struct class_object
class_objects[] =
{
{ &CLSID_VideoProcessorMFT, &video_processor_create },
+ { &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create },
};
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
@@ -414,6 +420,9 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
unsigned int i;
HRESULT hr;
+ if (!(init_gstreamer()))
+ return CLASS_E_CLASSNOTAVAILABLE;
+
for (i = 0; i < ARRAY_SIZE(class_objects); ++i)
{
if (IsEqualGUID(class_objects[i].clsid, rclsid))
diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs
index 923ba673f8..0bc26761e9 100644
--- a/dlls/winegstreamer/winegstreamer.rgs
+++ b/dlls/winegstreamer/winegstreamer.rgs
@@ -12,3 +12,35 @@ HKCR
}
}
}
+
+HKLM
+{
+ NoRemove 'Software'
+ {
+ NoRemove 'Microsoft'
+ {
+ NoRemove 'Windows Media Foundation'
+ {
+ NoRemove 'ByteStreamHandlers'
+ {
+ '.m4v'
+ {
+ val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
+ }
+ '.mp4'
+ {
+ val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
+ }
+ 'video/m4v'
+ {
+ val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
+ }
+ 'video/mp4'
+ {
+ val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl
index fa0e178405..997a28b052 100644
--- a/dlls/winegstreamer/winegstreamer_classes.idl
+++ b/dlls/winegstreamer/winegstreamer_classes.idl
@@ -54,3 +54,10 @@ coclass Gstreamer_Splitter {}
uuid(88753b26-5b24-49bd-b2e7-0c445c78c982)
]
coclass VideoProcessorMFT {}
+
+[
+ helpstring("MP4 Byte Stream Handler"),
+ threading(both),
+ uuid(271c3902-6095-4c45-a22f-20091816ee9e)
+]
+coclass MPEG4ByteStreamHandler {}
diff --git a/include/mfidl.idl b/include/mfidl.idl
index 4ceeb707bd..fc13dfba7a 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -1241,3 +1241,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_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
\ No newline at end of file
--
2.28.0

View File

@ -0,0 +1,154 @@
From 431129df1f3ee134e792b05456325c91d76a683d Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 30 Mar 2020 15:19:01 -0500
Subject: [PATCH 08/54] winegstreamer: Implement IMFMediaSource::Shutdown.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/mfplat/tests/mfplat.c | 2 +-
dlls/winegstreamer/media_source.c | 39 +++++++++++++++++++++++++++++--
2 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index c9548c6b18..af7e0d0459 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -626,13 +626,13 @@ todo_wine
IMFMediaTypeHandler_Release(handler);
IMFPresentationDescriptor_Release(descriptor);
+skip_source_tests:
hr = IMFMediaSource_Shutdown(mediasource);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaSource_CreatePresentationDescriptor(mediasource, NULL);
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
-skip_source_tests:
IMFMediaSource_Release(mediasource);
IMFByteStream_Release(stream);
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index df28f54444..09a40a0620 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -20,6 +20,14 @@ struct media_source
IMFMediaSource IMFMediaSource_iface;
LONG ref;
IMFMediaEventQueue *event_queue;
+ enum
+ {
+ SOURCE_OPENING,
+ SOURCE_STOPPED, /* (READY) */
+ SOURCE_PAUSED,
+ SOURCE_RUNNING,
+ SOURCE_SHUTDOWN,
+ } state;
};
static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
@@ -81,6 +89,9 @@ static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags,
TRACE("(%p)->(%#x, %p)\n", source, flags, event);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
}
@@ -90,6 +101,9 @@ static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsync
TRACE("(%p)->(%p, %p)\n", source, callback, state);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
}
@@ -99,6 +113,9 @@ static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncRe
TRACE("(%p)->(%p, %p)\n", source, result, event);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
}
@@ -109,6 +126,9 @@ static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventT
TRACE("(%p)->(%d, %s, %#x, %p)\n", source, event_type, debugstr_guid(ext_type), hr, value);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
}
@@ -118,6 +138,9 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO
FIXME("(%p)->(%p): stub\n", source, characteristics);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return E_NOTIMPL;
}
@@ -127,6 +150,9 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *
FIXME("(%p)->(%p): stub\n", source, descriptor);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return E_NOTIMPL;
}
@@ -137,6 +163,9 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD
FIXME("(%p)->(%p, %p, %p): stub\n", source, descriptor, time_format, start_position);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return E_NOTIMPL;
}
@@ -146,6 +175,9 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
FIXME("(%p): stub\n", source);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return E_NOTIMPL;
}
@@ -170,9 +202,10 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
- FIXME("(%p): stub\n", source);
+ TRACE("(%p)\n", source);
- return E_NOTIMPL;
+ source->state = SOURCE_SHUTDOWN;
+ return media_source_teardown(source);
}
static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
@@ -203,6 +236,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
+ object->state = SOURCE_STOPPED;
+
object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
object->ref = 1;
--
2.28.0

View File

@ -0,0 +1,441 @@
From 34ca87dde0bd4e3cab92aaf674903791de20bdc0 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 30 Mar 2020 14:19:35 -0500
Subject: [PATCH 09/54] winegstreamer: Add a GstPad wrapping the media source's
bytestream.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_cbs.c | 58 ++++++++
dlls/winegstreamer/gst_cbs.h | 12 +-
dlls/winegstreamer/media_source.c | 237 +++++++++++++++++++++++++++++-
3 files changed, 302 insertions(+), 5 deletions(-)
diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
index bf7103b160..dfe33dd627 100644
--- a/dlls/winegstreamer/gst_cbs.c
+++ b/dlls/winegstreamer/gst_cbs.c
@@ -49,6 +49,8 @@ static void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user)
if (cbdata->type < GSTDEMUX_MAX)
perform_cb_gstdemux(cbdata);
+ else if (cbdata->type < MEDIA_SOURCE_MAX)
+ perform_cb_media_source(cbdata);
pthread_mutex_lock(&cbdata->lock);
cbdata->finished = 1;
@@ -301,3 +303,59 @@ gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
return cbdata.u.query_sink_data.ret;
}
+
+GstFlowReturn pull_from_bytestream_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
+ GstBuffer **buf)
+{
+ struct cb_data cbdata = { PULL_FROM_BYTESTREAM };
+
+ cbdata.u.getrange_data.pad = pad;
+ cbdata.u.getrange_data.parent = parent;
+ cbdata.u.getrange_data.ofs = ofs;
+ cbdata.u.getrange_data.len = len;
+ cbdata.u.getrange_data.buf = buf;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.getrange_data.ret;
+}
+
+gboolean query_bytestream_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
+{
+ struct cb_data cbdata = { QUERY_BYTESTREAM };
+
+ cbdata.u.query_function_data.pad = pad;
+ cbdata.u.query_function_data.parent = parent;
+ cbdata.u.query_function_data.query = query;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.query_function_data.ret;
+}
+
+gboolean activate_bytestream_pad_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
+{
+ struct cb_data cbdata = { ACTIVATE_BYTESTREAM_PAD_MODE };
+
+ cbdata.u.activate_mode_data.pad = pad;
+ cbdata.u.activate_mode_data.parent = parent;
+ cbdata.u.activate_mode_data.mode = mode;
+ cbdata.u.activate_mode_data.activate = activate;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.activate_mode_data.ret;
+}
+
+gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, GstEvent *event)
+{
+ struct cb_data cbdata = { PROCESS_BYTESTREAM_PAD_EVENT };
+
+ cbdata.u.event_src_data.pad = pad;
+ cbdata.u.event_src_data.parent = parent;
+ cbdata.u.event_src_data.event = event;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.event_src_data.ret;
+}
\ No newline at end of file
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
index 4725f23ad1..10e999feea 100644
--- a/dlls/winegstreamer/gst_cbs.h
+++ b/dlls/winegstreamer/gst_cbs.h
@@ -43,7 +43,12 @@ enum CB_TYPE {
AUTOPLUG_BLACKLIST,
UNKNOWN_TYPE,
QUERY_SINK,
- GSTDEMUX_MAX
+ GSTDEMUX_MAX,
+ PULL_FROM_BYTESTREAM,
+ QUERY_BYTESTREAM,
+ ACTIVATE_BYTESTREAM_PAD_MODE,
+ PROCESS_BYTESTREAM_PAD_EVENT,
+ MEDIA_SOURCE_MAX,
};
struct cb_data {
@@ -138,6 +143,7 @@ struct cb_data {
void mark_wine_thread(void) DECLSPEC_HIDDEN;
void perform_cb_gstdemux(struct cb_data *data) DECLSPEC_HIDDEN;
+void perform_cb_media_source(struct cb_data *data) DECLSPEC_HIDDEN;
GstBusSyncReply watch_bus_wrapper(GstBus *bus, GstMessage *msg, gpointer user) DECLSPEC_HIDDEN;
void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
@@ -154,5 +160,9 @@ GstAutoplugSelectResult autoplug_blacklist_wrapper(GstElement *bin, GstPad *pad,
void unknown_type_wrapper(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer user) DECLSPEC_HIDDEN;
void Gstreamer_transform_pad_added_wrapper(GstElement *filter, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
+GstFlowReturn pull_from_bytestream_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len, GstBuffer **buf) DECLSPEC_HIDDEN;
+gboolean query_bytestream_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
+gboolean activate_bytestream_pad_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN;
+gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN;
#endif
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 09a40a0620..48119e4a89 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -1,4 +1,9 @@
+#include "config.h"
+
+#include <gst/gst.h>
+
#include "gst_private.h"
+#include "gst_cbs.h"
#include <stdarg.h>
@@ -8,6 +13,7 @@
#include "mfapi.h"
#include "mferror.h"
#include "mfidl.h"
+#include "mfobjects.h"
#include "wine/debug.h"
#include "wine/heap.h"
@@ -15,11 +21,24 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+static struct source_desc
+{
+ GstStaticCaps bytestream_caps;
+} source_descs[] =
+{
+ {/*SOURCE_TYPE_MPEG_4*/
+ GST_STATIC_CAPS("video/quicktime"),
+ }
+};
+
struct media_source
{
IMFMediaSource IMFMediaSource_iface;
LONG ref;
+ enum source_type type;
IMFMediaEventQueue *event_queue;
+ IMFByteStream *byte_stream;
+ GstPad *my_src;
enum
{
SOURCE_OPENING,
@@ -35,6 +54,154 @@ static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *ifac
return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
}
+GstFlowReturn pull_from_bytestream(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
+ GstBuffer **buf)
+{
+ struct media_source *source = gst_pad_get_element_private(pad);
+ IMFByteStream *byte_stream = source->byte_stream;
+ ULONG bytes_read;
+ GstMapInfo info;
+ BOOL is_eof;
+ HRESULT hr;
+
+ TRACE("gstreamer requesting %u bytes at %s from source %p into buffer %p\n", len, wine_dbgstr_longlong(ofs), source, buf);
+
+ if (ofs != GST_BUFFER_OFFSET_NONE)
+ {
+ if (FAILED(IMFByteStream_SetCurrentPosition(byte_stream, ofs)))
+ return GST_FLOW_ERROR;
+ }
+
+ if (FAILED(IMFByteStream_IsEndOfStream(byte_stream, &is_eof)))
+ return GST_FLOW_ERROR;
+ if (is_eof)
+ return GST_FLOW_EOS;
+
+ if (!(*buf))
+ *buf = gst_buffer_new_and_alloc(len);
+ gst_buffer_map(*buf, &info, GST_MAP_WRITE);
+ hr = IMFByteStream_Read(byte_stream, info.data, len, &bytes_read);
+ gst_buffer_unmap(*buf, &info);
+
+ gst_buffer_set_size(*buf, bytes_read);
+
+ if (FAILED(hr))
+ {
+ return GST_FLOW_ERROR;
+ }
+ GST_BUFFER_OFFSET(*buf) = ofs;
+ return GST_FLOW_OK;
+}
+
+static gboolean query_bytestream(GstPad *pad, GstObject *parent, GstQuery *query)
+{
+ struct media_source *source = gst_pad_get_element_private(pad);
+ GstFormat format;
+ QWORD bytestream_len;
+
+ TRACE("GStreamer queries source %p for %s\n", source, GST_QUERY_TYPE_NAME(query));
+
+ if (FAILED(IMFByteStream_GetLength(source->byte_stream, &bytestream_len)))
+ return FALSE;
+
+ switch (GST_QUERY_TYPE(query))
+ {
+ case GST_QUERY_DURATION:
+ {
+ gst_query_parse_duration (query, &format, NULL);
+ if (format == GST_FORMAT_PERCENT) {
+ gst_query_set_duration (query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
+ return TRUE;
+ }
+ else if (format == GST_FORMAT_BYTES)
+ {
+ QWORD length;
+ IMFByteStream_GetLength(source->byte_stream, &length);
+ gst_query_set_duration (query, GST_FORMAT_BYTES, length);
+ return TRUE;
+ }
+ return FALSE;
+ }
+ case GST_QUERY_SEEKING:
+ {
+ gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+ if (format != GST_FORMAT_BYTES)
+ {
+ WARN("Cannot seek using format \"%s\".\n", gst_format_get_name(format));
+ return FALSE;
+ }
+ gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, bytestream_len);
+ return TRUE;
+ }
+ case GST_QUERY_SCHEDULING:
+ {
+ gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
+ gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL);
+ return TRUE;
+ }
+ case GST_QUERY_CAPS:
+ {
+ GstCaps *caps, *filter;
+
+ gst_query_parse_caps(query, &filter);
+
+ caps = gst_static_caps_get(&source_descs[source->type].bytestream_caps);
+
+ if (filter) {
+ GstCaps* filtered;
+ filtered = gst_caps_intersect_full(
+ filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref(caps);
+ caps = filtered;
+ }
+ gst_query_set_caps_result(query, caps);
+ gst_caps_unref(caps);
+ return TRUE;
+ }
+ default:
+ {
+ WARN("Unhandled query type %s\n", GST_QUERY_TYPE_NAME(query));
+ return FALSE;
+ }
+ }
+}
+
+static gboolean activate_bytestream_pad_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
+{
+ struct media_source *source = gst_pad_get_element_private(pad);
+
+ TRACE("%s source pad for mediasource %p in %s mode.\n",
+ activate ? "Activating" : "Deactivating", source, gst_pad_mode_get_name(mode));
+
+ switch (mode) {
+ case GST_PAD_MODE_PULL:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ return FALSE;
+}
+
+static gboolean process_bytestream_pad_event(GstPad *pad, GstObject *parent, GstEvent *event)
+{
+ struct media_source *source = gst_pad_get_element_private(pad);
+
+ TRACE("source %p, type \"%s\".\n", source, GST_EVENT_TYPE_NAME(event));
+
+ switch (event->type) {
+ /* the seek event should fail in pull mode */
+ case GST_EVENT_SEEK:
+ return FALSE;
+ default:
+ WARN("Ignoring \"%s\" event.\n", GST_EVENT_TYPE_NAME(event));
+ case GST_EVENT_TAG:
+ case GST_EVENT_QOS:
+ case GST_EVENT_RECONFIGURE:
+ return gst_pad_event_default(pad, parent, event);
+ }
+ return TRUE;
+}
+
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
@@ -187,13 +354,20 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
FIXME("(%p): stub\n", source);
+ if (source->state == SOURCE_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
return E_NOTIMPL;
}
static HRESULT media_source_teardown(struct media_source *source)
{
+ if (source->my_src)
+ gst_object_unref(GST_OBJECT(source->my_src));
if (source->event_queue)
IMFMediaEventQueue_Release(source->event_queue);
+ if (source->byte_stream)
+ IMFByteStream_Release(source->byte_stream);
return S_OK;
}
@@ -227,19 +401,35 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_type type, struct media_source **out_media_source)
{
+ GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE(
+ "mf_src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ source_descs[type].bytestream_caps);
+
struct media_source *object = heap_alloc_zero(sizeof(*object));
HRESULT hr;
if (!object)
return E_OUTOFMEMORY;
+ object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
+ object->ref = 1;
+ object->type = type;
+ object->byte_stream = bytestream;
+ IMFByteStream_AddRef(bytestream);
+
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
- object->state = SOURCE_STOPPED;
+ object->my_src = gst_pad_new_from_static_template(&src_template, "mf-src");
+ gst_pad_set_element_private(object->my_src, object);
+ gst_pad_set_getrange_function(object->my_src, pull_from_bytestream_wrapper);
+ gst_pad_set_query_function(object->my_src, query_bytestream_wrapper);
+ gst_pad_set_activatemode_function(object->my_src, activate_bytestream_pad_mode_wrapper);
+ gst_pad_set_event_function(object->my_src, process_bytestream_pad_event_wrapper);
- object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
- object->ref = 1;
+ object->state = SOURCE_STOPPED;
*out_media_source = object;
return S_OK;
@@ -249,6 +439,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
media_source_teardown(object);
heap_free(object);
+ *out_media_source = NULL;
return hr;
}
@@ -712,4 +903,42 @@ HRESULT container_stream_handler_construct(REFIID riid, void **obj, enum source_
IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
return hr;
-}
\ No newline at end of file
+}
+
+/* helper for callback forwarding */
+void perform_cb_media_source(struct cb_data *cbdata)
+{
+ switch(cbdata->type)
+ {
+ case PULL_FROM_BYTESTREAM:
+ {
+ struct getrange_data *data = &cbdata->u.getrange_data;
+ cbdata->u.getrange_data.ret = pull_from_bytestream(data->pad, data->parent,
+ data->ofs, data->len, data->buf);
+ break;
+ }
+ case QUERY_BYTESTREAM:
+ {
+ struct query_function_data *data = &cbdata->u.query_function_data;
+ cbdata->u.query_function_data.ret = query_bytestream(data->pad, data->parent, data->query);
+ break;
+ }
+ case ACTIVATE_BYTESTREAM_PAD_MODE:
+ {
+ struct activate_mode_data *data = &cbdata->u.activate_mode_data;
+ cbdata->u.activate_mode_data.ret = activate_bytestream_pad_mode(data->pad, data->parent, data->mode, data->activate);
+ break;
+ }
+ case PROCESS_BYTESTREAM_PAD_EVENT:
+ {
+ struct event_src_data *data = &cbdata->u.event_src_data;
+ cbdata->u.event_src_data.ret = process_bytestream_pad_event(data->pad, data->parent, data->event);
+ break;
+ }
+ default:
+ {
+ ERR("Wrong callback forwarder called\n");
+ return;
+ }
+ }
+}
--
2.28.0

View File

@ -0,0 +1,221 @@
From 42170f6bd111e333694f4122e38944c5f87ac1f2 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 31 Mar 2020 13:34:57 -0500
Subject: [PATCH 10/54] winegstreamer: Find an appropriate demuxer for the
source.
We can add a path later which uses decodebin as the demuxer, for use with formats not supported on windows. (like Theora)
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_cbs.c | 15 ++++-
dlls/winegstreamer/gst_cbs.h | 2 +
dlls/winegstreamer/media_source.c | 99 ++++++++++++++++++++++++++++++-
3 files changed, 114 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
index dfe33dd627..cf49745f1d 100644
--- a/dlls/winegstreamer/gst_cbs.c
+++ b/dlls/winegstreamer/gst_cbs.c
@@ -358,4 +358,17 @@ gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, Gs
call_cb(&cbdata);
return cbdata.u.event_src_data.ret;
-}
\ No newline at end of file
+}
+
+GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user)
+{
+ struct cb_data cbdata = { WATCH_SOURCE_BUS };
+
+ cbdata.u.watch_bus_data.bus = bus;
+ cbdata.u.watch_bus_data.msg = message;
+ cbdata.u.watch_bus_data.user = user;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.watch_bus_data.ret;
+}
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
index 10e999feea..0d7acaf0b8 100644
--- a/dlls/winegstreamer/gst_cbs.h
+++ b/dlls/winegstreamer/gst_cbs.h
@@ -48,6 +48,7 @@ enum CB_TYPE {
QUERY_BYTESTREAM,
ACTIVATE_BYTESTREAM_PAD_MODE,
PROCESS_BYTESTREAM_PAD_EVENT,
+ WATCH_SOURCE_BUS,
MEDIA_SOURCE_MAX,
};
@@ -164,5 +165,6 @@ GstFlowReturn pull_from_bytestream_wrapper(GstPad *pad, GstObject *parent, guint
gboolean query_bytestream_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
gboolean activate_bytestream_pad_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN;
gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN;
+GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) DECLSPEC_HIDDEN;
#endif
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 48119e4a89..e1f5c77375 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -38,7 +38,12 @@ struct media_source
enum source_type type;
IMFMediaEventQueue *event_queue;
IMFByteStream *byte_stream;
- GstPad *my_src;
+ struct media_stream **streams;
+ ULONG stream_count;
+ GstBus *bus;
+ GstElement *container;
+ GstElement *demuxer;
+ GstPad *my_src, *their_sink;
enum
{
SOURCE_OPENING,
@@ -202,6 +207,37 @@ static gboolean process_bytestream_pad_event(GstPad *pad, GstObject *parent, Gst
return TRUE;
}
+GstBusSyncReply watch_source_bus(GstBus *bus, GstMessage *message, gpointer user)
+{
+ struct media_source *source = (struct media_source *) user;
+ gchar *dbg_info = NULL;
+ GError *err = NULL;
+
+ TRACE("source %p message type %s\n", source, GST_MESSAGE_TYPE_NAME(message));
+
+ switch (message->type)
+ {
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error(message, &err, &dbg_info);
+ ERR("%s: %s\n", GST_OBJECT_NAME(message->src), err->message);
+ ERR("%s\n", dbg_info);
+ g_error_free(err);
+ g_free(dbg_info);
+ break;
+ case GST_MESSAGE_WARNING:
+ gst_message_parse_warning(message, &err, &dbg_info);
+ WARN("%s: %s\n", GST_OBJECT_NAME(message->src), err->message);
+ WARN("%s\n", dbg_info);
+ g_error_free(err);
+ g_free(dbg_info);
+ break;
+ default:
+ break;
+ }
+
+ return GST_BUS_PASS;
+}
+
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
@@ -364,6 +400,13 @@ static HRESULT media_source_teardown(struct media_source *source)
{
if (source->my_src)
gst_object_unref(GST_OBJECT(source->my_src));
+ if (source->their_sink)
+ gst_object_unref(GST_OBJECT(source->their_sink));
+ if (source->container)
+ {
+ gst_element_set_state(source->container, GST_STATE_NULL);
+ gst_object_unref(GST_OBJECT(source->container));
+ }
if (source->event_queue)
IMFMediaEventQueue_Release(source->event_queue);
if (source->byte_stream)
@@ -408,7 +451,10 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
source_descs[type].bytestream_caps);
struct media_source *object = heap_alloc_zero(sizeof(*object));
+ GList *demuxer_list_one, *demuxer_list_two;
+ GstElementFactory *demuxer_factory = NULL;
HRESULT hr;
+ int ret;
if (!object)
return E_OUTOFMEMORY;
@@ -422,6 +468,11 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
+ object->container = gst_bin_new(NULL);
+ object->bus = gst_bus_new();
+ gst_bus_set_sync_handler(object->bus, watch_source_bus_wrapper, object, NULL);
+ gst_element_set_bus(object->container, object->bus);
+
object->my_src = gst_pad_new_from_static_template(&src_template, "mf-src");
gst_pad_set_element_private(object->my_src, object);
gst_pad_set_getrange_function(object->my_src, pull_from_bytestream_wrapper);
@@ -429,6 +480,44 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
gst_pad_set_activatemode_function(object->my_src, activate_bytestream_pad_mode_wrapper);
gst_pad_set_event_function(object->my_src, process_bytestream_pad_event_wrapper);
+ /* Find demuxer */
+ demuxer_list_one = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DEMUXER, 1);
+
+ demuxer_list_two = gst_element_factory_list_filter(demuxer_list_one, gst_static_caps_get(&source_descs[type].bytestream_caps), GST_PAD_SINK, 0);
+ gst_plugin_feature_list_free(demuxer_list_one);
+
+ if (!(g_list_length(demuxer_list_two)))
+ {
+ ERR("Failed to find demuxer for source.\n");
+ gst_plugin_feature_list_free(demuxer_list_two);
+ hr = E_FAIL;
+ goto fail;
+ }
+
+ demuxer_factory = g_list_first(demuxer_list_two)->data;
+ gst_object_ref(demuxer_factory);
+ gst_plugin_feature_list_free(demuxer_list_two);
+
+ TRACE("Found demuxer %s.\n", GST_ELEMENT_NAME(demuxer_factory));
+
+ object->demuxer = gst_element_factory_create(demuxer_factory, NULL);
+ if (!(object->demuxer))
+ {
+ WARN("Failed to create demuxer for source\n");
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+ gst_bin_add(GST_BIN(object->container), object->demuxer);
+
+ object->their_sink = gst_element_get_static_pad(object->demuxer, "sink");
+
+ if ((ret = gst_pad_link(object->my_src, object->their_sink)) < 0)
+ {
+ WARN("Failed to link our bytestream pad to the demuxer input\n");
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+
object->state = SOURCE_STOPPED;
*out_media_source = object;
@@ -437,6 +526,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
fail:
WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
+ if (demuxer_factory)
+ gst_object_unref(demuxer_factory);
media_source_teardown(object);
heap_free(object);
*out_media_source = NULL;
@@ -935,6 +1026,12 @@ void perform_cb_media_source(struct cb_data *cbdata)
cbdata->u.event_src_data.ret = process_bytestream_pad_event(data->pad, data->parent, data->event);
break;
}
+ case WATCH_SOURCE_BUS:
+ {
+ struct watch_bus_data *data = &cbdata->u.watch_bus_data;
+ cbdata->u.watch_bus_data.ret = watch_source_bus(data->bus, data->msg, data->user);
+ break;
+ }
default:
{
ERR("Wrong callback forwarder called\n");
--
2.28.0

View File

@ -0,0 +1,584 @@
From 9a688b8b82d57f2fcf482b2aff30a28c2acf13bb Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 20 Apr 2020 13:02:23 -0500
Subject: [PATCH 11/54] winegstreamer: Use the demuxer to establish
IMFMediaStreams.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_cbs.c | 44 ++++
dlls/winegstreamer/gst_cbs.h | 13 +
dlls/winegstreamer/media_source.c | 404 ++++++++++++++++++++++++++++++
3 files changed, 461 insertions(+)
diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
index cf49745f1d..d2d36aeb86 100644
--- a/dlls/winegstreamer/gst_cbs.c
+++ b/dlls/winegstreamer/gst_cbs.c
@@ -372,3 +372,47 @@ GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpoin
return cbdata.u.watch_bus_data.ret;
}
+
+void source_stream_added_wrapper(GstElement *bin, GstPad *pad, gpointer user)
+{
+ struct cb_data cbdata = { SOURCE_STREAM_ADDED };
+
+ cbdata.u.pad_added_data.element = bin;
+ cbdata.u.pad_added_data.pad = pad;
+ cbdata.u.pad_added_data.user = user;
+
+ call_cb(&cbdata);
+}
+
+void source_stream_removed_wrapper(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct cb_data cbdata = { SOURCE_STREAM_REMOVED };
+
+ cbdata.u.pad_removed_data.element = element;
+ cbdata.u.pad_removed_data.pad = pad;
+ cbdata.u.pad_removed_data.user = user;
+
+ call_cb(&cbdata);
+}
+
+void source_all_streams_wrapper(GstElement *element, gpointer user)
+{
+ struct cb_data cbdata = { SOURCE_ALL_STREAMS };
+
+ cbdata.u.no_more_pads_data.element = element;
+ cbdata.u.no_more_pads_data.user = user;
+
+ call_cb(&cbdata);
+}
+
+GstFlowReturn stream_new_sample_wrapper(GstElement *appsink, gpointer user)
+{
+ struct cb_data cbdata = { STREAM_NEW_SAMPLE };
+
+ cbdata.u.new_sample_data.appsink = appsink;
+ cbdata.u.new_sample_data.user = user;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.new_sample_data.ret;
+}
\ No newline at end of file
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
index 0d7acaf0b8..106368a064 100644
--- a/dlls/winegstreamer/gst_cbs.h
+++ b/dlls/winegstreamer/gst_cbs.h
@@ -49,6 +49,10 @@ enum CB_TYPE {
ACTIVATE_BYTESTREAM_PAD_MODE,
PROCESS_BYTESTREAM_PAD_EVENT,
WATCH_SOURCE_BUS,
+ SOURCE_STREAM_ADDED,
+ SOURCE_STREAM_REMOVED,
+ SOURCE_ALL_STREAMS,
+ STREAM_NEW_SAMPLE,
MEDIA_SOURCE_MAX,
};
@@ -134,6 +138,11 @@ struct cb_data {
GstQuery *query;
gboolean ret;
} query_sink_data;
+ struct new_sample_data {
+ GstElement *appsink;
+ gpointer user;
+ GstFlowReturn ret;
+ } new_sample_data;
} u;
int finished;
@@ -166,5 +175,9 @@ gboolean query_bytestream_wrapper(GstPad *pad, GstObject *parent, GstQuery *quer
gboolean activate_bytestream_pad_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN;
gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN;
GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) DECLSPEC_HIDDEN;
+void source_stream_added_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
+void source_stream_removed_wrapper(GstElement *element, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
+void source_all_streams_wrapper(GstElement *element, gpointer user) DECLSPEC_HIDDEN;
+GstFlowReturn stream_new_sample_wrapper(GstElement *appsink, gpointer user) DECLSPEC_HIDDEN;
#endif
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index e1f5c77375..8335c64338 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -5,6 +5,7 @@
#include "gst_private.h"
#include "gst_cbs.h"
+#include <assert.h>
#include <stdarg.h>
#define COBJMACROS
@@ -31,6 +32,26 @@ static struct source_desc
}
};
+struct media_stream
+{
+ IMFMediaStream IMFMediaStream_iface;
+ LONG ref;
+ struct media_source *parent_source;
+ IMFMediaEventQueue *event_queue;
+ IMFStreamDescriptor *descriptor;
+ GstElement *appsink;
+ GstPad *their_src, *my_sink;
+ /* usually reflects state of source */
+ enum
+ {
+ STREAM_INACTIVE,
+ STREAM_ENABLED,
+ STREAM_PAUSED,
+ STREAM_RUNNING,
+ STREAM_SHUTDOWN,
+ } state;
+};
+
struct media_source
{
IMFMediaSource IMFMediaSource_iface;
@@ -52,13 +73,32 @@ struct media_source
SOURCE_RUNNING,
SOURCE_SHUTDOWN,
} state;
+ HANDLE all_streams_event;
};
+static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface);
+}
+
static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
{
return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
}
+/* inactive stream sample discarder */
+static GstFlowReturn stream_new_sample(GstElement *appsink, gpointer user)
+{
+ struct media_stream *stream = (struct media_stream *) user;
+ GstSample *discard_sample;
+
+ TRACE("(%p) got sample\n", stream);
+
+ g_signal_emit_by_name(stream->appsink, "pull-sample", &discard_sample);
+ gst_sample_unref(discard_sample);
+ return GST_FLOW_OK;
+}
+
GstFlowReturn pull_from_bytestream(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
GstBuffer **buf)
{
@@ -238,6 +278,314 @@ GstBusSyncReply watch_source_bus(GstBus *bus, GstMessage *message, gpointer user
return GST_BUS_PASS;
}
+static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream);
+static void source_stream_added(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct media_source *source = (struct media_source *) user;
+ struct media_stream **new_stream_array;
+ struct media_stream *stream;
+ gchar *g_stream_id;
+ DWORD stream_id;
+
+ /* Most/All seen randomly calculate the initial part of the stream id, the last three digits are the only deterministic part */
+ g_stream_id = gst_pad_get_stream_id(pad);
+ sscanf(strstr(g_stream_id, "/"), "/%03u", &stream_id);
+ g_free(g_stream_id);
+
+ TRACE("stream-id: %u\n", stream_id);
+
+ /* find existing stream */
+ for (unsigned int i = 0; i < source->stream_count; i++)
+ {
+ DWORD existing_stream_id;
+ IMFStreamDescriptor *descriptor = source->streams[i]->descriptor;
+
+ if (FAILED(IMFStreamDescriptor_GetStreamIdentifier(descriptor, &existing_stream_id)))
+ goto leave;
+
+ if (existing_stream_id == stream_id)
+ {
+ struct media_stream *existing_stream = source->streams[i];
+ GstPadLinkReturn ret;
+
+ TRACE("Found existing stream %p\n", existing_stream);
+
+ if (!existing_stream->my_sink)
+ {
+ ERR("Couldn't find our sink\n");
+ goto leave;
+ }
+
+ existing_stream->their_src = pad;
+ gst_pad_set_element_private(pad, existing_stream);
+
+ if ((ret = gst_pad_link(existing_stream->their_src, existing_stream->my_sink)) != GST_PAD_LINK_OK)
+ {
+ ERR("Error linking demuxer to stream %p, err = %d\n", existing_stream, ret);
+ }
+ gst_element_sync_state_with_parent(existing_stream->appsink);
+
+ goto leave;
+ }
+ }
+
+ if (FAILED(media_stream_constructor(source, pad, stream_id, &stream)))
+ {
+ goto leave;
+ }
+
+ if (!(new_stream_array = heap_realloc(source->streams, (source->stream_count + 1) * (sizeof(*new_stream_array)))))
+ {
+ ERR("Failed to add stream to source\n");
+ goto leave;
+ }
+
+ source->streams = new_stream_array;
+ source->streams[source->stream_count++] = stream;
+
+ leave:
+ return;
+}
+
+static void source_stream_removed(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct media_stream *stream;
+
+ if (gst_pad_get_direction(pad) != GST_PAD_SRC)
+ return;
+
+ stream = (struct media_stream *) gst_pad_get_element_private(pad);
+
+ if (stream)
+ {
+ TRACE("Stream %p of Source %p removed\n", stream, stream->parent_source);
+
+ assert (stream->their_src == pad);
+
+ gst_pad_unlink(stream->their_src, stream->my_sink);
+
+ stream->their_src = NULL;
+ gst_pad_set_element_private(pad, NULL);
+ }
+}
+
+static void source_all_streams(GstElement *element, gpointer user)
+{
+ struct media_source *source = (struct media_source *) user;
+
+ SetEvent(source->all_streams_event);
+}
+
+static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%s %p)\n", stream, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFMediaStream) ||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = &stream->IMFMediaStream_iface;
+ }
+ else
+ {
+ FIXME("(%s, %p)\n", debugstr_guid(riid), out);
+ *out = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+ ULONG ref = InterlockedIncrement(&stream->ref);
+
+ TRACE("(%p) ref=%u\n", stream, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ ULONG ref = InterlockedDecrement(&stream->ref);
+
+ TRACE("(%p) ref=%u\n", stream, ref);
+
+ if (!ref)
+ {
+ if (stream->their_src)
+ gst_object_unref(GST_OBJECT(stream->their_src));
+ if (stream->my_sink)
+ gst_object_unref(GST_OBJECT(stream->my_sink));
+
+ if (stream->descriptor)
+ IMFStreamDescriptor_Release(stream->descriptor);
+ if (stream->event_queue)
+ IMFMediaEventQueue_Release(stream->event_queue);
+ if (stream->parent_source)
+ IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
+
+ heap_free(stream);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%#x, %p)\n", stream, flags, event);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
+}
+
+static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%p, %p)\n", stream, callback, state);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
+}
+
+static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%p, %p)\n", stream, result, event);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
+}
+
+static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
+ HRESULT hr, const PROPVARIANT *value)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%d, %s, %#x, %p)\n", stream, event_type, debugstr_guid(ext_type), hr, value);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
+}
+
+static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ FIXME("stub (%p)->(%p)\n", stream, source);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%p)\n", stream, descriptor);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%p)\n", iface, token);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return E_NOTIMPL;
+}
+
+static const IMFMediaStreamVtbl media_stream_vtbl =
+{
+ media_stream_QueryInterface,
+ media_stream_AddRef,
+ media_stream_Release,
+ media_stream_GetEvent,
+ media_stream_BeginGetEvent,
+ media_stream_EndGetEvent,
+ media_stream_QueueEvent,
+ media_stream_GetMediaSource,
+ media_stream_GetStreamDescriptor,
+ media_stream_RequestSample
+};
+
+static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream)
+{
+ struct media_stream *object = heap_alloc_zero(sizeof(*object));
+ HRESULT hr;
+
+ TRACE("(%p %p)->(%p)\n", source, pad, out_stream);
+
+ object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
+ object->ref = 1;
+
+ IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+ object->parent_source = source;
+ object->their_src = pad;
+
+ object->state = STREAM_INACTIVE;
+
+ if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
+ goto fail;
+
+ if (!(object->appsink = gst_element_factory_make("appsink", NULL)))
+ {
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+ gst_bin_add(GST_BIN(object->parent_source->container), object->appsink);
+
+ g_object_set(object->appsink, "emit-signals", TRUE, NULL);
+ g_object_set(object->appsink, "sync", FALSE, NULL);
+ g_object_set(object->appsink, "async", FALSE, NULL); /* <- This allows us interact with the bin w/o prerolling */
+ g_signal_connect(object->appsink, "new-sample", G_CALLBACK(stream_new_sample_wrapper), object);
+
+ object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
+ gst_pad_set_element_private(pad, object);
+
+ gst_pad_link(object->their_src, object->my_sink);
+
+ gst_element_sync_state_with_parent(object->appsink);
+
+ TRACE("->(%p)\n", object);
+
+ *out_stream = object;
+ return S_OK;
+
+ fail:
+ WARN("Failed to construct media stream, hr %#x.\n", hr);
+
+ IMFMediaStream_Release(&object->IMFMediaStream_iface);
+ return hr;
+}
+
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
@@ -412,6 +760,18 @@ static HRESULT media_source_teardown(struct media_source *source)
if (source->byte_stream)
IMFByteStream_Release(source->byte_stream);
+ for (unsigned int i = 0; i < source->stream_count; i++)
+ {
+ source->streams[i]->state = STREAM_SHUTDOWN;
+ IMFMediaStream_Release(&source->streams[i]->IMFMediaStream_iface);
+ }
+
+ if (source->stream_count)
+ heap_free(source->streams);
+
+ if (source->all_streams_event)
+ CloseHandle(source->all_streams_event);
+
return S_OK;
}
@@ -464,6 +824,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
object->type = type;
object->byte_stream = bytestream;
IMFByteStream_AddRef(bytestream);
+ object->all_streams_event = CreateEventA(NULL, FALSE, FALSE, NULL);
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
@@ -509,6 +870,10 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
}
gst_bin_add(GST_BIN(object->container), object->demuxer);
+ g_signal_connect(object->demuxer, "pad-added", G_CALLBACK(source_stream_added_wrapper), object);
+ g_signal_connect(object->demuxer, "pad-removed", G_CALLBACK(source_stream_removed_wrapper), object);
+ g_signal_connect(object->demuxer, "no-more-pads", G_CALLBACK(source_all_streams_wrapper), object);
+
object->their_sink = gst_element_get_static_pad(object->demuxer, "sink");
if ((ret = gst_pad_link(object->my_src, object->their_sink)) < 0)
@@ -518,6 +883,21 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
goto fail;
}
+ object->state = SOURCE_OPENING;
+
+ gst_element_set_state(object->container, GST_STATE_PAUSED);
+ ret = gst_element_get_state(object->container, NULL, NULL, -1);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ {
+ ERR("Failed to play source.\n");
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+
+ WaitForSingleObject(object->all_streams_event, INFINITE);
+
+ gst_element_set_state(object->container, GST_STATE_READY);
+
object->state = SOURCE_STOPPED;
*out_media_source = object;
@@ -1032,6 +1412,30 @@ void perform_cb_media_source(struct cb_data *cbdata)
cbdata->u.watch_bus_data.ret = watch_source_bus(data->bus, data->msg, data->user);
break;
}
+ case SOURCE_STREAM_ADDED:
+ {
+ struct pad_added_data *data = &cbdata->u.pad_added_data;
+ source_stream_added(data->element, data->pad, data->user);
+ break;
+ }
+ case SOURCE_STREAM_REMOVED:
+ {
+ struct pad_removed_data *data = &cbdata->u.pad_removed_data;
+ source_stream_removed(data->element, data->pad, data->user);
+ break;
+ }
+ case SOURCE_ALL_STREAMS:
+ {
+ struct no_more_pads_data *data = &cbdata->u.no_more_pads_data;
+ source_all_streams(data->element, data->user);
+ break;
+ }
+ case STREAM_NEW_SAMPLE:
+ {
+ struct new_sample_data *data = &cbdata->u.new_sample_data;
+ cbdata->u.new_sample_data.ret = stream_new_sample(data->appsink, data->user);
+ break;
+ }
default:
{
ERR("Wrong callback forwarder called\n");
--
2.28.0

View File

@ -0,0 +1,327 @@
From c8d76047c38b229c76f6ecd810e0fdb2f73ee788 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 31 Mar 2020 11:11:05 -0500
Subject: [PATCH 12/54] winegstreamer: Implement
IMFMediaStream::GetStreamDescriptor.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_private.h | 4 +
dlls/winegstreamer/media_source.c | 45 ++++++-
dlls/winegstreamer/mfplat.c | 196 ++++++++++++++++++++++++++++++
3 files changed, 244 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 71ca429088..780cf1b02f 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -36,6 +36,7 @@
#include "winuser.h"
#include "dshow.h"
#include "strmif.h"
+#include "mfobjects.h"
#include "wine/heap.h"
#include "wine/strmbase.h"
@@ -54,6 +55,9 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
+GstCaps *make_mf_compatible_caps(GstCaps *caps);
+IMFMediaType *mf_media_type_from_caps(GstCaps *caps);
+
enum source_type
{
SOURCE_TYPE_MPEG_4,
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 8335c64338..a654d555bc 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -507,7 +507,10 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM
if (stream->state == STREAM_SHUTDOWN)
return MF_E_SHUTDOWN;
- return E_NOTIMPL;
+ IMFStreamDescriptor_AddRef(stream->descriptor);
+ *descriptor = stream->descriptor;
+
+ return S_OK;
}
static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
@@ -539,6 +542,9 @@ static const IMFMediaStreamVtbl media_stream_vtbl =
static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream)
{
struct media_stream *object = heap_alloc_zero(sizeof(*object));
+ IMFMediaTypeHandler *type_handler = NULL;
+ IMFMediaType *stream_type = NULL;
+ GstCaps *caps = NULL;
HRESULT hr;
TRACE("(%p %p)->(%p)\n", source, pad, out_stream);
@@ -567,6 +573,36 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
g_object_set(object->appsink, "async", FALSE, NULL); /* <- This allows us interact with the bin w/o prerolling */
g_signal_connect(object->appsink, "new-sample", G_CALLBACK(stream_new_sample_wrapper), object);
+ if (!(caps = gst_pad_query_caps(pad, NULL)))
+ goto fail;
+
+ if (TRACE_ON(mfplat))
+ {
+ gchar *caps_str = gst_caps_to_string(caps);
+ TRACE("caps %s\n", debugstr_a(caps_str));
+ g_free(caps_str);
+ }
+
+ if (!(stream_type = mf_media_type_from_caps(caps)))
+ goto fail;
+
+ gst_caps_unref(caps);
+ caps = NULL;
+
+ if (FAILED(hr = MFCreateStreamDescriptor(stream_id, 1, &stream_type, &object->descriptor)))
+ goto fail;
+
+ if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(object->descriptor, &type_handler)))
+ goto fail;
+
+ if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_type)))
+ goto fail;
+
+ IMFMediaTypeHandler_Release(type_handler);
+ type_handler = NULL;
+ IMFMediaType_Release(stream_type);
+ stream_type = NULL;
+
object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
gst_pad_set_element_private(pad, object);
@@ -582,6 +618,13 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
fail:
WARN("Failed to construct media stream, hr %#x.\n", hr);
+ if (caps)
+ gst_caps_unref(caps);
+ if (stream_type)
+ IMFMediaType_Release(stream_type);
+ if (type_handler)
+ IMFMediaTypeHandler_Release(type_handler);
+
IMFMediaStream_Release(&object->IMFMediaStream_iface);
return hr;
}
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 16e55247de..90eb583c4a 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -16,6 +16,11 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "config.h"
+#include <gst/gst.h>
+
+#include "gst_private.h"
+
#include <stdarg.h>
#include "gst_private.h"
@@ -442,3 +447,194 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
return CLASS_E_CLASSNOTAVAILABLE;
}
+
+const static struct
+{
+ const GUID *subtype;
+ GstVideoFormat format;
+}
+uncompressed_formats[] =
+{
+ {&MFVideoFormat_ARGB32, GST_VIDEO_FORMAT_BGRA},
+ {&MFVideoFormat_RGB32, GST_VIDEO_FORMAT_BGRx},
+ {&MFVideoFormat_RGB24, GST_VIDEO_FORMAT_BGR},
+ {&MFVideoFormat_RGB565, GST_VIDEO_FORMAT_BGR16},
+ {&MFVideoFormat_RGB555, GST_VIDEO_FORMAT_BGR15},
+};
+
+/* caps will be modified to represent the exact type needed for the format */
+static IMFMediaType* transform_to_media_type(GstCaps *caps)
+{
+ IMFMediaType *media_type;
+ GstStructure *info;
+ const char *mime_type;
+
+ if (TRACE_ON(mfplat))
+ {
+ gchar *human_readable = gst_caps_to_string(caps);
+ TRACE("caps = %s\n", debugstr_a(human_readable));
+ g_free(human_readable);
+ }
+
+ if (FAILED(MFCreateMediaType(&media_type)))
+ {
+ return NULL;
+ }
+
+ info = gst_caps_get_structure(caps, 0);
+ mime_type = gst_structure_get_name(info);
+
+ if (!(strncmp(mime_type, "video", 5)))
+ {
+ GstVideoInfo video_info;
+
+ if (!(gst_video_info_from_caps(&video_info, caps)))
+ {
+ return NULL;
+ }
+
+ IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
+
+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ((UINT64)video_info.width << 32) | video_info.height);
+
+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ((UINT64)video_info.fps_n << 32) | video_info.fps_d);
+
+ if (!(strcmp(mime_type, "video/x-raw")))
+ {
+ GUID fourcc_subtype = MFVideoFormat_Base;
+ unsigned int i;
+
+ IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, FALSE);
+
+ /* First try FOURCC */
+ if ((fourcc_subtype.Data1 = gst_video_format_to_fourcc(video_info.finfo->format)))
+ {
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &fourcc_subtype);
+ }
+ else
+ {
+ for (i = 0; i < ARRAY_SIZE(uncompressed_formats); i++)
+ {
+ if (uncompressed_formats[i].format == video_info.finfo->format)
+ {
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, uncompressed_formats[i].subtype);
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(uncompressed_formats))
+ FIXME("Unrecognized format.\n");
+ }
+ }
+ else
+ FIXME("Unrecognized video format %s\n", mime_type);
+ }
+ else if (!(strncmp(mime_type, "audio", 5)))
+ {
+ gint rate, channels, bitrate;
+ IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+
+ if (gst_structure_get_int(info, "rate", &rate))
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, rate);
+
+ if (gst_structure_get_int(info, "channels", &channels))
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channels);
+
+ if (gst_structure_get_int(info, "bitrate", &bitrate))
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AVG_BITRATE, bitrate);
+
+ if (!(strcmp(mime_type, "audio/x-raw")))
+ {
+ const char *format;
+ if ((format = gst_structure_get_string(info, "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))
+ {
+ FIXME("Unhandled audio format %s\n", format);
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+
+ if (type == 'F')
+ {
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_Float);
+ }
+ else if (type == 'U' || type == 'S')
+ {
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+ if (bits_per_sample == 8)
+ type = 'U';
+ else
+ type = 'S';
+ }
+ else
+ {
+ FIXME("Unrecognized audio format: %s\n", format);
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, bits_per_sample);
+
+ 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);
+ }
+ else
+ {
+ ERR("Failed to get audio format\n");
+ }
+ }
+ else
+ FIXME("Unrecognized audio format %s\n", mime_type);
+ }
+ else
+ {
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+
+ return media_type;
+}
+
+/* returns NULL if doesn't match exactly */
+IMFMediaType *mf_media_type_from_caps(GstCaps *caps)
+{
+ GstCaps *writeable_caps;
+ IMFMediaType *ret;
+
+ writeable_caps = gst_caps_copy(caps);
+ ret = transform_to_media_type(writeable_caps);
+
+ if (!(gst_caps_is_equal(caps, writeable_caps)))
+ {
+ IMFMediaType_Release(ret);
+ ret = NULL;
+ }
+ gst_caps_unref(writeable_caps);
+ return ret;
+}
+
+GstCaps *make_mf_compatible_caps(GstCaps *caps)
+{
+ GstCaps *ret;
+ IMFMediaType *media_type;
+
+ ret = gst_caps_copy(caps);
+
+ if ((media_type = transform_to_media_type(ret)))
+ IMFMediaType_Release(media_type);
+
+ if (!media_type)
+ {
+ gst_caps_unref(ret);
+ return NULL;
+ }
+
+ return ret;
+}
\ No newline at end of file
--
2.28.0

View File

@ -0,0 +1,98 @@
From a3c30ab707ba1b3216cdad1a8543839d0b04568a Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:00:26 -0500
Subject: [PATCH 13/54] winegstreamer: Translate H.264 caps to attributes.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/mfplat.c | 67 +++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 90eb583c4a..1b37e1cc90 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"
@@ -525,6 +526,72 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps)
FIXME("Unrecognized format.\n");
}
}
+ else if (!(strcmp(mime_type, "video/x-h264")))
+ {
+ const char *profile, *level;
+
+ 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);
+ }
+ }
+ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL);
+ gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL);
+ for (unsigned int i = 0; i < gst_caps_get_size(caps); i++)
+ {
+ GstStructure *structure = gst_caps_get_structure (caps, i);
+ gst_structure_remove_field(structure, "codec_data");
+ }
+ }
else
FIXME("Unrecognized video format %s\n", mime_type);
}
--
2.28.0

View File

@ -0,0 +1,82 @@
From 3c23e1570ad895c52069c895a3e50353730d20c1 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:01:20 -0500
Subject: [PATCH 14/54] 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 1b37e1cc90..96195c887c 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -463,6 +463,24 @@ uncompressed_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);
+ }
+ }
+}
+
/* caps will be modified to represent the exact type needed for the format */
static IMFMediaType* transform_to_media_type(GstCaps *caps)
{
@@ -592,6 +610,39 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps)
gst_structure_remove_field(structure, "codec_data");
}
}
+ 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.28.0

View File

@ -0,0 +1,138 @@
From 13019300d005d7bcea386435894841a7154231e9 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:02:27 -0500
Subject: [PATCH 15/54] winegstreamer: Translate AAC caps to attributes.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/mfplat.c | 107 ++++++++++++++++++++++++++++++++++++
1 file changed, 107 insertions(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 96195c887c..ecb5de8b88 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -463,6 +463,15 @@ uncompressed_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;
@@ -708,6 +717,104 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps)
ERR("Failed to get audio format\n");
}
}
+ 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);
+
+ 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.28.0

View File

@ -0,0 +1,41 @@
From f1afd8f222ee3f552368117ef85953a90464f719 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 25 Mar 2020 13:36:19 -0500
Subject: [PATCH 16/54] 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 ecb5de8b88..c45cfacc08 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -652,6 +652,22 @@ static IMFMediaType* transform_to_media_type(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.28.0

View File

@ -0,0 +1,48 @@
From bf38004a42ba81f27e8edc65c1c04cab3cfccf14 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 12 May 2020 17:05:41 -0500
Subject: [PATCH 17/54] 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 c45cfacc08..fe187e6cd1 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -831,6 +831,30 @@ static IMFMediaType* transform_to_media_type(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.28.0

View File

@ -0,0 +1,139 @@
From 1357055cc0aeb862a74426b12188236bde82bfd1 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 31 Mar 2020 11:21:21 -0500
Subject: [PATCH 18/54] winegstreamer: Implement
IMFMediaSource::CreatePresentationDescriptor.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/mfplat/tests/mfplat.c | 8 +++----
dlls/winegstreamer/media_source.c | 36 +++++++++++++++++++++++++++++--
2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index af7e0d0459..8fef44181c 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -529,10 +529,7 @@ static void test_source_resolver(void)
ok(obj_type == MF_OBJECT_MEDIASOURCE, "got %d\n", obj_type);
hr = IMFMediaSource_CreatePresentationDescriptor(mediasource, &descriptor);
-todo_wine
ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr);
- if (FAILED(hr))
- goto skip_source_tests;
ok(descriptor != NULL, "got %p\n", descriptor);
hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, 0, &selected, &sd);
@@ -560,7 +557,10 @@ todo_wine
var.vt = VT_EMPTY;
hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var);
+todo_wine
ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr);
+ if (FAILED(hr))
+ goto skip_source_tests;
get_event((IMFMediaEventGenerator *)mediasource, MENewStream, &var);
ok(var.vt == VT_UNKNOWN, "Unexpected value type %u from MENewStream event.\n", var.vt);
@@ -623,10 +623,10 @@ todo_wine
get_event((IMFMediaEventGenerator *)mediasource, MEEndOfPresentation, NULL);
+skip_source_tests:
IMFMediaTypeHandler_Release(handler);
IMFPresentationDescriptor_Release(descriptor);
-skip_source_tests:
hr = IMFMediaSource_Shutdown(mediasource);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index a654d555bc..04b3b9f6c7 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -61,6 +61,7 @@ struct media_source
IMFByteStream *byte_stream;
struct media_stream **streams;
ULONG stream_count;
+ IMFPresentationDescriptor *pres_desc;
GstBus *bus;
GstElement *container;
GstElement *demuxer;
@@ -742,12 +743,19 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *
{
struct media_source *source = impl_from_IMFMediaSource(iface);
- FIXME("(%p)->(%p): stub\n", source, descriptor);
+ TRACE("(%p)->(%p)\n", source, descriptor);
if (source->state == SOURCE_SHUTDOWN)
return MF_E_SHUTDOWN;
- return E_NOTIMPL;
+ if (!(source->pres_desc))
+ {
+ return MF_E_NOT_INITIALIZED;
+ }
+
+ IMFPresentationDescriptor_Clone(source->pres_desc, descriptor);
+
+ return S_OK;
}
static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
@@ -798,6 +806,8 @@ static HRESULT media_source_teardown(struct media_source *source)
gst_element_set_state(source->container, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(source->container));
}
+ if (source->pres_desc)
+ IMFPresentationDescriptor_Release(source->pres_desc);
if (source->event_queue)
IMFMediaEventQueue_Release(source->event_queue);
if (source->byte_stream)
@@ -856,6 +866,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
struct media_source *object = heap_alloc_zero(sizeof(*object));
GList *demuxer_list_one, *demuxer_list_two;
GstElementFactory *demuxer_factory = NULL;
+ IMFStreamDescriptor **descriptors = NULL;
HRESULT hr;
int ret;
@@ -939,6 +950,25 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
WaitForSingleObject(object->all_streams_event, INFINITE);
+ /* init presentation descriptor */
+
+ descriptors = heap_alloc(object->stream_count * sizeof(IMFStreamDescriptor*));
+ for (unsigned int i = 0; i < object->stream_count; i++)
+ {
+ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]);
+ }
+
+ if (FAILED(MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
+ goto fail;
+
+ for (unsigned int i = 0; i < object->stream_count; i++)
+ {
+ IMFPresentationDescriptor_SelectStream(object->pres_desc, i);
+ IMFStreamDescriptor_Release(descriptors[i]);
+ }
+ heap_free(descriptors);
+ descriptors = NULL;
+
gst_element_set_state(object->container, GST_STATE_READY);
object->state = SOURCE_STOPPED;
@@ -951,6 +981,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
if (demuxer_factory)
gst_object_unref(demuxer_factory);
+ if (descriptors)
+ heap_free(descriptors);
media_source_teardown(object);
heap_free(object);
*out_media_source = NULL;
--
2.28.0

View File

@ -0,0 +1,398 @@
From 1771f2861fc08035e0baa768b15fd4b1083573f9 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 31 Mar 2020 15:10:03 -0500
Subject: [PATCH 19/54] winegstreamer: Implement IMFMediaSource::Start.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/mfplat/tests/mfplat.c | 8 +-
dlls/winegstreamer/media_source.c | 283 +++++++++++++++++++++++++++++-
2 files changed, 284 insertions(+), 7 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 8fef44181c..c26c40d531 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -557,10 +557,7 @@ static void test_source_resolver(void)
var.vt = VT_EMPTY;
hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var);
-todo_wine
ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr);
- if (FAILED(hr))
- goto skip_source_tests;
get_event((IMFMediaEventGenerator *)mediasource, MENewStream, &var);
ok(var.vt == VT_UNKNOWN, "Unexpected value type %u from MENewStream event.\n", var.vt);
@@ -578,10 +575,13 @@ todo_wine
hr = IMFMediaStream_RequestSample(video_stream, NULL);
if (i == sample_count)
break;
+todo_wine
ok(hr == S_OK, "Failed to request sample %u, hr %#x.\n", i + 1, hr);
if (hr != S_OK)
break;
}
+ if (FAILED(hr))
+ goto skip_source_tests;
for (i = 0; i < sample_count; ++i)
{
@@ -619,11 +619,11 @@ todo_wine
hr = IMFMediaStream_RequestSample(video_stream, NULL);
ok(hr == MF_E_END_OF_STREAM, "Unexpected hr %#x.\n", hr);
- IMFMediaStream_Release(video_stream);
get_event((IMFMediaEventGenerator *)mediasource, MEEndOfPresentation, NULL);
skip_source_tests:
+ IMFMediaStream_Release(video_stream);
IMFMediaTypeHandler_Release(handler);
IMFPresentationDescriptor_Release(descriptor);
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 04b3b9f6c7..abf0cfd56f 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -50,12 +50,36 @@ struct media_stream
STREAM_RUNNING,
STREAM_SHUTDOWN,
} state;
+ BOOL eos;
+};
+
+enum source_async_op
+{
+ SOURCE_ASYNC_START,
+};
+
+struct source_async_command
+{
+ IUnknown IUnknown_iface;
+ LONG refcount;
+ enum source_async_op op;
+ union
+ {
+ struct
+ {
+ IMFPresentationDescriptor *descriptor;
+ GUID format;
+ PROPVARIANT position;
+ } start;
+ } u;
};
struct media_source
{
IMFMediaSource IMFMediaSource_iface;
+ IMFAsyncCallback async_commands_callback;
LONG ref;
+ DWORD async_commands_queue;
enum source_type type;
IMFMediaEventQueue *event_queue;
IMFByteStream *byte_stream;
@@ -87,6 +111,236 @@ 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_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_source, async_commands_callback);
+}
+
+static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
+{
+ return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface);
+}
+
+static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
+{
+ if (IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI source_async_command_AddRef(IUnknown *iface)
+{
+ struct source_async_command *command = impl_from_async_command_IUnknown(iface);
+ return InterlockedIncrement(&command->refcount);
+}
+
+static ULONG WINAPI source_async_command_Release(IUnknown *iface)
+{
+ struct source_async_command *command = impl_from_async_command_IUnknown(iface);
+ ULONG refcount = InterlockedDecrement(&command->refcount);
+
+ if (!refcount)
+ {
+ if (command->op == SOURCE_ASYNC_START)
+ PropVariantClear(&command->u.start.position);
+ heap_free(command);
+ }
+
+ return refcount;
+}
+
+static const IUnknownVtbl source_async_command_vtbl =
+{
+ source_async_command_QueryInterface,
+ source_async_command_AddRef,
+ source_async_command_Release,
+};
+
+static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret)
+{
+ struct source_async_command *command;
+
+ if (!(command = heap_alloc_zero(sizeof(*command))))
+ return E_OUTOFMEMORY;
+
+ command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
+ command->op = op;
+
+ *ret = command;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFAsyncCallback_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
+ DWORD *flags, DWORD *queue)
+{
+ return E_NOTIMPL;
+}
+
+static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+}
+
+static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ return IMFMediaSource_Release(&source->IMFMediaSource_iface);
+}
+
+static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected)
+{
+ ULONG sd_count;
+ IMFStreamDescriptor *ret;
+
+ if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count)))
+ return NULL;
+
+ for (unsigned int i = 0; i < sd_count; i++)
+ {
+ DWORD stream_id;
+
+ if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret)))
+ return NULL;
+
+ if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id)
+ return ret;
+
+ IMFStreamDescriptor_Release(ret);
+ }
+ return NULL;
+}
+
+static HRESULT start_pipeline(struct media_source *source, struct source_async_command *command)
+{
+ PROPVARIANT *position = &command->u.start.position;
+ BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY;
+
+ /* we can't seek until the pipeline is in a valid state */
+ gst_element_set_state(source->container, GST_STATE_PAUSED);
+ assert(gst_element_get_state(source->container, NULL, NULL, -1) == GST_STATE_CHANGE_SUCCESS);
+ if (source->state == SOURCE_STOPPED)
+ {
+ WaitForSingleObject(source->all_streams_event, INFINITE);
+ }
+
+ for (unsigned int i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream;
+ IMFStreamDescriptor *sd;
+ DWORD stream_id;
+ BOOL was_active;
+ BOOL selected;
+
+ stream = source->streams[i];
+
+ IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id);
+
+ sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected);
+ IMFStreamDescriptor_Release(sd);
+
+ was_active = stream->state != STREAM_INACTIVE;
+
+ if (position->vt != VT_EMPTY)
+ {
+ GstEvent *seek_event = gst_event_new_seek(1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET, position->u.hVal.QuadPart / 100, GST_SEEK_TYPE_NONE, 0);
+
+
+ gst_pad_push_event(stream->my_sink, seek_event);
+ gst_bus_poll(source->bus, GST_MESSAGE_RESET_TIME, -1);
+
+ stream->eos = FALSE;
+ }
+
+ stream->state = selected ? STREAM_RUNNING : STREAM_INACTIVE;
+
+ if (selected)
+ {
+ TRACE("Stream %u (%p) selected\n", i, stream);
+ IMFMediaEventQueue_QueueEventParamUnk(source->event_queue,
+ was_active ? MEUpdatedStream : MENewStream, &GUID_NULL,
+ S_OK, (IUnknown*) &stream->IMFMediaStream_iface);
+
+ IMFMediaEventQueue_QueueEventParamVar(stream->event_queue,
+ seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position);
+ }
+ }
+
+ IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
+ seek_message ? MESourceSeeked : MESourceStarted,
+ &GUID_NULL, S_OK, position);
+
+ source->state = SOURCE_RUNNING;
+
+ gst_element_set_state(source->container, GST_STATE_PLAYING);
+ gst_element_get_state(source->container, NULL, NULL, -1);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+ struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
+ struct source_async_command *command;
+ IUnknown *state;
+ HRESULT hr;
+
+ if (source->state == SOURCE_SHUTDOWN)
+ return S_OK;
+
+ if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
+ return hr;
+
+ command = impl_from_async_command_IUnknown(state);
+ switch (command->op)
+ {
+ case SOURCE_ASYNC_START:
+ start_pipeline(source, command);
+ break;
+ default:
+ ;
+ }
+
+ IUnknown_Release(state);
+
+ return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
+{
+ callback_QueryInterface,
+ source_async_commands_callback_AddRef,
+ source_async_commands_callback_Release,
+ callback_GetParameters,
+ source_async_commands_Invoke,
+};
+
/* inactive stream sample discarder */
static GstFlowReturn stream_new_sample(GstElement *appsink, gpointer user)
{
@@ -759,16 +1013,32 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *
}
static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
- const GUID *time_format, const PROPVARIANT *start_position)
+ const GUID *time_format, const PROPVARIANT *position)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
+ struct source_async_command *command;
+ HRESULT hr;
- FIXME("(%p)->(%p, %p, %p): stub\n", source, descriptor, time_format, start_position);
+ TRACE("(%p)->(%p, %p, %p)\n", source, descriptor, time_format, position);
if (source->state == SOURCE_SHUTDOWN)
return MF_E_SHUTDOWN;
- return E_NOTIMPL;
+ if (!(IsEqualIID(time_format, &GUID_NULL)))
+ {
+ return MF_E_UNSUPPORTED_TIME_FORMAT;
+ }
+
+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command)))
+ {
+ command->u.start.descriptor = descriptor;
+ command->u.start.format = *time_format;
+ PropVariantCopy(&command->u.start.position, position);
+
+ hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
+ }
+
+ return hr;
}
static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
@@ -825,6 +1095,9 @@ static HRESULT media_source_teardown(struct media_source *source)
if (source->all_streams_event)
CloseHandle(source->all_streams_event);
+ if (source->async_commands_queue)
+ MFUnlockWorkQueue(source->async_commands_queue);
+
return S_OK;
}
@@ -874,6 +1147,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
return E_OUTOFMEMORY;
object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
+ object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
object->ref = 1;
object->type = type;
object->byte_stream = bytestream;
@@ -883,6 +1157,9 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
+ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
+ goto fail;
+
object->container = gst_bin_new(NULL);
object->bus = gst_bus_new();
gst_bus_set_sync_handler(object->bus, watch_source_bus_wrapper, object, NULL);
--
2.28.0

View File

@ -0,0 +1,179 @@
From cb6513ea1aafad23b5c16ddb6fc287e9a0bf8a0c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 31 Mar 2020 15:11:31 -0500
Subject: [PATCH 20/54] winegstreamer: Insert parser into pipeline to rectify
type differences.
It's probably better to use caps negotiation here, but this seemed simpler for now.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/media_source.c | 114 ++++++++++++++++++++++++------
1 file changed, 91 insertions(+), 23 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index abf0cfd56f..cb247adcef 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -578,7 +578,6 @@ static void source_stream_added(GstElement *element, GstPad *pad, gpointer user)
{
ERR("Error linking demuxer to stream %p, err = %d\n", existing_stream, ret);
}
- gst_element_sync_state_with_parent(existing_stream->appsink);
goto leave;
}
@@ -794,12 +793,99 @@ static const IMFMediaStreamVtbl media_stream_vtbl =
media_stream_RequestSample
};
+/* TODO: Use gstreamer caps negotiation */
+/* connects their_src to appsink */
+static HRESULT media_stream_align_with_mf(struct media_stream *stream, IMFMediaType **stream_type)
+{
+ GstCaps *source_caps = NULL;
+ GstCaps *target_caps = NULL;
+ GstElement *parser = NULL;
+ HRESULT hr = E_FAIL;
+
+ if (!(source_caps = gst_pad_query_caps(stream->their_src, NULL)))
+ goto done;
+ if (!(target_caps = make_mf_compatible_caps(source_caps)))
+ goto done;
+
+ if (TRACE_ON(mfplat))
+ {
+ gchar *source_caps_str = gst_caps_to_string(source_caps), *target_caps_str = gst_caps_to_string(target_caps);
+ TRACE("source caps %s\ntarget caps %s\n", debugstr_a(source_caps_str), debugstr_a(target_caps_str));
+ g_free(source_caps_str);
+ g_free(target_caps_str);
+ }
+
+ 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;
+
+ if (!(g_list_length(parser_list_one)))
+ {
+ gst_plugin_feature_list_free(parser_list_one);
+ ERR("Failed to find parser for stream\n");
+ hr = E_FAIL;
+ goto done;
+ }
+
+ 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)
+ {
+ hr = E_FAIL;
+ goto done;
+ }
+
+ gst_bin_add(GST_BIN(stream->parent_source->container), parser);
+
+ assert(gst_pad_link(stream->their_src, gst_element_get_static_pad(parser, "sink")) == GST_PAD_LINK_OK);
+
+ assert(gst_element_link(parser, stream->appsink));
+
+ gst_element_sync_state_with_parent(parser);
+ }
+ else
+ {
+ assert(gst_pad_link(stream->their_src, gst_element_get_static_pad(stream->appsink, "sink")) == GST_PAD_LINK_OK);
+ }
+
+ stream->my_sink = gst_element_get_static_pad(parser ? parser : stream->appsink, "sink");
+
+ *stream_type = mf_media_type_from_caps(target_caps);
+
+ hr = S_OK;
+
+ done:
+ if (source_caps)
+ gst_caps_unref(source_caps);
+ if (target_caps)
+ gst_caps_unref(target_caps);
+
+ return hr;
+}
+
static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream)
{
struct media_stream *object = heap_alloc_zero(sizeof(*object));
IMFMediaTypeHandler *type_handler = NULL;
IMFMediaType *stream_type = NULL;
- GstCaps *caps = NULL;
HRESULT hr;
TRACE("(%p %p)->(%p)\n", source, pad, out_stream);
@@ -828,22 +914,9 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
g_object_set(object->appsink, "async", FALSE, NULL); /* <- This allows us interact with the bin w/o prerolling */
g_signal_connect(object->appsink, "new-sample", G_CALLBACK(stream_new_sample_wrapper), object);
- if (!(caps = gst_pad_query_caps(pad, NULL)))
+ if (FAILED(hr = media_stream_align_with_mf(object, &stream_type)))
goto fail;
- if (TRACE_ON(mfplat))
- {
- gchar *caps_str = gst_caps_to_string(caps);
- TRACE("caps %s\n", debugstr_a(caps_str));
- g_free(caps_str);
- }
-
- if (!(stream_type = mf_media_type_from_caps(caps)))
- goto fail;
-
- gst_caps_unref(caps);
- caps = NULL;
-
if (FAILED(hr = MFCreateStreamDescriptor(stream_id, 1, &stream_type, &object->descriptor)))
goto fail;
@@ -858,23 +931,18 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
IMFMediaType_Release(stream_type);
stream_type = NULL;
- object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
- gst_pad_set_element_private(pad, object);
-
- gst_pad_link(object->their_src, object->my_sink);
+ gst_pad_set_element_private(object->their_src, object);
gst_element_sync_state_with_parent(object->appsink);
TRACE("->(%p)\n", object);
-
*out_stream = object;
+
return S_OK;
fail:
WARN("Failed to construct media stream, hr %#x.\n", hr);
- if (caps)
- gst_caps_unref(caps);
if (stream_type)
IMFMediaType_Release(stream_type);
if (type_handler)
--
2.28.0

View File

@ -0,0 +1,332 @@
From 7e99ccd002a6923c6cabad58d9691bf1f64e30ae Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 25 Mar 2020 10:43:03 -0500
Subject: [PATCH 21/54] winegstreamer: Implement IMFMediaStream::RequestSample.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/mfplat/tests/mfplat.c | 4 -
dlls/winegstreamer/gst_private.h | 1 +
dlls/winegstreamer/media_source.c | 117 ++++++++++++++++++++++++++++--
dlls/winegstreamer/mfplat.c | 90 +++++++++++++++++++++++
4 files changed, 203 insertions(+), 9 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index c26c40d531..a9408c998c 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -575,13 +575,10 @@ static void test_source_resolver(void)
hr = IMFMediaStream_RequestSample(video_stream, NULL);
if (i == sample_count)
break;
-todo_wine
ok(hr == S_OK, "Failed to request sample %u, hr %#x.\n", i + 1, hr);
if (hr != S_OK)
break;
}
- if (FAILED(hr))
- goto skip_source_tests;
for (i = 0; i < sample_count; ++i)
{
@@ -622,7 +619,6 @@ todo_wine
get_event((IMFMediaEventGenerator *)mediasource, MEEndOfPresentation, NULL);
-skip_source_tests:
IMFMediaStream_Release(video_stream);
IMFMediaTypeHandler_Release(handler);
IMFPresentationDescriptor_Release(descriptor);
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 780cf1b02f..823e023f52 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -57,6 +57,7 @@ extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
GstCaps *make_mf_compatible_caps(GstCaps *caps);
IMFMediaType *mf_media_type_from_caps(GstCaps *caps);
+IMFSample *mf_sample_from_gst_buffer(GstBuffer *in);
enum source_type
{
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index cb247adcef..b6f2fcc8fa 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -56,6 +56,7 @@ struct media_stream
enum source_async_op
{
SOURCE_ASYNC_START,
+ SOURCE_ASYNC_REQUEST_SAMPLE,
};
struct source_async_command
@@ -71,6 +72,11 @@ struct source_async_command
GUID format;
PROPVARIANT position;
} start;
+ struct
+ {
+ struct media_stream *stream;
+ IUnknown *token;
+ } request_sample;
} u;
};
@@ -304,6 +310,77 @@ static HRESULT start_pipeline(struct media_source *source, struct source_async_c
return S_OK;
}
+static void dispatch_end_of_presentation(struct media_source *source)
+{
+ PROPVARIANT empty = {.vt = VT_EMPTY};
+
+ /* A stream has ended, check whether all have */
+ for (unsigned int i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream = source->streams[i];
+
+ if (stream->state != STREAM_INACTIVE && !stream->eos)
+ return;
+ }
+
+ IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty);
+}
+
+static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token)
+{
+ PROPVARIANT empty_var = {.vt = VT_EMPTY};
+ GstSample *gst_sample;
+ GstBuffer *buffer;
+ IMFSample *sample;
+
+ TRACE("%p, %p\n", stream, token);
+
+ g_signal_emit_by_name(stream->appsink, "pull-sample", &gst_sample);
+ if (gst_sample)
+ {
+ buffer = gst_sample_get_buffer(gst_sample);
+
+ if (TRACE_ON(mfplat))
+ {
+ const GstCaps *sample_caps = gst_sample_get_caps(gst_sample);
+ const GstStructure *sample_info = gst_sample_get_info(gst_sample);
+ if (sample_caps)
+ {
+ gchar *sample_caps_str = gst_caps_to_string(sample_caps);
+ TRACE("sample caps %s\n", debugstr_a(sample_caps_str));
+ g_free(sample_caps_str);
+ }
+ if (sample_info)
+ {
+ gchar *sample_info_str = gst_structure_to_string(sample_info);
+ TRACE("sample info %s\n", debugstr_a(sample_info_str));
+ g_free(sample_info_str);
+ }
+ TRACE("PTS = %lu DTS = %llu\n", GST_BUFFER_PTS(buffer), GST_BUFFER_DTS(buffer));
+ }
+
+ sample = mf_sample_from_gst_buffer(buffer);
+ gst_sample_unref(gst_sample);
+
+ if (token)
+ IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
+
+ IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, &GUID_NULL, S_OK, (IUnknown *)sample);
+ }
+
+ g_object_get(stream->appsink, "eos", &stream->eos, NULL);
+ if (stream->eos)
+ {
+ if (token)
+ IUnknown_Release(token);
+ IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var);
+ dispatch_end_of_presentation(stream->parent_source);
+ return S_OK;
+ }
+
+ return S_OK;
+}
+
static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
{
struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
@@ -323,6 +400,9 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA
case SOURCE_ASYNC_START:
start_pipeline(source, command);
break;
+ case SOURCE_ASYNC_REQUEST_SAMPLE:
+ wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token);
+ break;
default:
;
}
@@ -345,12 +425,14 @@ static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
static GstFlowReturn stream_new_sample(GstElement *appsink, gpointer user)
{
struct media_stream *stream = (struct media_stream *) user;
- GstSample *discard_sample;
- TRACE("(%p) got sample\n", stream);
+ if (stream->state == STREAM_INACTIVE)
+ {
+ GstSample *discard_sample;
+ g_signal_emit_by_name(stream->appsink, "pull-sample", &discard_sample);
+ gst_sample_unref(discard_sample);
+ }
- g_signal_emit_by_name(stream->appsink, "pull-sample", &discard_sample);
- gst_sample_unref(discard_sample);
return GST_FLOW_OK;
}
@@ -770,13 +852,37 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM
static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
{
struct media_stream *stream = impl_from_IMFMediaStream(iface);
+ struct source_async_command *command;
+ HRESULT hr;
TRACE("(%p)->(%p)\n", iface, token);
if (stream->state == STREAM_SHUTDOWN)
return MF_E_SHUTDOWN;
- return E_NOTIMPL;
+ if (stream->state == STREAM_INACTIVE || stream->state == STREAM_ENABLED)
+ {
+ WARN("Stream isn't active\n");
+ return MF_E_MEDIA_SOURCE_WRONGSTATE;
+ }
+
+ if (stream->eos)
+ {
+ return MF_E_END_OF_STREAM;
+ }
+
+ if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command)))
+ {
+ command->u.request_sample.stream = stream;
+ if (token)
+ IUnknown_AddRef(token);
+ command->u.request_sample.token = token;
+
+ /* Once pause support is added, this will need to into a stream queue, and synchronization will need to be added*/
+ hr = MFPutWorkItem(stream->parent_source->async_commands_queue, &stream->parent_source->async_commands_callback, &command->IUnknown_iface);
+ }
+
+ return hr;
}
static const IMFMediaStreamVtbl media_stream_vtbl =
@@ -898,6 +1004,7 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
object->their_src = pad;
object->state = STREAM_INACTIVE;
+ object->eos = FALSE;
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index fe187e6cd1..e09309fd4d 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -902,4 +902,94 @@ GstCaps *make_mf_compatible_caps(GstCaps *caps)
}
return ret;
+}
+
+/* IMFSample = GstBuffer
+ IMFBuffer = GstMemory */
+
+/* TODO: Future optimization could be to create a custom
+ IMFMediaBuffer wrapper around GstMemory, and to utilize
+ gst_memory_new_wrapped on IMFMediaBuffer data. However,
+ this wouldn't work if we allow the callers to allocate
+ the buffers. */
+
+IMFSample* mf_sample_from_gst_buffer(GstBuffer *gst_buffer)
+{
+ IMFSample *out = NULL;
+ LONGLONG duration, time;
+ int buffer_count;
+ HRESULT hr;
+
+ if (FAILED(hr = MFCreateSample(&out)))
+ goto fail;
+
+ duration = GST_BUFFER_DURATION(gst_buffer);
+ time = GST_BUFFER_PTS(gst_buffer);
+
+ if (FAILED(IMFSample_SetSampleDuration(out, duration / 100)))
+ goto fail;
+
+ if (FAILED(IMFSample_SetSampleTime(out, time / 100)))
+ goto fail;
+
+ buffer_count = gst_buffer_n_memory(gst_buffer);
+
+ for (unsigned int i = 0; i < buffer_count; i++)
+ {
+ GstMemory *memory = gst_buffer_get_memory(gst_buffer, i);
+ IMFMediaBuffer *mf_buffer = NULL;
+ GstMapInfo map_info;
+ BYTE *buf_data;
+
+ if (!memory)
+ {
+ hr = E_FAIL;
+ goto loop_done;
+ }
+
+ if (!(gst_memory_map(memory, &map_info, GST_MAP_READ)))
+ {
+ hr = E_FAIL;
+ goto loop_done;
+ }
+
+ if (FAILED(hr = MFCreateMemoryBuffer(map_info.maxsize, &mf_buffer)))
+ {
+ gst_memory_unmap(memory, &map_info);
+ goto loop_done;
+ }
+
+ if (FAILED(hr = IMFMediaBuffer_Lock(mf_buffer, &buf_data, NULL, NULL)))
+ {
+ gst_memory_unmap(memory, &map_info);
+ goto loop_done;
+ }
+
+ memcpy(buf_data, map_info.data, map_info.size);
+
+ gst_memory_unmap(memory, &map_info);
+
+ if (FAILED(hr = IMFMediaBuffer_Unlock(mf_buffer)))
+ goto loop_done;
+
+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(mf_buffer, map_info.size)))
+ goto loop_done;
+
+ if (FAILED(hr = IMFSample_AddBuffer(out, mf_buffer)))
+ goto loop_done;
+
+ loop_done:
+ if (mf_buffer)
+ IMFMediaBuffer_Release(mf_buffer);
+ if (memory)
+ gst_memory_unref(memory);
+ if (FAILED(hr))
+ goto fail;
+ }
+
+ return out;
+ fail:
+ ERR("Failed to copy IMFSample to GstBuffer, hr = %#x\n", hr);
+ IMFSample_Release(out);
+ return NULL;
}
\ No newline at end of file
--
2.28.0

View File

@ -0,0 +1,35 @@
From ffaf4ac88336833aa64b83b9edcd0c23b3f1bdbb Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 31 Mar 2020 15:15:07 -0500
Subject: [PATCH 22/54] winegstreamer: Implement
IMFMediaSource::GetCharacteristics.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/media_source.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index b6f2fcc8fa..675ee9bd20 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -1160,12 +1160,14 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO
{
struct media_source *source = impl_from_IMFMediaSource(iface);
- FIXME("(%p)->(%p): stub\n", source, characteristics);
+ TRACE("(%p)->(%p)\n", source, characteristics);
if (source->state == SOURCE_SHUTDOWN)
return MF_E_SHUTDOWN;
- return E_NOTIMPL;
+ *characteristics = MFMEDIASOURCE_CAN_SEEK;
+
+ return S_OK;
}
static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
--
2.28.0

View File

@ -0,0 +1,65 @@
From 27d73f359d729bc5ad06f251d398d81a01298eb2 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 31 Mar 2020 15:15:50 -0500
Subject: [PATCH 23/54] winegstreamer: Calculate the MF_PD_DURATION of the
media source's PD.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/media_source.c | 40 +++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 675ee9bd20..5811baf0c0 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -1423,6 +1423,46 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
heap_free(descriptors);
descriptors = NULL;
+ /* miscelaneous presentation descriptor setup */
+ {
+ IMFAttributes *byte_stream_attributes;
+ gint64 total_pres_time = 0;
+
+ 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);
+ }
+
+ for (unsigned int i = 0; i < object->stream_count; i++)
+ {
+ GstQuery *query = gst_query_new_duration(GST_FORMAT_TIME);
+ if (gst_pad_query(object->streams[i]->their_src, query))
+ {
+ gint64 stream_pres_time;
+ gst_query_parse_duration(query, NULL, &stream_pres_time);
+
+ TRACE("Stream %u has duration %lu\n", i, stream_pres_time);
+
+ if (stream_pres_time > total_pres_time)
+ total_pres_time = stream_pres_time;
+ }
+ else
+ {
+ WARN("Unable to get presentation time of stream %u\n", i);
+ }
+ }
+
+ if (object->stream_count)
+ IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time / 100);
+ }
+
gst_element_set_state(object->container, GST_STATE_READY);
object->state = SOURCE_STOPPED;
--
2.28.0

View File

@ -0,0 +1,174 @@
From 97507c173539685376d1cad7782529b8394d7cd0 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 29 Jan 2020 15:37:39 -0600
Subject: [PATCH 24/54] tools: Add support for multiple parent directories.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
tools/make_makefiles | 45 +++++++++++++++++++++++++++-----------------
tools/makedep.c | 30 ++++++++++++++++++++---------
2 files changed, 49 insertions(+), 26 deletions(-)
diff --git a/tools/make_makefiles b/tools/make_makefiles
index c18fa90e2d..1e34a280a4 100755
--- a/tools/make_makefiles
+++ b/tools/make_makefiles
@@ -231,14 +231,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);
@@ -293,19 +293,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
@@ -410,13 +418,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 825458156f..f76747e00a 100644
--- a/tools/makedep.c
+++ b/tools/makedep.c
@@ -183,6 +183,7 @@ struct makefile
struct strarray install_lib;
struct strarray install_dev;
struct strarray extra_targets;
+ struct strarray parent_dirs;
struct strarray extra_imports;
struct list sources;
struct list includes;
@@ -191,7 +192,6 @@ struct makefile
const char *obj_dir;
const char *top_src_dir;
const char *top_obj_dir;
- const char *parent_dir;
const char *module;
const char *testdll;
const char *sharedlib;
@@ -1376,15 +1376,24 @@ static struct file *open_local_file( const struct makefile *make, const char *pa
{
char *src_path = root_dir_path( base_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 = root_dir_path( base_dir_path( make, path ));
+ new_path = strmake( "%s/%s", make->parent_dirs.str[i], path );
+ src_path = root_dir_path( base_dir_path( make, new_path ));
ret = load_file( src_path );
- if (ret) ret->flags |= FLAG_PARENTDIR;
+ if (ret)
+ {
+ ret->flags |= FLAG_PARENTDIR;
+ path = new_path;
+ }
+ else
+ free(new_path);
}
if (ret) *filename = src_dir_path( make, path );
@@ -4271,13 +4280,13 @@ static void load_sources( struct makefile *make )
strarray_set_value( &make->vars, "top_srcdir", top_src_dir_path( make, "" ));
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" );
@@ -4322,8 +4331,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, strmake( "-I%s", top_obj_dir_path( make, "include" )));
if (make->top_src_dir)
strarray_add( &make->include_args, strmake( "-I%s", top_src_dir_path( make, "include" )));
--
2.28.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
From 32b23b1380f44a6c3106e0e789e31c5cbed94b5e Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:15:35 -0500
Subject: [PATCH 26/54] winegstreamer: Introduce IMFMediaType -> GstCaps
converter.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_private.h | 1 +
dlls/winegstreamer/mfplat.c | 145 +++++++++++++++++++++++++++++++
2 files changed, 146 insertions(+)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 823e023f52..20d3beef02 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -57,6 +57,7 @@ extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
GstCaps *make_mf_compatible_caps(GstCaps *caps);
IMFMediaType *mf_media_type_from_caps(GstCaps *caps);
+GstCaps *caps_from_mf_media_type(IMFMediaType *type);
IMFSample *mf_sample_from_gst_buffer(GstBuffer *in);
enum source_type
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index e09309fd4d..ba2a32e610 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -904,6 +904,151 @@ GstCaps *make_mf_compatible_caps(GstCaps *caps)
return ret;
}
+GstCaps *caps_from_mf_media_type(IMFMediaType *type)
+{
+ GUID major_type;
+ GUID subtype;
+ GstCaps *output = NULL;
+
+ if (FAILED(IMFMediaType_GetMajorType(type, &major_type)))
+ return NULL;
+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
+ return NULL;
+
+ if (IsEqualGUID(&major_type, &MFMediaType_Video))
+ {
+ UINT64 frame_rate = 0, frame_size = 0;
+ DWORD width, height, framerate_num, framerate_den;
+ UINT32 unused;
+
+ if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
+ return NULL;
+ width = frame_size >> 32;
+ height = frame_size;
+ if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)))
+ {
+ frame_rate = TRUE;
+ framerate_num = 0;
+ framerate_den = 1;
+ }
+ else
+ {
+ framerate_num = frame_rate >> 32;
+ framerate_den = frame_rate;
+ }
+
+ /* Check if type is uncompressed */
+ if (SUCCEEDED(MFCalculateImageSize(&subtype, 100, 100, &unused)))
+ {
+ GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
+ unsigned int i;
+
+ output = gst_caps_new_empty_simple("video/x-raw");
+
+ for (i = 0; i < ARRAY_SIZE(uncompressed_formats); i++)
+ {
+ if (IsEqualGUID(uncompressed_formats[i].subtype, &subtype))
+ {
+ format = uncompressed_formats[i].format;
+ break;
+ }
+ }
+
+ if (format == GST_VIDEO_FORMAT_UNKNOWN)
+ {
+ format = gst_video_format_from_fourcc(subtype.Data1);
+ }
+
+ if (format == GST_VIDEO_FORMAT_UNKNOWN)
+ {
+ FIXME("Unrecognized format %s\n", debugstr_guid(&subtype));
+ return NULL;
+ }
+ else
+ {
+ GstVideoInfo info;
+
+ gst_video_info_set_format(&info, format, width, height);
+ output = gst_video_info_to_caps(&info);
+ }
+
+ }
+ else {
+ FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype));
+ return NULL;
+ }
+
+
+ if (frame_size)
+ {
+ gst_caps_set_simple(output, "width", G_TYPE_INT, width, NULL);
+ gst_caps_set_simple(output, "height", G_TYPE_INT, height, NULL);
+ }
+ if (frame_rate)
+ gst_caps_set_simple(output, "framerate", GST_TYPE_FRACTION, framerate_num, framerate_den, NULL);
+ return output;
+ }
+ else if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+ {
+ DWORD rate, channels, bitrate;
+
+ if (IsEqualGUID(&subtype, &MFAudioFormat_Float))
+ {
+ output = gst_caps_new_empty_simple("audio/x-raw");
+
+ gst_caps_set_simple(output, "format", G_TYPE_STRING, "F32LE", NULL);
+ gst_caps_set_simple(output, "layout", G_TYPE_STRING, "interleaved", NULL);
+ }
+ else if (IsEqualGUID(&subtype, &MFAudioFormat_PCM))
+ {
+ DWORD bits_per_sample;
+
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample)))
+ {
+ char format[6];
+ char type;
+
+ type = bits_per_sample > 8 ? 'S' : 'U';
+
+ output = gst_caps_new_empty_simple("audio/x-raw");
+
+ sprintf(format, "%c%u%s", type, bits_per_sample, bits_per_sample > 8 ? "LE" : "");
+
+ gst_caps_set_simple(output, "format", G_TYPE_STRING, format, NULL);
+ }
+ else
+ {
+ ERR("Bits per sample not set.\n");
+ return NULL;
+ }
+ }
+ else
+ {
+ FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype));
+ return NULL;
+ }
+
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate)))
+ {
+ gst_caps_set_simple(output, "rate", G_TYPE_INT, rate, NULL);
+ }
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels)))
+ {
+ gst_caps_set_simple(output, "channels", G_TYPE_INT, channels, NULL);
+ }
+
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AVG_BITRATE, &bitrate)))
+ {
+ gst_caps_set_simple(output, "bitrate", G_TYPE_INT, bitrate, NULL);
+ }
+
+ return output;
+ }
+
+ FIXME("Unrecognized major type %s\n", debugstr_guid(&major_type));
+ return NULL;
+}
+
/* IMFSample = GstBuffer
IMFBuffer = GstMemory */
--
2.28.0

View File

@ -0,0 +1,72 @@
From c60414ceb49b5ff025a101b9ffdf0aa665b0cf2c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:18:40 -0500
Subject: [PATCH 27/54] winegstreamer: Translate H.264 attributes to caps.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/mfplat.c | 48 +++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index ba2a32e610..26ad75584d 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -973,6 +973,54 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type)
}
}
+ else if (IsEqualGUID(&subtype, &MFVideoFormat_H264))
+ {
+ 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)))
+ {
+ 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 {
FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype));
return NULL;
--
2.28.0

View File

@ -0,0 +1,55 @@
From 79ffdf47055128475526a432b175362bbbaf57da Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 24 Mar 2020 16:20:17 -0500
Subject: [PATCH 28/54] winegstreamer: Translate WMV attributes to caps.
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 26ad75584d..f5b44f9214 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -904,6 +904,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;
@@ -1021,6 +1036,15 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type)
gst_caps_set_simple(output, "level", G_TYPE_STRING, level, NULL);
}
}
+ 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 {
FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype));
return NULL;
--
2.28.0

View File

@ -0,0 +1,90 @@
From f94f3362a246e5f1f476f6a51465424e1ae6d7c7 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 21 Apr 2020 10:31:02 -0500
Subject: [PATCH 29/54] 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 f5b44f9214..7e96e6af20 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -1094,6 +1094,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.28.0

View File

@ -0,0 +1,32 @@
From 8bd70d8a970af6e9a31158fa57085918ee57817c Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 11 May 2020 16:03:09 -0500
Subject: [PATCH 30/54] winegstreamer: Translate MPEG-4 Section-2 attributes to
caps.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/mfplat.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 7e96e6af20..c7d6e4806a 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -1045,6 +1045,13 @@ 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);
+
+ user_data_to_codec_data(type, output);
+ }
else {
FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype));
return NULL;
--
2.28.0

View File

@ -0,0 +1,39 @@
From e73bfd928bb2a0e02fe6243013132b0e63b27a52 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 12 May 2020 17:05:59 -0500
Subject: [PATCH 31/54] 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 c7d6e4806a..86f0f79630 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -1167,6 +1167,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.28.0

View File

@ -0,0 +1,110 @@
From 21cfe494d559a7d10e065d830d1d7a90c71da69b Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 25 Mar 2020 10:43:27 -0500
Subject: [PATCH 32/54] Introduce IMFSample -> GstBuffer converter.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_private.h | 1 +
dlls/winegstreamer/mfplat.c | 74 ++++++++++++++++++++++++++++++++
2 files changed, 75 insertions(+)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 20d3beef02..258df0d040 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -59,6 +59,7 @@ GstCaps *make_mf_compatible_caps(GstCaps *caps);
IMFMediaType *mf_media_type_from_caps(GstCaps *caps);
GstCaps *caps_from_mf_media_type(IMFMediaType *type);
IMFSample *mf_sample_from_gst_buffer(GstBuffer *in);
+GstBuffer *gst_buffer_from_mf_sample(IMFSample *in);
enum source_type
{
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 86f0f79630..6499c39a8f 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -1297,4 +1297,78 @@ IMFSample* mf_sample_from_gst_buffer(GstBuffer *gst_buffer)
ERR("Failed to copy IMFSample to GstBuffer, hr = %#x\n", hr);
IMFSample_Release(out);
return NULL;
+}
+
+GstBuffer* gst_buffer_from_mf_sample(IMFSample *mf_sample)
+{
+ GstBuffer *out = gst_buffer_new();
+ IMFMediaBuffer *mf_buffer = NULL;
+ LONGLONG duration, time;
+ DWORD buffer_count;
+ 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 (unsigned int i = 0; i < buffer_count; i++)
+ {
+ DWORD buffer_max_size, 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_GetMaxLength(mf_buffer, &buffer_max_size)))
+ 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;
+
+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(mf_buffer, buffer_size)))
+ 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;
}
\ No newline at end of file
--
2.28.0

View File

@ -0,0 +1,385 @@
From 0c33d653e5c481bec56a2d1ebd6a0b2ae53774d1 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 16 Mar 2020 12:09:39 -0500
Subject: [PATCH 33/54] winegstreamer: Implement decoder MFT on gstreamer.
---
dlls/winegstreamer/Makefile.in | 1 +
dlls/winegstreamer/gst_cbs.c | 65 ++++++++++
dlls/winegstreamer/gst_cbs.h | 18 +++
dlls/winegstreamer/gst_private.h | 7 ++
dlls/winegstreamer/main.c | 3 +-
dlls/winegstreamer/mfplat.c | 118 ++++++++++++++++++-
dlls/winegstreamer/winegstreamer_classes.idl | 12 ++
include/mfidl.idl | 4 +-
8 files changed, 225 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in
index f2e8749445..e2af408582 100644
--- a/dlls/winegstreamer/Makefile.in
+++ b/dlls/winegstreamer/Makefile.in
@@ -13,6 +13,7 @@ C_SRCS = \
main.c \
media_source.c \
mediatype.c \
+ mf_decode.c \
mfplat.c \
pin.c \
qualitycontrol.c \
diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
index d2d36aeb86..e392f4526f 100644
--- a/dlls/winegstreamer/gst_cbs.c
+++ b/dlls/winegstreamer/gst_cbs.c
@@ -51,6 +51,8 @@ static void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user)
perform_cb_gstdemux(cbdata);
else if (cbdata->type < MEDIA_SOURCE_MAX)
perform_cb_media_source(cbdata);
+ else if (cbdata->type < MF_DECODE_MAX)
+ perform_cb_mf_decode(cbdata);
pthread_mutex_lock(&cbdata->lock);
cbdata->finished = 1;
@@ -414,5 +416,68 @@ GstFlowReturn stream_new_sample_wrapper(GstElement *appsink, gpointer user)
call_cb(&cbdata);
+ return cbdata.u.new_sample_data.ret;
+}
+
+gboolean activate_push_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
+{
+ struct cb_data cbdata = { ACTIVATE_PUSH_MODE };
+
+ cbdata.u.activate_mode_data.pad = pad;
+ cbdata.u.activate_mode_data.parent = parent;
+ cbdata.u.activate_mode_data.mode = mode;
+ cbdata.u.activate_mode_data.activate = activate;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.query_function_data.ret;
+}
+
+gboolean query_input_src_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
+{
+ struct cb_data cbdata = { QUERY_INPUT_SRC };
+
+ cbdata.u.query_function_data.pad = pad;
+ cbdata.u.query_function_data.parent = parent;
+ cbdata.u.query_function_data.query = query;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.query_function_data.ret;
+}
+
+GstBusSyncReply watch_decoder_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user)
+{
+ struct cb_data cbdata = { WATCH_DECODER_BUS };
+
+ cbdata.u.watch_bus_data.bus = bus;
+ cbdata.u.watch_bus_data.msg = message;
+ cbdata.u.watch_bus_data.user = user;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.watch_bus_data.ret;
+}
+
+void decoder_pad_added_wrapper(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct cb_data cbdata = { DECODER_PAD_ADDED };
+
+ cbdata.u.pad_added_data.element = element;
+ cbdata.u.pad_added_data.pad = pad;
+ cbdata.u.pad_added_data.user = user;
+
+ call_cb(&cbdata);
+}
+
+GstFlowReturn decoder_new_sample_wrapper(GstElement *appsink, gpointer user)
+{
+ struct cb_data cbdata = {DECODER_NEW_SAMPLE};
+
+ cbdata.u.new_sample_data.appsink = appsink;
+ cbdata.u.new_sample_data.user = user;
+
+ call_cb(&cbdata);
+
return cbdata.u.new_sample_data.ret;
}
\ No newline at end of file
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
index 106368a064..a35d6d8830 100644
--- a/dlls/winegstreamer/gst_cbs.h
+++ b/dlls/winegstreamer/gst_cbs.h
@@ -54,6 +54,12 @@ enum CB_TYPE {
SOURCE_ALL_STREAMS,
STREAM_NEW_SAMPLE,
MEDIA_SOURCE_MAX,
+ ACTIVATE_PUSH_MODE,
+ QUERY_INPUT_SRC,
+ DECODER_NEW_SAMPLE,
+ WATCH_DECODER_BUS,
+ DECODER_PAD_ADDED,
+ MF_DECODE_MAX,
};
struct cb_data {
@@ -143,6 +149,12 @@ struct cb_data {
gpointer user;
GstFlowReturn ret;
} new_sample_data;
+ struct chain_data {
+ GstPad *pad;
+ GstObject *parent;
+ GstBuffer *buffer;
+ GstFlowReturn ret;
+ } chain_data;
} u;
int finished;
@@ -154,6 +166,7 @@ struct cb_data {
void mark_wine_thread(void) DECLSPEC_HIDDEN;
void perform_cb_gstdemux(struct cb_data *data) DECLSPEC_HIDDEN;
void perform_cb_media_source(struct cb_data *data) DECLSPEC_HIDDEN;
+void perform_cb_mf_decode(struct cb_data *data) DECLSPEC_HIDDEN;
GstBusSyncReply watch_bus_wrapper(GstBus *bus, GstMessage *msg, gpointer user) DECLSPEC_HIDDEN;
void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
@@ -179,5 +192,10 @@ void source_stream_added_wrapper(GstElement *bin, GstPad *pad, gpointer user) DE
void source_stream_removed_wrapper(GstElement *element, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
void source_all_streams_wrapper(GstElement *element, gpointer user) DECLSPEC_HIDDEN;
GstFlowReturn stream_new_sample_wrapper(GstElement *appsink, gpointer user) DECLSPEC_HIDDEN;
+gboolean activate_push_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN;
+gboolean query_input_src_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
+GstBusSyncReply watch_decoder_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) DECLSPEC_HIDDEN;
+GstFlowReturn decoder_new_sample_wrapper(GstElement *appsink, gpointer user) DECLSPEC_HIDDEN;
+void decoder_pad_added_wrapper(GstElement *element, GstPad *Pad, gpointer user) DECLSPEC_HIDDEN;
#endif
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 258df0d040..6e25b895ff 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -53,6 +53,7 @@ BOOL init_gstreamer(void) DECLSPEC_HIDDEN;
void start_dispatch_thread(void) DECLSPEC_HIDDEN;
+extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN;
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
GstCaps *make_mf_compatible_caps(GstCaps *caps);
@@ -61,6 +62,12 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type);
IMFSample *mf_sample_from_gst_buffer(GstBuffer *in);
GstBuffer *gst_buffer_from_mf_sample(IMFSample *in);
+enum decoder_type
+{
+ DECODER_TYPE_H264,
+ DECODER_TYPE_AAC,
+};
+HRESULT generic_decoder_construct(REFIID riid, void **obj, enum decoder_type);
enum source_type
{
SOURCE_TYPE_MPEG_4,
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index 2872710b3e..12ca11fa6c 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -365,7 +365,8 @@ HRESULT WINAPI DllRegisterServer(void)
IFilterMapper2_RegisterFilter(mapper, &CLSID_WAVEParser, wave_parserW, NULL, NULL, NULL, &reg_wave_parser);
IFilterMapper2_Release(mapper);
- return S_OK;
+
+ return mfplat_DllRegisterServer();
}
HRESULT WINAPI DllUnregisterServer(void)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 6499c39a8f..aaef966a5b 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -404,6 +404,16 @@ failed:
return hr;
}
+static HRESULT h264_decoder_create(REFIID riid, void **ret)
+{
+ return generic_decoder_construct(riid, ret, DECODER_TYPE_H264);
+}
+
+static HRESULT aac_decoder_create(REFIID riid, void **ret)
+{
+ return generic_decoder_construct(riid, ret, DECODER_TYPE_AAC);
+}
+
static HRESULT mp4_stream_handler_create(REFIID riid, void **ret)
{
return container_stream_handler_construct(riid, ret, SOURCE_TYPE_MPEG_4);
@@ -417,6 +427,8 @@ static const struct class_object
class_objects[] =
{
{ &CLSID_VideoProcessorMFT, &video_processor_create },
+ { &CLSID_CMSH264DecoderMFT, &h264_decoder_create },
+ { &CLSID_CMSAACDecMFT, &aac_decoder_create },
{ &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create },
};
@@ -449,6 +461,111 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
return CLASS_E_CLASSNOTAVAILABLE;
}
+
+static WCHAR h264decoderW[] = {'H','.','2','6','4',' ','D','e','c','o','d','e','r',0};
+const GUID *h264_decoder_input_types[] =
+{
+ &MFVideoFormat_H264,
+};
+const GUID *h264_decoder_output_types[] =
+{
+ &MFVideoFormat_I420,
+ &MFVideoFormat_IYUV,
+ &MFVideoFormat_NV12,
+ &MFVideoFormat_YUY2,
+ &MFVideoFormat_YV12,
+};
+
+static WCHAR aacdecoderW[] = {'A','A','C',' ','D','e','c','o','d','e','r',0};
+const GUID *aac_decoder_input_types[] =
+{
+ &MFAudioFormat_AAC,
+};
+
+const GUID *aac_decoder_output_types[] =
+{
+ &MFAudioFormat_Float,
+ &MFAudioFormat_PCM,
+};
+
+static const struct mft
+{
+ const GUID *clsid;
+ const GUID *category;
+ LPWSTR name;
+ const UINT32 flags;
+ const GUID *major_type;
+ const UINT32 input_types_count;
+ const GUID **input_types;
+ const UINT32 output_types_count;
+ const GUID **output_types;
+ IMFAttributes *attributes;
+}
+mfts[] =
+{
+ {
+ &CLSID_CMSH264DecoderMFT,
+ &MFT_CATEGORY_VIDEO_DECODER,
+ h264decoderW,
+ MFT_ENUM_FLAG_SYNCMFT,
+ &MFMediaType_Video,
+ ARRAY_SIZE(h264_decoder_input_types),
+ h264_decoder_input_types,
+ ARRAY_SIZE(h264_decoder_output_types),
+ h264_decoder_output_types,
+ NULL
+ },
+ {
+ &CLSID_CMSAACDecMFT,
+ &MFT_CATEGORY_AUDIO_DECODER,
+ aacdecoderW,
+ MFT_ENUM_FLAG_SYNCMFT,
+ &MFMediaType_Audio,
+ ARRAY_SIZE(aac_decoder_input_types),
+ aac_decoder_input_types,
+ ARRAY_SIZE(aac_decoder_output_types),
+ aac_decoder_output_types,
+ NULL
+ }
+};
+
+HRESULT mfplat_DllRegisterServer(void)
+{
+ HRESULT hr;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(mfts); i++)
+ {
+ const struct mft *cur = &mfts[i];
+
+ MFT_REGISTER_TYPE_INFO *input_types, *output_types;
+ input_types = heap_alloc(cur->input_types_count * sizeof(input_types[0]));
+ output_types = heap_alloc(cur->output_types_count * sizeof(output_types[0]));
+ for (unsigned int i = 0; i < cur->input_types_count; i++)
+ {
+ input_types[i].guidMajorType = *(cur->major_type);
+ input_types[i].guidSubtype = *(cur->input_types[i]);
+ }
+ for (unsigned int i = 0; i < cur->output_types_count; i++)
+ {
+ output_types[i].guidMajorType = *(cur->major_type);
+ output_types[i].guidSubtype = *(cur->output_types[i]);
+ }
+
+ hr = MFTRegister(*(cur->clsid), *(cur->category), cur->name, cur->flags, cur->input_types_count,
+ input_types, cur->output_types_count, output_types, cur->attributes);
+
+ heap_free(input_types);
+ heap_free(output_types);
+
+ if (FAILED(hr))
+ {
+ FIXME("Failed to register MFT, hr %#x\n", hr);
+ return hr;
+ }
+ }
+ return S_OK;
+}
+
const static struct
{
const GUID *subtype;
@@ -467,7 +584,6 @@ struct aac_user_data
{
WORD payload_type;
WORD profile_level_indication;
- WORD struct_type;
WORD reserved;
/* audio-specific-config is stored here */
};
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl
index 997a28b052..ee8090cf4a 100644
--- a/dlls/winegstreamer/winegstreamer_classes.idl
+++ b/dlls/winegstreamer/winegstreamer_classes.idl
@@ -61,3 +61,15 @@ coclass VideoProcessorMFT {}
uuid(271c3902-6095-4c45-a22f-20091816ee9e)
]
coclass MPEG4ByteStreamHandler {}
+
+[
+ threading(both),
+ uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d)
+]
+coclass CMSH264DecoderMFT { }
+
+[
+ threading(both),
+ uuid(32d186a7-218f-4c75-8876-dd77273a8999)
+]
+coclass CMSAACDecMFT { }
diff --git a/include/mfidl.idl b/include/mfidl.idl
index fc13dfba7a..f7092dfa6c 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -1241,4 +1241,6 @@ 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_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
\ No newline at end of file
+cpp_quote("EXTERN_GUID(CLSID_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
+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.28.0

View File

@ -0,0 +1,28 @@
From 5b5fb65ee4d8f7e8932076b4d8ee0eb1722f0058 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 23 Mar 2020 11:55:41 -0500
Subject: [PATCH 34/54] 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 96a82b798a..3b1dcbb963 100644
--- a/dlls/mfreadwrite/reader.c
+++ b/dlls/mfreadwrite/reader.c
@@ -2120,6 +2120,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.28.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,225 @@
From 9a72ebab1d3dd0fdbe06a61ba473f019695477fe Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Wed, 25 Mar 2020 19:07:11 -0500
Subject: [PATCH 36/54] WMV
---
dlls/winegstreamer/gst_private.h | 2 +
dlls/winegstreamer/media_source.c | 3 ++
dlls/winegstreamer/mf_decode.c | 10 +++++
dlls/winegstreamer/mfplat.c | 47 ++++++++++++++++++++
dlls/winegstreamer/winegstreamer.rgs | 12 +++++
dlls/winegstreamer/winegstreamer_classes.idl | 12 +++++
include/mfidl.idl | 2 +
7 files changed, 88 insertions(+)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 6e25b895ff..0b61bc9e3c 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -66,11 +66,13 @@ enum decoder_type
{
DECODER_TYPE_H264,
DECODER_TYPE_AAC,
+ DECODER_TYPE_WMV,
};
HRESULT generic_decoder_construct(REFIID riid, void **obj, enum decoder_type);
enum source_type
{
SOURCE_TYPE_MPEG_4,
+ SOURCE_TYPE_ASF,
};
HRESULT container_stream_handler_construct(REFIID riid, void **obj, enum source_type);
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 308b98c5e6..c66e211faf 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -30,6 +30,9 @@ static struct source_desc
{
{/*SOURCE_TYPE_MPEG_4*/
GST_STATIC_CAPS("video/quicktime"),
+ },
+ {/*SOURCE_TYPE_ASF*/
+ GST_STATIC_CAPS("video/x-ms-asf"),
}
};
diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c
index f5d9a83cd4..21b310a996 100644
--- a/dlls/winegstreamer/mf_decode.c
+++ b/dlls/winegstreamer/mf_decode.c
@@ -28,6 +28,9 @@ const GUID *h264_output_types[] = {&MFVideoFormat_I420, &MFVideoFormat_IYUV, &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;
@@ -50,6 +53,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 aaef966a5b..e1735a5f82 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -414,11 +414,21 @@ 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 HRESULT mp4_stream_handler_create(REFIID riid, void **ret)
{
return container_stream_handler_construct(riid, ret, SOURCE_TYPE_MPEG_4);
}
+static HRESULT asf_stream_handler_create(REFIID riid, void **ret)
+{
+ return container_stream_handler_construct(riid, ret, SOURCE_TYPE_ASF);
+}
+
static const struct class_object
{
const GUID *clsid;
@@ -429,7 +439,9 @@ class_objects[] =
{ &CLSID_VideoProcessorMFT, &video_processor_create },
{ &CLSID_CMSH264DecoderMFT, &h264_decoder_create },
{ &CLSID_CMSAACDecMFT, &aac_decoder_create },
+ { &CLSID_CWMVDecMediaObject, &wmv_decoder_create },
{ &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create },
+ { &CLSID_ASFByteStreamHandler, &asf_stream_handler_create },
};
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
@@ -488,6 +500,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;
@@ -526,6 +561,18 @@ mfts[] =
ARRAY_SIZE(aac_decoder_output_types),
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
}
};
diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs
index 0bc26761e9..9dbbca1c80 100644
--- a/dlls/winegstreamer/winegstreamer.rgs
+++ b/dlls/winegstreamer/winegstreamer.rgs
@@ -23,6 +23,10 @@ HKLM
{
NoRemove 'ByteStreamHandlers'
{
+ '.asf'
+ {
+ val '{41457294-644C-4298-A28A-BD69F2C0CF3B}' = s 'ASF Byte Stream Handler'
+ }
'.m4v'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
@@ -31,6 +35,14 @@ HKLM
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
+ '.wma'
+ {
+ val '{41457294-644C-4298-A28A-BD69F2C0CF3B}' = s 'ASF Byte Stream Handler'
+ }
+ '.wmv'
+ {
+ val '{41457294-644C-4298-A28A-BD69F2C0CF3B}' = s 'ASF Byte Stream Handler'
+ }
'video/m4v'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl
index ee8090cf4a..376e08c418 100644
--- a/dlls/winegstreamer/winegstreamer_classes.idl
+++ b/dlls/winegstreamer/winegstreamer_classes.idl
@@ -73,3 +73,15 @@ coclass CMSH264DecoderMFT { }
uuid(32d186a7-218f-4c75-8876-dd77273a8999)
]
coclass CMSAACDecMFT { }
+
+[
+ threading(both),
+ uuid(41457294-644c-4298-a28a-BD69F2C0CF3B)
+]
+coclass ASFByteStreamHandler {}
+
+[
+ threading(both),
+ uuid(82d353df-90bd-4382-8bc2-3f6192b76e34)
+]
+coclass CLSID_CWMVDecMediaObject {}
\ No newline at end of file
diff --git a/include/mfidl.idl b/include/mfidl.idl
index f7092dfa6c..ce3707ba50 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -1244,3 +1244,5 @@ cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2
cpp_quote("EXTERN_GUID(CLSID_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
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.28.0

View File

@ -0,0 +1,42 @@
From 478ac7d5e467e93a7a71ce1c8b2ebb227d89e034 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 2 Apr 2020 15:42:18 -0500
Subject: [PATCH 37/54] mf: Ask for more samples from upstream node when upon
MF_E_TRANSFORM_NEED_MORE_INPUT
---
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 e2a6b868ca..748df396d7 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -2451,6 +2451,8 @@ static HRESULT transform_node_pull_samples(struct topo_node *node)
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)
{
@@ -2523,7 +2525,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(topo_node);
+ if (transform_node_pull_samples(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.28.0

View File

@ -0,0 +1,46 @@
From 3162911a265859e6767fb3c61229ca512dc06bc1 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 2 Apr 2020 15:43:52 -0500
Subject: [PATCH 38/54] mf: Miscelaneous fixes to topology resolution.
---
dlls/mf/topology.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index d4a59f7136..2e84920434 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -2026,7 +2026,7 @@ static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, IMFMediaType
IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0);
- IMFActivate_ShutdownObject(activates_convs[i]);
+ IMFActivate_ShutdownObject(activates_decs[i]);
return S_OK;
}
@@ -2165,12 +2165,14 @@ static HRESULT topology_loader_resolve_partial_topology(struct topology_node *sr
}
else
{
- if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, MF_CONNECT_DIRECT)))
- {
- topology_loader_add_branch(*full_topology, clone_src, clone_sink);
- heap_free(src_mediatypes);
- return S_OK;
- }
+ for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+ if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, method)))
+ {
+ TRACE("Successfully connected nodes with method %u\n", method);
+ topology_loader_add_branch(*full_topology, clone_src, clone_sink);
+ heap_free(src_mediatypes);
+ return S_OK;
+ }
}
heap_free(src_mediatypes);
--
2.28.0

View File

@ -0,0 +1,363 @@
From 5f7531a377c92c3491b2701108801e7e57f6f475 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 2 Apr 2020 15:45:52 -0500
Subject: [PATCH 39/54] Rewrite branch resolver.
and a HACK: Set output type of found decoder, this should probably happen somewhere else.
---
dlls/mf/topology.c | 279 +++++++++++++++++++++++++++------------------
1 file changed, 171 insertions(+), 108 deletions(-)
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index 2e84920434..94c9d63094 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1948,135 +1948,194 @@ static void topology_loader_add_branch(struct topology *topology, IMFTopologyNod
}
}
+struct available_output_type
+{
+ IMFMediaType *type;
+ IMFTransform *transform;
+};
+
+static HRESULT topology_loader_enumerate_output_types(GUID *category, IMFMediaType *input_type, HRESULT (*new_type)(struct available_output_type *, void *), void *context)
+{
+ MFT_REGISTER_TYPE_INFO mft_typeinfo;
+ GUID major_type, subtype;
+ IMFActivate **activates;
+ UINT32 num_activates;
+ HRESULT hr;
+
+ if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &major_type)))
+ return hr;
+
+ if (FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &subtype)))
+ return hr;
+
+ mft_typeinfo.guidMajorType = major_type;
+ mft_typeinfo.guidSubtype = subtype;
+
+ if (FAILED(hr = MFTEnumEx(*category, MFT_ENUM_FLAG_ALL, &mft_typeinfo, NULL, &activates, &num_activates)))
+ return hr;
+
+ hr = E_FAIL;
+
+ for (unsigned int i = 0; i < num_activates; i++)
+ {
+ IMFTransform *mft;
+
+ IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void**) &mft);
+
+ if (SUCCEEDED(hr = IMFTransform_SetInputType(mft, 0, input_type, 0)))
+ {
+ struct available_output_type avail = {.transform = mft};
+ unsigned int output_count = 0;
+
+ while (SUCCEEDED(IMFTransform_GetOutputAvailableType(mft, 0, output_count++, &avail.type)))
+ {
+ if (SUCCEEDED(hr = new_type(&avail, context)))
+ {
+ IMFActivate_ShutdownObject(activates[i]);
+ return hr;
+ }
+ }
+ }
+
+ IMFActivate_ShutdownObject(activates[i]);
+ }
+
+ return hr;
+}
+
+struct connect_to_sink_context
+{
+ IMFTopologyNode *src, *sink;
+ IMFMediaTypeHandler *sink_mth;
+};
+
+HRESULT connect_to_sink(struct available_output_type *type, void *context)
+{
+ IMFTopologyNode *node;
+ struct connect_to_sink_context *ctx = context;
+
+ if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(ctx->sink_mth, type->type)))
+ {
+ MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node);
+ IMFTopologyNode_SetObject(node, (IUnknown *) type->transform);
+ IMFTopologyNode_ConnectOutput(ctx->src, 0, node, 0);
+ IMFTopologyNode_ConnectOutput(node, 0, ctx->sink, 0);
+
+ IMFTransform_SetOutputType(type->transform, 0, type->type, 0);
+
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+struct connect_to_converter_context
+{
+ struct connect_to_sink_context sink_ctx;
+ GUID *converter_category;
+};
+
+HRESULT connect_to_converter(struct available_output_type *type, void *context)
+{
+ struct connect_to_converter_context *ctx = context;
+ struct connect_to_sink_context sink_ctx;
+ IMFTopologyNode *node;
+
+ MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node);
+ IMFTopologyNode_SetObject(node, (IUnknown *) type->transform);
+
+ sink_ctx = ctx->sink_ctx;
+ sink_ctx.src = node;
+ if (SUCCEEDED(topology_loader_enumerate_output_types(ctx->converter_category, type->type, connect_to_sink, &sink_ctx)))
+ {
+ IMFTopologyNode_ConnectOutput(ctx->sink_ctx.src, 0, node, 0);
+
+ IMFTransform_SetOutputType(type->transform, 0, type->type, 0);
+
+ return S_OK;
+ }
+ IMFTopologyNode_Release(node);
+ return E_FAIL;
+}
+
static HRESULT topology_loader_resolve_branch(IMFTopologyNode *src, IMFMediaType *mediatype, IMFTopologyNode *sink, MF_CONNECT_METHOD method)
{
+ struct connect_to_converter_context convert_ctx;
+ struct connect_to_sink_context sink_ctx;
+ GUID major_type, decode_cat, convert_cat;
IMFStreamSink *streamsink;
IMFMediaTypeHandler *mth;
HRESULT hr;
+ TRACE("method %u\n", method);
+
IMFTopologyNode_GetObject(sink, (IUnknown **)&streamsink);
IMFStreamSink_GetMediaTypeHandler(streamsink, &mth);
- if (method == MF_CONNECT_DIRECT)
+
+ if (SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype)))
{
- if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(mth, mediatype)))
- return hr;
- hr = IMFTopologyNode_ConnectOutput(src, 0, sink, 0);
+ return IMFTopologyNode_ConnectOutput(src, 0, sink, 0);
+ }
+
+ if (FAILED(hr = IMFMediaType_GetMajorType(mediatype, &major_type)))
return hr;
+
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+ {
+ decode_cat = MFT_CATEGORY_AUDIO_DECODER;
+ convert_cat = MFT_CATEGORY_AUDIO_EFFECT;
}
- else
+ else if (IsEqualGUID(&major_type, &MFMediaType_Video))
{
- IMFTopologyNode *node_dec, *node_conv;
- GUID major_type, subtype, mft_category;
- MFT_REGISTER_TYPE_INFO mft_typeinfo;
- UINT32 flags = MFT_ENUM_FLAG_ALL;
- IMFActivate **activates_decs;
- UINT32 num_activates_decs;
- int i, j;
-
- IMFMediaType_GetGUID(mediatype, &MF_MT_MAJOR_TYPE, &major_type);
- if (IsEqualGUID(&major_type, &MFMediaType_Audio))
- mft_category = MFT_CATEGORY_AUDIO_DECODER;
- else if (IsEqualGUID(&major_type, &MFMediaType_Video))
- mft_category = MFT_CATEGORY_VIDEO_DECODER;
- else
- return MF_E_INVALIDMEDIATYPE;
-
- IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype);
- mft_typeinfo.guidMajorType = major_type;
- mft_typeinfo.guidSubtype = subtype;
- MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_decs, &num_activates_decs);
-
- /* for getting converters later on */
- if (IsEqualGUID(&major_type, &MFMediaType_Audio))
- mft_category = MFT_CATEGORY_AUDIO_EFFECT;
- else if (IsEqualGUID(&major_type, &MFMediaType_Video))
- mft_category = MFT_CATEGORY_VIDEO_EFFECT;
-
- /*
- * Iterate over number of decoders.
- * Try to set input type on decoder with source's output media type.
- * If succeeds, iterate over decoder's output media types.
- * Try to set input type on sink with decoder's output media type.
- * If fails, iterate over number of converters.
- * Try to set input type on converter with decoder's output media type.
- * If succeeds, iterate over converters output media types.
- * Try to set input type on sink with converter's output media type.
- */
- for (i = 0; i < num_activates_decs; i++)
- {
- IMFTransform *decoder;
+ decode_cat = MFT_CATEGORY_VIDEO_DECODER;
+ convert_cat = MFT_CATEGORY_VIDEO_EFFECT;
+ }
+ else
+ return E_FAIL;
- IMFActivate_ActivateObject(activates_decs[i], &IID_IMFTransform, (void **)&decoder);
- if (SUCCEEDED(hr = IMFTransform_SetInputType(decoder, 0, mediatype, 0)))
- {
- UINT32 num_activates_convs;
- IMFActivate **activates_convs;
- IMFMediaType *decoder_mtype;
+ sink_ctx.src = src;
+ sink_ctx.sink = sink;
+ sink_ctx.sink_mth = mth;
- int count = 0;
- while (SUCCEEDED(IMFTransform_GetOutputAvailableType(decoder, 0, count++, &decoder_mtype)))
- {
- IMFTransform *converter;
+ convert_ctx.sink_ctx = sink_ctx;
+ convert_ctx.converter_category = &convert_cat;
- /* succeeded with source -> decoder -> sink */
- if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, decoder_mtype)))
- {
- MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
- IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
- IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
- IMFTopologyNode_ConnectOutput(node_dec, 0, sink, 0);
+ hr = E_FAIL;
- IMFActivate_ShutdownObject(activates_decs[i]);
- return S_OK;
- }
+ if (method & MF_CONNECT_ALLOW_CONVERTER)
+ {
+ if (SUCCEEDED(hr = topology_loader_enumerate_output_types(&convert_cat, mediatype, connect_to_sink, &sink_ctx)))
+ goto done;
+ }
- IMFMediaType_GetGUID(decoder_mtype, &MF_MT_SUBTYPE, &subtype);
- mft_typeinfo.guidSubtype = subtype;
- MFTEnumEx(mft_category, flags, &mft_typeinfo, NULL, &activates_convs, &num_activates_convs);
- for (j = 0; j < num_activates_convs; j++)
- {
- IMFMediaType *converter_mtype;
-
- IMFActivate_ActivateObject(activates_convs[j], &IID_IMFTransform, (void **)&converter);
- if (SUCCEEDED(IMFTransform_SetInputType(converter, 0, decoder_mtype, 0)))
- {
- int count = 0;
- while (SUCCEEDED(IMFTransform_GetOutputAvailableType(converter, 0, count++, &converter_mtype)))
- {
- /* succeeded with source -> decoder -> converter -> sink */
- if (SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(mth, converter_mtype)))
- {
- MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_dec);
- IMFTopologyNode_SetObject(node_dec, (IUnknown *)decoder);
- MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node_conv);
- IMFTopologyNode_SetObject(node_conv, (IUnknown *)converter);
- IMFTopologyNode_ConnectOutput(src, 0, node_dec, 0);
- IMFTopologyNode_ConnectOutput(node_dec, 0, node_conv, 0);
- IMFTopologyNode_ConnectOutput(node_conv, 0, sink, 0);
-
- IMFActivate_ShutdownObject(activates_convs[j]);
- IMFActivate_ShutdownObject(activates_decs[i]);
- return S_OK;
- }
- }
- }
- IMFActivate_ShutdownObject(activates_convs[j]);
- }
- }
- }
- IMFActivate_ShutdownObject(activates_decs[i]);
+ /* 2 = decoder flag */
+ if (method & 2)
+ {
+ if (method & MF_CONNECT_ALLOW_CONVERTER)
+ {
+ if (SUCCEEDED(hr = topology_loader_enumerate_output_types(&decode_cat, mediatype, connect_to_converter, &convert_ctx)))
+ goto done;
+ }
+ else
+ {
+ if (SUCCEEDED(hr = topology_loader_enumerate_output_types(&decode_cat, mediatype, connect_to_sink, &sink_ctx)))
+ goto done;
}
}
- return E_FAIL;
+
+ done:
+ IMFMediaTypeHandler_Release(mth);
+ IMFStreamSink_Release(streamsink);
+ return hr;
}
static HRESULT topology_loader_resolve_partial_topology(struct topology_node *src, struct topology_node *sink, struct topology *topology, struct topology **full_topology)
{
+ UINT32 method, src_method, sink_method, enum_src_types, streamid;
IMFMediaTypeHandler *mth_src, *mth_sink;
IMFTopologyNode *clone_src, *clone_sink;
- UINT32 method, enum_src_types, streamid;
IMFMediaType **src_mediatypes;
IMFStreamDescriptor *desc;
+ IMFAttributes *attrs_sink;
IMFAttributes *attrs_src;
IMFStreamSink *strm_sink;
IMFMediaType *mtype_src;
@@ -2084,6 +2143,7 @@ static HRESULT topology_loader_resolve_partial_topology(struct topology_node *sr
HRESULT hr;
int i;
+ attrs_sink = sink->attributes;
attrs_src = src->attributes;
if (FAILED(hr = IMFAttributes_GetUnknown(attrs_src, &MF_TOPONODE_STREAM_DESCRIPTOR, &IID_IMFStreamDescriptor, (void **)&desc)))
return hr;
@@ -2137,12 +2197,15 @@ static HRESULT topology_loader_resolve_partial_topology(struct topology_node *sr
if (FAILED(IMFTopologyNode_GetUINT32(clone_sink, &MF_TOPONODE_STREAMID, &streamid)))
IMFTopologyNode_SetUINT32(clone_sink, &MF_TOPONODE_STREAMID, 0);
+ if (FAILED(IMFAttributes_GetUINT32(attrs_sink, &MF_TOPONODE_CONNECT_METHOD, &sink_method)))
+ sink_method = MF_CONNECT_ALLOW_DECODER;
+
if (enum_src_types)
{
- hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &method);
- if (hr == S_OK && method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)
+ hr = IMFAttributes_GetUINT32(attrs_src, &MF_TOPONODE_CONNECT_METHOD, &src_method);
+ if (hr == S_OK && src_method != MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)
{
- for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+ for (method = MF_CONNECT_DIRECT; method <= sink_method; method++)
for (i = 0; i < num_media_types; i++)
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
{
@@ -2154,7 +2217,7 @@ static HRESULT topology_loader_resolve_partial_topology(struct topology_node *sr
else
{
for (i = 0; i < num_media_types; i++)
- for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+ for (method = MF_CONNECT_DIRECT; method <= sink_method; method++)
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[i], clone_sink, method)))
{
topology_loader_add_branch(*full_topology, clone_src, clone_sink);
@@ -2165,10 +2228,10 @@ static HRESULT topology_loader_resolve_partial_topology(struct topology_node *sr
}
else
{
- for (method = MF_CONNECT_DIRECT; method < MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES; method++)
+ for (method = MF_CONNECT_DIRECT; method <= sink_method; method++)
if (SUCCEEDED(topology_loader_resolve_branch(clone_src, src_mediatypes[0], clone_sink, method)))
{
- TRACE("Successfully connected nodes with method %u\n", method);
+ TRACE("Successfully connected nodes with method %u\n", src_method);
topology_loader_add_branch(*full_topology, clone_src, clone_sink);
heap_free(src_mediatypes);
return S_OK;
--
2.28.0

View File

@ -0,0 +1,35 @@
From 47d4811b9feead9bd1f4acbba67170d30561aa89 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 2 Apr 2020 15:46:25 -0500
Subject: [PATCH 40/54] winegstreamer: Implement
IMFMedisStream::GetMediaSource.
---
dlls/winegstreamer/media_source.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index c66e211faf..11b28176fd 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -842,12 +842,15 @@ static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMedi
{
struct media_stream *stream = impl_from_IMFMediaStream(iface);
- FIXME("stub (%p)->(%p)\n", stream, source);
+ TRACE("(%p)->(%p)\n", stream, source);
if (stream->state == STREAM_SHUTDOWN)
return MF_E_SHUTDOWN;
- return E_NOTIMPL;
+ IMFMediaSource_AddRef(&stream->parent_source->IMFMediaSource_iface);
+ *source = &stream->parent_source->IMFMediaSource_iface;
+
+ return S_OK;
}
static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
--
2.28.0

View File

@ -0,0 +1,25 @@
From a88773344facfd8e308f5feb6f69e12c334690e6 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 3 Apr 2020 11:12:33 -0500
Subject: [PATCH 41/54] 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 21b310a996..7fe216d67d 100644
--- a/dlls/winegstreamer/mf_decode.c
+++ b/dlls/winegstreamer/mf_decode.c
@@ -26,7 +26,7 @@ const GUID *h264_input_types[] = {&MFVideoFormat_H264};
const GUID *h264_output_types[] = {&MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_NV12, &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.28.0

View File

@ -0,0 +1,24 @@
From 6e87e29160026d27f950fce99f3a5a044add84af Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 3 Apr 2020 13:09:30 -0500
Subject: [PATCH 42/54] Set BPS on AAC.
---
dlls/winegstreamer/mfplat.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index e1735a5f82..780008face 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -916,6 +916,7 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps)
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)
--
2.28.0

View File

@ -0,0 +1,25 @@
From ba51cc01a42eb3cca95495afc42c68b7ec726ad8 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 1 May 2020 11:46:26 -0500
Subject: [PATCH 43/54] mfplat: Add I420 format information.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/mfplat/mediatype.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c
index 5eaa4fdd08..db789c4f8e 100644
--- a/dlls/mfplat/mediatype.c
+++ b/dlls/mfplat/mediatype.c
@@ -2238,6 +2238,7 @@ static const struct uncompressed_video_format video_formats[] =
{ &MFVideoFormat_A2R10G10B10, 4, 3, 1, 0 },
{ &MFVideoFormat_RGB8, 1, 3, 1, 0 },
{ &MFVideoFormat_L8, 1, 3, 1, 0 },
+ { &MFVideoFormat_I420, 1, 0, 0, 1 },
{ &MFVideoFormat_AYUV, 4, 3, 0, 1 },
{ &MFVideoFormat_I420, 1, 0, 0, 1 },
{ &MFVideoFormat_IMC1, 2, 3, 0, 1 },
--
2.28.0

View File

@ -0,0 +1,837 @@
From e8fa967f34edbe26f323498ad2a2b0ef313a01eb Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 1 May 2020 13:20:49 -0500
Subject: [PATCH 44/54] winegstreamer: Implement Color Converter MFT.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/Makefile.in | 1 +
dlls/winegstreamer/colorconvert.c | 704 +++++++++++++++++++
dlls/winegstreamer/gst_private.h | 2 +
dlls/winegstreamer/mfplat.c | 35 +
dlls/winegstreamer/winegstreamer_classes.idl | 8 +-
5 files changed, 749 insertions(+), 1 deletion(-)
create mode 100644 dlls/winegstreamer/colorconvert.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in
index e2af408582..a266b0a95e 100644
--- a/dlls/winegstreamer/Makefile.in
+++ b/dlls/winegstreamer/Makefile.in
@@ -6,6 +6,7 @@ EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS)
PARENTSRC = ../strmbase ../mf
C_SRCS = \
+ colorconvert.c \
filter.c \
gst_cbs.c \
gstdemux.c \
diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c
new file mode 100644
index 0000000000..f149ab553f
--- /dev/null
+++ b/dlls/winegstreamer/colorconvert.c
@@ -0,0 +1,704 @@
+#include "config.h"
+#include <gst/gst.h>
+
+#include "gst_private.h"
+#include "gst_cbs.h"
+
+#include "mfapi.h"
+#include "mferror.h"
+#include "mfidl.h"
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+const GUID *raw_types[] = {
+ &MFVideoFormat_RGB24,
+ &MFVideoFormat_RGB32,
+ &MFVideoFormat_RGB555,
+ &MFVideoFormat_RGB8,
+ &MFVideoFormat_AYUV,
+ &MFVideoFormat_I420,
+ &MFVideoFormat_IYUV,
+ &MFVideoFormat_NV11,
+ &MFVideoFormat_NV12,
+ &MFVideoFormat_UYVY,
+ &MFVideoFormat_v216,
+ &MFVideoFormat_v410,
+ &MFVideoFormat_YUY2,
+ &MFVideoFormat_YVYU,
+ &MFVideoFormat_YVYU,
+};
+
+struct color_converter
+{
+ IMFTransform IMFTransform_iface;
+ LONG refcount;
+ IMFAttributes *attributes;
+ IMFAttributes *output_attributes;
+ IMFMediaType *input_type;
+ IMFMediaType *output_type;
+ BOOL valid_state, inflight;
+ GstElement *container, *appsrc, *videoconvert, *appsink;
+ GstBus *bus;
+ CRITICAL_SECTION cs;
+};
+
+static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface)
+{
+ return CONTAINING_RECORD(iface, struct color_converter, IMFTransform_iface);
+}
+
+static HRESULT WINAPI color_converter_QueryInterface(IMFTransform *iface, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+ if (IsEqualIID(riid, &IID_IMFTransform) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFTransform_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI color_converter_AddRef(IMFTransform *iface)
+{
+ struct color_converter *transform = impl_color_converter_from_IMFTransform(iface);
+ ULONG refcount = InterlockedIncrement(&transform->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI color_converter_Release(IMFTransform *iface)
+{
+ struct color_converter *transform = impl_color_converter_from_IMFTransform(iface);
+ ULONG refcount = InterlockedDecrement(&transform->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ if (transform->attributes)
+ IMFAttributes_Release(transform->attributes);
+ if (transform->output_attributes)
+ IMFAttributes_Release(transform->output_attributes);
+ heap_free(transform);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI color_converter_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 color_converter_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+ TRACE("%p, %p, %p.\n", iface, inputs, outputs);
+
+ *inputs = *outputs = 1;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+ DWORD output_size, DWORD *outputs)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+
+ TRACE("%p %u %p\n", converter, id, info);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ /* If we create a wrapped GstBuffer, remove MFT_INPUT_STREAM_DOES_NOT_ADDREF */
+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF;
+ info->cbMaxLookahead = 0;
+ info->cbAlignment = 0;
+ /* this is incorrect */
+ info->hnsMaxLatency = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+
+ MFT_OUTPUT_STREAM_INFO stream_info = {};
+
+ TRACE("%p %u %p\n", converter, id, info);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ stream_info.dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
+ stream_info.cbSize = 0;
+ stream_info.cbAlignment = 0;
+
+ *info = stream_info;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+ struct color_converter *transform = impl_color_converter_from_IMFTransform(iface);
+
+ TRACE("%p, %p.\n", iface, attributes);
+
+ *attributes = transform->attributes;
+ IMFAttributes_AddRef(*attributes);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_GetInputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
+ IMFAttributes **attributes)
+{
+ struct color_converter *transform = impl_color_converter_from_IMFTransform(iface);
+
+ TRACE("%p, %u, %p.\n", iface, id, attributes);
+
+ *attributes = transform->output_attributes;
+ IMFAttributes_AddRef(*attributes);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+ TRACE("%p, %u.\n", iface, id);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+ TRACE("%p, %u, %p.\n", iface, streams, ids);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+ IMFMediaType **type)
+{
+ IMFMediaType *ret;
+ HRESULT hr;
+
+ 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;
+
+ 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 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)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ IMFMediaType *output_type;
+ HRESULT hr;
+
+ TRACE("%p, %u, %u, %p.\n", iface, id, index, type);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (!(converter->input_type))
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+
+ if (index >= ARRAY_SIZE(raw_types))
+ return MF_E_NO_MORE_TYPES;
+
+ if (FAILED(hr = MFCreateMediaType(&output_type)))
+ return hr;
+
+ copy_attr(output_type, converter->input_type, &MF_MT_MAJOR_TYPE);
+ copy_attr(output_type, converter->input_type, &MF_MT_FRAME_SIZE);
+ copy_attr(output_type, converter->input_type, &MF_MT_FRAME_RATE);
+
+ 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 void color_converter_update_pipeline_state(struct color_converter *converter)
+{
+ converter->valid_state = converter->input_type && converter->output_type;
+
+ if (!converter->valid_state)
+ {
+ gst_element_set_state(converter->container, GST_STATE_READY);
+ return;
+ }
+
+ g_object_set(converter->appsrc, "caps", caps_from_mf_media_type(converter->input_type), NULL);
+ g_object_set(converter->appsink, "caps", caps_from_mf_media_type(converter->output_type), NULL);
+
+ gst_element_set_state(converter->container, GST_STATE_PLAYING);
+ return;
+}
+
+static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ HRESULT hr;
+
+ 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;
+ BOOL found = FALSE;
+
+ 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 (unsigned int i = 0; i < ARRAY_SIZE(raw_types); i++)
+ {
+ UINT64 unused;
+
+ if (IsEqualGUID(&subtype, raw_types[i]))
+ {
+ if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &unused)))
+ return MF_E_INVALIDTYPE;
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ return MF_E_INVALIDTYPE;
+ }
+
+ if (flags & MFT_SET_TYPE_TEST_ONLY)
+ {
+ return S_OK;
+ }
+
+ hr = S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (type)
+ {
+ if (!converter->input_type)
+ if (FAILED(hr = MFCreateMediaType(&converter->input_type)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->input_type)))
+ goto done;
+ }
+ else if (converter->input_type)
+ {
+ IMFMediaType_Release(converter->input_type);
+ converter->input_type = NULL;
+ }
+
+ done:
+ if (hr == S_OK)
+ color_converter_update_pipeline_state(converter);
+ LeaveCriticalSection(&converter->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ HRESULT hr;
+ GUID major_type, subtype;
+ UINT64 unused;
+
+ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags);
+
+ if (id != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (type)
+ {
+ /* validate the type */
+
+ 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 (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &unused)))
+ return MF_E_INVALIDTYPE;
+
+ if (!(IsEqualGUID(&major_type, &MFMediaType_Video)))
+ return MF_E_INVALIDTYPE;
+
+ for (unsigned int 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;
+ }
+
+ EnterCriticalSection(&converter->cs);
+
+ hr = S_OK;
+
+ if (type)
+ {
+ if (!converter->output_type)
+ if (FAILED(hr = MFCreateMediaType(&converter->output_type)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->output_type)))
+ goto done;
+ }
+ else if (converter->output_type)
+ {
+ IMFMediaType_Release(converter->output_type);
+ converter->output_type = NULL;
+ }
+
+ done:
+ if (hr == S_OK)
+ color_converter_update_pipeline_state(converter);
+ LeaveCriticalSection(&converter->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("%p, %u, %p.\n", iface, id, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+ FIXME("%p, %u, %p.\n", iface, id, type);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+ FIXME("%p, %u, %p.\n", iface, id, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+ FIXME("%p, %p.\n", iface, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_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 color_converter_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+ TRACE("%p, %u, %p.\n", iface, id, event);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+ FIXME("%p, %u.\n", iface, message);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ GstBuffer *gst_buffer;
+ HRESULT hr = S_OK;
+ int ret;
+
+ 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->valid_state)
+ {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ goto done;
+ }
+
+ if (converter->inflight)
+ {
+ hr = MF_E_NOTACCEPTING;
+ goto done;
+ }
+
+ if (!(gst_buffer = gst_buffer_from_mf_sample(sample)))
+ {
+ hr = E_FAIL;
+ goto done;
+ }
+
+ 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\n", ret);
+ hr = E_FAIL;
+ goto done;
+ }
+
+ converter->inflight = TRUE;
+
+ done:
+ LeaveCriticalSection(&converter->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
+{
+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface);
+ MFT_OUTPUT_DATA_BUFFER *relevant_buffer = NULL;
+ GstSample *sample;
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status);
+
+ if (flags)
+ WARN("Unsupported flags %#x\n", flags);
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ MFT_OUTPUT_DATA_BUFFER *out_buffer = &samples[i];
+
+ if (out_buffer->dwStreamID != 0)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ if (relevant_buffer)
+ return MF_E_INVALIDSTREAMNUMBER;
+
+ relevant_buffer = out_buffer;
+ }
+
+ if (!relevant_buffer)
+ return S_OK;
+
+ EnterCriticalSection(&converter->cs);
+
+ if (!converter->valid_state)
+ {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ goto done;
+ }
+
+ if (!converter->inflight)
+ {
+ hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
+ goto done;
+ }
+
+ g_signal_emit_by_name(converter->appsink, "pull-sample", &sample);
+
+ converter->inflight = FALSE;
+
+ relevant_buffer->pSample = mf_sample_from_gst_buffer(gst_sample_get_buffer(sample));
+ gst_sample_unref(sample);
+ relevant_buffer->dwStatus = S_OK;
+ relevant_buffer->pEvents = NULL;
+ *status = 0;
+
+ done:
+ LeaveCriticalSection(&converter->cs);
+
+ return hr;
+}
+
+static const IMFTransformVtbl color_converter_vtbl =
+{
+ color_converter_QueryInterface,
+ color_converter_AddRef,
+ color_converter_Release,
+ color_converter_GetStreamLimits,
+ color_converter_GetStreamCount,
+ color_converter_GetStreamIDs,
+ color_converter_GetInputStreamInfo,
+ color_converter_GetOutputStreamInfo,
+ color_converter_GetAttributes,
+ color_converter_GetInputStreamAttributes,
+ color_converter_GetOutputStreamAttributes,
+ color_converter_DeleteInputStream,
+ color_converter_AddInputStreams,
+ color_converter_GetInputAvailableType,
+ color_converter_GetOutputAvailableType,
+ color_converter_SetInputType,
+ color_converter_SetOutputType,
+ color_converter_GetInputCurrentType,
+ color_converter_GetOutputCurrentType,
+ color_converter_GetInputStatus,
+ color_converter_GetOutputStatus,
+ color_converter_SetOutputBounds,
+ color_converter_ProcessEvent,
+ color_converter_ProcessMessage,
+ color_converter_ProcessInput,
+ color_converter_ProcessOutput,
+};
+
+HRESULT color_converter_create(REFIID riid, void **ret)
+{
+ struct color_converter *object;
+ HRESULT hr;
+
+ TRACE("%s %p\n", debugstr_guid(riid), ret);
+
+ if (!(object = heap_alloc_zero(sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+ object->IMFTransform_iface.lpVtbl = &color_converter_vtbl;
+ object->refcount = 1;
+
+ InitializeCriticalSection(&object->cs);
+
+ if (FAILED(hr = MFCreateAttributes(&object->attributes, 0)))
+ goto failed;
+
+ if (FAILED(hr = MFCreateAttributes(&object->output_attributes, 0)))
+ goto failed;
+
+ object->container = gst_bin_new(NULL);
+ object->bus = gst_bus_new();
+ gst_element_set_bus(object->container, object->bus);
+
+ if (!(object->appsrc = gst_element_factory_make("appsrc", NULL)))
+ {
+ ERR("Failed to create appsrc");
+ hr = E_FAIL;
+ goto failed;
+ }
+ gst_bin_add(GST_BIN(object->container), object->appsrc);
+
+ if (!(object->videoconvert = gst_element_factory_make("videoconvert", NULL)))
+ {
+ ERR("Failed to create converter\n");
+ hr = E_FAIL;
+ goto failed;
+ }
+ gst_bin_add(GST_BIN(object->container), object->videoconvert);
+
+ if (!(object->appsink = gst_element_factory_make("appsink", NULL)))
+ {
+ ERR("Failed to create appsink\n");
+ hr = E_FAIL;
+ goto failed;
+ }
+ 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");
+ hr = E_FAIL;
+ goto failed;
+ }
+
+ if (!(gst_element_link(object->videoconvert, object->appsink)))
+ {
+ ERR("Failed to link videoconvert to appsink\n");
+ hr = E_FAIL;
+ goto failed;
+ }
+
+ *ret = &object->IMFTransform_iface;
+ return S_OK;
+
+failed:
+
+ IMFTransform_Release(&object->IMFTransform_iface);
+ return hr;
+}
\ No newline at end of file
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 0b61bc9e3c..b855d650dc 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -76,4 +76,6 @@ enum source_type
};
HRESULT container_stream_handler_construct(REFIID riid, void **obj, enum source_type);
+HRESULT color_converter_create(REFIID riid, void **ret);
+
#endif /* __GST_PRIVATE_INCLUDED__ */
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 780008face..161c8032a7 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -429,6 +429,8 @@ static HRESULT asf_stream_handler_create(REFIID riid, void **ret)
return container_stream_handler_construct(riid, ret, SOURCE_TYPE_ASF);
}
+static GUID CLSID_CColorConvertDMO = {0x98230571,0x0087,0x4204,{0xb0,0x20,0x32,0x82,0x53,0x8e,0x57,0xd3}};
+
static const struct class_object
{
const GUID *clsid;
@@ -442,6 +444,7 @@ class_objects[] =
{ &CLSID_CWMVDecMediaObject, &wmv_decoder_create },
{ &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create },
{ &CLSID_ASFByteStreamHandler, &asf_stream_handler_create },
+ { &CLSID_CColorConvertDMO, &color_converter_create },
};
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
@@ -473,6 +476,26 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
return CLASS_E_CLASSNOTAVAILABLE;
}
+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[] =
+{
+ &MFVideoFormat_RGB24,
+ &MFVideoFormat_RGB32,
+ &MFVideoFormat_RGB555,
+ &MFVideoFormat_RGB8,
+ &MFVideoFormat_AYUV,
+ &MFVideoFormat_I420,
+ &MFVideoFormat_IYUV,
+ &MFVideoFormat_NV11,
+ &MFVideoFormat_NV12,
+ &MFVideoFormat_UYVY,
+ &MFVideoFormat_v216,
+ &MFVideoFormat_v410,
+ &MFVideoFormat_YUY2,
+ &MFVideoFormat_YVYU,
+ &MFVideoFormat_YVYU,
+};
static WCHAR h264decoderW[] = {'H','.','2','6','4',' ','D','e','c','o','d','e','r',0};
const GUID *h264_decoder_input_types[] =
@@ -538,6 +561,18 @@ static const struct mft
}
mfts[] =
{
+ {
+ &CLSID_CColorConvertDMO,
+ &MFT_CATEGORY_VIDEO_EFFECT,
+ color_converterW,
+ MFT_ENUM_FLAG_SYNCMFT,
+ &MFMediaType_Video,
+ ARRAY_SIZE(color_converter_supported_types),
+ color_converter_supported_types,
+ ARRAY_SIZE(color_converter_supported_types),
+ color_converter_supported_types,
+ NULL
+ },
{
&CLSID_CMSH264DecoderMFT,
&MFT_CATEGORY_VIDEO_DECODER,
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl
index 376e08c418..d933d40cfd 100644
--- a/dlls/winegstreamer/winegstreamer_classes.idl
+++ b/dlls/winegstreamer/winegstreamer_classes.idl
@@ -84,4 +84,10 @@ coclass ASFByteStreamHandler {}
threading(both),
uuid(82d353df-90bd-4382-8bc2-3f6192b76e34)
]
-coclass CLSID_CWMVDecMediaObject {}
\ No newline at end of file
+coclass CLSID_CWMVDecMediaObject {}
+
+[
+ threading(both),
+ uuid(98230571-0087-4204-b020-3282538e57d3)
+]
+coclass CColorConvertDMO { }
\ No newline at end of file
--
2.28.0

View File

@ -0,0 +1,28 @@
From 97211ce51e21d1b1fd7f6fe1bf442f0ce5152f7b Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 1 May 2020 22:36:02 -0500
Subject: [PATCH 45/54] HACK: Set BPS to 16 for output template.
---
dlls/winegstreamer/mf_decode.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c
index 7fe216d67d..c7e1bfb1a9 100644
--- a/dlls/winegstreamer/mf_decode.c
+++ b/dlls/winegstreamer/mf_decode.c
@@ -321,6 +321,11 @@ static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWO
return hr;
}
+ if (IsEqualGUID(decoder_descs[decoder->type].output_types[index], &MFAudioFormat_PCM))
+ {
+ IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 16);
+ }
+
*type = output_type;
return S_OK;
--
2.28.0

View File

@ -0,0 +1,25 @@
From 1a9c319df408558561b503743f64061df204b237 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 4 May 2020 12:40:56 -0500
Subject: [PATCH 46/54] Set "wait-on-eos" to allow other streams to continue
while appsink buffers.
---
dlls/winegstreamer/media_source.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 11b28176fd..1ce9b06b8c 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -1038,6 +1038,7 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
g_object_set(object->appsink, "emit-signals", TRUE, NULL);
g_object_set(object->appsink, "sync", FALSE, NULL);
g_object_set(object->appsink, "async", FALSE, NULL); /* <- This allows us interact with the bin w/o prerolling */
+ g_object_set(object->appsink, "wait-on-eos", FALSE, NULL);
g_signal_connect(object->appsink, "new-sample", G_CALLBACK(stream_new_sample_wrapper), object);
if (FAILED(hr = media_stream_align_with_mf(object, &stream_type)))
--
2.28.0

View File

@ -0,0 +1,62 @@
From 541db537f1af37c69cc03d024114930e69dd7239 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 5 May 2020 15:35:16 -0500
Subject: [PATCH 47/54] Report streams backwards and only select one of each
stream type.
---
dlls/winegstreamer/media_source.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 1ce9b06b8c..3052c0393a 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -1431,6 +1431,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
source_descs[type].bytestream_caps);
struct media_source *object = heap_alloc_zero(sizeof(*object));
+ BOOL video_selected = FALSE, audio_selected = FALSE;
GList *demuxer_list_one, *demuxer_list_two;
GstElementFactory *demuxer_factory = NULL;
IMFStreamDescriptor **descriptors = NULL;
@@ -1528,15 +1529,34 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t
descriptors = heap_alloc(object->stream_count * sizeof(IMFStreamDescriptor*));
for (unsigned int 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(MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
goto fail;
+ /* Select one of each major type. */
for (unsigned int i = 0; i < object->stream_count; i++)
{
- IMFPresentationDescriptor_SelectStream(object->pres_desc, i);
+ IMFMediaTypeHandler *handler;
+ GUID major_type;
+ BOOL select_stream = FALSE;
+
+ IMFStreamDescriptor_GetMediaTypeHandler(descriptors[i], &handler);
+ IMFMediaTypeHandler_GetMajorType(handler, &major_type);
+ if (IsEqualGUID(&major_type, &MFMediaType_Video) && !video_selected)
+ {
+ select_stream = TRUE;
+ video_selected = TRUE;
+ }
+ if (IsEqualGUID(&major_type, &MFMediaType_Audio) && !audio_selected)
+ {
+ select_stream = TRUE;
+ audio_selected = TRUE;
+ }
+ if (select_stream)
+ IMFPresentationDescriptor_SelectStream(object->pres_desc, i);
+ IMFMediaTypeHandler_Release(handler);
IMFStreamDescriptor_Release(descriptors[i]);
}
heap_free(descriptors);
--
2.28.0

View File

@ -0,0 +1,80 @@
From 23fc1309973d818a608a54d3ac0c04bc731aa32a Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Thu, 7 May 2020 13:09:47 -0500
Subject: [PATCH 48/54] winegstreamer: Implement IMFMediaSource::Stop.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/media_source.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 3052c0393a..78395f9dcd 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -60,6 +60,7 @@ struct media_stream
enum source_async_op
{
SOURCE_ASYNC_START,
+ SOURCE_ASYNC_STOP,
SOURCE_ASYNC_REQUEST_SAMPLE,
};
@@ -326,6 +327,23 @@ static HRESULT start_pipeline(struct media_source *source, struct source_async_c
return S_OK;
}
+static void stop_pipeline(struct media_source *source)
+{
+ for (unsigned int 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;
+
+ gst_element_set_state(source->container, GST_STATE_READY);
+ gst_element_get_state(source->container, NULL, NULL, -1);
+}
+
static void dispatch_end_of_presentation(struct media_source *source)
{
PROPVARIANT empty = {.vt = VT_EMPTY};
@@ -416,6 +434,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;
@@ -1245,13 +1266,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.28.0

View File

@ -0,0 +1,153 @@
From 6f5d0e6c4694d6dab828318998ed6f5c1c33b27a Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 11 May 2020 16:05:50 -0500
Subject: [PATCH 49/54] 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 | 34 ++++++++++++++++++++
dlls/winegstreamer/winegstreamer_classes.idl | 6 ++++
include/mfidl.idl | 1 +
5 files changed, 52 insertions(+)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index b855d650dc..6dc90e2881 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -67,6 +67,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);
enum source_type
diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c
index c7e1bfb1a9..633a468ed3 100644
--- a/dlls/winegstreamer/mf_decode.c
+++ b/dlls/winegstreamer/mf_decode.c
@@ -31,6 +31,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;
@@ -60,6 +63,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 161c8032a7..e0da02074e 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -419,6 +419,11 @@ 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 HRESULT mp4_stream_handler_create(REFIID riid, void **ret)
{
return container_stream_handler_construct(riid, ret, SOURCE_TYPE_MPEG_4);
@@ -442,6 +447,7 @@ class_objects[] =
{ &CLSID_CMSH264DecoderMFT, &h264_decoder_create },
{ &CLSID_CMSAACDecMFT, &aac_decoder_create },
{ &CLSID_CWMVDecMediaObject, &wmv_decoder_create },
+ { &CLSID_CMpeg4sDecMFT, m4s2_decoder_create },
{ &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create },
{ &CLSID_ASFByteStreamHandler, &asf_stream_handler_create },
{ &CLSID_CColorConvertDMO, &color_converter_create },
@@ -546,6 +552,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;
@@ -608,6 +630,18 @@ mfts[] =
ARRAY_SIZE(wmv_decoder_output_types),
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
}
};
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl
index d933d40cfd..3a3daad3ab 100644
--- a/dlls/winegstreamer/winegstreamer_classes.idl
+++ b/dlls/winegstreamer/winegstreamer_classes.idl
@@ -74,6 +74,12 @@ coclass CMSH264DecoderMFT { }
]
coclass CMSAACDecMFT { }
+[
+ threading(both),
+ uuid(5686a0d9-fe39-409f-9dff-3fdbc849f9f5)
+]
+coclass CMpeg4sDecMFT { }
+
[
threading(both),
uuid(41457294-644c-4298-a28a-BD69F2C0CF3B)
diff --git a/include/mfidl.idl b/include/mfidl.idl
index ce3707ba50..35dd4c2f96 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -1244,5 +1244,6 @@ cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2
cpp_quote("EXTERN_GUID(CLSID_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
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.28.0

View File

@ -0,0 +1,48 @@
From 3450bedc5c9b3e80be234b30191e3e604d24495d Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 12 May 2020 16:48:52 -0500
Subject: [PATCH 50/54] HACK: Switch between all selection streams on
MF_SOURCE_READER_ANY_STREAM.
---
dlls/mfreadwrite/reader.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c
index f8c03e62d3..423250e3cb 100644
--- a/dlls/mfreadwrite/reader.c
+++ b/dlls/mfreadwrite/reader.c
@@ -1045,7 +1045,29 @@ static HRESULT source_reader_get_stream_read_index(struct source_reader *reader,
{
/* Cycle through all selected streams once, next pick first selected. */
if (FAILED(hr = source_reader_get_first_selected_stream(reader, STREAM_FLAG_REQUESTED_ONCE, stream_index)))
- hr = source_reader_get_first_selected_stream(reader, 0, stream_index);
+ {
+ //hr = source_reader_get_first_selected_stream(reader, 0, stream_index);
+ static int last_selection = -1;
+ int i;
+ BOOL selected;
+
+ for (i = 0; i < (int) reader->stream_count; ++i)
+ {
+ source_reader_get_stream_selection(reader, i, &selected);
+ if (selected && i > last_selection)
+ {
+ last_selection = i;
+ *stream_index = i;
+ hr = S_OK;
+ break;
+ }
+ }
+ if (i == reader->stream_count)
+ {
+ hr = source_reader_get_first_selected_stream(reader, 0, stream_index);
+ last_selection = hr == S_OK ? *stream_index : -1;
+ }
+ }
}
return hr;
default:
--
2.28.0

View File

@ -0,0 +1,151 @@
From 39e3081768b545c0c4f3f16f4b7d3219d0b249b1 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 12 May 2020 16:50:41 -0500
Subject: [PATCH 51/54] 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 6dc90e2881..af2134078a 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -67,6 +67,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);
diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c
index 633a468ed3..3d314eaab4 100644
--- a/dlls/winegstreamer/mf_decode.c
+++ b/dlls/winegstreamer/mf_decode.c
@@ -31,6 +31,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};
@@ -64,6 +67,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 e0da02074e..bcfcd398ec 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -419,6 +419,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);
@@ -447,6 +452,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 },
{ &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create },
{ &CLSID_ASFByteStreamHandler, &asf_stream_handler_create },
@@ -552,6 +558,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[] =
@@ -631,6 +651,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 3a3daad3ab..9f210fbbf7 100644
--- a/dlls/winegstreamer/winegstreamer_classes.idl
+++ b/dlls/winegstreamer/winegstreamer_classes.idl
@@ -92,6 +92,12 @@ coclass ASFByteStreamHandler {}
]
coclass CLSID_CWMVDecMediaObject {}
+[
+ threading(both),
+ uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a)
+]
+coclass CLSID_CWMADecMediaObject {}
+
[
threading(both),
uuid(98230571-0087-4204-b020-3282538e57d3)
diff --git a/include/mfidl.idl b/include/mfidl.idl
index 35dd4c2f96..3c11402931 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -1246,4 +1246,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.28.0

View File

@ -0,0 +1,27 @@
From 12817ac3db28b1945a664ea3411186e1e64f6ed4 Mon Sep 17 00:00:00 2001
From: Victor Hermann Chiletto <v@hnn.net.br>
Date: Tue, 9 Jun 2020 01:35:53 -0300
Subject: [PATCH 52/54] winegstreamer: Fix unrecognized format errors when
transforming caps to media type
Probably not needed, but it's nice to get this out of the way
---
dlls/winegstreamer/mfplat.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index bcfcd398ec..39b98f3eba 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -910,6 +910,8 @@ static IMFMediaType* transform_to_media_type(GstCaps *caps)
{
if (!(strcmp(format, "WVC1")))
IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WVC1);
+ else if (!(strcmp(format, "WMV3")))
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_WMV3);
else
FIXME("Unrecognized format %s\n", format);
}
--
2.28.0

View File

@ -0,0 +1,32 @@
From 69fd2aa695178b36154ded6a13b74a5ec4b98304 Mon Sep 17 00:00:00 2001
From: Victor Hermann Chiletto <v@hnn.net.br>
Date: Tue, 9 Jun 2020 01:36:53 -0300
Subject: [PATCH 53/54] winegstreamer: Translate WMV3 attributes to caps
---
dlls/winegstreamer/mfplat.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 39b98f3eba..042c02c486 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -1319,6 +1319,15 @@ GstCaps *caps_from_mf_media_type(IMFMediaType *type)
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 {
FIXME("Unrecognized subtype %s\n", debugstr_guid(&subtype));
return NULL;
--
2.28.0

View File

@ -0,0 +1,42 @@
From 8aabbee010a69fde257706cf3d178864feb1858c Mon Sep 17 00:00:00 2001
From: Victor Hermann Chiletto <v@hnn.net.br>
Date: Wed, 10 Jun 2020 01:10:57 -0300
Subject: [PATCH 54/54] winegstreamer: expose NV12 as the first color space in
IMFTransform::GetOutputAvailableType
---
dlls/winegstreamer/mf_decode.c | 2 +-
dlls/winegstreamer/mfplat.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/mf_decode.c b/dlls/winegstreamer/mf_decode.c
index 3d314eaab4..6e41838fdc 100644
--- a/dlls/winegstreamer/mf_decode.c
+++ b/dlls/winegstreamer/mf_decode.c
@@ -23,7 +23,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
/* keep in sync with mfplat.c's mft registrations */
const GUID *h264_input_types[] = {&MFVideoFormat_H264};
-const GUID *h264_output_types[] = {&MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_NV12, &MFVideoFormat_YUY2, &MFVideoFormat_YV12};
+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, &MFAudioFormat_PCM};
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 042c02c486..94e6ca534f 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -516,9 +516,9 @@ const GUID *h264_decoder_input_types[] =
};
const GUID *h264_decoder_output_types[] =
{
+ &MFVideoFormat_NV12,
&MFVideoFormat_I420,
&MFVideoFormat_IYUV,
- &MFVideoFormat_NV12,
&MFVideoFormat_YUY2,
&MFVideoFormat_YV12,
};
--
2.28.0

View File

@ -0,0 +1 @@
Fixes: [49692] mfplat: Improved support for multiple video formats.

View File

@ -149,6 +149,7 @@ patch_enable_all ()
enable_krnl386_exe16_GDT_LDT_Emulation="$1"
enable_krnl386_exe16_Invalid_Console_Handles="$1"
enable_loader_KeyboardLayouts="$1"
enable_mfplat_streaming_support="$1"
enable_mmsystem_dll16_MIDIHDR_Refcount="$1"
enable_mountmgr_DosDevices="$1"
enable_mscoree_CorValidateImage="$1"
@ -537,6 +538,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"
;;
@ -3142,6 +3146,133 @@ if test "$enable_loader_KeyboardLayouts" -eq 1; then
) >> "$patchlist"
fi
# Patchset mfplat-streaming-support
# |
# | This patchset fixes the following Wine bugs:
# | * [#49692] mfplat: Improved support for multiple video formats.
# |
# | Modified files:
# | * dlls/mf/Makefile.in, dlls/mf/handler.c, dlls/mf/handler.h, dlls/mf/main.c, dlls/mf/session.c, dlls/mf/tests/mf.c,
# | dlls/mf/topology.c, dlls/mfplat/mediatype.c, dlls/mfplat/tests/mfplat.c, dlls/mfreadwrite/reader.c,
# | dlls/winegstreamer/Makefile.in, dlls/winegstreamer/colorconvert.c, dlls/winegstreamer/gst_cbs.c,
# | dlls/winegstreamer/gst_cbs.h, dlls/winegstreamer/gst_private.h, dlls/winegstreamer/main.c,
# | dlls/winegstreamer/media_source.c, dlls/winegstreamer/mf_decode.c, dlls/winegstreamer/mfplat.c,
# | dlls/winegstreamer/winegstreamer.rgs, dlls/winegstreamer/winegstreamer_classes.idl, include/mfidl.idl,
# | tools/make_makefiles, tools/makedep.c
# |
if test "$enable_mfplat_streaming_support" -eq 1; then
patch_apply mfplat-streaming-support/0001-Revert-mf-topoloader-Add-a-structure-for-iterative-b.patch
patch_apply mfplat-streaming-support/0002-Revert-mf-topoloader-Clone-source-nodes-as-a-first-l.patch
patch_apply mfplat-streaming-support/0003-Revert-mf-topoloader-Switch-to-public-interface-for-.patch
patch_apply mfplat-streaming-support/0004-mf-tests-Sink-objects-are-stream-sinks-not-media-sin.patch
patch_apply mfplat-streaming-support/0005-mf-tests-Add-tests-for-the-topology-loader.patch
patch_apply mfplat-streaming-support/0006-mf-Partially-implement-the-topology-loader.patch
patch_apply mfplat-streaming-support/0007-Implement-stub-bytestream-handler-and-source.patch
patch_apply mfplat-streaming-support/0008-winegstreamer-Implement-IMFMediaSource-Shutdown.patch
patch_apply mfplat-streaming-support/0009-winegstreamer-Add-a-GstPad-wrapping-the-media-source.patch
patch_apply mfplat-streaming-support/0010-winegstreamer-Find-an-appropriate-demuxer-for-the-so.patch
patch_apply mfplat-streaming-support/0011-winegstreamer-Use-the-demuxer-to-establish-IMFMediaS.patch
patch_apply mfplat-streaming-support/0012-winegstreamer-Implement-IMFMediaStream-GetStreamDesc.patch
patch_apply mfplat-streaming-support/0013-winegstreamer-Translate-H.264-caps-to-attributes.patch
patch_apply mfplat-streaming-support/0014-winegstreamer-Translate-WMV-caps-to-attributes.patch
patch_apply mfplat-streaming-support/0015-winegstreamer-Translate-AAC-caps-to-attributes.patch
patch_apply mfplat-streaming-support/0016-winegstreamer-Translate-MPEG-4-Section-2-caps-to-att.patch
patch_apply mfplat-streaming-support/0017-winegstreamer-Translate-WMA-caps-to-attributes.patch
patch_apply mfplat-streaming-support/0018-winegstreamer-Implement-IMFMediaSource-CreatePresent.patch
patch_apply mfplat-streaming-support/0019-winegstreamer-Implement-IMFMediaSource-Start.patch
patch_apply mfplat-streaming-support/0020-winegstreamer-Insert-parser-into-pipeline-to-rectify.patch
patch_apply mfplat-streaming-support/0021-winegstreamer-Implement-IMFMediaStream-RequestSample.patch
patch_apply mfplat-streaming-support/0022-winegstreamer-Implement-IMFMediaSource-GetCharacteri.patch
patch_apply mfplat-streaming-support/0023-winegstreamer-Calculate-the-MF_PD_DURATION-of-the-me.patch
patch_apply mfplat-streaming-support/0024-tools-Add-support-for-multiple-parent-directories.patch
patch_apply mfplat-streaming-support/0025-mf-Introduce-handler-helper.patch
patch_apply mfplat-streaming-support/0026-winegstreamer-Introduce-IMFMediaType-GstCaps-convert.patch
patch_apply mfplat-streaming-support/0027-winegstreamer-Translate-H.264-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0028-winegstreamer-Translate-WMV-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0029-winegstreamer-Translate-AAC-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0030-winegstreamer-Translate-MPEG-4-Section-2-attributes-.patch
patch_apply mfplat-streaming-support/0031-winegstreamer-Translate-WMA-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0032-Introduce-IMFSample-GstBuffer-converter.patch
patch_apply mfplat-streaming-support/0033-winegstreamer-Implement-decoder-MFT-on-gstreamer.patch
patch_apply mfplat-streaming-support/0034-mfreadwrite-Select-all-streams-when-creating-a-sourc.patch
patch_apply mfplat-streaming-support/0035-Miscellaneous.patch
patch_apply mfplat-streaming-support/0036-WMV.patch
patch_apply mfplat-streaming-support/0037-mf-Ask-for-more-samples-from-upstream-node-when-upon.patch
patch_apply mfplat-streaming-support/0038-mf-Miscelaneous-fixes-to-topology-resolution.patch
patch_apply mfplat-streaming-support/0039-Rewrite-branch-resolver.patch
patch_apply mfplat-streaming-support/0040-winegstreamer-Implement-IMFMedisStream-GetMediaSourc.patch
patch_apply mfplat-streaming-support/0041-Expose-PCM-output-type-on-AAC-decoder.patch
patch_apply mfplat-streaming-support/0042-Set-BPS-on-AAC.patch
patch_apply mfplat-streaming-support/0043-mfplat-Add-I420-format-information.patch
patch_apply mfplat-streaming-support/0044-winegstreamer-Implement-Color-Converter-MFT.patch
patch_apply mfplat-streaming-support/0045-HACK-Set-BPS-to-16-for-output-template.patch
patch_apply mfplat-streaming-support/0046-Set-wait-on-eos-to-allow-other-streams-to-continue-w.patch
patch_apply mfplat-streaming-support/0047-Report-streams-backwards-and-only-select-one-of-each.patch
patch_apply mfplat-streaming-support/0048-winegstreamer-Implement-IMFMediaSource-Stop.patch
patch_apply mfplat-streaming-support/0049-winegstreamer-Introduce-MPEG-4-Section-2-video-decod.patch
patch_apply mfplat-streaming-support/0050-HACK-Switch-between-all-selection-streams-on-MF_SOUR.patch
patch_apply mfplat-streaming-support/0051-winegstreamer-Introduce-WMA-audio-decoder.patch
patch_apply mfplat-streaming-support/0052-winegstreamer-Fix-unrecognized-format-errors-when-tr.patch
patch_apply mfplat-streaming-support/0053-winegstreamer-Translate-WMV3-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0054-winegstreamer-expose-NV12-as-the-first-color-space-i.patch
(
printf '%s\n' '+ { "Alistair Leslie-Hughes", "Revert \"mf/topoloader: Add a structure for iterative branch resolution.\".", 1 },';
printf '%s\n' '+ { "Alistair Leslie-Hughes", "Revert \"mf/topoloader: Clone source nodes as a first layer of resulting topology.\".", 1 },';
printf '%s\n' '+ { "Alistair Leslie-Hughes", "Revert \"mf/topoloader: Switch to public interface for initial topology validation.\".", 1 },';
printf '%s\n' '+ { "Sergio Gómez Del Real", "mf/tests: Sink objects are stream sinks, not media sinks.", 1 },';
printf '%s\n' '+ { "Sergio Gómez Del Real", "mf/tests: Add tests for the topology loader.", 1 },';
printf '%s\n' '+ { "Sergio Gómez Del Real", "mf: Partially implement the topology loader.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "Implement stub bytestream handler and source.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement IMFMediaSource::Shutdown.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Add a GstPad wrapping the media source'\''s bytestream.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Find an appropriate demuxer for the source.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Use the demuxer to establish IMFMediaStreams.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement IMFMediaStream::GetStreamDescriptor.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate H.264 caps to attributes.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate WMV caps to attributes.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate AAC caps to attributes.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate MPEG-4 Section-2 caps to attributes.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate WMA caps to attributes.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement IMFMediaSource::CreatePresentationDescriptor.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement IMFMediaSource::Start.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Insert parser into pipeline to rectify type differences.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement IMFMediaStream::RequestSample.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement IMFMediaSource::GetCharacteristics.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Calculate the MF_PD_DURATION of the media source'\''s PD.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "tools: Add support for multiple parent directories.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "mf: Introduce handler helper.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Introduce IMFMediaType -> GstCaps converter.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate H.264 attributes to caps.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate WMV attributes to caps.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate AAC attributes to caps.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate MPEG-4 Section-2 attributes to caps.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Translate WMA attributes to caps.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "Introduce IMFSample -> GstBuffer converter.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement decoder MFT on gstreamer.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "mfreadwrite: Select all streams when creating a source reader.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "Miscellaneous.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "WMV.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "mf: Ask for more samples from upstream node when upon MF_E_TRANSFORM_NEED_MORE_INPUT.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "mf: Miscelaneous fixes to topology resolution.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "Rewrite branch resolver.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement IMFMedisStream::GetMediaSource.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "Expose PCM output type on AAC decoder.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "Set BPS on AAC.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "mfplat: Add I420 format information.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement Color Converter MFT.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "HACK: Set BPS to 16 for output template.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "Set \"wait-on-eos\" to allow other streams to continue while appsink buffers.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "Report streams backwards and only select one of each stream type.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Implement IMFMediaSource::Stop.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Introduce MPEG-4 Section-2 video decoder.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "HACK: Switch between all selection streams on MF_SOURCE_READER_ANY_STREAM.", 1 },';
printf '%s\n' '+ { "Derek Lesho", "winegstreamer: Introduce WMA audio decoder.", 1 },';
printf '%s\n' '+ { "Victor Hermann Chiletto", "winegstreamer: Fix unrecognized format errors when transforming caps to media type.", 1 },';
printf '%s\n' '+ { "Victor Hermann Chiletto", "winegstreamer: Translate WMV3 attributes to caps.", 1 },';
printf '%s\n' '+ { "Victor Hermann Chiletto", "winegstreamer: Expose NV12 as the first color space in IMFTransform::GetOutputAvailableType.", 1 },';
) >> "$patchlist"
fi
# Patchset mmsystem.dll16-MIDIHDR_Refcount
# |
# | This patchset fixes the following Wine bugs: