Rebase against 23c6dd55b8c983ec88cada0a6d6c75ee9cd93976.

This commit is contained in:
Zebediah Figura 2020-09-29 15:52:53 -05:00
parent 639755741e
commit 76a479203b
9 changed files with 7 additions and 1520 deletions

View File

@ -1,2 +1,5 @@
Fixes: [47699] Multiple games fail to connect to online services (missing BCryptSecretAgreement / BCryptDeriveKey implementation)
# Needs to be moved to the unix lib, but that's a nontrivial amount of work, and
# using gcrypt is the wrong way forward (we should expose the missing APIs from
# gnutls instead).
Disabled: true

View File

@ -1,33 +0,0 @@
From d037faddfa629e54b5ba13d57f2e4c185de2a555 Mon Sep 17 00:00:00 2001
From: Christian Costa <titan.costa@gmail.com>
Date: Tue, 4 Nov 2014 22:25:58 +0100
Subject: d3dx9_36: No need to fail if we don't support vertices reordering in
D3DXMESHOPT_ATTRSORT
A non optimized mesh does not prevent rendering as long as we return valid data to the application.
In our case we provided an identity remapping array when no vertices reordering is done.
Avencast demo works perfectly well (using native effects functions).
---
dlls/d3dx9_36/mesh.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c
index 6f268f2..b15e033 100644
--- a/dlls/d3dx9_36/mesh.c
+++ b/dlls/d3dx9_36/mesh.c
@@ -1700,11 +1700,7 @@ static HRESULT WINAPI d3dx9_mesh_OptimizeInplace(ID3DXMesh *iface, DWORD flags,
if (FAILED(hr)) goto cleanup;
} else if (flags & D3DXMESHOPT_ATTRSORT) {
if (!(flags & D3DXMESHOPT_IGNOREVERTS))
- {
FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
- hr = E_NOTIMPL;
- goto cleanup;
- }
hr = iface->lpVtbl->LockAttributeBuffer(iface, 0, &attrib_buffer);
if (FAILED(hr)) goto cleanup;
--
2.1.3

View File

@ -1 +0,0 @@
Fixes: [48529] Avencast fails to launch

View File

@ -1,394 +0,0 @@
From 76ebf639f8c353cba828c0dfb26fdc0e01318098 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Mon, 30 Mar 2020 14:19:35 -0500
Subject: [PATCH] winegstreamer: Add a GstPad wrapping the media source's
bytestream.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_cbs.c | 58 +++++++++
dlls/winegstreamer/gst_cbs.h | 12 +-
dlls/winegstreamer/main.c | 3 +
dlls/winegstreamer/media_source.c | 189 +++++++++++++++++++++++++++++-
4 files changed, 258 insertions(+), 4 deletions(-)
diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
index bf7103b1606..12b53bc5d68 100644
--- a/dlls/winegstreamer/gst_cbs.c
+++ b/dlls/winegstreamer/gst_cbs.c
@@ -49,6 +49,8 @@ static void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user)
if (cbdata->type < GSTDEMUX_MAX)
perform_cb_gstdemux(cbdata);
+ else if (cbdata->type < MEDIA_SOURCE_MAX)
+ perform_cb_media_source(cbdata);
pthread_mutex_lock(&cbdata->lock);
cbdata->finished = 1;
@@ -301,3 +303,59 @@ gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
return cbdata.u.query_sink_data.ret;
}
+
+GstFlowReturn bytestream_wrapper_pull_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
+ GstBuffer **buf)
+{
+ struct cb_data cbdata = { BYTESTREAM_WRAPPER_PULL };
+
+ cbdata.u.getrange_data.pad = pad;
+ cbdata.u.getrange_data.parent = parent;
+ cbdata.u.getrange_data.ofs = ofs;
+ cbdata.u.getrange_data.len = len;
+ cbdata.u.getrange_data.buf = buf;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.getrange_data.ret;
+}
+
+gboolean bytestream_query_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
+{
+ struct cb_data cbdata = { BYTESTREAM_QUERY };
+
+ cbdata.u.query_function_data.pad = pad;
+ cbdata.u.query_function_data.parent = parent;
+ cbdata.u.query_function_data.query = query;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.query_function_data.ret;
+}
+
+gboolean bytestream_pad_mode_activate_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
+{
+ struct cb_data cbdata = { BYTESTREAM_PAD_MODE_ACTIVATE };
+
+ cbdata.u.activate_mode_data.pad = pad;
+ cbdata.u.activate_mode_data.parent = parent;
+ cbdata.u.activate_mode_data.mode = mode;
+ cbdata.u.activate_mode_data.activate = activate;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.activate_mode_data.ret;
+}
+
+gboolean bytestream_pad_event_process_wrapper(GstPad *pad, GstObject *parent, GstEvent *event)
+{
+ struct cb_data cbdata = { BYTESTREAM_PAD_EVENT_PROCESS };
+
+ cbdata.u.event_src_data.pad = pad;
+ cbdata.u.event_src_data.parent = parent;
+ cbdata.u.event_src_data.event = event;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.event_src_data.ret;
+}
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
index 4725f23ad1a..3459a9ef8ee 100644
--- a/dlls/winegstreamer/gst_cbs.h
+++ b/dlls/winegstreamer/gst_cbs.h
@@ -43,7 +43,12 @@ enum CB_TYPE {
AUTOPLUG_BLACKLIST,
UNKNOWN_TYPE,
QUERY_SINK,
- GSTDEMUX_MAX
+ GSTDEMUX_MAX,
+ BYTESTREAM_WRAPPER_PULL,
+ BYTESTREAM_QUERY,
+ BYTESTREAM_PAD_MODE_ACTIVATE,
+ BYTESTREAM_PAD_EVENT_PROCESS,
+ MEDIA_SOURCE_MAX,
};
struct cb_data {
@@ -138,6 +143,7 @@ struct cb_data {
void mark_wine_thread(void) DECLSPEC_HIDDEN;
void perform_cb_gstdemux(struct cb_data *data) DECLSPEC_HIDDEN;
+void perform_cb_media_source(struct cb_data *data) DECLSPEC_HIDDEN;
GstBusSyncReply watch_bus_wrapper(GstBus *bus, GstMessage *msg, gpointer user) DECLSPEC_HIDDEN;
void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
@@ -154,5 +160,9 @@ GstAutoplugSelectResult autoplug_blacklist_wrapper(GstElement *bin, GstPad *pad,
void unknown_type_wrapper(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer user) DECLSPEC_HIDDEN;
void Gstreamer_transform_pad_added_wrapper(GstElement *filter, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
+GstFlowReturn bytestream_wrapper_pull_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len, GstBuffer **buf) DECLSPEC_HIDDEN;
+gboolean bytestream_query_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
+gboolean bytestream_pad_mode_activate_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN;
+gboolean bytestream_pad_event_process_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN;
#endif
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index 2872710b3e2..4ca371d58bd 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -146,6 +146,9 @@ 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;
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index f365c8a1827..1accf55c6a2 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -17,9 +17,15 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "config.h"
+
+#include <gst/gst.h>
+
#include "gst_private.h"
+#include "gst_cbs.h"
#include <stdarg.h>
+#include <assert.h>
#define COBJMACROS
#define NONAMELESSUNION
@@ -27,6 +33,7 @@
#include "mfapi.h"
#include "mferror.h"
#include "mfidl.h"
+#include "mfobjects.h"
#include "wine/debug.h"
#include "wine/heap.h"
@@ -39,6 +46,8 @@ struct media_source
IMFMediaSource IMFMediaSource_iface;
LONG ref;
IMFMediaEventQueue *event_queue;
+ IMFByteStream *byte_stream;
+ GstPad *my_src;
enum
{
SOURCE_OPENING,
@@ -52,6 +61,127 @@ static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *ifac
return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
}
+static GstFlowReturn bytestream_wrapper_pull(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
+ GstBuffer **buf)
+{
+ struct media_source *source = gst_pad_get_element_private(pad);
+ IMFByteStream *byte_stream = source->byte_stream;
+ ULONG bytes_read;
+ GstMapInfo info;
+ BOOL is_eof;
+ HRESULT hr;
+
+ TRACE("requesting %u bytes at %s from source %p into buffer %p\n", len, wine_dbgstr_longlong(ofs), source, *buf);
+
+ if (ofs != GST_BUFFER_OFFSET_NONE)
+ {
+ if (FAILED(IMFByteStream_SetCurrentPosition(byte_stream, ofs)))
+ return GST_FLOW_ERROR;
+ }
+
+ if (FAILED(IMFByteStream_IsEndOfStream(byte_stream, &is_eof)))
+ return GST_FLOW_ERROR;
+ if (is_eof)
+ return GST_FLOW_EOS;
+
+ if (!(*buf))
+ *buf = gst_buffer_new_and_alloc(len);
+ gst_buffer_map(*buf, &info, GST_MAP_WRITE);
+ hr = IMFByteStream_Read(byte_stream, info.data, len, &bytes_read);
+ gst_buffer_unmap(*buf, &info);
+
+ gst_buffer_set_size(*buf, bytes_read);
+
+ if (FAILED(hr))
+ return GST_FLOW_ERROR;
+ return GST_FLOW_OK;
+}
+
+static gboolean bytestream_query(GstPad *pad, GstObject *parent, GstQuery *query)
+{
+ struct media_source *source = gst_pad_get_element_private(pad);
+ GstFormat format;
+ QWORD bytestream_len;
+
+ TRACE("GStreamer queries source %p for %s\n", source, GST_QUERY_TYPE_NAME(query));
+
+ if (FAILED(IMFByteStream_GetLength(source->byte_stream, &bytestream_len)))
+ return FALSE;
+
+ switch (GST_QUERY_TYPE(query))
+ {
+ case GST_QUERY_DURATION:
+ {
+ gst_query_parse_duration(query, &format, NULL);
+ if (format == GST_FORMAT_PERCENT)
+ {
+ gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
+ return TRUE;
+ }
+ else if (format == GST_FORMAT_BYTES)
+ {
+ QWORD length;
+ IMFByteStream_GetLength(source->byte_stream, &length);
+ gst_query_set_duration(query, GST_FORMAT_BYTES, length);
+ return TRUE;
+ }
+ return FALSE;
+ }
+ case GST_QUERY_SEEKING:
+ {
+ gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
+ if (format != GST_FORMAT_BYTES)
+ {
+ WARN("Cannot seek using format \"%s\".\n", gst_format_get_name(format));
+ return FALSE;
+ }
+ gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, bytestream_len);
+ return TRUE;
+ }
+ case GST_QUERY_SCHEDULING:
+ {
+ gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
+ gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL);
+ return TRUE;
+ }
+ default:
+ {
+ WARN("Unhandled query type %s\n", GST_QUERY_TYPE_NAME(query));
+ return FALSE;
+ }
+ }
+}
+
+static gboolean bytestream_pad_mode_activate(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
+{
+ struct media_source *source = gst_pad_get_element_private(pad);
+
+ TRACE("%s source pad for mediasource %p in %s mode.\n",
+ activate ? "Activating" : "Deactivating", source, gst_pad_mode_get_name(mode));
+
+ return mode == GST_PAD_MODE_PULL;
+}
+
+static gboolean bytestream_pad_event_process(GstPad *pad, GstObject *parent, GstEvent *event)
+{
+ struct media_source *source = gst_pad_get_element_private(pad);
+
+ TRACE("source %p, type \"%s\".\n", source, GST_EVENT_TYPE_NAME(event));
+
+ switch (event->type) {
+ /* the seek event should fail in pull mode */
+ case GST_EVENT_SEEK:
+ return FALSE;
+ default:
+ WARN("Ignoring \"%s\" event.\n", GST_EVENT_TYPE_NAME(event));
+ case GST_EVENT_TAG:
+ case GST_EVENT_QOS:
+ case GST_EVENT_RECONFIGURE:
+ return gst_pad_event_default(pad, parent, event);
+ }
+ return TRUE;
+}
+
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
@@ -211,8 +341,12 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
source->state = SOURCE_SHUTDOWN;
+ if (source->my_src)
+ gst_object_unref(GST_OBJECT(source->my_src));
if (source->event_queue)
IMFMediaEventQueue_Shutdown(source->event_queue);
+ if (source->byte_stream)
+ IMFByteStream_Release(source->byte_stream);
return S_OK;
}
@@ -236,19 +370,31 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
{
+ GstStaticPadTemplate src_template =
+ GST_STATIC_PAD_TEMPLATE("mf_src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
+
struct media_source *object = heap_alloc_zero(sizeof(*object));
HRESULT hr;
if (!object)
return E_OUTOFMEMORY;
+ object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
+ object->ref = 1;
+ object->byte_stream = bytestream;
+ IMFByteStream_AddRef(bytestream);
+
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
- object->state = SOURCE_STOPPED;
+ object->my_src = gst_pad_new_from_static_template(&src_template, "mf-src");
+ gst_pad_set_element_private(object->my_src, object);
+ gst_pad_set_getrange_function(object->my_src, bytestream_wrapper_pull_wrapper);
+ gst_pad_set_query_function(object->my_src, bytestream_query_wrapper);
+ gst_pad_set_activatemode_function(object->my_src, bytestream_pad_mode_activate_wrapper);
+ gst_pad_set_event_function(object->my_src, bytestream_pad_event_process_wrapper);
- object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
- object->ref = 1;
+ object->state = SOURCE_STOPPED;
*out_media_source = object;
return S_OK;
@@ -716,3 +862,40 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj)
return hr;
}
+
+/* helper for callback forwarding */
+void perform_cb_media_source(struct cb_data *cbdata)
+{
+ switch(cbdata->type)
+ {
+ case BYTESTREAM_WRAPPER_PULL:
+ {
+ struct getrange_data *data = &cbdata->u.getrange_data;
+ cbdata->u.getrange_data.ret = bytestream_wrapper_pull(data->pad, data->parent,
+ data->ofs, data->len, data->buf);
+ break;
+ }
+ case BYTESTREAM_QUERY:
+ {
+ struct query_function_data *data = &cbdata->u.query_function_data;
+ cbdata->u.query_function_data.ret = bytestream_query(data->pad, data->parent, data->query);
+ break;
+ }
+ case BYTESTREAM_PAD_MODE_ACTIVATE:
+ {
+ struct activate_mode_data *data = &cbdata->u.activate_mode_data;
+ cbdata->u.activate_mode_data.ret = bytestream_pad_mode_activate(data->pad, data->parent, data->mode, data->activate);
+ break;
+ }
+ case BYTESTREAM_PAD_EVENT_PROCESS:
+ {
+ struct event_src_data *data = &cbdata->u.event_src_data;
+ cbdata->u.event_src_data.ret = bytestream_pad_event_process(data->pad, data->parent, data->event);
+ break;
+ }
+ default:
+ {
+ assert(0);
+ }
+ }
+}
--
2.28.0

View File

@ -1,597 +0,0 @@
From 49b2e0568ffe3e5e2ea7e9c3572ec09ef2cf8ad7 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Tue, 31 Mar 2020 13:34:57 -0500
Subject: [PATCH] winegstreamer: Use decodebin to initialize media streams.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_cbs.c | 45 ++++
dlls/winegstreamer/gst_cbs.h | 8 +
dlls/winegstreamer/media_source.c | 405 +++++++++++++++++++++++++++++-
3 files changed, 457 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c
index 12b53bc5d68..51aaefa911d 100644
--- a/dlls/winegstreamer/gst_cbs.c
+++ b/dlls/winegstreamer/gst_cbs.c
@@ -359,3 +359,48 @@ gboolean bytestream_pad_event_process_wrapper(GstPad *pad, GstObject *parent, Gs
return cbdata.u.event_src_data.ret;
}
+
+GstBusSyncReply mf_src_bus_watch_wrapper(GstBus *bus, GstMessage *message, gpointer user)
+{
+ struct cb_data cbdata = { MF_SRC_BUS_WATCH };
+
+ cbdata.u.watch_bus_data.bus = bus;
+ cbdata.u.watch_bus_data.msg = message;
+ cbdata.u.watch_bus_data.user = user;
+
+ call_cb(&cbdata);
+
+ return cbdata.u.watch_bus_data.ret;
+}
+
+void mf_src_stream_added_wrapper(GstElement *bin, GstPad *pad, gpointer user)
+{
+ struct cb_data cbdata = { MF_SRC_STREAM_ADDED };
+
+ cbdata.u.pad_added_data.element = bin;
+ cbdata.u.pad_added_data.pad = pad;
+ cbdata.u.pad_added_data.user = user;
+
+ call_cb(&cbdata);
+}
+
+void mf_src_stream_removed_wrapper(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct cb_data cbdata = { MF_SRC_STREAM_REMOVED };
+
+ cbdata.u.pad_removed_data.element = element;
+ cbdata.u.pad_removed_data.pad = pad;
+ cbdata.u.pad_removed_data.user = user;
+
+ call_cb(&cbdata);
+}
+
+void mf_src_no_more_pads_wrapper(GstElement *element, gpointer user)
+{
+ struct cb_data cbdata = { MF_SRC_NO_MORE_PADS };
+
+ cbdata.u.no_more_pads_data.element = element;
+ cbdata.u.no_more_pads_data.user = user;
+
+ call_cb(&cbdata);
+}
diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h
index 3459a9ef8ee..a48999bbf71 100644
--- a/dlls/winegstreamer/gst_cbs.h
+++ b/dlls/winegstreamer/gst_cbs.h
@@ -48,6 +48,10 @@ enum CB_TYPE {
BYTESTREAM_QUERY,
BYTESTREAM_PAD_MODE_ACTIVATE,
BYTESTREAM_PAD_EVENT_PROCESS,
+ MF_SRC_BUS_WATCH,
+ MF_SRC_STREAM_ADDED,
+ MF_SRC_STREAM_REMOVED,
+ MF_SRC_NO_MORE_PADS,
MEDIA_SOURCE_MAX,
};
@@ -164,5 +168,9 @@ GstFlowReturn bytestream_wrapper_pull_wrapper(GstPad *pad, GstObject *parent, gu
gboolean bytestream_query_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN;
gboolean bytestream_pad_mode_activate_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN;
gboolean bytestream_pad_event_process_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN;
+GstBusSyncReply mf_src_bus_watch_wrapper(GstBus *bus, GstMessage *message, gpointer user) DECLSPEC_HIDDEN;
+void mf_src_stream_added_wrapper(GstElement *bin, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
+void mf_src_stream_removed_wrapper(GstElement *element, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
+void mf_src_no_more_pads_wrapper(GstElement *element, gpointer user) DECLSPEC_HIDDEN;
#endif
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 1accf55c6a2..f61f84359d5 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -24,6 +24,7 @@
#include "gst_private.h"
#include "gst_cbs.h"
+#include <assert.h>
#include <stdarg.h>
#include <assert.h>
@@ -41,21 +42,47 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct media_stream
+{
+ IMFMediaStream IMFMediaStream_iface;
+ LONG ref;
+ struct media_source *parent_source;
+ IMFMediaEventQueue *event_queue;
+ GstElement *appsink;
+ GstPad *their_src, *my_sink;
+ enum
+ {
+ STREAM_STUB,
+ STREAM_SHUTDOWN,
+ } state;
+};
+
struct media_source
{
IMFMediaSource IMFMediaSource_iface;
LONG ref;
IMFMediaEventQueue *event_queue;
IMFByteStream *byte_stream;
- GstPad *my_src;
+ struct media_stream **streams;
+ ULONG stream_count;
+ GstBus *bus;
+ GstElement *container;
+ GstElement *decodebin;
+ GstPad *my_src, *their_sink;
enum
{
SOURCE_OPENING,
SOURCE_STOPPED,
SOURCE_SHUTDOWN,
} state;
+ HANDLE all_streams_event;
};
+static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface)
+{
+ return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface);
+}
+
static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
{
return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
@@ -182,6 +209,242 @@ static gboolean bytestream_pad_event_process(GstPad *pad, GstObject *parent, Gst
return TRUE;
}
+GstBusSyncReply bus_watch(GstBus *bus, GstMessage *message, gpointer user)
+{
+ struct media_source *source = user;
+ gchar *dbg_info = NULL;
+ GError *err = NULL;
+
+ TRACE("source %p message type %s\n", source, GST_MESSAGE_TYPE_NAME(message));
+
+ switch (message->type)
+ {
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error(message, &err, &dbg_info);
+ ERR("%s: %s\n", GST_OBJECT_NAME(message->src), err->message);
+ ERR("%s\n", dbg_info);
+ g_error_free(err);
+ g_free(dbg_info);
+ break;
+ case GST_MESSAGE_WARNING:
+ gst_message_parse_warning(message, &err, &dbg_info);
+ WARN("%s: %s\n", GST_OBJECT_NAME(message->src), err->message);
+ WARN("%s\n", dbg_info);
+ g_error_free(err);
+ g_free(dbg_info);
+ break;
+ default:
+ break;
+ }
+
+ gst_message_unref(message);
+ return GST_BUS_DROP;
+}
+
+static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%s %p)\n", stream, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFMediaStream) ||
+ IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = &stream->IMFMediaStream_iface;
+ }
+ else
+ {
+ FIXME("(%s, %p)\n", debugstr_guid(riid), out);
+ *out = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+ ULONG ref = InterlockedIncrement(&stream->ref);
+
+ TRACE("(%p) ref=%u\n", stream, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ ULONG ref = InterlockedDecrement(&stream->ref);
+
+ TRACE("(%p) ref=%u\n", stream, ref);
+
+ if (!ref)
+ {
+ if (stream->my_sink)
+ gst_object_unref(GST_OBJECT(stream->my_sink));
+ if (stream->event_queue)
+ IMFMediaEventQueue_Release(stream->event_queue);
+ if (stream->parent_source)
+ IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
+
+ heap_free(stream);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%#x, %p)\n", stream, flags, event);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
+}
+
+static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%p, %p)\n", stream, callback, state);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
+}
+
+static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%p, %p)\n", stream, result, event);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
+}
+
+static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
+ HRESULT hr, const PROPVARIANT *value)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%d, %s, %#x, %p)\n", stream, event_type, debugstr_guid(ext_type), hr, value);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
+}
+
+static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ FIXME("stub (%p)->(%p)\n", stream, source);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%p)\n", stream, descriptor);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
+{
+ struct media_stream *stream = impl_from_IMFMediaStream(iface);
+
+ TRACE("(%p)->(%p)\n", iface, token);
+
+ if (stream->state == STREAM_SHUTDOWN)
+ return MF_E_SHUTDOWN;
+
+ return E_NOTIMPL;
+}
+
+static const IMFMediaStreamVtbl media_stream_vtbl =
+{
+ media_stream_QueryInterface,
+ media_stream_AddRef,
+ media_stream_Release,
+ media_stream_GetEvent,
+ media_stream_BeginGetEvent,
+ media_stream_EndGetEvent,
+ media_stream_QueueEvent,
+ media_stream_GetMediaSource,
+ media_stream_GetStreamDescriptor,
+ media_stream_RequestSample
+};
+
+/* creates a stub stream */
+static HRESULT new_media_stream(struct media_source *source, GstPad *pad, struct media_stream **out_stream)
+{
+ struct media_stream *object = heap_alloc_zero(sizeof(*object));
+ HRESULT hr;
+
+ TRACE("(%p %p)->(%p)\n", source, pad, out_stream);
+
+ object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
+ object->ref = 1;
+
+ IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
+ object->parent_source = source;
+ object->their_src = pad;
+
+ object->state = STREAM_STUB;
+
+ if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
+ goto fail;
+
+ if (!(object->appsink = gst_element_factory_make("appsink", NULL)))
+ {
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+ gst_bin_add(GST_BIN(object->parent_source->container), object->appsink);
+
+ g_object_set(object->appsink, "sync", FALSE, NULL);
+ g_object_set(object->appsink, "max-buffers", 5, NULL);
+
+ object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
+ gst_pad_set_element_private(object->my_sink, object);
+
+ gst_pad_link(object->their_src, object->my_sink);
+
+ gst_element_sync_state_with_parent(object->appsink);
+
+ TRACE("->(%p)\n", object);
+ *out_stream = object;
+
+ return S_OK;
+
+fail:
+ WARN("Failed to construct media stream, hr %#x.\n", hr);
+
+ IMFMediaStream_Release(&object->IMFMediaStream_iface);
+ return hr;
+}
+
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
@@ -333,6 +596,7 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
+ unsigned int i;
TRACE("(%p)\n", source);
@@ -341,13 +605,34 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
source->state = SOURCE_SHUTDOWN;
+ if (source->container)
+ {
+ gst_element_set_state(source->container, GST_STATE_NULL);
+ gst_object_unref(GST_OBJECT(source->container));
+ }
+
if (source->my_src)
gst_object_unref(GST_OBJECT(source->my_src));
+ if (source->their_sink)
+ gst_object_unref(GST_OBJECT(source->their_sink));
+
if (source->event_queue)
IMFMediaEventQueue_Shutdown(source->event_queue);
if (source->byte_stream)
IMFByteStream_Release(source->byte_stream);
+ for (i = 0; i < source->stream_count; i++)
+ {
+ source->streams[i]->state = STREAM_SHUTDOWN;
+ IMFMediaStream_Release(&source->streams[i]->IMFMediaStream_iface);
+ }
+
+ if (source->stream_count)
+ heap_free(source->streams);
+
+ if (source->all_streams_event)
+ CloseHandle(source->all_streams_event);
+
return S_OK;
}
@@ -368,6 +653,50 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
media_source_Shutdown,
};
+static void stream_added(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct media_source *source = user;
+ struct media_stream **new_stream_array;
+ struct media_stream *stream;
+
+ if (gst_pad_get_direction(pad) != GST_PAD_SRC)
+ return;
+
+ if (FAILED(new_media_stream(source, pad, &stream)))
+ return;
+
+ if (!(new_stream_array = heap_realloc(source->streams, (source->stream_count + 1) * (sizeof(*new_stream_array)))))
+ {
+ ERR("Failed to add stream to source\n");
+ IMFMediaStream_Release(&stream->IMFMediaStream_iface);
+ return;
+ }
+
+ source->streams = new_stream_array;
+ source->streams[source->stream_count++] = stream;
+}
+
+static void stream_removed(GstElement *element, GstPad *pad, gpointer user)
+{
+ struct media_source *source = user;
+ unsigned int i;
+
+ for (i = 0; i < source->stream_count; i++)
+ {
+ struct media_stream *stream = source->streams[i];
+ if (stream->their_src != pad)
+ continue;
+ stream->their_src = NULL;
+ }
+}
+
+static void no_more_pads(GstElement *element, gpointer user)
+{
+ struct media_source *source = user;
+
+ SetEvent(source->all_streams_event);
+}
+
static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
{
GstStaticPadTemplate src_template =
@@ -375,6 +704,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
struct media_source *object = heap_alloc_zero(sizeof(*object));
HRESULT hr;
+ int ret;
if (!object)
return E_OUTOFMEMORY;
@@ -383,10 +713,16 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
object->ref = 1;
object->byte_stream = bytestream;
IMFByteStream_AddRef(bytestream);
+ object->all_streams_event = CreateEventA(NULL, FALSE, FALSE, NULL);
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
+ object->container = gst_bin_new(NULL);
+ object->bus = gst_bus_new();
+ gst_bus_set_sync_handler(object->bus, mf_src_bus_watch_wrapper, object, NULL);
+ gst_element_set_bus(object->container, object->bus);
+
object->my_src = gst_pad_new_from_static_template(&src_template, "mf-src");
gst_pad_set_element_private(object->my_src, object);
gst_pad_set_getrange_function(object->my_src, bytestream_wrapper_pull_wrapper);
@@ -394,6 +730,49 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
gst_pad_set_activatemode_function(object->my_src, bytestream_pad_mode_activate_wrapper);
gst_pad_set_event_function(object->my_src, bytestream_pad_event_process_wrapper);
+ if (!(object->decodebin = gst_element_factory_make("decodebin", NULL)))
+ {
+ WARN("Failed to create decodebin for source\n");
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+
+ /* In Media Foundation, sources will infinitely leak buffers, when a subset of the selected
+ streams are read from. This behavior is relied upon in the Unity3D engine game, Trailmakers,
+ where Unity selects both the video and audio streams, yet only reads from the video stream.
+ Removing these buffering limits reflects that behavior. */
+ g_object_set(object->decodebin, "max-size-buffers", 0, NULL);
+ g_object_set(object->decodebin, "max-size-time", G_GUINT64_CONSTANT(0), NULL);
+ g_object_set(object->decodebin, "max-size-bytes", 0, NULL);
+
+ gst_bin_add(GST_BIN(object->container), object->decodebin);
+
+ g_signal_connect(object->decodebin, "pad-added", G_CALLBACK(mf_src_stream_added_wrapper), object);
+ g_signal_connect(object->decodebin, "pad-removed", G_CALLBACK(mf_src_stream_removed_wrapper), object);
+ g_signal_connect(object->decodebin, "no-more-pads", G_CALLBACK(mf_src_no_more_pads_wrapper), object);
+
+ object->their_sink = gst_element_get_static_pad(object->decodebin, "sink");
+
+ if ((ret = gst_pad_link(object->my_src, object->their_sink)) < 0)
+ {
+ WARN("Failed to link our bytestream pad to the demuxer input\n");
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+
+ object->state = SOURCE_OPENING;
+
+ gst_element_set_state(object->container, GST_STATE_PAUSED);
+ ret = gst_element_get_state(object->container, NULL, NULL, -1);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ {
+ ERR("Failed to play source.\n");
+ hr = E_OUTOFMEMORY;
+ goto fail;
+ }
+
+ WaitForSingleObject(object->all_streams_event, INFINITE);
+
object->state = SOURCE_STOPPED;
*out_media_source = object;
@@ -893,6 +1272,30 @@ void perform_cb_media_source(struct cb_data *cbdata)
cbdata->u.event_src_data.ret = bytestream_pad_event_process(data->pad, data->parent, data->event);
break;
}
+ case MF_SRC_BUS_WATCH:
+ {
+ struct watch_bus_data *data = &cbdata->u.watch_bus_data;
+ cbdata->u.watch_bus_data.ret = bus_watch(data->bus, data->msg, data->user);
+ break;
+ }
+ case MF_SRC_STREAM_ADDED:
+ {
+ struct pad_added_data *data = &cbdata->u.pad_added_data;
+ stream_added(data->element, data->pad, data->user);
+ break;
+ }
+ case MF_SRC_STREAM_REMOVED:
+ {
+ struct pad_removed_data *data = &cbdata->u.pad_removed_data;
+ stream_removed(data->element, data->pad, data->user);
+ break;
+ }
+ case MF_SRC_NO_MORE_PADS:
+ {
+ struct no_more_pads_data *data = &cbdata->u.no_more_pads_data;
+ no_more_pads(data->element, data->user);
+ break;
+ }
default:
{
assert(0);
--
2.28.0

View File

@ -1,381 +0,0 @@
From 5119cb0704635fb1b4e30f4b67f86826b28e6015 Mon Sep 17 00:00:00 2001
From: Derek Lesho <dlesho@codeweavers.com>
Date: Fri, 11 Sep 2020 13:51:20 -0500
Subject: [PATCH] winegstreamer: Implement IMFMediaStream::GetStreamDescriptor.
Signed-off-by: Derek Lesho <dlesho@codeweavers.com>
---
dlls/winegstreamer/gst_private.h | 4 +
dlls/winegstreamer/media_source.c | 75 +++++++++++++-
dlls/winegstreamer/mfplat.c | 166 ++++++++++++++++++++++++++++++
3 files changed, 240 insertions(+), 5 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index ef07d3591e7..60b38a48f5a 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -36,6 +36,7 @@
#include "winuser.h"
#include "dshow.h"
#include "strmif.h"
+#include "mfobjects.h"
#include "wine/heap.h"
#include "wine/strmbase.h"
@@ -54,6 +55,9 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
+HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
+IMFMediaType *mf_media_type_from_caps(const GstCaps *caps) DECLSPEC_HIDDEN;
+
HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN;
#endif /* __GST_PRIVATE_INCLUDED__ */
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index f61f84359d5..723f052c10d 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -48,13 +48,17 @@ struct media_stream
LONG ref;
struct media_source *parent_source;
IMFMediaEventQueue *event_queue;
+ IMFStreamDescriptor *descriptor;
GstElement *appsink;
GstPad *their_src, *my_sink;
enum
{
STREAM_STUB,
+ STREAM_INACTIVE,
STREAM_SHUTDOWN,
} state;
+ /* used when in STUB state: */
+ DWORD stream_id;
};
struct media_source
@@ -286,6 +290,8 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
{
if (stream->my_sink)
gst_object_unref(GST_OBJECT(stream->my_sink));
+ if (stream->descriptor)
+ IMFStreamDescriptor_Release(stream->descriptor);
if (stream->event_queue)
IMFMediaEventQueue_Release(stream->event_queue);
if (stream->parent_source)
@@ -367,7 +373,10 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM
if (stream->state == STREAM_SHUTDOWN)
return MF_E_SHUTDOWN;
- return E_NOTIMPL;
+ IMFStreamDescriptor_AddRef(stream->descriptor);
+ *descriptor = stream->descriptor;
+
+ return S_OK;
}
static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
@@ -397,7 +406,7 @@ static const IMFMediaStreamVtbl media_stream_vtbl =
};
/* creates a stub stream */
-static HRESULT new_media_stream(struct media_source *source, GstPad *pad, struct media_stream **out_stream)
+static HRESULT new_media_stream(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream)
{
struct media_stream *object = heap_alloc_zero(sizeof(*object));
HRESULT hr;
@@ -410,6 +419,7 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, struct
IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
object->parent_source = source;
object->their_src = pad;
+ object->stream_id = stream_id;
object->state = STREAM_STUB;
@@ -427,8 +437,6 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, struct
g_object_set(object->appsink, "max-buffers", 5, NULL);
object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
- gst_pad_set_element_private(object->my_sink, object);
-
gst_pad_link(object->their_src, object->my_sink);
gst_element_sync_state_with_parent(object->appsink);
@@ -445,6 +453,47 @@ fail:
return hr;
}
+static HRESULT media_stream_init_desc(struct media_stream *stream)
+{
+ GstCaps *current_caps = gst_pad_get_current_caps(stream->their_src);
+ IMFMediaTypeHandler *type_handler;
+ IMFMediaType *stream_type = NULL;
+ HRESULT hr;
+
+ if (!current_caps)
+ {
+ hr = E_FAIL;
+ goto fail;
+ }
+
+ stream_type = mf_media_type_from_caps(current_caps);
+ gst_caps_unref(current_caps);
+ if (!stream_type)
+ {
+ hr = E_FAIL;
+ goto fail;
+ }
+
+ if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, 1, &stream_type, &stream->descriptor)))
+ goto fail;
+
+ if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
+ goto fail;
+
+ if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_type)))
+ goto fail;
+
+ IMFMediaTypeHandler_Release(type_handler);
+
+ stream->state = STREAM_INACTIVE;
+
+ return S_OK;
+ fail:
+ if (type_handler)
+ IMFMediaTypeHandler_Release(type_handler);
+ return hr;
+}
+
static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
{
struct media_source *source = impl_from_IMFMediaSource(iface);
@@ -662,7 +711,7 @@ static void stream_added(GstElement *element, GstPad *pad, gpointer user)
if (gst_pad_get_direction(pad) != GST_PAD_SRC)
return;
- if (FAILED(new_media_stream(source, pad, &stream)))
+ if (FAILED(new_media_stream(source, pad, source->stream_count, &stream)))
return;
if (!(new_stream_array = heap_realloc(source->streams, (source->stream_count + 1) * (sizeof(*new_stream_array)))))
@@ -687,6 +736,8 @@ static void stream_removed(GstElement *element, GstPad *pad, gpointer user)
if (stream->their_src != pad)
continue;
stream->their_src = NULL;
+ if (stream->state != STREAM_INACTIVE)
+ stream->state = STREAM_INACTIVE;
}
}
@@ -703,6 +754,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
GST_STATIC_PAD_TEMPLATE("mf_src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
struct media_source *object = heap_alloc_zero(sizeof(*object));
+ unsigned int i;
HRESULT hr;
int ret;
@@ -772,6 +824,19 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
}
WaitForSingleObject(object->all_streams_event, INFINITE);
+ for (i = 0; i < object->stream_count; i++)
+ {
+ GstSample *preroll;
+ g_signal_emit_by_name(object->streams[i]->appsink, "pull-preroll", &preroll);
+ hr = E_FAIL;
+ if (!preroll || FAILED(hr = media_stream_init_desc(object->streams[i])))
+ {
+ ERR("Failed to finish initialization of media stream %p, hr %x.\n", object->streams[i], hr);
+ IMFMediaStream_Release(&object->streams[i]->IMFMediaStream_iface);
+ goto fail;
+ }
+ gst_sample_unref(preroll);
+ }
object->state = SOURCE_STOPPED;
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index c996f06211e..2c2216f94b6 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -16,6 +16,11 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "config.h"
+#include <gst/gst.h>
+
+#include "gst_private.h"
+
#include <stdarg.h>
#include "gst_private.h"
@@ -436,3 +441,164 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
return CLASS_E_CLASSNOTAVAILABLE;
}
+
+static const struct
+{
+ const GUID *subtype;
+ GstVideoFormat format;
+}
+uncompressed_video_formats[] =
+{
+ {&MFVideoFormat_ARGB32, GST_VIDEO_FORMAT_BGRA},
+ {&MFVideoFormat_RGB32, GST_VIDEO_FORMAT_BGRx},
+ {&MFVideoFormat_RGB24, GST_VIDEO_FORMAT_BGR},
+ {&MFVideoFormat_RGB565, GST_VIDEO_FORMAT_BGR16},
+ {&MFVideoFormat_RGB555, GST_VIDEO_FORMAT_BGR15},
+};
+
+/* returns NULL if doesn't match exactly */
+IMFMediaType *mf_media_type_from_caps(const GstCaps *caps)
+{
+ IMFMediaType *media_type;
+ GstStructure *info;
+ const char *mime_type;
+
+ if (TRACE_ON(mfplat))
+ {
+ gchar *human_readable = gst_caps_to_string(caps);
+ TRACE("caps = %s\n", debugstr_a(human_readable));
+ g_free(human_readable);
+ }
+
+ if (FAILED(MFCreateMediaType(&media_type)))
+ return NULL;
+
+ info = gst_caps_get_structure(caps, 0);
+ mime_type = gst_structure_get_name(info);
+
+ if (!strncmp(mime_type, "video", 5))
+ {
+ GstVideoInfo video_info;
+
+ if (!gst_video_info_from_caps(&video_info, caps))
+ {
+ return NULL;
+ }
+
+ IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
+
+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ((UINT64)video_info.width << 32) | video_info.height);
+
+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ((UINT64)video_info.fps_n << 32) | video_info.fps_d);
+
+ if (!strcmp(mime_type, "video/x-raw"))
+ {
+ GUID fourcc_subtype = MFVideoFormat_Base;
+ unsigned int i;
+
+ IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, FALSE);
+
+ /* First try FOURCC */
+ if ((fourcc_subtype.Data1 = gst_video_format_to_fourcc(video_info.finfo->format)))
+ {
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &fourcc_subtype);
+ }
+ else
+ {
+ for (i = 0; i < ARRAY_SIZE(uncompressed_video_formats); i++)
+ {
+ if (uncompressed_video_formats[i].format == video_info.finfo->format)
+ {
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, uncompressed_video_formats[i].subtype);
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(uncompressed_video_formats))
+ {
+ FIXME("Unrecognized uncompressed video format %x\n", video_info.finfo->format);
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ FIXME("Unrecognized video format %s\n", mime_type);
+ return NULL;
+ }
+ }
+ else if (!strncmp(mime_type, "audio", 5))
+ {
+ gint rate, channels, bitrate;
+ guint64 channel_mask;
+ IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+
+ if (gst_structure_get_int(info, "rate", &rate))
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, rate);
+
+ if (gst_structure_get_int(info, "channels", &channels))
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channels);
+
+ if (gst_structure_get(info, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL))
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_CHANNEL_MASK, channel_mask);
+
+ if (gst_structure_get_int(info, "bitrate", &bitrate))
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AVG_BITRATE, bitrate);
+
+ if (!strcmp(mime_type, "audio/x-raw"))
+ {
+ GstAudioInfo audio_info;
+
+ if (gst_audio_info_from_caps(&audio_info, caps))
+ {
+ DWORD depth = GST_AUDIO_INFO_DEPTH(&audio_info);
+
+ /* validation */
+ if ((audio_info.finfo->flags & GST_AUDIO_FORMAT_FLAG_INTEGER && depth > 8) ||
+ (audio_info.finfo->flags & GST_AUDIO_FORMAT_FLAG_SIGNED && depth <= 8) ||
+ (audio_info.finfo->endianness != G_LITTLE_ENDIAN && depth > 8))
+ {
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+
+ /* conversion */
+ switch (audio_info.finfo->flags)
+ {
+ case GST_AUDIO_FORMAT_FLAG_FLOAT:
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_Float);
+ break;
+ case GST_AUDIO_FORMAT_FLAG_INTEGER:
+ case GST_AUDIO_FORMAT_FLAG_SIGNED:
+ IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+ break;
+ default:
+ FIXME("Unrecognized audio format %x\n", audio_info.finfo->format);
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+
+ IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, depth);
+ }
+ else
+ {
+ ERR("Failed to get caps audio info\n");
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+ }
+ else
+ {
+ FIXME("Unrecognized audio format %s\n", mime_type);
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+ }
+ else
+ {
+ IMFMediaType_Release(media_type);
+ return NULL;
+ }
+
+ return media_type;
+}
--
2.28.0

