From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/Makefile.in | 2 +- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 14 +++ dlls/winegstreamer/media_sink.c | 9 ++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 8 ++ dlls/winegstreamer/wg_muxer.c | 143 ++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 19 ++++ 8 files changed, 196 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index f963dcea7f0..5b8e9fcab2c 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -3,7 +3,7 @@ UNIXLIB = winegstreamer.so IMPORTLIB = winegstreamer IMPORTS = strmbase ole32 oleaut32 msdmo DELAYIMPORTS = mfplat mf -UNIX_CFLAGS = $(GSTREAMER_CFLAGS) +UNIX_CFLAGS = $(GSTREAMER_CFLAGS) -Wno-deprecated-declarations UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS)
C_SRCS = \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 243dab16c72..36f0030f6c4 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -112,6 +112,7 @@ HRESULT wg_transform_flush(wg_transform_t transform);
HRESULT wg_muxer_create(struct wg_container_format *format, wg_muxer_t *muxer); void wg_muxer_destroy(wg_muxer_t muxer); +HRESULT wg_muxer_add_stream(wg_muxer_t muxer, UINT32 stream_id, const struct wg_format *format);
unsigned int wg_format_get_max_size(const struct wg_format *format);
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index e4c93076eea..4e8ae64db96 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -482,6 +482,20 @@ void wg_muxer_destroy(wg_muxer_t muxer) WINE_UNIX_CALL(unix_wg_muxer_destroy, &muxer); }
+HRESULT wg_muxer_add_stream(wg_muxer_t muxer, UINT32 stream_id, const struct wg_format *format) +{ + struct wg_muxer_add_stream_params params = + { + .muxer = muxer, + .stream_id = stream_id, + .format = format, + }; + + TRACE("muxer %#I64x, stream_id %u, format %p.\n", muxer, stream_id, format); + + return WINE_UNIX_CALL(unix_wg_muxer_add_stream, ¶ms); +} + #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
unsigned int wg_format_get_stride(const struct wg_format *format) diff --git a/dlls/winegstreamer/media_sink.c b/dlls/winegstreamer/media_sink.c index 392ffb17bf9..7b772a7dd13 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -589,6 +589,7 @@ static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, D { struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); struct stream_sink *object; + struct wg_format format; HRESULT hr;
TRACE("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p.\n", @@ -609,6 +610,14 @@ static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, D return hr; }
+ mf_media_type_to_wg_format(media_type, &format); + if (FAILED(hr = wg_muxer_add_stream(media_sink->muxer, stream_sink_id, &format))) + { + LeaveCriticalSection(&media_sink->cs); + IMFStreamSink_Release(&object->IMFStreamSink_iface); + return hr; + } + list_add_tail(&media_sink->stream_sinks, &object->entry);
LeaveCriticalSection(&media_sink->cs); diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 90a31f53f38..6078d73de93 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -63,6 +63,7 @@ extern NTSTATUS wg_transform_flush(void *args) DECLSPEC_HIDDEN;
extern NTSTATUS wg_muxer_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_muxer_destroy(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_muxer_add_stream(void *args) DECLSPEC_HIDDEN;
/* wg_allocator.c */
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 6fa5fb99039..71a6112decb 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -395,6 +395,13 @@ struct wg_muxer_create_params const struct wg_container_format *format; };
+struct wg_muxer_add_stream_params +{ + wg_muxer_t muxer; + UINT32 stream_id; + const struct wg_format *format; +}; + enum unix_funcs { unix_wg_init_gstreamer, @@ -437,6 +444,7 @@ enum unix_funcs
unix_wg_muxer_create, unix_wg_muxer_destroy, + unix_wg_muxer_add_stream, };
#endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_muxer.c b/dlls/winegstreamer/wg_muxer.c index 67fa849cb10..280154efa3f 100644 --- a/dlls/winegstreamer/wg_muxer.c +++ b/dlls/winegstreamer/wg_muxer.c @@ -22,12 +22,16 @@ #pragma makedep unix #endif
+#include <stdio.h> + #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h"
#include "unix_private.h"
+#include "wine/list.h" + struct wg_muxer { GstElement *container, *muxer; @@ -39,6 +43,20 @@ struct wg_muxer
pthread_mutex_t mutex; pthread_cond_t cond; + + struct list streams; +}; + +struct wg_muxer_stream +{ + struct wg_muxer *muxer; + struct wg_format format; + uint32_t id; + + GstPad *my_src; + GstSegment segment; + + struct list entry; };
static struct wg_muxer *get_muxer(wg_muxer_t muxer) @@ -55,6 +73,15 @@ static void muxer_free_buffer(struct wg_muxer *muxer)
static void muxer_destroy(struct wg_muxer *muxer) { + struct wg_muxer_stream *stream, *next; + + LIST_FOR_EACH_ENTRY_SAFE(stream, next, &muxer->streams, struct wg_muxer_stream, entry) + { + list_remove(&stream->entry); + if (stream->my_src) + gst_object_unref(stream->my_src); + free(stream); + } pthread_cond_destroy(&muxer->cond); pthread_mutex_destroy(&muxer->mutex); if (muxer->buffer) @@ -71,6 +98,23 @@ static void muxer_destroy(struct wg_muxer *muxer) free(muxer); }
+static gboolean muxer_src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) +{ + struct wg_muxer_stream *stream = gst_pad_get_element_private(pad); + + GST_DEBUG("pad %p, parent %p, query %p, stream %u, type "%s".", + pad, parent, query, stream->id, gst_query_type_get_name(query->type)); + + switch (query->type) + { + case GST_QUERY_LATENCY: + gst_query_set_latency(query, true, 0, 0); + return true; + default: + return gst_pad_query_default(pad, parent, query); + } +} + static gboolean muxer_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) { struct wg_muxer *muxer = gst_pad_get_element_private(pad); @@ -100,6 +144,7 @@ NTSTATUS wg_muxer_create(void *args) /* Create wg_muxer object. */ if (!(muxer = calloc(1, sizeof(*muxer)))) return E_OUTOFMEMORY; + list_init(&muxer->streams); pthread_mutex_init(&muxer->mutex, NULL); pthread_cond_init(&muxer->cond, NULL); if (!(muxer->container = gst_bin_new("wg_muxer"))) @@ -158,3 +203,101 @@ NTSTATUS wg_muxer_destroy(void *args) muxer_destroy(muxer); return S_OK; } + +NTSTATUS wg_muxer_add_stream(void *args) +{ + struct wg_muxer_add_stream_params *params = args; + struct wg_muxer *muxer = get_muxer(params->muxer); + GstPadTemplate *template = NULL; + const char *muxer_sink_pad_name; + struct wg_muxer_stream *stream; + GstPad *muxer_sink = NULL; + NTSTATUS status = E_FAIL; + GstCaps *src_caps = NULL; + char src_pad_name[32]; + int ret; + + /* Create stream object. */ + if (!(stream = calloc(1, sizeof(*stream)))) + return E_OUTOFMEMORY; + stream->muxer = muxer; + stream->format = *params->format; + stream->id = params->stream_id; + + /* Create src pad. */ + if (!(src_caps = wg_format_to_caps(params->format))) + goto out; + if (params->format->major_type == WG_MAJOR_TYPE_VIDEO_H264) + gst_caps_set_simple(src_caps, "stream-format", G_TYPE_STRING, "avc", NULL); + if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) + goto out; + sprintf(src_pad_name, "wg_muxer_src_%u", stream->id); + stream->my_src = gst_pad_new_from_template(template, src_pad_name); + gst_object_unref(template); + if (!stream->my_src) + goto out; + gst_pad_set_element_private(stream->my_src, stream); + gst_pad_set_query_function(stream->my_src, muxer_src_query_cb); + + /* Request muxer sink pad. */ + switch (stream->format.major_type) + { + case WG_MAJOR_TYPE_VIDEO: + case WG_MAJOR_TYPE_VIDEO_CINEPAK: + case WG_MAJOR_TYPE_VIDEO_H264: + case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: + muxer_sink_pad_name = "video_%u"; + break; + case WG_MAJOR_TYPE_AUDIO: + case WG_MAJOR_TYPE_AUDIO_MPEG1: + case WG_MAJOR_TYPE_AUDIO_MPEG4: + case WG_MAJOR_TYPE_AUDIO_WMA: + muxer_sink_pad_name = "audio_%u"; + break; + default: + goto out; + } + if (!(muxer_sink = gst_element_get_request_pad(muxer->muxer, muxer_sink_pad_name))) + goto out; + + /* Link src pad to muxer sink pad. */ + if ((ret = gst_pad_link(stream->my_src, muxer_sink)) < 0) + { + GST_ERROR("Failed to link %s to muxer, ret %d.\n", src_pad_name, ret); + goto out; + } + if (!gst_pad_set_active(stream->my_src, 1)) + goto out; + + /* Push events to prepare for streaming. */ + if (!push_event(stream->my_src, gst_event_new_stream_start(src_pad_name))) + goto out; + if (!push_event(stream->my_src, gst_event_new_caps(src_caps))) + goto out; + gst_segment_init(&stream->segment, GST_FORMAT_TIME); + if (!push_event(stream->my_src, gst_event_new_segment(&stream->segment))) + goto out; + + list_add_tail(&muxer->streams, &stream->entry); + + gst_object_unref(muxer_sink); + gst_caps_unref(src_caps); + GST_INFO("Created winegstreamer muxer stream %p.", stream); + + return S_OK; + +out: + if (muxer_sink) + { + gst_element_release_request_pad(muxer->muxer, muxer_sink); + gst_object_unref(muxer_sink); + } + if (stream->my_src) + gst_object_unref(stream->my_src); + if (src_caps) + gst_caps_unref(src_caps); + free(stream); + + return status; +} diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 016691d448d..1880b052680 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1948,6 +1948,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_muxer_create), X(wg_muxer_destroy), + X(wg_muxer_add_stream), };
#ifdef _WIN64 @@ -2172,6 +2173,23 @@ NTSTATUS wow64_wg_muxer_create(void *args) return ret; }
+NTSTATUS wow64_wg_muxer_add_stream(void *args) +{ + struct + { + wg_muxer_t muxer; + DWORD stream_id; + PTR32 format; + } *params32 = args; + struct wg_muxer_add_stream_params params = + { + .muxer = params32->muxer, + .stream_id = params32->stream_id, + .format = ULongToPtr(params32->format), + }; + return wg_muxer_add_stream(¶ms); +} + const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { #define X64(name) [unix_ ## name] = wow64_ ## name @@ -2215,6 +2233,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
X64(wg_muxer_create), X(wg_muxer_destroy), + X64(wg_muxer_add_stream), };
#endif /* _WIN64 */