Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 899aca73d9..8e9cb66058 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -651,24 +651,19 @@ static inline mfattributes *impl_from_IMFAttributes(IMFAttributes *iface)
static HRESULT WINAPI mfattributes_QueryInterface(IMFAttributes *iface, REFIID riid, void **out) { - mfattributes *This = impl_from_IMFAttributes(iface); - - TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
- if(IsEqualGUID(riid, &IID_IUnknown) || - IsEqualGUID(riid, &IID_IMFAttributes)) + if (IsEqualIID(riid, &IID_IMFAttributes) || + IsEqualGUID(riid, &IID_IUnknown)) { - *out = &This->IMFAttributes_iface; - } - else - { - FIXME("(%s, %p)\n", debugstr_guid(riid), out); - *out = NULL; - return E_NOINTERFACE; + *out = iface; + IMFAttributes_AddRef(iface); + return S_OK; }
- IUnknown_AddRef((IUnknown*)*out); - return S_OK; + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; }
static ULONG WINAPI mfattributes_AddRef(IMFAttributes *iface)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 18 +++++++++--------- dlls/mfplat/mfplat_private.h | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 8e9cb66058..30c3073f09 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -644,9 +644,9 @@ static const char *debugstr_attr(const GUID *guid) return ret ? wine_dbg_sprintf("%s", ret->name) : wine_dbgstr_guid(guid); }
-static inline mfattributes *impl_from_IMFAttributes(IMFAttributes *iface) +static inline struct attributes *impl_from_IMFAttributes(IMFAttributes *iface) { - return CONTAINING_RECORD(iface, mfattributes, IMFAttributes_iface); + return CONTAINING_RECORD(iface, struct attributes, IMFAttributes_iface); }
static HRESULT WINAPI mfattributes_QueryInterface(IMFAttributes *iface, REFIID riid, void **out) @@ -668,12 +668,12 @@ static HRESULT WINAPI mfattributes_QueryInterface(IMFAttributes *iface, REFIID r
static ULONG WINAPI mfattributes_AddRef(IMFAttributes *iface) { - mfattributes *This = impl_from_IMFAttributes(iface); - ULONG ref = InterlockedIncrement(&This->ref); + struct attributes *attributes = impl_from_IMFAttributes(iface); + ULONG refcount = InterlockedIncrement(&attributes->ref);
- TRACE("(%p) ref=%u\n", This, ref); + TRACE("%p, refcount %d.\n", iface, refcount);
- return ref; + return refcount; }
static ULONG WINAPI mfattributes_Release(IMFAttributes *iface) @@ -1792,7 +1792,7 @@ HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *dest, const UINT8 *buffer
typedef struct _mfbytestream { - mfattributes attributes; + struct attributes attributes; IMFByteStream IMFByteStream_iface; } mfbytestream;
@@ -2273,7 +2273,7 @@ HRESULT WINAPI MFGetPluginControl(IMFPluginControl **ret)
typedef struct _mfpresentationdescriptor { - mfattributes attributes; + struct attributes attributes; IMFPresentationDescriptor IMFPresentationDescriptor_iface; } mfpresentationdescriptor;
@@ -3566,7 +3566,7 @@ HRESULT WINAPI MFCreateSourceResolver(IMFSourceResolver **resolver)
typedef struct media_event { - mfattributes attributes; + struct attributes attributes; IMFMediaEvent IMFMediaEvent_iface;
MediaEventType type; diff --git a/dlls/mfplat/mfplat_private.h b/dlls/mfplat/mfplat_private.h index 7d2e25f435..b3ed1764b2 100644 --- a/dlls/mfplat/mfplat_private.h +++ b/dlls/mfplat/mfplat_private.h @@ -30,7 +30,7 @@ struct attribute PROPVARIANT value; };
-typedef struct attributes +struct attributes { IMFAttributes IMFAttributes_iface; LONG ref; @@ -38,7 +38,7 @@ typedef struct attributes struct attribute *attributes; size_t capacity; size_t count; -} mfattributes; +};
extern HRESULT init_attributes_object(struct attributes *object, UINT32 size) DECLSPEC_HIDDEN; extern void clear_attributes_object(struct attributes *object) DECLSPEC_HIDDEN;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 1 + dlls/mfplat/mediatype.c | 72 ++++++++++++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 4 +-- dlls/mfplat/tests/mfplat.c | 57 ++++++++++++++++++++++++++++++ include/mfapi.h | 3 ++ 5 files changed, 135 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 30c3073f09..dd89f4c91a 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -559,6 +559,7 @@ static const char *debugstr_attr(const GUID *guid) X(MF_SOURCE_READER_ENABLE_TRANSCODE_ONLY_TRANSFORMS), X(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS), X(MF_MT_PIXEL_ASPECT_RATIO), + X(MF_MT_WRAPPED_TYPE), X(MF_MT_AVG_BITRATE), X(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING), X(MF_PD_PMPHOST_CONTEXT), diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index a2e3a96902..e64dd3da63 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -1515,3 +1515,75 @@ BOOL WINAPI MFCompareFullToPartialMediaType(IMFMediaType *full_type, IMFMediaTyp
return result; } + +/*********************************************************************** + * MFWrapMediaType (mfplat.@) + */ +HRESULT WINAPI MFWrapMediaType(IMFMediaType *original, REFGUID major, REFGUID subtype, IMFMediaType **ret) +{ + IMFMediaType *mediatype; + UINT8 *buffer; + UINT32 size; + HRESULT hr; + + TRACE("%p, %s, %s, %p.\n", original, debugstr_guid(major), debugstr_guid(subtype), ret); + + if (FAILED(hr = MFGetAttributesAsBlobSize((IMFAttributes *)original, &size))) + return hr; + + if (!(buffer = heap_alloc(size))) + return E_OUTOFMEMORY; + + if (FAILED(hr = MFGetAttributesAsBlob((IMFAttributes *)original, buffer, size))) + goto failed; + + if (FAILED(hr = MFCreateMediaType(&mediatype))) + goto failed; + + if (FAILED(hr = IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, major))) + goto failed; + + if (FAILED(hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, subtype))) + goto failed; + + if (FAILED(hr = IMFMediaType_SetBlob(mediatype, &MF_MT_WRAPPED_TYPE, buffer, size))) + goto failed; + + *ret = mediatype; + +failed: + heap_free(buffer); + + return hr; +} + +/*********************************************************************** + * MFUnwrapMediaType (mfplat.@) + */ +HRESULT WINAPI MFUnwrapMediaType(IMFMediaType *wrapper, IMFMediaType **ret) +{ + IMFMediaType *mediatype; + UINT8 *buffer; + UINT32 size; + HRESULT hr; + + TRACE("%p, %p.\n", wrapper, ret); + + if (FAILED(hr = MFCreateMediaType(&mediatype))) + return hr; + + if (FAILED(hr = IMFMediaType_GetAllocatedBlob(wrapper, &MF_MT_WRAPPED_TYPE, &buffer, &size))) + { + IMFMediaType_Release(mediatype); + return hr; + } + + hr = MFInitAttributesFromBlob((IMFAttributes *)mediatype, buffer, size); + CoTaskMemFree(buffer); + if (FAILED(hr)) + return hr; + + *ret = mediatype; + + return S_OK; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 4272a206e6..79f25f53d5 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -152,9 +152,9 @@ @ stub MFUnblockThread @ stdcall MFUnlockPlatform() @ stdcall MFUnlockWorkQueue(long) -@ stub MFUnwrapMediaType +@ stdcall MFUnwrapMediaType(ptr ptr) @ stub MFValidateMediaTypeSize -@ stub MFWrapMediaType +@ stdcall MFWrapMediaType(ptr ptr ptr ptr) @ stub MFllMulDiv @ stub PropVariantFromStream @ stub PropVariantToStream diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 85fc176046..d53251c318 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -2616,6 +2616,62 @@ static void test_attributes_serialization(void) IMFAttributes_Release(dest); }
+static void test_wrapped_media_type(void) +{ + IMFMediaType *mediatype, *mediatype2; + UINT32 count, type; + HRESULT hr; + GUID guid; + + hr = MFCreateMediaType(&mediatype); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = MFUnwrapMediaType(mediatype, &mediatype2); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaType_SetUINT32(mediatype, &GUID_NULL, 1); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetUINT32(mediatype, &DUMMY_GUID1, 2); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Failed to set GUID value, hr %#x.\n", hr); + + hr = MFWrapMediaType(mediatype, &MFMediaType_Audio, &IID_IUnknown, &mediatype2); + ok(hr == S_OK, "Failed to create wrapped media type, hr %#x.\n", hr); + + hr = IMFMediaType_GetGUID(mediatype2, &MF_MT_MAJOR_TYPE, &guid); + ok(hr == S_OK, "Failed to get major type, hr %#x.\n", hr); + ok(IsEqualGUID(&guid, &MFMediaType_Audio), "Unexpected major type.\n"); + + hr = IMFMediaType_GetGUID(mediatype2, &MF_MT_SUBTYPE, &guid); + ok(hr == S_OK, "Failed to get subtype, hr %#x.\n", hr); + ok(IsEqualGUID(&guid, &IID_IUnknown), "Unexpected major type.\n"); + + hr = IMFMediaType_GetCount(mediatype2, &count); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(count == 3, "Unexpected count %u.\n", count); + + hr = IMFMediaType_GetItemType(mediatype2, &MF_MT_WRAPPED_TYPE, &type); + ok(hr == S_OK, "Failed to get item type, hr %#x.\n", hr); + ok(type == MF_ATTRIBUTE_BLOB, "Unexpected item type.\n"); + + IMFMediaType_Release(mediatype); + + hr = MFUnwrapMediaType(mediatype2, &mediatype); + ok(hr == S_OK, "Failed to unwrap, hr %#x.\n", hr); + + hr = IMFMediaType_GetGUID(mediatype, &MF_MT_MAJOR_TYPE, &guid); + ok(hr == S_OK, "Failed to get major type, hr %#x.\n", hr); + ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected major type.\n"); + + hr = IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &guid); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#x.\n", hr); + + IMFMediaType_Release(mediatype); + IMFMediaType_Release(mediatype2); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -2648,6 +2704,7 @@ START_TEST(mfplat) test_MFCalculateImageSize(); test_MFCompareFullToPartialMediaType(); test_attributes_serialization(); + test_wrapped_media_type();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index b082f9c2dd..2d794e49eb 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -105,6 +105,7 @@ DEFINE_GUID(MF_MT_ALL_SAMPLES_INDEPENDENT, 0xc9173739, 0x5e56, 0x461c, 0xb7, 0x1 DEFINE_GUID(MF_MT_USER_DATA, 0xb6bc765f, 0x4c3b, 0x40a4, 0xbd, 0x51, 0x25, 0x35, 0xb6, 0x6f, 0xe0, 0x9d); DEFINE_GUID(MF_MT_FRAME_RATE_RANGE_MIN, 0xd2e7558c, 0xdc1f, 0x403f, 0x9a, 0x72, 0xd2, 0x8b, 0xb1, 0xeb, 0x3b, 0x5e); DEFINE_GUID(MF_MT_FRAME_RATE_RANGE_MAX, 0xe3371d41, 0xb4cf, 0x4a05, 0xbd, 0x4e, 0x20, 0xb8, 0x8b, 0xb2, 0xc4, 0xd6); +DEFINE_GUID(MF_MT_WRAPPED_TYPE, 0x4d3f7b23, 0xd02f, 0x4e6c, 0x9b, 0xee, 0xe4, 0xbf, 0x2c, 0x6c, 0x69, 0x5d);
DEFINE_GUID(MFT_CATEGORY_VIDEO_DECODER, 0xd6c02d4b, 0x6833, 0x45b4, 0x97, 0x1a, 0x05, 0xa4, 0xb0, 0x4b, 0xab, 0x91); DEFINE_GUID(MFT_CATEGORY_VIDEO_ENCODER, 0xf79eac7d, 0xe545, 0x4387, 0xbd, 0xee, 0xd6, 0x47, 0xd7, 0xbd, 0xe4, 0x2a); @@ -236,6 +237,8 @@ HRESULT WINAPI MFUnlockWorkQueue(DWORD queue); HRESULT WINAPI MFTUnregister(CLSID clsid); HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory); HRESULT WINAPI MFGetPluginControl(IMFPluginControl**); +HRESULT WINAPI MFWrapMediaType(IMFMediaType *original, REFGUID major, REFGUID subtype, IMFMediaType **wrapped); +HRESULT WINAPI MFUnwrapMediaType(IMFMediaType *wrapped, IMFMediaType **original);
#if defined(__cplusplus) }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=49720
Your paranoid android.
=== w2008s64 (task log) ===
Task errors: The previous 1 run(s) terminated abnormally
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 649 +++++++++++++++++++++++++++++++++---- dlls/mfplat/tests/mfplat.c | 100 +++++- include/mfidl.idl | 42 +++ include/mfobjects.idl | 1 + 4 files changed, 726 insertions(+), 66 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index dd89f4c91a..2adf3819c1 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -1791,10 +1791,17 @@ HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *dest, const UINT8 *buffer return hr; }
-typedef struct _mfbytestream +typedef struct bytestream { struct attributes attributes; IMFByteStream IMFByteStream_iface; + IMFAsyncCallback read_callback; + IMFAsyncCallback write_callback; + IStream *stream; + QWORD position; + DWORD capabilities; + struct list pending; + CRITICAL_SECTION cs; } mfbytestream;
static inline mfbytestream *impl_from_IMFByteStream(IMFByteStream *iface) @@ -1802,20 +1809,209 @@ static inline mfbytestream *impl_from_IMFByteStream(IMFByteStream *iface) return CONTAINING_RECORD(iface, mfbytestream, IMFByteStream_iface); }
-static HRESULT WINAPI mfbytestream_QueryInterface(IMFByteStream *iface, REFIID riid, void **out) +static struct bytestream *impl_from_read_callback_IMFAsyncCallback(IMFAsyncCallback *iface) { - mfbytestream *This = impl_from_IMFByteStream(iface); + return CONTAINING_RECORD(iface, struct bytestream, read_callback); +}
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out); +static struct bytestream *impl_from_write_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct bytestream, write_callback); +}
- if(IsEqualGUID(riid, &IID_IUnknown) || - IsEqualGUID(riid, &IID_IMFByteStream)) +enum async_stream_op_type +{ + ASYNC_STREAM_OP_READ, + ASYNC_STREAM_OP_WRITE, +}; + +struct async_stream_op +{ + IUnknown IUnknown_iface; + LONG refcount; + union + { + const BYTE *src; + BYTE *dest; + } u; + ULONG requested_length; + ULONG actual_length; + IMFAsyncResult *caller; + struct list entry; + enum async_stream_op_type type; +}; + +static struct async_stream_op *impl_async_stream_op_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct async_stream_op, IUnknown_iface); +} + +static HRESULT WINAPI async_stream_op_QueryInterface(IUnknown *iface, REFIID riid, void **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 async_stream_op_AddRef(IUnknown *iface) +{ + struct async_stream_op *op = impl_async_stream_op_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&op->refcount); + + TRACE("%p, refcount %d.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI async_stream_op_Release(IUnknown *iface) +{ + struct async_stream_op *op = impl_async_stream_op_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&op->refcount); + + TRACE("%p, refcount %d.\n", iface, refcount); + + if (!refcount) + { + if (op->caller) + IMFAsyncResult_Release(op->caller); + heap_free(op); + } + + return refcount; +} + +static const IUnknownVtbl async_stream_op_vtbl = +{ + async_stream_op_QueryInterface, + async_stream_op_AddRef, + async_stream_op_Release, +}; + +static HRESULT bytestream_create_io_request(struct bytestream *stream, enum async_stream_op_type type, + const BYTE *data, ULONG size, IMFAsyncCallback *callback, IUnknown *state) +{ + struct async_stream_op *op; + IMFAsyncResult *request; + HRESULT hr; + + op = heap_alloc(sizeof(*op)); + if (!op) + return E_OUTOFMEMORY; + + op->IUnknown_iface.lpVtbl = &async_stream_op_vtbl; + op->refcount = 1; + op->u.src = data; + op->requested_length = size; + op->type = type; + if (FAILED(hr = MFCreateAsyncResult((IUnknown *)&stream->IMFByteStream_iface, callback, state, &op->caller))) + goto failed; + + if (FAILED(hr = MFCreateAsyncResult(&op->IUnknown_iface, type == ASYNC_STREAM_OP_READ ? &stream->read_callback : + &stream->write_callback, NULL, &request))) + goto failed; + + MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, request); + IMFAsyncResult_Release(request); + +failed: + IUnknown_Release(&op->IUnknown_iface); + return hr; +} + +static HRESULT bytestream_complete_io_request(struct bytestream *stream, enum async_stream_op_type type, + IMFAsyncResult *result, ULONG *actual_length) +{ + struct async_stream_op *op = NULL, *cur; + HRESULT hr; + + EnterCriticalSection(&stream->cs); + LIST_FOR_EACH_ENTRY(cur, &stream->pending, struct async_stream_op, entry) + { + if (cur->caller == result && cur->type == type) + { + op = cur; + list_remove(&cur->entry); + break; + } + } + LeaveCriticalSection(&stream->cs); + + if (!op) + return E_INVALIDARG; + + if (SUCCEEDED(hr = IMFAsyncResult_GetStatus(result))) + *actual_length = op->actual_length; + + IUnknown_Release(&op->IUnknown_iface); + + return hr; +} + +static HRESULT WINAPI bytestream_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 bytestream_read_callback_AddRef(IMFAsyncCallback *iface) +{ + struct bytestream *stream = impl_from_read_callback_IMFAsyncCallback(iface); + return IMFByteStream_AddRef(&stream->IMFByteStream_iface); +} + +static ULONG WINAPI bytestream_read_callback_Release(IMFAsyncCallback *iface) +{ + struct bytestream *stream = impl_from_read_callback_IMFAsyncCallback(iface); + return IMFByteStream_Release(&stream->IMFByteStream_iface); +} + +static HRESULT WINAPI bytestream_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static ULONG WINAPI bytestream_write_callback_AddRef(IMFAsyncCallback *iface) +{ + struct bytestream *stream = impl_from_write_callback_IMFAsyncCallback(iface); + return IMFByteStream_AddRef(&stream->IMFByteStream_iface); +} + +static ULONG WINAPI bytestream_write_callback_Release(IMFAsyncCallback *iface) +{ + struct bytestream *stream = impl_from_write_callback_IMFAsyncCallback(iface); + return IMFByteStream_Release(&stream->IMFByteStream_iface); +} + +static HRESULT WINAPI bytestream_QueryInterface(IMFByteStream *iface, REFIID riid, void **out) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFByteStream) || + IsEqualIID(riid, &IID_IUnknown)) { - *out = &This->IMFByteStream_iface; + *out = &stream->IMFByteStream_iface; } - else if(IsEqualGUID(riid, &IID_IMFAttributes)) + else if (IsEqualIID(riid, &IID_IMFAttributes)) { - *out = &This->attributes.IMFAttributes_iface; + *out = &stream->attributes.IMFAttributes_iface; } else { @@ -1828,46 +2024,55 @@ static HRESULT WINAPI mfbytestream_QueryInterface(IMFByteStream *iface, REFIID r return S_OK; }
-static ULONG WINAPI mfbytestream_AddRef(IMFByteStream *iface) +static ULONG WINAPI bytestream_AddRef(IMFByteStream *iface) { - mfbytestream *This = impl_from_IMFByteStream(iface); - ULONG ref = InterlockedIncrement(&This->attributes.ref); + struct bytestream *stream = impl_from_IMFByteStream(iface); + ULONG refcount = InterlockedIncrement(&stream->attributes.ref);
- TRACE("(%p) ref=%u\n", This, ref); + TRACE("%p, refcount %d.\n", iface, refcount);
- return ref; + return refcount; }
-static ULONG WINAPI mfbytestream_Release(IMFByteStream *iface) +static ULONG WINAPI bytestream_Release(IMFByteStream *iface) { - mfbytestream *This = impl_from_IMFByteStream(iface); - ULONG ref = InterlockedDecrement(&This->attributes.ref); + struct bytestream *stream = impl_from_IMFByteStream(iface); + ULONG refcount = InterlockedDecrement(&stream->attributes.ref); + struct async_stream_op *cur, *cur2;
- TRACE("(%p) ref=%u\n", This, ref); + TRACE("%p, refcount %d.\n", iface, refcount);
- if (!ref) + if (!refcount) { - clear_attributes_object(&This->attributes); - HeapFree(GetProcessHeap(), 0, This); + clear_attributes_object(&stream->attributes); + LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &stream->pending, struct async_stream_op, entry) + { + list_remove(&cur->entry); + IUnknown_Release(&cur->IUnknown_iface); + } + DeleteCriticalSection(&stream->cs); + if (stream->stream) + IStream_Release(stream->stream); + heap_free(stream); }
- return ref; + return refcount; }
-static HRESULT WINAPI mfbytestream_GetCapabilities(IMFByteStream *iface, DWORD *capabilities) +static HRESULT WINAPI bytestream_GetCapabilities(IMFByteStream *iface, DWORD *capabilities) { - mfbytestream *This = impl_from_IMFByteStream(iface); + struct bytestream *stream = impl_from_IMFByteStream(iface);
- FIXME("%p, %p\n", This, capabilities); + TRACE("%p, %p.\n", iface, capabilities);
- return E_NOTIMPL; + *capabilities = stream->capabilities; + + return S_OK; }
static HRESULT WINAPI mfbytestream_GetLength(IMFByteStream *iface, QWORD *length) { - mfbytestream *This = impl_from_IMFByteStream(iface); - - FIXME("%p, %p\n", This, length); + FIXME("%p, %p.\n", iface, length);
return E_NOTIMPL; } @@ -1920,23 +2125,23 @@ static HRESULT WINAPI mfbytestream_Read(IMFByteStream *iface, BYTE *data, ULONG return E_NOTIMPL; }
-static HRESULT WINAPI mfbytestream_BeginRead(IMFByteStream *iface, BYTE *data, ULONG count, - IMFAsyncCallback *callback, IUnknown *state) +static HRESULT WINAPI bytestream_BeginRead(IMFByteStream *iface, BYTE *data, ULONG size, IMFAsyncCallback *callback, + IUnknown *state) { - mfbytestream *This = impl_from_IMFByteStream(iface); + struct bytestream *stream = impl_from_IMFByteStream(iface);
- FIXME("%p, %p, %u, %p, %p\n", This, data, count, callback, state); + TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
- return E_NOTIMPL; + return bytestream_create_io_request(stream, ASYNC_STREAM_OP_READ, data, size, callback, state); }
-static HRESULT WINAPI mfbytestream_EndRead(IMFByteStream *iface, IMFAsyncResult *result, ULONG *byte_read) +static HRESULT WINAPI bytestream_EndRead(IMFByteStream *iface, IMFAsyncResult *result, ULONG *byte_read) { - mfbytestream *This = impl_from_IMFByteStream(iface); + struct bytestream *stream = impl_from_IMFByteStream(iface);
- FIXME("%p, %p, %p\n", This, result, byte_read); + TRACE("%p, %p, %p.\n", iface, result, byte_read);
- return E_NOTIMPL; + return bytestream_complete_io_request(stream, ASYNC_STREAM_OP_READ, result, byte_read); }
static HRESULT WINAPI mfbytestream_Write(IMFByteStream *iface, const BYTE *data, ULONG count, ULONG *written) @@ -1948,23 +2153,46 @@ static HRESULT WINAPI mfbytestream_Write(IMFByteStream *iface, const BYTE *data, return E_NOTIMPL; }
-static HRESULT WINAPI mfbytestream_BeginWrite(IMFByteStream *iface, const BYTE *data, ULONG count, - IMFAsyncCallback *callback, IUnknown *state) +static HRESULT WINAPI bytestream_BeginWrite(IMFByteStream *iface, const BYTE *data, ULONG size, + IMFAsyncCallback *callback, IUnknown *state) { - mfbytestream *This = impl_from_IMFByteStream(iface); + struct bytestream *stream = impl_from_IMFByteStream(iface); + struct async_stream_op *op; + IMFAsyncResult *request; + HRESULT hr;
- FIXME("%p, %p, %u, %p, %p\n", This, data, count, callback, state); + TRACE("%p, %p, %u, %p, %p.\n", iface, data, size, callback, state);
- return E_NOTIMPL; + op = heap_alloc(sizeof(*op)); + if (!op) + return E_OUTOFMEMORY; + + op->IUnknown_iface.lpVtbl = &async_stream_op_vtbl; + op->refcount = 1; + op->u.src = data; + op->requested_length = size; + op->type = ASYNC_STREAM_OP_WRITE; + if (FAILED(hr = MFCreateAsyncResult((IUnknown *)iface, callback, state, &op->caller))) + goto failed; + + if (FAILED(hr = MFCreateAsyncResult(&op->IUnknown_iface, &stream->write_callback, NULL, &request))) + goto failed; + + MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, request); + IMFAsyncResult_Release(request); + +failed: + IUnknown_Release(&op->IUnknown_iface); + return hr; }
-static HRESULT WINAPI mfbytestream_EndWrite(IMFByteStream *iface, IMFAsyncResult *result, ULONG *written) +static HRESULT WINAPI bytestream_EndWrite(IMFByteStream *iface, IMFAsyncResult *result, ULONG *written) { - mfbytestream *This = impl_from_IMFByteStream(iface); + struct bytestream *stream = impl_from_IMFByteStream(iface);
- FIXME("%p, %p, %p\n", This, result, written); + TRACE("%p, %p, %p.\n", iface, result, written);
- return E_NOTIMPL; + return bytestream_complete_io_request(stream, ASYNC_STREAM_OP_WRITE, result, written); }
static HRESULT WINAPI mfbytestream_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN seek, LONGLONG offset, @@ -1997,26 +2225,190 @@ static HRESULT WINAPI mfbytestream_Close(IMFByteStream *iface)
static const IMFByteStreamVtbl mfbytestream_vtbl = { - mfbytestream_QueryInterface, - mfbytestream_AddRef, - mfbytestream_Release, - mfbytestream_GetCapabilities, + bytestream_QueryInterface, + bytestream_AddRef, + bytestream_Release, + bytestream_GetCapabilities, mfbytestream_GetLength, mfbytestream_SetLength, mfbytestream_GetCurrentPosition, mfbytestream_SetCurrentPosition, mfbytestream_IsEndOfStream, mfbytestream_Read, - mfbytestream_BeginRead, - mfbytestream_EndRead, + bytestream_BeginRead, + bytestream_EndRead, mfbytestream_Write, - mfbytestream_BeginWrite, - mfbytestream_EndWrite, + bytestream_BeginWrite, + bytestream_EndWrite, mfbytestream_Seek, mfbytestream_Flush, mfbytestream_Close };
+static HRESULT WINAPI bytestream_stream_GetLength(IMFByteStream *iface, QWORD *length) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + STATSTG statstg; + HRESULT hr; + + TRACE("%p, %p.\n", iface, length); + + if (FAILED(hr = IStream_Stat(stream->stream, &statstg, STATFLAG_NONAME))) + return hr; + + *length = statstg.cbSize.QuadPart; + + return S_OK; +} + +static HRESULT WINAPI bytestream_stream_SetLength(IMFByteStream *iface, QWORD length) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + ULARGE_INTEGER size; + + TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(length)); + + size.QuadPart = length; + return IStream_SetSize(stream->stream, size); +} + +static HRESULT WINAPI bytestream_stream_GetCurrentPosition(IMFByteStream *iface, QWORD *position) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + + TRACE("%p, %p.\n", iface, position); + + *position = stream->position; + + return S_OK; +} + +static HRESULT WINAPI bytestream_stream_SetCurrentPosition(IMFByteStream *iface, QWORD position) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + + TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(position)); + + stream->position = position; + + return S_OK; +} + +static HRESULT WINAPI bytestream_stream_IsEndOfStream(IMFByteStream *iface, BOOL *ret) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + STATSTG statstg; + HRESULT hr; + + TRACE("%p, %p.\n", iface, ret); + + if (FAILED(hr = IStream_Stat(stream->stream, &statstg, STATFLAG_NONAME))) + return hr; + + *ret = stream->position >= statstg.cbSize.QuadPart; + + return S_OK; +} + +static HRESULT WINAPI bytestream_stream_Read(IMFByteStream *iface, BYTE *buffer, ULONG size, ULONG *read_len) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + LARGE_INTEGER position; + HRESULT hr; + + TRACE("%p, %p, %u, %p.\n", iface, buffer, size, read_len); + + position.QuadPart = stream->position; + if (FAILED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL))) + return hr; + + if (SUCCEEDED(hr = IStream_Read(stream->stream, buffer, size, read_len))) + stream->position += *read_len; + + return hr; +} + +static HRESULT WINAPI bytestream_stream_Write(IMFByteStream *iface, const BYTE *buffer, ULONG size, ULONG *written) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + LARGE_INTEGER position; + HRESULT hr; + + TRACE("%p, %p, %u, %p.\n", iface, buffer, size, written); + + position.QuadPart = stream->position; + if (FAILED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL))) + return hr; + + if (SUCCEEDED(hr = IStream_Write(stream->stream, buffer, size, written))) + stream->position += *written; + + return hr; +} + +static HRESULT WINAPI bytestream_stream_Seek(IMFByteStream *iface, MFBYTESTREAM_SEEK_ORIGIN origin, LONGLONG offset, + DWORD flags, QWORD *current) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + + TRACE("%p, %u, %s, %#x, %p.\n", iface, origin, wine_dbgstr_longlong(offset), flags, current); + + switch (origin) + { + case msoBegin: + stream->position = offset; + break; + case msoCurrent: + stream->position += offset; + break; + default: + WARN("Unknown origin mode %d.\n", origin); + return E_INVALIDARG; + } + + *current = stream->position; + + return S_OK; +} + +static HRESULT WINAPI bytestream_stream_Flush(IMFByteStream *iface) +{ + struct bytestream *stream = impl_from_IMFByteStream(iface); + + TRACE("%p.\n", iface); + + return IStream_Commit(stream->stream, STGC_DEFAULT); +} + +static HRESULT WINAPI bytestream_stream_Close(IMFByteStream *iface) +{ + TRACE("%p.\n", iface); + + return S_OK; +} + +static const IMFByteStreamVtbl bytestream_stream_vtbl = +{ + bytestream_QueryInterface, + bytestream_AddRef, + bytestream_Release, + bytestream_GetCapabilities, + bytestream_stream_GetLength, + bytestream_stream_SetLength, + bytestream_stream_GetCurrentPosition, + bytestream_stream_SetCurrentPosition, + bytestream_stream_IsEndOfStream, + bytestream_stream_Read, + bytestream_BeginRead, + bytestream_EndRead, + bytestream_stream_Write, + bytestream_BeginWrite, + bytestream_EndWrite, + bytestream_stream_Seek, + bytestream_stream_Flush, + bytestream_stream_Close, +}; + static inline mfbytestream *impl_from_IMFByteStream_IMFAttributes(IMFAttributes *iface) { return CONTAINING_RECORD(iface, mfbytestream, attributes.IMFAttributes_iface); @@ -2078,15 +2470,99 @@ static const IMFAttributesVtbl mfbytestream_attributes_vtbl = mfattributes_CopyAllItems };
+static HRESULT WINAPI bytestream_stream_read_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct bytestream *stream = impl_from_read_callback_IMFAsyncCallback(iface); + struct async_stream_op *op; + LARGE_INTEGER position; + IUnknown *object; + HRESULT hr; + + if (FAILED(hr = IMFAsyncResult_GetObject(result, &object))) + return hr; + + op = impl_async_stream_op_from_IUnknown(object); + + position.QuadPart = stream->position; + if (SUCCEEDED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL))) + { + if (SUCCEEDED(hr = IStream_Read(stream->stream, op->u.dest, op->requested_length, &op->actual_length))) + stream->position += op->actual_length; + } + + IMFAsyncResult_SetStatus(op->caller, hr); + + EnterCriticalSection(&stream->cs); + list_add_tail(&stream->pending, &op->entry); + LeaveCriticalSection(&stream->cs); + + MFInvokeCallback(op->caller); + + return S_OK; +} + +static HRESULT WINAPI bytestream_stream_write_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct bytestream *stream = impl_from_read_callback_IMFAsyncCallback(iface); + struct async_stream_op *op; + LARGE_INTEGER position; + IUnknown *object; + HRESULT hr; + + if (FAILED(hr = IMFAsyncResult_GetObject(result, &object))) + return hr; + + op = impl_async_stream_op_from_IUnknown(object); + + position.QuadPart = stream->position; + if (SUCCEEDED(hr = IStream_Seek(stream->stream, position, STREAM_SEEK_SET, NULL))) + { + if (SUCCEEDED(hr = IStream_Write(stream->stream, op->u.src, op->requested_length, &op->actual_length))) + stream->position += op->actual_length; + } + + IMFAsyncResult_SetStatus(op->caller, hr); + + EnterCriticalSection(&stream->cs); + list_add_tail(&stream->pending, &op->entry); + LeaveCriticalSection(&stream->cs); + + MFInvokeCallback(op->caller); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl bytestream_stream_read_callback_vtbl = +{ + bytestream_callback_QueryInterface, + bytestream_read_callback_AddRef, + bytestream_read_callback_Release, + bytestream_callback_GetParameters, + bytestream_stream_read_callback_Invoke, +}; + +static const IMFAsyncCallbackVtbl bytestream_stream_write_callback_vtbl = +{ + bytestream_callback_QueryInterface, + bytestream_write_callback_AddRef, + bytestream_write_callback_Release, + bytestream_callback_GetParameters, + bytestream_stream_write_callback_Invoke, +}; + +/*********************************************************************** + * MFCreateMFByteStreamOnStream (mfplat.@) + */ HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **bytestream) { - mfbytestream *object; + struct bytestream *object; + LARGE_INTEGER position; HRESULT hr;
- TRACE("(%p, %p): stub\n", stream, bytestream); + TRACE("%p, %p.\n", stream, bytestream);
- object = heap_alloc( sizeof(*object) ); - if(!object) + object = heap_alloc_zero(sizeof(*object)); + if (!object) return E_OUTOFMEMORY;
if (FAILED(hr = init_attributes_object(&object->attributes, 0))) @@ -2094,14 +2570,59 @@ HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **byt heap_free(object); return hr; } - object->IMFByteStream_iface.lpVtbl = &mfbytestream_vtbl; + + object->IMFByteStream_iface.lpVtbl = &bytestream_stream_vtbl; object->attributes.IMFAttributes_iface.lpVtbl = &mfbytestream_attributes_vtbl; + object->read_callback.lpVtbl = &bytestream_stream_read_callback_vtbl; + object->write_callback.lpVtbl = &bytestream_stream_write_callback_vtbl; + InitializeCriticalSection(&object->cs); + list_init(&object->pending); + + object->stream = stream; + IStream_AddRef(object->stream); + position.QuadPart = 0; + IStream_Seek(object->stream, position, STREAM_SEEK_SET, NULL);
*bytestream = &object->IMFByteStream_iface;
return S_OK; }
+static HRESULT WINAPI bytestream_file_read_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + FIXME("%p, %p.\n", iface, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI bytestream_file_write_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + FIXME("%p, %p.\n", iface, result); + + return E_NOTIMPL; +} + +static const IMFAsyncCallbackVtbl bytestream_file_read_callback_vtbl = +{ + bytestream_callback_QueryInterface, + bytestream_read_callback_AddRef, + bytestream_read_callback_Release, + bytestream_callback_GetParameters, + bytestream_file_read_callback_Invoke, +}; + +static const IMFAsyncCallbackVtbl bytestream_file_write_callback_vtbl = +{ + bytestream_callback_QueryInterface, + bytestream_write_callback_AddRef, + bytestream_write_callback_Release, + bytestream_callback_GetParameters, + bytestream_file_write_callback_Invoke, +}; + +/*********************************************************************** + * MFCreateFile (mfplat.@) + */ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE openmode, MF_FILE_FLAGS flags, LPCWSTR url, IMFByteStream **bytestream) { @@ -2161,8 +2682,8 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open /* Close the file again, since we don't do anything with it yet */ CloseHandle(file);
- object = heap_alloc( sizeof(*object) ); - if(!object) + object = heap_alloc_zero(sizeof(*object)); + if (!object) return E_OUTOFMEMORY;
if (FAILED(hr = init_attributes_object(&object->attributes, 0))) @@ -2172,6 +2693,10 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open } object->IMFByteStream_iface.lpVtbl = &mfbytestream_vtbl; object->attributes.IMFAttributes_iface.lpVtbl = &mfbytestream_attributes_vtbl; + object->read_callback.lpVtbl = &bytestream_file_read_callback_vtbl; + object->write_callback.lpVtbl = &bytestream_file_write_callback_vtbl; + InitializeCriticalSection(&object->cs); + list_init(&object->pending);
*bytestream = &object->IMFByteStream_iface;
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index d53251c318..f0148e1a5a 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -1009,9 +1009,10 @@ static void test_MFCreateMFByteStreamOnStream(void) IMFByteStream *bytestream2; IStream *stream; IMFAttributes *attributes = NULL; + DWORD caps, written, count; IUnknown *unknown; + ULONG ref, size; HRESULT hr; - ULONG ref;
if(!pMFCreateMFByteStreamOnStream) { @@ -1022,6 +1023,10 @@ static void test_MFCreateMFByteStreamOnStream(void) hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); ok(hr == S_OK, "got 0x%08x\n", hr);
+ caps = 0xffff0000; + hr = IStream_Write(stream, &caps, sizeof(caps), &written); + ok(hr == S_OK, "Failed to write, hr %#x.\n", hr); + hr = pMFCreateMFByteStreamOnStream(stream, &bytestream); ok(hr == S_OK, "got 0x%08x\n", hr);
@@ -1054,6 +1059,9 @@ static void test_MFCreateMFByteStreamOnStream(void) }
ok(attributes != NULL, "got NULL\n"); + hr = IMFAttributes_GetCount(attributes, &count); + ok(hr == S_OK, "Failed to get attributes count, hr %#x.\n", hr); + ok(count == 0, "Unexpected attributes count %u.\n", count);
hr = IMFAttributes_QueryInterface(attributes, &IID_IUnknown, (void **)&unknown); @@ -1069,18 +1077,55 @@ static void test_MFCreateMFByteStreamOnStream(void) ref = IMFByteStream_Release(bytestream2); ok(ref == 2, "got %u\n", ref);
+ hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFByteStreamBuffering, (void **)&unknown); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFByteStreamCacheControl, (void **)&unknown); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFMediaEventGenerator, (void **)&unknown); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFGetService, (void **)&unknown); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + hr = IMFByteStream_GetCapabilities(bytestream, &caps); + ok(hr == S_OK, "Failed to get stream capabilities, hr %#x.\n", hr); +todo_wine + ok(caps == (MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE), "Unexpected caps %#x.\n", caps); + + hr = IMFByteStream_Close(bytestream); + ok(hr == S_OK, "Failed to close, hr %#x.\n", hr); + + hr = IMFByteStream_Close(bytestream); + ok(hr == S_OK, "Failed to close, hr %#x.\n", hr); + + hr = IMFByteStream_GetCapabilities(bytestream, &caps); + ok(hr == S_OK, "Failed to get stream capabilities, hr %#x.\n", hr); +todo_wine + ok(caps == (MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE), "Unexpected caps %#x.\n", caps); + + caps = 0; + hr = IMFByteStream_Read(bytestream, (BYTE *)&caps, sizeof(caps), &size); + ok(hr == S_OK, "Failed to read from stream, hr %#x.\n", hr); + ok(caps == 0xffff0000, "Unexpected content.\n"); + IMFAttributes_Release(attributes); IMFByteStream_Release(bytestream); IStream_Release(stream); }
-static void test_MFCreateFile(void) +static void test_file_stream(void) { IMFByteStream *bytestream; IMFByteStream *bytestream2; IMFAttributes *attributes = NULL; - HRESULT hr; + MF_ATTRIBUTE_TYPE item_type; + DWORD caps, count; WCHAR *filename; + IUnknown *unk; + HRESULT hr; + WCHAR *str;
static const WCHAR newfilename[] = {'n','e','w','.','m','p','4',0};
@@ -1093,10 +1138,57 @@ static void test_MFCreateFile(void) MF_FILEFLAGS_NONE, filename, &bytestream); ok(hr == S_OK, "got 0x%08x\n", hr);
+ hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFByteStreamBuffering, (void **)&unk); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFByteStreamCacheControl, (void **)&unk); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFMediaEventGenerator, (void **)&unk); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFGetService, (void **)&unk); +todo_wine + ok(hr == S_OK, "Failed to get interface pointer, hr %#x.\n", hr); + if (SUCCEEDED(hr)) + IUnknown_Release(unk); + + hr = IMFByteStream_GetCapabilities(bytestream, &caps); + ok(hr == S_OK, "Failed to get stream capabilities, hr %#x.\n", hr); + if (is_win8_plus) + { +todo_wine + ok(caps == (MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE | MFBYTESTREAM_DOES_NOT_USE_NETWORK), + "Unexpected caps %#x.\n", caps); + } + else + ok(caps == (MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE), "Unexpected caps %#x.\n", caps); + hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFAttributes, (void **)&attributes); ok(hr == S_OK, "got 0x%08x\n", hr); ok(attributes != NULL, "got NULL\n"); + + hr = IMFAttributes_GetCount(attributes, &count); + ok(hr == S_OK, "Failed to get attributes count, hr %#x.\n", hr); +todo_wine + ok(count == 2, "Unexpected attributes count %u.\n", count); + + /* Original file name. */ + hr = IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_ORIGIN_NAME, &str, &count); +todo_wine + ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); +if (SUCCEEDED(hr)) +{ + ok(!lstrcmpW(str, filename), "Unexpected name %s.\n", wine_dbgstr_w(str)); + CoTaskMemFree(str); +} + /* Modification time. */ + hr = IMFAttributes_GetItemType(attributes, &MF_BYTESTREAM_LAST_MODIFIED_TIME, &item_type); +todo_wine { + ok(hr == S_OK, "Failed to get item type, hr %#x.\n", hr); + ok(item_type == MF_ATTRIBUTE_BLOB, "Unexpected item type.\n"); +} IMFAttributes_Release(attributes);
hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, @@ -2684,7 +2776,7 @@ START_TEST(mfplat) test_MFCreateMediaEvent(); test_attributes(); test_sample(); - test_MFCreateFile(); + test_file_stream(); test_MFCreateMFByteStreamOnStream(); test_system_memory_buffer(); test_source_resolver(); diff --git a/include/mfidl.idl b/include/mfidl.idl index 944f8f95ba..7f98d0e821 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -211,6 +211,48 @@ interface IMFByteStreamHandler : IUnknown [out] QWORD *bytes); }
+typedef [public] struct _MF_LEAKY_BUCKET_PAIR +{ + DWORD dwBitrate; + DWORD msBufferWindow; +} MF_LEAKY_BUCKET_PAIR; + +typedef [public] struct _MFBYTESTREAM_BUFFERING_PARAMS +{ + QWORD cbTotalFileSize; + QWORD cbPlayableDataSize; + MF_LEAKY_BUCKET_PAIR *prgBuckets; + DWORD cBuckets; + QWORD qwNetBufferingTime; + QWORD qwExtraBufferingTimeDuringSeek; + QWORD qwPlayDuration; + float dRate; +} MFBYTESTREAM_BUFFERING_PARAMS; + +[ + object, + uuid(6d66d782-1d4f-4db7-8c63-cb8c77f1ef5e), +] +interface IMFByteStreamBuffering : IUnknown +{ + HRESULT SetBufferingParams( + [in] MFBYTESTREAM_BUFFERING_PARAMS *params); + + HRESULT EnableBuffering( + [in] BOOL enable); + + HRESULT StopBuffering(); +} + +[ + object, + uuid(f5042ea4-7a96-4a75-aa7b-2be1ef7f88d5), +] +interface IMFByteStreamCacheControl : IUnknown +{ + HRESULT StopBackgroundTransfer(); +} + [ object, uuid(6d4c7b74-52a0-4bb7-b0db-55f29f47a668), diff --git a/include/mfobjects.idl b/include/mfobjects.idl index b67aec2a61..ff30b81755 100644 --- a/include/mfobjects.idl +++ b/include/mfobjects.idl @@ -613,6 +613,7 @@ cpp_quote("#define MFBYTESTREAM_IS_DIRECTORY 0x00000080") cpp_quote("#define MFBYTESTREAM_HAS_SLOW_SEEK 0x00000100") cpp_quote("#define MFBYTESTREAM_IS_PARTIALLY_DOWNLOADED 0x00000200") cpp_quote("#define MFBYTESTREAM_SHARE_WRITE 0x00000400") +cpp_quote("#define MFBYTESTREAM_DOES_NOT_USE_NETWORK 0x00000800")
cpp_quote("#define MFBYTESTREAM_SEEK_FLAG_CANCEL_PENDING_IO 0x00000001")
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=49721
Your paranoid android.
=== debian9 (32 bit Chinese:China report) ===
mfplat: mfplat.c:2437: Test failed: Unexpected refcount 1. Unhandled exception: page fault on execute access to 0x00000000 in 32-bit code (0x00000000).
Report errors: mfplat:mfplat crashed (c0000005)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 1 + dlls/mfplat/tests/mfplat.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 2adf3819c1..b3c264b6e0 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -2582,6 +2582,7 @@ HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **byt IStream_AddRef(object->stream); position.QuadPart = 0; IStream_Seek(object->stream, position, STREAM_SEEK_SET, NULL); + object->capabilities = MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE;
*bytestream = &object->IMFByteStream_iface;
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index f0148e1a5a..6603808e8b 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -1091,7 +1091,6 @@ static void test_MFCreateMFByteStreamOnStream(void)
hr = IMFByteStream_GetCapabilities(bytestream, &caps); ok(hr == S_OK, "Failed to get stream capabilities, hr %#x.\n", hr); -todo_wine ok(caps == (MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE), "Unexpected caps %#x.\n", caps);
hr = IMFByteStream_Close(bytestream); @@ -1102,7 +1101,6 @@ todo_wine
hr = IMFByteStream_GetCapabilities(bytestream, &caps); ok(hr == S_OK, "Failed to get stream capabilities, hr %#x.\n", hr); -todo_wine ok(caps == (MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE), "Unexpected caps %#x.\n", caps);
caps = 0;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 20 ++++++++++++++++---- dlls/mfplat/tests/mfplat.c | 9 ++------- 2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index b3c264b6e0..12ac940bf0 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -2632,6 +2632,7 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open DWORD filesharemode = FILE_SHARE_READ; DWORD filecreation_disposition = 0; DWORD fileattributes = 0; + FILETIME writetime; HANDLE file; HRESULT hr;
@@ -2680,15 +2681,16 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open if(file == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError());
- /* Close the file again, since we don't do anything with it yet */ - CloseHandle(file); - object = heap_alloc_zero(sizeof(*object)); if (!object) + { + CloseHandle(file); return E_OUTOFMEMORY; + }
- if (FAILED(hr = init_attributes_object(&object->attributes, 0))) + if (FAILED(hr = init_attributes_object(&object->attributes, 2))) { + CloseHandle(file); heap_free(object); return hr; } @@ -2699,8 +2701,18 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open InitializeCriticalSection(&object->cs); list_init(&object->pending);
+ if (GetFileTime(file, NULL, NULL, &writetime)) + { + IMFAttributes_SetBlob(&object->attributes.IMFAttributes_iface, &MF_BYTESTREAM_LAST_MODIFIED_TIME, + (const UINT8 *)&writetime, sizeof(writetime)); + } + + IMFAttributes_SetString(&object->attributes.IMFAttributes_iface, &MF_BYTESTREAM_ORIGIN_NAME, url); + *bytestream = &object->IMFByteStream_iface;
+ CloseHandle(file); + return S_OK; }
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 6603808e8b..4e01abf6dc 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -1169,24 +1169,19 @@ todo_wine
hr = IMFAttributes_GetCount(attributes, &count); ok(hr == S_OK, "Failed to get attributes count, hr %#x.\n", hr); -todo_wine ok(count == 2, "Unexpected attributes count %u.\n", count);
/* Original file name. */ hr = IMFAttributes_GetAllocatedString(attributes, &MF_BYTESTREAM_ORIGIN_NAME, &str, &count); -todo_wine ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); -if (SUCCEEDED(hr)) -{ ok(!lstrcmpW(str, filename), "Unexpected name %s.\n", wine_dbgstr_w(str)); CoTaskMemFree(str); -} + /* Modification time. */ hr = IMFAttributes_GetItemType(attributes, &MF_BYTESTREAM_LAST_MODIFIED_TIME, &item_type); -todo_wine { ok(hr == S_OK, "Failed to get item type, hr %#x.\n", hr); ok(item_type == MF_ATTRIBUTE_BLOB, "Unexpected item type.\n"); -} + IMFAttributes_Release(attributes);
hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 47 +++++++++++++++++++++++++++++++++++++- dlls/mfplat/tests/mfplat.c | 4 +--- 2 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 12ac940bf0..bac5905cff 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -1795,6 +1795,7 @@ typedef struct bytestream { struct attributes attributes; IMFByteStream IMFByteStream_iface; + IMFGetService IMFGetService_iface; IMFAsyncCallback read_callback; IMFAsyncCallback write_callback; IStream *stream; @@ -1809,6 +1810,11 @@ static inline mfbytestream *impl_from_IMFByteStream(IMFByteStream *iface) return CONTAINING_RECORD(iface, mfbytestream, IMFByteStream_iface); }
+static struct bytestream *impl_bytestream_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct bytestream, IMFGetService_iface); +} + static struct bytestream *impl_from_read_callback_IMFAsyncCallback(IMFAsyncCallback *iface) { return CONTAINING_RECORD(iface, struct bytestream, read_callback); @@ -2013,9 +2019,13 @@ static HRESULT WINAPI bytestream_QueryInterface(IMFByteStream *iface, REFIID rii { *out = &stream->attributes.IMFAttributes_iface; } + else if (stream->IMFGetService_iface.lpVtbl && IsEqualIID(riid, &IID_IMFGetService)) + { + *out = &stream->IMFGetService_iface; + } else { - FIXME("(%s, %p)\n", debugstr_guid(riid), out); + WARN("Unsupported %s.\n", debugstr_guid(riid)); *out = NULL; return E_NOINTERFACE; } @@ -2621,6 +2631,40 @@ static const IMFAsyncCallbackVtbl bytestream_file_write_callback_vtbl = bytestream_file_write_callback_Invoke, };
+static HRESULT WINAPI bytestream_file_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct bytestream *stream = impl_bytestream_from_IMFGetService(iface); + return IMFByteStream_QueryInterface(&stream->IMFByteStream_iface, riid, obj); +} + +static ULONG WINAPI bytestream_file_getservice_AddRef(IMFGetService *iface) +{ + struct bytestream *stream = impl_bytestream_from_IMFGetService(iface); + return IMFByteStream_AddRef(&stream->IMFByteStream_iface); +} + +static ULONG WINAPI bytestream_file_getservice_Release(IMFGetService *iface) +{ + struct bytestream *stream = impl_bytestream_from_IMFGetService(iface); + return IMFByteStream_Release(&stream->IMFByteStream_iface); +} + +static HRESULT WINAPI bytestream_file_getservice_GetService(IMFGetService *iface, REFGUID service, + REFIID riid, void **obj) +{ + FIXME("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj); + + return E_NOTIMPL; +} + +static const IMFGetServiceVtbl bytestream_file_getservice_vtbl = +{ + bytestream_file_getservice_QueryInterface, + bytestream_file_getservice_AddRef, + bytestream_file_getservice_Release, + bytestream_file_getservice_GetService, +}; + /*********************************************************************** * MFCreateFile (mfplat.@) */ @@ -2696,6 +2740,7 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open } object->IMFByteStream_iface.lpVtbl = &mfbytestream_vtbl; object->attributes.IMFAttributes_iface.lpVtbl = &mfbytestream_attributes_vtbl; + object->IMFGetService_iface.lpVtbl = &bytestream_file_getservice_vtbl; object->read_callback.lpVtbl = &bytestream_file_read_callback_vtbl; object->write_callback.lpVtbl = &bytestream_file_write_callback_vtbl; InitializeCriticalSection(&object->cs); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 4e01abf6dc..6c6bfc16b6 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -1146,10 +1146,8 @@ static void test_file_stream(void) ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFGetService, (void **)&unk); -todo_wine ok(hr == S_OK, "Failed to get interface pointer, hr %#x.\n", hr); - if (SUCCEEDED(hr)) - IUnknown_Release(unk); + IUnknown_Release(unk);
hr = IMFByteStream_GetCapabilities(bytestream, &caps); ok(hr == S_OK, "Failed to get stream capabilities, hr %#x.\n", hr);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=49724
Your paranoid android.
=== debian9 (32 bit Chinese:China report) ===
mfplat: mfplat.c:2428: Test failed: Unexpected refcount 1. Unhandled exception: page fault on read access to 0x00000009 in 32-bit code (0x7e7d650a).
Report errors: mfplat:mfplat crashed (c0000005)