View File

@ -1 +1,2 @@
Fixes: [49692] mfplat: Improved support for multiple video formats.
Disabled: true

View File

@ -51,7 +51,7 @@ usage()
# Get the upstream commit sha
upstream_commit()
{
echo "2ee75bf9ade3e90f10ffe4236c8c95d817402392"
echo "23c6dd55b8c983ec88cada0a6d6c75ee9cd93976"
}
# Show version information
@ -88,7 +88,6 @@ patch_enable_all ()
enable_advapi32_LsaLookupPrivilegeName="$1"
enable_api_ms_win_Stub_DLLs="$1"
enable_atl_AtlAxDialogBox="$1"
enable_bcrypt_ECDHSecretAgreement="$1"
enable_cmd_launch_association="$1"
enable_color_sRGB_profile="$1"
enable_comctl32_Listview_DrawItem="$1"
@ -107,7 +106,6 @@ patch_enable_all ()
enable_d3dx9_36_D3DXStubs="$1"
enable_d3dx9_36_DDS="$1"
enable_d3dx9_36_Filter_Warnings="$1"
enable_d3dx9_36_Optimize_Inplace="$1"
enable_d3dx9_36_UpdateSkinnedMesh="$1"
enable_dbghelp_Debug_Symbols="$1"
enable_ddraw_Device_Caps="$1"
@ -146,7 +144,6 @@ patch_enable_all ()
enable_krnl386_exe16_GDT_LDT_Emulation="$1"
enable_krnl386_exe16_Invalid_Console_Handles="$1"
enable_loader_KeyboardLayouts="$1"
enable_mfplat_streaming_support="$1"
enable_mmsystem_dll16_MIDIHDR_Refcount="$1"
enable_mountmgr_DosDevices="$1"
enable_mscoree_CorValidateImage="$1"
@ -358,9 +355,6 @@ patch_enable ()
atl-AtlAxDialogBox)
enable_atl_AtlAxDialogBox="$2"
;;
bcrypt-ECDHSecretAgreement)
enable_bcrypt_ECDHSecretAgreement="$2"
;;
cmd-launch-association)
enable_cmd_launch_association="$2"
;;
@ -415,9 +409,6 @@ patch_enable ()
d3dx9_36-Filter_Warnings)
enable_d3dx9_36_Filter_Warnings="$2"
;;
d3dx9_36-Optimize_Inplace)
enable_d3dx9_36_Optimize_Inplace="$2"
;;
d3dx9_36-UpdateSkinnedMesh)
enable_d3dx9_36_UpdateSkinnedMesh="$2"
;;
@ -532,9 +523,6 @@ patch_enable ()
loader-KeyboardLayouts)
enable_loader_KeyboardLayouts="$2"
;;
mfplat-streaming-support)
enable_mfplat_streaming_support="$2"
;;
mmsystem.dll16-MIDIHDR_Refcount)
enable_mmsystem_dll16_MIDIHDR_Refcount="$2"
;;
@ -1840,21 +1828,6 @@ if test "$enable_atl_AtlAxDialogBox" -eq 1; then
patch_apply atl-AtlAxDialogBox/0001-atl-Implement-AtlAxDialogBox-A-W.patch
fi
# Patchset bcrypt-ECDHSecretAgreement
# |
# | This patchset fixes the following Wine bugs:
# | * [#47699] Multiple games fail to connect to online services (missing BCryptSecretAgreement / BCryptDeriveKey
# | implementation)
# |
# | Modified files:
# | * configure.ac, dlls/bcrypt/Makefile.in, dlls/bcrypt/bcrypt_internal.h, dlls/bcrypt/bcrypt_main.c, dlls/bcrypt/gcrypt.c,
# | dlls/bcrypt/gnutls.c, dlls/bcrypt/macos.c, dlls/bcrypt/tests/bcrypt.c
# |
if test "$enable_bcrypt_ECDHSecretAgreement" -eq 1; then
patch_apply bcrypt-ECDHSecretAgreement/0001-bcrypt-Implement-BCryptSecretAgreement-with-libgcryp.patch
patch_apply bcrypt-ECDHSecretAgreement/0002-bcrypt-Implement-BCRYPT_KDF_HASH.patch
fi
# Patchset cmd-launch-association
# |
# | This patchset fixes the following Wine bugs:
@ -2196,18 +2169,6 @@ if test "$enable_d3dx9_36_Filter_Warnings" -eq 1; then
patch_apply d3dx9_36-Filter_Warnings/0001-d3dx9_36-Filter-out-D3DCompile-warning-messages-that.patch
fi
# Patchset d3dx9_36-Optimize_Inplace
# |
# | This patchset fixes the following Wine bugs:
# | * [#48529] Avencast fails to launch
# |
# | Modified files:
# | * dlls/d3dx9_36/mesh.c
# |
if test "$enable_d3dx9_36_Optimize_Inplace" -eq 1; then
patch_apply d3dx9_36-Optimize_Inplace/0001-d3dx9_36-No-need-to-fail-if-we-don-t-support-vertice.patch
fi
# Patchset d3dx9_36-UpdateSkinnedMesh
# |
# | This patchset fixes the following Wine bugs:
@ -2718,78 +2679,6 @@ if test "$enable_loader_KeyboardLayouts" -eq 1; then
patch_apply loader-KeyboardLayouts/0002-user32-Improve-GetKeyboardLayoutList.patch
fi
# Patchset mfplat-streaming-support
# |
# | This patchset fixes the following Wine bugs:
# | * [#49692] mfplat: Improved support for multiple video formats.
# |
# | Modified files:
# | * configure.ac, dlls/mf/Makefile.in, dlls/mf/handler.c, dlls/mf/handler.h, dlls/mf/main.c, dlls/mf/sar.c,
# | dlls/mf/session.c, dlls/mf/tests/mf.c, dlls/mf/topology.c, dlls/mfplat/mediatype.c, dlls/mfplat/tests/mfplat.c,
# | dlls/mfplat/tests/test.mp4, dlls/mfreadwrite/reader.c, dlls/mfreadwrite/tests/mfplat.c,
# | dlls/mfreadwrite/tests/resource.rc, dlls/mfreadwrite/tests/test.mp4, dlls/winegstreamer/Makefile.in,
# | dlls/winegstreamer/audioconvert.c, dlls/winegstreamer/colorconvert.c, dlls/winegstreamer/gst_cbs.c,
# | dlls/winegstreamer/gst_cbs.h, dlls/winegstreamer/gst_private.h, dlls/winegstreamer/main.c,
# | dlls/winegstreamer/media_source.c, dlls/winegstreamer/mf_decode.c, dlls/winegstreamer/mfplat.c,
# | dlls/winegstreamer/winegstreamer_classes.idl, include/mfidl.idl, tools/make_makefiles, tools/makedep.c
# |
if test "$enable_mfplat_streaming_support" -eq 1; then
patch_apply mfplat-streaming-support/0001-winegstreamer-Add-a-GstPad-wrapping-the-media-source.patch
patch_apply mfplat-streaming-support/0002-winegstreamer-Use-decodebin-to-initialize-media-stre.patch
patch_apply mfplat-streaming-support/0003-winegstreamer-Implement-IMFMediaStream-GetStreamDesc.patch
patch_apply mfplat-streaming-support/0004-winegstreamer-Insert-parser-into-pipeline-to-rectify.patch
patch_apply mfplat-streaming-support/0005-winegstreamer-Insert-videoconvert-into-decoded-video.patch
patch_apply mfplat-streaming-support/0006-winegstreamer-Insert-audioconvert-into-decoded-audio.patch
patch_apply mfplat-streaming-support/0007-winegstreamer-Translate-H.264-caps-to-attributes.patch
patch_apply mfplat-streaming-support/0008-winegstreamer-Translate-WMV-caps-to-attributes.patch
patch_apply mfplat-streaming-support/0009-winegstreamer-Translate-AAC-caps-to-attributes.patch
patch_apply mfplat-streaming-support/0010-winegstreamer-Translate-MPEG-4-Section-2-caps-to-att.patch
patch_apply mfplat-streaming-support/0011-winegstreamer-Translate-WMA-caps-to-attributes.patch
patch_apply mfplat-streaming-support/0012-winegstreamer-Implement-IMFMediaSource-CreatePresent.patch
patch_apply mfplat-streaming-support/0013-winegstreamer-Introduce-IMFMediaType-GstCaps-convert.patch
patch_apply mfplat-streaming-support/0014-winegstreamer-Translate-H.264-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0015-winegstreamer-Translate-WMV-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0016-winegstreamer-Translate-AAC-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0017-winegstreamer-Translate-MPEG-4-Section-2-attributes-.patch
patch_apply mfplat-streaming-support/0018-winegstreamer-Translate-WMA-attributes-to-caps.patch
patch_apply mfplat-streaming-support/0019-winegstreamer-Implement-IMFMediaSource-Start.patch
patch_apply mfplat-streaming-support/0020-winegstreamer-Implement-IMFMediaStream-RequestSample.patch
patch_apply mfplat-streaming-support/0021-winegstreamer-Implement-IMFMediaSource-GetCharacteri.patch
patch_apply mfplat-streaming-support/0022-winegstreamer-Calculate-the-MF_PD_DURATION-of-the-me.patch
patch_apply mfplat-streaming-support/0023-tools-Add-support-for-multiple-parent-directories.patch
patch_apply mfplat-streaming-support/0024-mf-Introduce-handler-helper.patch
patch_apply mfplat-streaming-support/0025-Introduce-IMFSample-GstBuffer-converter.patch
patch_apply mfplat-streaming-support/0026-winegstreamer-Implement-decoder-MFT-on-gstreamer.patch
patch_apply mfplat-streaming-support/0027-mfreadwrite-Select-all-streams-when-creating-a-sourc.patch
patch_apply mfplat-streaming-support/0028-Miscellaneous.patch
patch_apply mfplat-streaming-support/0029-WMV.patch
patch_apply mfplat-streaming-support/0030-mf-Ask-for-more-samples-from-upstream-node-when-upon.patch
patch_apply mfplat-streaming-support/0031-winegstreamer-Implement-IMFMedisStream-GetMediaSourc.patch
patch_apply mfplat-streaming-support/0032-Expose-PCM-output-type-on-AAC-decoder.patch
patch_apply mfplat-streaming-support/0033-mfplat-Add-I420-format-information.patch
patch_apply mfplat-streaming-support/0034-winegstreamer-Implement-Color-Converter-MFT.patch
patch_apply mfplat-streaming-support/0035-HACK-Set-BPS-to-16-for-output-template.patch
patch_apply mfplat-streaming-support/0036-Improve-tests.patch
patch_apply mfplat-streaming-support/0037-Revert-Improve-tests.patch
patch_apply mfplat-streaming-support/0038-Report-streams-backwards-and-only-select-one-of-each.patch
patch_apply mfplat-streaming-support/0039-winegstreamer-Implement-IMFMediaSource-Stop.patch
patch_apply mfplat-streaming-support/0040-winegstreamer-Introduce-MPEG-4-Section-2-video-decod.patch
patch_apply mfplat-streaming-support/0041-HACK-Switch-between-all-selection-streams-on-MF_SOUR.patch
patch_apply mfplat-streaming-support/0042-winegstreamer-Introduce-WMA-audio-decoder.patch
patch_apply mfplat-streaming-support/0043-Support-stereo-down-folding.patch
patch_apply mfplat-streaming-support/0044-winegstreamer-Implement-MF_SD_LANGUAGE.patch
patch_apply mfplat-streaming-support/0045-Revert-mf-topoloader-Add-a-structure-for-iterative-b.patch
patch_apply mfplat-streaming-support/0046-Revert-mf-topoloader-Clone-source-nodes-as-a-first-l.patch
patch_apply mfplat-streaming-support/0047-Revert-mf-topoloader-Switch-to-public-interface-for-.patch
patch_apply mfplat-streaming-support/0048-mf-Partially-implement-the-topology-loader.patch
patch_apply mfplat-streaming-support/0049-mf-Miscelaneous-fixes-to-topology-resolution.patch
patch_apply mfplat-streaming-support/0050-Rewrite-branch-resolver.patch
patch_apply mfplat-streaming-support/0051-mf-sar-Compare-against-native-media-type-in-IsMediaT.patch
patch_apply mfplat-streaming-support/0052-winegstreamer-Implement-audio-conversion-MFT.patch
patch_apply mfplat-streaming-support/0053-winegstreamer-Support-eAVEncH264VProfile_Constrained.patch
patch_apply mfplat-streaming-support/0054-winegstreamer-Support-older-versions.patch
fi
# Patchset mmsystem.dll16-MIDIHDR_Refcount
# |
# | This patchset fixes the following Wine bugs:

View File

@ -1 +1 @@
2ee75bf9ade3e90f10ffe4236c8c95d817402392
23c6dd55b8c983ec88cada0a6d6c75ee9cd93976