Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45715 Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com --- dlls/mfplat/main.c | 176 +++++++++++++++++++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 90 +++++++++++++++++++++++ include/mfapi.h | 1 + 4 files changed, 268 insertions(+), 1 deletion(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 2d87429..9f381ef 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -2347,3 +2347,179 @@ HRESULT WINAPI MFCreateStreamDescriptor(DWORD identifier, DWORD count, *descriptor = &object->IMFStreamDescriptor_iface; return S_OK; } + + +typedef struct _mfbuffer +{ + IMFMediaBuffer IMFMediaBuffer_iface; + LONG ref; + + BYTE *buffer; + DWORD max_length; + DWORD current; +} mfbuffer; + +static inline mfbuffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) +{ + return CONTAINING_RECORD(iface, mfbuffer, IMFMediaBuffer_iface); +} + +static HRESULT WINAPI mfbuffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out); + + if(IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IMFMediaBuffer)) + { + *out = &This->IMFMediaBuffer_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 mfbuffer_AddRef(IMFMediaBuffer *iface) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%u\n", This, ref); + + return ref; +} + +static ULONG WINAPI mfbuffer_Release(IMFMediaBuffer *iface) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%u\n", This, ref); + + if (!ref) + { + heap_free(This->buffer); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI mfbuffer_Lock(IMFMediaBuffer *iface, BYTE **buffer, DWORD *max, DWORD *current) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %p %p, %p\n", This, buffer, max, current); + + if(!buffer) + return E_INVALIDARG; + + *buffer = This->buffer; + if(max) + *max = This->max_length; + if(current) + *current = This->current; + + return S_OK; +} + +static HRESULT WINAPI mfbuffer_Unlock(IMFMediaBuffer *iface) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface); + + TRACE("%p\n", This); + + return S_OK; +} + +static HRESULT WINAPI mfbuffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *current) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface); + + TRACE("%p\n", This); + + if(!current) + return E_INVALIDARG; + + *current = This->current; + + return S_OK; +} + +static HRESULT WINAPI mfbuffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD current) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %u\n", This, current); + + if(current > This->max_length) + return E_INVALIDARG; + + This->current = current; + + return S_OK; +} + +static HRESULT WINAPI mfbuffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *max) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %p\n", This, max); + + if(!max) + return E_INVALIDARG; + + *max = This->max_length; + + return S_OK; +} + +static const IMFMediaBufferVtbl mfbuffer_vtbl = +{ + mfbuffer_QueryInterface, + mfbuffer_AddRef, + mfbuffer_Release, + mfbuffer_Lock, + mfbuffer_Unlock, + mfbuffer_GetCurrentLength, + mfbuffer_SetCurrentLength, + mfbuffer_GetMaxLength +}; + +HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer) +{ + mfbuffer *object; + BYTE *bytes; + + TRACE("%u, %p\n", max_length, buffer); + + if(!buffer) + return E_INVALIDARG; + + object = heap_alloc( sizeof(*object) ); + if(!object) + return E_OUTOFMEMORY; + + bytes = heap_alloc( max_length ); + if(!bytes) + { + heap_free(object); + return E_OUTOFMEMORY; + } + + object->ref = 1; + object->max_length = max_length; + object->current = 0; + object->buffer = bytes; + object->IMFMediaBuffer_iface.lpVtbl = &mfbuffer_vtbl; + *buffer = &object->IMFMediaBuffer_iface; + + return S_OK; +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 1d64420..42b0b86 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -51,7 +51,7 @@ @ stub MFCreateMediaEvent @ stdcall MFCreateMediaType(ptr) @ stub MFCreateMediaTypeFromRepresentation -@ stub MFCreateMemoryBuffer +@ stdcall MFCreateMemoryBuffer(long ptr) @ stub MFCreateMemoryStream @ stub MFCreatePathFromURL @ stub MFCreatePresentationDescriptor diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index f4b5014..ccbbfb7 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -38,6 +38,8 @@
static HRESULT (WINAPI *pMFCreateSourceResolver)(IMFSourceResolver **resolver); static HRESULT (WINAPI *pMFCreateMFByteStreamOnStream)(IStream *stream, IMFByteStream **bytestream); +static HRESULT (WINAPI *pMFCreateMemoryBuffer)(DWORD max_length, IMFMediaBuffer **buffer); +
DEFINE_GUID(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 0xa634a91c, 0x822b, 0x41b9, 0xa4, 0x94, 0x4d, 0xe4, 0x64, 0x36, 0x12, 0xb0);
@@ -196,6 +198,7 @@ static void init_functions(void) #define X(f) if (!(p##f = (void*)GetProcAddress(mod, #f))) return; X(MFCreateSourceResolver); X(MFCreateMFByteStreamOnStream); + X(MFCreateMemoryBuffer); #undef X }
@@ -274,6 +277,92 @@ static void test_MFCreateMFByteStreamOnStream(void) IMFByteStream_Release(bytestream); }
+static void test_MFCreateMemoryBuffer(void) +{ + IMFMediaBuffer *buffer; + HRESULT hr; + DWORD length, max; + BYTE *data, *data2; + + if(!pMFCreateMemoryBuffer) + { + win_skip("MFCreateMemoryBuffer() not found\n"); + return; + } + + hr = pMFCreateMemoryBuffer(1024, NULL); + ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr); + + hr = pMFCreateMemoryBuffer(0, &buffer); + ok(hr == S_OK, "got 0x%08x\n", hr); + if(buffer) + { + hr = IMFMediaBuffer_GetMaxLength(buffer, &length); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(length == 0, "got %u\n", length); + + IMFMediaBuffer_Release(buffer); + } + + hr = pMFCreateMemoryBuffer(1024, &buffer); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_GetMaxLength(buffer, NULL); + ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_GetMaxLength(buffer, &length); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(length == 1024, "got %u\n", length); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, 1025); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, 10); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_GetCurrentLength(buffer, NULL); + ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_GetCurrentLength(buffer, &length); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(length == 10, "got %u\n", length); + + length = 0; + max = 0; + hr = IMFMediaBuffer_Lock(buffer, NULL, &length, &max); + ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr); + ok(length == 0, "got %u\n", length); + ok(max == 0, "got %u\n", length); + + hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(length == 10, "got %u\n", length); + ok(max == 1024, "got %u\n", max); + + /* Attempt to lock the bufer twice */ + hr = IMFMediaBuffer_Lock(buffer, &data2, &max, &length); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(data == data2, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "got 0x%08x\n", hr); + + /* Extra Unlock */ + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "got 0x%08x\n", hr); + + IMFMediaBuffer_Release(buffer); +} + START_TEST(mfplat) { CoInitialize(NULL); @@ -285,6 +374,7 @@ START_TEST(mfplat) test_MFCreateMediaType(); test_MFCreateAttributes(); test_MFCreateMFByteStreamOnStream(); + test_MFCreateMemoryBuffer();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 890d7bd..5b98187 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -67,6 +67,7 @@ HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key); HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size); HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue); HRESULT WINAPI MFCreateMediaType(IMFMediaType **type); +HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer); HRESULT WINAPI MFGetTimerPeriodicity(DWORD *periodicity); HRESULT WINAPI MFTEnum(GUID category, UINT32 flags, MFT_REGISTER_TYPE_INFO *input_type, MFT_REGISTER_TYPE_INFO *output_type, IMFAttributes *attributes,
On 09/07/2018 03:58 AM, Alistair Leslie-Hughes wrote:
+static HRESULT WINAPI mfbuffer_Lock(IMFMediaBuffer *iface, BYTE **buffer, DWORD *max, DWORD *current) +{
- mfbuffer *This = impl_from_IMFMediaBuffer(iface);
- TRACE("%p, %p %p, %p\n", This, buffer, max, current);
- if(!buffer)
return E_INVALIDARG;
- *buffer = This->buffer;
- if(max)
*max = This->max_length;
- if(current)
*current = This->current;
- return S_OK;
+}
This doesn't lock anything. How did you test this?
Hi Nikolay,
On 07/09/18 14:00, Nikolay Sivov wrote:
On 09/07/2018 03:58 AM, Alistair Leslie-Hughes wrote:
+static HRESULT WINAPI mfbuffer_Lock(IMFMediaBuffer *iface, BYTE **buffer, DWORD *max, DWORD *current) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface);
+ TRACE("%p, %p %p, %p\n", This, buffer, max, current);
+ if(!buffer) + return E_INVALIDARG;
+ *buffer = This->buffer; + if(max) + *max = This->max_length; + if(current) + *current = This->current;
+ return S_OK; +}
This doesn't lock anything. How did you test this?
Only with the tests written.
When attempting to lock the buffer twice doesn't result return an error and in fact returns the same buffer pointer.
The msdn reference, also suggests that locking the buffer really isn't a lock in the traditional sense, and allows multiple threads to change the data without error.
https://docs.microsoft.com/en-us/windows/desktop/api/mfobjects/nf-mfobjects-... "Locking the buffer does not prevent other threads from calling Lock, so you should not rely on this method to synchronize threads."
Regards Alistair
On 09/07/2018 10:51 AM, Alistair Leslie-Hughes wrote:
Hi Nikolay,
On 07/09/18 14:00, Nikolay Sivov wrote:
On 09/07/2018 03:58 AM, Alistair Leslie-Hughes wrote:
+static HRESULT WINAPI mfbuffer_Lock(IMFMediaBuffer *iface, BYTE **buffer, DWORD *max, DWORD *current) +{ + mfbuffer *This = impl_from_IMFMediaBuffer(iface);
+ TRACE("%p, %p %p, %p\n", This, buffer, max, current);
+ if(!buffer) + return E_INVALIDARG;
+ *buffer = This->buffer; + if(max) + *max = This->max_length; + if(current) + *current = This->current;
+ return S_OK; +}
This doesn't lock anything. How did you test this?
Only with the tests written.
When attempting to lock the buffer twice doesn't result return an error and in fact returns the same buffer pointer.
The msdn reference, also suggests that locking the buffer really isn't a lock in the traditional sense, and allows multiple threads to change the data without error.
https://docs.microsoft.com/en-us/windows/desktop/api/mfobjects/nf-mfobjects-... "Locking the buffer does not prevent other threads from calling Lock, so you should not rely on this method to synchronize threads."
Ok, but does Lock -> Unlock -> Lock return same pointer second time? This could be a useful test to add later.
Regards Alistair