[PATCH 4/5] mf/session: Implement support for sinks that provide sample allocators.
Nikolay Sivov
nsivov at codeweavers.com
Thu Nov 12 04:36:38 CST 2020
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/mf/session.c | 173 ++++++++++++++++++++++++++++++++++++++--------
1 file changed, 146 insertions(+), 27 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index af8500cb7d6..cf351c003e7 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -45,6 +45,7 @@ enum session_command
/* Internally used commands. */
SESSION_CMD_END,
SESSION_CMD_QM_NOTIFY_TOPOLOGY,
+ SESSION_CMD_SA_READY,
};
struct session_op
@@ -68,6 +69,10 @@ struct session_op
{
IMFTopology *topology;
} notify_topology;
+ struct
+ {
+ TOPOID node_id;
+ } sa_ready;
} u;
struct list entry;
};
@@ -148,6 +153,7 @@ enum topo_node_flags
struct topo_node
{
struct list entry;
+ struct media_session *session;
MF_TOPOLOGY_TYPE type;
TOPOID node_id;
IMFTopologyNode *node;
@@ -171,7 +177,9 @@ struct topo_node
struct
{
unsigned int requests;
+ IMFVideoSampleAllocatorNotify notify_cb;
IMFVideoSampleAllocator *allocator;
+ IMFVideoSampleAllocatorCallback *allocator_cb;
} sink;
struct
{
@@ -400,6 +408,11 @@ static struct quality_manager *impl_from_IMFQualityManager(IMFQualityManager *if
return CONTAINING_RECORD(iface, struct quality_manager, IMFQualityManager_iface);
}
+static struct topo_node *impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
+{
+ return CONTAINING_RECORD(iface, struct topo_node, u.sink.notify_cb);
+}
+
/* IMFLocalMFTRegistration */
static HRESULT WINAPI local_mft_registration_QueryInterface(IMFLocalMFTRegistration *iface, REFIID riid, void **obj)
{
@@ -746,6 +759,11 @@ static void release_topo_node(struct topo_node *node)
case MF_TOPOLOGY_OUTPUT_NODE:
if (node->u.sink.allocator)
IMFVideoSampleAllocator_Release(node->u.sink.allocator);
+ if (node->u.sink.allocator_cb)
+ {
+ IMFVideoSampleAllocatorCallback_SetCallback(node->u.sink.allocator_cb, NULL);
+ IMFVideoSampleAllocatorCallback_Release(node->u.sink.allocator_cb);
+ }
break;
default:
;
@@ -804,6 +822,19 @@ static void session_clear_presentation(struct media_session *session)
}
}
+static struct topo_node *session_get_node_by_id(const struct media_session *session, TOPOID id)
+{
+ struct topo_node *node;
+
+ LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
+ {
+ if (node->node_id == id)
+ return node;
+ }
+
+ return NULL;
+}
+
static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position)
{
struct media_source *source;
@@ -1204,6 +1235,56 @@ static HRESULT session_get_stream_sink_type(IMFStreamSink *sink, IMFMediaType **
return hr;
}
+static HRESULT WINAPI node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
+ REFIID riid, void **obj)
+{
+ if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IMFVideoSampleAllocatorNotify_AddRef(iface);
+ return S_OK;
+ }
+
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
+{
+ return 1;
+}
+
+static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output);
+
+static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
+{
+ struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(iface);
+ struct session_op *op;
+
+ if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY, &op)))
+ {
+ op->u.sa_ready.node_id = topo_node->node_id;
+ MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &topo_node->session->commands_callback, &op->IUnknown_iface);
+ IUnknown_Release(&op->IUnknown_iface);
+ }
+
+ return S_OK;
+}
+
+static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl =
+{
+ node_sample_allocator_cb_QueryInterface,
+ node_sample_allocator_cb_AddRef,
+ node_sample_allocator_cb_Release,
+ node_sample_allocator_cb_NotifyRelease,
+};
+
static HRESULT session_append_node(struct media_session *session, IMFTopologyNode *node)
{
struct topo_node *topo_node;
@@ -1220,10 +1301,13 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod
IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
topo_node->node = node;
IMFTopologyNode_AddRef(topo_node->node);
+ topo_node->session = session;
switch (topo_node->type)
{
case MF_TOPOLOGY_OUTPUT_NODE:
+ topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
+
if (FAILED(hr = IMFTopologyNode_GetObject(node, &object)))
{
WARN("Node %s does not have associated object.\n", wine_dbgstr_longlong(topo_node->node_id));
@@ -1245,6 +1329,10 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod
&IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator)))
{
IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator, 2, media_type);
+ IMFVideoSampleAllocator_QueryInterface(topo_node->u.sink.allocator,
+ &IID_IMFVideoSampleAllocatorCallback, (void **)&topo_node->u.sink.allocator_cb);
+ IMFVideoSampleAllocatorCallback_SetCallback(topo_node->u.sink.allocator_cb,
+ &topo_node->u.sink.notify_cb);
}
IMFMediaType_Release(media_type);
}
@@ -1955,6 +2043,9 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
{
struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result));
struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface);
+ struct topo_node *topo_node;
+ IMFTopologyNode *upstream_node;
+ unsigned int upstream_output;
EnterCriticalSection(&session->cs);
@@ -1985,6 +2076,18 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface,
case SESSION_CMD_QM_NOTIFY_TOPOLOGY:
IMFQualityManager_NotifyTopology(session->quality_manager, op->u.notify_topology.topology);
break;
+ case SESSION_CMD_SA_READY:
+ topo_node = session_get_node_by_id(session, op->u.sa_ready.node_id);
+
+ if (topo_node->u.sink.requests)
+ {
+ if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output)))
+ {
+ session_request_sample_from_node(session, upstream_node, upstream_output);
+ IMFTopologyNode_Release(upstream_node);
+ }
+ }
+ break;
default:
;
}
@@ -2463,19 +2566,6 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre
}
}
-static struct topo_node *session_get_node_by_id(struct media_session *session, TOPOID id)
-{
- struct topo_node *node;
-
- LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry)
- {
- if (node->node_id == id)
- return node;
- }
-
- return NULL;
-}
-
static DWORD transform_node_get_stream_id(struct topo_node *node, BOOL output, DWORD index)
{
unsigned int *map = output ? node->u.transform.output_map : node->u.transform.input_map;
@@ -2496,6 +2586,47 @@ static struct sample *transform_create_sample(IMFSample *sample)
return sample_entry;
}
+static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform,
+ unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample)
+{
+ IMFTopologyNode *downstream_node;
+ unsigned int downstream_input;
+ IMFMediaBuffer *buffer = NULL;
+ struct topo_node *topo_node;
+ TOPOID node_id;
+ HRESULT hr;
+
+ if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input)))
+ {
+ WARN("Failed to get connected node for output %u.\n", output_index);
+ return MF_E_UNEXPECTED;
+ }
+
+ IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id);
+ IMFTopologyNode_Release(downstream_node);
+
+ topo_node = session_get_node_by_id(session, node_id);
+
+ if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator)
+ {
+ hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample);
+ }
+ else
+ {
+ hr = MFCreateAlignedMemoryBuffer(stream_info->cbSize, stream_info->cbAlignment, &buffer);
+ if (SUCCEEDED(hr))
+ hr = MFCreateSample(sample);
+
+ if (SUCCEEDED(hr))
+ hr = IMFSample_AddBuffer(*sample, buffer);
+
+ if (buffer)
+ IMFMediaBuffer_Release(buffer);
+ }
+
+ return hr;
+}
+
static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node)
{
MFT_OUTPUT_STREAM_INFO stream_info;
@@ -2503,7 +2634,7 @@ static HRESULT transform_node_pull_samples(const struct media_session *session,
struct sample *queued_sample;
DWORD status = 0;
unsigned int i;
- HRESULT hr;
+ HRESULT hr = E_UNEXPECTED;
if (!(buffers = heap_calloc(node->u.transform.output_count, sizeof(*buffers))))
return E_OUTOFMEMORY;
@@ -2521,19 +2652,7 @@ static HRESULT transform_node_pull_samples(const struct media_session *session,
if (!(stream_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
{
- IMFMediaBuffer *buffer = NULL;
-
- hr = MFCreateAlignedMemoryBuffer(stream_info.cbSize, stream_info.cbAlignment, &buffer);
- if (SUCCEEDED(hr))
- hr = MFCreateSample(&buffers[i].pSample);
-
- if (SUCCEEDED(hr))
- hr = IMFSample_AddBuffer(buffers[i].pSample, buffer);
-
- if (buffer)
- IMFMediaBuffer_Release(buffer);
-
- if (FAILED(hr))
+ if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample)))
break;
}
}
--
2.28.0
More information about the wine-devel
mailing list