Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: * Reorder and split patches differently, isolate the simple changes from the new features.
* Keep zero-copy consideration aside for the moment. It should be still possible to add it later, when everything else is in place.
dlls/winegstreamer/wg_transform.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index d316071cf60..7160fd087b6 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -46,6 +46,7 @@ struct wg_transform { GstElement *container; GstPad *my_src, *my_sink; + GstPad *their_sink, *their_src; };
static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) @@ -64,6 +65,10 @@ NTSTATUS wg_transform_destroy(void *args) struct wg_transform *transform = args;
gst_element_set_state(transform->container, GST_STATE_NULL); + gst_pad_unlink(transform->their_src, transform->my_sink); + gst_pad_unlink(transform->my_src, transform->their_sink); + g_object_unref(transform->their_sink); + g_object_unref(transform->their_src); g_object_unref(transform->container); g_object_unref(transform->my_sink); g_object_unref(transform->my_src); @@ -237,9 +242,22 @@ NTSTATUS wg_transform_create(void *args) goto out_free_sink_pad; }
+ if (!(transform->their_sink = gst_element_get_static_pad(first, "sink"))) + goto out_free_sink_pad; + if (!(transform->their_src = gst_element_get_static_pad(last, "src"))) + goto out_free_their_sink; + if (gst_pad_link(transform->my_src, transform->their_sink) < 0) + goto out_free_their_src; + if (gst_pad_link(transform->their_src, transform->my_sink) < 0) + goto out_unlink_src_pad; + if (!gst_pad_set_active(transform->my_sink, 1)) + goto out_unlink_sink_pad; + if (!gst_pad_set_active(transform->my_src, 1)) + goto out_unlink_sink_pad; + gst_element_set_state(transform->container, GST_STATE_PAUSED); if (!gst_element_get_state(transform->container, NULL, NULL, -1)) - goto out_free_sink_pad; + goto out_unlink_sink_pad;
gst_caps_unref(sink_caps); gst_caps_unref(src_caps); @@ -248,6 +266,14 @@ NTSTATUS wg_transform_create(void *args) params->transform = transform; return STATUS_SUCCESS;
+out_unlink_sink_pad: + gst_pad_unlink(transform->their_src, transform->my_sink); +out_unlink_src_pad: + gst_pad_unlink(transform->my_src, transform->their_sink); +out_free_their_src: + g_object_unref(transform->their_src); +out_free_their_sink: + g_object_unref(transform->their_sink); out_free_sink_pad: gst_object_unref(transform->my_sink); out_free_sink_caps:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/wg_transform.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 7160fd087b6..a4a4d886865 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -47,6 +47,7 @@ struct wg_transform GstElement *container; GstPad *my_src, *my_sink; GstPad *their_sink, *their_src; + GstSegment segment; };
static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) @@ -156,6 +157,7 @@ NTSTATUS wg_transform_create(void *args) GstPadTemplate *template = NULL; struct wg_transform *transform; const gchar *media_type; + GstEvent *event;
if (!init_gstreamer()) return STATUS_UNSUCCESSFUL; @@ -259,6 +261,23 @@ NTSTATUS wg_transform_create(void *args) if (!gst_element_get_state(transform->container, NULL, NULL, -1)) goto out_unlink_sink_pad;
+ if (!(event = gst_event_new_stream_start("stream")) + || !gst_pad_push_event(transform->my_src, event)) + goto out_unlink_sink_pad; + if (!(event = gst_event_new_caps(src_caps)) + || !gst_pad_push_event(transform->my_src, event)) + goto out_unlink_sink_pad; + + /* We need to use GST_FORMAT_TIME here because it's the only format + * some elements such avdec_wmav2 correctly support. + */ + gst_segment_init(&transform->segment, GST_FORMAT_TIME); + transform->segment.start = 0; + transform->segment.stop = -1; + if (!(event = gst_event_new_segment(&transform->segment)) + || !gst_pad_push_event(transform->my_src, event)) + goto out_unlink_sink_pad; + gst_caps_unref(sink_caps); gst_caps_unref(src_caps);
@@ -283,6 +302,7 @@ out_free_src_pad: out_free_src_caps: gst_caps_unref(src_caps); out_free_container: + gst_element_set_state(transform->container, GST_STATE_NULL); gst_object_unref(transform->container); out_free_transform: free(transform);
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 21 +++++++++++++-------- dlls/winegstreamer/wma_decoder.c | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 60d95529f97..1f31eab60bc 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -5823,6 +5823,7 @@ static void test_wma_decoder(void) MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Audio, MFAudioFormat_WMAudioV8}; MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Audio, MFAudioFormat_Float}; MFT_OUTPUT_STREAM_INFO output_info; + MFT_OUTPUT_DATA_BUFFER outputs[2]; MFT_INPUT_STREAM_INFO input_info; MFT_OUTPUT_DATA_BUFFER output; const BYTE *wma_encoded_data; @@ -6023,16 +6024,13 @@ static void test_wma_decoder(void) status = 0xdeadbeef; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); ok(output.dwStreamID == 0, "got dwStreamID %u\n", output.dwStreamID); ok(!output.pSample, "got pSample %p\n", output.pSample); - todo_wine ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE || broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) /* Win7 */, "got dwStatus %#x\n", output.dwStatus); ok(!output.pEvents, "got pEvents %p\n", output.pEvents); - todo_wine ok(status == 0, "got status %#x\n", status);
sample = create_sample(wma_encoded_data, wma_block_size); @@ -6045,16 +6043,25 @@ static void test_wma_decoder(void) status = 0xdeadbeef; memset(&output, 0, sizeof(output)); hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); ok(!output.pSample, "got pSample %p\n", output.pSample); - todo_wine ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE || broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) /* Win7 */, "got dwStatus %#x\n", output.dwStatus); - todo_wine ok(status == 0, "got status %#x\n", status);
+ status = 0xdeadbeef; + memset(&output, 0, sizeof(output)); + output_info.cbSize = sizeof(wma_decoded_data); + sample = create_sample(NULL, output_info.cbSize); + outputs[0].pSample = sample; + sample = create_sample(NULL, output_info.cbSize); + outputs[1].pSample = sample; + hr = IMFTransform_ProcessOutput(transform, 0, 2, outputs, &status); + ok(hr == E_INVALIDARG, "ProcessOutput returned %#x\n", hr); + IMFSample_Release(outputs[0].pSample); + IMFSample_Release(outputs[1].pSample); + i = 1; status = 0xdeadbeef; output_info.cbSize = sizeof(wma_decoded_data); @@ -6125,7 +6132,6 @@ static void test_wma_decoder(void) ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); ok(output.pSample == sample, "got pSample %p\n", output.pSample); ok(output.dwStatus == 0, "got dwStatus %#x\n", output.dwStatus); - todo_wine ok(status == 0, "got status %#x\n", status); ret = IMFSample_Release(sample); ok(ret == 0, "Release returned %u\n", ret); @@ -6141,7 +6147,6 @@ static void test_wma_decoder(void) ok(output.dwStatus == 0 || broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7)) /* Win7 */, "got dwStatus %#x\n", output.dwStatus); - todo_wine ok(status == 0, "got status %#x\n", status); check_sample(sample, NULL, 0, NULL); ret = IMFSample_Release(sample); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 6c198706944..fef10b9c920 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -527,7 +527,29 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { + struct wma_decoder *decoder = impl_from_IMFTransform(iface); + MFT_OUTPUT_STREAM_INFO info; + HRESULT hr; + FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); + + if (count > 1) + return E_INVALIDARG; + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) + return hr; + + *status = 0; + samples[0].dwStatus = 0; + if (!samples[0].pSample) + { + samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; + return MF_E_TRANSFORM_NEED_MORE_INPUT; + } + return E_NOTIMPL; }
This one has nothing winegstreamer specific, so I can respond to it. Patches 5/7/8 that are also assigned to me are all about winegstreamer changes, and for that we'll need someone else.
Using a new wg_sample struct.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/gst_private.h | 3 ++ dlls/winegstreamer/mfplat.c | 48 ++++++++++++++++++++++++++++++++ dlls/winegstreamer/unixlib.h | 6 ++++ dlls/winegstreamer/wma_decoder.c | 13 ++++++++- 4 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index a63daaf04b9..7ad3434fd1d 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -119,6 +119,9 @@ extern HRESULT mfplat_DllRegisterServer(void); IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format); void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format);
+HRESULT mf_create_wg_sample(IMFSample *sample, struct wg_sample **out); +void mf_destroy_wg_sample(struct wg_sample *wg_sample); + HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj);
HRESULT audio_converter_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 9b3fc429d32..c457a4ee79a 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -827,3 +827,51 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) else FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); } + +struct mf_sample +{ + IMFSample *sample; + IMFMediaBuffer *media_buffer; + struct wg_sample wg_sample; +}; + +HRESULT mf_create_wg_sample(IMFSample *sample, struct wg_sample **out) +{ + DWORD current_length, max_length; + struct mf_sample *mf_sample; + BYTE *buffer; + HRESULT hr; + + if (!(mf_sample = calloc(1, sizeof(*mf_sample)))) + return E_OUTOFMEMORY; + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &mf_sample->media_buffer))) + goto out_free_sample; + if (FAILED(hr = IMFMediaBuffer_Lock(mf_sample->media_buffer, &buffer, &max_length, ¤t_length))) + goto out_release_buffer; + + IMFSample_AddRef((mf_sample->sample = sample)); + mf_sample->wg_sample.size = current_length; + mf_sample->wg_sample.max_size = max_length; + + TRACE("Created mf_sample %p for sample %p.\n", mf_sample, sample); + *out = &mf_sample->wg_sample; + return S_OK; + +out_release_buffer: + IMFMediaBuffer_Release(mf_sample->media_buffer); +out_free_sample: + free(mf_sample); + return hr; +} + +void mf_destroy_wg_sample(struct wg_sample *wg_sample) +{ + struct mf_sample *mf_sample = CONTAINING_RECORD(wg_sample, struct mf_sample, wg_sample); + + IMFMediaBuffer_Unlock(mf_sample->media_buffer); + IMFMediaBuffer_SetCurrentLength(mf_sample->media_buffer, wg_sample->size); + IMFMediaBuffer_Release(mf_sample->media_buffer); + + IMFSample_Release(mf_sample->sample); + free(mf_sample); +} diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 4adbb694766..5bcad297fa9 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -103,6 +103,12 @@ struct wg_format } u; };
+struct wg_sample +{ + UINT32 max_size; + UINT32 size; +}; + enum wg_parser_event_type { WG_PARSER_EVENT_NONE = 0, diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index fef10b9c920..ffd05520f8c 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -529,6 +529,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, { struct wma_decoder *decoder = impl_from_IMFTransform(iface); MFT_OUTPUT_STREAM_INFO info; + struct wg_sample *wg_sample; HRESULT hr;
FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); @@ -550,7 +551,17 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return MF_E_TRANSFORM_NEED_MORE_INPUT; }
- return E_NOTIMPL; + if (FAILED(hr = mf_create_wg_sample(samples[0].pSample, &wg_sample))) + return hr; + + wg_sample->size = 0; + if (wg_sample->max_size < info.cbSize) + hr = MF_E_BUFFERTOOSMALL; + else + hr = E_NOTIMPL; + + mf_destroy_wg_sample(wg_sample); + return hr; }
static const IMFTransformVtbl transform_vtbl =
On 2/23/22 08:46, Rémi Bernon wrote:
Using a new wg_sample struct.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
This patch is hard to review on its own; I'd rather just see it merged with 7/8.
Checking that WMA decoder ignores any incorrectly sized input sample.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 4 +--- dlls/winegstreamer/wma_decoder.c | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 1f31eab60bc..f3c0db7a2c6 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -5997,13 +5997,11 @@ static void test_wma_decoder(void)
sample = create_sample(wma_encoded_data, wma_block_size / 2); hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == S_OK, "ProcessInput returned %#x\n", hr); ret = IMFSample_Release(sample); ok(ret == 0, "Release returned %u\n", ret); - sample = create_sample(wma_encoded_data + wma_block_size, wma_block_size - wma_block_size / 2); + sample = create_sample(wma_encoded_data, wma_block_size + 1); hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == S_OK, "ProcessInput returned %#x\n", hr); ret = IMFSample_Release(sample); ok(ret == 0, "Release returned %u\n", ret); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index ffd05520f8c..354f363bedf 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -520,8 +520,30 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_
static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { + struct wma_decoder *decoder = impl_from_IMFTransform(iface); + struct wg_sample *wg_sample; + MFT_INPUT_STREAM_INFO info; + HRESULT hr; + FIXME("iface %p, id %lu, sample %p, flags %#lx stub!\n", iface, id, sample, flags); - return E_NOTIMPL; + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) + return hr; + + if (FAILED(hr = mf_create_wg_sample(sample, &wg_sample))) + return hr; + + /* WMA transform uses fixed size input samples and ignores samples with invalid sizes */ + if (wg_sample->size % info.cbSize) + hr = S_OK; + else + hr = E_NOTIMPL; + + mf_destroy_wg_sample(wg_sample); + return hr; }
static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/wg_transform.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index a4a4d886865..ed4f95afde3 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -39,23 +39,44 @@
#include "unix_private.h"
+#include "wine/list.h" + GST_DEBUG_CATEGORY_EXTERN(wine); #define GST_CAT_DEFAULT wine
+struct sample_entry +{ + struct list entry; + GstSample *sample; +}; + struct wg_transform { GstElement *container; GstPad *my_src, *my_sink; GstPad *their_sink, *their_src; GstSegment segment; + pthread_mutex_t mutex; + struct list samples; };
static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) { struct wg_transform *transform = gst_pad_get_element_private(pad); + struct sample_entry *entry;
GST_INFO("transform %p, buffer %p.", transform, buffer);
+ if (!(entry = calloc(1, sizeof(*entry)))) + GST_ERROR("Failed to allocate sample entry"); + else + { + pthread_mutex_lock(&transform->mutex); + entry->sample = gst_sample_new(buffer, NULL, NULL, NULL); + list_add_tail(&transform->samples, &entry->entry); + pthread_mutex_unlock(&transform->mutex); + } + gst_buffer_unref(buffer);
return GST_FLOW_OK; @@ -64,8 +85,14 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst NTSTATUS wg_transform_destroy(void *args) { struct wg_transform *transform = args; + struct sample_entry *entry, *next;
gst_element_set_state(transform->container, GST_STATE_NULL); + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &transform->samples, struct sample_entry, entry) + { + gst_sample_unref(entry->sample); + free(entry); + } gst_pad_unlink(transform->their_src, transform->my_sink); gst_pad_unlink(transform->my_src, transform->their_sink); g_object_unref(transform->their_sink); @@ -73,6 +100,7 @@ NTSTATUS wg_transform_destroy(void *args) g_object_unref(transform->container); g_object_unref(transform->my_sink); g_object_unref(transform->my_src); + pthread_mutex_destroy(&transform->mutex); free(transform);
return STATUS_SUCCESS; @@ -281,6 +309,9 @@ NTSTATUS wg_transform_create(void *args) gst_caps_unref(sink_caps); gst_caps_unref(src_caps);
+ pthread_mutex_init(&transform->mutex, NULL); + list_init(&transform->samples); + GST_INFO("Created winegstreamer transform %p.", transform); params->transform = transform; return STATUS_SUCCESS;
On 2/23/22 08:46, Rémi Bernon wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/winegstreamer/wg_transform.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
What's the motivation for doing this?
(And why not, say, use a queue element instead? Not that this is particularly complex, to be fair.)
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index a4a4d886865..ed4f95afde3 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -39,23 +39,44 @@
#include "unix_private.h"
+#include "wine/list.h"
GST_DEBUG_CATEGORY_EXTERN(wine); #define GST_CAT_DEFAULT wine
+struct sample_entry +{
- struct list entry;
- GstSample *sample;
+};
struct wg_transform { GstElement *container; GstPad *my_src, *my_sink; GstPad *their_sink, *their_src; GstSegment segment;
- pthread_mutex_t mutex;
- struct list samples;
};
static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) { struct wg_transform *transform = gst_pad_get_element_private(pad);
struct sample_entry *entry;
GST_INFO("transform %p, buffer %p.", transform, buffer);
if (!(entry = calloc(1, sizeof(*entry))))
GST_ERROR("Failed to allocate sample entry");
else
{
pthread_mutex_lock(&transform->mutex);
entry->sample = gst_sample_new(buffer, NULL, NULL, NULL);
list_add_tail(&transform->samples, &entry->entry);
pthread_mutex_unlock(&transform->mutex);
Why create a GstSample?
}
gst_buffer_unref(buffer);
return GST_FLOW_OK;
On 2/25/22 18:45, Zebediah Figura (she/her) wrote:
On 2/23/22 08:46, Rémi Bernon wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/winegstreamer/wg_transform.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
What's the motivation for doing this?
(And why not, say, use a queue element instead? Not that this is particularly complex, to be fair.)
It seemed simpler like this as it doesn't need to wait on ProcessOutput to be called.
Still, I'd like to add a queue later anyway, for the purpose of implementing zero-copy, so maybe I can use it there, I'll have a try.
- if (!(entry = calloc(1, sizeof(*entry))))
GST_ERROR("Failed to allocate sample entry");
- else
- {
pthread_mutex_lock(&transform->mutex);
entry->sample = gst_sample_new(buffer, NULL, NULL, NULL);
list_add_tail(&transform->samples, &entry->entry);
pthread_mutex_unlock(&transform->mutex);
Why create a GstSample?
Because I think we'll need to hold the caps for the buffers too, to detect format changes which can and must happen with H264.
I can change it later too, it makes future changes smaller to have the sample now.
On 2/25/22 14:37, Rémi Bernon wrote:
On 2/25/22 18:45, Zebediah Figura (she/her) wrote:
On 2/23/22 08:46, Rémi Bernon wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/winegstreamer/wg_transform.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
What's the motivation for doing this?
(And why not, say, use a queue element instead? Not that this is particularly complex, to be fair.)
It seemed simpler like this as it doesn't need to wait on ProcessOutput to be called.
That's a good point; I did not consider that. And of course the concern of memory usage doesn't apply here.
Still, I'd like to add a queue later anyway, for the purpose of implementing zero-copy, so maybe I can use it there, I'll have a try.
+ if (!(entry = calloc(1, sizeof(*entry)))) + GST_ERROR("Failed to allocate sample entry"); + else + { + pthread_mutex_lock(&transform->mutex); + entry->sample = gst_sample_new(buffer, NULL, NULL, NULL); + list_add_tail(&transform->samples, &entry->entry); + pthread_mutex_unlock(&transform->mutex);
Why create a GstSample?
Because I think we'll need to hold the caps for the buffers too, to detect format changes which can and must happen with H264.
I can change it later too, it makes future changes smaller to have the sample now.
Okay, that probably makes sense; I just couldn't tell from the commit.
On 2/26/22 02:33, Zebediah Figura (she/her) wrote:
On 2/25/22 14:37, Rémi Bernon wrote:
On 2/25/22 18:45, Zebediah Figura (she/her) wrote:
On 2/23/22 08:46, Rémi Bernon wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/winegstreamer/wg_transform.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
What's the motivation for doing this?
(And why not, say, use a queue element instead? Not that this is particularly complex, to be fair.)
It seemed simpler like this as it doesn't need to wait on ProcessOutput to be called.
That's a good point; I did not consider that. And of course the concern of memory usage doesn't apply here.
The queue seems actually to make the code a little bit shorter, if not simpler logic.
As I intended to add one at some point, and have it wait on ProcessOutput to allow zero-copy output I think I'm going to use it here already instead.
Then it makes all the transforms async, which is slightly incorrect for the WMA decoder, but I guess it's a small price to pay and I don't think it matters too much.
If it actually does, we can later enforce synchronicity by waiting, either on output to be generated, or the queue to be empty.
And use it to implement WMA decoder ProcessOutput.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 9 +++- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 15 +++++++ dlls/winegstreamer/mfplat.c | 1 + dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 16 +++++++ dlls/winegstreamer/wg_parser.c | 2 + dlls/winegstreamer/wg_transform.c | 74 ++++++++++++++++++++++++++++++- dlls/winegstreamer/wma_decoder.c | 9 ++-- 9 files changed, 123 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index f3c0db7a2c6..e5c0e6051b5 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6079,9 +6079,17 @@ static void test_wma_decoder(void)
sample = create_sample(wma_encoded_data + i * wma_block_size, wma_block_size); hr = IMFTransform_ProcessInput(transform, 0, sample, 0); + todo_wine ok(hr == S_OK, "ProcessInput returned %#x\n", hr); ret = IMFSample_Release(sample); + todo_wine ok(ret == 1, "Release returned %u\n", ret); + if (hr != S_OK) + { + memset(&output, 0, sizeof(output)); + output.pSample = sample = create_sample(NULL, output_info.cbSize); + break; + } i++;
status = 0xdeadbeef; @@ -6139,7 +6147,6 @@ static void test_wma_decoder(void) memset(&output, 0, sizeof(output)); output.pSample = sample; hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); ok(output.pSample == sample, "got pSample %p\n", output.pSample); ok(output.dwStatus == 0 || diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 7ad3434fd1d..7970980e5ba 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -99,6 +99,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, struct wg_transform *wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format); void wg_transform_destroy(struct wg_transform *transform); +HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample);
unsigned int wg_format_get_max_size(const struct wg_format *format);
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index f85e9995525..4337bd7e5e1 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -273,6 +273,21 @@ void wg_transform_destroy(struct wg_transform *transform) __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); }
+HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) +{ + struct wg_transform_read_data_params params = + { + .transform = transform, + .sample = sample, + }; + NTSTATUS status; + + if ((status = __wine_unix_call(unix_handle, unix_wg_transform_read_data, ¶ms))) + return HRESULT_FROM_NT(status); + + return params.result; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index c457a4ee79a..4b4d647170a 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -850,6 +850,7 @@ HRESULT mf_create_wg_sample(IMFSample *sample, struct wg_sample **out) goto out_release_buffer;
IMFSample_AddRef((mf_sample->sample = sample)); + mf_sample->wg_sample.data = buffer; mf_sample->wg_sample.size = current_length; mf_sample->wg_sample.max_size = max_length;
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index d3f32484ee6..d14d0d309f5 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -34,5 +34,6 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE
extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN;
#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 5bcad297fa9..8bc8b5f9ec2 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -103,10 +103,17 @@ struct wg_format } u; };
+enum wg_sample_flag +{ + WG_SAMPLE_FLAG_INCOMPLETE = 1, +}; + struct wg_sample { + UINT32 flags; UINT32 max_size; UINT32 size; + BYTE *data; };
enum wg_parser_event_type @@ -242,6 +249,13 @@ struct wg_transform_create_params const struct wg_format *output_format; };
+struct wg_transform_read_data_params +{ + struct wg_transform *transform; + struct wg_sample *sample; + HRESULT result; +}; + enum unix_funcs { unix_wg_parser_create, @@ -273,6 +287,8 @@ enum unix_funcs
unix_wg_transform_create, unix_wg_transform_destroy, + + unix_wg_transform_read_data, };
#endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index d9bbc60964e..8b7c5278c27 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1660,4 +1660,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_transform_create), X(wg_transform_destroy), + + X(wg_transform_read_data), }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index ed4f95afde3..5200d836db4 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -35,7 +35,7 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h" -#include "dshow.h" +#include "mferror.h"
#include "unix_private.h"
@@ -48,6 +48,7 @@ struct sample_entry { struct list entry; GstSample *sample; + gsize buffer_size; };
struct wg_transform @@ -72,6 +73,7 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst else { pthread_mutex_lock(&transform->mutex); + entry->buffer_size = gst_buffer_get_size(buffer); entry->sample = gst_sample_new(buffer, NULL, NULL, NULL); list_add_tail(&transform->samples, &entry->entry); pthread_mutex_unlock(&transform->mutex); @@ -340,3 +342,73 @@ out_free_transform: GST_ERROR("Failed to create winegstreamer transform."); return status; } + +static void release_sample_entry(struct wg_sample *sample, struct sample_entry *entry) +{ + GstBuffer *buffer = gst_sample_get_buffer(entry->sample); + + if (entry->buffer_size > sample->size) + { + gst_buffer_resize(buffer, sample->size, -1); + entry->buffer_size -= sample->size; + } + else + { + gst_sample_unref(entry->sample); + list_remove(&entry->entry); + free(entry); + } +} + +static NTSTATUS copy_from_sample_entry(struct wg_sample *sample, struct sample_entry *entry) +{ + GstBuffer *buffer = gst_sample_get_buffer(entry->sample); + GstMapInfo info; + + if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) + { + GST_ERROR("Failed to map buffer %p", buffer); + return STATUS_UNSUCCESSFUL; + } + + if (sample->max_size >= info.size) + sample->size = info.size; + else + { + sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE; + sample->size = sample->max_size; + } + + memcpy(sample->data, info.data, sample->size); + gst_buffer_unmap(buffer, &info); + + GST_INFO("Copied %u bytes, flags %#x", sample->size, (UINT32)sample->flags); + return STATUS_SUCCESS; +} + +NTSTATUS wg_transform_read_data(void *args) +{ + struct wg_transform_read_data_params *params = args; + struct wg_transform *transform = params->transform; + struct wg_sample *sample = params->sample; + struct sample_entry *entry; + struct list *head; + NTSTATUS status; + + pthread_mutex_lock(&transform->mutex); + if ((head = list_head(&transform->samples))) + { + params->result = S_OK; + entry = LIST_ENTRY(head, struct sample_entry, entry); + status = copy_from_sample_entry(sample, entry); + release_sample_entry(sample, entry); + } + else + { + params->result = MF_E_TRANSFORM_NEED_MORE_INPUT; + status = STATUS_SUCCESS; + } + pthread_mutex_unlock(&transform->mutex); + + return status; +} diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 354f363bedf..af7db10b335 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -554,7 +554,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, struct wg_sample *wg_sample; HRESULT hr;
- FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
if (count > 1) return E_INVALIDARG; @@ -579,8 +579,11 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, wg_sample->size = 0; if (wg_sample->max_size < info.cbSize) hr = MF_E_BUFFERTOOSMALL; - else - hr = E_NOTIMPL; + else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, wg_sample))) + { + if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE) + samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; + }
mf_destroy_wg_sample(wg_sample); return hr;
On 2/23/22 08:46, Rémi Bernon wrote:
+static void release_sample_entry(struct wg_sample *sample, struct sample_entry *entry) +{
- GstBuffer *buffer = gst_sample_get_buffer(entry->sample);
- if (entry->buffer_size > sample->size)
- {
gst_buffer_resize(buffer, sample->size, -1);
entry->buffer_size -= sample->size;
- }
- else
- {
gst_sample_unref(entry->sample);
list_remove(&entry->entry);
free(entry);
- }
+}
+static NTSTATUS copy_from_sample_entry(struct wg_sample *sample, struct sample_entry *entry) +{
- GstBuffer *buffer = gst_sample_get_buffer(entry->sample);
- GstMapInfo info;
- if (!gst_buffer_map(buffer, &info, GST_MAP_READ))
- {
GST_ERROR("Failed to map buffer %p", buffer);
return STATUS_UNSUCCESSFUL;
- }
- if (sample->max_size >= info.size)
sample->size = info.size;
- else
- {
sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE;
sample->size = sample->max_size;
- }
- memcpy(sample->data, info.data, sample->size);
- gst_buffer_unmap(buffer, &info);
- GST_INFO("Copied %u bytes, flags %#x", sample->size, (UINT32)sample->flags);
Isn't that cast redundant?
- return STATUS_SUCCESS;
+}
release_sample_entry() feels initially confusing to me, or at least more than necessary. Could we just combine these two functions?
(As far as I can see the only point is to release the buffer it mapping it fails, but I'd rather just copy the relevant two or three lines.)
And use it to implement WMA decoder ProcessInput.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 23 ++++++----------------- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 15 +++++++++++++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 8 ++++++++ dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 30 ++++++++++++++++++++++++++++++ dlls/winegstreamer/wma_decoder.c | 4 ++-- 8 files changed, 64 insertions(+), 19 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index e5c0e6051b5..37778be1851 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6007,10 +6007,8 @@ static void test_wma_decoder(void) ok(ret == 0, "Release returned %u\n", ret); sample = create_sample(wma_encoded_data, wma_block_size); hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == S_OK, "ProcessInput returned %#x\n", hr); hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#x\n", hr); ret = IMFSample_Release(sample); todo_wine @@ -6033,7 +6031,6 @@ static void test_wma_decoder(void)
sample = create_sample(wma_encoded_data, wma_block_size); hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#x\n", hr); ret = IMFSample_Release(sample); ok(ret == 0, "Release returned %u\n", ret); @@ -6079,17 +6076,9 @@ static void test_wma_decoder(void)
sample = create_sample(wma_encoded_data + i * wma_block_size, wma_block_size); hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == S_OK, "ProcessInput returned %#x\n", hr); ret = IMFSample_Release(sample); - todo_wine ok(ret == 1, "Release returned %u\n", ret); - if (hr != S_OK) - { - memset(&output, 0, sizeof(output)); - output.pSample = sample = create_sample(NULL, output_info.cbSize); - break; - } i++;
status = 0xdeadbeef; @@ -6099,7 +6088,6 @@ static void test_wma_decoder(void) hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); }
- todo_wine ok(hr == S_OK, "ProcessOutput returned %#x\n", hr); ok(output.pSample == sample, "got pSample %p\n", output.pSample);
@@ -6112,7 +6100,8 @@ static void test_wma_decoder(void) "got dwStatus %#x\n", output.dwStatus); ok(status == 0, "got status %#x\n", status); if (output.dwStatus == MFT_OUTPUT_DATA_BUFFER_INCOMPLETE || - broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7))) + broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7)) || + !strcmp(winetest_platform, "wine")) { check_sample(sample, wma_decoded_data, sizeof(wma_decoded_data), NULL); i += sizeof(wma_decoded_data); @@ -6131,10 +6120,11 @@ static void test_wma_decoder(void) output.pSample = sample; hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); } - todo_wine - ok(i == 0xe000, "ProcessOutput produced %#x bytes\n", i); + if (!strcmp(winetest_platform, "wine")) + ok(i == 0x10000, "ProcessOutput produced %#x bytes\n", i); + else + ok(i == 0xe000, "ProcessOutput produced %#x bytes\n", i);
- todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); ok(output.pSample == sample, "got pSample %p\n", output.pSample); ok(output.dwStatus == 0, "got dwStatus %#x\n", output.dwStatus); @@ -6159,7 +6149,6 @@ static void test_wma_decoder(void)
sample = create_sample(wma_encoded_data, wma_block_size); hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - todo_wine ok(hr == S_OK, "ProcessInput returned %#x\n", hr);
ret = IMFTransform_Release(transform); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 7970980e5ba..863bff91e4b 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -99,6 +99,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, struct wg_transform *wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format); void wg_transform_destroy(struct wg_transform *transform); +HRESULT wg_transform_push_data(struct wg_transform *transform, struct wg_sample *sample); HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample);
unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 4337bd7e5e1..0900ee6f05c 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -273,6 +273,21 @@ void wg_transform_destroy(struct wg_transform *transform) __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); }
+HRESULT wg_transform_push_data(struct wg_transform *transform, struct wg_sample *sample) +{ + struct wg_transform_push_data_params params = + { + .transform = transform, + .sample = sample, + }; + NTSTATUS status; + + if ((status = __wine_unix_call(unix_handle, unix_wg_transform_push_data, ¶ms))) + return HRESULT_FROM_NT(status); + + return params.result; +} + HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) { struct wg_transform_read_data_params params = diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index d14d0d309f5..7bce8263aaf 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -34,6 +34,7 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE
extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN;
#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 8bc8b5f9ec2..cf3d1df4957 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -249,6 +249,13 @@ struct wg_transform_create_params const struct wg_format *output_format; };
+struct wg_transform_push_data_params +{ + struct wg_transform *transform; + struct wg_sample *sample; + HRESULT result; +}; + struct wg_transform_read_data_params { struct wg_transform *transform; @@ -288,6 +295,7 @@ enum unix_funcs unix_wg_transform_create, unix_wg_transform_destroy,
+ unix_wg_transform_push_data, unix_wg_transform_read_data, };
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 8b7c5278c27..72f562d3feb 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1661,5 +1661,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_create), X(wg_transform_destroy),
+ X(wg_transform_push_data), X(wg_transform_read_data), }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 5200d836db4..66530625e07 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -343,6 +343,36 @@ out_free_transform: return status; }
+NTSTATUS wg_transform_push_data(void *args) +{ + struct wg_transform_push_data_params *params = args; + struct wg_transform *transform = params->transform; + struct wg_sample *sample = params->sample; + GstFlowReturn ret; + GstBuffer *buffer; + + pthread_mutex_lock(&transform->mutex); + if (!list_empty(&transform->samples)) + { + pthread_mutex_unlock(&transform->mutex); + params->result = MF_E_NOTACCEPTING; + return STATUS_SUCCESS; + } + pthread_mutex_unlock(&transform->mutex); + + buffer = gst_buffer_new_and_alloc(sample->size); + if (!buffer) + return STATUS_NO_MEMORY; + + gst_buffer_fill(buffer, 0, sample->data, sample->size); + if ((ret = gst_pad_push(transform->my_src, buffer))) + return STATUS_UNSUCCESSFUL; + + GST_DEBUG("Pushed %u bytes", sample->size); + params->result = S_OK; + return STATUS_SUCCESS; +} + static void release_sample_entry(struct wg_sample *sample, struct sample_entry *entry) { GstBuffer *buffer = gst_sample_get_buffer(entry->sample); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index af7db10b335..6ee43e19414 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -525,7 +525,7 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS MFT_INPUT_STREAM_INFO info; HRESULT hr;
- FIXME("iface %p, id %lu, sample %p, flags %#lx stub!\n", iface, id, sample, flags); + TRACE("iface %p, id %lu, sample %p, flags %#lx.\n", iface, id, sample, flags);
if (!decoder->wg_transform) return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -540,7 +540,7 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS if (wg_sample->size % info.cbSize) hr = S_OK; else - hr = E_NOTIMPL; + hr = wg_transform_push_data(decoder->wg_transform, wg_sample);
mf_destroy_wg_sample(wg_sample); return hr;