First part of a series introducing a separate unix interface for the MF media source. The goal is to use a synchronous demuxing-only interface, similar to native, which will be simpler and faster and better fitted to most MF media source use cases.
-- v2: winegstreamer/media_source: Handle GST_QUERY_SCHEDULING on wg_source src pad. winegstreamer/media_source: Handle GST_QUERY_DURATION on wg_source src pad. winegstreamer/media_source: Handle GST_QUERY_URI on wg_source src pad. winegstreamer/media_source: Push a stream and segment event to the wg_source. winegstreamer/media_source: Create a demuxer element in wg_source_create. winegstreamer/media_source: Create a source pad on the wg_source. winegstreamer/media_source: Prefer MF_BYTESTREAM_ORIGIN_NAME for source URL. winegstreamer/media_source: Provide first block of data and stream URL to wg_source. winegstreamer/media_source: Call (Begin|End)Read to read the byte stream header. winegstreamer/media_source: Introduce a new wg_source interface.
From: Rémi Bernon rbernon@codeweavers.com
--- MAINTAINERS | 1 + dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 3 + dlls/winegstreamer/main.c | 25 ++++++++ dlls/winegstreamer/media_source.c | 15 ++++- dlls/winegstreamer/unix_private.h | 5 ++ dlls/winegstreamer/unixlib.h | 9 +++ dlls/winegstreamer/wg_parser.c | 6 ++ dlls/winegstreamer/wg_source.c | 94 +++++++++++++++++++++++++++++++ 9 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 dlls/winegstreamer/wg_source.c
diff --git a/MAINTAINERS b/MAINTAINERS index 29fa77c0404..64c696ddc09 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -217,6 +217,7 @@ F: dlls/winegstreamer/mfplat.c F: dlls/winegstreamer/resampler.c F: dlls/winegstreamer/video_decoder.c F: dlls/winegstreamer/video_processor.c +F: dlls/winegstreamer/wg_source.c F: dlls/winegstreamer/wg_sample.c F: dlls/winegstreamer/wg_transform.c F: dlls/winegstreamer/wma_decoder.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 63ca3f61fdf..40ff4515281 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -27,6 +27,7 @@ SOURCES = \ wg_muxer.c \ wg_parser.c \ wg_sample.c \ + wg_source.c \ wg_transform.c \ winegstreamer_classes.idl \ wm_reader.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 0f7d945ba37..6380b8fb7ff 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -104,6 +104,9 @@ char *wg_parser_stream_get_tag(wg_parser_stream_t stream, enum wg_parser_tag tag void wg_parser_stream_seek(wg_parser_stream_t stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags);
+HRESULT wg_source_create(wg_source_t *out); +void wg_source_destroy(wg_source_t source); + HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, const struct wg_transform_attrs *attrs, wg_transform_t *transform); HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 2d144a6f71f..92a44be0c96 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -435,6 +435,31 @@ void wg_parser_stream_seek(wg_parser_stream_t stream, double rate, WINE_UNIX_CALL(unix_wg_parser_stream_seek, ¶ms); }
+HRESULT wg_source_create(wg_source_t *out) +{ + struct wg_source_create_params params = {0}; + NTSTATUS status; + + TRACE("out %p\n", out); + + if ((status = WINE_UNIX_CALL(unix_wg_source_create, ¶ms))) + WARN("wg_source_create returned status %#lx\n", status); + else + { + TRACE("Returning source %#I64x.\n", params.source); + *out = params.source; + } + + return HRESULT_FROM_NT(status); +} + +void wg_source_destroy(wg_source_t source) +{ + TRACE("source %#I64x.\n", source); + + WINE_UNIX_CALL(unix_wg_source_destroy, &source); +} + HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, const struct wg_transform_attrs *attrs, wg_transform_t *transform) { diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 030d0c1b9a2..0de82d76db9 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -36,6 +36,8 @@ struct object_context IMFByteStream *stream; UINT64 file_size; WCHAR *url; + + wg_source_t wg_source; };
static struct object_context *impl_from_IUnknown(IUnknown *iface) @@ -78,6 +80,8 @@ static ULONG WINAPI object_context_Release(IUnknown *iface)
if (!refcount) { + if (context->wg_source) + wg_source_destroy(context->wg_source); IMFAsyncResult_Release(context->result); IMFByteStream_Release(context->stream); free(context->url); @@ -182,6 +186,7 @@ struct media_source
CRITICAL_SECTION cs;
+ wg_source_t wg_source; UINT64 file_size; wg_parser_t wg_parser; UINT64 duration; @@ -1364,6 +1369,7 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) IMFMediaSource_Shutdown(iface); IMFMediaEventQueue_Release(source->event_queue); IMFByteStream_Release(source->byte_stream); + wg_source_destroy(source->wg_source); wg_parser_destroy(source->wg_parser); source->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&source->cs); @@ -1642,6 +1648,9 @@ static HRESULT media_source_create(struct object_context *context, IMFMediaSourc InitializeCriticalSectionEx(&object->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
+ object->wg_source = context->wg_source; + context->wg_source = 0; + if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) goto fail;
@@ -1721,6 +1730,8 @@ fail: WaitForSingleObject(object->read_thread, INFINITE); CloseHandle(object->read_thread); } + if (object->wg_source) + wg_source_destroy(object->wg_source); if (object->wg_parser) wg_parser_destroy(object->wg_parser); if (object->async_commands_queue) @@ -2003,7 +2014,9 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM if (!state || !(context = impl_from_IUnknown(state))) return E_INVALIDARG;
- if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) + if (FAILED(hr = wg_source_create(&context->wg_source))) + WARN("Failed to create wg_source, hr %#lx\n", hr); + else if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) WARN("Failed to create media source, hr %#lx\n", hr); else { diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index b2cc036c914..52412a283ab 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -68,6 +68,11 @@ extern NTSTATUS wg_transform_drain(void *args); extern NTSTATUS wg_transform_flush(void *args); extern NTSTATUS wg_transform_notify_qos(void *args);
+/* wg_source.c */ + +extern NTSTATUS wg_source_create(void *args); +extern NTSTATUS wg_source_destroy(void *args); + /* wg_media_type.c */
static inline BOOL is_mf_video_area_empty(const MFVideoArea *area) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 19270bd731b..0a98aadd1ab 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -205,6 +205,7 @@ C_ASSERT(sizeof(struct wg_parser_buffer) == 32);
typedef UINT64 wg_parser_t; typedef UINT64 wg_parser_stream_t; +typedef UINT64 wg_source_t; typedef UINT64 wg_transform_t; typedef UINT64 wg_muxer_t;
@@ -329,6 +330,11 @@ struct wg_parser_stream_seek_params DWORD start_flags, stop_flags; };
+struct wg_source_create_params +{ + wg_source_t source; +}; + struct wg_transform_attrs { UINT32 output_plane_align; @@ -444,6 +450,9 @@ enum unix_funcs unix_wg_parser_stream_get_tag, unix_wg_parser_stream_seek,
+ unix_wg_source_create, + unix_wg_source_destroy, + unix_wg_transform_create, unix_wg_transform_destroy, unix_wg_transform_get_output_type, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 710cfe6a0a5..51753b1f429 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1887,6 +1887,9 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_stream_get_tag), X(wg_parser_stream_seek),
+ X(wg_source_create), + X(wg_source_destroy), + X(wg_transform_create), X(wg_transform_destroy), X(wg_transform_get_output_type), @@ -2284,6 +2287,9 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X64(wg_parser_stream_get_tag), X(wg_parser_stream_seek),
+ X(wg_source_create), + X(wg_source_destroy), + X64(wg_transform_create), X(wg_transform_destroy), X64(wg_transform_get_output_type), diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c new file mode 100644 index 00000000000..52a54196ea9 --- /dev/null +++ b/dlls/winegstreamer/wg_source.c @@ -0,0 +1,94 @@ +/* + * Copyright 2023 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> + +#include <gst/gst.h> +#include <gst/video/video.h> +#include <gst/audio/audio.h> +#include <gst/base/base.h> +#include <gst/tag/tag.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" +#include "mferror.h" + +#include "unix_private.h" + +struct wg_source +{ + GstElement *container; +}; + +static struct wg_source *get_source(wg_source_t source) +{ + return (struct wg_source *)(ULONG_PTR)source; +} + +NTSTATUS wg_source_create(void *args) +{ + struct wg_source_create_params *params = args; + struct wg_source *source; + + if (!(source = calloc(1, sizeof(*source)))) + return STATUS_UNSUCCESSFUL; + + if (!(source->container = gst_bin_new("wg_source"))) + goto error; + + gst_element_set_state(source->container, GST_STATE_PAUSED); + if (!gst_element_get_state(source->container, NULL, NULL, -1)) + goto error; + + params->source = (wg_source_t)(ULONG_PTR)source; + GST_INFO("Created winegstreamer source %p.", source); + return STATUS_SUCCESS; + +error: + if (source->container) + { + gst_element_set_state(source->container, GST_STATE_NULL); + gst_object_unref(source->container); + } + free(source); + + GST_ERROR("Failed to create winegstreamer source."); + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS wg_source_destroy(void *args) +{ + struct wg_source *source = get_source(*(wg_source_t *)args); + + GST_TRACE("source %p", source); + + gst_element_set_state(source->container, GST_STATE_NULL); + gst_object_unref(source->container); + free(source); + + return STATUS_SUCCESS; +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/media_source.c | 38 +++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 0de82d76db9..61a93ffa4ba 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -38,6 +38,8 @@ struct object_context WCHAR *url;
wg_source_t wg_source; + UINT32 buffer_size; + BYTE *buffer; };
static struct object_context *impl_from_IUnknown(IUnknown *iface) @@ -84,6 +86,7 @@ static ULONG WINAPI object_context_Release(IUnknown *iface) wg_source_destroy(context->wg_source); IMFAsyncResult_Release(context->result); IMFByteStream_Release(context->stream); + free(context->buffer); free(context->url); free(context); } @@ -99,14 +102,17 @@ static const IUnknownVtbl object_context_vtbl = };
static HRESULT object_context_create(DWORD flags, IMFByteStream *stream, const WCHAR *url, - QWORD file_size, IMFAsyncResult *result, IUnknown **out) + QWORD file_size, IMFAsyncResult *result, struct object_context **out) { + UINT buffer_size = file_size >= 128 * 1024 ? 32 * 1024 : min(file_size, 4 * 1024); WCHAR *tmp_url = url ? wcsdup(url) : NULL; struct object_context *context;
- if (!(context = calloc(1, sizeof(*context)))) + if (!(context = calloc(1, sizeof(*context))) + || !(context->buffer = malloc(buffer_size))) { free(tmp_url); + free(context); return E_OUTOFMEMORY; }
@@ -118,8 +124,9 @@ static HRESULT object_context_create(DWORD flags, IMFByteStream *stream, const W context->url = tmp_url; context->result = result; IMFAsyncResult_AddRef(context->result); + context->buffer_size = buffer_size;
- *out = &context->IUnknown_iface; + *out = context; return S_OK; }
@@ -1865,8 +1872,8 @@ static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *ifa { struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface); IMFAsyncResult *result; - IUnknown *context; - QWORD file_size; + struct object_context *context; + QWORD file_size, position; HRESULT hr; DWORD caps;
@@ -1896,13 +1903,16 @@ static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *ifa if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &result))) return hr; if (FAILED(hr = object_context_create(flags, stream, url, file_size, result, &context))) - { - IMFAsyncResult_Release(result); - return hr; - } + goto done;
- hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_IO, &handler->IMFAsyncCallback_iface, context); - IUnknown_Release(context); + if (FAILED(hr = IMFByteStream_GetCurrentPosition(stream, &position))) + WARN("Failed to get byte stream position, hr %#lx\n", hr); + else if (position != 0 && FAILED(hr = IMFByteStream_SetCurrentPosition(stream, 0))) + WARN("Failed to set byte stream position, hr %#lx\n", hr); + else if (FAILED(hr = IMFByteStream_BeginRead(context->stream, context->buffer, context->buffer_size, + &handler->IMFAsyncCallback_iface, &context->IUnknown_iface))) + WARN("Failed to queue byte stream async read, hr %#lx\n", hr); + IUnknown_Release(&context->IUnknown_iface);
if (SUCCEEDED(hr) && cancel_cookie) { @@ -1910,6 +1920,7 @@ static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *ifa IUnknown_AddRef(*cancel_cookie); }
+done: IMFAsyncResult_Release(result);
return hr; @@ -2009,12 +2020,15 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM IUnknown *object, *state = IMFAsyncResult_GetStateNoAddRef(result); struct object_context *context; struct result_entry *entry; + DWORD size = 0; HRESULT hr;
if (!state || !(context = impl_from_IUnknown(state))) return E_INVALIDARG;
- if (FAILED(hr = wg_source_create(&context->wg_source))) + if (FAILED(hr = IMFByteStream_EndRead(context->stream, result, &size))) + WARN("Failed to complete stream read, hr %#lx\n", hr); + else if (FAILED(hr = wg_source_create(&context->wg_source))) WARN("Failed to create wg_source, hr %#lx\n", hr); else if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) WARN("Failed to create media source, hr %#lx\n", hr);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 17 +++++++++++++--- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/unixlib.h | 3 +++ dlls/winegstreamer/wg_parser.c | 24 +++++++++++++++++++++- dlls/winegstreamer/wg_source.c | 33 +++++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 6 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 6380b8fb7ff..11dfbf8e0b5 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -104,7 +104,7 @@ char *wg_parser_stream_get_tag(wg_parser_stream_t stream, enum wg_parser_tag tag void wg_parser_stream_seek(wg_parser_stream_t stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags);
-HRESULT wg_source_create(wg_source_t *out); +HRESULT wg_source_create(const WCHAR *url, const void *data, uint32_t size, wg_source_t *out); void wg_source_destroy(wg_source_t source);
HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 92a44be0c96..04bff47bd5c 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -435,12 +435,22 @@ void wg_parser_stream_seek(wg_parser_stream_t stream, double rate, WINE_UNIX_CALL(unix_wg_parser_stream_seek, ¶ms); }
-HRESULT wg_source_create(wg_source_t *out) +HRESULT wg_source_create(const WCHAR *url, const void *data, uint32_t size, wg_source_t *out) { - struct wg_source_create_params params = {0}; + struct wg_source_create_params params = + { + .data = data, .size = size, + }; + char *tmp = NULL; NTSTATUS status; + UINT len; + + TRACE("url %s, data %p, size %#x\n", debugstr_w(url), data, size);
- TRACE("out %p\n", out); + if (url && (len = WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, 0, NULL, NULL))) + tmp = malloc(len); + if ((params.url = tmp)) + WideCharToMultiByte(CP_ACP, 0, url, -1, tmp, len, NULL, NULL);
if ((status = WINE_UNIX_CALL(unix_wg_source_create, ¶ms))) WARN("wg_source_create returned status %#lx\n", status); @@ -450,6 +460,7 @@ HRESULT wg_source_create(wg_source_t *out) *out = params.source; }
+ free(tmp); return HRESULT_FROM_NT(status); }
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 61a93ffa4ba..ffc7d652934 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -2028,7 +2028,7 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM
if (FAILED(hr = IMFByteStream_EndRead(context->stream, result, &size))) WARN("Failed to complete stream read, hr %#lx\n", hr); - else if (FAILED(hr = wg_source_create(&context->wg_source))) + else if (FAILED(hr = wg_source_create(context->url, context->buffer, size, &context->wg_source))) WARN("Failed to create wg_source, hr %#lx\n", hr); else if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) WARN("Failed to create media source, hr %#lx\n", hr); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 0a98aadd1ab..9eab68e14da 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -332,6 +332,9 @@ struct wg_parser_stream_seek_params
struct wg_source_create_params { + const char *url; + const void *data; + UINT32 size; wg_source_t source; };
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 51753b1f429..60dca79ef16 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2063,6 +2063,28 @@ static NTSTATUS wow64_wg_parser_stream_get_tag(void *args) return wg_parser_stream_get_tag(¶ms); }
+NTSTATUS wow64_wg_source_create(void *args) +{ + struct + { + PTR32 url; + PTR32 data; + UINT32 size; + wg_source_t source; + } *params32 = args; + struct wg_source_create_params params = + { + .url = ULongToPtr(params32->url), + .data = ULongToPtr(params32->data), + .size = params32->size, + }; + NTSTATUS ret; + + ret = wg_source_create(¶ms); + params32->source = params.source; + return ret; +} + NTSTATUS wow64_wg_transform_create(void *args) { struct @@ -2287,7 +2309,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X64(wg_parser_stream_get_tag), X(wg_parser_stream_seek),
- X(wg_source_create), + X64(wg_source_create), X(wg_source_destroy),
X64(wg_transform_create), diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 52a54196ea9..071b800b6d1 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -49,13 +49,42 @@ static struct wg_source *get_source(wg_source_t source) return (struct wg_source *)(ULONG_PTR)source; }
+static GstCaps *detect_caps_from_data(const char *url, const void *data, guint size) +{ + const char *extension = url ? strrchr(url, '.') : NULL; + GstTypeFindProbability probability; + GstCaps *caps; + + GST_LOG("url %s, data %p, size %#x", url, data, size); + + if (!(caps = gst_type_find_helper_for_data_with_extension(NULL, data, size, + extension ? extension + 1 : NULL, &probability))) + { + GST_ERROR("Failed to detect caps for url %s", url); + return NULL; + } + + if (probability > GST_TYPE_FIND_POSSIBLE) + GST_INFO("Got probability %u for caps %" GST_PTR_FORMAT, probability, caps); + else + GST_FIXME("Got probability %u for caps %" GST_PTR_FORMAT, probability, caps); + + return caps; +} + NTSTATUS wg_source_create(void *args) { struct wg_source_create_params *params = args; struct wg_source *source; + GstCaps *src_caps;
+ if (!(src_caps = detect_caps_from_data(params->url, params->data, params->size))) + return STATUS_UNSUCCESSFUL; if (!(source = calloc(1, sizeof(*source)))) + { + gst_caps_unref(src_caps); return STATUS_UNSUCCESSFUL; + }
if (!(source->container = gst_bin_new("wg_source"))) goto error; @@ -64,6 +93,8 @@ NTSTATUS wg_source_create(void *args) if (!gst_element_get_state(source->container, NULL, NULL, -1)) goto error;
+ gst_caps_unref(src_caps); + params->source = (wg_source_t)(ULONG_PTR)source; GST_INFO("Created winegstreamer source %p.", source); return STATUS_SUCCESS; @@ -76,6 +107,8 @@ error: } free(source);
+ gst_caps_unref(src_caps); + GST_ERROR("Failed to create winegstreamer source."); return STATUS_UNSUCCESSFUL; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/media_source.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ffc7d652934..7688631f7bf 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -101,11 +101,31 @@ static const IUnknownVtbl object_context_vtbl = object_context_Release, };
+static WCHAR *byte_stream_get_url(IMFByteStream *stream, const WCHAR *url) +{ + IMFAttributes *attributes; + WCHAR buffer[MAX_PATH]; + UINT32 size; + HRESULT hr; + + if (SUCCEEDED(hr = IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes))) + { + if (FAILED(hr = IMFAttributes_GetString(attributes, &MF_BYTESTREAM_ORIGIN_NAME, + buffer, ARRAY_SIZE(buffer), &size))) + WARN("Failed to get MF_BYTESTREAM_ORIGIN_NAME got size %#x, hr %#lx\n", size, hr); + else + url = buffer; + IMFAttributes_Release(attributes); + } + + return url ? wcsdup(url) : NULL; +} + static HRESULT object_context_create(DWORD flags, IMFByteStream *stream, const WCHAR *url, QWORD file_size, IMFAsyncResult *result, struct object_context **out) { UINT buffer_size = file_size >= 128 * 1024 ? 32 * 1024 : min(file_size, 4 * 1024); - WCHAR *tmp_url = url ? wcsdup(url) : NULL; + WCHAR *tmp_url = byte_stream_get_url(stream, url); struct object_context *context;
if (!(context = calloc(1, sizeof(*context)))
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/wg_source.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 071b800b6d1..2bb3ba0c396 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -41,6 +41,7 @@
struct wg_source { + GstPad *src_pad; GstElement *container; };
@@ -72,6 +73,24 @@ static GstCaps *detect_caps_from_data(const char *url, const void *data, guint s return caps; }
+static GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) +{ + GstCaps *pad_caps = caps ? gst_caps_ref(caps) : gst_caps_new_any(); + const char *name = direction == GST_PAD_SRC ? "src" : "sink"; + GstPadTemplate *template; + GstPad *pad = NULL; + + if (!pad_caps) + return NULL; + if ((template = gst_pad_template_new(name, direction, GST_PAD_ALWAYS, pad_caps))) + { + pad = gst_pad_new_from_template(template, "src"); + g_object_unref(template); + } + gst_caps_unref(pad_caps); + return pad; +} + NTSTATUS wg_source_create(void *args) { struct wg_source_create_params *params = args; @@ -88,6 +107,9 @@ NTSTATUS wg_source_create(void *args)
if (!(source->container = gst_bin_new("wg_source"))) goto error; + if (!(source->src_pad = create_pad_with_caps(GST_PAD_SRC, src_caps))) + goto error; + gst_pad_set_element_private(source->src_pad, source);
gst_element_set_state(source->container, GST_STATE_PAUSED); if (!gst_element_get_state(source->container, NULL, NULL, -1)) @@ -105,6 +127,8 @@ error: gst_element_set_state(source->container, GST_STATE_NULL); gst_object_unref(source->container); } + if (source->src_pad) + gst_object_unref(source->src_pad); free(source);
gst_caps_unref(src_caps); @@ -121,6 +145,7 @@ NTSTATUS wg_source_destroy(void *args)
gst_element_set_state(source->container, GST_STATE_NULL); gst_object_unref(source->container); + gst_object_unref(source->src_pad); free(source);
return STATUS_SUCCESS;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/wg_source.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 2bb3ba0c396..0731c6f156d 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -94,6 +94,7 @@ static GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) NTSTATUS wg_source_create(void *args) { struct wg_source_create_params *params = args; + GstElement *first = NULL, *last = NULL, *element; struct wg_source *source; GstCaps *src_caps;
@@ -111,6 +112,15 @@ NTSTATUS wg_source_create(void *args) goto error; gst_pad_set_element_private(source->src_pad, source);
+ if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODABLE, src_caps, GST_CAPS_ANY)) + || !append_element(source->container, element, &first, &last)) + goto error; + + if (!link_src_to_element(source->src_pad, first)) + goto error; + if (!gst_pad_set_active(source->src_pad, true)) + goto error; + gst_element_set_state(source->container, GST_STATE_PAUSED); if (!gst_element_get_state(source->container, NULL, NULL, -1)) goto error;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 15 ++++++++++ dlls/winegstreamer/media_source.c | 3 ++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 9 ++++++ dlls/winegstreamer/wg_parser.c | 22 ++++++++++++++ dlls/winegstreamer/wg_source.c | 48 +++++++++++++++++++++++++++++++ 7 files changed, 99 insertions(+)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 11dfbf8e0b5..527fdf47b07 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -106,6 +106,7 @@ void wg_parser_stream_seek(wg_parser_stream_t stream, double rate,
HRESULT wg_source_create(const WCHAR *url, const void *data, uint32_t size, wg_source_t *out); void wg_source_destroy(wg_source_t source); +HRESULT wg_source_push_data(wg_source_t source, UINT64 offset, const void *data, uint32_t size);
HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, const struct wg_transform_attrs *attrs, wg_transform_t *transform); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 04bff47bd5c..7caf1fb0782 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -471,6 +471,21 @@ void wg_source_destroy(wg_source_t source) WINE_UNIX_CALL(unix_wg_source_destroy, &source); }
+HRESULT wg_source_push_data(wg_source_t source, UINT64 offset, const void *data, uint32_t size) +{ + struct wg_source_push_data_params params = + { + .source = source, + .offset = offset, + .data = data, + .size = size, + }; + + TRACE("source %#I64x, offset %#I64x, data %p, size %#x\n", source, offset, data, size); + + return HRESULT_FROM_NT(WINE_UNIX_CALL(unix_wg_source_push_data, ¶ms)); +} + HRESULT wg_transform_create_mf(IMFMediaType *input_type, IMFMediaType *output_type, const struct wg_transform_attrs *attrs, wg_transform_t *transform) { diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 7688631f7bf..0cb83437b61 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -38,6 +38,7 @@ struct object_context WCHAR *url;
wg_source_t wg_source; + UINT64 read_offset; UINT32 buffer_size; BYTE *buffer; }; @@ -2050,6 +2051,8 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM WARN("Failed to complete stream read, hr %#lx\n", hr); else if (FAILED(hr = wg_source_create(context->url, context->buffer, size, &context->wg_source))) WARN("Failed to create wg_source, hr %#lx\n", hr); + else if (FAILED(hr = wg_source_push_data(context->wg_source, context->read_offset, context->buffer, size))) + WARN("Failed to push wg_source data, hr %#lx\n", hr); else if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) WARN("Failed to create media source, hr %#lx\n", hr); else diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 52412a283ab..7ae74c13a8c 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -72,6 +72,7 @@ extern NTSTATUS wg_transform_notify_qos(void *args);
extern NTSTATUS wg_source_create(void *args); extern NTSTATUS wg_source_destroy(void *args); +extern NTSTATUS wg_source_push_data(void *args);
/* wg_media_type.c */
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 9eab68e14da..a70ecf9cd25 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -338,6 +338,14 @@ struct wg_source_create_params wg_source_t source; };
+struct wg_source_push_data_params +{ + wg_source_t source; + UINT64 offset; + UINT64 size; + const void *data; +}; + struct wg_transform_attrs { UINT32 output_plane_align; @@ -455,6 +463,7 @@ enum unix_funcs
unix_wg_source_create, unix_wg_source_destroy, + unix_wg_source_push_data,
unix_wg_transform_create, unix_wg_transform_destroy, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 60dca79ef16..d2292087544 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1889,6 +1889,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_source_create), X(wg_source_destroy), + X(wg_source_push_data),
X(wg_transform_create), X(wg_transform_destroy), @@ -2085,6 +2086,26 @@ NTSTATUS wow64_wg_source_create(void *args) return ret; }
+NTSTATUS wow64_wg_source_push_data(void *args) +{ + struct + { + wg_source_t source; + UINT64 offset; + UINT64 size; + PTR32 data; + } *params32 = args; + struct wg_source_push_data_params params = + { + .source = params32->source, + .offset = params32->offset, + .size = params32->size, + .data = ULongToPtr(params32->data), + }; + + return wg_source_push_data(¶ms); +} + NTSTATUS wow64_wg_transform_create(void *args) { struct @@ -2311,6 +2332,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
X64(wg_source_create), X(wg_source_destroy), + X64(wg_source_push_data),
X64(wg_transform_create), X(wg_transform_destroy), diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 0731c6f156d..4e11adcd878 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -43,6 +43,7 @@ struct wg_source { GstPad *src_pad; GstElement *container; + GstSegment segment; };
static struct wg_source *get_source(wg_source_t source) @@ -73,6 +74,21 @@ static GstCaps *detect_caps_from_data(const char *url, const void *data, guint s return caps; }
+static GstEvent *create_stream_start_event(const char *stream_id) +{ + GstEvent *event; + + if ((event = gst_event_new_stream_start(stream_id))) + { + GstStream *stream = gst_stream_new(stream_id, NULL, GST_STREAM_TYPE_UNKNOWN, 0); + gst_event_set_stream(event, stream); + gst_event_set_group_id(event, 1); + gst_object_unref(stream); + } + + return event; +} + static GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) { GstCaps *pad_caps = caps ? gst_caps_ref(caps) : gst_caps_new_any(); @@ -105,6 +121,7 @@ NTSTATUS wg_source_create(void *args) gst_caps_unref(src_caps); return STATUS_UNSUCCESSFUL; } + gst_segment_init(&source->segment, GST_FORMAT_BYTES);
if (!(source->container = gst_bin_new("wg_source"))) goto error; @@ -125,6 +142,11 @@ NTSTATUS wg_source_create(void *args) if (!gst_element_get_state(source->container, NULL, NULL, -1)) goto error;
+ if (!push_event(source->src_pad, create_stream_start_event("wg_source"))) + goto error; + if (!push_event(source->src_pad, gst_event_new_segment(&source->segment))) + goto error; + gst_caps_unref(src_caps);
params->source = (wg_source_t)(ULONG_PTR)source; @@ -160,3 +182,29 @@ NTSTATUS wg_source_destroy(void *args)
return STATUS_SUCCESS; } + +NTSTATUS wg_source_push_data(void *args) +{ + struct wg_source_push_data_params *params = args; + struct wg_source *source = get_source(params->source); + + GST_TRACE("source %p, offset %#" G_GINT64_MODIFIER "x, size %#" G_GINT64_MODIFIER "x, data %p", + source, params->offset, params->size, params->data); + + if (!params->size) + { + push_event(source->src_pad, gst_event_new_eos()); + return STATUS_SUCCESS; + } + + if (params->offset > source->segment.start) + source->segment.start = params->offset; + else if (params->offset < source->segment.start) + { + source->segment.start = params->offset; + push_event(source->src_pad, gst_event_new_segment(&source->segment)); + } + + source->segment.start += params->size; + return STATUS_SUCCESS; +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/wg_source.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 4e11adcd878..77c40179314 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -41,6 +41,7 @@
struct wg_source { + gchar *url; GstPad *src_pad; GstElement *container; GstSegment segment; @@ -107,6 +108,34 @@ static GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) return pad; }
+static gboolean src_query_uri(struct wg_source *source, GstQuery *query) +{ + gchar *uri; + + GST_LOG("source %p, query %" GST_PTR_FORMAT, source, query); + + gst_query_parse_uri(query, &uri); + gst_query_set_uri(query, source->url); + + return true; +} + +static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) +{ + struct wg_source *source = gst_pad_get_element_private(pad); + + switch (GST_QUERY_TYPE(query)) + { + case GST_QUERY_URI: + if (!source->url) + return false; + return src_query_uri(source, query); + default: + GST_TRACE("source %p, ignoring %" GST_PTR_FORMAT, source, query); + return gst_pad_query_default(pad, parent, query); + } +} + NTSTATUS wg_source_create(void *args) { struct wg_source_create_params *params = args; @@ -121,6 +150,7 @@ NTSTATUS wg_source_create(void *args) gst_caps_unref(src_caps); return STATUS_UNSUCCESSFUL; } + source->url = params->url ? strdup(params->url) : NULL; gst_segment_init(&source->segment, GST_FORMAT_BYTES);
if (!(source->container = gst_bin_new("wg_source"))) @@ -128,6 +158,7 @@ NTSTATUS wg_source_create(void *args) if (!(source->src_pad = create_pad_with_caps(GST_PAD_SRC, src_caps))) goto error; gst_pad_set_element_private(source->src_pad, source); + gst_pad_set_query_function(source->src_pad, src_query_cb);
if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODABLE, src_caps, GST_CAPS_ANY)) || !append_element(source->container, element, &first, &last)) @@ -161,6 +192,7 @@ error: } if (source->src_pad) gst_object_unref(source->src_pad); + free(source->url); free(source);
gst_caps_unref(src_caps); @@ -178,6 +210,7 @@ NTSTATUS wg_source_destroy(void *args) gst_element_set_state(source->container, GST_STATE_NULL); gst_object_unref(source->container); gst_object_unref(source->src_pad); + free(source->url); free(source);
return STATUS_SUCCESS;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 3 ++- dlls/winegstreamer/main.c | 7 +++++-- dlls/winegstreamer/media_source.c | 3 ++- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_source.c | 17 +++++++++++++++++ 5 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 527fdf47b07..cf46768122f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -104,7 +104,8 @@ char *wg_parser_stream_get_tag(wg_parser_stream_t stream, enum wg_parser_tag tag void wg_parser_stream_seek(wg_parser_stream_t stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags);
-HRESULT wg_source_create(const WCHAR *url, const void *data, uint32_t size, wg_source_t *out); +HRESULT wg_source_create(const WCHAR *url, uint64_t file_size, + const void *data, uint32_t size, wg_source_t *out); void wg_source_destroy(wg_source_t source); HRESULT wg_source_push_data(wg_source_t source, UINT64 offset, const void *data, uint32_t size);
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 7caf1fb0782..038ddf3e045 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -435,17 +435,20 @@ void wg_parser_stream_seek(wg_parser_stream_t stream, double rate, WINE_UNIX_CALL(unix_wg_parser_stream_seek, ¶ms); }
-HRESULT wg_source_create(const WCHAR *url, const void *data, uint32_t size, wg_source_t *out) +HRESULT wg_source_create(const WCHAR *url, uint64_t file_size, + const void *data, uint32_t size, wg_source_t *out) { struct wg_source_create_params params = { + .file_size = file_size, .data = data, .size = size, }; char *tmp = NULL; NTSTATUS status; UINT len;
- TRACE("url %s, data %p, size %#x\n", debugstr_w(url), data, size); + TRACE("url %s, file_size %#I64x, data %p, size %#x\n", debugstr_w(url), + file_size, data, size);
if (url && (len = WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, 0, NULL, NULL))) tmp = malloc(len); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 0cb83437b61..3393ff33dd5 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -2049,7 +2049,8 @@ static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IM
if (FAILED(hr = IMFByteStream_EndRead(context->stream, result, &size))) WARN("Failed to complete stream read, hr %#lx\n", hr); - else if (FAILED(hr = wg_source_create(context->url, context->buffer, size, &context->wg_source))) + else if (FAILED(hr = wg_source_create(context->url, context->file_size, + context->buffer, size, &context->wg_source))) WARN("Failed to create wg_source, hr %#lx\n", hr); else if (FAILED(hr = wg_source_push_data(context->wg_source, context->read_offset, context->buffer, size))) WARN("Failed to push wg_source data, hr %#lx\n", hr); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index a70ecf9cd25..f7ed2fafd54 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -333,6 +333,7 @@ struct wg_parser_stream_seek_params struct wg_source_create_params { const char *url; + UINT64 file_size; const void *data; UINT32 size; wg_source_t source; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 77c40179314..e1a907db3e6 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -108,6 +108,20 @@ static GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) return pad; }
+static gboolean src_query_duration(struct wg_source *source, GstQuery *query) +{ + GstFormat format; + + GST_LOG("source %p, query %" GST_PTR_FORMAT, source, query); + + gst_query_parse_duration(query, &format, NULL); + if (format != GST_FORMAT_BYTES) + return false; + + gst_query_set_duration(query, format, source->segment.stop); + return true; +} + static gboolean src_query_uri(struct wg_source *source, GstQuery *query) { gchar *uri; @@ -126,6 +140,8 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query)
switch (GST_QUERY_TYPE(query)) { + case GST_QUERY_DURATION: + return src_query_duration(source, query); case GST_QUERY_URI: if (!source->url) return false; @@ -152,6 +168,7 @@ NTSTATUS wg_source_create(void *args) } source->url = params->url ? strdup(params->url) : NULL; gst_segment_init(&source->segment, GST_FORMAT_BYTES); + source->segment.stop = params->file_size;
if (!(source->container = gst_bin_new("wg_source"))) goto error;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/wg_source.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index e1a907db3e6..ca73eba5cc0 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -122,6 +122,16 @@ static gboolean src_query_duration(struct wg_source *source, GstQuery *query) return true; }
+static gboolean src_query_scheduling(struct wg_source *source, GstQuery *query) +{ + GST_LOG("source %p, query %" GST_PTR_FORMAT, source, query); + + gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); + gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); + + return true; +} + static gboolean src_query_uri(struct wg_source *source, GstQuery *query) { gchar *uri; @@ -142,6 +152,8 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) { case GST_QUERY_DURATION: return src_query_duration(source, query); + case GST_QUERY_SCHEDULING: + return src_query_scheduling(source, query); case GST_QUERY_URI: if (!source->url) return false;
Does this fix any known application that 5988 does not?
Also:
* In an attempt to simplify the code, this removes the ability to output uncompressed samples—which spans about 70 self-contained lines of code in pad_added()—and replaces it with a whole separate transform per frontend. Why is this an improvement?
* This removes pull-mode support, which breaks seeking or playback in many demuxers, including demuxers for formats that Windows natively supports.
* Since the plan is to both push and read data from the same thread, how do we make sure we've pushed enough data (to get a sample) without pushing too much (such that pushing blocks due to overflow)?
The answer I've been given is "we always assume that the GStreamer demuxer acts synchronously". This is not guaranteed and may easily be broken by future library changes. The same assumption has already been broken in the transform.
Simplicity cannot come at the cost of removing vital code.
* Setting aside the above: removing pull mode is done with the express goal of removing the PE-side read thread.
However, removing the read thread can be done without removing support for pull mode, simply by calling wg_parser_get_next_read_offset() from the same thread before pushing.
Does this fix any known application that 5988 does not?
Unreal Engine games like [1] (sack boy) for example that have a race condition triggered by a slow media source initialisation.
[1]: https://www.codeweavers.com/support/bugs/browse/?cmd=bug_edit;bug_id=22038#c...
On Mon Jul 8 12:06:34 2024 +0000, Derek Lesho wrote:
Does this fix any known application that 5988 does not?
Unreal Engine games like [1] (sack boy) for example that have a race condition triggered by a slow media source initialisation. [1]: https://www.codeweavers.com/support/bugs/browse/?cmd=bug_edit;bug_id=22038#c...
So, first of all, thanks for giving the name of a specific application.
I'm not sure which is the offending video, but I tested a couple that looked like they were relevant, and with 5988 they both resolve in 0.9-1.1 ms. That's about on the level of the measurement for Rémi's proposal given in 3606, and faster than the "0-3ms" given for Windows.
As was projected, most of the time overhead in media source resolution is related to autoplugging decoders. I don't think any other source of resolution speed was ever mentioned or even hypothesized, and these results seem to suggest that simply stopping at compressed video *is* enough.
On Tue Jul 9 01:15:16 2024 +0000, Elizabeth Figura wrote:
So, first of all, thanks for giving the name of a specific application. I'm not sure which is the offending video, but I tested a couple that looked like they were relevant, and with 5988 they both resolve in 0.9-1.1 ms. That's about on the level of the measurement for Rémi's proposal given in 3606, and faster than the "0-3ms" given for Windows. As was projected, most of the time overhead in media source resolution is related to autoplugging decoders. I don't think any other source of resolution speed was ever mentioned or even hypothesized, and these results seem to suggest that simply stopping at compressed video *is* enough.
Oh cool, I wasn't aware that MR also speeds up init times so drastically. Yeah in that case it shouldn't be a problem 👍
In an attempt to simplify the code, this removes the ability to output uncompressed samples—which spans about 70 self-contained lines of code in pad_added()—and replaces it with a whole separate transform per frontend. Why is this an improvement?
It is an improvement because it is how native behaves. The feature is not going to be used by any application and therefore unnecessary.
This removes pull-mode support, which breaks seeking or playback in many demuxers, including demuxers for formats that Windows natively supports.
You've mentioned sfdec and musepack before, these aren't supported by Media Foundation.
Setting aside the above: removing pull mode is done with the express goal of removing the PE-side read thread.
However, removing the read thread can be done without removing support for pull mode, simply by calling wg_parser_get_next_read_offset() from the same thread before pushing.
Decoupling MF from the other frontends makes other things easier to change. Removing the PE-side thread isn't really the goal, making the demuxer calls synchronous is.
There's several other reasons to do this, which I've written about in length elsewhere and which I'm not going over again.
Since the plan is to both push and read data from the same thread, how do we make sure we've pushed enough data (to get a sample) without pushing too much (such that pushing blocks due to overflow)?
The answer I've been given is "we always assume that the GStreamer demuxer acts synchronously". This is not guaranteed and may easily be broken by future library changes. The same assumption has already been broken in the transform.
Simplicity cannot come at the cost of removing vital code.
The assumption made for the transform still holds. Requiring multiple threads to parse a file is even more silly, and it makes our work toward Windows compatibility harder.
If it ever breaks, we should probably take that opportunity to reconsider the choice of GStreamer as a backend. Maybe I should even start doing that instead of arguing in vain.
In an attempt to simplify the code, this removes the ability to output uncompressed samples—which spans about 70 self-contained lines of code in pad_added()—and replaces it with a whole separate transform per frontend. Why is this an improvement?
It is an improvement because it is how native behaves.
Simply outputting the result of parsebin, with opaque formats, isn't how native behaves either.
The feature is not going to be used by any application and therefore unnecessary.
As shown in 5988, mfplat does not need to use this feature. quartz still does, and wmvcore does too.
Perhaps we should get rid of that in quartz and wmvcore. I would argue that 70 lines of self-contained code is worth it to allow people to play oggs in their Windows media players, but if matching Windows exactly trumps all else, then sure.
Either way, it doesn't justify rewriting and replacing the entirety of wg_parser. If we want to do this, we should just delete the !output_compressed case from the existing wg_parser. That is far, far simpler than any other patch to achieve the same goal.
This removes pull-mode support, which breaks seeking or playback in many demuxers, including demuxers for formats that Windows natively supports.
You've mentioned sfdec and musepack before, these aren't supported by Media Foundation.
Yes. The demuxers I'm referring to are midiparse and avdemux.
Setting aside the above: removing pull mode is done with the express goal of removing the PE-side read thread.
However, removing the read thread can be done without removing support for pull mode, simply by calling wg_parser_get_next_read_offset() from the same thread before pushing.
Decoupling MF from the other frontends makes other things easier to change.
I'm not just concerned about how things are being changed, but also about the end goal here.
Removing the PE-side thread isn't really the goal, making the demuxer calls synchronous is.
What's the point of making the demuxer synchronous as an end goal, if not to remove the extra PE thread?
There's several other reasons to do this, which I've written about in length elsewhere and which I'm not going over again.
I've provided responses to all of those reasons. I haven't heard a compelling reason that we need to make the demuxer synchronous.
Since the plan is to both push and read data from the same thread, how do we make sure we've pushed enough data (to get a sample) without pushing too much (such that pushing blocks due to overflow)?
The answer I've been given is "we always assume that the GStreamer demuxer acts synchronously". This is not guaranteed and may easily be broken by future library changes. The same assumption has already been broken in the transform.
Simplicity cannot come at the cost of removing vital code.
The assumption made for the transform still holds.
Only after disabling a specific GStreamer element that violated it.
Requiring multiple threads to parse a file is even more silly, and it makes our work toward Windows compatibility harder.
It's only a hard requirement because of Wine's unusual architecture.
It's also quite reasonable, actually, because it allows the demuxer to buffer at the same time as individual streams are processing their data.
Also, using a separate thread to read from is *exactly* how DirectShow *and* Media Foundation work, for this very reason. So as long as we're talking about Windows compatibility, this patch series actually makes it worse.
If it ever breaks, we should probably take that opportunity to reconsider the choice of GStreamer as a backend. Maybe I should even start doing that instead of arguing in vain.
If we need a more convenient API, let's talk to GStreamer about creating one. They're really quite amenable to catering to new users.
Does this merge request fix any known application that 5988 does not?
This merge request was closed by Rémi Bernon.