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;