Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 137 +------------------------ dlls/winegstreamer/unixlib.h | 165 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 17 +++- 3 files changed, 179 insertions(+), 140 deletions(-) create mode 100644 dlls/winegstreamer/unixlib.h
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 3470f7870fa..91c646571cf 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -36,6 +36,8 @@ #include "wine/debug.h" #include "wine/strmbase.h"
+#include "unixlib.h" + static inline const char *debugstr_time(REFERENCE_TIME time) { ULONGLONG abstime = time >= 0 ? time : -time; @@ -59,141 +61,6 @@ static inline const char *debugstr_time(REFERENCE_TIME time)
#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000)
-struct wg_format -{ - enum wg_major_type - { - WG_MAJOR_TYPE_UNKNOWN, - WG_MAJOR_TYPE_VIDEO, - WG_MAJOR_TYPE_AUDIO, - } major_type; - - union - { - struct - { - enum wg_video_format - { - WG_VIDEO_FORMAT_UNKNOWN, - - WG_VIDEO_FORMAT_BGRA, - WG_VIDEO_FORMAT_BGRx, - WG_VIDEO_FORMAT_BGR, - WG_VIDEO_FORMAT_RGB15, - WG_VIDEO_FORMAT_RGB16, - - WG_VIDEO_FORMAT_AYUV, - WG_VIDEO_FORMAT_I420, - WG_VIDEO_FORMAT_NV12, - WG_VIDEO_FORMAT_UYVY, - WG_VIDEO_FORMAT_YUY2, - WG_VIDEO_FORMAT_YV12, - WG_VIDEO_FORMAT_YVYU, - - WG_VIDEO_FORMAT_CINEPAK, - } format; - uint32_t width, height; - uint32_t fps_n, fps_d; - } video; - struct - { - enum wg_audio_format - { - WG_AUDIO_FORMAT_UNKNOWN, - - WG_AUDIO_FORMAT_U8, - WG_AUDIO_FORMAT_S16LE, - WG_AUDIO_FORMAT_S24LE, - WG_AUDIO_FORMAT_S32LE, - WG_AUDIO_FORMAT_F32LE, - WG_AUDIO_FORMAT_F64LE, - - WG_AUDIO_FORMAT_MPEG1_LAYER1, - WG_AUDIO_FORMAT_MPEG1_LAYER2, - WG_AUDIO_FORMAT_MPEG1_LAYER3, - } format; - - uint32_t channels; - uint32_t channel_mask; /* In WinMM format. */ - uint32_t rate; - } audio; - } u; -}; - -enum wg_parser_event_type -{ - WG_PARSER_EVENT_NONE = 0, - WG_PARSER_EVENT_BUFFER, - WG_PARSER_EVENT_EOS, - WG_PARSER_EVENT_SEGMENT, -}; - -struct wg_parser_event -{ - enum wg_parser_event_type type; - union - { - struct - { - /* pts and duration are in 100-nanosecond units. */ - ULONGLONG pts, duration; - uint32_t size; - bool discontinuity, preroll, delta, has_pts, has_duration; - } buffer; - struct - { - ULONGLONG position, stop; - DOUBLE rate; - } segment; - } u; -}; -C_ASSERT(sizeof(struct wg_parser_event) == 40); - -enum wg_parser_type -{ - WG_PARSER_DECODEBIN, - WG_PARSER_AVIDEMUX, - WG_PARSER_MPEGAUDIOPARSE, - WG_PARSER_WAVPARSE, -}; - -struct unix_funcs -{ - struct wg_parser *(CDECL *wg_parser_create)(enum wg_parser_type type, bool unlimited_buffering); - void (CDECL *wg_parser_destroy)(struct wg_parser *parser); - - HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size); - void (CDECL *wg_parser_disconnect)(struct wg_parser *parser); - - void (CDECL *wg_parser_begin_flush)(struct wg_parser *parser); - void (CDECL *wg_parser_end_flush)(struct wg_parser *parser); - - bool (CDECL *wg_parser_get_next_read_offset)(struct wg_parser *parser, - uint64_t *offset, uint32_t *size); - void (CDECL *wg_parser_push_data)(struct wg_parser *parser, - const void *data, uint32_t size); - - uint32_t (CDECL *wg_parser_get_stream_count)(struct wg_parser *parser); - struct wg_parser_stream *(CDECL *wg_parser_get_stream)(struct wg_parser *parser, uint32_t index); - - void (CDECL *wg_parser_stream_get_preferred_format)(struct wg_parser_stream *stream, struct wg_format *format); - void (CDECL *wg_parser_stream_enable)(struct wg_parser_stream *stream, const struct wg_format *format); - void (CDECL *wg_parser_stream_disable)(struct wg_parser_stream *stream); - - bool (CDECL *wg_parser_stream_get_event)(struct wg_parser_stream *stream, struct wg_parser_event *event); - bool (CDECL *wg_parser_stream_copy_buffer)(struct wg_parser_stream *stream, - void *data, uint32_t offset, uint32_t size); - void (CDECL *wg_parser_stream_release_buffer)(struct wg_parser_stream *stream); - void (CDECL *wg_parser_stream_notify_qos)(struct wg_parser_stream *stream, - bool underflow, double proportion, int64_t diff, uint64_t timestamp); - - /* Returns the duration in 100-nanosecond units. */ - uint64_t (CDECL *wg_parser_stream_get_duration)(struct wg_parser_stream *stream); - /* start_pos and stop_pos are in 100-nanosecond units. */ - bool (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); -}; - extern const struct unix_funcs *unix_funcs;
HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h new file mode 100644 index 00000000000..e917f7b5557 --- /dev/null +++ b/dlls/winegstreamer/unixlib.h @@ -0,0 +1,165 @@ +/* + * winegstreamer Unix library interface + * + * Copyright 2020-2021 Zebediah Figura 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 + */ + +#ifndef __WINE_WINEGSTREAMER_UNIXLIB_H +#define __WINE_WINEGSTREAMER_UNIXLIB_H + +#include <stdbool.h> +#include <stdint.h> +#include "windef.h" +#include "wtypes.h" +#include "mmreg.h" + +struct wg_format +{ + enum wg_major_type + { + WG_MAJOR_TYPE_UNKNOWN, + WG_MAJOR_TYPE_VIDEO, + WG_MAJOR_TYPE_AUDIO, + } major_type; + + union + { + struct + { + enum wg_video_format + { + WG_VIDEO_FORMAT_UNKNOWN, + + WG_VIDEO_FORMAT_BGRA, + WG_VIDEO_FORMAT_BGRx, + WG_VIDEO_FORMAT_BGR, + WG_VIDEO_FORMAT_RGB15, + WG_VIDEO_FORMAT_RGB16, + + WG_VIDEO_FORMAT_AYUV, + WG_VIDEO_FORMAT_I420, + WG_VIDEO_FORMAT_NV12, + WG_VIDEO_FORMAT_UYVY, + WG_VIDEO_FORMAT_YUY2, + WG_VIDEO_FORMAT_YV12, + WG_VIDEO_FORMAT_YVYU, + + WG_VIDEO_FORMAT_CINEPAK, + } format; + uint32_t width, height; + uint32_t fps_n, fps_d; + } video; + struct + { + enum wg_audio_format + { + WG_AUDIO_FORMAT_UNKNOWN, + + WG_AUDIO_FORMAT_U8, + WG_AUDIO_FORMAT_S16LE, + WG_AUDIO_FORMAT_S24LE, + WG_AUDIO_FORMAT_S32LE, + WG_AUDIO_FORMAT_F32LE, + WG_AUDIO_FORMAT_F64LE, + + WG_AUDIO_FORMAT_MPEG1_LAYER1, + WG_AUDIO_FORMAT_MPEG1_LAYER2, + WG_AUDIO_FORMAT_MPEG1_LAYER3, + } format; + + uint32_t channels; + uint32_t channel_mask; /* In WinMM format. */ + uint32_t rate; + } audio; + } u; +}; + +enum wg_parser_event_type +{ + WG_PARSER_EVENT_NONE = 0, + WG_PARSER_EVENT_BUFFER, + WG_PARSER_EVENT_EOS, + WG_PARSER_EVENT_SEGMENT, +}; + +struct wg_parser_event +{ + enum wg_parser_event_type type; + union + { + struct + { + /* pts and duration are in 100-nanosecond units. */ + ULONGLONG pts, duration; + uint32_t size; + bool discontinuity, preroll, delta, has_pts, has_duration; + } buffer; + struct + { + ULONGLONG position, stop; + DOUBLE rate; + } segment; + } u; +}; +C_ASSERT(sizeof(struct wg_parser_event) == 40); + +enum wg_parser_type +{ + WG_PARSER_DECODEBIN, + WG_PARSER_AVIDEMUX, + WG_PARSER_MPEGAUDIOPARSE, + WG_PARSER_WAVPARSE, +}; + +struct unix_funcs +{ + struct wg_parser *(CDECL *wg_parser_create)(enum wg_parser_type type, bool unlimited_buffering); + void (CDECL *wg_parser_destroy)(struct wg_parser *parser); + + HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size); + void (CDECL *wg_parser_disconnect)(struct wg_parser *parser); + + void (CDECL *wg_parser_begin_flush)(struct wg_parser *parser); + void (CDECL *wg_parser_end_flush)(struct wg_parser *parser); + + bool (CDECL *wg_parser_get_next_read_offset)(struct wg_parser *parser, + uint64_t *offset, uint32_t *size); + void (CDECL *wg_parser_push_data)(struct wg_parser *parser, + const void *data, uint32_t size); + + uint32_t (CDECL *wg_parser_get_stream_count)(struct wg_parser *parser); + struct wg_parser_stream *(CDECL *wg_parser_get_stream)(struct wg_parser *parser, uint32_t index); + + void (CDECL *wg_parser_stream_get_preferred_format)(struct wg_parser_stream *stream, struct wg_format *format); + void (CDECL *wg_parser_stream_enable)(struct wg_parser_stream *stream, const struct wg_format *format); + void (CDECL *wg_parser_stream_disable)(struct wg_parser_stream *stream); + + bool (CDECL *wg_parser_stream_get_event)(struct wg_parser_stream *stream, struct wg_parser_event *event); + bool (CDECL *wg_parser_stream_copy_buffer)(struct wg_parser_stream *stream, + void *data, uint32_t offset, uint32_t size); + void (CDECL *wg_parser_stream_release_buffer)(struct wg_parser_stream *stream); + void (CDECL *wg_parser_stream_notify_qos)(struct wg_parser_stream *stream, + bool underflow, double proportion, int64_t diff, uint64_t timestamp); + + /* Returns the duration in 100-nanosecond units. */ + uint64_t (CDECL *wg_parser_stream_get_duration)(struct wg_parser_stream *stream); + /* start_pos and stop_pos are in 100-nanosecond units. */ + bool (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); +}; + +#endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 21278682318..b89a50b5d8f 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -25,15 +25,22 @@ #endif
#include "config.h" -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "gst_private.h" -#include "winternl.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 "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" +#include "dshow.h" + +#include "unixlib.h" + typedef enum { GST_AUTOPLUG_SELECT_TRY, @@ -1859,7 +1866,7 @@ static void init_gstreamer_once(void)
if (!gst_init_check(&argc, &argv, &err)) { - fprintf(stderr, "winegstreamer: failed to initialize GStreamer: %s\n", debugstr_a(err->message)); + fprintf(stderr, "winegstreamer: failed to initialize GStreamer: %s\n", err->message); g_error_free(err); return; }
We do not expect this to fail.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/quartz_parser.c | 12 +++--------- dlls/winegstreamer/unixlib.h | 2 +- dlls/winegstreamer/wg_parser.c | 7 ++++--- 3 files changed, 8 insertions(+), 13 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index a1fa7daec6f..5dd232ea0da 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1233,7 +1233,6 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface, { struct parser_source *pin = impl_from_IMediaSeeking(iface); struct parser *filter = impl_from_strmbase_filter(pin->pin.pin.filter); - HRESULT hr = S_OK; int i;
TRACE("pin %p, current %s, current_flags %#x, stop %s, stop_flags %#x.\n", @@ -1270,13 +1269,8 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface,
SourceSeekingImpl_SetPositions(iface, current, current_flags, stop, stop_flags);
- if (!unix_funcs->wg_parser_stream_seek(pin->wg_stream, pin->seek.dRate, - pin->seek.llCurrent, pin->seek.llStop, current_flags, stop_flags)) - { - ERR("Failed to seek (current %s, stop %s).\n", - debugstr_time(pin->seek.llCurrent), debugstr_time(pin->seek.llStop)); - hr = E_FAIL; - } + unix_funcs->wg_parser_stream_seek(pin->wg_stream, pin->seek.dRate, + pin->seek.llCurrent, pin->seek.llStop, current_flags, stop_flags);
if (!(current_flags & AM_SEEKING_NoFlush)) { @@ -1299,7 +1293,7 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface, LeaveCriticalSection(&pin->flushing_cs); }
- return hr; + return S_OK; }
static const IMediaSeekingVtbl GST_Seeking_Vtbl = diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index e917f7b5557..dade020916a 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -158,7 +158,7 @@ struct unix_funcs /* Returns the duration in 100-nanosecond units. */ uint64_t (CDECL *wg_parser_stream_get_duration)(struct wg_parser_stream *stream); /* start_pos and stop_pos are in 100-nanosecond units. */ - bool (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, + void (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); };
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b89a50b5d8f..694f8b57ed1 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -686,7 +686,7 @@ static uint64_t CDECL wg_parser_stream_get_duration(struct wg_parser_stream *str return stream->duration; }
-static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, +static void CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) { GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET; @@ -704,8 +704,9 @@ static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double if ((stop_flags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning) stop_type = GST_SEEK_TYPE_NONE;
- return gst_pad_push_event(stream->my_sink, gst_event_new_seek(rate, - GST_FORMAT_TIME, flags, start_type, start_pos * 100, stop_type, stop_pos * 100)); + if (!gst_pad_push_event(stream->my_sink, gst_event_new_seek(rate, GST_FORMAT_TIME, + flags, start_type, start_pos * 100, stop_type, stop_pos * 100))) + GST_ERROR("Failed to seek.\n"); }
static void CDECL wg_parser_stream_notify_qos(struct wg_parser_stream *stream,
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 32 ++++- dlls/winegstreamer/main.c | 197 ++++++++++++++++++++++++++- dlls/winegstreamer/media_source.c | 44 +++--- dlls/winegstreamer/quartz_parser.c | 72 +++++----- dlls/winegstreamer/unixlib.h | 139 +++++++++++++++---- dlls/winegstreamer/wg_parser.c | 210 ++++++++++++++++++----------- 7 files changed, 528 insertions(+), 167 deletions(-)
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 13e61abee36..e35df3cf3f9 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -1,4 +1,5 @@ MODULE = winegstreamer.dll +UNIXLIB = winegstreamer.so IMPORTS = strmbase strmiids uuid ole32 mfuuid DELAYIMPORTS = mfplat EXTRAINCL = $(GSTREAMER_CFLAGS) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 91c646571cf..ebe0bf6f50d 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -61,7 +61,37 @@ static inline const char *debugstr_time(REFERENCE_TIME time)
#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000)
-extern const struct unix_funcs *unix_funcs; +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) DECLSPEC_HIDDEN; +void wg_parser_destroy(struct wg_parser *parser) DECLSPEC_HIDDEN; + +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) DECLSPEC_HIDDEN; +void wg_parser_disconnect(struct wg_parser *parser) DECLSPEC_HIDDEN; + +void wg_parser_begin_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; +void wg_parser_end_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; + +bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size) DECLSPEC_HIDDEN; +void wg_parser_push_data(struct wg_parser *parser, const void *data, uint32_t size) DECLSPEC_HIDDEN; + +uint32_t wg_parser_get_stream_count(struct wg_parser *parser) DECLSPEC_HIDDEN; +struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index) DECLSPEC_HIDDEN; + +void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) DECLSPEC_HIDDEN; +void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) DECLSPEC_HIDDEN; +void wg_parser_stream_disable(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; + +bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event) DECLSPEC_HIDDEN; +bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, + void *data, uint32_t offset, uint32_t size) DECLSPEC_HIDDEN; +void wg_parser_stream_release_buffer(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; +void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, + bool underflow, double proportion, int64_t diff, uint64_t timestamp) DECLSPEC_HIDDEN; + +/* Returns the duration in 100-nanosecond units. */ +uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; +/* start_pos and stop_pos are in 100-nanosecond units. */ +void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) DECLSPEC_HIDDEN;
HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 6742724948e..c799aa06d1b 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -27,16 +27,209 @@ #include "initguid.h" #include "gst_guids.h"
+static unixlib_handle_t unix_handle; + WINE_DEFAULT_DEBUG_CHANNEL(quartz);
-const struct unix_funcs *unix_funcs = NULL; +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) +{ + struct wg_parser_create_params params = + { + .type = type, + .unlimited_buffering = unlimited_buffering, + }; + + if (__wine_unix_call(unix_handle, unix_wg_parser_create, ¶ms)) + return NULL; + return params.parser; +} + +void wg_parser_destroy(struct wg_parser *parser) +{ + __wine_unix_call(unix_handle, unix_wg_parser_destroy, parser); +} + +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) +{ + struct wg_parser_connect_params params = + { + .parser = parser, + .file_size = file_size, + }; + + return __wine_unix_call(unix_handle, unix_wg_parser_connect, ¶ms); +} + +void wg_parser_disconnect(struct wg_parser *parser) +{ + __wine_unix_call(unix_handle, unix_wg_parser_disconnect, parser); +} + +void wg_parser_begin_flush(struct wg_parser *parser) +{ + __wine_unix_call(unix_handle, unix_wg_parser_begin_flush, parser); +} + +void wg_parser_end_flush(struct wg_parser *parser) +{ + __wine_unix_call(unix_handle, unix_wg_parser_end_flush, parser); +} + +bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size) +{ + struct wg_parser_get_next_read_offset_params params = + { + .parser = parser, + }; + + if (__wine_unix_call(unix_handle, unix_wg_parser_get_next_read_offset, ¶ms)) + return false; + *offset = params.offset; + *size = params.size; + return true; +} + +void wg_parser_push_data(struct wg_parser *parser, const void *data, uint32_t size) +{ + struct wg_parser_push_data_params params = + { + .parser = parser, + .data = data, + .size = size, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_push_data, ¶ms); +} + +uint32_t wg_parser_get_stream_count(struct wg_parser *parser) +{ + struct wg_parser_get_stream_count_params params = + { + .parser = parser, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_get_stream_count, ¶ms); + return params.count; +} + +struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index) +{ + struct wg_parser_get_stream_params params = + { + .parser = parser, + .index = index, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_get_stream, ¶ms); + return params.stream; +} + +void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) +{ + struct wg_parser_stream_get_preferred_format_params params = + { + .stream = stream, + .format = format, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_stream_get_preferred_format, ¶ms); +} + +void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) +{ + struct wg_parser_stream_enable_params params = + { + .stream = stream, + .format = format, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_stream_enable, ¶ms); +} + +void wg_parser_stream_disable(struct wg_parser_stream *stream) +{ + __wine_unix_call(unix_handle, unix_wg_parser_stream_disable, stream); +} + +bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event) +{ + struct wg_parser_stream_get_event_params params = + { + .stream = stream, + .event = event, + }; + + return !__wine_unix_call(unix_handle, unix_wg_parser_stream_get_event, ¶ms); +} + +bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, + void *data, uint32_t offset, uint32_t size) +{ + struct wg_parser_stream_copy_buffer_params params = + { + .stream = stream, + .data = data, + .offset = offset, + .size = size, + }; + + return !__wine_unix_call(unix_handle, unix_wg_parser_stream_copy_buffer, ¶ms); +} + +void wg_parser_stream_release_buffer(struct wg_parser_stream *stream) +{ + __wine_unix_call(unix_handle, unix_wg_parser_stream_release_buffer, stream); +} + +void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, + bool underflow, double proportion, int64_t diff, uint64_t timestamp) +{ + struct wg_parser_stream_notify_qos_params params = + { + .stream = stream, + .underflow = underflow, + .proportion = proportion, + .diff = diff, + .timestamp = timestamp, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_stream_notify_qos, ¶ms); +} + +uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) +{ + struct wg_parser_stream_get_duration_params params = + { + .stream = stream, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_stream_get_duration, ¶ms); + return params.duration; +} + +void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, + uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) +{ + struct wg_parser_stream_seek_params params = + { + .stream = stream, + .rate = rate, + .start_pos = start_pos, + .stop_pos = stop_pos, + .start_flags = start_flags, + .stop_flags = stop_flags, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); +}
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(instance); - __wine_init_unix_lib(instance, reason, NULL, &unix_funcs); + NtQueryVirtualMemory(GetCurrentProcess(), instance, MemoryWineUnixFuncs, + &unix_handle, sizeof(unix_handle), NULL); } return TRUE; } diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 18bffca1362..da898f20f66 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -357,7 +357,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt);
mf_media_type_to_wg_format(current_mt, &format); - unix_funcs->wg_parser_stream_enable(stream->wg_stream, &format); + wg_parser_stream_enable(stream->wg_stream, &format);
IMFMediaType_Release(current_mt); IMFMediaTypeHandler_Release(mth); @@ -385,9 +385,9 @@ static void start_pipeline(struct media_source *source, struct source_async_comm source->state = SOURCE_RUNNING;
if (position->vt == VT_I8) - unix_funcs->wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, - position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); - unix_funcs->wg_parser_end_flush(source->wg_parser); + wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, position->hVal.QuadPart, 0, + AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); + wg_parser_end_flush(source->wg_parser);
for (i = 0; i < source->stream_count; i++) flush_token_queue(source->streams[i], position->vt == VT_EMPTY); @@ -415,7 +415,7 @@ static void stop_pipeline(struct media_source *source) { unsigned int i;
- unix_funcs->wg_parser_begin_flush(source->wg_parser); + wg_parser_begin_flush(source->wg_parser);
for (i = 0; i < source->stream_count; i++) { @@ -423,7 +423,7 @@ static void stop_pipeline(struct media_source *source) if (stream->state != STREAM_INACTIVE) { IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL); - unix_funcs->wg_parser_stream_disable(stream->wg_stream); + wg_parser_stream_disable(stream->wg_stream); } }
@@ -490,13 +490,13 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_even goto out; }
- if (!unix_funcs->wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, event->u.buffer.size)) + if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, event->u.buffer.size)) { - unix_funcs->wg_parser_stream_release_buffer(stream->wg_stream); + wg_parser_stream_release_buffer(stream->wg_stream); IMFMediaBuffer_Unlock(buffer); goto out; } - unix_funcs->wg_parser_stream_release_buffer(stream->wg_stream); + wg_parser_stream_release_buffer(stream->wg_stream);
if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) { @@ -536,7 +536,7 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token)
for (;;) { - if (!unix_funcs->wg_parser_stream_get_event(stream->wg_stream, &event)) + if (!wg_parser_stream_get_event(stream->wg_stream, &event)) return;
TRACE("Got event of type %#x.\n", event.type); @@ -628,7 +628,7 @@ static DWORD CALLBACK read_thread(void *arg) uint32_t size; HRESULT hr;
- if (!unix_funcs->wg_parser_get_next_read_offset(source->wg_parser, &offset, &size)) + if (!wg_parser_get_next_read_offset(source->wg_parser, &offset, &size)) continue;
if (offset >= file_size) @@ -650,7 +650,7 @@ static DWORD CALLBACK read_thread(void *arg) ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); else if (ret_size != size) ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); - unix_funcs->wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); + wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); }
free(data); @@ -867,7 +867,7 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) unsigned int i; HRESULT hr;
- unix_funcs->wg_parser_stream_get_preferred_format(stream->wg_stream, &format); + wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
if (format.major_type == WG_MAJOR_TYPE_VIDEO) { @@ -1327,7 +1327,7 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
source->state = SOURCE_SHUTDOWN;
- unix_funcs->wg_parser_disconnect(source->wg_parser); + wg_parser_disconnect(source->wg_parser);
source->read_thread_shutdown = true; WaitForSingleObject(source->read_thread, INFINITE); @@ -1350,7 +1350,7 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) IMFMediaStream_Release(&stream->IMFMediaStream_iface); }
- unix_funcs->wg_parser_destroy(source->wg_parser); + wg_parser_destroy(source->wg_parser);
free(source->streams);
@@ -1427,7 +1427,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ * never deselects it). Remove buffering limits from decodebin in order to * account for this. Note that this does leak memory, but the same memory * leak occurs with native. */ - if (!(parser = unix_funcs->wg_parser_create(WG_PARSER_DECODEBIN, true))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) { hr = E_OUTOFMEMORY; goto fail; @@ -1438,10 +1438,10 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
object->state = SOURCE_OPENING;
- if (FAILED(hr = unix_funcs->wg_parser_connect(parser, file_size))) + if (FAILED(hr = wg_parser_connect(parser, file_size))) goto fail;
- stream_count = unix_funcs->wg_parser_get_stream_count(parser); + stream_count = wg_parser_get_stream_count(parser);
if (!(object->streams = calloc(stream_count, sizeof(*object->streams)))) { @@ -1451,7 +1451,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
for (i = 0; i < stream_count; ++i) { - if (FAILED(hr = new_media_stream(object, unix_funcs->wg_parser_get_stream(parser, i), i, &object->streams[i]))) + if (FAILED(hr = new_media_stream(object, wg_parser_get_stream(parser, i), i, &object->streams[i]))) goto fail;
if (FAILED(hr = media_stream_init_desc(object->streams[i]))) @@ -1487,7 +1487,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
for (i = 0; i < object->stream_count; i++) total_pres_time = max(total_pres_time, - unix_funcs->wg_parser_stream_get_duration(object->streams[i]->wg_stream)); + wg_parser_stream_get_duration(object->streams[i]->wg_stream));
if (object->stream_count) IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time); @@ -1518,7 +1518,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ } free(object->streams); if (stream_count != UINT_MAX) - unix_funcs->wg_parser_disconnect(object->wg_parser); + wg_parser_disconnect(object->wg_parser); if (object->read_thread) { object->read_thread_shutdown = true; @@ -1526,7 +1526,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ CloseHandle(object->read_thread); } if (object->wg_parser) - unix_funcs->wg_parser_destroy(object->wg_parser); + wg_parser_destroy(object->wg_parser); if (object->async_commands_queue) MFUnlockWorkQueue(object->async_commands_queue); if (object->event_queue) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 5dd232ea0da..6ae1a99a14a 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -623,7 +623,7 @@ static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample,
IMediaSample_GetPointer(sample, &ptr);
- if (!unix_funcs->wg_parser_stream_copy_buffer(pin->wg_stream, ptr, offset, size)) + if (!wg_parser_stream_copy_buffer(pin->wg_stream, ptr, offset, size)) { /* The GStreamer pin has been flushed. */ return S_OK; @@ -732,7 +732,7 @@ static void send_buffer(struct parser_source *pin, const struct wg_parser_event } }
- unix_funcs->wg_parser_stream_release_buffer(pin->wg_stream); + wg_parser_stream_release_buffer(pin->wg_stream); }
static DWORD CALLBACK stream_thread(void *arg) @@ -748,7 +748,7 @@ static DWORD CALLBACK stream_thread(void *arg)
EnterCriticalSection(&pin->flushing_cs);
- if (!unix_funcs->wg_parser_stream_get_event(pin->wg_stream, &event)) + if (!wg_parser_stream_get_event(pin->wg_stream, &event)) { LeaveCriticalSection(&pin->flushing_cs); continue; @@ -799,7 +799,7 @@ static DWORD CALLBACK read_thread(void *arg) uint32_t size; HRESULT hr;
- if (!unix_funcs->wg_parser_get_next_read_offset(filter->wg_parser, &offset, &size)) + if (!wg_parser_get_next_read_offset(filter->wg_parser, &offset, &size)) continue;
if (offset >= file_size) @@ -817,7 +817,7 @@ static DWORD CALLBACK read_thread(void *arg) if (FAILED(hr)) ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr);
- unix_funcs->wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? data : NULL, size); + wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? data : NULL, size); }
free(data); @@ -869,7 +869,7 @@ static void parser_destroy(struct strmbase_filter *iface) IAsyncReader_Release(filter->reader); filter->reader = NULL;
- unix_funcs->wg_parser_destroy(filter->wg_parser); + wg_parser_destroy(filter->wg_parser);
strmbase_sink_cleanup(&filter->sink); strmbase_filter_cleanup(&filter->filter); @@ -887,7 +887,7 @@ static HRESULT parser_init_stream(struct strmbase_filter *iface) return S_OK;
filter->streaming = true; - unix_funcs->wg_parser_end_flush(filter->wg_parser); + wg_parser_end_flush(filter->wg_parser);
/* DirectShow retains the old seek positions, but resets to them every time * it transitions from stopped -> paused. */ @@ -895,7 +895,7 @@ static HRESULT parser_init_stream(struct strmbase_filter *iface) seeking = &filter->sources[0]->seek; if (seeking->llStop) stop_flags = AM_SEEKING_AbsolutePositioning; - unix_funcs->wg_parser_stream_seek(filter->sources[0]->wg_stream, seeking->dRate, + wg_parser_stream_seek(filter->sources[0]->wg_stream, seeking->dRate, seeking->llCurrent, seeking->llStop, AM_SEEKING_AbsolutePositioning, stop_flags);
for (i = 0; i < filter->source_count; ++i) @@ -923,7 +923,7 @@ static HRESULT parser_cleanup_stream(struct strmbase_filter *iface) return S_OK;
filter->streaming = false; - unix_funcs->wg_parser_begin_flush(filter->wg_parser); + wg_parser_begin_flush(filter->wg_parser);
for (i = 0; i < filter->source_count; ++i) { @@ -978,7 +978,7 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons filter->sink_connected = true; filter->read_thread = CreateThread(NULL, 0, read_thread, filter, 0, NULL);
- if (FAILED(hr = unix_funcs->wg_parser_connect(filter->wg_parser, file_size))) + if (FAILED(hr = wg_parser_connect(filter->wg_parser, file_size))) goto err;
if (!filter->init_gst(filter)) @@ -991,7 +991,7 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons { struct parser_source *pin = filter->sources[i];
- pin->seek.llDuration = pin->seek.llStop = unix_funcs->wg_parser_stream_get_duration(pin->wg_stream); + pin->seek.llDuration = pin->seek.llStop = wg_parser_stream_get_duration(pin->wg_stream); pin->seek.llCurrent = 0; }
@@ -1026,11 +1026,11 @@ static BOOL decodebin_parser_filter_init_gst(struct parser *filter) unsigned int i, stream_count; WCHAR source_name[20];
- stream_count = unix_funcs->wg_parser_get_stream_count(parser); + stream_count = wg_parser_get_stream_count(parser); for (i = 0; i < stream_count; ++i) { swprintf(source_name, ARRAY_SIZE(source_name), L"Stream %02u", i); - if (!create_pin(filter, unix_funcs->wg_parser_get_stream(parser, i), source_name)) + if (!create_pin(filter, wg_parser_get_stream(parser, i), source_name)) return FALSE; }
@@ -1069,7 +1069,7 @@ static HRESULT decodebin_parser_source_get_media_type(struct parser_source *pin, WG_VIDEO_FORMAT_RGB15, };
- unix_funcs->wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_preferred_format(pin->wg_stream, &format);
memset(mt, 0, sizeof(AM_MEDIA_TYPE));
@@ -1115,7 +1115,7 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
- if (!(object->wg_parser = unix_funcs->wg_parser_create(WG_PARSER_DECODEBIN, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) { free(object); return E_OUTOFMEMORY; @@ -1205,7 +1205,7 @@ static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface) { struct parser_source *pin = impl_from_IMediaSeeking(iface);
- unix_funcs->wg_parser_stream_seek(pin->wg_stream, pin->seek.dRate, 0, 0, + wg_parser_stream_seek(pin->wg_stream, pin->seek.dRate, 0, 0, AM_SEEKING_NoPositioning, AM_SEEKING_NoPositioning); return S_OK; } @@ -1247,7 +1247,7 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface,
if (!(current_flags & AM_SEEKING_NoFlush)) { - unix_funcs->wg_parser_begin_flush(filter->wg_parser); + wg_parser_begin_flush(filter->wg_parser);
for (i = 0; i < filter->source_count; ++i) { @@ -1269,12 +1269,12 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface,
SourceSeekingImpl_SetPositions(iface, current, current_flags, stop, stop_flags);
- unix_funcs->wg_parser_stream_seek(pin->wg_stream, pin->seek.dRate, + wg_parser_stream_seek(pin->wg_stream, pin->seek.dRate, pin->seek.llCurrent, pin->seek.llStop, current_flags, stop_flags);
if (!(current_flags & AM_SEEKING_NoFlush)) { - unix_funcs->wg_parser_end_flush(filter->wg_parser); + wg_parser_end_flush(filter->wg_parser);
for (i = 0; i < filter->source_count; ++i) { @@ -1383,7 +1383,7 @@ static HRESULT WINAPI GST_QualityControl_Notify(IQualityControl *iface, IBaseFil /* GST_QOS_TYPE_OVERFLOW is also used for buffers that arrive on time, but * DirectShow filters might use Famine, so check that there actually is an * underrun. */ - unix_funcs->wg_parser_stream_notify_qos(pin->wg_stream, q.Type == Famine && q.Proportion < 1000, + wg_parser_stream_notify_qos(pin->wg_stream, q.Type == Famine && q.Proportion < 1000, 1000.0 / q.Proportion, diff, timestamp);
return S_OK; @@ -1463,7 +1463,7 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface,
ret = amt_to_wg_format(&pin->pin.pin.mt, &format); assert(ret); - unix_funcs->wg_parser_stream_enable(pin->wg_stream, &format); + wg_parser_stream_enable(pin->wg_stream, &format);
/* We do need to drop any buffers that might have been sent with the old * caps, but this will be handled in parser_init_stream(). */ @@ -1478,7 +1478,7 @@ static void source_disconnect(struct strmbase_source *iface) { struct parser_source *pin = impl_source_from_IPin(&iface->pin.IPin_iface);
- unix_funcs->wg_parser_stream_disable(pin->wg_stream); + wg_parser_stream_disable(pin->wg_stream); }
static void free_source_pin(struct parser_source *pin) @@ -1544,7 +1544,7 @@ static HRESULT GST_RemoveOutputPins(struct parser *This) if (!This->sink_connected) return S_OK;
- unix_funcs->wg_parser_disconnect(This->wg_parser); + wg_parser_disconnect(This->wg_parser);
/* read_thread() needs to stay alive to service any read requests GStreamer * sends, so we can only shut it down after GStreamer stops. */ @@ -1597,7 +1597,7 @@ static BOOL wave_parser_filter_init_gst(struct parser *filter) { struct wg_parser *parser = filter->wg_parser;
- if (!create_pin(filter, unix_funcs->wg_parser_get_stream(parser, 0), L"output")) + if (!create_pin(filter, wg_parser_get_stream(parser, 0), L"output")) return FALSE;
return TRUE; @@ -1609,7 +1609,7 @@ static HRESULT wave_parser_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE pad_mt; HRESULT hr;
- unix_funcs->wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_preferred_format(pin->wg_stream, &format); if (!amt_from_wg_format(&pad_mt, &format)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; @@ -1624,7 +1624,7 @@ static HRESULT wave_parser_source_get_media_type(struct parser_source *pin,
if (index > 0) return VFW_S_NO_MORE_ITEMS; - unix_funcs->wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_preferred_format(pin->wg_stream, &format); if (!amt_from_wg_format(mt, &format)) return E_OUTOFMEMORY; return S_OK; @@ -1640,7 +1640,7 @@ HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
- if (!(object->wg_parser = unix_funcs->wg_parser_create(WG_PARSER_WAVPARSE, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_WAVPARSE, false))) { free(object); return E_OUTOFMEMORY; @@ -1678,11 +1678,11 @@ static BOOL avi_splitter_filter_init_gst(struct parser *filter) uint32_t i, stream_count; WCHAR source_name[20];
- stream_count = unix_funcs->wg_parser_get_stream_count(parser); + stream_count = wg_parser_get_stream_count(parser); for (i = 0; i < stream_count; ++i) { swprintf(source_name, ARRAY_SIZE(source_name), L"Stream %02u", i); - if (!create_pin(filter, unix_funcs->wg_parser_get_stream(parser, i), source_name)) + if (!create_pin(filter, wg_parser_get_stream(parser, i), source_name)) return FALSE; }
@@ -1695,7 +1695,7 @@ static HRESULT avi_splitter_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE pad_mt; HRESULT hr;
- unix_funcs->wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_preferred_format(pin->wg_stream, &format); if (!amt_from_wg_format(&pad_mt, &format)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; @@ -1710,7 +1710,7 @@ static HRESULT avi_splitter_source_get_media_type(struct parser_source *pin,
if (index > 0) return VFW_S_NO_MORE_ITEMS; - unix_funcs->wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_preferred_format(pin->wg_stream, &format); if (!amt_from_wg_format(mt, &format)) return E_OUTOFMEMORY; return S_OK; @@ -1726,7 +1726,7 @@ HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
- if (!(object->wg_parser = unix_funcs->wg_parser_create(WG_PARSER_AVIDEMUX, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_AVIDEMUX, false))) { free(object); return E_OUTOFMEMORY; @@ -1767,7 +1767,7 @@ static BOOL mpeg_splitter_filter_init_gst(struct parser *filter) { struct wg_parser *parser = filter->wg_parser;
- if (!create_pin(filter, unix_funcs->wg_parser_get_stream(parser, 0), L"Audio")) + if (!create_pin(filter, wg_parser_get_stream(parser, 0), L"Audio")) return FALSE;
return TRUE; @@ -1779,7 +1779,7 @@ static HRESULT mpeg_splitter_source_query_accept(struct parser_source *pin, cons AM_MEDIA_TYPE pad_mt; HRESULT hr;
- unix_funcs->wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_preferred_format(pin->wg_stream, &format); if (!amt_from_wg_format(&pad_mt, &format)) return E_OUTOFMEMORY; hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE; @@ -1794,7 +1794,7 @@ static HRESULT mpeg_splitter_source_get_media_type(struct parser_source *pin,
if (index > 0) return VFW_S_NO_MORE_ITEMS; - unix_funcs->wg_parser_stream_get_preferred_format(pin->wg_stream, &format); + wg_parser_stream_get_preferred_format(pin->wg_stream, &format); if (!amt_from_wg_format(mt, &format)) return E_OUTOFMEMORY; return S_OK; @@ -1833,7 +1833,7 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
- if (!(object->wg_parser = unix_funcs->wg_parser_create(WG_PARSER_MPEGAUDIOPARSE, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_MPEGAUDIOPARSE, false))) { free(object); return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index dade020916a..90101893541 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -24,9 +24,12 @@ #include <stdbool.h> #include <stdint.h> #include "windef.h" +#include "winternl.h" #include "wtypes.h" #include "mmreg.h"
+#include "wine/unixlib.h" + struct wg_format { enum wg_major_type @@ -125,41 +128,123 @@ enum wg_parser_type WG_PARSER_WAVPARSE, };
-struct unix_funcs +struct wg_parser_create_params { - struct wg_parser *(CDECL *wg_parser_create)(enum wg_parser_type type, bool unlimited_buffering); - void (CDECL *wg_parser_destroy)(struct wg_parser *parser); + struct wg_parser *parser; + enum wg_parser_type type; + bool unlimited_buffering; +};
- HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size); - void (CDECL *wg_parser_disconnect)(struct wg_parser *parser); +struct wg_parser_connect_params +{ + struct wg_parser *parser; + UINT64 file_size; +};
- void (CDECL *wg_parser_begin_flush)(struct wg_parser *parser); - void (CDECL *wg_parser_end_flush)(struct wg_parser *parser); +struct wg_parser_get_next_read_offset_params +{ + struct wg_parser *parser; + UINT32 size; + UINT64 offset; +};
- bool (CDECL *wg_parser_get_next_read_offset)(struct wg_parser *parser, - uint64_t *offset, uint32_t *size); - void (CDECL *wg_parser_push_data)(struct wg_parser *parser, - const void *data, uint32_t size); +struct wg_parser_push_data_params +{ + struct wg_parser *parser; + const void *data; + UINT32 size; +};
- uint32_t (CDECL *wg_parser_get_stream_count)(struct wg_parser *parser); - struct wg_parser_stream *(CDECL *wg_parser_get_stream)(struct wg_parser *parser, uint32_t index); +struct wg_parser_get_stream_count_params +{ + struct wg_parser *parser; + UINT32 count; +};
- void (CDECL *wg_parser_stream_get_preferred_format)(struct wg_parser_stream *stream, struct wg_format *format); - void (CDECL *wg_parser_stream_enable)(struct wg_parser_stream *stream, const struct wg_format *format); - void (CDECL *wg_parser_stream_disable)(struct wg_parser_stream *stream); +struct wg_parser_get_stream_params +{ + struct wg_parser *parser; + UINT32 index; + struct wg_parser_stream *stream; +};
- bool (CDECL *wg_parser_stream_get_event)(struct wg_parser_stream *stream, struct wg_parser_event *event); - bool (CDECL *wg_parser_stream_copy_buffer)(struct wg_parser_stream *stream, - void *data, uint32_t offset, uint32_t size); - void (CDECL *wg_parser_stream_release_buffer)(struct wg_parser_stream *stream); - void (CDECL *wg_parser_stream_notify_qos)(struct wg_parser_stream *stream, - bool underflow, double proportion, int64_t diff, uint64_t timestamp); +struct wg_parser_stream_get_preferred_format_params +{ + struct wg_parser_stream *stream; + struct wg_format *format; +};
- /* Returns the duration in 100-nanosecond units. */ - uint64_t (CDECL *wg_parser_stream_get_duration)(struct wg_parser_stream *stream); - /* start_pos and stop_pos are in 100-nanosecond units. */ - void (CDECL *wg_parser_stream_seek)(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); +struct wg_parser_stream_enable_params +{ + struct wg_parser_stream *stream; + const struct wg_format *format; +}; + +struct wg_parser_stream_get_event_params +{ + struct wg_parser_stream *stream; + struct wg_parser_event *event; +}; + +struct wg_parser_stream_copy_buffer_params +{ + struct wg_parser_stream *stream; + void *data; + UINT32 offset; + UINT32 size; +}; + +struct wg_parser_stream_notify_qos_params +{ + struct wg_parser_stream *stream; + bool underflow; + DOUBLE proportion; + INT64 diff; + UINT64 timestamp; +}; + +struct wg_parser_stream_get_duration_params +{ + struct wg_parser_stream *stream; + UINT64 duration; +}; + +struct wg_parser_stream_seek_params +{ + struct wg_parser_stream *stream; + DOUBLE rate; + UINT64 start_pos, stop_pos; + DWORD start_flags, stop_flags; +}; + +enum unix_funcs +{ + unix_wg_parser_create, + unix_wg_parser_destroy, + + unix_wg_parser_connect, + unix_wg_parser_disconnect, + + unix_wg_parser_begin_flush, + unix_wg_parser_end_flush, + + unix_wg_parser_get_next_read_offset, + unix_wg_parser_push_data, + + unix_wg_parser_get_stream_count, + unix_wg_parser_get_stream, + + unix_wg_parser_stream_get_preferred_format, + unix_wg_parser_stream_enable, + unix_wg_parser_stream_disable, + + unix_wg_parser_stream_get_event, + unix_wg_parser_stream_copy_buffer, + unix_wg_parser_stream_release_buffer, + unix_wg_parser_stream_notify_qos, + + unix_wg_parser_stream_get_duration, + unix_wg_parser_stream_seek, };
#endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 694f8b57ed1..72dfab8f3d6 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -34,8 +34,6 @@ #include <gst/video/video.h> #include <gst/audio/audio.h>
-#include "ntstatus.h" -#define WIN32_NO_STATUS #include "winternl.h" #include "dshow.h"
@@ -503,18 +501,25 @@ static bool wg_format_compare(const struct wg_format *a, const struct wg_format return false; }
-static uint32_t CDECL wg_parser_get_stream_count(struct wg_parser *parser) +static NTSTATUS wg_parser_get_stream_count(void *args) { - return parser->stream_count; + struct wg_parser_get_stream_count_params *params = args; + + params->count = params->parser->stream_count; + return S_OK; }
-static struct wg_parser_stream * CDECL wg_parser_get_stream(struct wg_parser *parser, uint32_t index) +static NTSTATUS wg_parser_get_stream(void *args) { - return parser->streams[index]; + struct wg_parser_get_stream_params *params = args; + + params->stream = params->parser->streams[params->index]; + return S_OK; }
-static void CDECL wg_parser_begin_flush(struct wg_parser *parser) +static NTSTATUS wg_parser_begin_flush(void *args) { + struct wg_parser *parser = args; unsigned int i;
pthread_mutex_lock(&parser->mutex); @@ -526,18 +531,26 @@ static void CDECL wg_parser_begin_flush(struct wg_parser *parser) if (parser->streams[i]->enabled) pthread_cond_signal(&parser->streams[i]->event_cond); } + + return S_OK; }
-static void CDECL wg_parser_end_flush(struct wg_parser *parser) +static NTSTATUS wg_parser_end_flush(void *args) { + struct wg_parser *parser = args; + pthread_mutex_lock(&parser->mutex); parser->flushing = false; pthread_mutex_unlock(&parser->mutex); + + return S_OK; }
-static bool CDECL wg_parser_get_next_read_offset(struct wg_parser *parser, - uint64_t *offset, uint32_t *size) +static NTSTATUS wg_parser_get_next_read_offset(void *args) { + struct wg_parser_get_next_read_offset_params *params = args; + struct wg_parser *parser = params->parser; + pthread_mutex_lock(&parser->mutex);
while (parser->sink_connected && !parser->read_request.data) @@ -546,19 +559,23 @@ static bool CDECL wg_parser_get_next_read_offset(struct wg_parser *parser, if (!parser->sink_connected) { pthread_mutex_unlock(&parser->mutex); - return false; + return VFW_E_WRONG_STATE; }
- *offset = parser->read_request.offset; - *size = parser->read_request.size; + params->offset = parser->read_request.offset; + params->size = parser->read_request.size;
pthread_mutex_unlock(&parser->mutex); - return true; + return S_OK; }
-static void CDECL wg_parser_push_data(struct wg_parser *parser, - const void *data, uint32_t size) +static NTSTATUS wg_parser_push_data(void *args) { + const struct wg_parser_push_data_params *params = args; + struct wg_parser *parser = params->parser; + const void *data = params->data; + uint32_t size = params->size; + pthread_mutex_lock(&parser->mutex); parser->read_request.size = size; parser->read_request.done = true; @@ -568,15 +585,24 @@ static void CDECL wg_parser_push_data(struct wg_parser *parser, parser->read_request.data = NULL; pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&parser->read_done_cond); + + return S_OK; }
-static void CDECL wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) +static NTSTATUS wg_parser_stream_get_preferred_format(void *args) { - *format = stream->preferred_format; + const struct wg_parser_stream_get_preferred_format_params *params = args; + + *params->format = params->stream->preferred_format; + return S_OK; }
-static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) +static NTSTATUS wg_parser_stream_enable(void *args) { + const struct wg_parser_stream_enable_params *params = args; + struct wg_parser_stream *stream = params->stream; + const struct wg_format *format = params->format; + stream->current_format = *format; stream->enabled = true;
@@ -607,15 +633,21 @@ static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const }
gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure()); + return S_OK; }
-static void CDECL wg_parser_stream_disable(struct wg_parser_stream *stream) +static NTSTATUS wg_parser_stream_disable(void *args) { + struct wg_parser_stream *stream = args; + stream->enabled = false; + return S_OK; }
-static bool CDECL wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event) +static NTSTATUS wg_parser_stream_get_event(void *args) { + const struct wg_parser_stream_get_event_params *params = args; + struct wg_parser_stream *stream = params->stream; struct wg_parser *parser = stream->parser;
pthread_mutex_lock(&parser->mutex); @@ -627,10 +659,10 @@ static bool CDECL wg_parser_stream_get_event(struct wg_parser_stream *stream, st { pthread_mutex_unlock(&parser->mutex); GST_DEBUG("Filter is flushing.\n"); - return false; + return VFW_E_WRONG_STATE; }
- *event = stream->event; + *params->event = stream->event;
if (stream->event.type != WG_PARSER_EVENT_BUFFER) { @@ -639,33 +671,37 @@ static bool CDECL wg_parser_stream_get_event(struct wg_parser_stream *stream, st } pthread_mutex_unlock(&parser->mutex);
- return true; + return S_OK; }
-static bool CDECL wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, - void *data, uint32_t offset, uint32_t size) +static NTSTATUS wg_parser_stream_copy_buffer(void *args) { + const struct wg_parser_stream_copy_buffer_params *params = args; + struct wg_parser_stream *stream = params->stream; struct wg_parser *parser = stream->parser; + uint32_t offset = params->offset; + uint32_t size = params->size;
pthread_mutex_lock(&parser->mutex);
if (!stream->buffer) { pthread_mutex_unlock(&parser->mutex); - return false; + return VFW_E_WRONG_STATE; }
assert(stream->event.type == WG_PARSER_EVENT_BUFFER); assert(offset < stream->map_info.size); assert(offset + size <= stream->map_info.size); - memcpy(data, stream->map_info.data + offset, size); + memcpy(params->data, stream->map_info.data + offset, size);
pthread_mutex_unlock(&parser->mutex); - return true; + return S_OK; }
-static void CDECL wg_parser_stream_release_buffer(struct wg_parser_stream *stream) +static NTSTATUS wg_parser_stream_release_buffer(void *args) { + struct wg_parser_stream *stream = args; struct wg_parser *parser = stream->parser;
pthread_mutex_lock(&parser->mutex); @@ -679,17 +715,24 @@ static void CDECL wg_parser_stream_release_buffer(struct wg_parser_stream *strea
pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&stream->event_empty_cond); + + return S_OK; }
-static uint64_t CDECL wg_parser_stream_get_duration(struct wg_parser_stream *stream) +static NTSTATUS wg_parser_stream_get_duration(void *args) { - return stream->duration; + struct wg_parser_stream_get_duration_params *params = args; + + params->duration = params->stream->duration; + return S_OK; }
-static void CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) +static NTSTATUS wg_parser_stream_seek(void *args) { GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET; + const struct wg_parser_stream_seek_params *params = args; + DWORD start_flags = params->start_flags; + DWORD stop_flags = params->stop_flags; GstSeekFlags flags = 0;
if (start_flags & AM_SEEKING_SeekToKeyFrame) @@ -704,34 +747,39 @@ static void CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double if ((stop_flags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning) stop_type = GST_SEEK_TYPE_NONE;
- if (!gst_pad_push_event(stream->my_sink, gst_event_new_seek(rate, GST_FORMAT_TIME, - flags, start_type, start_pos * 100, stop_type, stop_pos * 100))) + if (!gst_pad_push_event(params->stream->my_sink, gst_event_new_seek(params->rate, GST_FORMAT_TIME, + flags, start_type, params->start_pos * 100, stop_type, params->stop_pos * 100))) GST_ERROR("Failed to seek.\n"); + + return S_OK; }
-static void CDECL wg_parser_stream_notify_qos(struct wg_parser_stream *stream, - bool underflow, double proportion, int64_t diff, uint64_t timestamp) +static NTSTATUS wg_parser_stream_notify_qos(void *args) { + const struct wg_parser_stream_notify_qos_params *params = args; + struct wg_parser_stream *stream = params->stream; GstClockTime stream_time; GstEvent *event;
/* We return timestamps in stream time, i.e. relative to the start of the * file (or other medium), but gst_event_new_qos() expects the timestamp in * running time. */ - stream_time = gst_segment_to_running_time(&stream->segment, GST_FORMAT_TIME, timestamp * 100); + stream_time = gst_segment_to_running_time(&stream->segment, GST_FORMAT_TIME, params->timestamp * 100); if (stream_time == -1) { /* This can happen legitimately if the sample falls outside of the * segment bounds. GStreamer elements shouldn't present the sample in * that case, but DirectShow doesn't care. */ GST_LOG("Ignoring QoS event.\n"); - return; + return S_OK; }
- if (!(event = gst_event_new_qos(underflow ? GST_QOS_TYPE_UNDERFLOW : GST_QOS_TYPE_OVERFLOW, - proportion, diff * 100, stream_time))) + if (!(event = gst_event_new_qos(params->underflow ? GST_QOS_TYPE_UNDERFLOW : GST_QOS_TYPE_OVERFLOW, + params->proportion, params->diff * 100, stream_time))) GST_ERROR("Failed to create QOS event.\n"); gst_pad_push_event(stream->my_sink, event); + + return S_OK; }
static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, @@ -1527,14 +1575,16 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) return ret; }
-static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size) +static NTSTATUS wg_parser_connect(void *args) { GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); + const struct wg_parser_connect_params *params = args; + struct wg_parser *parser = params->parser; unsigned int i; int ret;
- parser->file_size = file_size; + parser->file_size = params->file_size; parser->sink_connected = true;
if (!parser->bus) @@ -1684,8 +1734,9 @@ out: return E_FAIL; }
-static void CDECL wg_parser_disconnect(struct wg_parser *parser) +static NTSTATUS wg_parser_disconnect(void *args) { + struct wg_parser *parser = args; unsigned int i;
/* Unblock all of our streams. */ @@ -1718,6 +1769,8 @@ static void CDECL wg_parser_disconnect(struct wg_parser *parser) gst_element_set_bus(parser->container, NULL); gst_object_unref(parser->container); parser->container = NULL; + + return S_OK; }
static BOOL decodebin_parser_init_gst(struct wg_parser *parser) @@ -1878,7 +1931,7 @@ static void init_gstreamer_once(void) gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); }
-static struct wg_parser * CDECL wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) +static NTSTATUS wg_parser_create(void *args) { static const init_gst_cb init_funcs[] = { @@ -1889,28 +1942,32 @@ static struct wg_parser * CDECL wg_parser_create(enum wg_parser_type type, bool };
static pthread_once_t once = PTHREAD_ONCE_INIT; + struct wg_parser_create_params *params = args; struct wg_parser *parser;
if (pthread_once(&once, init_gstreamer_once)) - return NULL; + return E_FAIL;
if (!(parser = calloc(1, sizeof(*parser)))) - return NULL; + return E_OUTOFMEMORY;
pthread_mutex_init(&parser->mutex, NULL); pthread_cond_init(&parser->init_cond, NULL); pthread_cond_init(&parser->read_cond, NULL); pthread_cond_init(&parser->read_done_cond, NULL); parser->flushing = true; - parser->init_gst = init_funcs[type]; - parser->unlimited_buffering = unlimited_buffering; + parser->init_gst = init_funcs[params->type]; + parser->unlimited_buffering = params->unlimited_buffering;
GST_DEBUG("Created winegstreamer parser %p.\n", parser); - return parser; + params->parser = parser; + return S_OK; }
-static void CDECL wg_parser_destroy(struct wg_parser *parser) +static NTSTATUS wg_parser_destroy(void *args) { + struct wg_parser *parser = args; + if (parser->bus) { gst_bus_set_sync_handler(parser->bus, NULL, NULL, NULL); @@ -1923,41 +1980,36 @@ static void CDECL wg_parser_destroy(struct wg_parser *parser) pthread_cond_destroy(&parser->read_done_cond);
free(parser); + return S_OK; }
-static const struct unix_funcs funcs = +const unixlib_entry_t __wine_unix_call_funcs[] = { - wg_parser_create, - wg_parser_destroy, +#define X(name) [unix_ ## name] = name + X(wg_parser_create), + X(wg_parser_destroy),
- wg_parser_connect, - wg_parser_disconnect, + X(wg_parser_connect), + X(wg_parser_disconnect),
- wg_parser_begin_flush, - wg_parser_end_flush, + X(wg_parser_begin_flush), + X(wg_parser_end_flush),
- wg_parser_get_next_read_offset, - wg_parser_push_data, + X(wg_parser_get_next_read_offset), + X(wg_parser_push_data),
- wg_parser_get_stream_count, - wg_parser_get_stream, + X(wg_parser_get_stream_count), + X(wg_parser_get_stream),
- wg_parser_stream_get_preferred_format, - wg_parser_stream_enable, - wg_parser_stream_disable, + X(wg_parser_stream_get_preferred_format), + X(wg_parser_stream_enable), + X(wg_parser_stream_disable),
- wg_parser_stream_get_event, - wg_parser_stream_copy_buffer, - wg_parser_stream_release_buffer, - wg_parser_stream_notify_qos, + X(wg_parser_stream_get_event), + X(wg_parser_stream_copy_buffer), + X(wg_parser_stream_release_buffer), + X(wg_parser_stream_notify_qos),
- wg_parser_stream_get_duration, - wg_parser_stream_seek, + X(wg_parser_stream_get_duration), + X(wg_parser_stream_seek), }; - -NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out) -{ - if (reason == DLL_PROCESS_ATTACH) - *(const struct unix_funcs **)ptr_out = &funcs; - return STATUS_SUCCESS; -}
Hi Zebediah,
On Tue, 5 Oct 2021 at 01:21, Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 32 ++++- dlls/winegstreamer/main.c | 197 ++++++++++++++++++++++++++- dlls/winegstreamer/media_source.c | 44 +++--- dlls/winegstreamer/quartz_parser.c | 72 +++++----- dlls/winegstreamer/unixlib.h | 139 +++++++++++++++---- dlls/winegstreamer/wg_parser.c | 210 ++++++++++++++++++----------- 7 files changed, 528 insertions(+), 167 deletions(-)
I've looked around for information about the unix library -> unix call transition, and didn't spot much. So if you don't mind I'll be asking a couple of, perhaps silly, questions :-)
The transition seems to move the unix library across the user->kernel space line, from Windows app POV, does it not? At the same time, what's the practical reason - do apps search through the process/namespace and fail, as they find the unix libs. Is there any overhead change - I would imagine it has increased to a point?
In addition, did the team consider using linux kernel style ioctls? These will allow you to preserve the type of the arguments, their respective size, as well as access level. This should help with out-of-bounds access and potentially writing into read-only memory, say due to a bug or security vulnerability in the unix lib.
Thanks in advance, Emil
On 10/5/21 07:43, Emil Velikov wrote:
Hi Zebediah,
On Tue, 5 Oct 2021 at 01:21, Zebediah Figura zfigura@codeweavers.com wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 32 ++++- dlls/winegstreamer/main.c | 197 ++++++++++++++++++++++++++- dlls/winegstreamer/media_source.c | 44 +++--- dlls/winegstreamer/quartz_parser.c | 72 +++++----- dlls/winegstreamer/unixlib.h | 139 +++++++++++++++---- dlls/winegstreamer/wg_parser.c | 210 ++++++++++++++++++----------- 7 files changed, 528 insertions(+), 167 deletions(-)
I've looked around for information about the unix library -> unix call transition, and didn't spot much. So if you don't mind I'll be asking a couple of, perhaps silly, questions :-)
The transition seems to move the unix library across the user->kernel space line, from Windows app POV, does it not? At the same time, what's the practical reason - do apps search through the process/namespace and fail, as they find the unix libs. Is there any overhead change - I would imagine it has increased to a point?
Broadly speaking, yes. There's basically three reasons I'm aware of (and can remember at the moment) for patches like this or d6d32434a7:
* By putting the Unix side behind the syscall interface, we essentially prevent debuggers from seeing it when debugging. We want this because debuggers just get confused when they see Unix code. (E.g. if you set a breakpoint in a signal handler, things tend to break badly.)
* The syscall interface can be used to swap architecture boundaries. Mac dropped 32-bit, some enterprise Linux distributions want to do the same; this would allow us to no longer require 32-bit Unix libraries.
* This one hasn't been discussed, but we have a bug (47808) where an application (Cygwin) replaces the normal thread stack with one that's actually split into reserved/committed parts, but then libfreetype jumps several pages at once expecting it to all be committed. This is a moot point for libfreetype specifically, because we'll probably compile it with MinGW and keep it on the PE side (in theory it has the same problem, but Windows applications should emit chkstk or something similar here and MinGW indeed does so). On the other hand, another library could run into something similar.
In addition, did the team consider using linux kernel style ioctls? These will allow you to preserve the type of the arguments, their respective size, as well as access level. This should help with out-of-bounds access and potentially writing into read-only memory, say due to a bug or security vulnerability in the unix lib.
I don't think it was thought of before. I don't think there was really any internal discussion about it either. I can definitely see the value in checking argument size—that's pretty easy to get wrong—although I'm not sure we can reasonably check access level.
Thanks for the elaborate answer Zebediah,
On Tue, 5 Oct 2021 at 17:57, Zebediah Figura (she/her) zfigura@codeweavers.com wrote:
- The syscall interface can be used to swap architecture boundaries. Mac
dropped 32-bit, some enterprise Linux distributions want to do the same; this would allow us to no longer require 32-bit Unix libraries.
Due to the different struct sizes, paddings and alike, this means that Wine will need to add a "compat_ioctl" style wrapper, correct? I guess such code is planned, although I don't think it landed just yet.
- This one hasn't been discussed, but we have a bug (47808) where an
application (Cygwin) replaces the normal thread stack with one that's actually split into reserved/committed parts, but then libfreetype jumps several pages at once expecting it to all be committed. This is a moot point for libfreetype specifically, because we'll probably compile it with MinGW and keep it on the PE side (in theory it has the same problem, but Windows applications should emit chkstk or something similar here and MinGW indeed does so). On the other hand, another library could run into something similar.
That is an interesting way to workaround such "lovely" behaviour. Sounds like prime contender for the hall of shame :-P
In addition, did the team consider using linux kernel style ioctls? These will allow you to preserve the type of the arguments, their respective size, as well as access level. This should help with out-of-bounds access and potentially writing into read-only memory, say due to a bug or security vulnerability in the unix lib.
I don't think it was thought of before. I don't think there was really any internal discussion about it either. I can definitely see the value in checking argument size—that's pretty easy to get wrong—although I'm not sure we can reasonably check access level.
Hope the team finds a way. Or at least get the infra in, so when the eureka moment comes it won't involve updating dozens of modules.
-Emil
On 10/6/21 06:25, Emil Velikov wrote:
Thanks for the elaborate answer Zebediah,
On Tue, 5 Oct 2021 at 17:57, Zebediah Figura (she/her) zfigura@codeweavers.com wrote:
- The syscall interface can be used to swap architecture boundaries. Mac
dropped 32-bit, some enterprise Linux distributions want to do the same; this would allow us to no longer require 32-bit Unix libraries.
Due to the different struct sizes, paddings and alike, this means that Wine will need to add a "compat_ioctl" style wrapper, correct? I guess such code is planned, although I don't think it landed just yet.
Yes, and there's actually already a __wine_unix_call_wow64_funcs which I believe is supposed to serve that purpose, although nothing defines it yet. Of course, another alternative is just to use constant struct sizes (including e.g. a 64-bit integer for all pointers).
- This one hasn't been discussed, but we have a bug (47808) where an
application (Cygwin) replaces the normal thread stack with one that's actually split into reserved/committed parts, but then libfreetype jumps several pages at once expecting it to all be committed. This is a moot point for libfreetype specifically, because we'll probably compile it with MinGW and keep it on the PE side (in theory it has the same problem, but Windows applications should emit chkstk or something similar here and MinGW indeed does so). On the other hand, another library could run into something similar.
That is an interesting way to workaround such "lovely" behaviour. Sounds like prime contender for the hall of shame :-P
In addition, did the team consider using linux kernel style ioctls? These will allow you to preserve the type of the arguments, their respective size, as well as access level. This should help with out-of-bounds access and potentially writing into read-only memory, say due to a bug or security vulnerability in the unix lib.
I don't think it was thought of before. I don't think there was really any internal discussion about it either. I can definitely see the value in checking argument size—that's pretty easy to get wrong—although I'm not sure we can reasonably check access level.
Hope the team finds a way. Or at least get the infra in, so when the eureka moment comes it won't involve updating dozens of modules.
-Emil
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/Makefile.in | 4 +++- dlls/winegstreamer/gst_private.h | 2 -- dlls/winegstreamer/main.c | 26 -------------------------- dlls/winegstreamer/quartz_parser.c | 19 ------------------- 4 files changed, 3 insertions(+), 48 deletions(-)
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index e35df3cf3f9..95c2d885482 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -3,7 +3,9 @@ UNIXLIB = winegstreamer.so IMPORTS = strmbase strmiids uuid ole32 mfuuid DELAYIMPORTS = mfplat EXTRAINCL = $(GSTREAMER_CFLAGS) -EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) +# GLib pins some of its own libraries, and breaks if libraries that import it +# try to initialize themselves after being unloaded. +EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) -Wl,-z,nodelete
C_SRCS = \ audioconvert.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index ebe0bf6f50d..c141dd44921 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -98,8 +98,6 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
-BOOL init_gstreamer(void) DECLSPEC_HIDDEN; - extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN; extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN;
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index c799aa06d1b..6b2b70f9c60 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -318,9 +318,6 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out)
TRACE("clsid %s, iid %s, out %p.\n", debugstr_guid(clsid), debugstr_guid(iid), out);
- if (!init_gstreamer()) - return CLASS_E_CLASSNOTAVAILABLE; - if (SUCCEEDED(hr = mfplat_get_class_object(clsid, iid, out))) return hr;
@@ -341,29 +338,6 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) return IClassFactory_QueryInterface(&factory->IClassFactory_iface, iid, out); }
-static BOOL CALLBACK init_gstreamer_proc(INIT_ONCE *once, void *param, void **ctx) -{ - HINSTANCE handle; - - /* Unloading glib is a bad idea.. it installs atexit handlers, - * so never unload the dll after loading */ - GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, - (LPCWSTR)init_gstreamer_proc, &handle); - if (!handle) - ERR("Failed to pin module.\n"); - - return TRUE; -} - -BOOL init_gstreamer(void) -{ - static INIT_ONCE once = INIT_ONCE_STATIC_INIT; - - InitOnceExecuteOnce(&once, init_gstreamer_proc, NULL, NULL); - - return TRUE; -} - static const REGPINTYPES reg_audio_mt = {&MEDIATYPE_Audio, &GUID_NULL}; static const REGPINTYPES reg_stream_mt = {&MEDIATYPE_Stream, &GUID_NULL}; static const REGPINTYPES reg_video_mt = {&MEDIATYPE_Video, &GUID_NULL}; diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 6ae1a99a14a..d6a58801f51 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1098,20 +1098,10 @@ static HRESULT decodebin_parser_source_get_media_type(struct parser_source *pin, return VFW_S_NO_MORE_ITEMS; }
-static BOOL parser_init_gstreamer(void) -{ - if (!init_gstreamer()) - return FALSE; - return TRUE; -} - HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) { struct parser *object;
- if (!parser_init_gstreamer()) - return E_FAIL; - if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
@@ -1634,9 +1624,6 @@ HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) { struct parser *object;
- if (!parser_init_gstreamer()) - return E_FAIL; - if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
@@ -1720,9 +1707,6 @@ HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) { struct parser *object;
- if (!parser_init_gstreamer()) - return E_FAIL; - if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
@@ -1827,9 +1811,6 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) { struct parser *object;
- if (!parser_init_gstreamer()) - return E_FAIL; - if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
October 4, 2021 7:21 PM, "Zebediah Figura" zfigura@codeweavers.com wrote:
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index e35df3cf3f9..95c2d885482 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -3,7 +3,9 @@ UNIXLIB = winegstreamer.so IMPORTS = strmbase strmiids uuid ole32 mfuuid DELAYIMPORTS = mfplat EXTRAINCL = $(GSTREAMER_CFLAGS) -EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) +# GLib pins some of its own libraries, and breaks if libraries that import it +# try to initialize themselves after being unloaded. +EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) -Wl,-z,nodelete
This needs a configure check--especially since it won't work on macOS.
Chip
On 10/4/21 20:57, Chip Davis wrote:
October 4, 2021 7:21 PM, "Zebediah Figura" zfigura@codeweavers.com wrote:
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index e35df3cf3f9..95c2d885482 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -3,7 +3,9 @@ UNIXLIB = winegstreamer.so IMPORTS = strmbase strmiids uuid ole32 mfuuid DELAYIMPORTS = mfplat EXTRAINCL = $(GSTREAMER_CFLAGS) -EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) +# GLib pins some of its own libraries, and breaks if libraries that import it +# try to initialize themselves after being unloaded. +EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) -Wl,-z,nodelete
This needs a configure check--especially since it won't work on macOS.
Of course it won't. Please ignore this patch, then.