[PATCH 0/6] MR9913: Draft: winedmo: Allow building against multiple and specific FFmpeg versions.
This would achieve ABI compatibility with arbitrary FFmpeg versions, without having to redefine / fixup FFmpeg structures manually. Downstream Wine distributions may be interested in having an embedded but crippled FFmpeg shipped with them, avoiding issues related to FFmpeg distribution, while still being able to dynamically load the system, or externally provided, more capable FFmpeg version. The distributions would only need to build every supported winedmo versions, targeting the corresponding FFmpeg ABI, to later dynamically load them. The non-versioned winedmo would load the distribution embedded FFmpeg for instance, while the versioned modules would target a matching system library. This also introduces an unified interface with winegstreamer, allowing us to get rid of the duplicated media source code. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9913
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mfsrcsnk/Makefile.in | 3 +- dlls/mfsrcsnk/media_source.c | 142 ++++++++++++++++++++++------------- 2 files changed, 91 insertions(+), 54 deletions(-) diff --git a/dlls/mfsrcsnk/Makefile.in b/dlls/mfsrcsnk/Makefile.in index 5bef58ca10d..20518168f2c 100644 --- a/dlls/mfsrcsnk/Makefile.in +++ b/dlls/mfsrcsnk/Makefile.in @@ -1,6 +1,7 @@ MODULE = mfsrcsnk.dll IMPORTLIB = mfsrcsnk -IMPORTS = advapi32 ole32 mfplat mfuuid uuid winedmo +IMPORTS = advapi32 ole32 mfplat mfuuid uuid +DELAYIMPORTS = winedmo EXTRADLLFLAGS = -Wb,--prefer-native diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index b084db6ee6b..b39f4b3b125 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -26,6 +26,56 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +struct winedmo_demuxer_funcs +{ + NTSTATUS (*CDECL p_check)(const char *mime_type); + NTSTATUS (*CDECL p_create)(const WCHAR *url, struct winedmo_stream *stream, UINT64 stream_size, INT64 *duration, + UINT *stream_count, WCHAR *mime_type, struct winedmo_demuxer *demuxer); + NTSTATUS (*CDECL p_destroy)(struct winedmo_demuxer *demuxer); + NTSTATUS (*CDECL p_read)(struct winedmo_demuxer demuxer, UINT *stream, DMO_OUTPUT_DATA_BUFFER *buffer, UINT *buffer_size); + NTSTATUS (*CDECL p_seek)(struct winedmo_demuxer demuxer, INT64 timestamp); + NTSTATUS (*CDECL p_stream_lang)(struct winedmo_demuxer demuxer, UINT stream, WCHAR *buffer, UINT len); + NTSTATUS (*CDECL p_stream_name)(struct winedmo_demuxer demuxer, UINT stream, WCHAR *buffer, UINT len); + NTSTATUS (*CDECL p_stream_type)(struct winedmo_demuxer demuxer, UINT stream, + GUID *major, union winedmo_format **format); +}; + +static const struct winedmo_demuxer_funcs winedmo_funcs = +{ + .p_check = winedmo_demuxer_check, + .p_create = winedmo_demuxer_create, + .p_destroy = winedmo_demuxer_destroy, + .p_read = winedmo_demuxer_read, + .p_seek = winedmo_demuxer_seek, + .p_stream_lang = winedmo_demuxer_stream_lang, + .p_stream_name = winedmo_demuxer_stream_name, + .p_stream_type = winedmo_demuxer_stream_type, +}; + +static BOOL use_gst_byte_stream_handler(void) +{ + BOOL result; + DWORD size = sizeof(result); + + /* @@ Wine registry key: HKCU\Software\Wine\MediaFoundation */ + if (!RegGetValueW(HKEY_CURRENT_USER, L"Software\\Wine\\MediaFoundation", L"DisableGstByteStreamHandler", + RRF_RT_REG_DWORD, NULL, &result, &size)) + return !result; + + return TRUE; +} + +static const struct winedmo_demuxer_funcs *get_winedmo_demuxer_funcs(const char *mime_type) +{ + if (use_gst_byte_stream_handler()) + return NULL; + + if (!winedmo_funcs.p_check(mime_type)) + return &winedmo_funcs; + + return NULL; +} + #define DEFINE_MF_ASYNC_PARAMS(type) \ static struct type *type ## _from_IUnknown(IUnknown *iface) \ { \ @@ -271,6 +321,7 @@ struct media_source float rate; BOOL thin; + const struct winedmo_demuxer_funcs *funcs; struct winedmo_demuxer winedmo_demuxer; struct winedmo_stream winedmo_stream; UINT64 file_size; @@ -496,7 +547,7 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe media_stream_start(stream, source->stream_map[i], position); } - if (position->vt == VT_I8 && (status = winedmo_demuxer_seek(source->winedmo_demuxer, position->hVal.QuadPart))) + if (position->vt == VT_I8 && (status = source->funcs->p_seek(source->winedmo_demuxer, position->hVal.QuadPart))) WARN("Failed to seek to %I64d, status %#lx\n", position->hVal.QuadPart, status); source->state = SOURCE_RUNNING; @@ -637,7 +688,7 @@ static HRESULT create_media_buffer_sample(UINT buffer_size, IMFSample **sample, return hr; } -static HRESULT demuxer_read_sample(struct winedmo_demuxer demuxer, UINT *index, IMFSample **out) +static HRESULT source_demuxer_read_sample(struct media_source *source, UINT *index, IMFSample **out) { UINT buffer_size = 0x1000; IMFSample *sample; @@ -650,7 +701,7 @@ static HRESULT demuxer_read_sample(struct winedmo_demuxer demuxer, UINT *index, if (FAILED(hr = create_media_buffer_sample(buffer_size, &sample, &output.pBuffer))) return hr; - if ((status = winedmo_demuxer_read(demuxer, index, &output, &buffer_size))) + if ((status = source->funcs->p_read(source->winedmo_demuxer, index, &output, &buffer_size))) { if (status == STATUS_BUFFER_TOO_SMALL) hr = E_PENDING; else if (status == STATUS_END_OF_FILE) hr = MF_E_END_OF_STREAM; @@ -696,7 +747,7 @@ static HRESULT media_source_read(struct media_source *source) if (source->state != SOURCE_RUNNING) return S_OK; - if (FAILED(hr = demuxer_read_sample(source->winedmo_demuxer, &index, &sample)) && hr != MF_E_END_OF_STREAM) + if (FAILED(hr = source_demuxer_read_sample(source, &index, &sample)) && hr != MF_E_END_OF_STREAM) { WARN("Failed to read stream %u data, hr %#lx\n", index, hr); return hr; @@ -1255,7 +1306,7 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) { IMFMediaSource_Shutdown(iface); - winedmo_demuxer_destroy(&source->winedmo_demuxer); + source->funcs->p_destroy(&source->winedmo_demuxer); free(source->stream_map); free(source->streams); @@ -1524,15 +1575,15 @@ static HRESULT media_type_from_winedmo_format( GUID major, union winedmo_format return E_NOTIMPL; } -static HRESULT get_stream_media_type(struct winedmo_demuxer demuxer, UINT index, GUID *major, IMFMediaType **media_type) +static HRESULT get_stream_media_type(struct media_source *source, UINT index, GUID *major, IMFMediaType **media_type) { union winedmo_format *format; NTSTATUS status; HRESULT hr; - TRACE("demuxer %p, index %u, media_type %p\n", &demuxer, index, media_type); + TRACE("source %p, index %u, media_type %p\n", source, index, media_type); - if ((status = winedmo_demuxer_stream_type(demuxer, index, major, &format))) + if ((status = source->funcs->p_stream_type(source->winedmo_demuxer, index, major, &format))) { WARN("Failed to get stream %u type, status %#lx\n", index, status); return HRESULT_FROM_NT(status); @@ -1554,7 +1605,7 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea { for (i = 0; i < stream_count; i++) { - if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major, NULL))) + if (FAILED(get_stream_media_type(source, i, &major, NULL))) continue; TRACE("mapping source %p stream %u to demuxer stream %u\n", source, n, i); source->stream_map[n++] = i; @@ -1564,7 +1615,7 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea for (i = stream_count - 1; i >= 0; i--) { - if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major, NULL))) + if (FAILED(get_stream_media_type(source, i, &major, NULL))) continue; if (IsEqualGUID(&major, &MFMediaType_Audio)) { @@ -1574,7 +1625,7 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea } for (i = stream_count - 1; i >= 0; i--) { - if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major, NULL))) + if (FAILED(get_stream_media_type(source, i, &major, NULL))) continue; if (IsEqualGUID(&major, &MFMediaType_Video)) { @@ -1584,7 +1635,7 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea } for (i = stream_count - 1; i >= 0; i--) { - if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major, NULL))) + if (FAILED(get_stream_media_type(source, i, &major, NULL))) major = GUID_NULL; if (!IsEqualGUID(&major, &MFMediaType_Audio) && !IsEqualGUID(&major, &MFMediaType_Video)) { @@ -1649,15 +1700,15 @@ static void media_source_init_descriptors(struct media_source *source) NTSTATUS status; GUID major; - if ((status = winedmo_demuxer_stream_lang(source->winedmo_demuxer, source->stream_map[i], buffer, ARRAY_SIZE(buffer))) + if (FAILED(status = source->funcs->p_stream_lang(source->winedmo_demuxer, source->stream_map[i], buffer, ARRAY_SIZE(buffer))) || (!wcscmp(source->mime_type, L"video/mp4") && FAILED(normalize_mp4_language_code(source, buffer))) || FAILED(IMFStreamDescriptor_SetString(stream->descriptor, &MF_SD_LANGUAGE, buffer))) WARN("Failed to set stream descriptor language, status %#lx\n", status); - if ((status = winedmo_demuxer_stream_name(source->winedmo_demuxer, source->stream_map[i], buffer, ARRAY_SIZE(buffer))) + if (FAILED(status = source->funcs->p_stream_name(source->winedmo_demuxer, source->stream_map[i], buffer, ARRAY_SIZE(buffer))) || FAILED(IMFStreamDescriptor_SetString(stream->descriptor, &MF_SD_STREAM_NAME, buffer))) WARN("Failed to set stream descriptor name, status %#lx\n", status); - if (FAILED(get_stream_media_type(source->winedmo_demuxer, source->stream_map[i], &major, NULL))) + if (FAILED(get_stream_media_type(source, source->stream_map[i], &major, NULL))) continue; if (IsEqualGUID(&major, &MFMediaType_Audio)) @@ -1767,7 +1818,7 @@ static HRESULT media_source_async_create(struct media_source *source, IMFAsyncRe source->winedmo_stream.p_seek = media_source_seek_cb; source->winedmo_stream.p_read = media_source_read_cb; - if ((status = winedmo_demuxer_create(source->url, &source->winedmo_stream, source->file_size, &source->duration, + if ((status = source->funcs->p_create(source->url, &source->winedmo_stream, source->file_size, &source->duration, &stream_count, source->mime_type, &source->winedmo_demuxer))) { WARN("Failed to create demuxer, status %#lx\n", status); @@ -1790,7 +1841,7 @@ static HRESULT media_source_async_create(struct media_source *source, IMFAsyncRe IMFMediaType *media_type; GUID major; - if (FAILED(hr = get_stream_media_type(source->winedmo_demuxer, source->stream_map[i], &major, &media_type))) + if (FAILED(hr = get_stream_media_type(source, source->stream_map[i], &major, &media_type))) continue; if (SUCCEEDED(hr = stream_descriptor_create(i + 1, media_type, &descriptor))) { @@ -1832,7 +1883,7 @@ static WCHAR *get_byte_stream_url(IMFByteStream *stream, const WCHAR *url) return url ? wcsdup(url) : NULL; } -static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFMediaSource **out) +static HRESULT media_source_create(const struct winedmo_demuxer_funcs *funcs, const WCHAR *url, IMFByteStream *stream, IMFMediaSource **out) { struct media_source *source; HRESULT hr; @@ -1852,6 +1903,7 @@ static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFM source->async_read_iface.lpVtbl = &media_source_async_read_vtbl; source->async_set_rate_iface.lpVtbl = &media_source_async_set_rate_vtbl; source->refcount = 1; + source->funcs = funcs; if (FAILED(hr = MFCreateEventQueue(&source->queue))) { @@ -1875,6 +1927,7 @@ struct byte_stream_handler { IMFByteStreamHandler IMFByteStreamHandler_iface; LONG refcount; + const struct winedmo_demuxer_funcs *funcs; }; static struct byte_stream_handler *byte_stream_handler_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) @@ -1946,7 +1999,7 @@ static HRESULT WINAPI byte_stream_handler_BeginCreateObject(IMFByteStreamHandler return MF_E_BYTESTREAM_NOT_SEEKABLE; } - if (FAILED(hr = media_source_create(url, stream, &source))) + if (FAILED(hr = media_source_create(handler->funcs, url, stream, &source))) return hr; if (SUCCEEDED(hr = MFCreateAsyncResult((IUnknown *)source, callback, state, &result))) { @@ -2004,7 +2057,7 @@ static const IMFByteStreamHandlerVtbl byte_stream_handler_vtbl = byte_stream_handler_GetMaxNumberOfBytesRequiredForResolution, }; -static HRESULT byte_stream_plugin_create(IUnknown *outer, REFIID riid, void **out) +static HRESULT byte_stream_plugin_create(const struct winedmo_demuxer_funcs *funcs, IUnknown *outer, REFIID riid, void **out) { struct byte_stream_handler *handler; HRESULT hr; @@ -2017,6 +2070,7 @@ static HRESULT byte_stream_plugin_create(IUnknown *outer, REFIID riid, void **ou return E_OUTOFMEMORY; handler->IMFByteStreamHandler_iface.lpVtbl = &byte_stream_handler_vtbl; handler->refcount = 1; + handler->funcs = funcs; TRACE("created %p\n", handler); hr = IMFByteStreamHandler_QueryInterface(&handler->IMFByteStreamHandler_iface, riid, out); @@ -2024,32 +2078,18 @@ static HRESULT byte_stream_plugin_create(IUnknown *outer, REFIID riid, void **ou return hr; } -static BOOL use_gst_byte_stream_handler(void) -{ - BOOL result; - DWORD size = sizeof(result); - - /* @@ Wine registry key: HKCU\Software\Wine\MediaFoundation */ - if (!RegGetValueW( HKEY_CURRENT_USER, L"Software\\Wine\\MediaFoundation", L"DisableGstByteStreamHandler", - RRF_RT_REG_DWORD, NULL, &result, &size )) - return !result; - - return TRUE; -} - static HRESULT WINAPI asf_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - NTSTATUS status; + const struct winedmo_demuxer_funcs *funcs; - if ((status = winedmo_demuxer_check("video/x-ms-asf")) || use_gst_byte_stream_handler()) + if (!(funcs = get_winedmo_demuxer_funcs("video/x-ms-asf")) || use_gst_byte_stream_handler()) { static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - if (status) WARN("Unsupported demuxer, status %#lx.\n", status); return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); } - return byte_stream_plugin_create(outer, riid, out); + return byte_stream_plugin_create(funcs, outer, riid, out); } static const IClassFactoryVtbl asf_byte_stream_plugin_factory_vtbl = @@ -2066,16 +2106,15 @@ IClassFactory asf_byte_stream_plugin_factory = {&asf_byte_stream_plugin_factory_ static HRESULT WINAPI avi_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - NTSTATUS status; + const struct winedmo_demuxer_funcs *funcs; - if ((status = winedmo_demuxer_check("video/avi")) || use_gst_byte_stream_handler()) + if (!(funcs = get_winedmo_demuxer_funcs("video/avi")) || use_gst_byte_stream_handler()) { static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - if (status) WARN("Unsupported demuxer, status %#lx.\n", status); return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); } - return byte_stream_plugin_create(outer, riid, out); + return byte_stream_plugin_create(funcs, outer, riid, out); } static const IClassFactoryVtbl avi_byte_stream_plugin_factory_vtbl = @@ -2092,16 +2131,15 @@ IClassFactory avi_byte_stream_plugin_factory = {&avi_byte_stream_plugin_factory_ static HRESULT WINAPI mpeg4_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - NTSTATUS status; + const struct winedmo_demuxer_funcs *funcs; - if ((status = winedmo_demuxer_check("video/mp4")) || use_gst_byte_stream_handler()) + if (!(funcs = get_winedmo_demuxer_funcs("video/mp4")) || use_gst_byte_stream_handler()) { static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - if (status) WARN("Unsupported demuxer, status %#lx.\n", status); return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); } - return byte_stream_plugin_create(outer, riid, out); + return byte_stream_plugin_create(funcs, outer, riid, out); } static const IClassFactoryVtbl mpeg4_byte_stream_plugin_factory_vtbl = @@ -2118,16 +2156,15 @@ IClassFactory mpeg4_byte_stream_plugin_factory = {&mpeg4_byte_stream_plugin_fact static HRESULT WINAPI wav_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - NTSTATUS status; + const struct winedmo_demuxer_funcs *funcs; - if ((status = winedmo_demuxer_check("audio/wav")) || use_gst_byte_stream_handler()) + if (!(funcs = get_winedmo_demuxer_funcs("audio/wav")) || use_gst_byte_stream_handler()) { static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - if (status) WARN("Unsupported demuxer, status %#lx.\n", status); return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); } - return byte_stream_plugin_create(outer, riid, out); + return byte_stream_plugin_create(funcs, outer, riid, out); } static const IClassFactoryVtbl wav_byte_stream_plugin_factory_vtbl = @@ -2144,16 +2181,15 @@ IClassFactory wav_byte_stream_plugin_factory = {&wav_byte_stream_plugin_factory_ static HRESULT WINAPI mp3_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - NTSTATUS status; + const struct winedmo_demuxer_funcs *funcs; - if ((status = winedmo_demuxer_check("audio/mp3")) || use_gst_byte_stream_handler()) + if (!(funcs = get_winedmo_demuxer_funcs("audio/mp3")) || use_gst_byte_stream_handler()) { static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - if (status) WARN("Unsupported demuxer, status %#lx.\n", status); return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); } - return byte_stream_plugin_create(outer, riid, out); + return byte_stream_plugin_create(funcs, outer, riid, out); } static const IClassFactoryVtbl mp3_byte_stream_plugin_factory_vtbl = -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9913
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mfsrcsnk/media_source.c | 88 +++---- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 2 +- dlls/winegstreamer/winedmo.c | 324 ++++++++++++++++++++++++++ dlls/winegstreamer/winegstreamer.spec | 9 + 6 files changed, 374 insertions(+), 51 deletions(-) create mode 100644 dlls/winegstreamer/winedmo.c diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index b39f4b3b125..53bb00fb64a 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -40,7 +40,7 @@ struct winedmo_demuxer_funcs GUID *major, union winedmo_format **format); }; -static const struct winedmo_demuxer_funcs winedmo_funcs = +static struct winedmo_demuxer_funcs winedmo_funcs = { .p_check = winedmo_demuxer_check, .p_create = winedmo_demuxer_create, @@ -52,28 +52,51 @@ static const struct winedmo_demuxer_funcs winedmo_funcs = .p_stream_type = winedmo_demuxer_stream_type, }; -static BOOL use_gst_byte_stream_handler(void) +static NTSTATUS winedmo_unsupported_check(const char *mime_type) +{ + return STATUS_UNSUCCESSFUL; +} + +static BOOL load_winedmo_demuxer_funcs(const WCHAR *name, struct winedmo_demuxer_funcs *funcs) +{ + HMODULE module; + + if (!(module = LoadLibraryW(name))) + { + funcs->p_check = winedmo_unsupported_check; + return FALSE; + } + funcs->p_check = (void *)GetProcAddress(module, "winedmo_demuxer_check"); + funcs->p_create = (void *)GetProcAddress(module, "winedmo_demuxer_create"); + funcs->p_destroy = (void *)GetProcAddress(module, "winedmo_demuxer_destroy"); + funcs->p_read = (void *)GetProcAddress(module, "winedmo_demuxer_read"); + funcs->p_seek = (void *)GetProcAddress(module, "winedmo_demuxer_seek"); + funcs->p_stream_lang = (void *)GetProcAddress(module, "winedmo_demuxer_stream_lang"); + funcs->p_stream_name = (void *)GetProcAddress(module, "winedmo_demuxer_stream_name"); + funcs->p_stream_type = (void *)GetProcAddress(module, "winedmo_demuxer_stream_type"); + return TRUE; +} + +static BOOL CALLBACK init_dynamic_funcs(INIT_ONCE *once, void *param, void **ctx) { BOOL result; DWORD size = sizeof(result); /* @@ Wine registry key: HKCU\Software\Wine\MediaFoundation */ - if (!RegGetValueW(HKEY_CURRENT_USER, L"Software\\Wine\\MediaFoundation", L"DisableGstByteStreamHandler", - RRF_RT_REG_DWORD, NULL, &result, &size)) - return !result; + if (RegGetValueW(HKEY_CURRENT_USER, L"Software\\Wine\\MediaFoundation", L"DisableGstByteStreamHandler", + RRF_RT_REG_DWORD, NULL, &result, &size ) || !result) + load_winedmo_demuxer_funcs(L"winegstreamer", &winedmo_funcs); return TRUE; } static const struct winedmo_demuxer_funcs *get_winedmo_demuxer_funcs(const char *mime_type) { - if (use_gst_byte_stream_handler()) - return NULL; + static INIT_ONCE once = INIT_ONCE_STATIC_INIT; - if (!winedmo_funcs.p_check(mime_type)) - return &winedmo_funcs; + InitOnceExecuteOnce(&once, init_dynamic_funcs, NULL, NULL); - return NULL; + return &winedmo_funcs; } #define DEFINE_MF_ASYNC_PARAMS(type) \ @@ -2081,14 +2104,7 @@ static HRESULT byte_stream_plugin_create(const struct winedmo_demuxer_funcs *fun static HRESULT WINAPI asf_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - const struct winedmo_demuxer_funcs *funcs; - - if (!(funcs = get_winedmo_demuxer_funcs("video/x-ms-asf")) || use_gst_byte_stream_handler()) - { - static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); - } - + const struct winedmo_demuxer_funcs *funcs = get_winedmo_demuxer_funcs("video/x-ms-asf"); return byte_stream_plugin_create(funcs, outer, riid, out); } @@ -2106,14 +2122,7 @@ IClassFactory asf_byte_stream_plugin_factory = {&asf_byte_stream_plugin_factory_ static HRESULT WINAPI avi_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - const struct winedmo_demuxer_funcs *funcs; - - if (!(funcs = get_winedmo_demuxer_funcs("video/avi")) || use_gst_byte_stream_handler()) - { - static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); - } - + const struct winedmo_demuxer_funcs *funcs = get_winedmo_demuxer_funcs("video/avi"); return byte_stream_plugin_create(funcs, outer, riid, out); } @@ -2131,14 +2140,7 @@ IClassFactory avi_byte_stream_plugin_factory = {&avi_byte_stream_plugin_factory_ static HRESULT WINAPI mpeg4_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - const struct winedmo_demuxer_funcs *funcs; - - if (!(funcs = get_winedmo_demuxer_funcs("video/mp4")) || use_gst_byte_stream_handler()) - { - static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); - } - + const struct winedmo_demuxer_funcs *funcs = get_winedmo_demuxer_funcs("video/mp4"); return byte_stream_plugin_create(funcs, outer, riid, out); } @@ -2156,14 +2158,7 @@ IClassFactory mpeg4_byte_stream_plugin_factory = {&mpeg4_byte_stream_plugin_fact static HRESULT WINAPI wav_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - const struct winedmo_demuxer_funcs *funcs; - - if (!(funcs = get_winedmo_demuxer_funcs("audio/wav")) || use_gst_byte_stream_handler()) - { - static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); - } - + const struct winedmo_demuxer_funcs *funcs = get_winedmo_demuxer_funcs("audio/wav"); return byte_stream_plugin_create(funcs, outer, riid, out); } @@ -2181,14 +2176,7 @@ IClassFactory wav_byte_stream_plugin_factory = {&wav_byte_stream_plugin_factory_ static HRESULT WINAPI mp3_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) { - const struct winedmo_demuxer_funcs *funcs; - - if (!(funcs = get_winedmo_demuxer_funcs("audio/mp3")) || use_gst_byte_stream_handler()) - { - static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; - return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); - } - + const struct winedmo_demuxer_funcs *funcs = get_winedmo_demuxer_funcs("audio/mp3"); return byte_stream_plugin_create(funcs, outer, riid, out); } diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 63ca3f61fdf..26f83901e4e 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -28,6 +28,7 @@ SOURCES = \ wg_parser.c \ wg_sample.c \ wg_transform.c \ + winedmo.c \ winegstreamer_classes.idl \ wm_reader.c \ wma_decoder.c diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 84b7db4a14c..62f2aa71279 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -152,6 +152,7 @@ extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format); void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format); +HRESULT wg_media_type_from_mf(IMFMediaType *media_type, struct wg_media_type *wg_media_type); HRESULT wg_sample_create_mf(IMFSample *sample, struct wg_sample **out); HRESULT wg_sample_create_quartz(IMediaSample *sample, struct wg_sample **out); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 7ff79bda4ab..4a13436b8d4 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -108,7 +108,7 @@ static HRESULT video_format_from_media_type(IMFMediaType *media_type, MFVIDEOFOR return hr; } -static HRESULT wg_media_type_from_mf(IMFMediaType *media_type, struct wg_media_type *wg_media_type) +HRESULT wg_media_type_from_mf(IMFMediaType *media_type, struct wg_media_type *wg_media_type) { HRESULT hr; diff --git a/dlls/winegstreamer/winedmo.c b/dlls/winegstreamer/winedmo.c new file mode 100644 index 00000000000..92bcb5327d5 --- /dev/null +++ b/dlls/winegstreamer/winedmo.c @@ -0,0 +1,324 @@ +/* + * Copyright 2025 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stddef.h> +#include <stdarg.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" + +#include "gst_private.h" + +#include "wine/winedmo.h" +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dmo); + +struct demuxer +{ + struct winedmo_stream *stream; + UINT64 stream_size; + wg_parser_t wg_parser; + HANDLE thread; + LONG shutdown; +}; + +static struct demuxer *demuxer_from_handle(struct winedmo_demuxer handle) +{ + return (struct demuxer *)(UINT_PTR)handle.handle; +} + +static DWORD CALLBACK read_thread(void *arg) +{ + struct demuxer *demuxer = arg; + QWORD file_size = demuxer->stream_size; + size_t buffer_size = 4096; + void *data; + + if (!(data = malloc(buffer_size))) + return 0; + + TRACE("Starting read thread for demuxer %p.\n", demuxer); + + while (!ReadAcquire(&demuxer->shutdown)) + { + uint64_t offset; + ULONG ret_size; + uint32_t size; + HRESULT hr; + + if (!wg_parser_get_next_read_offset(demuxer->wg_parser, &offset, &size)) + continue; + + if (offset >= file_size) + size = 0; + else if (offset + size >= file_size) + size = file_size - offset; + + /* Some IMFByteStreams (including the standard file-based stream) return + * an error when reading past the file size. */ + if (!size) + { + wg_parser_push_data(demuxer->wg_parser, data, 0); + continue; + } + + if (!array_reserve(&data, &buffer_size, size, 1)) + { + free(data); + return 0; + } + + ret_size = size; + if (FAILED(hr = HRESULT_FROM_NT(demuxer->stream->p_seek(demuxer->stream, &offset))) + || FAILED(hr = HRESULT_FROM_NT(demuxer->stream->p_read(demuxer->stream, data, &ret_size)))) + ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); + if (ret_size != size) + ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size); + wg_parser_push_data(demuxer->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); + } + + free(data); + TRACE("Media source is shutting down; exiting.\n"); + return 0; +} + +NTSTATUS CDECL winedmo_demuxer_check(const char *mime_type) +{ + return STATUS_SUCCESS; +} + +NTSTATUS CDECL winedmo_demuxer_create(const WCHAR *url, struct winedmo_stream *stream, UINT64 stream_size, + INT64 *duration, UINT *stream_count, WCHAR *mime_type, struct winedmo_demuxer *demuxer) +{ + struct demuxer *object; + + TRACE("url %s, stream %p, stream_size %#I64x, mime_type %p, demuxer %p\n", debugstr_w(url), + stream, stream_size, mime_type, demuxer); + + if (!init_gstreamer()) + return STATUS_UNSUCCESSFUL; + + if (!(object = calloc(1, sizeof(*object)))) + return STATUS_NO_MEMORY; + object->stream = stream; + object->stream_size = stream_size; + + if (!(object->wg_parser = wg_parser_create(TRUE))) + goto failed; + if (!(object->thread = CreateThread(NULL, 0, read_thread, object, 0, NULL))) + goto failed; + if (FAILED(wg_parser_connect(object->wg_parser, stream_size, url))) + goto failed; + + *duration = 0; + *stream_count = wg_parser_get_stream_count(object->wg_parser); + wcscpy(mime_type, L"video/x-application"); + + for (UINT i = 0; i < *stream_count; i++) + { + wg_parser_stream_t wg_stream = wg_parser_get_stream(object->wg_parser, i); + *duration = max(*duration, wg_parser_stream_get_duration(wg_stream)); + } + + demuxer->handle = (UINT_PTR)object; + TRACE("created demuxer %#I64x, stream %p, duration %I64d, stream_count %u, mime_type %s\n", + demuxer->handle, stream, *duration, *stream_count, debugstr_w(mime_type)); + return STATUS_SUCCESS; + +failed: + if (object->thread) + { + WriteRelease(&object->shutdown, 1); + WaitForSingleObject(object->thread, INFINITE); + CloseHandle(object->thread); + } + + wg_parser_destroy(object->wg_parser); + free(object); + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS CDECL winedmo_demuxer_destroy(struct winedmo_demuxer *demuxer) +{ + struct demuxer *object = demuxer_from_handle(*demuxer); + + if (!object) + return STATUS_SUCCESS; + + TRACE("demuxer %#I64x\n", demuxer->handle); + + wg_parser_disconnect(object->wg_parser); + + WriteRelease(&object->shutdown, 1); + WaitForSingleObject(object->thread, INFINITE); + CloseHandle(object->thread); + + wg_parser_destroy(object->wg_parser); + free(object); + + demuxer->handle = 0; + return STATUS_SUCCESS; +} + +static void buffer_lock( DMO_OUTPUT_DATA_BUFFER *buffer, BYTE **data, DWORD *size ) +{ + HRESULT hr; + + if (FAILED(hr = IMediaBuffer_GetBufferAndLength( buffer->pBuffer, data, size ))) + ERR( "Failed to get media buffer data %p, hr %#lx\n", buffer, hr ); + if (FAILED(hr = IMediaBuffer_GetMaxLength( buffer->pBuffer, size ))) + ERR( "Failed to get media buffer max length %p, hr %#lx\n", buffer, hr ); +} + +static void buffer_unlock( DMO_OUTPUT_DATA_BUFFER *buffer, struct wg_parser_buffer *sample ) +{ + IMFSample *object; + HRESULT hr; + + if (FAILED(hr = IMediaBuffer_SetLength( buffer->pBuffer, sample->size ))) + ERR( "Failed to update buffer length, hr %#lx\n", hr ); + + buffer->dwStatus = 0; + if (SUCCEEDED(hr = IMediaBuffer_QueryInterface( buffer->pBuffer, &IID_IMFSample, (void **)&object ))) + { + if (sample->has_pts) IMFSample_SetSampleTime( object, sample->pts ); + if (sample->has_duration) IMFSample_SetSampleDuration( object, sample->duration ); + if (!sample->delta) IMFSample_SetUINT32( object, &MFSampleExtension_CleanPoint, 1 ); + IMFSample_Release( object ); + } + + if ((buffer->rtTimestamp = sample->pts) != INT64_MIN) buffer->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME; + if ((buffer->rtTimelength = sample->duration) != INT64_MIN) buffer->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; + if (!sample->delta) buffer->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT; +} + +NTSTATUS CDECL winedmo_demuxer_read(struct winedmo_demuxer demuxer, UINT *stream, DMO_OUTPUT_DATA_BUFFER *buffer, UINT *buffer_size) +{ + struct demuxer *object = demuxer_from_handle(demuxer); + struct wg_parser_buffer wg_buffer; + NTSTATUS status = STATUS_SUCCESS; + wg_parser_stream_t wg_stream; + BYTE *data; + DWORD size; + + TRACE("demuxer %#I64x, stream %p, buffer %p, buffer_size %p\n", demuxer.handle, stream, buffer, buffer_size); + + if (!wg_parser_stream_get_buffer(object->wg_parser, 0, &wg_buffer)) + return STATUS_END_OF_FILE; + *buffer_size = wg_buffer.size; + *stream = wg_buffer.stream; + + if (SUCCEEDED(IMediaBuffer_GetMaxLength( buffer->pBuffer, &size )) && size < wg_buffer.size) + return STATUS_BUFFER_TOO_SMALL; + + buffer_lock(buffer, &data, &size); + wg_stream = wg_parser_get_stream(object->wg_parser, wg_buffer.stream); + if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, wg_buffer.size)) + { + status = STATUS_UNSUCCESSFUL; + size = 0; + } + wg_parser_stream_release_buffer(wg_stream); + buffer_unlock(buffer, &wg_buffer); + + TRACE("Got buffer %p, buffer_size %#x on stream %u\n", buffer->pBuffer, *buffer_size, *stream); + return status; +} + +NTSTATUS CDECL winedmo_demuxer_seek(struct winedmo_demuxer demuxer, INT64 timestamp) +{ + struct demuxer *object = demuxer_from_handle(demuxer); + wg_parser_stream_t wg_stream; + + TRACE("demuxer %#I64x, timestamp %I64d\n", demuxer.handle, timestamp); + + wg_stream = wg_parser_get_stream(object->wg_parser, 0); + wg_parser_stream_seek(wg_stream, 1.0, timestamp, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); + return STATUS_SUCCESS; +} + +NTSTATUS CDECL winedmo_demuxer_stream_lang(struct winedmo_demuxer demuxer, UINT stream, WCHAR *buffer, UINT len) +{ + struct demuxer *object = demuxer_from_handle(demuxer); + wg_parser_stream_t wg_stream; + char *tag; + + TRACE("demuxer %#I64x, stream %u\n", demuxer.handle, stream); + + wg_stream = wg_parser_get_stream(object->wg_parser, stream); + if (!(tag = wg_parser_stream_get_tag(wg_stream, WG_PARSER_TAG_LANGUAGE))) return STATUS_UNSUCCESSFUL; + len = MultiByteToWideChar(CP_UTF8, 0, tag, -1, buffer, len); + buffer[len - 1] = 0; + free(tag); + + return STATUS_SUCCESS; +} + +NTSTATUS CDECL winedmo_demuxer_stream_name(struct winedmo_demuxer demuxer, UINT stream, WCHAR *buffer, UINT len) +{ + struct demuxer *object = demuxer_from_handle(demuxer); + wg_parser_stream_t wg_stream; + char *tag; + + TRACE("demuxer %#I64x, stream %u\n", demuxer.handle, stream); + + wg_stream = wg_parser_get_stream(object->wg_parser, stream); + if (!(tag = wg_parser_stream_get_tag(wg_stream, WG_PARSER_TAG_NAME))) return STATUS_UNSUCCESSFUL; + len = MultiByteToWideChar(CP_UTF8, 0, tag, -1, buffer, len); + buffer[len - 1] = 0; + free(tag); + + return STATUS_SUCCESS; +} + +NTSTATUS CDECL winedmo_demuxer_stream_type(struct winedmo_demuxer demuxer, UINT stream, GUID *major, union winedmo_format **format) +{ + struct demuxer *object = demuxer_from_handle(demuxer); + struct wg_media_type wg_media_type; + wg_parser_stream_t wg_stream; + struct wg_format wg_format; + IMFMediaType *media_type; + HRESULT hr; + + TRACE("demuxer %#I64x, stream %u, major %p, format %p\n", demuxer.handle, stream, major, format); + + wg_stream = wg_parser_get_stream(object->wg_parser, stream); + wg_parser_stream_get_current_format(wg_stream, &wg_format); + + if (!(media_type = mf_media_type_from_wg_format(&wg_format))) + return STATUS_NO_MEMORY; + hr = wg_media_type_from_mf(media_type, &wg_media_type); + IMFMediaType_Release(media_type); + if (FAILED(hr)) + return STATUS_UNSUCCESSFUL; + + if (!(*format = calloc(1, wg_media_type.format_size))) + { + CoTaskMemFree(wg_media_type.u.format); + return STATUS_NO_MEMORY; + } + + *major = wg_media_type.major; + memcpy(*format, wg_media_type.u.format, wg_media_type.format_size); + CoTaskMemFree(wg_media_type.u.format); + return STATUS_SUCCESS; +} diff --git a/dlls/winegstreamer/winegstreamer.spec b/dlls/winegstreamer/winegstreamer.spec index 095f75a0865..f9e206eb588 100644 --- a/dlls/winegstreamer/winegstreamer.spec +++ b/dlls/winegstreamer/winegstreamer.spec @@ -4,3 +4,12 @@ @ stdcall -private DllUnregisterServer() @ stdcall winegstreamer_create_wm_sync_reader(ptr ptr) @ stdcall winegstreamer_create_video_decoder(ptr) + +@ cdecl winedmo_demuxer_check(ptr) +@ cdecl winedmo_demuxer_create(wstr ptr int64 ptr ptr ptr ptr) +@ cdecl winedmo_demuxer_destroy(ptr) +@ cdecl winedmo_demuxer_read(int64 ptr ptr ptr) +@ cdecl winedmo_demuxer_seek(int64 int64) +@ cdecl winedmo_demuxer_stream_lang(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_name(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_type(int64 long ptr ptr) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9913
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mfplat/main.c | 10 +++++----- dlls/mfsrcsnk/factory.c | 4 ++++ dlls/mfsrcsnk/media_source.c | 18 ++++++++++++++++++ dlls/mfsrcsnk/media_source.h | 1 + dlls/mfsrcsnk/mfsrcsnk.idl | 7 +++++++ 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 01d9d2ddd89..a0c99c9365c 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -6298,10 +6298,10 @@ static HRESULT resolver_get_bytestream_url_hint(IMFByteStream *stream, WCHAR con return S_OK; } -static HRESULT resolver_create_gstreamer_handler(IMFByteStreamHandler **handler) +static HRESULT resolver_create_generic_handler(IMFByteStreamHandler **handler) { - static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; - return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); + static const GUID CLSID_WineByteStreamPlugin = {0x3f6eb6c1,0xea89,0x4312,{0x85,0x04,0x8d,0x82,0x10,0xbb,0xf8,0x8c}}; + return CoCreateInstance(&CLSID_WineByteStreamPlugin, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); } static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHAR *url, DWORD flags, @@ -6342,7 +6342,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA hr = resolver_create_bytestream_handler(stream, flags, mimeW, url_ext, handler); if (FAILED(hr)) - hr = resolver_create_gstreamer_handler(handler); + hr = resolver_create_generic_handler(handler); } CoTaskMemFree(mimeW); @@ -6360,7 +6360,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA hr = resolver_create_bytestream_handler(stream, flags, NULL, url_ext, handler); if (FAILED(hr)) - hr = resolver_create_gstreamer_handler(handler); + hr = resolver_create_generic_handler(handler); return hr; } diff --git a/dlls/mfsrcsnk/factory.c b/dlls/mfsrcsnk/factory.c index d8fe4268feb..b653c51a1e0 100644 --- a/dlls/mfsrcsnk/factory.c +++ b/dlls/mfsrcsnk/factory.c @@ -27,6 +27,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); */ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) { + static const GUID CLSID_WineByteStreamPlugin = {0x3f6eb6c1,0xea89,0x4312,{0x85,0x04,0x8d,0x82,0x10,0xbb,0xf8,0x8c}}; + *out = NULL; if (IsEqualGUID(clsid, &CLSID_AVIByteStreamPlugin)) @@ -35,6 +37,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) return IClassFactory_QueryInterface(&wav_byte_stream_plugin_factory, riid, out); if (IsEqualGUID(clsid, &CLSID_MP3ByteStreamPlugin)) return IClassFactory_QueryInterface(&mp3_byte_stream_plugin_factory, riid, out); + if (IsEqualGUID(clsid, &CLSID_WineByteStreamPlugin)) + return IClassFactory_QueryInterface(&wine_byte_stream_plugin_factory, riid, out); if (IsEqualGUID(clsid, &CLSID_MFWAVESinkClassFactory)) return IClassFactory_QueryInterface(wave_sink_class_factory, riid, out); diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 53bb00fb64a..1f506082565 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -2190,3 +2190,21 @@ static const IClassFactoryVtbl mp3_byte_stream_plugin_factory_vtbl = }; IClassFactory mp3_byte_stream_plugin_factory = {&mp3_byte_stream_plugin_factory_vtbl}; + +static HRESULT WINAPI wine_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, + IUnknown *outer, REFIID riid, void **out) +{ + const struct winedmo_demuxer_funcs *funcs = get_winedmo_demuxer_funcs("application/octet-stream"); + return byte_stream_plugin_create(funcs, outer, riid, out); +} + +static const IClassFactoryVtbl wine_byte_stream_plugin_factory_vtbl = +{ + class_factory_QueryInterface, + class_factory_AddRef, + class_factory_Release, + wine_byte_stream_plugin_factory_CreateInstance, + class_factory_LockServer, +}; + +IClassFactory wine_byte_stream_plugin_factory = {&wine_byte_stream_plugin_factory_vtbl}; diff --git a/dlls/mfsrcsnk/media_source.h b/dlls/mfsrcsnk/media_source.h index 7703e7634ec..3712493678c 100644 --- a/dlls/mfsrcsnk/media_source.h +++ b/dlls/mfsrcsnk/media_source.h @@ -25,3 +25,4 @@ extern IClassFactory avi_byte_stream_plugin_factory; extern IClassFactory mpeg4_byte_stream_plugin_factory; extern IClassFactory wav_byte_stream_plugin_factory; extern IClassFactory mp3_byte_stream_plugin_factory; +extern IClassFactory wine_byte_stream_plugin_factory; diff --git a/dlls/mfsrcsnk/mfsrcsnk.idl b/dlls/mfsrcsnk/mfsrcsnk.idl index e6473b355e9..573290b5b9a 100644 --- a/dlls/mfsrcsnk/mfsrcsnk.idl +++ b/dlls/mfsrcsnk/mfsrcsnk.idl @@ -45,3 +45,10 @@ coclass WAVByteStreamPlugin {} uuid(a82e50ba-8e92-41eb-9df2-433f50ec2993) ] coclass MP3ByteStreamPlugin {} + +[ + helpstring("Wine Byte Stream Handler"), + threading(both), + uuid(3f6eb6c1-ea89-4312-8504-8d8210bbf88c) +] +coclass WineByteStreamPlugin {} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9913
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/winegstreamer/Makefile.in | 1 - dlls/winegstreamer/gst_private.h | 2 - dlls/winegstreamer/media_source.c | 2080 ------------------ dlls/winegstreamer/mfplat.c | 2 - dlls/winegstreamer/winegstreamer_classes.idl | 7 - 5 files changed, 2092 deletions(-) delete mode 100644 dlls/winegstreamer/media_source.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 26f83901e4e..6abf84498c3 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -11,7 +11,6 @@ SOURCES = \ color_convert.c \ main.c \ media_sink.c \ - media_source.c \ mfplat.c \ quartz_parser.c \ quartz_transform.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 62f2aa71279..414b0d02aa9 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -175,8 +175,6 @@ HRESULT wg_transform_read_dmo(wg_transform_t transform, DMO_OUTPUT_DATA_BUFFER * HRESULT wg_transform_push_data(wg_transform_t transform, struct wg_sample *sample); HRESULT wg_transform_read_data(wg_transform_t transform, struct wg_sample *sample); -HRESULT gstreamer_byte_stream_handler_create(REFIID riid, void **obj); - unsigned int wg_format_get_stride(const struct wg_format *format); bool wg_video_format_is_rgb(enum wg_video_format format); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c deleted file mode 100644 index 05166d78cdb..00000000000 --- a/dlls/winegstreamer/media_source.c +++ /dev/null @@ -1,2080 +0,0 @@ -/* GStreamer Media Source - * - * Copyright 2020 Derek Lesho - * Copyright 2020 Zebediah Figura for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "gst_private.h" - -#include "mfapi.h" -#include "mferror.h" - -#include "wine/list.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -struct object_context -{ - IUnknown IUnknown_iface; - LONG refcount; - - IMFAsyncResult *result; - IMFByteStream *stream; - UINT64 file_size; - WCHAR *url; -}; - -static struct object_context *impl_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct object_context, IUnknown_iface); -} - -static HRESULT WINAPI object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - - if (IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IUnknown_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI object_context_AddRef(IUnknown *iface) -{ - struct object_context *context = impl_from_IUnknown(iface); - ULONG refcount = InterlockedIncrement(&context->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - return refcount; -} - -static ULONG WINAPI object_context_Release(IUnknown *iface) -{ - struct object_context *context = impl_from_IUnknown(iface); - ULONG refcount = InterlockedDecrement(&context->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - { - IMFAsyncResult_Release(context->result); - IMFByteStream_Release(context->stream); - free(context->url); - free(context); - } - - return refcount; -} - -static const IUnknownVtbl object_context_vtbl = -{ - object_context_QueryInterface, - object_context_AddRef, - object_context_Release, -}; - -static HRESULT object_context_create(DWORD flags, IMFByteStream *stream, const WCHAR *url, - QWORD file_size, IMFAsyncResult *result, IUnknown **out) -{ - WCHAR *tmp_url = url ? wcsdup(url) : NULL; - struct object_context *context; - - if (!(context = calloc(1, sizeof(*context)))) - { - free(tmp_url); - return E_OUTOFMEMORY; - } - - context->IUnknown_iface.lpVtbl = &object_context_vtbl; - context->refcount = 1; - context->stream = stream; - IMFByteStream_AddRef(context->stream); - context->file_size = file_size; - context->url = tmp_url; - context->result = result; - IMFAsyncResult_AddRef(context->result); - - *out = &context->IUnknown_iface; - return S_OK; -} - -struct media_stream -{ - IMFMediaStream IMFMediaStream_iface; - LONG ref; - - IMFMediaSource *media_source; - IMFMediaEventQueue *event_queue; - IMFStreamDescriptor *descriptor; - - wg_parser_stream_t wg_stream; - - IUnknown **token_queue; - LONG token_queue_count; - LONG token_queue_cap; - - DWORD stream_id; - BOOL active; - BOOL eos; -}; - -enum source_async_op -{ - SOURCE_ASYNC_START, - SOURCE_ASYNC_PAUSE, - SOURCE_ASYNC_STOP, - SOURCE_ASYNC_REQUEST_SAMPLE, -}; - -struct source_async_command -{ - IUnknown IUnknown_iface; - LONG refcount; - enum source_async_op op; - union - { - struct - { - IMFPresentationDescriptor *descriptor; - GUID format; - PROPVARIANT position; - } start; - struct - { - struct media_stream *stream; - IUnknown *token; - } request_sample; - } u; -}; - -struct media_source -{ - IMFMediaSource IMFMediaSource_iface; - IMFGetService IMFGetService_iface; - IMFRateSupport IMFRateSupport_iface; - IMFRateControl IMFRateControl_iface; - IMFAsyncCallback async_commands_callback; - LONG ref; - DWORD async_commands_queue; - IMFMediaEventQueue *event_queue; - IMFByteStream *byte_stream; - - CRITICAL_SECTION cs; - - UINT64 file_size; - wg_parser_t wg_parser; - UINT64 duration; - - IMFStreamDescriptor **descriptors; - struct media_stream **streams; - ULONG stream_count; - - enum - { - SOURCE_OPENING, - SOURCE_STOPPED, - SOURCE_PAUSED, - SOURCE_RUNNING, - SOURCE_SHUTDOWN, - } state; - float rate; - - HANDLE read_thread; - bool read_thread_shutdown; -}; - -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); -} - -static inline struct media_source *impl_from_IMFGetService(IMFGetService *iface) -{ - return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface); -} - -static inline struct media_source *impl_from_IMFRateSupport(IMFRateSupport *iface) -{ - return CONTAINING_RECORD(iface, struct media_source, IMFRateSupport_iface); -} - -static inline struct media_source *impl_from_IMFRateControl(IMFRateControl *iface) -{ - return CONTAINING_RECORD(iface, struct media_source, IMFRateControl_iface); -} - -static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct media_source, async_commands_callback); -} - -static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface); -} - -static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IUnknown_AddRef(iface); - return S_OK; - } - - WARN("Unsupported interface %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI source_async_command_AddRef(IUnknown *iface) -{ - struct source_async_command *command = impl_from_async_command_IUnknown(iface); - return InterlockedIncrement(&command->refcount); -} - -static ULONG WINAPI source_async_command_Release(IUnknown *iface) -{ - struct source_async_command *command = impl_from_async_command_IUnknown(iface); - ULONG refcount = InterlockedDecrement(&command->refcount); - - if (!refcount) - { - if (command->op == SOURCE_ASYNC_START) - { - IMFPresentationDescriptor_Release(command->u.start.descriptor); - PropVariantClear(&command->u.start.position); - } - else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE) - { - if (command->u.request_sample.token) - IUnknown_Release(command->u.request_sample.token); - } - free(command); - } - - return refcount; -} - -static const IUnknownVtbl source_async_command_vtbl = -{ - source_async_command_QueryInterface, - source_async_command_AddRef, - source_async_command_Release, -}; - -static HRESULT source_create_async_op(enum source_async_op op, IUnknown **out) -{ - struct source_async_command *command; - - if (!(command = calloc(1, sizeof(*command)))) - return E_OUTOFMEMORY; - - command->IUnknown_iface.lpVtbl = &source_async_command_vtbl; - command->refcount = 1; - command->op = op; - - *out = &command->IUnknown_iface; - return S_OK; -} - -static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - - if (IsEqualIID(riid, &IID_IMFAsyncCallback) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFAsyncCallback_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface, - DWORD *flags, DWORD *queue) -{ - return E_NOTIMPL; -} - -static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface) -{ - struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface); - return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); -} - -static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface) -{ - struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface); - return IMFMediaSource_Release(&source->IMFMediaSource_iface); -} - -static HRESULT stream_descriptor_get_media_type(IMFStreamDescriptor *descriptor, IMFMediaType **media_type) -{ - IMFMediaTypeHandler *handler; - HRESULT hr; - - if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler))) - return hr; - hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type); - IMFMediaTypeHandler_Release(handler); - - return hr; -} - -static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, struct wg_format *format) -{ - IMFMediaType *media_type; - HRESULT hr; - - if (FAILED(hr = stream_descriptor_get_media_type(descriptor, &media_type))) - return hr; - mf_media_type_to_wg_format(media_type, format); - IMFMediaType_Release(media_type); - - return hr; -} - -static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, wg_parser_stream_t stream, - const GUID *attr, enum wg_parser_tag tag) -{ - WCHAR *strW; - HRESULT hr; - DWORD len; - char *str; - - if (!(str = wg_parser_stream_get_tag(stream, tag)) - || !(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0))) - hr = S_OK; - else if (!(strW = malloc(len * sizeof(*strW)))) - hr = E_OUTOFMEMORY; - else - { - if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len)) - hr = IMFStreamDescriptor_SetString(descriptor, attr, strW); - else - hr = E_FAIL; - free(strW); - } - - free(str); - return hr; -} - -static HRESULT init_video_media_types(struct wg_format *format, IMFMediaType *types[6], DWORD *types_count) -{ - /* Try to prefer YUV formats over RGB ones. Most decoders output in the - * YUV color space, and it's generally much less expensive for - * videoconvert to do YUV -> YUV transformations. */ - static const enum wg_video_format video_formats[] = - { - WG_VIDEO_FORMAT_NV12, - WG_VIDEO_FORMAT_YV12, - WG_VIDEO_FORMAT_YUY2, - WG_VIDEO_FORMAT_I420, - }; - UINT count = *types_count, i; - GUID base_subtype; - HRESULT hr; - - if (FAILED(hr = IMFMediaType_GetGUID(types[0], &MF_MT_SUBTYPE, &base_subtype))) - return hr; - - for (i = 0; i < ARRAY_SIZE(video_formats); ++i) - { - struct wg_format new_format = *format; - IMFMediaType *new_type; - - new_format.u.video.format = video_formats[i]; - - if (!(new_type = mf_media_type_from_wg_format(&new_format))) - { - hr = E_OUTOFMEMORY; - goto done; - } - types[count++] = new_type; - - if (video_formats[i] == WG_VIDEO_FORMAT_I420) - { - IMFMediaType *iyuv_type; - - if (FAILED(hr = MFCreateMediaType(&iyuv_type))) - goto done; - if (FAILED(hr = IMFMediaType_CopyAllItems(new_type, (IMFAttributes *)iyuv_type))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(iyuv_type, &MF_MT_SUBTYPE, &MFVideoFormat_IYUV))) - goto done; - types[count++] = iyuv_type; - } - } - -done: - *types_count = count; - return hr; -} - -static HRESULT init_audio_media_types(struct wg_format *format, IMFMediaType *types[6], DWORD *types_count) -{ - /* Expose at least one PCM and one floating point type for the - consumer to pick from. */ - static const enum wg_audio_format audio_types[] = - { - WG_AUDIO_FORMAT_S16LE, - WG_AUDIO_FORMAT_F32LE, - }; - UINT count = *types_count, i; - - for (i = 0; i < ARRAY_SIZE(audio_types); i++) - { - struct wg_format new_format = *format; - if (new_format.u.audio.format == audio_types[i]) - continue; - new_format.u.audio.format = audio_types[i]; - if ((types[count] = mf_media_type_from_wg_format(&new_format))) - count++; - } - - *types_count = count; - return S_OK; -} - -static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMFStreamDescriptor **out) -{ - IMFStreamDescriptor *descriptor; - IMFMediaTypeHandler *handler; - IMFMediaType *types[6]; - DWORD count = 0; - HRESULT hr; - - if (!(types[0] = mf_media_type_from_wg_format(format))) - return MF_E_INVALIDMEDIATYPE; - count = 1; - - if (format->major_type == WG_MAJOR_TYPE_VIDEO) - { - if (FAILED(hr = init_video_media_types(format, types, &count))) - goto done; - } - else if (format->major_type == WG_MAJOR_TYPE_AUDIO) - { - if (FAILED(hr = init_audio_media_types(format, types, &count))) - goto done; - } - - assert(count <= ARRAY_SIZE(types)); - - if (FAILED(hr = MFCreateStreamDescriptor(id, count, types, &descriptor))) - goto done; - - if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler))) - IMFStreamDescriptor_Release(descriptor); - else - { - hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, types[0]); - IMFMediaTypeHandler_Release(handler); - } - -done: - while (count--) - IMFMediaType_Release(types[count]); - *out = SUCCEEDED(hr) ? descriptor : NULL; - return hr; -} - -static BOOL enqueue_token(struct media_stream *stream, IUnknown *token) -{ - if (stream->token_queue_count == stream->token_queue_cap) - { - IUnknown **buf; - stream->token_queue_cap = stream->token_queue_cap * 2 + 1; - buf = realloc(stream->token_queue, stream->token_queue_cap * sizeof(*buf)); - if (buf) - stream->token_queue = buf; - else - { - stream->token_queue_cap = stream->token_queue_count; - return FALSE; - } - } - stream->token_queue[stream->token_queue_count++] = token; - return TRUE; -} - -static void flush_token_queue(struct media_stream *stream, BOOL send) -{ - struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - LONG i; - - for (i = 0; i < stream->token_queue_count; i++) - { - if (send) - { - IUnknown *op; - HRESULT hr; - - if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op))) - { - struct source_async_command *command = impl_from_async_command_IUnknown(op); - command->u.request_sample.stream = stream; - command->u.request_sample.token = stream->token_queue[i]; - - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); - IUnknown_Release(op); - } - if (FAILED(hr)) - WARN("Could not enqueue sample request, hr %#lx\n", hr); - } - else if (stream->token_queue[i]) - IUnknown_Release(stream->token_queue[i]); - } - free(stream->token_queue); - stream->token_queue = NULL; - stream->token_queue_count = 0; - stream->token_queue_cap = 0; -} - -static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL seeking, const PROPVARIANT *position) -{ - struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - struct wg_format format; - HRESULT hr; - - TRACE("source %p, stream %p\n", source, stream); - - if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format))) - WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr); - wg_parser_stream_enable(stream->wg_stream, &format); - - if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream, - &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface))) - WARN("Failed to send source stream event, hr %#lx\n", hr); - return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, seeking ? MEStreamSeeked : MEStreamStarted, - &GUID_NULL, S_OK, position); -} - -static HRESULT media_source_start(struct media_source *source, IMFPresentationDescriptor *descriptor, - GUID *format, PROPVARIANT *position) -{ - BOOL starting = source->state == SOURCE_STOPPED, seek_message = !starting && position->vt != VT_EMPTY; - IMFStreamDescriptor **descriptors; - DWORD i, count; - HRESULT hr; - - TRACE("source %p, descriptor %p, format %s, position %s\n", source, descriptor, - debugstr_guid(format), wine_dbgstr_variant((VARIANT *)position)); - - if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; - - /* seek to beginning on stop->play */ - if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY) - { - position->vt = VT_I8; - position->hVal.QuadPart = 0; - } - - if (!(descriptors = calloc(source->stream_count, sizeof(*descriptors)))) - return E_OUTOFMEMORY; - - if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count))) - WARN("Failed to get presentation descriptor stream count, hr %#lx\n", hr); - - for (i = 0; i < count; i++) - { - IMFStreamDescriptor *stream_descriptor; - BOOL selected; - DWORD id; - - if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, - &selected, &stream_descriptor))) - WARN("Failed to get presentation stream descriptor, hr %#lx\n", hr); - else - { - if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(stream_descriptor, &id))) - WARN("Failed to get stream descriptor id, hr %#lx\n", hr); - else if (id >= source->stream_count) - WARN("Invalid stream descriptor id %lu, hr %#lx\n", id, hr); - else if (selected) - IMFStreamDescriptor_AddRef((descriptors[id] = stream_descriptor)); - - IMFStreamDescriptor_Release(stream_descriptor); - } - } - - for (i = 0; i < source->stream_count; i++) - { - struct media_stream *stream = source->streams[i]; - BOOL was_active = !starting && stream->active; - - if (position->vt != VT_EMPTY) - stream->eos = FALSE; - - if (!(stream->active = !!descriptors[i])) - wg_parser_stream_disable(stream->wg_stream); - else - { - if (FAILED(hr = media_stream_start(stream, was_active, seek_message, position))) - WARN("Failed to start media stream, hr %#lx\n", hr); - IMFStreamDescriptor_Release(descriptors[i]); - } - } - - free(descriptors); - - source->state = SOURCE_RUNNING; - - if (position->vt == VT_I8) - wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, position->hVal.QuadPart, 0, - AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); - - for (i = 0; i < source->stream_count; i++) - flush_token_queue(source->streams[i], position->vt == VT_EMPTY); - - return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, - seek_message ? MESourceSeeked : MESourceStarted, &GUID_NULL, S_OK, position); -} - -static HRESULT media_source_pause(struct media_source *source) -{ - unsigned int i; - HRESULT hr; - - TRACE("source %p\n", source); - - if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; - - for (i = 0; i < source->stream_count; i++) - { - struct media_stream *stream = source->streams[i]; - if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused, - &GUID_NULL, S_OK, NULL))) - WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr); - } - - source->state = SOURCE_PAUSED; - return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL); -} - -static HRESULT media_source_stop(struct media_source *source) -{ - unsigned int i; - HRESULT hr; - - TRACE("source %p\n", source); - - if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; - - for (i = 0; i < source->stream_count; i++) - { - struct media_stream *stream = source->streams[i]; - if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, - &GUID_NULL, S_OK, NULL))) - WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr); - } - - source->state = SOURCE_STOPPED; - - for (i = 0; i < source->stream_count; i++) - flush_token_queue(source->streams[i], FALSE); - - return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL); -} - -static HRESULT media_stream_send_sample(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token) -{ - IMFSample *sample = NULL; - IMFMediaBuffer *buffer; - HRESULT hr; - BYTE *data; - - if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer->size, &buffer))) - return hr; - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer->size))) - goto out; - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) - goto out; - - if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, wg_buffer->size)) - { - hr = S_FALSE; - wg_parser_stream_release_buffer(stream->wg_stream); - IMFMediaBuffer_Unlock(buffer); - goto out; - } - wg_parser_stream_release_buffer(stream->wg_stream); - - if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) - goto out; - - if (FAILED(hr = MFCreateSample(&sample))) - goto out; - if (FAILED(hr = IMFSample_AddBuffer(sample, buffer))) - goto out; - if (FAILED(hr = IMFSample_SetSampleTime(sample, wg_buffer->pts))) - goto out; - if (FAILED(hr = IMFSample_SetSampleDuration(sample, wg_buffer->duration))) - goto out; - if (token && FAILED(hr = IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token))) - goto out; - - hr = IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, - &GUID_NULL, S_OK, (IUnknown *)sample); - -out: - if (sample) - IMFSample_Release(sample); - IMFMediaBuffer_Release(buffer); - return hr; -} - -static HRESULT media_stream_send_eos(struct media_source *source, struct media_stream *stream) -{ - PROPVARIANT empty = {.vt = VT_EMPTY}; - HRESULT hr; - UINT i; - - TRACE("source %p, stream %p\n", source, stream); - - stream->eos = TRUE; - if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty))) - WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr); - - for (i = 0; i < source->stream_count; i++) - { - struct media_stream *stream = source->streams[i]; - if (stream->active && !stream->eos) - return S_OK; - } - - if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty))) - WARN("Failed to queue MEEndOfPresentation event, hr %#lx\n", hr); - return S_OK; -} - -static bool stream_get_buffer(struct media_stream *stream, struct wg_parser_buffer *buffer) -{ - struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - wg_parser_stream_t wg_stream = stream->wg_stream; - wg_parser_t wg_parser = source->wg_parser; - bool ret; - - LeaveCriticalSection(&source->cs); - ret = wg_parser_stream_get_buffer(wg_parser, wg_stream, buffer); - EnterCriticalSection(&source->cs); - - return ret; -} - -static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token) -{ - struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - struct wg_parser_buffer buffer; - - TRACE("%p, %p\n", stream, token); - - while (stream_get_buffer(stream, &buffer)) - { - HRESULT hr = media_stream_send_sample(stream, &buffer, token); - if (hr != S_FALSE) - return hr; - } - - if (source->state == SOURCE_SHUTDOWN) - return S_OK; - - return media_stream_send_eos(source, stream); -} - -static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -{ - struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface); - struct source_async_command *command; - IUnknown *state; - HRESULT hr; - - if (FAILED(hr = IMFAsyncResult_GetState(result, &state))) - return hr; - - EnterCriticalSection(&source->cs); - - command = impl_from_async_command_IUnknown(state); - switch (command->op) - { - case SOURCE_ASYNC_START: - { - IMFPresentationDescriptor *descriptor = command->u.start.descriptor; - GUID format = command->u.start.format; - PROPVARIANT position = command->u.start.position; - - if (FAILED(hr = media_source_start(source, descriptor, &format, &position))) - WARN("Failed to start source %p, hr %#lx\n", source, hr); - break; - } - case SOURCE_ASYNC_PAUSE: - if (FAILED(hr = media_source_pause(source))) - WARN("Failed to pause source %p, hr %#lx\n", source, hr); - break; - case SOURCE_ASYNC_STOP: - if (FAILED(hr = media_source_stop(source))) - WARN("Failed to stop source %p, hr %#lx\n", source, hr); - break; - case SOURCE_ASYNC_REQUEST_SAMPLE: - if (source->state == SOURCE_PAUSED) - enqueue_token(command->u.request_sample.stream, command->u.request_sample.token); - else if (source->state == SOURCE_RUNNING) - { - if (FAILED(hr = wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token))) - WARN("Failed to request sample, hr %#lx\n", hr); - } - break; - } - - LeaveCriticalSection(&source->cs); - - IUnknown_Release(state); - - return S_OK; -} - -static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl = -{ - callback_QueryInterface, - source_async_commands_callback_AddRef, - source_async_commands_callback_Release, - callback_GetParameters, - source_async_commands_Invoke, -}; - -static DWORD CALLBACK read_thread(void *arg) -{ - struct media_source *source = arg; - IMFByteStream *byte_stream = source->byte_stream; - size_t buffer_size = 4096; - QWORD file_size; - void *data; - - if (!(data = malloc(buffer_size))) - return 0; - - IMFByteStream_GetLength(byte_stream, &file_size); - - TRACE("Starting read thread for media source %p.\n", source); - - while (!source->read_thread_shutdown) - { - uint64_t offset; - ULONG ret_size; - uint32_t size; - HRESULT hr; - - if (!wg_parser_get_next_read_offset(source->wg_parser, &offset, &size)) - continue; - - if (offset >= file_size) - size = 0; - else if (offset + size >= file_size) - size = file_size - offset; - - /* Some IMFByteStreams (including the standard file-based stream) return - * an error when reading past the file size. */ - if (!size) - { - wg_parser_push_data(source->wg_parser, data, 0); - continue; - } - - if (!array_reserve(&data, &buffer_size, size, 1)) - { - free(data); - return 0; - } - - ret_size = 0; - - if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset))) - hr = IMFByteStream_Read(byte_stream, data, size, &ret_size); - if (FAILED(hr)) - ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); - else if (ret_size != size) - ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size); - wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); - } - - free(data); - TRACE("Media source is shutting down; exiting.\n"); - return 0; -} - -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", iface, 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, refcount %lu.\n", iface, 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, refcount %lu.\n", iface, ref); - - if (!ref) - { - IMFMediaSource_Release(stream->media_source); - IMFStreamDescriptor_Release(stream->descriptor); - IMFMediaEventQueue_Release(stream->event_queue); - flush_token_queue(stream, FALSE); - 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, %#lx, %p.\n", iface, flags, event); - - 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", iface, callback, state); - - 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); - - 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, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); - - return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value); -} - -static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **out) -{ - struct media_stream *stream = impl_from_IMFMediaStream(iface); - struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - HRESULT hr = S_OK; - - TRACE("%p, %p.\n", iface, out); - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else - { - IMFMediaSource_AddRef(&source->IMFMediaSource_iface); - *out = &source->IMFMediaSource_iface; - } - - LeaveCriticalSection(&source->cs); - - return hr; -} - -static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor) -{ - struct media_stream *stream = impl_from_IMFMediaStream(iface); - struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - HRESULT hr = S_OK; - - TRACE("%p, %p.\n", iface, descriptor); - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else - { - IMFStreamDescriptor_AddRef(stream->descriptor); - *descriptor = stream->descriptor; - } - - LeaveCriticalSection(&source->cs); - - return hr; -} - -static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) -{ - struct media_stream *stream = impl_from_IMFMediaStream(iface); - struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - IUnknown *op; - HRESULT hr; - - TRACE("%p, %p.\n", iface, token); - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else if (!stream->active) - hr = MF_E_MEDIA_SOURCE_WRONGSTATE; - else if (stream->eos) - hr = MF_E_END_OF_STREAM; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op))) - { - struct source_async_command *command = impl_from_async_command_IUnknown(op); - command->u.request_sample.stream = stream; - if (token) - IUnknown_AddRef(token); - command->u.request_sample.token = token; - - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); - IUnknown_Release(op); - } - - LeaveCriticalSection(&source->cs); - - return hr; -} - -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 -}; - -static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor *descriptor, - wg_parser_stream_t wg_stream, struct media_stream **out) -{ - struct media_stream *object; - HRESULT hr; - - TRACE("source %p, descriptor %p, wg_stream %#I64x.\n", source, descriptor, wg_stream); - - if (!(object = calloc(1, sizeof(*object)))) - return E_OUTOFMEMORY; - - object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; - object->ref = 1; - - if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) - { - free(object); - return hr; - } - - IMFMediaSource_AddRef(source); - object->media_source = source; - IMFStreamDescriptor_AddRef(descriptor); - object->descriptor = descriptor; - - object->active = TRUE; - object->eos = FALSE; - object->wg_stream = wg_stream; - - TRACE("Created stream object %p.\n", object); - - *out = object; - return S_OK; -} - -static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) -{ - struct media_source *source = impl_from_IMFGetService(iface); - return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); -} - -static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface) -{ - struct media_source *source = impl_from_IMFGetService(iface); - return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); -} - -static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface) -{ - struct media_source *source = impl_from_IMFGetService(iface); - return IMFMediaSource_Release(&source->IMFMediaSource_iface); -} - -static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) -{ - struct media_source *source = impl_from_IMFGetService(iface); - - TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj); - - *obj = NULL; - - if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE)) - { - if (IsEqualIID(riid, &IID_IMFRateSupport)) - { - *obj = &source->IMFRateSupport_iface; - } - else if (IsEqualIID(riid, &IID_IMFRateControl)) - { - *obj = &source->IMFRateControl_iface; - } - } - else - FIXME("Unsupported service %s.\n", debugstr_guid(service)); - - if (*obj) - IUnknown_AddRef((IUnknown *)*obj); - - return *obj ? S_OK : E_NOINTERFACE; -} - -static const IMFGetServiceVtbl media_source_get_service_vtbl = -{ - media_source_get_service_QueryInterface, - media_source_get_service_AddRef, - media_source_get_service_Release, - media_source_get_service_GetService, -}; - -static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj) -{ - struct media_source *source = impl_from_IMFRateSupport(iface); - return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); -} - -static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface) -{ - struct media_source *source = impl_from_IMFRateSupport(iface); - return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); -} - -static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface) -{ - struct media_source *source = impl_from_IMFRateSupport(iface); - return IMFMediaSource_Release(&source->IMFMediaSource_iface); -} - -static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate) -{ - TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate); - - *rate = 0.0f; - - return S_OK; -} - -static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate) -{ - TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate); - - *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f; - - return S_OK; -} - -static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate, - float *nearest_rate) -{ - TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_rate); - - if (nearest_rate) - *nearest_rate = rate; - - return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE; -} - -static const IMFRateSupportVtbl media_source_rate_support_vtbl = -{ - media_source_rate_support_QueryInterface, - media_source_rate_support_AddRef, - media_source_rate_support_Release, - media_source_rate_support_GetSlowestRate, - media_source_rate_support_GetFastestRate, - media_source_rate_support_IsRateSupported, -}; - -static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj) -{ - struct media_source *source = impl_from_IMFRateControl(iface); - return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); -} - -static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface) -{ - struct media_source *source = impl_from_IMFRateControl(iface); - return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); -} - -static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface) -{ - struct media_source *source = impl_from_IMFRateControl(iface); - return IMFMediaSource_Release(&source->IMFMediaSource_iface); -} - -static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate) -{ - struct media_source *source = impl_from_IMFRateControl(iface); - HRESULT hr; - - FIXME("%p, %d, %f.\n", iface, thin, rate); - - if (rate < 0.0f) - return MF_E_REVERSE_UNSUPPORTED; - - if (thin) - return MF_E_THINNING_UNSUPPORTED; - - if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) - return hr; - - EnterCriticalSection(&source->cs); - source->rate = rate; - LeaveCriticalSection(&source->cs); - - return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); -} - -static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate) -{ - struct media_source *source = impl_from_IMFRateControl(iface); - - TRACE("%p, %p, %p.\n", iface, thin, rate); - - if (thin) - *thin = FALSE; - - EnterCriticalSection(&source->cs); - *rate = source->rate; - LeaveCriticalSection(&source->cs); - - return S_OK; -} - -static const IMFRateControlVtbl media_source_rate_control_vtbl = -{ - media_source_rate_control_QueryInterface, - media_source_rate_control_AddRef, - media_source_rate_control_Release, - media_source_rate_control_SetRate, - media_source_rate_control_GetRate, -}; - -static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); - - if (IsEqualIID(riid, &IID_IMFMediaSource) || - IsEqualIID(riid, &IID_IMFMediaEventGenerator) || - IsEqualIID(riid, &IID_IUnknown)) - { - *out = &source->IMFMediaSource_iface; - } - else if (IsEqualIID(riid, &IID_IMFGetService)) - { - *out = &source->IMFGetService_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_source_AddRef(IMFMediaSource *iface) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - ULONG ref = InterlockedIncrement(&source->ref); - - TRACE("%p, refcount %lu.\n", iface, ref); - - return ref; -} - -static ULONG WINAPI media_source_Release(IMFMediaSource *iface) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - ULONG ref = InterlockedDecrement(&source->ref); - - TRACE("%p, refcount %lu.\n", iface, ref); - - if (!ref) - { - IMFMediaSource_Shutdown(iface); - IMFMediaEventQueue_Release(source->event_queue); - IMFByteStream_Release(source->byte_stream); - wg_parser_destroy(source->wg_parser); - source->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&source->cs); - free(source); - } - - return ref; -} - -static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - - TRACE("%p, %#lx, %p.\n", iface, flags, event); - - return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event); -} - -static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - - TRACE("%p, %p, %p.\n", iface, callback, state); - - return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state); -} - -static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - - TRACE("%p, %p, %p.\n", iface, result, event); - - return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event); -} - -static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, - HRESULT hr, const PROPVARIANT *value) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - - TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); - - return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value); -} - -static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - HRESULT hr = S_OK; - - TRACE("%p, %p.\n", iface, characteristics); - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else - *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE; - - LeaveCriticalSection(&source->cs); - - return hr; -} - -static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - HRESULT hr; - UINT i; - - TRACE("%p, %p.\n", iface, descriptor); - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else if (SUCCEEDED(hr = MFCreatePresentationDescriptor(source->stream_count, source->descriptors, descriptor))) - { - if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_DURATION, source->duration))) - WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr); - - for (i = 0; i < source->stream_count; ++i) - { - if (FAILED(hr = IMFPresentationDescriptor_SelectStream(*descriptor, i))) - WARN("Failed to select stream %u, hr %#lx\n", i, hr); - } - - hr = S_OK; - } - - LeaveCriticalSection(&source->cs); - - return hr; -} - -static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, - const GUID *time_format, const PROPVARIANT *position) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - IUnknown *op; - HRESULT hr; - - TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position); - - if (!time_format) - time_format = &GUID_NULL; - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else if (!(IsEqualIID(time_format, &GUID_NULL))) - hr = MF_E_UNSUPPORTED_TIME_FORMAT; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &op))) - { - struct source_async_command *command = impl_from_async_command_IUnknown(op); - command->u.start.descriptor = descriptor; - IMFPresentationDescriptor_AddRef(descriptor); - command->u.start.format = *time_format; - PropVariantCopy(&command->u.start.position, position); - - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); - IUnknown_Release(op); - } - - LeaveCriticalSection(&source->cs); - - return hr; -} - -static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - IUnknown *op; - HRESULT hr; - - TRACE("%p.\n", iface); - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &op))) - { - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); - IUnknown_Release(op); - } - - LeaveCriticalSection(&source->cs); - - return hr; -} - -static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - IUnknown *op; - HRESULT hr; - - TRACE("%p.\n", iface); - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else if (source->state != SOURCE_RUNNING) - hr = MF_E_INVALID_STATE_TRANSITION; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &op))) - { - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); - IUnknown_Release(op); - } - - LeaveCriticalSection(&source->cs); - - return hr; -} - -static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) -{ - struct media_source *source = impl_from_IMFMediaSource(iface); - - TRACE("%p.\n", iface); - - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - { - LeaveCriticalSection(&source->cs); - return MF_E_SHUTDOWN; - } - - source->state = SOURCE_SHUTDOWN; - - wg_parser_disconnect(source->wg_parser); - - source->read_thread_shutdown = true; - WaitForSingleObject(source->read_thread, INFINITE); - CloseHandle(source->read_thread); - - IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEError, &GUID_NULL, MF_E_SHUTDOWN, NULL); - IMFMediaEventQueue_Shutdown(source->event_queue); - IMFByteStream_Close(source->byte_stream); - - while (source->stream_count--) - { - struct media_stream *stream = source->streams[source->stream_count]; - IMFStreamDescriptor_Release(source->descriptors[source->stream_count]); - IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEError, &GUID_NULL, MF_E_SHUTDOWN, NULL); - IMFMediaEventQueue_Shutdown(stream->event_queue); - IMFMediaStream_Release(&stream->IMFMediaStream_iface); - } - free(source->descriptors); - free(source->streams); - - LeaveCriticalSection(&source->cs); - - MFUnlockWorkQueue(source->async_commands_queue); - - return S_OK; -} - -static const IMFMediaSourceVtbl IMFMediaSource_vtbl = -{ - media_source_QueryInterface, - media_source_AddRef, - media_source_Release, - media_source_GetEvent, - media_source_BeginGetEvent, - media_source_EndGetEvent, - media_source_QueueEvent, - media_source_GetCharacteristics, - media_source_CreatePresentationDescriptor, - media_source_Start, - media_source_Stop, - media_source_Pause, - media_source_Shutdown, -}; - -static void media_source_init_descriptors(struct media_source *source) -{ - HRESULT hr = S_OK; - UINT i; - - for (i = 0; i < source->stream_count; i++) - { - struct media_stream *stream = source->streams[i]; - IMFStreamDescriptor *descriptor = stream->descriptor; - - if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream, - &MF_SD_LANGUAGE, WG_PARSER_TAG_LANGUAGE))) - WARN("Failed to set stream descriptor language, hr %#lx\n", hr); - if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream, - &MF_SD_STREAM_NAME, WG_PARSER_TAG_NAME))) - WARN("Failed to set stream descriptor name, hr %#lx\n", hr); - } -} - -static HRESULT media_source_create(struct object_context *context, IMFMediaSource **out) -{ - unsigned int stream_count = UINT_MAX; - struct media_source *object; - wg_parser_t parser; - unsigned int i; - HRESULT hr; - - if (!(object = calloc(1, sizeof(*object)))) - return E_OUTOFMEMORY; - - object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; - object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl; - object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl; - object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl; - object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl; - object->ref = 1; - object->byte_stream = context->stream; - IMFByteStream_AddRef(context->stream); - object->file_size = context->file_size; - object->rate = 1.0f; - InitializeCriticalSectionEx(&object->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); - - if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) - goto fail; - - if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) - goto fail; - - if (!(parser = wg_parser_create(FALSE))) - { - hr = E_OUTOFMEMORY; - goto fail; - } - object->wg_parser = parser; - - object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL); - - object->state = SOURCE_OPENING; - - if (FAILED(hr = wg_parser_connect(parser, object->file_size, context->url))) - goto fail; - - stream_count = wg_parser_get_stream_count(parser); - - if (!(object->descriptors = calloc(stream_count, sizeof(*object->descriptors))) - || !(object->streams = calloc(stream_count, sizeof(*object->streams)))) - { - hr = E_OUTOFMEMORY; - goto fail; - } - - for (i = 0; i < stream_count; ++i) - { - wg_parser_stream_t wg_stream = wg_parser_get_stream(object->wg_parser, i); - IMFStreamDescriptor *descriptor; - struct media_stream *stream; - struct wg_format format; - - wg_parser_stream_get_current_format(wg_stream, &format); - if (FAILED(hr = stream_descriptor_create(i, &format, &descriptor))) - goto fail; - if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, descriptor, wg_stream, &stream))) - { - IMFStreamDescriptor_Release(descriptor); - goto fail; - } - - object->duration = max(object->duration, wg_parser_stream_get_duration(wg_stream)); - IMFStreamDescriptor_AddRef(descriptor); - object->descriptors[i] = descriptor; - object->streams[i] = stream; - object->stream_count++; - } - - media_source_init_descriptors(object); - object->state = SOURCE_STOPPED; - - *out = &object->IMFMediaSource_iface; - TRACE("Created IMFMediaSource %p\n", *out); - return S_OK; - -fail: - WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr); - - while (object->streams && object->stream_count--) - { - struct media_stream *stream = object->streams[object->stream_count]; - IMFStreamDescriptor_Release(object->descriptors[object->stream_count]); - IMFMediaStream_Release(&stream->IMFMediaStream_iface); - } - free(object->descriptors); - free(object->streams); - - if (stream_count != UINT_MAX) - wg_parser_disconnect(object->wg_parser); - if (object->read_thread) - { - object->read_thread_shutdown = true; - WaitForSingleObject(object->read_thread, INFINITE); - CloseHandle(object->read_thread); - } - if (object->wg_parser) - wg_parser_destroy(object->wg_parser); - if (object->async_commands_queue) - MFUnlockWorkQueue(object->async_commands_queue); - if (object->event_queue) - IMFMediaEventQueue_Release(object->event_queue); - IMFByteStream_Release(object->byte_stream); - free(object); - return hr; -} - -struct result_entry -{ - struct list entry; - IMFAsyncResult *result; - MF_OBJECT_TYPE type; - IUnknown *object; -}; - -static HRESULT result_entry_create(IMFAsyncResult *result, MF_OBJECT_TYPE type, - IUnknown *object, struct result_entry **out) -{ - struct result_entry *entry; - - if (!(entry = malloc(sizeof(*entry)))) - return E_OUTOFMEMORY; - - entry->result = result; - IMFAsyncResult_AddRef(entry->result); - entry->object = object; - IUnknown_AddRef(entry->object); - entry->type = type; - - *out = entry; - return S_OK; -} - -static void result_entry_destroy(struct result_entry *entry) -{ - IMFAsyncResult_Release(entry->result); - IUnknown_Release(entry->object); - free(entry); -} - -struct stream_handler -{ - IMFByteStreamHandler IMFByteStreamHandler_iface; - IMFAsyncCallback IMFAsyncCallback_iface; - LONG refcount; - struct list results; - CRITICAL_SECTION cs; -}; - -static struct result_entry *handler_find_result_entry(struct stream_handler *handler, IMFAsyncResult *result) -{ - struct result_entry *entry; - - EnterCriticalSection(&handler->cs); - LIST_FOR_EACH_ENTRY(entry, &handler->results, struct result_entry, entry) - { - if (result == entry->result) - { - list_remove(&entry->entry); - LeaveCriticalSection(&handler->cs); - return entry; - } - } - LeaveCriticalSection(&handler->cs); - - return NULL; -} - -static struct stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) -{ - return CONTAINING_RECORD(iface, struct stream_handler, IMFByteStreamHandler_iface); -} - -static struct stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct stream_handler, IMFAsyncCallback_iface); -} - -static HRESULT WINAPI stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - - if (IsEqualIID(riid, &IID_IMFByteStreamHandler) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFByteStreamHandler_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI stream_handler_AddRef(IMFByteStreamHandler *iface) -{ - struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface); - ULONG refcount = InterlockedIncrement(&handler->refcount); - - TRACE("%p, refcount %lu.\n", handler, refcount); - - return refcount; -} - -static ULONG WINAPI stream_handler_Release(IMFByteStreamHandler *iface) -{ - struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface); - ULONG refcount = InterlockedDecrement(&handler->refcount); - struct result_entry *result, *next; - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - { - LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct result_entry, entry) - result_entry_destroy(result); - DeleteCriticalSection(&handler->cs); - free(handler); - } - - return refcount; -} - -static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags, - IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) -{ - struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface); - IMFAsyncResult *result; - IUnknown *context; - QWORD file_size; - HRESULT hr; - DWORD caps; - - TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); - - if (cancel_cookie) - *cancel_cookie = NULL; - - if (!stream) - return E_INVALIDARG; - if (flags != MF_RESOLUTION_MEDIASOURCE) - FIXME("Unimplemented flags %#lx\n", flags); - - if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps))) - return hr; - if (!(caps & MFBYTESTREAM_IS_SEEKABLE)) - { - FIXME("Non-seekable bytestreams not supported.\n"); - return MF_E_BYTESTREAM_NOT_SEEKABLE; - } - if (FAILED(hr = IMFByteStream_GetLength(stream, &file_size))) - { - FIXME("Failed to get byte stream length, hr %#lx.\n", hr); - return hr; - } - - if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &result))) - return hr; - if (FAILED(hr = object_context_create(flags, stream, url, file_size, result, &context))) - { - IMFAsyncResult_Release(result); - return hr; - } - - hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_IO, &handler->IMFAsyncCallback_iface, context); - IUnknown_Release(context); - - if (SUCCEEDED(hr) && cancel_cookie) - { - *cancel_cookie = (IUnknown *)result; - IUnknown_AddRef(*cancel_cookie); - } - - IMFAsyncResult_Release(result); - - return hr; -} - -static HRESULT WINAPI stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, - MF_OBJECT_TYPE *type, IUnknown **object) -{ - struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface); - struct result_entry *entry; - HRESULT hr; - - TRACE("%p, %p, %p, %p.\n", iface, result, type, object); - - if (!(entry = handler_find_result_entry(handler, result))) - { - *type = MF_OBJECT_INVALID; - *object = NULL; - return MF_E_UNEXPECTED; - } - - hr = IMFAsyncResult_GetStatus(entry->result); - *type = entry->type; - *object = entry->object; - IUnknown_AddRef(*object); - result_entry_destroy(entry); - return hr; -} - -static HRESULT WINAPI stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cookie) -{ - struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface); - IMFAsyncResult *result = (IMFAsyncResult *)cookie; - struct result_entry *entry; - - TRACE("%p, %p.\n", iface, cookie); - - if (!(entry = handler_find_result_entry(handler, result))) - return MF_E_UNEXPECTED; - - result_entry_destroy(entry); - return S_OK; -} - -static HRESULT WINAPI stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) -{ - FIXME("stub (%p %p)\n", iface, bytes); - return E_NOTIMPL; -} - -static const IMFByteStreamHandlerVtbl stream_handler_vtbl = -{ - stream_handler_QueryInterface, - stream_handler_AddRef, - stream_handler_Release, - stream_handler_BeginCreateObject, - stream_handler_EndCreateObject, - stream_handler_CancelObjectCreation, - stream_handler_GetMaxNumberOfBytesRequiredForResolution, -}; - -static HRESULT WINAPI stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFAsyncCallback) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFAsyncCallback_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI stream_handler_callback_AddRef(IMFAsyncCallback *iface) -{ - struct stream_handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface); -} - -static ULONG WINAPI stream_handler_callback_Release(IMFAsyncCallback *iface) -{ - struct stream_handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); -} - -static HRESULT WINAPI stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -{ - return E_NOTIMPL; -} - -static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -{ - struct stream_handler *handler = impl_from_IMFAsyncCallback(iface); - IUnknown *object, *state = IMFAsyncResult_GetStateNoAddRef(result); - struct object_context *context; - struct result_entry *entry; - HRESULT hr; - - if (!state || !(context = impl_from_IUnknown(state))) - return E_INVALIDARG; - - if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object))) - WARN("Failed to create media source, hr %#lx\n", hr); - else - { - if (FAILED(hr = result_entry_create(context->result, MF_OBJECT_MEDIASOURCE, object, &entry))) - WARN("Failed to create handler result, hr %#lx\n", hr); - else - { - EnterCriticalSection(&handler->cs); - list_add_tail(&handler->results, &entry->entry); - LeaveCriticalSection(&handler->cs); - } - - IUnknown_Release(object); - } - - IMFAsyncResult_SetStatus(context->result, hr); - MFInvokeCallback(context->result); - - return S_OK; -} - -static const IMFAsyncCallbackVtbl stream_handler_callback_vtbl = -{ - stream_handler_callback_QueryInterface, - stream_handler_callback_AddRef, - stream_handler_callback_Release, - stream_handler_callback_GetParameters, - stream_handler_callback_Invoke, -}; - -HRESULT gstreamer_byte_stream_handler_create(REFIID riid, void **obj) -{ - struct stream_handler *handler; - HRESULT hr; - - TRACE("%s, %p.\n", debugstr_guid(riid), obj); - - if (!(handler = calloc(1, sizeof(*handler)))) - return E_OUTOFMEMORY; - - list_init(&handler->results); - InitializeCriticalSection(&handler->cs); - - handler->IMFByteStreamHandler_iface.lpVtbl = &stream_handler_vtbl; - handler->IMFAsyncCallback_iface.lpVtbl = &stream_handler_callback_vtbl; - handler->refcount = 1; - - hr = IMFByteStreamHandler_QueryInterface(&handler->IMFByteStreamHandler_iface, riid, obj); - IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); - - return hr; -} diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 4088a935625..242c483952d 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -120,7 +120,6 @@ static const IClassFactoryVtbl class_factory_vtbl = class_factory_LockServer, }; -static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; static const GUID CLSID_wg_video_processor = {0xd527607f,0x89cb,0x4e94,{0x95,0x71,0xbc,0xfe,0x62,0x17,0x56,0x13}}; static const GUID CLSID_wg_aac_decoder = {0xe7889a8a,0x2083,0x4844,{0x83,0x70,0x5e,0xe3,0x49,0xb1,0x45,0x03}}; static const GUID CLSID_wg_h264_decoder = {0x1f1e273d,0x12c0,0x4b3a,{0x8e,0x9b,0x19,0x33,0xc2,0x49,0x8a,0xea}}; @@ -134,7 +133,6 @@ static const struct class_object class_objects[] = { { &CLSID_wg_video_processor, &video_processor_create }, - { &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create }, { &CLSID_wg_aac_decoder, &aac_decoder_create }, { &CLSID_wg_h264_decoder, &h264_decoder_create }, { &CLSID_wg_h264_encoder, &h264_encoder_create }, diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index bb9f81c2341..487550a47f5 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -70,13 +70,6 @@ coclass decodebin_parser {} ] coclass wg_video_processor {} -[ - helpstring("Generic Decodebin Byte Stream Handler"), - threading(both), - uuid(317df618-5e5a-468a-9f15-d827a9a08162) -] -coclass GStreamerByteStreamHandler {} - [ threading(both), uuid(5b4d4e54-0620-4cf9-94ae-7823965c28b6) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9913
From: Rémi Bernon <rbernon@codeweavers.com> --- configure.ac | 60 ++++++++++++++++++++++++------------- dlls/winedmo/unix_private.h | 8 +++++ dlls/winedmo4/Makefile.in | 12 ++++++++ dlls/winedmo4/winedmo4.spec | 8 +++++ dlls/winedmo5/Makefile.in | 12 ++++++++ dlls/winedmo5/winedmo5.spec | 8 +++++ dlls/winedmo6/Makefile.in | 12 ++++++++ dlls/winedmo6/winedmo6.spec | 8 +++++ dlls/winedmo7/Makefile.in | 12 ++++++++ dlls/winedmo7/winedmo7.spec | 8 +++++ dlls/winedmo8/Makefile.in | 12 ++++++++ dlls/winedmo8/winedmo8.spec | 8 +++++ 12 files changed, 148 insertions(+), 20 deletions(-) create mode 100644 dlls/winedmo4/Makefile.in create mode 100644 dlls/winedmo4/winedmo4.spec create mode 100644 dlls/winedmo5/Makefile.in create mode 100644 dlls/winedmo5/winedmo5.spec create mode 100644 dlls/winedmo6/Makefile.in create mode 100644 dlls/winedmo6/winedmo6.spec create mode 100644 dlls/winedmo7/Makefile.in create mode 100644 dlls/winedmo7/winedmo7.spec create mode 100644 dlls/winedmo8/Makefile.in create mode 100644 dlls/winedmo8/winedmo8.spec diff --git a/configure.ac b/configure.ac index da4a0af4a60..ca1e7850122 100644 --- a/configure.ac +++ b/configure.ac @@ -1684,26 +1684,41 @@ WINE_NOTICE_WITH(pulse, [test -z "$PULSE_LIBS"], [libpulse ${notice_platform}development files not found or too old, Pulse won't be supported.], [enable_winepulse_drv]) -dnl **** Check for FFmpeg **** -if test "x$with_ffmpeg" != "xno"; -then - WINE_PACKAGE_FLAGS(FFMPEG,[libavutil libavformat libavcodec],,,, - [AC_CHECK_HEADERS([libavutil/avutil.h libavformat/avformat.h libavcodec/avcodec.h libavcodec/bsf.h]) - if test "$ac_cv_header_libavutil_avutil_h" = "yes" -a "$ac_cv_header_libavformat_avformat_h" = "yes" -a "$ac_cv_header_libavcodec_avcodec_h" = "yes" - then - AC_CHECK_LIB(avutil,av_log_set_callback, - [AC_CHECK_LIB(avformat,av_find_input_format, - [AC_CHECK_LIB(avcodec,avcodec_get_name, - [AC_DEFINE(HAVE_FFMPEG, 1, [Define to 1 if you have the FFmpeg libraries.])], - [FFMPEG_LIBS=""],[$FFMPEG_LIBS])], - [FFMPEG_LIBS=""],[$FFMPEG_LIBS])], - [FFMPEG_LIBS=""],[$FFMPEG_LIBS]) - else - FFMPEG_LIBS="" - fi]) -fi -WINE_NOTICE_WITH(ffmpeg,[test "x$FFMPEG_LIBS" = x], - [FFmpeg ${notice_platform}development files not found.]) +m4_foreach([ffmpeg_version],[4,5,6,7,8,],[ + m4_define([ffmpeg_libraries],[m4_case(ffmpeg_version,[4],[libavutil 'libavformat >= 58' 'libavformat < 59' 'libavcodec >= 58' 'libavcodec < 59'], + [5],[libavutil 'libavformat >= 59' 'libavformat < 60' 'libavcodec >= 59' 'libavcodec < 60'], + [6],[libavutil 'libavformat >= 60' 'libavformat < 61' 'libavcodec >= 60' 'libavcodec < 61'], + [7],[libavutil 'libavformat >= 61' 'libavformat < 62' 'libavcodec >= 61' 'libavcodec < 62'], + [8],[libavutil 'libavformat >= 62' 'libavformat < 63' 'libavcodec >= 62' 'libavcodec < 63'], + [libavutil libavformat libavcodec])]) + + AS_CASE([$with_ffmpeg],m4_if(ffmpeg_version,[],[[""|,*|*,]],[ffmpeg_version[|*,]ffmpeg_version[|]ffmpeg_version[,*|*,]ffmpeg_version[,*]]),[ + ac_save_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" + PKG_CONFIG_PATH="[$FFMPEG]ffmpeg_version[_PKG_CONFIG_PATH]:$PKG_CONFIG_PATH" + + WINE_PACKAGE_FLAGS([FFMPEG]ffmpeg_version,ffmpeg_libraries,,,, + [AC_CHECK_HEADERS([libavutil/avutil.h + libavformat/avformat.h + libavcodec/avcodec.h + libavcodec/bsf.h]) + if test "$ac_cv_header_libavutil_avutil_h" = "yes" \ + -a "$ac_cv_header_libavformat_avformat_h" = "yes" \ + -a "$ac_cv_header_libavcodec_avcodec_h" = "yes" \ + ; then + AC_DEFINE([HAVE_FFMPEG]ffmpeg_version, 1, [Define to 1 if you have the FFmpeg libraries.]) + else + [FFMPEG]ffmpeg_version[_LIBS]="" + fi]) + + m4_if(ffmpeg_version,[],[], + WINE_TRY_CFLAGS([-Wno-deprecated-declarations],[FFMPEG]ffmpeg_version[_CFLAGS="-Wno-deprecated-declarations $FFMPEG]ffmpeg_version[_CFLAGS"])) + + WINE_NOTICE_WITH(ffmpeg,[test "x$[FFMPEG]ffmpeg_version[_LIBS]" = x], + [FFmpeg]ffmpeg_version[ ${notice_platform}development files not found.], + m4_if(ffmpeg_version,[],[],[enable_winedmo]ffmpeg_version)) + PKG_CONFIG_PATH="$ac_save_PKG_CONFIG_PATH" + ],[m4_if(ffmpeg_version,[],[],[enable_winedmo]ffmpeg_version=${[enable_winedmo]ffmpeg_version:-no})]) +]) dnl **** Check for gstreamer **** if test "x$with_gstreamer" != "xno" @@ -3362,6 +3377,11 @@ WINE_CONFIG_MAKEFILE(dlls/winecoreaudio.drv) WINE_CONFIG_MAKEFILE(dlls/winecrt0) WINE_CONFIG_MAKEFILE(dlls/wined3d) WINE_CONFIG_MAKEFILE(dlls/winedmo) +WINE_CONFIG_MAKEFILE(dlls/winedmo4) +WINE_CONFIG_MAKEFILE(dlls/winedmo5) +WINE_CONFIG_MAKEFILE(dlls/winedmo6) +WINE_CONFIG_MAKEFILE(dlls/winedmo7) +WINE_CONFIG_MAKEFILE(dlls/winedmo8) WINE_CONFIG_MAKEFILE(dlls/winegstreamer) WINE_CONFIG_MAKEFILE(dlls/winehid.sys) WINE_CONFIG_MAKEFILE(dlls/winemac.drv) diff --git a/dlls/winedmo/unix_private.h b/dlls/winedmo/unix_private.h index 8192926bfc4..2df468f139f 100644 --- a/dlls/winedmo/unix_private.h +++ b/dlls/winedmo/unix_private.h @@ -22,6 +22,14 @@ #include <stdint.h> +#if !defined(HAVE_FFMPEG) && defined(WINEDMO_VERSION) +#if (WINEDMO_VERSION == 4 && defined(HAVE_FFMPEG4)) || (WINEDMO_VERSION == 5 && defined(HAVE_FFMPEG5)) || \ + (WINEDMO_VERSION == 6 && defined(HAVE_FFMPEG6)) || (WINEDMO_VERSION == 7 && defined(HAVE_FFMPEG7)) || \ + (WINEDMO_VERSION == 8 && defined(HAVE_FFMPEG8)) +#define HAVE_FFMPEG +#endif +#endif + #ifdef HAVE_FFMPEG #include <libavutil/avutil.h> #include <libavutil/imgutils.h> diff --git a/dlls/winedmo4/Makefile.in b/dlls/winedmo4/Makefile.in new file mode 100644 index 00000000000..daaab802e11 --- /dev/null +++ b/dlls/winedmo4/Makefile.in @@ -0,0 +1,12 @@ +MODULE = winedmo4.dll +UNIXLIB = winedmo4.so +IMPORTS = mfuuid +PARENTSRC = ../winedmo +UNIX_CFLAGS = $(FFMPEG4_CFLAGS) -DWINEDMO_VERSION=4 +UNIX_LIBS = $(FFMPEG4_LIBS) $(PTHREAD_LIBS) + +SOURCES = \ + main.c \ + unix_demuxer.c \ + unix_media_type.c \ + unixlib.c diff --git a/dlls/winedmo4/winedmo4.spec b/dlls/winedmo4/winedmo4.spec new file mode 100644 index 00000000000..90eff030dfd --- /dev/null +++ b/dlls/winedmo4/winedmo4.spec @@ -0,0 +1,8 @@ +@ cdecl winedmo_demuxer_check(str) +@ cdecl winedmo_demuxer_create(wstr ptr int64 ptr ptr ptr ptr) +@ cdecl winedmo_demuxer_destroy(ptr) +@ cdecl winedmo_demuxer_read(int64 ptr ptr ptr) +@ cdecl winedmo_demuxer_seek(int64 int64) +@ cdecl winedmo_demuxer_stream_lang(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_name(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_type(int64 long ptr ptr) diff --git a/dlls/winedmo5/Makefile.in b/dlls/winedmo5/Makefile.in new file mode 100644 index 00000000000..65bb9b81739 --- /dev/null +++ b/dlls/winedmo5/Makefile.in @@ -0,0 +1,12 @@ +MODULE = winedmo5.dll +UNIXLIB = winedmo5.so +IMPORTS = mfuuid +PARENTSRC = ../winedmo +UNIX_CFLAGS = $(FFMPEG5_CFLAGS) -DWINEDMO_VERSION=5 +UNIX_LIBS = $(FFMPEG5_LIBS) $(PTHREAD_LIBS) + +SOURCES = \ + main.c \ + unix_demuxer.c \ + unix_media_type.c \ + unixlib.c diff --git a/dlls/winedmo5/winedmo5.spec b/dlls/winedmo5/winedmo5.spec new file mode 100644 index 00000000000..90eff030dfd --- /dev/null +++ b/dlls/winedmo5/winedmo5.spec @@ -0,0 +1,8 @@ +@ cdecl winedmo_demuxer_check(str) +@ cdecl winedmo_demuxer_create(wstr ptr int64 ptr ptr ptr ptr) +@ cdecl winedmo_demuxer_destroy(ptr) +@ cdecl winedmo_demuxer_read(int64 ptr ptr ptr) +@ cdecl winedmo_demuxer_seek(int64 int64) +@ cdecl winedmo_demuxer_stream_lang(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_name(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_type(int64 long ptr ptr) diff --git a/dlls/winedmo6/Makefile.in b/dlls/winedmo6/Makefile.in new file mode 100644 index 00000000000..c69578d9eb5 --- /dev/null +++ b/dlls/winedmo6/Makefile.in @@ -0,0 +1,12 @@ +MODULE = winedmo6.dll +UNIXLIB = winedmo6.so +IMPORTS = mfuuid +PARENTSRC = ../winedmo +UNIX_CFLAGS = $(FFMPEG6_CFLAGS) -DWINEDMO_VERSION=6 +UNIX_LIBS = $(FFMPEG6_LIBS) $(PTHREAD_LIBS) + +SOURCES = \ + main.c \ + unix_demuxer.c \ + unix_media_type.c \ + unixlib.c diff --git a/dlls/winedmo6/winedmo6.spec b/dlls/winedmo6/winedmo6.spec new file mode 100644 index 00000000000..90eff030dfd --- /dev/null +++ b/dlls/winedmo6/winedmo6.spec @@ -0,0 +1,8 @@ +@ cdecl winedmo_demuxer_check(str) +@ cdecl winedmo_demuxer_create(wstr ptr int64 ptr ptr ptr ptr) +@ cdecl winedmo_demuxer_destroy(ptr) +@ cdecl winedmo_demuxer_read(int64 ptr ptr ptr) +@ cdecl winedmo_demuxer_seek(int64 int64) +@ cdecl winedmo_demuxer_stream_lang(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_name(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_type(int64 long ptr ptr) diff --git a/dlls/winedmo7/Makefile.in b/dlls/winedmo7/Makefile.in new file mode 100644 index 00000000000..b31b3f0a2b6 --- /dev/null +++ b/dlls/winedmo7/Makefile.in @@ -0,0 +1,12 @@ +MODULE = winedmo7.dll +UNIXLIB = winedmo7.so +IMPORTS = mfuuid +PARENTSRC = ../winedmo +UNIX_CFLAGS = $(FFMPEG7_CFLAGS) -DWINEDMO_VERSION=7 +UNIX_LIBS = $(FFMPEG7_LIBS) $(PTHREAD_LIBS) + +SOURCES = \ + main.c \ + unix_demuxer.c \ + unix_media_type.c \ + unixlib.c diff --git a/dlls/winedmo7/winedmo7.spec b/dlls/winedmo7/winedmo7.spec new file mode 100644 index 00000000000..90eff030dfd --- /dev/null +++ b/dlls/winedmo7/winedmo7.spec @@ -0,0 +1,8 @@ +@ cdecl winedmo_demuxer_check(str) +@ cdecl winedmo_demuxer_create(wstr ptr int64 ptr ptr ptr ptr) +@ cdecl winedmo_demuxer_destroy(ptr) +@ cdecl winedmo_demuxer_read(int64 ptr ptr ptr) +@ cdecl winedmo_demuxer_seek(int64 int64) +@ cdecl winedmo_demuxer_stream_lang(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_name(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_type(int64 long ptr ptr) diff --git a/dlls/winedmo8/Makefile.in b/dlls/winedmo8/Makefile.in new file mode 100644 index 00000000000..d1c758e1845 --- /dev/null +++ b/dlls/winedmo8/Makefile.in @@ -0,0 +1,12 @@ +MODULE = winedmo8.dll +UNIXLIB = winedmo8.so +IMPORTS = mfuuid +PARENTSRC = ../winedmo +UNIX_CFLAGS = $(FFMPEG8_CFLAGS) -DWINEDMO_VERSION=8 +UNIX_LIBS = $(FFMPEG8_LIBS) $(PTHREAD_LIBS) + +SOURCES = \ + main.c \ + unix_demuxer.c \ + unix_media_type.c \ + unixlib.c diff --git a/dlls/winedmo8/winedmo8.spec b/dlls/winedmo8/winedmo8.spec new file mode 100644 index 00000000000..90eff030dfd --- /dev/null +++ b/dlls/winedmo8/winedmo8.spec @@ -0,0 +1,8 @@ +@ cdecl winedmo_demuxer_check(str) +@ cdecl winedmo_demuxer_create(wstr ptr int64 ptr ptr ptr ptr) +@ cdecl winedmo_demuxer_destroy(ptr) +@ cdecl winedmo_demuxer_read(int64 ptr ptr ptr) +@ cdecl winedmo_demuxer_seek(int64 int64) +@ cdecl winedmo_demuxer_stream_lang(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_name(int64 long ptr long) +@ cdecl winedmo_demuxer_stream_type(int64 long ptr ptr) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9913
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mfsrcsnk/media_source.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index 1f506082565..cf0532d2bc5 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -52,6 +52,15 @@ static struct winedmo_demuxer_funcs winedmo_funcs = .p_stream_type = winedmo_demuxer_stream_type, }; +static struct { const WCHAR *name; struct winedmo_demuxer_funcs funcs; } modules[] = +{ + {L"winedmo4"}, + {L"winedmo5"}, + {L"winedmo6"}, + {L"winedmo7"}, + {L"winedmo8"}, +}; + static NTSTATUS winedmo_unsupported_check(const char *mime_type) { return STATUS_UNSUCCESSFUL; @@ -87,6 +96,9 @@ static BOOL CALLBACK init_dynamic_funcs(INIT_ONCE *once, void *param, void **ctx RRF_RT_REG_DWORD, NULL, &result, &size ) || !result) load_winedmo_demuxer_funcs(L"winegstreamer", &winedmo_funcs); + for (int i = 0; i < ARRAY_SIZE(modules); i++) + load_winedmo_demuxer_funcs(modules[i].name, &modules[i].funcs); + return TRUE; } @@ -96,6 +108,10 @@ static const struct winedmo_demuxer_funcs *get_winedmo_demuxer_funcs(const char InitOnceExecuteOnce(&once, init_dynamic_funcs, NULL, NULL); + for (int i = 0; i < ARRAY_SIZE(modules); i++) + if (!modules[i].funcs.p_check(mime_type)) + return &modules[i].funcs; + return &winedmo_funcs; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9913
Doesn't look like there is anything for me to look at. It's got assigned because of trivial mfplat changes. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9913#note_127714
participants (3)
-
Nikolay Sivov (@nsivov) -
Rémi Bernon -
Rémi Bernon (@rbernon)