Added mf_http_support patchset

This commit is contained in:
Alistair Leslie-Hughes 2025-01-24 07:45:00 +11:00
parent 93f5b4f6a0
commit 49770c6bc6
5 changed files with 3466 additions and 0 deletions

View File

@ -0,0 +1,24 @@
From 252a1d6bb99c83ce8a0289fbd1f4fe135e2c55cd Mon Sep 17 00:00:00 2001
From: Torge Matthies <tmatthies@codeweavers.com>
Date: Fri, 25 Oct 2024 13:19:02 +0200
Subject: [PATCH] include: Add MFNETSOURCE_STATISTICS_SERVICE definition.
---
include/mfidl.idl | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/mfidl.idl b/include/mfidl.idl
index 666af53c6e3..a8c5af05e68 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -1626,6 +1626,7 @@ cpp_quote("EXTERN_GUID(MR_STREAM_VOLUME_SERVICE, 0xf8b5fa2f, 0x32ef, 0x46f5, 0xb
cpp_quote("EXTERN_GUID(MR_AUDIO_POLICY_SERVICE, 0x911fd737, 0x6775, 0x4ab0, 0xa6, 0x14, 0x29, 0x78, 0x62, 0xfd, 0xac, 0x88);")
cpp_quote("EXTERN_GUID(MF_PROPERTY_HANDLER_SERVICE, 0xa3face02, 0x32b8, 0x41dd, 0x90, 0xe7, 0x5f, 0xef, 0x7c, 0x89, 0x91, 0xb5);")
cpp_quote("EXTERN_GUID(MF_WORKQUEUE_SERVICES, 0x8e37d489, 0x41e0, 0x413a, 0x90, 0x68, 0x28, 0x7c, 0x88, 0x6d, 0x8d, 0xda);")
+cpp_quote("EXTERN_GUID(MFNETSOURCE_STATISTICS_SERVICE, 0x3cb1f275, 0x0505, 0x4c5d, 0xae, 0x71, 0x0a, 0x55, 0x63, 0x44, 0xef, 0xa1);")
cpp_quote("EXTERN_GUID(MF_PROGRESSIVE_CODING_CONTENT, 0x8f020eea, 0x1508, 0x471f, 0x9d, 0xa6, 0x50, 0x7d, 0x7c, 0xfa, 0x40, 0xdb);")
cpp_quote("EXTERN_GUID(MF_NALU_LENGTH_SET, 0xa7911d53, 0x12a4, 0x4965, 0xae, 0x70, 0x6e, 0xad, 0xd6, 0xff, 0x05, 0x51);")
--
2.45.2

View File

@ -0,0 +1,383 @@
From 0d4a7cf6b9bb3a57a098762113ca1750c43a810e Mon Sep 17 00:00:00 2001
From: Torge Matthies <tmatthies@codeweavers.com>
Date: Fri, 25 Oct 2024 10:47:30 +0200
Subject: [PATCH] mf/tests: Add network bytestream tests.
---
dlls/mf/tests/mf.c | 347 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 347 insertions(+)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index d0f1f1cf0a4..61daaf35741 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -4726,6 +4726,7 @@ static void test_evr(void)
hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&sink);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ if (!sink) return;
check_interface(sink, &IID_IMFMediaSinkPreroll, TRUE);
check_interface(sink, &IID_IMFVideoRenderer, TRUE);
@@ -6803,6 +6804,351 @@ static void test_media_session_Close(void)
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
}
+static void test_network_bytestream(void)
+{
+ static const WCHAR *URL = L"http://test.winehq.org/tests/test.mp3";
+ static const WCHAR *EFFECTIVE_URL = L"http://test.winehq.org:80/tests/test.mp3";
+ static const WCHAR *CONTENT_TYPE = L"audio/mpeg";
+ static const BYTE LAST_MODIFIED_TIME[] = { 0x00, 0x3b, 0x4b, 0xbf, 0x05, 0x80, 0xd8, 0x01 };
+
+ IMFSourceResolver *resolver;
+ IUnknown *object = NULL, *bs = NULL;
+ MF_OBJECT_TYPE obj_type;
+ HRESULT hr;
+ void *ptr;
+
+ hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
+ ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr);
+
+ hr = MFCreateSourceResolver(&resolver);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+ if (object) IUnknown_Release(object);
+
+ obj_type = (MF_OBJECT_TYPE)0xdeadbeef;
+ object = NULL;
+ hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"http://nonexistent.url/file.mp4", MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, &object);
+ todo_wine
+ ok(hr == NS_E_SERVER_NOT_FOUND, "Got hr %#lx.\n", hr);
+ ok(obj_type == MF_OBJECT_INVALID, "Unexpected obj_type %#x.\n", obj_type);
+ if (object) IUnknown_Release(object);
+
+ obj_type = (MF_OBJECT_TYPE)0xdeadbeef;
+ object = NULL;
+ hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"http://test.winehq.org/tests/invalid.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, &object);
+ todo_wine
+ ok(hr == NS_E_FILE_NOT_FOUND, "Got hr %#lx.\n", hr);
+ todo_wine
+ ok(obj_type == MF_OBJECT_INVALID, "Unexpected obj_type %#x.\n", obj_type);
+ if (object) IUnknown_Release(object);
+
+ obj_type = (MF_OBJECT_TYPE)0xdeadbeef;
+ object = NULL;
+ hr = IMFSourceResolver_CreateObjectFromURL(resolver, URL, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, &object);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ ok(obj_type == MF_OBJECT_BYTESTREAM, "Unexpected obj_type %#x.\n", obj_type);
+
+ ptr = NULL;
+ hr = IUnknown_QueryInterface(object, &IID_IMFAttributes, &ptr);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ ok(ptr != NULL, "Got NULL ptr.\n");
+ if (SUCCEEDED(hr) && ptr)
+ {
+ IMFAttributes *attr = ptr;
+ UINT32 count = 0;
+ PROPVARIANT var;
+ GUID key = {0};
+
+ hr = IMFAttributes_GetCount(attr, &count);
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+ todo_wine
+ ok(count == 3, "count = %u\n", count);
+
+ PropVariantInit(&var);
+
+ hr = IMFAttributes_GetItemByIndex(attr, 0, &key, &var);
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+ ok(IsEqualGUID(&key, &MF_BYTESTREAM_EFFECTIVE_URL), "Got key %s\n", debugstr_guid(&key));
+ ok(var.vt == VT_LPWSTR, "Got type %d\n", var.vt);
+ todo_wine
+ ok(!lstrcmpW(var.pwszVal, EFFECTIVE_URL), "Got value %s\n", var.pszVal);
+ memset(&key, 0, sizeof(key));
+ PropVariantClear(&var);
+
+ hr = IMFAttributes_GetItemByIndex(attr, 1, &key, &var);
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+ ok(IsEqualGUID(&key, &MF_BYTESTREAM_CONTENT_TYPE), "Got key %s\n", debugstr_guid(&key));
+ ok(var.vt == VT_LPWSTR, "Got type %d\n", var.vt);
+ todo_wine
+ ok(!lstrcmpW(var.pwszVal, CONTENT_TYPE), "Got value %s\n", var.pszVal);
+ memset(&key, 0, sizeof(key));
+ PropVariantClear(&var);
+
+ hr = IMFAttributes_GetItemByIndex(attr, 2, &key, &var);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+ todo_wine
+ ok(IsEqualGUID(&key, &MF_BYTESTREAM_LAST_MODIFIED_TIME), "Got key %s\n", debugstr_guid(&key));
+ todo_wine
+ ok(var.vt == (VT_VECTOR | VT_I1 | VT_NULL), "Got type %d\n", var.vt);
+ todo_wine
+ ok(var.blob.cbSize == sizeof(LAST_MODIFIED_TIME), "Got size %lu\n", var.blob.cbSize);
+ todo_wine
+ ok(var.blob.pBlobData != NULL, "Got NULL value\n");
+ if (var.blob.cbSize == sizeof(LAST_MODIFIED_TIME) && var.blob.pBlobData)
+ ok(!memcmp(var.blob.pBlobData, LAST_MODIFIED_TIME, sizeof(LAST_MODIFIED_TIME)), "Got wrong value\n");
+ memset(&key, 0, sizeof(key));
+ PropVariantClear(&var);
+
+ hr = IMFAttributes_GetItemByIndex(attr, 3, &key, &var);
+ ok(hr == E_INVALIDARG, "Got hr %#lx\n", hr);
+ ok(IsEqualGUID(&key, &GUID_NULL), "Got key %s\n", debugstr_guid(&key));
+ ok(var.vt == VT_EMPTY, "Got type %d\n", var.vt);
+ memset(&key, 0, sizeof(key));
+ PropVariantClear(&var);
+
+ IUnknown_Release((IUnknown *)ptr);
+ }
+
+ ptr = NULL;
+ hr = IUnknown_QueryInterface(object, &IID_IMFByteStreamCacheControl, &ptr);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ todo_wine
+ ok(ptr != NULL, "Got NULL ptr.\n");
+ if (SUCCEEDED(hr) && ptr)
+ {
+ IMFByteStreamCacheControl *ctrl = ptr;
+ HRESULT hr;
+
+ hr = IMFByteStreamCacheControl_StopBackgroundTransfer(ctrl);
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+
+ IMFByteStreamCacheControl_Release(ctrl);
+ }
+
+ ptr = NULL;
+ hr = IUnknown_QueryInterface(object, &IID_IMFByteStreamBuffering, &ptr);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ todo_wine
+ ok(ptr != NULL, "Got NULL ptr.\n");
+ if (SUCCEEDED(hr) && ptr)
+ {
+ MFBYTESTREAM_BUFFERING_PARAMS params = {0};
+ IMFByteStreamBuffering *buffering = ptr;
+ MF_LEAKY_BUCKET_PAIR bucket = {0};
+ HRESULT hr;
+
+ hr = IMFByteStreamBuffering_StopBuffering(buffering);
+ ok(hr == S_FALSE, "Got hr %#lx\n", hr);
+
+ hr = IMFByteStreamBuffering_EnableBuffering(buffering, FALSE);
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+
+ hr = IMFByteStreamBuffering_EnableBuffering(buffering, TRUE);
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+
+ hr = IMFByteStreamBuffering_StopBuffering(buffering);
+ ok(hr == S_OK || hr == S_FALSE, "Got hr %#lx\n", hr);
+
+ hr = IMFByteStreamBuffering_SetBufferingParams(buffering, NULL);
+ ok(hr == E_INVALIDARG, "Got hr %#lx\n", hr);
+
+ params.cbTotalFileSize = -1;
+ params.cbPlayableDataSize = -1;
+ params.prgBuckets = NULL;
+ params.cBuckets = 0;
+ params.qwNetBufferingTime = 0;
+ params.qwExtraBufferingTimeDuringSeek = 0;
+ params.qwPlayDuration = 0;
+ params.dRate = 1.0f;
+ hr = IMFByteStreamBuffering_SetBufferingParams(buffering, &params);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+
+ params.cBuckets = 1;
+ hr = IMFByteStreamBuffering_SetBufferingParams(buffering, &params);
+ ok(hr == E_INVALIDARG, "Got hr %#lx\n", hr);
+
+ params.prgBuckets = &bucket;
+ bucket.dwBitrate = 0;
+ bucket.msBufferWindow = 0;
+ hr = IMFByteStreamBuffering_SetBufferingParams(buffering, &params);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+
+ params.cbTotalFileSize = 0xdeadbeef;
+ params.cbPlayableDataSize = 0xdeadbeef;
+ bucket.dwBitrate = 0xdeadbeef;
+ bucket.msBufferWindow = 0xdeadbeef;
+ params.qwNetBufferingTime = 0xdeadbeef;
+ params.qwExtraBufferingTimeDuringSeek = 0xdeadbeef;
+ params.qwPlayDuration = 0xdeadbeef;
+ params.dRate = 12345.0f;
+ hr = IMFByteStreamBuffering_SetBufferingParams(buffering, &params);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+
+ hr = IMFByteStreamBuffering_EnableBuffering(buffering, TRUE);
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+
+ IMFByteStreamBuffering_Release(buffering);
+ }
+
+ ptr = NULL;
+ hr = IUnknown_QueryInterface(object, &IID_IMFByteStreamTimeSeek, &ptr);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ todo_wine
+ ok(ptr != NULL, "Got NULL ptr.\n");
+ if (SUCCEEDED(hr) && ptr)
+ {
+ QWORD start_time = 0xdeadbeef, stop_time = 0xdeadbef0, duration = 0xdeadbef1;
+ IMFByteStreamTimeSeek *seek = ptr;
+ BOOL b = 0xdeadbeef;
+ HRESULT hr;
+
+ hr = IMFByteStreamTimeSeek_GetTimeSeekResult(seek, NULL, NULL, NULL);
+ ok(hr == E_INVALIDARG, "Got hr %#lx\n", hr);
+
+ hr = IMFByteStreamTimeSeek_GetTimeSeekResult(seek, &start_time, &stop_time, &duration);
+ ok(hr == MF_E_INVALIDREQUEST, "Got hr %#lx\n", hr);
+ ok(start_time == 0, "start_time = %I64u\n", start_time);
+ ok(stop_time == 0, "stop_time = %I64u\n", stop_time);
+ ok(duration == 0, "duration = %I64u\n", duration);
+
+ hr = IMFByteStreamTimeSeek_IsTimeSeekSupported(seek, NULL);
+ ok(hr == S_FALSE, "Got hr %#lx\n", hr);
+
+ hr = IMFByteStreamTimeSeek_IsTimeSeekSupported(seek, &b);
+ ok(hr == S_FALSE, "Got hr %#lx\n", hr);
+ ok(!b, "supported = %x\n", b);
+
+ hr = IMFByteStreamTimeSeek_TimeSeek(seek, 0);
+ ok(hr == MF_E_INVALIDREQUEST, "Got hr %#lx\n", hr);
+
+ hr = IMFByteStreamTimeSeek_GetTimeSeekResult(seek, &start_time, &stop_time, &duration);
+ ok(hr == MF_E_INVALIDREQUEST, "Got hr %#lx\n", hr);
+ ok(start_time == 0, "start_time = %I64u\n", start_time);
+ ok(stop_time == 0, "stop_time = %I64u\n", stop_time);
+ ok(duration == 0, "duration = %I64u\n", duration);
+
+ IMFByteStreamTimeSeek_Release(seek);
+ }
+
+ {
+ BYTE *tmp = malloc(8192);
+ ULONG read = 0, written = 0;
+ QWORD len = 0;
+
+ hr = IMFByteStream_SetLength((IMFByteStream*)object, 1000);
+ ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
+
+ hr = IMFByteStream_SetCurrentPosition((IMFByteStream*)object, 1000);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+ hr = IMFByteStream_Read((IMFByteStream*)object, tmp, 8192, &read);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ ok(read == 3365, "read = %lu\n", read);
+
+ hr = IMFByteStream_SetCurrentPosition((IMFByteStream*)object, 1000);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+ hr = IMFByteStream_Write((IMFByteStream*)object, tmp, 1000, &written);
+ ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
+ ok(written == 0, "written = %lu\n", written);
+
+ free(tmp);
+
+ hr = IMFByteStream_GetLength((IMFByteStream*)object, &len);
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+ ok(len != 0, "len = %I64u\n", len);
+
+ hr = IMFByteStream_Flush((IMFByteStream*)object);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx\n", hr);
+ }
+
+ ptr = NULL;
+ hr = MFGetService(object, &MFNETSOURCE_STATISTICS_SERVICE, &IID_IPropertyStore, &ptr);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ ok(ptr != NULL, "Got NULL ptr.\n");
+ if (SUCCEEDED(hr) && ptr)
+ {
+ IPropertyStore *pstore = ptr;
+ DWORD count = 0;
+
+ ptr = NULL;
+ hr = IUnknown_QueryInterface(object, &IID_IPropertyStore, &ptr);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ ok(ptr == (void *)pstore, "Got different IPropertyStore: %p != %p.\n", ptr, pstore);
+ IPropertyStore_Release((IPropertyStore *)ptr);
+
+ hr = IPropertyStore_GetCount(pstore, &count);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ ok(count == 0, "Got count %lu.\n", count);
+
+ IPropertyStore_Release(pstore);
+ }
+
+ ptr = NULL;
+ hr = IUnknown_QueryInterface(object, &IID_IMFMediaEventGenerator, &ptr);
+ todo_wine
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ todo_wine
+ ok(ptr != NULL, "Got NULL ptr.\n");
+ if (SUCCEEDED(hr) && ptr)
+ {
+ IMFMediaEvent *evt = (void *)(DWORD_PTR)0xdeadbeef;
+ BOOL seen_caps_changed = FALSE, buffering = FALSE;
+ IMFMediaEventGenerator *gen = ptr;
+ MediaEventType type;
+ HRESULT hr;
+
+ while (SUCCEEDED(hr = IMFMediaEventGenerator_GetEvent(gen, MF_EVENT_FLAG_NO_WAIT, &evt)))
+ {
+ type = (MediaEventType)0xdeadbeef;
+ hr = IMFMediaEvent_GetType(evt, &type);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+ if (type == MEByteStreamCharacteristicsChanged)
+ {
+ ok(!seen_caps_changed, "got multiple MEByteStreamCharacteristicsChanged events\n");
+ seen_caps_changed = TRUE;
+ }
+ else if (type == MEBufferingStarted)
+ {
+ ok(!buffering, "got MEBufferingStopped without MEBufferingStarted\n");
+ buffering = TRUE;
+ }
+ else if (type == MEBufferingStopped)
+ buffering = FALSE;
+ else
+ ok(0, "Unexpected event type %#lx\n", type);
+
+ IMFMediaEvent_Release(evt);
+ }
+ ok(hr == MF_E_NO_EVENTS_AVAILABLE, "Got hr %#lx.\n", hr);
+
+ IMFMediaEventGenerator_Release(gen);
+ }
+
+ obj_type = (MF_OBJECT_TYPE)0xdeadbeef;
+ bs = NULL;
+ hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (void *)object, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, &obj_type, &bs);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(obj_type == MF_OBJECT_MEDIASOURCE, "Unexpected obj_type %#x.\n", obj_type);
+
+ if (bs) IUnknown_Release(bs);
+ if (object) IUnknown_Release(object);
+
+ IMFSourceResolver_Release(resolver);
+
+ hr = MFShutdown();
+ ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr);
+}
+
START_TEST(mf)
{
init_functions();
@@ -6838,5 +7184,6 @@ START_TEST(mf)
test_media_session_Start();
test_MFEnumDeviceSources();
test_media_session_Close();
+ test_network_bytestream();
test_media_session_source_shutdown();
}
--
2.45.2

