Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/Makefile.in | 1 + dlls/mfplat/buffer.c | 216 +++++++++++++++++++++++++++++++++++++ dlls/mfplat/main.c | 174 ------------------------------ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 52 ++++++--- include/mfapi.h | 16 +++ 6 files changed, 273 insertions(+), 188 deletions(-) create mode 100644 dlls/mfplat/buffer.c
diff --git a/dlls/mfplat/Makefile.in b/dlls/mfplat/Makefile.in index 261c121cab..a117ede271 100644 --- a/dlls/mfplat/Makefile.in +++ b/dlls/mfplat/Makefile.in @@ -3,6 +3,7 @@ IMPORTLIB = mfplat IMPORTS = advapi32 ole32
C_SRCS = \ + buffer.c \ main.c \ mediatype.c \ queue.c diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c new file mode 100644 index 0000000000..e206b356dc --- /dev/null +++ b/dlls/mfplat/buffer.c @@ -0,0 +1,216 @@ +/* + * Copyright 2018 Alistair Leslie-Hughes + * + * 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 + */ + +#define COBJMACROS + +#include "mfplat_private.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct memory_buffer +{ + IMFMediaBuffer IMFMediaBuffer_iface; + LONG refcount; + + BYTE *data; + DWORD max_length; + DWORD current_length; +}; + +static inline struct memory_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct memory_buffer, IMFMediaBuffer_iface); +} + +static HRESULT WINAPI memory_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFMediaBuffer) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &buffer->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 memory_buffer_AddRef(IMFMediaBuffer *iface) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + ULONG refcount = InterlockedIncrement(&buffer->refcount); + + TRACE("%p, refcount %u.\n", buffer, refcount); + + return refcount; +} + +static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + ULONG refcount = InterlockedDecrement(&buffer->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + heap_free(buffer->data); + heap_free(buffer); + } + + return refcount; +} + +static HRESULT WINAPI memory_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %p %p, %p.\n", iface, data, max_length, current_length); + + if (!data) + return E_INVALIDARG; + + *data = buffer->data; + if (max_length) + *max_length = buffer->max_length; + if (current_length) + *current_length = buffer->current_length; + + return S_OK; +} + +static HRESULT WINAPI memory_buffer_Unlock(IMFMediaBuffer *iface) +{ + TRACE("%p.\n", iface); + + return S_OK; +} + +static HRESULT WINAPI memory_buffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *current_length) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p.\n", iface); + + if (!current_length) + return E_INVALIDARG; + + *current_length = buffer->current_length; + + return S_OK; +} + +static HRESULT WINAPI memory_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD current_length) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %u.\n", iface, current_length); + + if (current_length > buffer->max_length) + return E_INVALIDARG; + + buffer->current_length = current_length; + + return S_OK; +} + +static HRESULT WINAPI memory_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *max_length) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %p.\n", iface, max_length); + + if (!max_length) + return E_INVALIDARG; + + *max_length = buffer->max_length; + + return S_OK; +} + +static const IMFMediaBufferVtbl memorybuffervtbl = +{ + memory_buffer_QueryInterface, + memory_buffer_AddRef, + memory_buffer_Release, + memory_buffer_Lock, + memory_buffer_Unlock, + memory_buffer_GetCurrentLength, + memory_buffer_SetCurrentLength, + memory_buffer_GetMaxLength, +}; + +static HRESULT create_memory_buffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer) +{ + struct memory_buffer *object; + + if (!buffer) + return E_INVALIDARG; + + object = heap_alloc(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->data = heap_alloc((max_length + alignment) & ~alignment); + if (!object->data) + { + heap_free(object); + return E_OUTOFMEMORY; + } + + object->IMFMediaBuffer_iface.lpVtbl = &memorybuffervtbl; + object->refcount = 1; + object->max_length = max_length; + object->current_length = 0; + + *buffer = &object->IMFMediaBuffer_iface; + + return S_OK; +} + +/*********************************************************************** + * MFCreateMemoryBuffer (mfplat.@) + */ +HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer) +{ + TRACE("%u, %p.\n", max_length, buffer); + + return create_memory_buffer(max_length, MF_1_BYTE_ALIGNMENT, buffer); +} + +/*********************************************************************** + * MFCreateAlignedMemoryBuffer (mfplat.@) + */ +HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer) +{ + TRACE("%u, %u, %p.\n", max_length, alignment, buffer); + + return create_memory_buffer(max_length, alignment, buffer); +} diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 2217f3fb94..57943cf115 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -2798,180 +2798,6 @@ HRESULT WINAPI MFCreateEventQueue(IMFMediaEventQueue **queue) 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; -}
typedef struct _mfsample { diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 741dfafad3..900efc3780 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -37,7 +37,7 @@ @ stub MFConvertToFP16Array @ stdcall MFCopyImage(ptr long ptr long long long) @ stub MFCreateAMMediaTypeFromMFMediaType -@ stub MFCreateAlignedMemoryBuffer +@ stdcall MFCreateAlignedMemoryBuffer(long long ptr) @ stdcall MFCreateAsyncResult(ptr ptr ptr ptr) @ stdcall MFCreateAttributes(ptr long) @ stub MFCreateAudioMediaType diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index aa4104d9ed..674bcf418e 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -42,7 +42,6 @@ static HRESULT (WINAPI *pMFCopyImage)(BYTE *dest, LONG deststride, const BYTE *s DWORD width, DWORD lines); static HRESULT (WINAPI *pMFCreateSourceResolver)(IMFSourceResolver **resolver); static HRESULT (WINAPI *pMFCreateMFByteStreamOnStream)(IStream *stream, IMFByteStream **bytestream); -static HRESULT (WINAPI *pMFCreateMemoryBuffer)(DWORD max_length, IMFMediaBuffer **buffer); static void* (WINAPI *pMFHeapAlloc)(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type); static void (WINAPI *pMFHeapFree)(void *p); static HRESULT (WINAPI *pMFPutWaitingWorkItem)(HANDLE event, LONG priority, IMFAsyncResult *result, MFWORKITEM_KEY *key); @@ -323,7 +322,6 @@ static void init_functions(void) X(MFCopyImage); X(MFCreateSourceResolver); X(MFCreateMFByteStreamOnStream); - X(MFCreateMemoryBuffer); X(MFHeapAlloc); X(MFHeapFree); X(MFPutWaitingWorkItem); @@ -602,23 +600,17 @@ static void test_MFCreateFile(void) DeleteFileW(newfilename); }
-static void test_MFCreateMemoryBuffer(void) +static void test_system_memory_buffer(void) { IMFMediaBuffer *buffer; HRESULT hr; DWORD length, max; BYTE *data, *data2;
- if(!pMFCreateMemoryBuffer) - { - win_skip("MFCreateMemoryBuffer() not found\n"); - return; - } - - hr = pMFCreateMemoryBuffer(1024, NULL); + hr = MFCreateMemoryBuffer(1024, NULL); ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr);
- hr = pMFCreateMemoryBuffer(0, &buffer); + hr = MFCreateMemoryBuffer(0, &buffer); ok(hr == S_OK, "got 0x%08x\n", hr); if(buffer) { @@ -629,7 +621,7 @@ static void test_MFCreateMemoryBuffer(void) IMFMediaBuffer_Release(buffer); }
- hr = pMFCreateMemoryBuffer(1024, &buffer); + hr = MFCreateMemoryBuffer(1024, &buffer); ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IMFMediaBuffer_GetMaxLength(buffer, NULL); @@ -686,6 +678,40 @@ static void test_MFCreateMemoryBuffer(void) ok(hr == S_OK, "got 0x%08x\n", hr);
IMFMediaBuffer_Release(buffer); + + /* Aligned buffer. */ + hr = MFCreateAlignedMemoryBuffer(201, MF_8_BYTE_ALIGNMENT, &buffer); + ok(hr == S_OK, "Failed to create memory buffer, hr %#x.\n", hr); + + hr = IMFMediaBuffer_GetCurrentLength(buffer, &length); + ok(hr == S_OK, "Failed to get current length, hr %#x.\n", hr); + ok(length == 0, "Unexpected current length %u.\n", length); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, 1); + ok(hr == S_OK, "Failed to set current length, hr %#x.\n", hr); + hr = IMFMediaBuffer_GetCurrentLength(buffer, &length); + ok(hr == S_OK, "Failed to get current length, hr %#x.\n", hr); + ok(length == 1, "Unexpected current length %u.\n", length); + + hr = IMFMediaBuffer_GetMaxLength(buffer, &length); + ok(hr == S_OK, "Failed to get max length, hr %#x.\n", hr); + ok(length == 201, "Unexpected max length %u.\n", length); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, 202); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + hr = IMFMediaBuffer_GetMaxLength(buffer, &length); + ok(hr == S_OK, "Failed to get max length, hr %#x.\n", hr); + ok(length == 201, "Unexpected max length %u.\n", length); + hr = IMFMediaBuffer_SetCurrentLength(buffer, 10); + ok(hr == S_OK, "Failed to set current length, hr %#x.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &data, &max, &length); + ok(hr == S_OK, "Failed to lock, hr %#x.\n", hr); + ok(max == 201 && length == 10, "Unexpected length.\n"); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock, hr %#x.\n", hr); + + IMFMediaBuffer_Release(buffer); }
static void test_MFSample(void) @@ -1518,7 +1544,7 @@ START_TEST(mfplat) test_MFSample(); test_MFCreateFile(); test_MFCreateMFByteStreamOnStream(); - test_MFCreateMemoryBuffer(); + test_system_memory_buffer(); test_source_resolver(); test_MFCreateAsyncResult(); test_allocate_queue(); diff --git a/include/mfapi.h b/include/mfapi.h index 4560d5dee7..4062e2fd13 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -97,11 +97,27 @@ typedef enum
typedef void (CALLBACK *MFPERIODICCALLBACK)(IUnknown *context);
+#define MF_1_BYTE_ALIGNMENT 0x00000000 +#define MF_2_BYTE_ALIGNMENT 0x00000001 +#define MF_4_BYTE_ALIGNMENT 0x00000003 +#define MF_8_BYTE_ALIGNMENT 0x00000007 +#define MF_16_BYTE_ALIGNMENT 0x0000000f +#define MF_32_BYTE_ALIGNMENT 0x0000001f +#define MF_64_BYTE_ALIGNMENT 0x0000003f +#define MF_128_BYTE_ALIGNMENT 0x0000007f +#define MF_256_BYTE_ALIGNMENT 0x000000ff +#define MF_512_BYTE_ALIGNMENT 0x000001ff +#define MF_1024_BYTE_ALIGNMENT 0x000003ff +#define MF_2048_BYTE_ALIGNMENT 0x000007ff +#define MF_4096_BYTE_ALIGNMENT 0x00000fff +#define MF_8192_BYTE_ALIGNMENT 0x00001fff + HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key); HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue); HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue); HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key); HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines); +HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer); HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size); HRESULT WINAPI MFCreateAsyncResult(IUnknown *object, IMFAsyncCallback *callback, IUnknown *state, IMFAsyncResult **result); HRESULT WINAPI MFCreateCollection(IMFCollection **collection);