/* * 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); }