View File

@ -0,0 +1,346 @@
From 68227ee19646a7c98f1b1e6eed72a7a6a2a21fc1 Mon Sep 17 00:00:00 2001
From: Torge Matthies <tmatthies@codeweavers.com>
Date: Fri, 25 Oct 2024 10:47:31 +0200
Subject: [PATCH] mf: Implement and use HttpSchemePlugin.
---
dlls/mf/main.c | 2 ++
dlls/mf/mf.idl | 6 ++++++
dlls/mf/mf.rgs | 16 ++++++++++++++--
dlls/mf/mf_private.h | 1 +
dlls/mf/scheme_handler.c | 33 +++++++++++++++++++++++++++++++++
dlls/mf/tests/mf.c | 38 ++++----------------------------------
dlls/mfplat/mfplat.spec | 3 +++
dlls/mfplat/network.c | 5 +++++
8 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/dlls/mf/main.c b/dlls/mf/main.c
index e74a4ae8e4c..120343a1be2 100644
--- a/dlls/mf/main.c
+++ b/dlls/mf/main.c
@@ -549,6 +549,7 @@ static const IClassFactoryVtbl class_factory_vtbl =
};
static struct class_factory file_scheme_handler_factory = { { &class_factory_vtbl }, file_scheme_handler_construct };
+static struct class_factory http_scheme_handler_factory = { { &class_factory_vtbl }, http_scheme_handler_construct };
static struct class_factory urlmon_scheme_handler_factory = { { &class_factory_vtbl }, urlmon_scheme_handler_construct };
static const struct class_object
@@ -559,6 +560,7 @@ static const struct class_object
class_objects[] =
{
{ &CLSID_FileSchemePlugin, &file_scheme_handler_factory.IClassFactory_iface },
+ { &CLSID_HttpSchemePlugin, &http_scheme_handler_factory.IClassFactory_iface },
{ &CLSID_UrlmonSchemePlugin, &urlmon_scheme_handler_factory.IClassFactory_iface },
};
diff --git a/dlls/mf/mf.idl b/dlls/mf/mf.idl
index 4f5ef36c965..ca05a991ca9 100644
--- a/dlls/mf/mf.idl
+++ b/dlls/mf/mf.idl
@@ -25,6 +25,12 @@
]
coclass FileSchemePlugin { }
+[
+ threading(both),
+ uuid(44cb442b-9da9-49df-b3fd-023777b16e50)
+]
+coclass HttpSchemePlugin {}
+
[
threading(both),
uuid(9ec4b4f9-3029-45ad-947b-344de2a249e2)
diff --git a/dlls/mf/mf.rgs b/dlls/mf/mf.rgs
index f06576baccb..778b07e65ed 100644
--- a/dlls/mf/mf.rgs
+++ b/dlls/mf/mf.rgs
@@ -14,11 +14,23 @@ HKLM
}
'http:'
{
- val '{9ec4b4f9-3029-45ad-947b-344de2a249e2}' = s 'Urlmon Scheme Handler'
+ val '{44cb442b-9da9-49df-b3fd-023777b16e50}' = s 'Http Scheme Handler'
}
'https:'
{
- val '{9ec4b4f9-3029-45ad-947b-344de2a249e2}' = s 'Urlmon Scheme Handler'
+ val '{44cb442b-9da9-49df-b3fd-023777b16e50}' = s 'Http Scheme Handler'
+ }
+ 'httpd:'
+ {
+ val '{44cb442b-9da9-49df-b3fd-023777b16e50}' = s 'Http Scheme Handler'
+ }
+ 'httpsd:'
+ {
+ val '{44cb442b-9da9-49df-b3fd-023777b16e50}' = s 'Http Scheme Handler'
+ }
+ 'mms:'
+ {
+ val '{44cb442b-9da9-49df-b3fd-023777b16e50}' = s 'Http Scheme Handler'
}
}
}
diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h
index 1f2ef17a8c9..adb35e14194 100644
--- a/dlls/mf/mf_private.h
+++ b/dlls/mf/mf_private.h
@@ -114,6 +114,7 @@ static inline const char *debugstr_propvar(const PROPVARIANT *v)
}
extern HRESULT file_scheme_handler_construct(REFIID riid, void **obj);
+extern HRESULT http_scheme_handler_construct(REFIID riid, void **obj);
extern HRESULT urlmon_scheme_handler_construct(REFIID riid, void **obj);
extern BOOL mf_is_sample_copier_transform(IMFTransform *transform);
diff --git a/dlls/mf/scheme_handler.c b/dlls/mf/scheme_handler.c
index 7e92748aeb9..3cd16319b2a 100644
--- a/dlls/mf/scheme_handler.c
+++ b/dlls/mf/scheme_handler.c
@@ -483,6 +483,39 @@ HRESULT file_scheme_handler_construct(REFIID riid, void **obj)
return hr;
}
+WINAPI HRESULT __wine_create_http_bytestream(const WCHAR *url, void **out);
+
+static HRESULT http_stream_create(const WCHAR *url, DWORD flags, IMFByteStream **out)
+{
+ if (flags & MF_RESOLUTION_WRITE)
+ return E_INVALIDARG;
+
+ return __wine_create_http_bytestream(url, (void **)out);
+}
+
+HRESULT http_scheme_handler_construct(REFIID riid, void **obj)
+{
+ struct scheme_handler *handler;
+ HRESULT hr;
+
+ TRACE("%s, %p.\n", debugstr_guid(riid), obj);
+
+ if (!(handler = calloc(1, sizeof(*handler))))
+ return E_OUTOFMEMORY;
+
+ handler->IMFSchemeHandler_iface.lpVtbl = &scheme_handler_vtbl;
+ handler->IMFAsyncCallback_iface.lpVtbl = &scheme_handler_callback_vtbl;
+ handler->refcount = 1;
+ list_init(&handler->results);
+ InitializeCriticalSection(&handler->cs);
+ handler->create_stream = http_stream_create;
+
+ hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj);
+ IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface);
+
+ return hr;
+}
+
static HRESULT urlmon_stream_create(const WCHAR *url, DWORD flags, IMFByteStream **out)
{
IMFAttributes *attributes;
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 61daaf35741..39dfe3ca1b2 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -5384,7 +5384,6 @@ static void test_scheme_resolvers(void)
for (i = 0; i < ARRAY_SIZE(urls); i++)
{
hr = IMFSourceResolver_CreateObjectFromURL(resolver, urls[i], MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine_if(i >= 2)
ok(hr == S_OK, "got hr %#lx\n", hr);
if (hr != S_OK)
continue;
@@ -5408,7 +5407,6 @@ static void test_scheme_resolvers(void)
hr = IMFAttributes_GetItem(attributes, &MF_BYTESTREAM_CONTENT_TYPE, NULL);
ok(hr == S_OK, "got hr %#lx\n", hr);
hr = IMFAttributes_GetItem(attributes, &MF_BYTESTREAM_LAST_MODIFIED_TIME, NULL);
- todo_wine
ok(hr == S_OK, "got hr %#lx\n", hr);
IMFAttributes_Release(attributes);
@@ -5416,8 +5414,7 @@ static void test_scheme_resolvers(void)
ok(hr == S_OK, "got hr %#lx\n", hr);
hr = IMFByteStream_GetCapabilities(byte_stream, &caps);
ok(hr == S_OK, "got hr %#lx\n", hr);
- todo_wine
- ok(caps == (expect_caps | MFBYTESTREAM_IS_PARTIALLY_DOWNLOADED)
+ ok(caps == expect_caps || caps == (expect_caps | MFBYTESTREAM_IS_PARTIALLY_DOWNLOADED)
|| caps == (expect_caps | MFBYTESTREAM_DOES_NOT_USE_NETWORK),
"got caps %#lx\n", caps);
hr = IMFByteStream_GetLength(byte_stream, &length);
@@ -5436,35 +5433,25 @@ static void test_scheme_resolvers(void)
ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"http://test.winehq.bla/tests/test.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == NS_E_SERVER_NOT_FOUND, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"https://test.winehq.bla/tests/test.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == WININET_E_NAME_NOT_RESOLVED, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"httpd://test.winehq.bla/tests/test.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == WININET_E_NAME_NOT_RESOLVED, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"httpsd://test.winehq.bla/tests/test.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == WININET_E_NAME_NOT_RESOLVED, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"mms://test.winehq.bla/tests/test.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == WININET_E_NAME_NOT_RESOLVED, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"http://test.winehq.org/tests/invalid.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == NS_E_FILE_NOT_FOUND, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"https://test.winehq.org/tests/invalid.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == NS_E_FILE_NOT_FOUND, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"httpd://test.winehq.org/tests/invalid.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == NS_E_FILE_NOT_FOUND, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"httpsd://test.winehq.org/tests/invalid.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == NS_E_FILE_NOT_FOUND, "got hr %#lx\n", hr);
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"mms://test.winehq.org/tests/invalid.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &type, &object);
- todo_wine
ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got hr %#lx\n", hr);
IMFSourceResolver_Release(resolver);
@@ -6828,7 +6815,6 @@ static void test_network_bytestream(void)
obj_type = (MF_OBJECT_TYPE)0xdeadbeef;
object = NULL;
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"http://nonexistent.url/file.mp4", MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, &object);
- todo_wine
ok(hr == NS_E_SERVER_NOT_FOUND, "Got hr %#lx.\n", hr);
ok(obj_type == MF_OBJECT_INVALID, "Unexpected obj_type %#x.\n", obj_type);
if (object) IUnknown_Release(object);
@@ -6836,9 +6822,7 @@ static void test_network_bytestream(void)
obj_type = (MF_OBJECT_TYPE)0xdeadbeef;
object = NULL;
hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"http://test.winehq.org/tests/invalid.mp3", MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, &object);
- todo_wine
ok(hr == NS_E_FILE_NOT_FOUND, "Got hr %#lx.\n", hr);
- todo_wine
ok(obj_type == MF_OBJECT_INVALID, "Unexpected obj_type %#x.\n", obj_type);
if (object) IUnknown_Release(object);
@@ -6861,7 +6845,6 @@ static void test_network_bytestream(void)
hr = IMFAttributes_GetCount(attr, &count);
ok(hr == S_OK, "Got hr %#lx\n", hr);
- todo_wine
ok(count == 3, "count = %u\n", count);
PropVariantInit(&var);
@@ -6870,7 +6853,6 @@ static void test_network_bytestream(void)
ok(hr == S_OK, "Got hr %#lx\n", hr);
ok(IsEqualGUID(&key, &MF_BYTESTREAM_EFFECTIVE_URL), "Got key %s\n", debugstr_guid(&key));
ok(var.vt == VT_LPWSTR, "Got type %d\n", var.vt);
- todo_wine
ok(!lstrcmpW(var.pwszVal, EFFECTIVE_URL), "Got value %s\n", var.pszVal);
memset(&key, 0, sizeof(key));
PropVariantClear(&var);
@@ -6879,21 +6861,15 @@ static void test_network_bytestream(void)
ok(hr == S_OK, "Got hr %#lx\n", hr);
ok(IsEqualGUID(&key, &MF_BYTESTREAM_CONTENT_TYPE), "Got key %s\n", debugstr_guid(&key));
ok(var.vt == VT_LPWSTR, "Got type %d\n", var.vt);
- todo_wine
ok(!lstrcmpW(var.pwszVal, CONTENT_TYPE), "Got value %s\n", var.pszVal);
memset(&key, 0, sizeof(key));
PropVariantClear(&var);
hr = IMFAttributes_GetItemByIndex(attr, 2, &key, &var);
- todo_wine
ok(hr == S_OK, "Got hr %#lx\n", hr);
- todo_wine
ok(IsEqualGUID(&key, &MF_BYTESTREAM_LAST_MODIFIED_TIME), "Got key %s\n", debugstr_guid(&key));
- todo_wine
ok(var.vt == (VT_VECTOR | VT_I1 | VT_NULL), "Got type %d\n", var.vt);
- todo_wine
ok(var.blob.cbSize == sizeof(LAST_MODIFIED_TIME), "Got size %lu\n", var.blob.cbSize);
- todo_wine
ok(var.blob.pBlobData != NULL, "Got NULL value\n");
if (var.blob.cbSize == sizeof(LAST_MODIFIED_TIME) && var.blob.pBlobData)
ok(!memcmp(var.blob.pBlobData, LAST_MODIFIED_TIME, sizeof(LAST_MODIFIED_TIME)), "Got wrong value\n");
@@ -6912,9 +6888,7 @@ static void test_network_bytestream(void)
ptr = NULL;
hr = IUnknown_QueryInterface(object, &IID_IMFByteStreamCacheControl, &ptr);
- todo_wine
ok(hr == S_OK, "Got hr %#lx.\n", hr);
- todo_wine
ok(ptr != NULL, "Got NULL ptr.\n");
if (SUCCEEDED(hr) && ptr)
{
@@ -6929,9 +6903,7 @@ static void test_network_bytestream(void)
ptr = NULL;
hr = IUnknown_QueryInterface(object, &IID_IMFByteStreamBuffering, &ptr);
- todo_wine
ok(hr == S_OK, "Got hr %#lx.\n", hr);
- todo_wine
ok(ptr != NULL, "Got NULL ptr.\n");
if (SUCCEEDED(hr) && ptr)
{
@@ -6998,9 +6970,7 @@ static void test_network_bytestream(void)
ptr = NULL;
hr = IUnknown_QueryInterface(object, &IID_IMFByteStreamTimeSeek, &ptr);
- todo_wine
ok(hr == S_OK, "Got hr %#lx.\n", hr);
- todo_wine
ok(ptr != NULL, "Got NULL ptr.\n");
if (SUCCEEDED(hr) && ptr)
{
@@ -7059,6 +7029,9 @@ static void test_network_bytestream(void)
ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
ok(written == 0, "written = %lu\n", written);
+ hr = IMFByteStream_BeginWrite((IMFByteStream*)object, tmp, 1000, (void *)(DWORD_PTR)0xdeadbeef, NULL);
+ ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
+
free(tmp);
hr = IMFByteStream_GetLength((IMFByteStream*)object, &len);
@@ -7066,7 +7039,6 @@ static void test_network_bytestream(void)
ok(len != 0, "len = %I64u\n", len);
hr = IMFByteStream_Flush((IMFByteStream*)object);
- todo_wine
ok(hr == S_OK, "Got hr %#lx\n", hr);
}
@@ -7094,9 +7066,7 @@ static void test_network_bytestream(void)
ptr = NULL;
hr = IUnknown_QueryInterface(object, &IID_IMFMediaEventGenerator, &ptr);
- todo_wine
ok(hr == S_OK, "Got hr %#lx.\n", hr);
- todo_wine
ok(ptr != NULL, "Got NULL ptr.\n");
if (SUCCEEDED(hr) && ptr)
{
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 7b356f9f457..f55f49b7e8c 100644
--- a/dlls/mfplat/mfplat.spec
+++ b/dlls/mfplat/mfplat.spec
@@ -181,3 +181,6 @@
@ stdcall -ret64 MFllMulDiv(int64 int64 int64 int64)
@ stub PropVariantFromStream
@ stub PropVariantToStream
+
+# Wine extension
+@ stdcall __wine_create_http_bytestream(wstr ptr)
diff --git a/dlls/mfplat/network.c b/dlls/mfplat/network.c
index d9a2981f5a7..2369dbf31fd 100644
--- a/dlls/mfplat/network.c
+++ b/dlls/mfplat/network.c
@@ -2012,3 +2012,8 @@ error:
hr = MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
return hr;
}
+
+WINAPI HRESULT __wine_create_http_bytestream(const WCHAR *url, void **out)
+{
+ return create_http_bytestream(url, out);
+}
--
2.45.2

View File

@ -0,0 +1,5 @@
Fixes: [52769] mf: Add HTTP/HTTPS IMFByteStream implementation.
# MR https://gitlab.winehq.org/wine/wine/-/merge_requests/6733
# Game: The good life.