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 ---
I believe this approach works best and doesn't suffer from any of the potential troubles the queue would introduce. It should also be fully synchronous in the general case, although I kept the mutex to be safe.
For now, one input buffer can be queued at a time, which is how the WMA decoder transform works, and the output buffers are appended to each other, although they are normally also produced one at a time.
Later, and to satisfy the requirements of the H264 transform and the expectations of CoD: BO3, I will change the input to a GstBufferList with a length limit.
Even for the zero-copy optimization, I was able to validate that it's still possible, and even simpler to implement as we now do all the processing in ProcessOutput.
We can then later consider adding some asynchronicity using queues, but I'm not sure it is going to be useful, and may even cause more problems than it's worth.
dlls/mf/tests/mf.c | 23 +++++++++++++--------- dlls/winegstreamer/wma_decoder.c | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index e61442bb512..0ab46445d9a 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6031,6 +6031,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; @@ -6208,7 +6209,7 @@ static void test_wma_decoder(void) 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); @@ -6231,16 +6232,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); @@ -6253,16 +6251,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); @@ -6333,7 +6340,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); @@ -6349,7 +6355,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..a35da1cdc70 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -520,14 +520,47 @@ 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); + MFT_INPUT_STREAM_INFO info; + HRESULT hr; + FIXME("iface %p, id %lu, sample %p, flags %#lx stub!\n", iface, id, sample, flags); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) + return hr; + return E_NOTIMPL; }
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; }
And use it to implement WMA decoder Process(Input|Output).
The test output is different because ffmpeg WMA decoder outputs data in a different way as native. The data seems valid audio nonetheless, and it shouldn't matter too much.
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 | 43 ++--------- dlls/winegstreamer/gst_private.h | 5 ++ dlls/winegstreamer/main.c | 30 ++++++++ dlls/winegstreamer/mfplat.c | 49 ++++++++++++ dlls/winegstreamer/unix_private.h | 2 + dlls/winegstreamer/unixlib.h | 30 ++++++++ dlls/winegstreamer/wg_parser.c | 3 + dlls/winegstreamer/wg_transform.c | 119 +++++++++++++++++++++++++++++- dlls/winegstreamer/wma_decoder.c | 33 ++++++++- 9 files changed, 270 insertions(+), 44 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 0ab46445d9a..be09c6040fe 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6205,22 +6205,18 @@ 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 + 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); 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 @@ -6243,7 +6239,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); @@ -6270,38 +6265,12 @@ static void test_wma_decoder(void) IMFSample_Release(outputs[0].pSample); IMFSample_Release(outputs[1].pSample);
- i = 1; status = 0xdeadbeef; output_info.cbSize = sizeof(wma_decoded_data); sample = create_sample(NULL, output_info.cbSize); memset(&output, 0, sizeof(output)); output.pSample = sample; hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) - { - 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); - ok(status == 0, "got status %#x\n", status); - check_sample(sample, NULL, 0, NULL); - ret = IMFSample_Release(sample); - ok(ret == 0, "Release returned %u\n", ret); - - sample = create_sample(wma_encoded_data + i * wma_block_size, wma_block_size); - hr = IMFTransform_ProcessInput(transform, 0, sample, 0); - ok(hr == S_OK, "ProcessInput returned %#x\n", hr); - ret = IMFSample_Release(sample); - ok(ret == 1, "Release returned %u\n", ret); - i++; - - status = 0xdeadbeef; - sample = create_sample(NULL, output_info.cbSize); - memset(&output, 0, sizeof(output)); - output.pSample = sample; - 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);
@@ -6314,7 +6283,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); @@ -6333,10 +6303,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); @@ -6349,7 +6320,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 || @@ -6362,7 +6332,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 2cbba09f9a7..e5870bc3b5d 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -96,6 +96,8 @@ 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);
@@ -116,6 +118,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/main.c b/dlls/winegstreamer/main.c index 327d144499e..8a41df6b223 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -263,6 +263,36 @@ 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 = + { + .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 9b3fc429d32..82e926d673d 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -827,3 +827,52 @@ 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; + if (FAILED(hr = IMFMediaBuffer_Lock(mf_sample->media_buffer, &buffer, &max_length, ¤t_length))) + goto out; + + 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; + + TRACE("Created mf_sample %p for sample %p.\n", mf_sample, sample); + *out = &mf_sample->wg_sample; + return S_OK; + +out: + if (mf_sample->media_buffer) + IMFMediaBuffer_Release(mf_sample->media_buffer); + 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/unix_private.h b/dlls/winegstreamer/unix_private.h index d3f32484ee6..7bce8263aaf 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -34,5 +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 3dfa30b4889..e1c0ec3f3b7 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -103,6 +103,19 @@ 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; +}; + struct wg_parser_buffer { /* pts and duration are in 100-nanosecond units. */ @@ -216,6 +229,20 @@ 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; + struct wg_sample *sample; + HRESULT result; +}; + enum unix_funcs { unix_wg_parser_create, @@ -244,6 +271,9 @@ enum unix_funcs
unix_wg_transform_create, unix_wg_transform_destroy, + + unix_wg_transform_push_data, + 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 46a298f13c1..df563e9336e 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1589,4 +1589,7 @@ 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 45f8588b9f1..6e272634653 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,15 +48,24 @@ struct wg_transform GstPad *my_src, *my_sink; GstPad *their_sink, *their_src; GstSegment segment; + GstBuffer *input; + + pthread_mutex_t mutex; + GstBuffer *output; };
static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) { struct wg_transform *transform = gst_pad_get_element_private(pad);
- GST_INFO("transform %p, buffer %p.", transform, buffer); + GST_LOG("transform %p, buffer %p.", transform, buffer);
- gst_buffer_unref(buffer); + pthread_mutex_lock(&transform->mutex); + if (transform->output) + transform->output = gst_buffer_append(transform->output, buffer); + else + transform->output = buffer; + pthread_mutex_unlock(&transform->mutex);
return GST_FLOW_OK; } @@ -65,12 +74,18 @@ NTSTATUS wg_transform_destroy(void *args) { struct wg_transform *transform = args;
+ if (transform->input) + gst_buffer_unref(transform->input); + if (transform->output) + gst_buffer_unref(transform->output); + gst_element_set_state(transform->container, GST_STATE_NULL); 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); + pthread_mutex_destroy(&transform->mutex); free(transform);
return STATUS_SUCCESS; @@ -278,6 +293,8 @@ NTSTATUS wg_transform_create(void *args) gst_caps_unref(sink_caps); gst_caps_unref(src_caps);
+ pthread_mutex_init(&transform->mutex, NULL); + GST_INFO("Created winegstreamer transform %p.", transform); params->transform = transform; return STATUS_SUCCESS; @@ -304,3 +321,99 @@ out: GST_ERROR("Failed to create winegstreamer 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; + GstBuffer *buffer; + + if (transform->input) + { + GST_INFO("Refusing %u bytes, a buffer is already queued", sample->size); + params->result = MF_E_NOTACCEPTING; + return STATUS_SUCCESS; + } + + if (!(buffer = gst_buffer_new_and_alloc(sample->size))) + { + GST_ERROR("Failed to allocate input buffer"); + return STATUS_NO_MEMORY; + } + gst_buffer_fill(buffer, 0, sample->data, sample->size); + transform->input = buffer; + + GST_INFO("Copied %u bytes from sample %p to input buffer", sample->size, sample); + params->result = S_OK; + return STATUS_SUCCESS; +} + +static NTSTATUS read_transform_output_data(struct wg_transform *transform, + struct wg_sample *sample) +{ + GstBuffer *buffer = transform->output; + 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_buffer_resize(buffer, sample->size, -1); + + if (info.size <= sample->size) + { + gst_buffer_unref(transform->output); + transform->output = NULL; + } + + GST_INFO("Copied %u bytes, sample %p, flags %#x", sample->size, sample, 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; + GstFlowReturn ret; + NTSTATUS status; + + if (!transform->input) + GST_DEBUG("Not input buffer queued"); + else if ((ret = gst_pad_push(transform->my_src, transform->input))) + { + GST_ERROR("Failed to push transform input, error %d", ret); + return STATUS_UNSUCCESSFUL; + } + transform->input = NULL; + + sample->size = 0; + pthread_mutex_lock(&transform->mutex); + if (transform->output) + { + params->result = S_OK; + status = read_transform_output_data(transform, sample); + } + else + { + params->result = MF_E_TRANSFORM_NEED_MORE_INPUT; + status = STATUS_SUCCESS; + GST_INFO("Cannot read %u bytes, no output available", sample->max_size); + } + pthread_mutex_unlock(&transform->mutex); + + return status; +} diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index a35da1cdc70..6ee43e19414 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -521,10 +521,11 @@ 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); + 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; @@ -532,7 +533,17 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) return hr;
- return E_NOTIMPL; + 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 = wg_transform_push_data(decoder->wg_transform, wg_sample); + + mf_destroy_wg_sample(wg_sample); + return hr; }
static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, @@ -540,9 +551,10 @@ 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); + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
if (count > 1) return E_INVALIDARG; @@ -561,7 +573,20 @@ 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 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; }
static const IMFTransformVtbl transform_vtbl =
On 2/28/22 10:27, Rémi Bernon wrote:
And use it to implement WMA decoder Process(Input|Output).
- 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);
This doesn't hold for me:
042c:fixme:wmadec:transform_GetInputAvailableType iface 00000000008225A8, id 0, index 0, type 000000000021F7D0 stub! 042c:fixme:mfplat:mf_media_type_to_wg_format_wma Bitrate is not set. mf.c:6307: Test failed: ProcessOutput produced 0xc000 bytes
On 3/3/22 02:17, Zebediah Figura (she/her) wrote:
On 2/28/22 10:27, Rémi Bernon wrote:
And use it to implement WMA decoder Process(Input|Output).
- 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);
This doesn't hold for me:
042c:fixme:wmadec:transform_GetInputAvailableType iface 00000000008225A8, id 0, index 0, type 000000000021F7D0 stub! 042c:fixme:mfplat:mf_media_type_to_wg_format_wma Bitrate is not set. mf.c:6307: Test failed: ProcessOutput produced 0xc000 bytes
Hmm... weird, maybe some ffmpeg variation?
The testbot seems happy with it, though as it differs from native already maybe I should simply make the check todo if it fails, or remove it altogether.
On 3/3/22 05:09, Rémi Bernon wrote:
On 3/3/22 02:17, Zebediah Figura (she/her) wrote:
On 2/28/22 10:27, Rémi Bernon wrote:
And use it to implement WMA decoder Process(Input|Output). - 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);
This doesn't hold for me:
042c:fixme:wmadec:transform_GetInputAvailableType iface 00000000008225A8, id 0, index 0, type 000000000021F7D0 stub! 042c:fixme:mfplat:mf_media_type_to_wg_format_wma Bitrate is not set. mf.c:6307: Test failed: ProcessOutput produced 0xc000 bytes
Hmm... weird, maybe some ffmpeg variation?
The testbot seems happy with it, though as it differs from native already maybe I should simply make the check todo if it fails, or remove it altogether.
I don't know what's responsible for the difference, but I don't think there's any reason to expect GStreamer or ffmpeg to be stable in the first place.
Personally I suspect we don't want to be that strict in the tests, unless applications really are going to depend on it.
Granted, it's one of those cases where it's probably not going to be easy to debug if an application does depend on it, but it's also rather difficult to fix Wine to match.
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/wma_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 6ee43e19414..57b0f204f9e 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -515,7 +515,7 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); - return E_NOTIMPL; + return S_OK; }
static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)