-- v5: winegstreamer: Implement wg_muxer_push_sample. winegstreamer: Implement ProcessSample for media sink. winegstreamer: Implement wg_muxer_start. winegstreamer: Implement wg_muxer_add_stream. winegstreamer: Introduce create_element_by_factory. winegstreamer: Introduce find_element_factory. winegstreamer: Introduce link_src_to_sink.
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/main.c | 8 ++++++-- dlls/winegstreamer/wg_muxer.c | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 853907e1825..beb48fa3731 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -466,13 +466,17 @@ HRESULT wg_muxer_create(const char *format, wg_muxer_t *muxer)
TRACE("format %p, muxer %p.\n", format, muxer);
- if (SUCCEEDED(status = WINE_UNIX_CALL(unix_wg_muxer_create, ¶ms))) + if (!(status = WINE_UNIX_CALL(unix_wg_muxer_create, ¶ms))) { *muxer = params.muxer; TRACE("Created wg_muxer %#I64x.\n", params.muxer); } + else + { + WARN("Failed to create muxer, status %#lx.\n", status); + }
- return status; + return HRESULT_FROM_NT(status); }
void wg_muxer_destroy(wg_muxer_t muxer) diff --git a/dlls/winegstreamer/wg_muxer.c b/dlls/winegstreamer/wg_muxer.c index 6887bc015ba..601c5f03d31 100644 --- a/dlls/winegstreamer/wg_muxer.c +++ b/dlls/winegstreamer/wg_muxer.c @@ -61,14 +61,14 @@ NTSTATUS wg_muxer_create(void *args) { struct wg_muxer_create_params *params = args; GstElement *first = NULL, *last = NULL; + NTSTATUS status = STATUS_UNSUCCESSFUL; GstPadTemplate *template = NULL; GstCaps *sink_caps = NULL; - NTSTATUS status = E_FAIL; struct wg_muxer *muxer;
/* Create wg_muxer object. */ if (!(muxer = calloc(1, sizeof(*muxer)))) - return E_OUTOFMEMORY; + return STATUS_NO_MEMORY; if (!(muxer->container = gst_bin_new("wg_muxer"))) goto out;
@@ -110,7 +110,7 @@ NTSTATUS wg_muxer_create(void *args) GST_INFO("Created winegstreamer muxer %p.", muxer); params->muxer = (wg_transform_t)(ULONG_PTR)muxer;
- return S_OK; + return STATUS_SUCCESS;
out: if (muxer->my_sink)
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.c | 58 ++++++++++++++++++------------- dlls/winegstreamer/wg_parser.c | 7 ++-- 3 files changed, 37 insertions(+), 29 deletions(-)
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 305d69c12a8..eefd3cdb259 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -37,6 +37,7 @@ extern GstStreamType stream_type_from_caps(GstCaps *caps) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; extern GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) DECLSPEC_HIDDEN; extern bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; +extern bool link_src_to_sink(GstPad *src_pad, GstPad *sink_pad) DECLSPEC_HIDDEN; extern bool link_src_to_element(GstPad *src_pad, GstElement *element) DECLSPEC_HIDDEN; extern bool link_element_to_sink(GstElement *element, GstPad *sink_pad) DECLSPEC_HIDDEN; extern bool push_event(GstPad *pad, GstEvent *event) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 513ece95a90..273801ac398 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -162,50 +162,60 @@ bool append_element(GstElement *container, GstElement *element, GstElement **fir return success; }
-bool link_src_to_element(GstPad *src_pad, GstElement *element) +bool link_src_to_sink(GstPad *src_pad, GstPad *sink_pad) { GstPadLinkReturn ret; - GstPad *sink_pad;
- if (!(sink_pad = gst_element_get_static_pad(element, "sink"))) + if ((ret = gst_pad_link(src_pad, sink_pad)) != GST_PAD_LINK_OK) { - gchar *name = gst_element_get_name(element); - GST_ERROR("Failed to find sink pad on %s", name); - g_free(name); + gchar *src_name = gst_pad_get_name(src_pad), *sink_name = gst_pad_get_name(sink_pad); + + GST_ERROR("Failed to link src pad %s to sink pad %s, reason: %s", + src_name, sink_name, gst_pad_link_get_name(ret)); + + g_free(sink_name); + g_free(src_name); + return false; } - if ((ret = gst_pad_link(src_pad, sink_pad))) + + return true; +} + +bool link_src_to_element(GstPad *src_pad, GstElement *element) +{ + GstPad *sink_pad; + bool ret; + + if (!(sink_pad = gst_element_get_compatible_pad(element, src_pad, NULL))) { - gchar *src_name = gst_pad_get_name(src_pad), *sink_name = gst_pad_get_name(sink_pad); - GST_ERROR("Failed to link element pad %s with pad %s", src_name, sink_name); - g_free(sink_name); + gchar *element_name = gst_element_get_name(element), *src_name = gst_pad_get_name(src_pad); + GST_ERROR("Failed to find sink pad compatible to %s on %s", src_name, element_name); g_free(src_name); + g_free(element_name); + return false; } + ret = link_src_to_sink(src_pad, sink_pad); gst_object_unref(sink_pad); - return !ret; + return ret; }
bool link_element_to_sink(GstElement *element, GstPad *sink_pad) { - GstPadLinkReturn ret; GstPad *src_pad; + bool ret;
- if (!(src_pad = gst_element_get_static_pad(element, "src"))) + if (!(src_pad = gst_element_get_compatible_pad(element, sink_pad, NULL))) { - gchar *name = gst_element_get_name(element); - GST_ERROR("Failed to find src pad on %s", name); - g_free(name); - return false; - } - if ((ret = gst_pad_link(src_pad, sink_pad))) - { - gchar *src_name = gst_pad_get_name(src_pad), *sink_name = gst_pad_get_name(sink_pad); - GST_ERROR("Failed to link pad %s with element pad %s", src_name, sink_name); + gchar *element_name = gst_element_get_name(element), *sink_name = gst_pad_get_name(sink_pad); + GST_ERROR("Failed to find src pad compatible %s on %s", sink_name, element_name); g_free(sink_name); - g_free(src_name); + g_free(element_name); + return false; } + ret = link_src_to_sink(src_pad, sink_pad); gst_object_unref(src_pad); - return !ret; + return ret; }
bool push_event(GstPad *pad, GstEvent *event) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 299eea09c90..ebdefb6a7f9 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -849,7 +849,6 @@ static bool stream_create_post_processing_elements(GstPad *pad, struct wg_parser struct wg_parser *parser = stream->parser; const char *name; GstCaps *caps; - int ret;
caps = gst_pad_query_caps(pad, NULL); name = gst_structure_get_name(gst_caps_get_structure(caps, 0)); @@ -898,11 +897,9 @@ static bool stream_create_post_processing_elements(GstPad *pad, struct wg_parser if (!link_src_to_element(pad, first) || !link_element_to_sink(last, stream->my_sink)) return false; } - else if ((ret = gst_pad_link(pad, stream->my_sink)) < 0) + else { - GST_ERROR("Failed to link decodebin source pad to our sink pad, error %s.", - gst_pad_link_get_name(ret)); - return false; + return link_src_to_sink(pad, stream->my_sink); }
return true;
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/unix_private.h | 5 ++- dlls/winegstreamer/unixlib.c | 60 +++++++++++++++++++------------ dlls/winegstreamer/wg_muxer.c | 2 +- dlls/winegstreamer/wg_transform.c | 2 +- 4 files changed, 43 insertions(+), 26 deletions(-)
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index eefd3cdb259..8574042a23c 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -35,7 +35,10 @@ extern NTSTATUS wg_init_gstreamer(void *args) DECLSPEC_HIDDEN;
extern GstStreamType stream_type_from_caps(GstCaps *caps) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; -extern GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) DECLSPEC_HIDDEN; +extern GList *find_element_factory(GstElementFactoryListType type, GstRank min_rank, + GstCaps *element_sink_caps, GstCaps *element_src_caps) DECLSPEC_HIDDEN; +extern GstElement *find_element(GstElementFactoryListType type, GstRank min_rank, + GstCaps *element_sink_caps, GstCaps *element_src_caps) DECLSPEC_HIDDEN; extern bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; extern bool link_src_to_sink(GstPad *src_pad, GstPad *sink_pad) DECLSPEC_HIDDEN; extern bool link_src_to_element(GstPad *src_pad, GstElement *element) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 273801ac398..7cd7cfb394a 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -78,32 +78,52 @@ GstElement *create_element(const char *name, const char *plugin_set) return element; }
-GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) +GList *find_element_factory(GstElementFactoryListType type, GstRank min_rank, + GstCaps *element_sink_caps, GstCaps *element_src_caps) { - GstElement *element = NULL; - GList *tmp, *transforms; - const gchar *name; + GList *tmp, *factories = NULL;
- if (!(transforms = gst_element_factory_list_get_elements(type, GST_RANK_MARGINAL))) + if (!(factories = gst_element_factory_list_get_elements(type, min_rank))) goto done;
- if (src_caps) + if (element_sink_caps) { - tmp = gst_element_factory_list_filter(transforms, src_caps, GST_PAD_SINK, FALSE); - gst_plugin_feature_list_free(transforms); - if (!(transforms = tmp)) + tmp = gst_element_factory_list_filter(factories, element_sink_caps, GST_PAD_SINK, FALSE); + gst_plugin_feature_list_free(factories); + if (!(factories = tmp)) goto done; }
- if (sink_caps) + if (element_src_caps) { - tmp = gst_element_factory_list_filter(transforms, sink_caps, GST_PAD_SRC, FALSE); - gst_plugin_feature_list_free(transforms); - if (!(transforms = tmp)) + tmp = gst_element_factory_list_filter(factories, element_src_caps, GST_PAD_SRC, FALSE); + gst_plugin_feature_list_free(factories); + if (!(factories = tmp)) goto done; }
- transforms = g_list_sort(transforms, gst_plugin_feature_rank_compare_func); + factories = g_list_sort(factories, gst_plugin_feature_rank_compare_func); + +done: + if (!factories) + GST_WARNING("Failed to find any element factory matching " + "type %"G_GINT64_MODIFIER"x, min_rank %d, " + "caps %"GST_PTR_FORMAT" / %"GST_PTR_FORMAT".", + type, min_rank, element_sink_caps, element_src_caps); + + return factories; +} + +GstElement *find_element(GstElementFactoryListType type, GstRank min_rank, + GstCaps *element_sink_caps, GstCaps *element_src_caps) +{ + GstElement *element = NULL; + GList *tmp, *transforms; + const gchar *name; + + if (!(transforms = find_element_factory(type, min_rank, element_sink_caps, element_src_caps))) + return NULL; + for (tmp = transforms; tmp != NULL && element == NULL; tmp = tmp->next) { name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(tmp->data)); @@ -120,20 +140,14 @@ GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstC if (!(element = gst_element_factory_create(GST_ELEMENT_FACTORY(tmp->data), NULL))) GST_WARNING("Failed to create %s element.", name); } + gst_plugin_feature_list_free(transforms);
-done: if (element) - { GST_DEBUG("Created %s element %p.", name, element); - } else - { - gchar *src_str = gst_caps_to_string(src_caps), *sink_str = gst_caps_to_string(sink_caps); - GST_WARNING("Failed to create element matching caps %s / %s.", src_str, sink_str); - g_free(sink_str); - g_free(src_str); - } + GST_WARNING("Failed to create the element matching caps %"GST_PTR_FORMAT" / %"GST_PTR_FORMAT".", + element_sink_caps, element_src_caps);
return element; } diff --git a/dlls/winegstreamer/wg_muxer.c b/dlls/winegstreamer/wg_muxer.c index 601c5f03d31..b74d5a4a3c2 100644 --- a/dlls/winegstreamer/wg_muxer.c +++ b/dlls/winegstreamer/wg_muxer.c @@ -88,7 +88,7 @@ NTSTATUS wg_muxer_create(void *args)
/* Create gstreamer muxer element. */ if (!(muxer->muxer = find_element(GST_ELEMENT_FACTORY_TYPE_MUXER | GST_ELEMENT_FACTORY_TYPE_FORMATTER, - NULL, sink_caps))) + GST_RANK_NONE, NULL, sink_caps))) goto out; if (!append_element(muxer->container, muxer->muxer, &first, &last)) goto out; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e2b14527a20..f5e1ce6ea34 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -361,7 +361,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_WMV: - if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) + if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, GST_RANK_MARGINAL, src_caps, raw_caps)) || !append_element(transform->container, element, &first, &last)) { gst_caps_unref(raw_caps);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.c | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 8574042a23c..4feb18a0c67 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -35,6 +35,7 @@ extern NTSTATUS wg_init_gstreamer(void *args) DECLSPEC_HIDDEN;
extern GstStreamType stream_type_from_caps(GstCaps *caps) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; +GstElement *create_element_by_factory(GstElementFactory *factory) DECLSPEC_HIDDEN; extern GList *find_element_factory(GstElementFactoryListType type, GstRank min_rank, GstCaps *element_sink_caps, GstCaps *element_src_caps) DECLSPEC_HIDDEN; extern GstElement *find_element(GstElementFactoryListType type, GstRank min_rank, diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 7cd7cfb394a..82eaa4ec73e 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -78,6 +78,25 @@ GstElement *create_element(const char *name, const char *plugin_set) return element; }
+GstElement *create_element_by_factory(GstElementFactory *factory) +{ + gchar *plugin_name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory)); + GstElement *element; + + if ((element = gst_element_factory_create(factory, NULL))) + { + gchar *element_name = gst_element_get_name(element); + GST_INFO("Created element %s %p by factory %s.", element_name, element, plugin_name); + g_free(element_name); + } + else + { + GST_WARNING("Failed to create element by factory %s.", plugin_name); + } + + return element; +} + GList *find_element_factory(GstElementFactoryListType type, GstRank min_rank, GstCaps *element_sink_caps, GstCaps *element_src_caps) { @@ -137,16 +156,13 @@ GstElement *find_element(GstElementFactoryListType type, GstRank min_rank, continue; }
- if (!(element = gst_element_factory_create(GST_ELEMENT_FACTORY(tmp->data), NULL))) - GST_WARNING("Failed to create %s element.", name); + element = create_element_by_factory(GST_ELEMENT_FACTORY(tmp->data)); }
gst_plugin_feature_list_free(transforms);
- if (element) - GST_DEBUG("Created %s element %p.", name, element); - else - GST_WARNING("Failed to create the element matching caps %"GST_PTR_FORMAT" / %"GST_PTR_FORMAT".", + if (!element) + GST_WARNING("Failed to create element matching caps %"GST_PTR_FORMAT" / %"GST_PTR_FORMAT".", element_sink_caps, element_src_caps);
return element;
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 21 ++++++++ dlls/winegstreamer/media_sink.c | 9 ++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 8 ++++ dlls/winegstreamer/wg_muxer.c | 80 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 19 ++++++++ 7 files changed, 139 insertions(+)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 8cfadd10bfc..23b59766d0c 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(const char *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 beb48fa3731..55817922e9b 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -486,6 +486,27 @@ 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, + }; + NTSTATUS status; + + TRACE("muxer %#I64x, stream_id %u, format %p.\n", muxer, stream_id, format); + + if ((status = WINE_UNIX_CALL(unix_wg_muxer_add_stream, ¶ms))) + { + WARN("Failed to add stream, status %#lx.\n", status); + return HRESULT_FROM_NT(status); + } + + return S_OK; +} + #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 6bd9fdcfb7d..344134d1633 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -588,6 +588,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", @@ -608,6 +609,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 4feb18a0c67..19645ef604f 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -67,6 +67,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 a3131e9f789..d00790c6b05 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -372,6 +372,13 @@ struct wg_muxer_create_params const char *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, @@ -414,6 +421,7 @@ enum unix_funcs
unix_wg_muxer_create, unix_wg_muxer_destroy, + unix_wg_muxer_add_stream,
unix_wg_funcs_count, }; diff --git a/dlls/winegstreamer/wg_muxer.c b/dlls/winegstreamer/wg_muxer.c index b74d5a4a3c2..23bbc22f66b 100644 --- a/dlls/winegstreamer/wg_muxer.c +++ b/dlls/winegstreamer/wg_muxer.c @@ -22,16 +22,33 @@ #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; GstPad *my_sink; + struct list streams; +}; + +struct wg_muxer_stream +{ + struct wg_muxer *muxer; + struct wg_format format; + uint32_t id; + + GstPad *my_src; + GstCaps *my_src_caps; + + struct list entry; };
static struct wg_muxer *get_muxer(wg_muxer_t muxer) @@ -57,6 +74,13 @@ static gboolean muxer_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *qu } }
+void stream_free(struct wg_muxer_stream *stream) +{ + gst_object_unref(stream->my_src); + gst_caps_unref(stream->my_src_caps); + free(stream); +} + NTSTATUS wg_muxer_create(void *args) { struct wg_muxer_create_params *params = args; @@ -69,6 +93,7 @@ NTSTATUS wg_muxer_create(void *args) /* Create wg_muxer object. */ if (!(muxer = calloc(1, sizeof(*muxer)))) return STATUS_NO_MEMORY; + list_init(&muxer->streams); if (!(muxer->container = gst_bin_new("wg_muxer"))) goto out;
@@ -132,7 +157,13 @@ out: NTSTATUS wg_muxer_destroy(void *args) { struct wg_muxer *muxer = get_muxer(*(wg_muxer_t *)args); + struct wg_muxer_stream *stream, *next;
+ LIST_FOR_EACH_ENTRY_SAFE(stream, next, &muxer->streams, struct wg_muxer_stream, entry) + { + list_remove(&stream->entry); + stream_free(stream); + } gst_object_unref(muxer->my_sink); gst_element_set_state(muxer->container, GST_STATE_NULL); gst_object_unref(muxer->container); @@ -140,3 +171,52 @@ NTSTATUS wg_muxer_destroy(void *args)
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); + NTSTATUS status = STATUS_UNSUCCESSFUL; + GstPadTemplate *template = NULL; + struct wg_muxer_stream *stream; + char src_pad_name[64]; + + GST_DEBUG("muxer %p, stream_id %u, format %p.", muxer, params->stream_id, params->format); + + /* Create stream object. */ + if (!(stream = calloc(1, sizeof(*stream)))) + return STATUS_NO_MEMORY; + stream->muxer = muxer; + stream->format = *params->format; + stream->id = params->stream_id; + + /* Create stream my_src pad. */ + if (!(stream->my_src_caps = wg_format_to_caps(params->format))) + goto out; + if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, stream->my_src_caps))) + goto out; + sprintf(src_pad_name, "wg_muxer_stream_src_%u", stream->id); + if (!(stream->my_src = gst_pad_new_from_template(template, src_pad_name))) + goto out; + gst_pad_set_element_private(stream->my_src, stream); + + /* Add to muxer stream list. */ + list_add_tail(&muxer->streams, &stream->entry); + + gst_object_unref(template); + + GST_INFO("Created winegstreamer muxer stream %p.", stream); + + return STATUS_SUCCESS; + +out: + if (stream->my_src) + gst_object_unref(stream->my_src); + if (template) + gst_object_unref(template); + if (stream->my_src_caps) + gst_caps_unref(stream->my_src_caps); + free(stream); + + return status; +} diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index ebdefb6a7f9..2d2e3450ccb 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1945,6 +1945,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X(wg_muxer_create), X(wg_muxer_destroy), + X(wg_muxer_add_stream), };
C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_wg_funcs_count); @@ -2171,6 +2172,23 @@ NTSTATUS wow64_wg_muxer_create(void *args) return ret; }
+NTSTATUS wow64_wg_muxer_add_stream(void *args) +{ + struct + { + wg_muxer_t muxer; + UINT32 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 @@ -2214,6 +2232,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
X64(wg_muxer_create), X(wg_muxer_destroy), + X64(wg_muxer_add_stream), };
C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_wg_funcs_count);
From: Ziqing Hui zhui@codeweavers.com
wg_muxer_start will autoplug gstreamer muxer and parser elements. It creates a pipeline like this:
------------------- ------- my_src 1 ==> |parser 1 (optional)| ==> | | ------------------- | | | | ------------------- | | my_src 2 ==> |parser 2 (optional)| ==> | | ------------------- | | | muxer | ==> my_sink | | [......] | | | | | | ------------------- | | my_src n ==> |parser n (optional)| ==> | | ------------------- ------- --- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 15 +++ dlls/winegstreamer/media_sink.c | 9 +- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_muxer.c | 166 ++++++++++++++++++++++++------ dlls/winegstreamer/wg_parser.c | 2 + 7 files changed, 163 insertions(+), 32 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 23b59766d0c..38516ba9024 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -113,6 +113,7 @@ HRESULT wg_transform_flush(wg_transform_t transform); HRESULT wg_muxer_create(const char *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); +HRESULT wg_muxer_start(wg_muxer_t muxer);
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 55817922e9b..95c4296812b 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -507,6 +507,21 @@ HRESULT wg_muxer_add_stream(wg_muxer_t muxer, UINT32 stream_id, const struct wg_ return S_OK; }
+HRESULT wg_muxer_start(wg_muxer_t muxer) +{ + NTSTATUS status; + + TRACE("muxer %#I64x.\n", muxer); + + if ((status = WINE_UNIX_CALL(unix_wg_muxer_start, &muxer))) + { + WARN("Failed to start muxer, status %#lx.\n", status); + return HRESULT_FROM_NT(status); + } + + return S_OK; +} + #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 344134d1633..489ede1d26a 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -498,7 +498,13 @@ static HRESULT media_sink_queue_stream_event(struct media_sink *media_sink, Medi
static HRESULT media_sink_start(struct media_sink *media_sink) { + HRESULT hr; + + if (FAILED(hr = wg_muxer_start(media_sink->muxer))) + return hr; + media_sink->state = STATE_STARTED; + return media_sink_queue_stream_event(media_sink, MEStreamSinkStarted); }
@@ -1007,7 +1013,8 @@ static HRESULT WINAPI media_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsy switch (command->op) { case ASYNC_START: - hr = media_sink_start(media_sink); + if (FAILED(hr = media_sink_start(media_sink))) + WARN("Failed to start media sink.\n"); break; case ASYNC_STOP: hr = media_sink_stop(media_sink); diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 19645ef604f..bc88a91f256 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -68,6 +68,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; +extern NTSTATUS wg_muxer_start(void *args) DECLSPEC_HIDDEN;
/* wg_allocator.c */
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index d00790c6b05..9cb6359af26 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -422,6 +422,7 @@ enum unix_funcs unix_wg_muxer_create, unix_wg_muxer_destroy, unix_wg_muxer_add_stream, + unix_wg_muxer_start,
unix_wg_funcs_count, }; diff --git a/dlls/winegstreamer/wg_muxer.c b/dlls/winegstreamer/wg_muxer.c index 23bbc22f66b..347044e7979 100644 --- a/dlls/winegstreamer/wg_muxer.c +++ b/dlls/winegstreamer/wg_muxer.c @@ -36,6 +36,8 @@ struct wg_muxer { GstElement *container, *muxer; GstPad *my_sink; + GstCaps *my_sink_caps; + struct list streams; };
@@ -46,7 +48,9 @@ struct wg_muxer_stream uint32_t id;
GstPad *my_src; - GstCaps *my_src_caps; + GstCaps *my_src_caps, *parser_src_caps; + GstElement *parser; + GstSegment segment;
struct list entry; }; @@ -56,6 +60,54 @@ static struct wg_muxer *get_muxer(wg_muxer_t muxer) return (struct wg_muxer *)(ULONG_PTR)muxer; }
+static bool muxer_try_muxer_factory(struct wg_muxer *muxer, GstElementFactory *muxer_factory) +{ + gchar *plugin_name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(muxer_factory)); + struct wg_muxer_stream *stream; + + GST_INFO("Trying %s.", plugin_name); + + LIST_FOR_EACH_ENTRY(stream, &muxer->streams, struct wg_muxer_stream, entry) + { + GstCaps *caps = stream->parser ? stream->parser_src_caps: stream->my_src_caps; + + if (!gst_element_factory_can_sink_any_caps(muxer_factory, caps)) + { + GST_INFO("%s cannot sink stream %u %p, caps %"GST_PTR_FORMAT, + plugin_name, stream->id, stream, caps); + return false; + } + } + + return true; +} + +static GstElement *muxer_find_muxer(struct wg_muxer *muxer) +{ + /* Some muxers are formatter, eg. id3mux. */ + GstElementFactoryListType muxer_type = GST_ELEMENT_FACTORY_TYPE_MUXER | GST_ELEMENT_FACTORY_TYPE_FORMATTER; + GstElement *element = NULL; + GList *muxers, *tmp; + + GST_DEBUG("muxer %p.", muxer); + + muxers = find_element_factory(muxer_type, GST_RANK_NONE, NULL, muxer->my_sink_caps); + + for (tmp = muxers; tmp && !element; tmp = tmp->next) + { + GstElementFactory *factory = GST_ELEMENT_FACTORY(tmp->data); + if (muxer_try_muxer_factory(muxer, factory)) + element = create_element_by_factory(factory); + } + + gst_plugin_feature_list_free(muxers); + + if (!element) + GST_WARNING("Failed to find any compatible muxer element."); + + return element; +} + static gboolean muxer_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) { struct wg_muxer *muxer = gst_pad_get_element_private(pad); @@ -74,8 +126,10 @@ static gboolean muxer_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *qu } }
-void stream_free(struct wg_muxer_stream *stream) +static void stream_free(struct wg_muxer_stream *stream) { + if (stream->parser_src_caps) + gst_caps_unref(stream->parser_src_caps); gst_object_unref(stream->my_src); gst_caps_unref(stream->my_src_caps); free(stream); @@ -84,10 +138,8 @@ void stream_free(struct wg_muxer_stream *stream) NTSTATUS wg_muxer_create(void *args) { struct wg_muxer_create_params *params = args; - GstElement *first = NULL, *last = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; GstPadTemplate *template = NULL; - GstCaps *sink_caps = NULL; struct wg_muxer *muxer;
/* Create wg_muxer object. */ @@ -98,12 +150,12 @@ NTSTATUS wg_muxer_create(void *args) goto out;
/* Create sink pad. */ - if (!(sink_caps = gst_caps_from_string(params->format))) + if (!(muxer->my_sink_caps = gst_caps_from_string(params->format))) { GST_ERROR("Failed to get caps from format string: "%s".", params->format); goto out; } - if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps))) + if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, muxer->my_sink_caps))) goto out; muxer->my_sink = gst_pad_new_from_template(template, "wg_muxer_sink"); if (!muxer->my_sink) @@ -111,26 +163,7 @@ NTSTATUS wg_muxer_create(void *args) gst_pad_set_element_private(muxer->my_sink, muxer); gst_pad_set_query_function(muxer->my_sink, muxer_sink_query_cb);
- /* Create gstreamer muxer element. */ - if (!(muxer->muxer = find_element(GST_ELEMENT_FACTORY_TYPE_MUXER | GST_ELEMENT_FACTORY_TYPE_FORMATTER, - GST_RANK_NONE, NULL, sink_caps))) - goto out; - if (!append_element(muxer->container, muxer->muxer, &first, &last)) - goto out; - - /* Link muxer to sink pad. */ - if (!link_element_to_sink(muxer->muxer, muxer->my_sink)) - goto out; - if (!gst_pad_set_active(muxer->my_sink, 1)) - goto out; - - /* Set to pause state. */ - gst_element_set_state(muxer->container, GST_STATE_PAUSED); - if (!gst_element_get_state(muxer->container, NULL, NULL, -1)) - goto out; - gst_object_unref(template); - gst_caps_unref(sink_caps);
GST_INFO("Created winegstreamer muxer %p.", muxer); params->muxer = (wg_transform_t)(ULONG_PTR)muxer; @@ -142,13 +175,10 @@ out: gst_object_unref(muxer->my_sink); if (template) gst_object_unref(template); - if (sink_caps) - gst_caps_unref(sink_caps); + if (muxer->my_sink_caps) + gst_caps_unref(muxer->my_sink_caps); if (muxer->container) - { - gst_element_set_state(muxer->container, GST_STATE_NULL); gst_object_unref(muxer->container); - } free(muxer);
return status; @@ -165,6 +195,7 @@ NTSTATUS wg_muxer_destroy(void *args) stream_free(stream); } gst_object_unref(muxer->my_sink); + gst_caps_unref(muxer->my_sink_caps); gst_element_set_state(muxer->container, GST_STATE_NULL); gst_object_unref(muxer->container); free(muxer); @@ -181,7 +212,7 @@ NTSTATUS wg_muxer_add_stream(void *args) struct wg_muxer_stream *stream; char src_pad_name[64];
- GST_DEBUG("muxer %p, stream_id %u, format %p.", muxer, params->stream_id, params->format); + GST_DEBUG("muxer %p, stream %u, format %p.", muxer, params->stream_id, params->format);
/* Create stream object. */ if (!(stream = calloc(1, sizeof(*stream)))) @@ -200,6 +231,21 @@ NTSTATUS wg_muxer_add_stream(void *args) goto out; gst_pad_set_element_private(stream->my_src, stream);
+ /* Create parser. */ + if ((stream->parser = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, GST_RANK_NONE, stream->my_src_caps, NULL))) + { + GstPad *parser_src = gst_element_get_static_pad(stream->parser, "src"); + gchar *parser_name = gst_element_get_name(stream->parser); + + gst_bin_add(GST_BIN(muxer->container), stream->parser); + stream->parser_src_caps = gst_pad_query_caps(parser_src, NULL); + GST_INFO("Create parser %s %p for stream %u %p.", + parser_name, stream->parser, stream->id, stream); + + g_free(parser_name); + gst_object_unref(parser_src); + } + /* Add to muxer stream list. */ list_add_tail(&muxer->streams, &stream->entry);
@@ -220,3 +266,61 @@ out:
return status; } + +NTSTATUS wg_muxer_start(void *args) +{ + struct wg_muxer *muxer = get_muxer(*(wg_muxer_t *)args); + NTSTATUS status = STATUS_UNSUCCESSFUL; + struct wg_muxer_stream *stream; + bool link_ok; + + GST_DEBUG("muxer %p.", muxer); + + /* Create muxer element. */ + if (!(muxer->muxer = muxer_find_muxer(muxer)) + || !gst_bin_add(GST_BIN(muxer->container), muxer->muxer)) + return status; + + /* Link muxer element to my_sink */ + if (!link_element_to_sink(muxer->muxer, muxer->my_sink) + || !gst_pad_set_active(muxer->my_sink, 1)) + return status; + + /* Link my_src of each stream to muxer element. */ + LIST_FOR_EACH_ENTRY(stream, &muxer->streams, struct wg_muxer_stream, entry) + { + if (stream->parser) + link_ok = link_src_to_element(stream->my_src, stream->parser) + && gst_element_link(stream->parser, muxer->muxer); + else + link_ok = link_src_to_element(stream->my_src, muxer->muxer); + + if (!link_ok) + return status; + } + + /* Set to pause state. */ + if (gst_element_set_state(muxer->container, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) + return status; + if (gst_element_get_state(muxer->container, NULL, NULL, -1) == GST_STATE_CHANGE_FAILURE) + return status; + + /* Active stream my_src pad and push events to prepare for streaming. */ + LIST_FOR_EACH_ENTRY(stream, &muxer->streams, struct wg_muxer_stream, entry) + { + char buffer[64]; + + sprintf(buffer, "wg_muxer_stream_src_%u", stream->id); + gst_segment_init(&stream->segment, GST_FORMAT_BYTES); + if (!gst_pad_set_active(stream->my_src, 1)) + return status; + if (!push_event(stream->my_src, gst_event_new_stream_start(buffer)) + || !push_event(stream->my_src, gst_event_new_caps(stream->my_src_caps)) + || !push_event(stream->my_src, gst_event_new_segment(&stream->segment))) + return status; + } + + GST_DEBUG("Started muxer %p.", muxer); + + return STATUS_SUCCESS; +} diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 2d2e3450ccb..072dc93ee49 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1946,6 +1946,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_muxer_create), X(wg_muxer_destroy), X(wg_muxer_add_stream), + X(wg_muxer_start), };
C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_wg_funcs_count); @@ -2233,6 +2234,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X64(wg_muxer_create), X(wg_muxer_destroy), X64(wg_muxer_add_stream), + X(wg_muxer_start), };
C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_wg_funcs_count);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 21 ++++++++ dlls/winegstreamer/media_sink.c | 88 ++++++++++++++++++++++++++++++- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 8 +++ dlls/winegstreamer/wg_muxer.c | 5 ++ dlls/winegstreamer/wg_parser.c | 19 +++++++ 7 files changed, 141 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 38516ba9024..1355171c751 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -114,6 +114,7 @@ HRESULT wg_muxer_create(const char *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); HRESULT wg_muxer_start(wg_muxer_t muxer); +HRESULT wg_muxer_push_sample(wg_muxer_t muxer, struct wg_sample *sample, UINT32 stream_id);
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 95c4296812b..eddd2a45661 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -522,6 +522,27 @@ HRESULT wg_muxer_start(wg_muxer_t muxer) return S_OK; }
+HRESULT wg_muxer_push_sample(wg_muxer_t muxer, struct wg_sample *sample, UINT32 steam_id) +{ + struct wg_muxer_push_sample_params params = + { + .muxer = muxer, + .sample = sample, + .stream_id = steam_id, + }; + NTSTATUS status; + + TRACE("muxer %#I64x, sample %p.\n", muxer, sample); + + if ((status = WINE_UNIX_CALL(unix_wg_muxer_push_sample, ¶ms))) + { + WARN("Failed to push sample, status %#lx.\n", status); + return HRESULT_FROM_NT(status); + } + + return S_OK; +} + #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 489ede1d26a..d9c15291b61 100644 --- a/dlls/winegstreamer/media_sink.c +++ b/dlls/winegstreamer/media_sink.c @@ -31,6 +31,7 @@ enum async_op ASYNC_START, ASYNC_STOP, ASYNC_PAUSE, + ASYNC_PROCESS, };
struct async_command @@ -39,6 +40,15 @@ struct async_command LONG refcount;
enum async_op op; + + union + { + struct + { + IMFSample *sample; + UINT32 stream_id; + } process; + } u; };
struct stream_sink @@ -142,7 +152,11 @@ static ULONG WINAPI async_command_Release(IUnknown *iface) ULONG refcount = InterlockedDecrement(&command->refcount);
if (!refcount) + { + if (command->op == ASYNC_PROCESS && command->u.process.sample) + IMFSample_Release(command->u.process.sample); free(command); + }
return refcount; } @@ -301,9 +315,41 @@ static HRESULT WINAPI stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFM
static HRESULT WINAPI stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) { - FIXME("iface %p, sample %p stub!\n", iface, sample); + struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface); + struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(stream_sink->media_sink); + struct async_command *command; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, sample %p.\n", iface, sample); + + EnterCriticalSection(&media_sink->cs); + + if (media_sink->state == STATE_SHUTDOWN) + { + LeaveCriticalSection(&media_sink->cs); + return MF_E_SHUTDOWN; + } + + if (media_sink->state != STATE_STARTED && media_sink->state != STATE_PAUSED) + { + LeaveCriticalSection(&media_sink->cs); + return MF_E_INVALIDREQUEST; + } + + if (FAILED(hr = (async_command_create(ASYNC_PROCESS, &command)))) + { + LeaveCriticalSection(&media_sink->cs); + return hr; + } + IMFSample_AddRef((command->u.process.sample = sample)); + command->u.process.stream_id = stream_sink->id; + + if (FAILED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &media_sink->async_callback, &command->IUnknown_iface))) + IUnknown_Release(&command->IUnknown_iface); + + LeaveCriticalSection(&media_sink->cs); + + return hr; }
static HRESULT WINAPI stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, @@ -521,6 +567,40 @@ static HRESULT media_sink_pause(struct media_sink *media_sink) return media_sink_queue_stream_event(media_sink, MEStreamSinkPaused); }
+static HRESULT media_sink_process(struct media_sink *media_sink, IMFSample *sample, UINT32 stream_id) +{ + wg_muxer_t muxer = media_sink->muxer; + struct wg_sample *wg_sample; + LONGLONG time, duration; + UINT32 value; + HRESULT hr; + + TRACE("media_sink %p, sample %p, stream_id %u.\n", media_sink, sample, stream_id); + + if (FAILED(hr = wg_sample_create_mf(sample, &wg_sample))) + return hr; + + if (SUCCEEDED(IMFSample_GetSampleTime(sample, &time))) + { + wg_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; + wg_sample->pts = time; + } + if (SUCCEEDED(IMFSample_GetSampleDuration(sample, &duration))) + { + wg_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; + wg_sample->duration = duration; + } + if (SUCCEEDED(IMFSample_GetUINT32(sample, &MFSampleExtension_CleanPoint, &value)) && value) + wg_sample->flags |= WG_SAMPLE_FLAG_SYNC_POINT; + if (SUCCEEDED(IMFSample_GetUINT32(sample, &MFSampleExtension_Discontinuity, &value)) && value) + wg_sample->flags |= WG_SAMPLE_FLAG_DISCONTINUITY; + + hr = wg_muxer_push_sample(muxer, wg_sample, stream_id); + wg_sample_release(wg_sample); + + return hr; +} + static HRESULT WINAPI media_sink_QueryInterface(IMFFinalizableMediaSink *iface, REFIID riid, void **obj) { struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface); @@ -1022,6 +1102,10 @@ static HRESULT WINAPI media_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsy case ASYNC_PAUSE: hr = media_sink_pause(media_sink); break; + case ASYNC_PROCESS: + if (FAILED(hr = media_sink_process(media_sink, command->u.process.sample, command->u.process.stream_id))) + WARN("Failed to process sample, hr %#lx.\n", hr); + break; default: WARN("Unsupported op %u.\n", command->op); break; diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index bc88a91f256..e66a73eacec 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -69,6 +69,7 @@ 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; extern NTSTATUS wg_muxer_start(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_muxer_push_sample(void *args) DECLSPEC_HIDDEN;
/* wg_allocator.c */
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 9cb6359af26..d20b8907925 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -379,6 +379,13 @@ struct wg_muxer_add_stream_params const struct wg_format *format; };
+struct wg_muxer_push_sample_params +{ + wg_muxer_t muxer; + struct wg_sample *sample; + UINT32 stream_id; +}; + enum unix_funcs { unix_wg_init_gstreamer, @@ -423,6 +430,7 @@ enum unix_funcs unix_wg_muxer_destroy, unix_wg_muxer_add_stream, unix_wg_muxer_start, + unix_wg_muxer_push_sample,
unix_wg_funcs_count, }; diff --git a/dlls/winegstreamer/wg_muxer.c b/dlls/winegstreamer/wg_muxer.c index 347044e7979..10f642e26ca 100644 --- a/dlls/winegstreamer/wg_muxer.c +++ b/dlls/winegstreamer/wg_muxer.c @@ -324,3 +324,8 @@ NTSTATUS wg_muxer_start(void *args)
return STATUS_SUCCESS; } + +NTSTATUS wg_muxer_push_sample(void *args) +{ + return STATUS_NOT_IMPLEMENTED; +} diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 072dc93ee49..922981137f1 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1947,6 +1947,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_muxer_destroy), X(wg_muxer_add_stream), X(wg_muxer_start), + X(wg_muxer_push_sample), };
C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_wg_funcs_count); @@ -2190,6 +2191,23 @@ NTSTATUS wow64_wg_muxer_add_stream(void *args) return wg_muxer_add_stream(¶ms); }
+NTSTATUS wow64_wg_muxer_push_sample(void *args) +{ + struct + { + wg_muxer_t muxer; + PTR32 sample; + UINT32 stream_id; + } *params32 = args; + struct wg_muxer_push_sample_params params = + { + .muxer = params32->muxer, + .sample = ULongToPtr(params32->sample), + .stream_id = params32->stream_id, + }; + return wg_muxer_push_sample(¶ms); +} + const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { #define X64(name) [unix_ ## name] = wow64_ ## name @@ -2235,6 +2253,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = X(wg_muxer_destroy), X64(wg_muxer_add_stream), X(wg_muxer_start), + X64(wg_muxer_push_sample), };
C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_wg_funcs_count);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/wg_muxer.c | 105 +++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/wg_muxer.c b/dlls/winegstreamer/wg_muxer.c index 10f642e26ca..db037ae847a 100644 --- a/dlls/winegstreamer/wg_muxer.c +++ b/dlls/winegstreamer/wg_muxer.c @@ -38,6 +38,9 @@ struct wg_muxer GstPad *my_sink; GstCaps *my_sink_caps;
+ pthread_mutex_t mutex; + guint64 offset; + struct list streams; };
@@ -60,6 +63,19 @@ static struct wg_muxer *get_muxer(wg_muxer_t muxer) return (struct wg_muxer *)(ULONG_PTR)muxer; }
+static struct wg_muxer_stream *muxer_get_stream_by_id(struct wg_muxer *muxer, DWORD id) +{ + struct wg_muxer_stream *stream; + + LIST_FOR_EACH_ENTRY(stream, &muxer->streams, struct wg_muxer_stream, entry) + { + if (stream->id == id) + return stream; + } + + return NULL; +} + static bool muxer_try_muxer_factory(struct wg_muxer *muxer, GstElementFactory *muxer_factory) { gchar *plugin_name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(muxer_factory)); @@ -126,6 +142,46 @@ static gboolean muxer_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *qu } }
+static gboolean muxer_sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) +{ + struct wg_muxer *muxer = gst_pad_get_element_private(pad); + const GstSegment *segment; + + GST_DEBUG("pad %p, parent %p, event %p, muxer %p, type "%s".", + pad, parent, event, muxer, GST_EVENT_TYPE_NAME(event)); + + switch (event->type) + { + case GST_EVENT_SEGMENT: + pthread_mutex_lock(&muxer->mutex); + + gst_event_parse_segment(event, &segment); + if (segment->format != GST_FORMAT_BYTES) + { + pthread_mutex_unlock(&muxer->mutex); + GST_FIXME("Unhandled segment format "%s".", gst_format_get_name(segment->format)); + break; + } + muxer->offset = segment->start; + + pthread_mutex_unlock(&muxer->mutex); + break; + + default: + GST_WARNING("Ignoring "%s" event.", GST_EVENT_TYPE_NAME(event)); + break; + } + + gst_event_unref(event); + return TRUE; +} + +static GstFlowReturn muxer_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) +{ + GST_FIXME("Stub."); + return GST_FLOW_ERROR; +} + static void stream_free(struct wg_muxer_stream *stream) { if (stream->parser_src_caps) @@ -146,6 +202,8 @@ NTSTATUS wg_muxer_create(void *args) if (!(muxer = calloc(1, sizeof(*muxer)))) return STATUS_NO_MEMORY; list_init(&muxer->streams); + muxer->offset = GST_BUFFER_OFFSET_NONE; + pthread_mutex_init(&muxer->mutex, NULL); if (!(muxer->container = gst_bin_new("wg_muxer"))) goto out;
@@ -162,6 +220,8 @@ NTSTATUS wg_muxer_create(void *args) goto out; gst_pad_set_element_private(muxer->my_sink, muxer); gst_pad_set_query_function(muxer->my_sink, muxer_sink_query_cb); + gst_pad_set_event_function(muxer->my_sink, muxer_sink_event_cb); + gst_pad_set_chain_function(muxer->my_sink, muxer_sink_chain_cb);
gst_object_unref(template);
@@ -179,6 +239,7 @@ out: gst_caps_unref(muxer->my_sink_caps); if (muxer->container) gst_object_unref(muxer->container); + pthread_mutex_destroy(&muxer->mutex); free(muxer);
return status; @@ -194,10 +255,14 @@ NTSTATUS wg_muxer_destroy(void *args) list_remove(&stream->entry); stream_free(stream); } + gst_object_unref(muxer->my_sink); gst_caps_unref(muxer->my_sink_caps); gst_element_set_state(muxer->container, GST_STATE_NULL); gst_object_unref(muxer->container); + + pthread_mutex_destroy(&muxer->mutex); + free(muxer);
return S_OK; @@ -327,5 +392,43 @@ NTSTATUS wg_muxer_start(void *args)
NTSTATUS wg_muxer_push_sample(void *args) { - return STATUS_NOT_IMPLEMENTED; + struct wg_muxer_push_sample_params *params = args; + struct wg_muxer *muxer = get_muxer(params->muxer); + struct wg_sample *sample = params->sample; + struct wg_muxer_stream *stream; + GstFlowReturn ret; + GstBuffer *buffer; + + if (!(stream = muxer_get_stream_by_id(muxer, params->stream_id))) + return STATUS_NOT_FOUND; + + /* Create sample data buffer. */ + if (!(buffer = gst_buffer_new_and_alloc(sample->size)) + || !gst_buffer_fill(buffer, 0, wg_sample_data(sample), sample->size)) + { + GST_ERROR("Failed to allocate input buffer."); + return STATUS_NO_MEMORY; + } + + GST_INFO("Copied %u bytes from sample %p to buffer %p.", sample->size, sample, buffer); + + /* Set sample properties. */ + if (sample->flags & WG_SAMPLE_FLAG_HAS_PTS) + GST_BUFFER_PTS(buffer) = sample->pts * 100; + if (sample->flags & WG_SAMPLE_FLAG_HAS_DURATION) + GST_BUFFER_DURATION(buffer) = sample->duration * 100; + if (!(sample->flags & WG_SAMPLE_FLAG_SYNC_POINT)) + GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); + if (sample->flags & WG_SAMPLE_FLAG_DISCONTINUITY) + GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DISCONT); + + /* Push sample data buffer to stream src pad. */ + if ((ret = gst_pad_push(stream->my_src, buffer)) < 0) + { + GST_ERROR("Failed to push buffer %p to pad %s, reason %s.", + buffer, gst_pad_get_name(stream->my_src), gst_flow_get_name(ret)); + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; }
I've submitted a newer version implementing manually autoplug. It is much much more simpler than the previous version. Also, the code amount is nearly identical to the my local version using encodebin. The difference between this version and encodebin version is the function muxer_find_muxer(), encodebin doesn't need to find muxer, but it requires creating a encode profile. So the code amount here is nearly the same.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/unixlib.c:
return false; }
- if ((ret = gst_pad_link(src_pad, sink_pad)))
- return true;
+}
+bool link_src_to_element(GstPad *src_pad, GstElement *element) {
gchar *src_name = gst_pad_get_name(src_pad), *sink_name = gst_pad_get_name(sink_pad);
GST_ERROR("Failed to link element pad %s with pad %s", src_name, sink_name);
g_free(sink_name);
- GstPad *sink_pad;
- bool ret;
- if (!(sink_pad = gst_element_get_compatible_pad(element, src_pad, NULL)))
I'd change `gst_element_get_static_pad` to `gst_element_get_compatible_pad` in a separate commit.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/unixlib.c:
GstPadLinkReturn ret;
GstPad *sink_pad;
if (!(sink_pad = gst_element_get_static_pad(element, "sink")))
- if ((ret = gst_pad_link(src_pad, sink_pad)) != GST_PAD_LINK_OK) {
gchar *name = gst_element_get_name(element);
GST_ERROR("Failed to find sink pad on %s", name);
g_free(name);
gchar *src_name = gst_pad_get_name(src_pad), *sink_name = gst_pad_get_name(sink_pad);
GST_ERROR("Failed to link src pad %s to sink pad %s, reason: %s",
src_name, sink_name, gst_pad_link_get_name(ret));
g_free(sink_name);
g_free(src_name);
You could maybe start using `GST_PTR_FORMAT` instead, as in https://gitlab.winehq.org/wine/wine/-/merge_requests/3938/diffs?commit_id=50..., it would simplify a lot the error paths, here and below. It works with pads and elements, and pretty much every GstObject.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/wg_transform.c:
case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_WMV:
if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps))
if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, GST_RANK_MARGINAL, src_caps, raw_caps))
We could use `GST_RANK_NONE` all the time, changed in a previous commit.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/unixlib.c:
return element;
}
+GstElement *create_element_by_factory(GstElementFactory *factory) +{
- gchar *plugin_name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
- GstElement *element;
- if ((element = gst_element_factory_create(factory, NULL)))
- {
gchar *element_name = gst_element_get_name(element);
GST_INFO("Created element %s %p by factory %s.", element_name, element, plugin_name);
Same here, I suspect `GST_PTR_FORMAT` would do a great job both for the factory and the element.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/unixlib.c:
return element;
}
+GstElement *create_element_by_factory(GstElementFactory *factory)
NP: `create_element_from_factory` or `factory_create_element` or just `create_element`.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/unix_private.h:
extern GstStreamType stream_type_from_caps(GstCaps *caps) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; -extern GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) DECLSPEC_HIDDEN; +extern GList *find_element_factory(GstElementFactoryListType type, GstRank min_rank,
```suggestion:-0+0 extern GList *find_element_factories(GstElementFactoryListType type, GstRank min_rank, ```
As there's more than one. Mind changing the commit title too.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/wg_muxer.c:
gst_pad_set_element_private(stream->my_src, stream);
- /* Create parser. */
- if ((stream->parser = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, GST_RANK_NONE, stream->my_src_caps, NULL)))
- {
GstPad *parser_src = gst_element_get_static_pad(stream->parser, "src");
gchar *parser_name = gst_element_get_name(stream->parser);
gst_bin_add(GST_BIN(muxer->container), stream->parser);
stream->parser_src_caps = gst_pad_query_caps(parser_src, NULL);
GST_INFO("Create parser %s %p for stream %u %p.",
parser_name, stream->parser, stream->id, stream);
g_free(parser_name);
gst_object_unref(parser_src);
- }
I'd split the parser creation in a separate commit. Maybe you could try to link it here already, and remove it if that fails instead of waiting until the muxer has been chosen?
Haven't really looked at the last two changes yet (fwiw maybe you should split the MR, to make it simpler), the muxer creation looks much simpler and mostly good to me now.
On Fri Oct 27 01:38:36 2023 +0000, Rémi Bernon wrote:
Haven't really looked at the last two changes yet (fwiw maybe you should split the MR, to make it simpler), the muxer creation looks much simpler and mostly good to me now.
I'll split the MR, submit a new MR which contains helper functions and add_stream implementation today.
Splitted first several commits from this MR to !4195, this MR will be updated after !4195 is merged.
I've submitted a newer version implementing manually autoplug. It is much much more simpler than the previous version. Also, the code amount is nearly identical to the my local version using encodebin. The difference between this version and encodebin version is the function muxer_find_muxer() and parser creation, encodebin doesn't need to find muxer and parser, but it requires creating a encode profile. So the code amount here is nearly the same.
Alright, that makes sense.
We could use `GST_RANK_NONE` all the time, changed in a previous commit.
I really don't think we want to do this.
Split second part to !4242.
This merge request was closed by Ziqing Hui.
Split the final part to !4316. And Close this MR.