From 365bbe8343f1f5461c4f2afe2d90be4007818878 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 10 Jun 2008 18:06:08 +0200 Subject: [PATCH] quartz: Expose some methods so that a custom allocator can be created. --- dlls/quartz/memallocator.c | 152 ++++++++++++++++------------------- dlls/quartz/quartz_private.h | 46 +++++++++++ 2 files changed, 116 insertions(+), 82 deletions(-) diff --git a/dlls/quartz/memallocator.c b/dlls/quartz/memallocator.c index 12effbb1fb9..d4539aae950 100644 --- a/dlls/quartz/memallocator.c +++ b/dlls/quartz/memallocator.c @@ -27,7 +27,6 @@ #include "vfwmsgs.h" #include "quartz_private.h" -#include "wine/list.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(quartz); @@ -51,35 +50,6 @@ void dump_AM_SAMPLE2_PROPERTIES(const AM_SAMPLE2_PROPERTIES * pProps) TRACE("\tcbBuffer: %d\n", pProps->cbBuffer); } -typedef struct BaseMemAllocator -{ - const IMemAllocatorVtbl * lpVtbl; - - LONG ref; - ALLOCATOR_PROPERTIES * pProps; - CRITICAL_SECTION csState; - HRESULT (* fnAlloc) (IMemAllocator *); - HRESULT (* fnFree)(IMemAllocator *); - HANDLE hSemWaiting; - BOOL bDecommitQueued; - BOOL bCommitted; - LONG lWaiting; - struct list free_list; - struct list used_list; -} BaseMemAllocator; - -typedef struct StdMediaSample2 -{ - const IMediaSample2Vtbl * lpvtbl; - - LONG ref; - AM_SAMPLE2_PROPERTIES props; - IMemAllocator * pParent; - struct list listentry; - LONGLONG tMediaStart; - LONGLONG tMediaEnd; -} StdMediaSample2; - static const IMemAllocatorVtbl BaseMemAllocator_VTable; static const IMediaSample2Vtbl StdMediaSample2_VTable; @@ -87,25 +57,34 @@ static const IMediaSample2Vtbl StdMediaSample2_VTable; #define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff) -static HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), HRESULT (* fnFree)(IMemAllocator *), BaseMemAllocator * pMemAlloc) +HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), + HRESULT (* fnFree)(IMemAllocator *), + HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *), + HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD), + HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *), + void (* fnDestroyed)(IMemAllocator *), + CRITICAL_SECTION *pCritSect, + BaseMemAllocator * pMemAlloc) { - assert(fnAlloc && fnFree); + assert(fnAlloc && fnFree && fnDestroyed); pMemAlloc->lpVtbl = &BaseMemAllocator_VTable; pMemAlloc->ref = 1; - pMemAlloc->pProps = NULL; + ZeroMemory(&pMemAlloc->props, sizeof(pMemAlloc->props)); list_init(&pMemAlloc->free_list); list_init(&pMemAlloc->used_list); pMemAlloc->fnAlloc = fnAlloc; pMemAlloc->fnFree = fnFree; + pMemAlloc->fnVerify = fnVerify; + pMemAlloc->fnBufferPrepare = fnBufferPrepare; + pMemAlloc->fnBufferReleased = fnBufferReleased; + pMemAlloc->fnDestroyed = fnDestroyed; pMemAlloc->bDecommitQueued = FALSE; pMemAlloc->bCommitted = FALSE; pMemAlloc->hSemWaiting = NULL; pMemAlloc->lWaiting = 0; - - InitializeCriticalSection(&pMemAlloc->csState); - pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BaseMemAllocator.csState"); + pMemAlloc->pCritSect = pCritSect; return S_OK; } @@ -155,10 +134,8 @@ static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface) CloseHandle(This->hSemWaiting); if (This->bCommitted) This->fnFree(iface); - CoTaskMemFree(This->pProps); - This->csState.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->csState); - CoTaskMemFree(This); + + This->fnDestroyed(iface); return 0; } return ref; @@ -171,7 +148,7 @@ static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLO TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual); - EnterCriticalSection(&This->csState); + EnterCriticalSection(This->pCritSect); { if (!list_empty(&This->used_list)) hr = VFW_E_BUFFERS_OUTSTANDING; @@ -181,22 +158,18 @@ static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLO hr = VFW_E_BADALIGN; else { - if (!This->pProps) - This->pProps = CoTaskMemAlloc(sizeof(*This->pProps)); - - if (!This->pProps) - hr = E_OUTOFMEMORY; + if (This->fnVerify) + hr = This->fnVerify(iface, pRequest); else - { - *This->pProps = *pRequest; + hr = S_OK; - *pActual = *pRequest; + if (SUCCEEDED(hr)) + This->props = *pRequest; - hr = S_OK; - } + *pActual = This->props; } } - LeaveCriticalSection(&This->csState); + LeaveCriticalSection(This->pCritSect); return hr; } @@ -208,20 +181,11 @@ static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLO TRACE("(%p)->(%p)\n", This, pProps); - EnterCriticalSection(&This->csState); + EnterCriticalSection(This->pCritSect); { - /* NOTE: this is different from the native version. - * It would silently succeed if the properties had - * not been set, but would fail further on down the - * line with some obscure error like having an - * invalid alignment. Whether or not our version - * will cause any problems remains to be seen */ - if (!This->pProps) - hr = VFW_E_SIZENOTSET; - else - memcpy(pProps, This->pProps, sizeof(*pProps)); + memcpy(pProps, &This->props, sizeof(*pProps)); } - LeaveCriticalSection(&This->csState); + LeaveCriticalSection(This->pCritSect); return hr; } @@ -233,10 +197,14 @@ static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface) TRACE("(%p)->()\n", This); - EnterCriticalSection(&This->csState); + EnterCriticalSection(This->pCritSect); { - if (!This->pProps) + if (!This->props.cbAlign) + hr = VFW_E_BADALIGN; + else if (!This->props.cbBuffer) hr = VFW_E_SIZENOTSET; + else if (!This->props.cBuffers) + hr = VFW_E_BUFFER_NOTSET; else if (This->bDecommitQueued && This->bCommitted) { This->bDecommitQueued = FALSE; @@ -246,7 +214,7 @@ static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface) hr = S_OK; else { - if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->pProps->cBuffers, This->pProps->cBuffers, NULL))) + if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->props.cBuffers, This->props.cBuffers, NULL))) { ERR("Couldn't create semaphore (error was %u)\n", GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError()); @@ -261,7 +229,7 @@ static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface) } } } - LeaveCriticalSection(&This->csState); + LeaveCriticalSection(This->pCritSect); return hr; } @@ -273,7 +241,7 @@ static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface) TRACE("(%p)->()\n", This); - EnterCriticalSection(&This->csState); + EnterCriticalSection(This->pCritSect); { if (!This->bCommitted) hr = S_OK; @@ -301,7 +269,7 @@ static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface) } } } - LeaveCriticalSection(&This->csState); + LeaveCriticalSection(This->pCritSect); return hr; } @@ -329,7 +297,7 @@ static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSa } This->lWaiting--; - EnterCriticalSection(&This->csState); + EnterCriticalSection(This->pCritSect); { if (!This->bCommitted) hr = VFW_E_NOT_COMMITTED; @@ -348,7 +316,7 @@ static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSa IMediaSample_AddRef(*pSample); } } - LeaveCriticalSection(&This->csState); + LeaveCriticalSection(This->pCritSect); return hr; } @@ -365,7 +333,7 @@ static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMed /* FIXME: we should probably check the ref count on the sample before freeing * it to make sure that it is not still in use */ - EnterCriticalSection(&This->csState); + EnterCriticalSection(This->pCritSect); { if (!This->bCommitted) ERR("Releasing a buffer when the allocator is not committed?!?\n"); @@ -391,7 +359,7 @@ static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMed ERR("fnFree failed with error 0x%x\n", hrfree); } } - LeaveCriticalSection(&This->csState); + LeaveCriticalSection(This->pCritSect); /* notify a waiting thread that there is now a free buffer */ if (This->hSemWaiting && !ReleaseSemaphore(This->hSemWaiting, 1, NULL)) @@ -416,7 +384,7 @@ static const IMemAllocatorVtbl BaseMemAllocator_VTable = BaseMemAllocator_ReleaseBuffer }; -static HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample) +HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample) { assert(pbBuffer && pParent && (cbBuffer > 0)); @@ -440,7 +408,7 @@ static HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAll return S_OK; } -static void StdMediaSample2_Delete(StdMediaSample2 * This) +void StdMediaSample2_Delete(StdMediaSample2 * This) { /* NOTE: does not remove itself from the list it belongs to */ CoTaskMemFree(This); @@ -507,6 +475,12 @@ static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** *ppBuffer = This->props.pbBuffer; + if (!*ppBuffer) + { + ERR("Requested an unlocked surface and trying to lock regardless\n"); + return E_FAIL; + } + return S_OK; } @@ -782,6 +756,7 @@ static const IMediaSample2Vtbl StdMediaSample2_VTable = typedef struct StdMemAllocator { BaseMemAllocator base; + CRITICAL_SECTION csState; LPVOID pMemory; } StdMemAllocator; @@ -798,21 +773,21 @@ static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface) GetSystemInfo(&si); /* we do not allow a courser alignment than the OS page size */ - if ((si.dwPageSize % This->base.pProps->cbAlign) != 0) + if ((si.dwPageSize % This->base.props.cbAlign) != 0) return VFW_E_BADALIGN; /* FIXME: each sample has to have its buffer start on the right alignment. * We don't do this at the moment */ /* allocate memory */ - This->pMemory = VirtualAlloc(NULL, (This->base.pProps->cbBuffer + This->base.pProps->cbPrefix) * This->base.pProps->cBuffers, MEM_COMMIT, PAGE_READWRITE); + This->pMemory = VirtualAlloc(NULL, (This->base.props.cbBuffer + This->base.props.cbPrefix) * This->base.props.cBuffers, MEM_COMMIT, PAGE_READWRITE); - for (i = This->base.pProps->cBuffers - 1; i >= 0; i--) + for (i = This->base.props.cBuffers - 1; i >= 0; i--) { /* pbBuffer does not start at the base address, it starts at base + cbPrefix */ - BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.pProps->cbBuffer + This->base.pProps->cbPrefix) + This->base.pProps->cbPrefix; + BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.props.cbBuffer + This->base.props.cbPrefix) + This->base.props.cbPrefix; - StdMediaSample2_Construct(pbBuffer, This->base.pProps->cbBuffer, iface, &pSample); + StdMediaSample2_Construct(pbBuffer, This->base.props.cbBuffer, iface, &pSample); list_add_head(&This->base.free_list, &pSample->listentry); } @@ -853,6 +828,16 @@ static HRESULT StdMemAllocator_Free(IMemAllocator * iface) return S_OK; } +static void StdMemAllocator_Destroy(IMemAllocator *iface) +{ + StdMemAllocator *This = (StdMemAllocator *)iface; + + This->csState.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->csState); + + CoTaskMemFree(This); +} + HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv) { StdMemAllocator * pMemAlloc; @@ -866,9 +851,12 @@ HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv) if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc)))) return E_OUTOFMEMORY; + InitializeCriticalSection(&pMemAlloc->csState); + pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StdMemAllocator.csState"); + pMemAlloc->pMemory = NULL; - if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, &pMemAlloc->base))) + if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, NULL, NULL, NULL, StdMemAllocator_Destroy, &pMemAlloc->csState, &pMemAlloc->base))) *ppv = (LPVOID)pMemAlloc; else CoTaskMemFree(pMemAlloc); diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index 9eb1630d0e5..e025078b9ab 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -33,6 +33,7 @@ #include "wingdi.h" #include "winuser.h" #include "dshow.h" +#include "wine/list.h" #define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) #define SEC_FROM_MEDIATIME(time) ((time) / 10000000) @@ -84,4 +85,49 @@ BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, B void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt); HRESULT updatehres( HRESULT original, HRESULT new ); +typedef struct StdMediaSample2 +{ + const IMediaSample2Vtbl * lpvtbl; + + LONG ref; + AM_SAMPLE2_PROPERTIES props; + IMemAllocator * pParent; + struct list listentry; + LONGLONG tMediaStart; + LONGLONG tMediaEnd; +} StdMediaSample2; + +typedef struct BaseMemAllocator +{ + const IMemAllocatorVtbl * lpVtbl; + + LONG ref; + ALLOCATOR_PROPERTIES props; + HRESULT (* fnAlloc) (IMemAllocator *); + HRESULT (* fnFree)(IMemAllocator *); + HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *); + HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD flags); + HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *); + void (* fnDestroyed)(IMemAllocator *); + HANDLE hSemWaiting; + BOOL bDecommitQueued; + BOOL bCommitted; + LONG lWaiting; + struct list free_list; + struct list used_list; + CRITICAL_SECTION *pCritSect; +} BaseMemAllocator; + +HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), + HRESULT (* fnFree)(IMemAllocator *), + HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *), + HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD), + HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *), + void (* fnDestroyed)(IMemAllocator *), + CRITICAL_SECTION *pCritSect, + BaseMemAllocator * pMemAlloc); + +HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample); +void StdMediaSample2_Delete(StdMediaSample2 * This); + #endif /* __QUARTZ_PRIVATE_INCLUDED__ */