diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c index 5427833a2c3..668e675da2b 100644 --- a/dlls/evr/sample.c +++ b/dlls/evr/sample.c @@ -48,6 +48,16 @@ static const char *debugstr_time(LONGLONG time) return wine_dbg_sprintf("%s", rev); } +struct surface_buffer +{ + IMFMediaBuffer IMFMediaBuffer_iface; + IMFGetService IMFGetService_iface; + LONG refcount; + + IUnknown *surface; + ULONG length; +}; + struct video_sample { IMFSample IMFSample_iface; @@ -80,6 +90,16 @@ static struct video_sample *impl_from_IMFDesiredSample(IMFDesiredSample *iface) return CONTAINING_RECORD(iface, struct video_sample, IMFDesiredSample_iface); } +static struct surface_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct surface_buffer, IMFMediaBuffer_iface); +} + +static struct surface_buffer *impl_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct surface_buffer, IMFGetService_iface); +} + struct sample_allocator { IMFVideoSampleAllocator IMFVideoSampleAllocator_iface; @@ -929,16 +949,171 @@ static const IMFDesiredSampleVtbl desired_video_sample_vtbl = desired_video_sample_Clear, }; +static HRESULT WINAPI surface_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **obj) +{ + struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFMediaBuffer) || IsEqualIID(riid, &IID_IUnknown)) + { + *obj = &buffer->IMFMediaBuffer_iface; + } + else if (IsEqualIID(riid, &IID_IMFGetService)) + { + *obj = &buffer->IMFGetService_iface; + } + else + { + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI surface_buffer_AddRef(IMFMediaBuffer *iface) +{ + struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface); + ULONG refcount = InterlockedIncrement(&buffer->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI surface_buffer_Release(IMFMediaBuffer *iface) +{ + struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface); + ULONG refcount = InterlockedDecrement(&buffer->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + IUnknown_Release(buffer->surface); + heap_free(buffer); + } + + return refcount; +} + +static HRESULT WINAPI surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *maxlength, DWORD *length) +{ + TRACE("%p, %p, %p, %p.\n", iface, data, maxlength, length); + + return E_NOTIMPL; +} + +static HRESULT WINAPI surface_buffer_Unlock(IMFMediaBuffer *iface) +{ + TRACE("%p.\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI surface_buffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *length) +{ + struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p.\n", iface); + + *length = buffer->length; + + return S_OK; +} + +static HRESULT WINAPI surface_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD length) +{ + struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p.\n", iface); + + buffer->length = length; + + return S_OK; +} + +static HRESULT WINAPI surface_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *length) +{ + TRACE("%p.\n", iface); + + return E_NOTIMPL; +} + +static const IMFMediaBufferVtbl surface_buffer_vtbl = +{ + surface_buffer_QueryInterface, + surface_buffer_AddRef, + surface_buffer_Release, + surface_buffer_Lock, + surface_buffer_Unlock, + surface_buffer_GetCurrentLength, + surface_buffer_SetCurrentLength, + surface_buffer_GetMaxLength, +}; + +static HRESULT WINAPI surface_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct surface_buffer *buffer = impl_from_IMFGetService(iface); + return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj); +} + +static ULONG WINAPI surface_buffer_gs_AddRef(IMFGetService *iface) +{ + struct surface_buffer *buffer = impl_from_IMFGetService(iface); + return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface); +} + +static ULONG WINAPI surface_buffer_gs_Release(IMFGetService *iface) +{ + struct surface_buffer *buffer = impl_from_IMFGetService(iface); + return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface); +} + +static HRESULT WINAPI surface_buffer_gs_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 surface_buffer_gs_vtbl = +{ + surface_buffer_gs_QueryInterface, + surface_buffer_gs_AddRef, + surface_buffer_gs_Release, + surface_buffer_gs_GetService, +}; + +static HRESULT create_surface_buffer(IUnknown *surface, IMFMediaBuffer **buffer) +{ + struct surface_buffer *object; + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFMediaBuffer_iface.lpVtbl = &surface_buffer_vtbl; + object->IMFGetService_iface.lpVtbl = &surface_buffer_gs_vtbl; + object->refcount = 1; + object->surface = surface; + IUnknown_AddRef(object->surface); + + *buffer = &object->IMFMediaBuffer_iface; + + return S_OK; +} + HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *surface, IMFSample **sample) { struct video_sample *object; + IMFMediaBuffer *buffer = NULL; HRESULT hr; TRACE("%p, %p.\n", surface, sample); - if (surface) - FIXME("Create surface buffer.\n"); - if (!(object = heap_alloc_zero(sizeof(*object)))) return E_OUTOFMEMORY; @@ -953,6 +1128,15 @@ HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *surface, IMFSample **sam return hr; } + if (surface && FAILED(hr = create_surface_buffer(surface, &buffer))) + { + IMFSample_Release(&object->IMFSample_iface); + return hr; + } + + if (buffer) + IMFSample_AddBuffer(object->sample, buffer); + *sample = &object->IMFSample_iface; return S_OK; diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index b924ac2d9b9..69ee2d3d967 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -750,6 +750,10 @@ static void test_surface_sample(void) IDirect3DSwapChain9_Release(swapchain); + hr = MFCreateVideoSampleFromSurface(NULL, &sample); + ok(hr == S_OK, "Failed to create surface sample, hr %#x.\n", hr); + IMFSample_Release(sample); + hr = MFCreateVideoSampleFromSurface((IUnknown *)backbuffer, &sample); ok(hr == S_OK, "Failed to create surface sample, hr %#x.\n", hr); @@ -808,7 +812,6 @@ static void test_surface_sample(void) count = 0; hr = IMFSample_GetBufferCount(sample, &count); ok(hr == S_OK, "Failed to get buffer count, hr %#x.\n", hr); -todo_wine ok(count == 1, "Unexpected attribute count.\n"); hr = IMFSample_GetTotalLength(sample, &length); @@ -822,11 +825,8 @@ todo_wine ok(hr == MF_E_NO_SAMPLE_TIMESTAMP, "Unexpected hr %#x.\n", hr); hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr); -if (SUCCEEDED(hr)) -{ hr = IMFMediaBuffer_GetMaxLength(buffer, &length); ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); @@ -834,9 +834,19 @@ if (SUCCEEDED(hr)) ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr); ok(!length, "Unexpected length %u.\n", length); + hr = IMFMediaBuffer_SetCurrentLength(buffer, 16); + ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr); + + hr = IMFMediaBuffer_GetCurrentLength(buffer, &length); + ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr); + ok(length == 16, "Unexpected length %u.\n", length); + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&unk); ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); @@ -861,7 +871,7 @@ if (SUCCEEDED(hr)) ok(!count, "Unexpected attribute count.\n"); IMFMediaBuffer_Release(buffer); -} + hr = IMFSample_GetSampleFlags(sample, &flags); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);