From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 69 ++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 28 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index ba18261674d..301dba1de11 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3172,45 +3172,59 @@ static HRESULT transform_get_external_output_sample(const struct media_session * return hr; }
-static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node) +static HRESULT allocate_output_samples(const struct media_session *session, struct topo_node *node, + MFT_OUTPUT_DATA_BUFFER *buffers) { - MFT_OUTPUT_STREAM_INFO stream_info; - MFT_OUTPUT_DATA_BUFFER *buffers; - HRESULT hr = E_UNEXPECTED; - DWORD status = 0; - unsigned int i; - - if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers)))) - return E_OUTOFMEMORY; + HRESULT hr; + UINT i;
for (i = 0; i < node->u.transform.output_count; ++i) { + MFT_OUTPUT_STREAM_INFO stream_info = {0}; + buffers[i].dwStreamID = transform_node_get_stream_id(node, TRUE, i); - buffers[i].pSample = NULL; - buffers[i].dwStatus = 0; - buffers[i].pEvents = NULL;
- memset(&stream_info, 0, sizeof(stream_info)); if (FAILED(hr = IMFTransform_GetOutputStreamInfo(node->object.transform, buffers[i].dwStreamID, &stream_info))) - break; - - if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))) - { - if (FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample))) - break; - } + return hr; + if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) + && FAILED(hr = transform_get_external_output_sample(session, node, i, &stream_info, &buffers[i].pSample))) + return hr; }
- if (SUCCEEDED(hr)) - hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status); + return S_OK; +} + +static void release_output_samples(struct topo_node *node, MFT_OUTPUT_DATA_BUFFER *buffers) +{ + UINT i;
- /* Collect returned samples for all streams. */ for (i = 0; i < node->u.transform.output_count; ++i) { - struct transform_stream *stream = &node->u.transform.outputs[i]; - + if (buffers[i].pSample) + IMFSample_Release(buffers[i].pSample); if (buffers[i].pEvents) IMFCollection_Release(buffers[i].pEvents); + } +} + +static HRESULT transform_node_pull_samples(const struct media_session *session, struct topo_node *node) +{ + MFT_OUTPUT_DATA_BUFFER *buffers; + DWORD status; + HRESULT hr; + UINT i; + + if (!(buffers = calloc(node->u.transform.output_count, sizeof(*buffers)))) + return E_OUTOFMEMORY; + if (FAILED(hr = allocate_output_samples(session, node, buffers))) + goto done; + + status = 0; + hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status); + + for (i = 0; i < node->u.transform.output_count; ++i) + { + struct transform_stream *stream = &node->u.transform.outputs[i];
if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) { @@ -3219,11 +3233,10 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, if (FAILED(hr = transform_stream_push_sample(stream, buffers[i].pSample))) WARN("Failed to queue output sample, hr %#lx\n", hr); } - - if (buffers[i].pSample) - IMFSample_Release(buffers[i].pSample); }
+done: + release_output_samples(node, buffers); free(buffers);
return hr;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 52 +++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 33 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 301dba1de11..77aa5edd1f9 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -856,14 +856,18 @@ 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) +static struct topo_node *session_get_topo_node(const struct media_session *session, IMFTopologyNode *node) { - struct topo_node *node; + struct topo_node *topo_node; + TOPOID id;
- LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) + if (FAILED(IMFTopologyNode_GetTopoNodeID(node, &id))) + return NULL; + + LIST_FOR_EACH_ENTRY(topo_node, &session->presentation.nodes, struct topo_node, entry) { - if (node->node_id == id) - return node; + if (topo_node->node_id == id) + return topo_node; }
return NULL; @@ -3136,7 +3140,6 @@ static HRESULT transform_get_external_output_sample(const struct media_session * struct topo_node *topo_node; unsigned int buffer_size; DWORD downstream_input; - TOPOID node_id; HRESULT hr;
if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input))) @@ -3145,11 +3148,9 @@ static HRESULT transform_get_external_output_sample(const struct media_session * return MF_E_UNEXPECTED; }
- IMFTopologyNode_GetTopoNodeID(downstream_node, &node_id); + topo_node = session_get_topo_node(session, downstream_node); 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); @@ -3366,19 +3367,14 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop IMFSample *sample) { struct topo_node *topo_node; - MF_TOPOLOGY_TYPE node_type; - TOPOID node_id; HRESULT hr;
if (session->quality_manager) IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample);
- IMFTopologyNode_GetNodeType(node, &node_type); - IMFTopologyNode_GetTopoNodeID(node, &node_id); - - topo_node = session_get_node_by_id(session, node_id); + topo_node = session_get_topo_node(session, node);
- switch (node_type) + switch (topo_node->type) { case MF_TOPOLOGY_OUTPUT_NODE: if (topo_node->u.sink.requests) @@ -3403,7 +3399,7 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop transform_node_deliver_samples(session, topo_node); break; case MF_TOPOLOGY_TEE_NODE: - FIXME("Unhandled downstream node type %d.\n", node_type); + FIXME("Unhandled downstream node type %d.\n", topo_node->type); break; default: ; @@ -3413,22 +3409,17 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node) { struct topo_node *topo_node; - MF_TOPOLOGY_TYPE node_type; - TOPOID node_id;
- IMFTopologyNode_GetNodeType(node, &node_type); - IMFTopologyNode_GetTopoNodeID(node, &node_id); + topo_node = session_get_topo_node(session, node);
- topo_node = session_get_node_by_id(session, node_id); - - switch (node_type) + switch (topo_node->type) { case MF_TOPOLOGY_TRANSFORM_NODE: transform_node_pull_samples(session, topo_node); transform_node_deliver_samples(session, topo_node); break; default: - FIXME("Unexpected node type %u.\n", node_type); + FIXME("Unexpected node type %u.\n", topo_node->type); } }
@@ -3437,18 +3428,13 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I { IMFTopologyNode *down_node; struct topo_node *topo_node; - MF_TOPOLOGY_TYPE node_type; HRESULT hr = S_OK; IMFSample *sample; - TOPOID node_id; DWORD input;
- IMFTopologyNode_GetNodeType(node, &node_type); - IMFTopologyNode_GetTopoNodeID(node, &node_id); + topo_node = session_get_topo_node(session, node);
- topo_node = session_get_node_by_id(session, node_id); - - switch (node_type) + switch (topo_node->type) { case MF_TOPOLOGY_SOURCESTREAM_NODE: if (FAILED(hr = IMFMediaStream_RequestSample(topo_node->object.source_stream, NULL))) @@ -3484,7 +3470,7 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I break; } case MF_TOPOLOGY_TEE_NODE: - FIXME("Unhandled upstream node type %d.\n", node_type); + FIXME("Unhandled upstream node type %d.\n", topo_node->type); default: hr = E_UNEXPECTED; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 73 +++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 37 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 77aa5edd1f9..9d9cf34ffd1 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -873,6 +873,21 @@ static struct topo_node *session_get_topo_node(const struct media_session *sessi return NULL; }
+static struct topo_node *session_get_topo_node_output(const struct media_session *session, + const struct topo_node *up_node, DWORD output, DWORD *input) +{ + struct topo_node *down_node = NULL; + IMFTopologyNode *node; + + if (SUCCEEDED(IMFTopologyNode_GetOutput(up_node->node, output, &node, input))) + { + down_node = session_get_topo_node(session, node); + IMFTopologyNode_Release(node); + } + + return down_node; +} + static void session_command_complete(struct media_session *session) { struct session_op *op; @@ -3133,31 +3148,27 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre }
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) + DWORD output, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample) { - IMFTopologyNode *downstream_node; IMFMediaBuffer *buffer = NULL; struct topo_node *topo_node; unsigned int buffer_size; - DWORD downstream_input; + DWORD input; HRESULT hr;
- if (FAILED(IMFTopologyNode_GetOutput(transform->node, output_index, &downstream_node, &downstream_input))) + if (!(topo_node = session_get_topo_node_output(session, transform, output, &input))) { - WARN("Failed to get connected node for output %u.\n", output_index); + WARN("Failed to node %p/%lu output.\n", transform, output); return MF_E_UNEXPECTED; }
- topo_node = session_get_topo_node(session, downstream_node); - IMFTopologyNode_Release(downstream_node); - if (topo_node->type == MF_TOPOLOGY_OUTPUT_NODE && topo_node->u.sink.allocator) { hr = IMFVideoSampleAllocator_AllocateSample(topo_node->u.sink.allocator, sample); } else { - buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output_index].min_buffer_size); + buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output].min_buffer_size);
hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer); if (SUCCEEDED(hr)) @@ -3293,13 +3304,14 @@ static HRESULT transform_node_push_sample(const struct media_session *session, s return hr; }
-static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, +static void session_deliver_sample_to_node(struct media_session *session, struct topo_node *topo_node, unsigned int input, IMFSample *sample);
static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node) { - IMFTopologyNode *up_node = topo_node->node, *down_node; + IMFTopologyNode *up_node = topo_node->node; BOOL drained = transform_node_is_drained(topo_node); + struct topo_node *down_node; DWORD output, input; IMFSample *sample; HRESULT hr = S_OK; @@ -3309,9 +3321,9 @@ static void transform_node_deliver_samples(struct media_session *session, struct { struct transform_stream *stream = &topo_node->u.transform.outputs[output];
- if (FAILED(hr = IMFTopologyNode_GetOutput(up_node, output, &down_node, &input))) + if (!(down_node = session_get_topo_node_output(session, topo_node, output, &input))) { - WARN("Failed to node %p/%lu output, hr %#lx.\n", up_node, output, hr); + WARN("Failed to node %p/%lu output\n", topo_node, output); continue; }
@@ -3336,8 +3348,6 @@ static void transform_node_deliver_samples(struct media_session *session, struct session_deliver_sample_to_node(session, down_node, input, NULL); stream->requests--; } - - IMFTopologyNode_Release(down_node); }
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && transform_node_has_requests(topo_node)) @@ -3349,7 +3359,7 @@ static void transform_node_deliver_samples(struct media_session *session, struct
if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) { - session_deliver_sample_to_node(session, topo_node->node, input, sample); + session_deliver_sample_to_node(session, topo_node, input, sample); IMFSample_Release(sample); } else if (FAILED(hr = IMFTopologyNode_GetInput(topo_node->node, input, &up_node, &output))) @@ -3363,16 +3373,13 @@ static void transform_node_deliver_samples(struct media_session *session, struct } }
-static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, +static void session_deliver_sample_to_node(struct media_session *session, struct topo_node *topo_node, unsigned int input, IMFSample *sample) { - struct topo_node *topo_node; HRESULT hr;
if (session->quality_manager) - IMFQualityManager_NotifyProcessInput(session->quality_manager, node, input, sample); - - topo_node = session_get_topo_node(session, node); + IMFQualityManager_NotifyProcessInput(session->quality_manager, topo_node->node, input, sample);
switch (topo_node->type) { @@ -3408,9 +3415,7 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop
static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node) { - struct topo_node *topo_node; - - topo_node = session_get_topo_node(session, node); + struct topo_node *topo_node = session_get_topo_node(session, node);
switch (topo_node->type) { @@ -3426,8 +3431,7 @@ static void session_deliver_pending_samples(struct media_session *session, IMFTo
static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output) { - IMFTopologyNode *down_node; - struct topo_node *topo_node; + struct topo_node *topo_node, *down_node; HRESULT hr = S_OK; IMFSample *sample; DWORD input; @@ -3444,9 +3448,9 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I { struct transform_stream *stream = &topo_node->u.transform.outputs[output];
- if (FAILED(hr = IMFTopologyNode_GetOutput(node, output, &down_node, &input))) + if (!(down_node = session_get_topo_node_output(session, topo_node, output, &input))) { - WARN("Failed to node %p/%lu output, hr %#lx.\n", node, output, hr); + WARN("Failed to node %p/%lu output\n", topo_node, output); break; }
@@ -3465,8 +3469,6 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I stream->requests++; transform_node_deliver_samples(session, topo_node); } - - IMFTopologyNode_Release(down_node); break; } case MF_TOPOLOGY_TEE_NODE: @@ -3512,9 +3514,7 @@ static void session_request_sample(struct media_session *session, IMFStreamSink static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value) { struct topo_node *source_node = NULL, *node; - IMFTopologyNode *downstream_node; - DWORD downstream_input; - HRESULT hr; + DWORD input;
if (value && (value->vt != VT_UNKNOWN || !value->punkVal)) { @@ -3537,14 +3537,13 @@ static void session_deliver_sample(struct media_session *session, IMFMediaStream if (!value) source_node->flags |= TOPO_NODE_END_OF_STREAM;
- if (FAILED(hr = IMFTopologyNode_GetOutput(source_node->node, 0, &downstream_node, &downstream_input))) + if (!(node = session_get_topo_node_output(session, source_node, 0, &input))) { - WARN("Failed to get downstream node connection, hr %#lx.\n", hr); + WARN("Failed to node %p/%u output.\n", source_node, 0); return; }
- session_deliver_sample_to_node(session, downstream_node, downstream_input, value ? (IMFSample *)value->punkVal : NULL); - IMFTopologyNode_Release(downstream_node); + session_deliver_sample_to_node(session, node, input, value ? (IMFSample *)value->punkVal : NULL); }
static void session_sink_invalidated(struct media_session *session, IMFMediaEvent *event, IMFStreamSink *sink)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 71 ++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 35 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 9d9cf34ffd1..f31bd92380b 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -873,6 +873,21 @@ static struct topo_node *session_get_topo_node(const struct media_session *sessi return NULL; }
+static struct topo_node *session_get_topo_node_input(const struct media_session *session, + const struct topo_node *down_node, DWORD input, DWORD *output) +{ + struct topo_node *up_node = NULL; + IMFTopologyNode *node; + + if (SUCCEEDED(IMFTopologyNode_GetInput(down_node->node, input, &node, output))) + { + up_node = session_get_topo_node(session, node); + IMFTopologyNode_Release(node); + } + + return up_node; +} + static struct topo_node *session_get_topo_node_output(const struct media_session *session, const struct topo_node *up_node, DWORD output, DWORD *input) { @@ -1683,7 +1698,7 @@ static ULONG WINAPI node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNoti return 1; }
-static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output); +static HRESULT session_request_sample_from_node(struct media_session *session, struct topo_node *topo_node, DWORD output);
static HRESULT WINAPI node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface) { @@ -2623,7 +2638,7 @@ static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback * return E_NOTIMPL; }
-static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node); +static void session_deliver_pending_samples(struct media_session *session, struct topo_node *topo_node);
static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { @@ -2727,20 +2742,18 @@ static HRESULT WINAPI session_sa_ready_callback_GetParameters(IMFAsyncCallback * static HRESULT WINAPI session_sa_ready_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { IMFVideoSampleAllocatorNotify *notify = (IMFVideoSampleAllocatorNotify *)IMFAsyncResult_GetStateNoAddRef(result); - struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(notify); + struct topo_node *topo_node = impl_node_from_IMFVideoSampleAllocatorNotify(notify), *up_node; struct media_session *session = impl_from_sa_ready_callback_IMFAsyncCallback(iface); - IMFTopologyNode *upstream_node; - DWORD upstream_output; + DWORD output;
EnterCriticalSection(&session->cs);
if (topo_node->u.sink.requests) { - if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node->node, 0, &upstream_node, &upstream_output))) - { - session_deliver_pending_samples(session, upstream_node); - IMFTopologyNode_Release(upstream_node); - } + if (!(up_node = session_get_topo_node_input(session, topo_node, 0, &output))) + WARN("Failed to node %p/%u input\n", topo_node, 0); + else + session_deliver_pending_samples(session, up_node); }
LeaveCriticalSection(&session->cs); @@ -3309,9 +3322,8 @@ static void session_deliver_sample_to_node(struct media_session *session, struct
static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node) { - IMFTopologyNode *up_node = topo_node->node; BOOL drained = transform_node_is_drained(topo_node); - struct topo_node *down_node; + struct topo_node *up_node, *down_node; DWORD output, input; IMFSample *sample; HRESULT hr = S_OK; @@ -3362,14 +3374,10 @@ static void transform_node_deliver_samples(struct media_session *session, struct session_deliver_sample_to_node(session, topo_node, input, sample); IMFSample_Release(sample); } - else if (FAILED(hr = IMFTopologyNode_GetInput(topo_node->node, input, &up_node, &output))) - WARN("Failed to get node %p/%lu input, hr %#lx\n", topo_node->node, input, hr); - else - { - if (FAILED(hr = session_request_sample_from_node(session, up_node, output))) - WARN("Failed to request sample from upstream node %p/%lu, hr %#lx\n", up_node, output, hr); - IMFTopologyNode_Release(up_node); - } + else if (!(up_node = session_get_topo_node_input(session, topo_node, input, &output))) + WARN("Failed to node %p/%lu input\n", topo_node, input); + else if (FAILED(hr = session_request_sample_from_node(session, up_node, output))) + WARN("Failed to request sample from upstream node %p/%lu, hr %#lx\n", up_node, output, hr); } }
@@ -3413,10 +3421,8 @@ static void session_deliver_sample_to_node(struct media_session *session, struct } }
-static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node) +static void session_deliver_pending_samples(struct media_session *session, struct topo_node *topo_node) { - struct topo_node *topo_node = session_get_topo_node(session, node); - switch (topo_node->type) { case MF_TOPOLOGY_TRANSFORM_NODE: @@ -3429,15 +3435,13 @@ static void session_deliver_pending_samples(struct media_session *session, IMFTo }
-static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output) +static HRESULT session_request_sample_from_node(struct media_session *session, struct topo_node *topo_node, DWORD output) { - struct topo_node *topo_node, *down_node; + struct topo_node *down_node; HRESULT hr = S_OK; IMFSample *sample; DWORD input;
- topo_node = session_get_topo_node(session, node); - switch (topo_node->type) { case MF_TOPOLOGY_SOURCESTREAM_NODE: @@ -3482,10 +3486,8 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I
static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream) { - struct topo_node *sink_node = NULL, *node; - IMFTopologyNode *upstream_node; - DWORD upstream_output; - HRESULT hr; + struct topo_node *sink_node = NULL, *node, *up_node; + DWORD output;
LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) { @@ -3499,16 +3501,15 @@ static void session_request_sample(struct media_session *session, IMFStreamSink if (!sink_node) return;
- if (FAILED(hr = IMFTopologyNode_GetInput(sink_node->node, 0, &upstream_node, &upstream_output))) + if (!(up_node = session_get_topo_node_input(session, sink_node, 0, &output))) { - WARN("Failed to get upstream node connection, hr %#lx.\n", hr); + WARN("Failed to node %p/%u input\n", sink_node, 0); return; }
sink_node->u.sink.requests++; - if (FAILED(session_request_sample_from_node(session, upstream_node, upstream_output))) + if (FAILED(session_request_sample_from_node(session, up_node, output))) sink_node->u.sink.requests--; - IMFTopologyNode_Release(upstream_node); }
static void session_deliver_sample(struct media_session *session, IMFMediaStream *stream, const PROPVARIANT *value)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 128 +++++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 53 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index f31bd92380b..474c4a58a94 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -145,15 +145,9 @@ struct media_sink BOOL finalized; };
-struct sample -{ - struct list entry; - IMFSample *sample; -}; - struct transform_stream { - struct list samples; + IMFCollection *events; unsigned int requests; unsigned int min_buffer_size; BOOL draining; @@ -675,41 +669,30 @@ static void session_set_caps(struct media_session *session, DWORD caps) IMFMediaEvent_Release(event); }
-static HRESULT transform_stream_push_sample(struct transform_stream *stream, IMFSample *sample) +static void transform_stream_push_sample(struct transform_stream *stream, IMFSample *sample) { - struct sample *entry; - - if (!(entry = calloc(1, sizeof(*entry)))) - return E_OUTOFMEMORY; - - entry->sample = sample; - IMFSample_AddRef(entry->sample); + PROPVARIANT value = {.vt = VT_UNKNOWN, .punkVal = (IUnknown *)sample}; + IMFMediaEvent *event;
- list_add_tail(&stream->samples, &entry->entry); - return S_OK; + if (SUCCEEDED(MFCreateMediaEvent(MEMediaSample, &GUID_NULL, S_OK, &value, &event))) + { + IMFCollection_AddElement(stream->events, (IUnknown *)event); + IMFMediaEvent_Release(event); + } }
-static HRESULT transform_stream_pop_sample(struct transform_stream *stream, IMFSample **sample) +static HRESULT transform_stream_pop_event(struct transform_stream *stream, IMFMediaEvent **event) { - struct sample *entry; - struct list *ptr; - - if (!(ptr = list_head(&stream->samples))) - return MF_E_TRANSFORM_NEED_MORE_INPUT; - - entry = LIST_ENTRY(ptr, struct sample, entry); - list_remove(&entry->entry); - *sample = entry->sample; - free(entry); - return S_OK; + HRESULT hr = IMFCollection_RemoveElement(stream->events, 0, (IUnknown **)event); + return hr == E_INVALIDARG ? MF_E_TRANSFORM_NEED_MORE_INPUT : hr; }
-static void transform_stream_drop_samples(struct transform_stream *stream) +static void transform_stream_drop_events(struct transform_stream *stream) { - IMFSample *sample; + IMFMediaEvent *event;
- while (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) - IMFSample_Release(sample); + while (SUCCEEDED(transform_stream_pop_event(stream, &event))) + IMFMediaEvent_Release(event); }
static void release_topo_node(struct topo_node *node) @@ -724,9 +707,15 @@ static void release_topo_node(struct topo_node *node) break; case MF_TOPOLOGY_TRANSFORM_NODE: for (i = 0; i < node->u.transform.input_count; ++i) - transform_stream_drop_samples(&node->u.transform.inputs[i]); + { + transform_stream_drop_events(&node->u.transform.inputs[i]); + IMFCollection_Release(node->u.transform.inputs[i].events); + } for (i = 0; i < node->u.transform.output_count; ++i) - transform_stream_drop_samples(&node->u.transform.outputs[i]); + { + transform_stream_drop_events(&node->u.transform.outputs[i]); + IMFCollection_Release(node->u.transform.outputs[i].events); + } free(node->u.transform.inputs); free(node->u.transform.outputs); free(node->u.transform.input_map); @@ -1630,14 +1619,14 @@ static HRESULT session_set_transform_stream_info(struct topo_node *node)
streams = calloc(input_count, sizeof(*streams)); for (i = 0; i < input_count; ++i) - list_init(&streams[i].samples); + MFCreateCollection(&streams[i].events); node->u.transform.inputs = streams; node->u.transform.input_count = input_count;
streams = calloc(output_count, sizeof(*streams)); for (i = 0; i < output_count; ++i) { - list_init(&streams[i].samples); + MFCreateCollection(&streams[i].events);
if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node->object.transform, transform_node_get_stream_id(node, TRUE, i), &media_type))) @@ -3255,8 +3244,7 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, { if (session->quality_manager) IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample); - if (FAILED(hr = transform_stream_push_sample(stream, buffers[i].pSample))) - WARN("Failed to queue output sample, hr %#lx\n", hr); + transform_stream_push_sample(stream, buffers[i].pSample); } }
@@ -3304,7 +3292,7 @@ static HRESULT transform_node_push_sample(const struct media_session *session, s { hr = IMFTransform_ProcessInput(transform, id, sample, 0); if (hr == MF_E_NOTACCEPTING) - hr = transform_stream_push_sample(stream, sample); + transform_stream_push_sample(stream, sample); } else { @@ -3320,12 +3308,40 @@ static HRESULT transform_node_push_sample(const struct media_session *session, s static void session_deliver_sample_to_node(struct media_session *session, struct topo_node *topo_node, unsigned int input, IMFSample *sample);
+static HRESULT transform_stream_handle_event(struct media_session *session, struct transform_stream *stream, + struct topo_node *topo_node, unsigned int input, IMFMediaEvent *event) +{ + MediaEventType type; + PROPVARIANT value; + HRESULT hr; + + if (FAILED(hr = IMFMediaEvent_GetType(event, &type))) + return hr; + PropVariantInit(&value); + + switch (type) + { + case MEMediaSample: + if (SUCCEEDED(hr = IMFMediaEvent_GetValue(event, &value))) + session_deliver_sample_to_node(session, topo_node, input, (IMFSample *)value.punkVal); + break; + + default: + ERR("Unexpected event type %lu\n", type); + hr = E_NOTIMPL; + break; + } + + PropVariantClear(&value); + return hr; +} + static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node) { BOOL drained = transform_node_is_drained(topo_node); struct topo_node *up_node, *down_node; + IMFMediaEvent *event; DWORD output, input; - IMFSample *sample; HRESULT hr = S_OK;
/* Push down all available output. */ @@ -3341,18 +3357,22 @@ static void transform_node_deliver_samples(struct media_session *session, struct
while (stream->requests) { - if (FAILED(hr = transform_stream_pop_sample(stream, &sample))) + MediaEventType type; + + if (FAILED(hr = transform_stream_pop_event(stream, &event))) { /* try getting more samples by calling IMFTransform_ProcessOutput */ if (FAILED(hr = transform_node_pull_samples(session, topo_node))) break; - if (FAILED(hr = transform_stream_pop_sample(stream, &sample))) + if (FAILED(hr = transform_stream_pop_event(stream, &event))) break; }
- session_deliver_sample_to_node(session, down_node, input, sample); - stream->requests--; - IMFSample_Release(sample); + if (FAILED(hr = transform_stream_handle_event(session, stream, down_node, input, event))) + ERR("Failed to handle stream event, hr %#lx\n", hr); + else if (SUCCEEDED(IMFMediaEvent_GetType(event, &type)) && type == MEMediaSample) + stream->requests--; + IMFMediaEvent_Release(event); }
while (stream->requests && drained) @@ -3369,10 +3389,11 @@ static void transform_node_deliver_samples(struct media_session *session, struct input = topo_node->u.transform.next_input++ % topo_node->u.transform.input_count; stream = &topo_node->u.transform.inputs[input];
- if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) + if (SUCCEEDED(transform_stream_pop_event(stream, &event))) { - session_deliver_sample_to_node(session, topo_node, input, sample); - IMFSample_Release(sample); + if (FAILED(hr = transform_stream_handle_event(session, stream, topo_node, input, event))) + ERR("Failed to handle stream event, hr %#lx\n", hr); + IMFMediaEvent_Release(event); } else if (!(up_node = session_get_topo_node_input(session, topo_node, input, &output))) WARN("Failed to node %p/%lu input\n", topo_node, input); @@ -3439,7 +3460,6 @@ static HRESULT session_request_sample_from_node(struct media_session *session, s { struct topo_node *down_node; HRESULT hr = S_OK; - IMFSample *sample; DWORD input;
switch (topo_node->type) @@ -3451,6 +3471,7 @@ static HRESULT session_request_sample_from_node(struct media_session *session, s case MF_TOPOLOGY_TRANSFORM_NODE: { struct transform_stream *stream = &topo_node->u.transform.outputs[output]; + IMFMediaEvent *event;
if (!(down_node = session_get_topo_node_output(session, topo_node, output, &input))) { @@ -3458,10 +3479,11 @@ static HRESULT session_request_sample_from_node(struct media_session *session, s break; }
- if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) + if (SUCCEEDED(transform_stream_pop_event(stream, &event))) { - session_deliver_sample_to_node(session, down_node, input, sample); - IMFSample_Release(sample); + if (FAILED(hr = transform_stream_handle_event(session, stream, down_node, input, event))) + ERR("Failed to handle stream event, hr %#lx\n", hr); + IMFMediaEvent_Release(event); } else if (transform_node_has_requests(topo_node)) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/session.c | 222 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 221 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 474c4a58a94..14aa13b0315 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -681,6 +681,29 @@ static void transform_stream_push_sample(struct transform_stream *stream, IMFSam } }
+static void transform_stream_push_format_change(struct transform_stream *stream, IMFMediaType *media_type) +{ + PROPVARIANT value = {.vt = VT_UNKNOWN, .punkVal = (IUnknown *)media_type}; + IMFMediaEvent *event; + + if (SUCCEEDED(MFCreateMediaEvent(MEStreamFormatChanged, &GUID_NULL, S_OK, &value, &event))) + { + IMFCollection_AddElement(stream->events, (IUnknown *)event); + IMFMediaEvent_Release(event); + } +} + +static void transform_stream_push_events(struct transform_stream *stream, IMFCollection *events) +{ + IMFMediaEvent *event; + + while (SUCCEEDED(IMFCollection_RemoveElement(events, 0, (IUnknown **)&event))) + { + IMFCollection_AddElement(stream->events, (IUnknown *)event); + IMFMediaEvent_Release(event); + } +} + static HRESULT transform_stream_pop_event(struct transform_stream *stream, IMFMediaEvent **event) { HRESULT hr = IMFCollection_RemoveElement(stream->events, 0, (IUnknown **)event); @@ -3186,6 +3209,121 @@ static HRESULT transform_get_external_output_sample(const struct media_session * return hr; }
+/* update the transform output type while keeping subtype which matches the old output type */ +static HRESULT transform_stream_update_output_type(struct topo_node *node, struct transform_stream *stream, + UINT id, IMFMediaType *old_output_type, IMFMediaType **new_output_type) +{ + GUID subtype, desired; + UINT i = 0; + HRESULT hr; + + TRACE("node %p, stream %p, id %u, old_output_type %p, new_output_type %p\n", + node, stream, id, old_output_type, new_output_type); + + IMFMediaType_GetGUID(old_output_type, &MF_MT_SUBTYPE, &desired); + + /* find an available output type matching the desired subtype */ + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(node->object.transform, id, + i++, new_output_type))) + { + IMFMediaType_GetGUID(*new_output_type, &MF_MT_SUBTYPE, &subtype); + if (IsEqualGUID(&subtype, &desired)) + { + if (FAILED(hr = IMFTransform_SetOutputType(node->object.transform, id, *new_output_type, 0))) + { + IMFMediaType_Release(*new_output_type); + break; + } + return S_OK; + } + IMFMediaType_Release(*new_output_type); + } + + *new_output_type = NULL; + return hr; +} + +static HRESULT transform_node_format_changed(struct topo_node *node, MFT_OUTPUT_DATA_BUFFER *buffers) +{ + HRESULT hr = S_OK; + unsigned int i; + + TRACE("node %p, buffers %p\n", node, buffers); + + for (i = 0; SUCCEEDED(hr) && i < node->u.transform.output_count; ++i) + { + struct transform_stream *stream = &node->u.transform.outputs[i]; + IMFMediaType *old_output_type, *new_output_type; + UINT id = buffers[i].dwStreamID; + + if (!(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE)) + continue; + + if (SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(node->object.transform, id, &old_output_type))) + { + if (SUCCEEDED(hr = transform_stream_update_output_type(node, stream, id, old_output_type, + &new_output_type))) + { + if (buffers[i].pEvents || SUCCEEDED(hr = MFCreateCollection(&buffers[i].pEvents))) + transform_stream_push_format_change(stream, new_output_type); + IMFMediaType_Release(new_output_type); + } + IMFMediaType_Release(old_output_type); + } + } + + return hr; +} + +static HRESULT transform_stream_update_input_type(struct topo_node *node, UINT input, IMFMediaType *media_type) +{ + IMFMediaType **old_output_types; + IMFMediaType *new_output_type; + IMFMediaTypeHandler *handler; + UINT output; + HRESULT hr; + + TRACE("node %p, input %u, media_type %p\n", node, input, media_type); + + if (!(old_output_types = calloc(node->u.transform.output_count, sizeof(*old_output_types)))) + return E_OUTOFMEMORY; + + for (output = 0; output < node->u.transform.output_count; ++output) + { + UINT id = transform_node_get_stream_id(node, TRUE, output); + if (FAILED(hr = IMFTransform_GetOutputCurrentType(node->object.transform, id, + &old_output_types[output]))) + goto done; + } + + if (SUCCEEDED(hr = topology_node_get_type_handler(node->node, input, FALSE, &handler))) + { + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type))) + WARN("Failed to change note %p input %u media type\n", node->node, input); + IMFMediaTypeHandler_Release(handler); + } + + for (output = 0; SUCCEEDED(hr) && output < node->u.transform.output_count; ++output) + { + struct transform_stream *stream = &node->u.transform.outputs[output]; + UINT id = transform_node_get_stream_id(node, TRUE, output); + + if (SUCCEEDED(hr = transform_stream_update_output_type(node, stream, id, + old_output_types[output], &new_output_type))) + { + transform_stream_push_format_change(stream, new_output_type); + IMFMediaType_Release(new_output_type); + } + } + +done: + for (output = 0; output < node->u.transform.output_count; ++output) + if (old_output_types[output]) + IMFMediaType_Release(old_output_types[output]); + free(old_output_types); + return hr; +} + static HRESULT allocate_output_samples(const struct media_session *session, struct topo_node *node, MFT_OUTPUT_DATA_BUFFER *buffers) { @@ -3235,12 +3373,28 @@ static HRESULT transform_node_pull_samples(const struct media_session *session,
status = 0; hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status); + if (hr == MF_E_TRANSFORM_STREAM_CHANGE && SUCCEEDED(hr = transform_node_format_changed(node, buffers))) + { + release_output_samples(node, buffers); + + memset(buffers, 0, node->u.transform.output_count * sizeof(*buffers)); + if (FAILED(hr = allocate_output_samples(session, node, buffers))) + goto done;
+ hr = IMFTransform_ProcessOutput(node->object.transform, 0, node->u.transform.output_count, buffers, &status); + } + + /* Collect returned samples for all streams. */ for (i = 0; i < node->u.transform.output_count; ++i) { struct transform_stream *stream = &node->u.transform.outputs[i];
- if (SUCCEEDED(hr) && !(buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) + if (buffers[i].pEvents) + transform_stream_push_events(stream, buffers[i].pEvents); + if (buffers[i].dwStatus & MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE) + continue; + + if (SUCCEEDED(hr)) { if (session->quality_manager) IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample); @@ -3307,6 +3461,67 @@ static HRESULT transform_node_push_sample(const struct media_session *session, s
static void session_deliver_sample_to_node(struct media_session *session, struct topo_node *topo_node, unsigned int input, IMFSample *sample); +static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node); + +static HRESULT transform_node_handle_format_change(struct media_session *session, struct topo_node *topo_node, + UINT input, IMFMediaType *media_type) +{ + struct transform_stream *stream = &topo_node->u.transform.inputs[input]; + UINT id = transform_node_get_stream_id(topo_node, FALSE, input); + IMFTransform *transform = topo_node->object.transform; + UINT32 support_dynamic_format_change = 0; + IMFAttributes *attributes; + HRESULT hr; + + TRACE("session %p, topo_node %p, input %u, media_type %p\n", session, topo_node, input, media_type); + + if (SUCCEEDED(IMFTransform_GetAttributes(transform, &attributes))) + { + if (FAILED(IMFAttributes_GetUINT32(attributes, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, &support_dynamic_format_change))) + support_dynamic_format_change = 0; + IMFAttributes_Release(attributes); + } + + if (!support_dynamic_format_change) + { + if (SUCCEEDED(hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, id))) + { + while (SUCCEEDED(hr = transform_node_pull_samples(session, topo_node))) + transform_node_deliver_samples(session, topo_node); + } + + if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT) + { + transform_stream_push_format_change(stream, media_type); + return hr; + } + } + + return transform_stream_update_input_type(topo_node, input, media_type); +} + +static HRESULT session_handle_format_change(struct media_session *session, struct topo_node *topo_node, + UINT input, IMFMediaType *media_type) +{ + HRESULT hr; + + switch (topo_node->type) + { + case MF_TOPOLOGY_OUTPUT_NODE: + if (!topo_node->u.sink.allocator) + return S_OK; + if (SUCCEEDED(hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(topo_node->u.sink.allocator))) + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator, 4, media_type); + return hr; + + case MF_TOPOLOGY_TRANSFORM_NODE: + return transform_node_handle_format_change(session, topo_node, input, media_type); + + default: + FIXME("Unhandled downstream node type %d.\n", topo_node->type); + return E_NOTIMPL; + } +}
static HRESULT transform_stream_handle_event(struct media_session *session, struct transform_stream *stream, struct topo_node *topo_node, unsigned int input, IMFMediaEvent *event) @@ -3326,6 +3541,11 @@ static HRESULT transform_stream_handle_event(struct media_session *session, stru session_deliver_sample_to_node(session, topo_node, input, (IMFSample *)value.punkVal); break;
+ case MEStreamFormatChanged: + if (SUCCEEDED(hr = IMFMediaEvent_GetValue(event, &value))) + hr = session_handle_format_change(session, topo_node, input, (IMFMediaType *)value.punkVal); + break; + default: ERR("Unexpected event type %lu\n", type); hr = E_NOTIMPL;
Anything here? This is pretty much the same thing that was implemented in mfreadwrite.
IMFCollection was used because it's already used in transform API, or to replace list with something typed?
Initially because I wanted to use MFT_OUTPUT_DATA_BUFFER pEvents to carry the format changes and avoid having to allocate dedicated event list for every stream but it ended up differently as events are now pushed directly to the stream queues.
Then it still looked convenient to reduce the amount of code, using the IMFMediaEvent as a wrapper structure around events / samples instead of a custom one, as well as reducing the manual allocations / reference counts.
Is there any drawback using IMFCollection?
Regarding IMFCollection, it looks like a lot of unrelated code changes, that does not help with format change improvements. Did it actually reduce line count? I see that error handling for AddElement()/CreateCollection is skipped also.
About error handling, I believe you said elsewhere that error handling wasn't very useful when the only possible errors were memory allocation failures. There's several instances of unchecked `IMFMediaType_Set*`, as well as `session_set_caps` right above which doesn't check anything either. I'm fine adding some, and I generally prefer to not leave any error unchecked, but I thought you preferred not to have these checks.
Regarding IMFCollection vs a custom list, I think it's mostly the same thing, except that IMFCollection and the skipped error checks actually reduce the number of LoC (which I don't think is a very good metric in general anyway). The change also introduces a new `transform_stream_handle_event` helper, and the required dispatch between samples and format change events is what's adding more LoC, and that's not really something we can get rid of. The same MR, but keeping a struct list instead of IMFCollection and checking errors (while still wrapping samples / format changes in IMFMediaEvent) add 20 more lines in total.