mfplat: Implement MFCreateDXSurfaceBuffer().

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2020-10-30 16:50:41 +03:00 committed by Alexandre Julliard
parent 74ea8d8c42
commit 23a656a083
3 changed files with 319 additions and 1 deletions

View File

@ -21,6 +21,10 @@
#include "mfplat_private.h"
#include "rtworkq.h"
#include "initguid.h"
#include "d3d9.h"
#include "evr.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@ -50,6 +54,11 @@ struct memory_buffer
unsigned int locks;
} _2d;
struct
{
IDirect3DSurface9 *surface;
D3DLOCKED_RECT rect;
} d3d9_surface;
CRITICAL_SECTION cs;
};
@ -142,6 +151,8 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface)
if (!refcount)
{
if (buffer->d3d9_surface.surface)
IDirect3DSurface9_Release(buffer->d3d9_surface.surface);
DeleteCriticalSection(&buffer->cs);
heap_free(buffer->_2d.linear_buffer);
heap_free(buffer->data);
@ -333,6 +344,97 @@ static const IMFMediaBufferVtbl memory_1d_2d_buffer_vtbl =
memory_buffer_GetMaxLength,
};
static HRESULT WINAPI d3d9_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length)
{
struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface);
HRESULT hr = S_OK;
TRACE("%p, %p, %p, %p.\n", iface, data, max_length, current_length);
if (!data)
return E_POINTER;
EnterCriticalSection(&buffer->cs);
if (!buffer->_2d.linear_buffer && buffer->_2d.locks)
hr = MF_E_INVALIDREQUEST;
else if (!buffer->_2d.linear_buffer)
{
D3DLOCKED_RECT rect;
if (!(buffer->_2d.linear_buffer = heap_alloc(ALIGN_SIZE(buffer->_2d.plane_size, MF_64_BYTE_ALIGNMENT))))
hr = E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0);
if (SUCCEEDED(hr))
{
MFCopyImage(buffer->_2d.linear_buffer, buffer->_2d.width, rect.pBits, rect.Pitch,
buffer->_2d.width, buffer->_2d.height);
IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
}
}
}
if (SUCCEEDED(hr))
{
++buffer->_2d.locks;
*data = buffer->_2d.linear_buffer;
if (max_length)
*max_length = buffer->_2d.plane_size;
if (current_length)
*current_length = buffer->_2d.plane_size;
}
LeaveCriticalSection(&buffer->cs);
return hr;
}
static HRESULT WINAPI d3d9_surface_buffer_Unlock(IMFMediaBuffer *iface)
{
struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface);
HRESULT hr = S_OK;
TRACE("%p.\n", iface);
EnterCriticalSection(&buffer->cs);
if (!buffer->_2d.linear_buffer)
hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
else if (!--buffer->_2d.locks)
{
D3DLOCKED_RECT rect;
if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0)))
{
MFCopyImage(rect.pBits, rect.Pitch, buffer->_2d.linear_buffer, buffer->_2d.width,
buffer->_2d.width, buffer->_2d.height);
IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
}
heap_free(buffer->_2d.linear_buffer);
buffer->_2d.linear_buffer = NULL;
}
LeaveCriticalSection(&buffer->cs);
return hr;
}
static const IMFMediaBufferVtbl d3d9_surface_1d_buffer_vtbl =
{
memory_1d_2d_buffer_QueryInterface,
memory_buffer_AddRef,
memory_buffer_Release,
d3d9_surface_buffer_Lock,
d3d9_surface_buffer_Unlock,
memory_buffer_GetCurrentLength,
memory_buffer_SetCurrentLength,
memory_buffer_GetMaxLength,
};
static HRESULT WINAPI memory_2d_buffer_QueryInterface(IMF2DBuffer2 *iface, REFIID riid, void **obj)
{
struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
@ -521,6 +623,144 @@ static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl =
memory_2d_buffer_Copy2DTo,
};
static HRESULT WINAPI d3d9_surface_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
{
struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
HRESULT hr = S_OK;
TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
if (!scanline0 || !pitch)
return E_POINTER;
EnterCriticalSection(&buffer->cs);
if (buffer->_2d.linear_buffer)
hr = MF_E_UNEXPECTED;
else if (!buffer->_2d.locks++)
{
hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0);
}
if (SUCCEEDED(hr))
{
*scanline0 = buffer->d3d9_surface.rect.pBits;
*pitch = buffer->d3d9_surface.rect.Pitch;
}
LeaveCriticalSection(&buffer->cs);
return hr;
}
static HRESULT WINAPI d3d9_surface_buffer_Unlock2D(IMF2DBuffer2 *iface)
{
struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
HRESULT hr = S_OK;
TRACE("%p.\n", iface);
EnterCriticalSection(&buffer->cs);
if (buffer->_2d.locks)
{
if (!--buffer->_2d.locks)
{
IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
memset(&buffer->d3d9_surface.rect, 0, sizeof(buffer->d3d9_surface.rect));
}
}
else
hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
LeaveCriticalSection(&buffer->cs);
return hr;
}
static HRESULT WINAPI d3d9_surface_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
{
struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
HRESULT hr = S_OK;
TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
if (!scanline0 || !pitch)
return E_POINTER;
EnterCriticalSection(&buffer->cs);
if (!buffer->_2d.locks)
hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
else
{
*scanline0 = buffer->d3d9_surface.rect.pBits;
*pitch = buffer->d3d9_surface.rect.Pitch;
}
LeaveCriticalSection(&buffer->cs);
return hr;
}
static HRESULT WINAPI d3d9_surface_buffer_GetContiguousLength(IMF2DBuffer2 *iface, DWORD *length)
{
FIXME("%p, %p.\n", iface, length);
return E_NOTIMPL;
}
static HRESULT WINAPI d3d9_surface_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0,
LONG *pitch, BYTE **buffer_start, DWORD *buffer_length)
{
struct memory_buffer *buffer = impl_from_IMF2DBuffer2(iface);
HRESULT hr = S_OK;
TRACE("%p, %#x, %p, %p, %p, %p.\n", iface, flags, scanline0, pitch, buffer_start, buffer_length);
if (!scanline0 || !pitch || !buffer_start || !buffer_length)
return E_POINTER;
EnterCriticalSection(&buffer->cs);
if (buffer->_2d.linear_buffer)
hr = MF_E_UNEXPECTED;
else if (!buffer->_2d.locks++)
{
hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0);
}
if (SUCCEEDED(hr))
{
*scanline0 = buffer->d3d9_surface.rect.pBits;
*pitch = buffer->d3d9_surface.rect.Pitch;
if (buffer_start)
*buffer_start = *scanline0;
if (buffer_length)
*buffer_length = buffer->d3d9_surface.rect.Pitch * buffer->_2d.height;
}
LeaveCriticalSection(&buffer->cs);
return hr;
}
static const IMF2DBuffer2Vtbl d3d9_surface_buffer_vtbl =
{
memory_2d_buffer_QueryInterface,
memory_2d_buffer_AddRef,
memory_2d_buffer_Release,
d3d9_surface_buffer_Lock2D,
d3d9_surface_buffer_Unlock2D,
d3d9_surface_buffer_GetScanline0AndPitch,
memory_2d_buffer_IsContiguousFormat,
d3d9_surface_buffer_GetContiguousLength,
memory_2d_buffer_ContiguousCopyTo,
memory_2d_buffer_ContiguousCopyFrom,
d3d9_surface_buffer_Lock2DSize,
memory_2d_buffer_Copy2DTo,
};
static HRESULT WINAPI memory_2d_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
{
struct memory_buffer *buffer = impl_from_IMFGetService(iface);
@ -554,6 +794,28 @@ static const IMFGetServiceVtbl memory_2d_buffer_gs_vtbl =
memory_2d_buffer_gs_GetService,
};
static HRESULT WINAPI d3d9_surface_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
{
struct memory_buffer *buffer = impl_from_IMFGetService(iface);
TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
if (IsEqualGUID(service, &MR_BUFFER_SERVICE))
{
return IDirect3DSurface9_QueryInterface(buffer->d3d9_surface.surface, riid, obj);
}
return E_NOTIMPL;
}
static const IMFGetServiceVtbl d3d9_surface_buffer_gs_vtbl =
{
memory_2d_buffer_gs_QueryInterface,
memory_2d_buffer_gs_AddRef,
memory_2d_buffer_gs_Release,
d3d9_surface_buffer_gs_GetService,
};
static HRESULT memory_buffer_init(struct memory_buffer *buffer, DWORD max_length, DWORD alignment,
const IMFMediaBufferVtbl *vtbl)
{
@ -675,6 +937,36 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo
return S_OK;
}
static HRESULT create_d3d9_surface_buffer(IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer)
{
struct memory_buffer *object;
D3DSURFACE_DESC desc;
object = heap_alloc_zero(sizeof(*object));
if (!object)
return E_OUTOFMEMORY;
object->IMFMediaBuffer_iface.lpVtbl = &d3d9_surface_1d_buffer_vtbl;
object->IMF2DBuffer2_iface.lpVtbl = &d3d9_surface_buffer_vtbl;
object->IMFGetService_iface.lpVtbl = &d3d9_surface_buffer_gs_vtbl;
object->refcount = 1;
InitializeCriticalSection(&object->cs);
object->d3d9_surface.surface = (IDirect3DSurface9 *)surface;
IUnknown_AddRef(surface);
IDirect3DSurface9_GetDesc(object->d3d9_surface.surface, &desc);
TRACE("format %#x, %u x %u.\n", desc.Format, desc.Width, desc.Height);
MFGetPlaneSize(desc.Format, desc.Width, desc.Height, &object->_2d.plane_size);
object->_2d.width = desc.Width;
object->_2d.height = desc.Height;
object->max_length = object->_2d.plane_size;
*buffer = &object->IMFMediaBuffer_iface;
return S_OK;
}
/***********************************************************************
* MFCreateMemoryBuffer (mfplat.@)
*/
@ -695,6 +987,9 @@ HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IM
return create_1d_buffer(max_length, alignment, buffer);
}
/***********************************************************************
* MFCreate2DMediaBuffer (mfplat.@)
*/
HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer)
{
TRACE("%u, %u, %s, %d, %p.\n", width, height, debugstr_fourcc(fourcc), bottom_up, buffer);
@ -702,6 +997,19 @@ HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BO
return create_2d_buffer(width, height, fourcc, bottom_up, buffer);
}
/***********************************************************************
* MFCreateDXSurfaceBuffer (mfplat.@)
*/
HRESULT WINAPI MFCreateDXSurfaceBuffer(REFIID riid, IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer)
{
TRACE("%s, %p, %d, %p.\n", debugstr_guid(riid), surface, bottom_up, buffer);
if (!IsEqualIID(riid, &IID_IDirect3DSurface9))
return E_INVALIDARG;
return create_d3d9_surface_buffer(surface, bottom_up, buffer);
}
static unsigned int buffer_get_aligned_length(unsigned int length, unsigned int alignment)
{
length = (length + alignment) / alignment;

View File

@ -46,6 +46,7 @@
@ stub MFCreateAudioMediaType
@ stdcall MFCreateCollection(ptr)
@ stdcall MFCreateDXGIDeviceManager(ptr ptr)
@ stdcall MFCreateDXSurfaceBuffer(ptr ptr long ptr)
@ stdcall MFCreateEventQueue(ptr)
@ stdcall MFCreateFile(long long long wstr ptr)
@ stub MFCreateLegacyMediaBufferOnMFMediaBuffer

View File

@ -5649,7 +5649,7 @@ static void test_MFCreateDXSurfaceBuffer(void)
if (!pMFCreateDXSurfaceBuffer)
{
skip("MFCreateDXSurfaceBuffer is not available.\n");
win_skip("MFCreateDXSurfaceBuffer is not available.\n");
return;
}
@ -5671,6 +5671,9 @@ static void test_MFCreateDXSurfaceBuffer(void)
IDirect3DSwapChain9_Release(swapchain);
hr = pMFCreateDXSurfaceBuffer(&IID_IUnknown, (IUnknown *)backbuffer, FALSE, &buffer);
ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
hr = pMFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)backbuffer, FALSE, &buffer);
ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
@ -5764,6 +5767,12 @@ static void test_MFCreateDXSurfaceBuffer(void)
ok(data[0] == 0xab, "Unexpected leading byte.\n");
IMF2DBuffer2_Unlock2D(_2dbuffer2);
hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(data[0] == 0xab, "Unexpected leading byte.\n");
hr = IMFMediaBuffer_Unlock(buffer);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IMF2DBuffer2_Unlock2D(_2dbuffer2);