quartz: Make the file source support multiple samples by preallocating enough handles.

This commit is contained in:
Maarten Lankhorst 2008-04-22 16:54:28 -07:00 committed by Alexandre Julliard
parent 3a39805ed8
commit e0fe0ef01b
1 changed files with 124 additions and 90 deletions

View File

@ -740,28 +740,21 @@ typedef struct DATAREQUEST
IMediaSample * pSample; /* sample passed to us by user */
DWORD_PTR dwUserData; /* user data passed to us */
OVERLAPPED ovl; /* our overlapped structure */
struct DATAREQUEST * pNext; /* next data request in list */
} DATAREQUEST;
static void queue(DATAREQUEST * pHead, DATAREQUEST * pItem)
{
DATAREQUEST * pCurrent;
for (pCurrent = pHead; pCurrent->pNext; pCurrent = pCurrent->pNext)
;
pCurrent->pNext = pItem;
}
typedef struct FileAsyncReader
{
OutputPin pin;
const struct IAsyncReaderVtbl * lpVtblAR;
HANDLE hFile;
HANDLE hEvent;
BOOL bFlushing;
DATAREQUEST * pHead; /* head of data request list */
CRITICAL_SECTION csList; /* critical section to protect operations on list */
/* Why would you need more? Every sample has its own handle */
LONG queued_number;
LONG samples;
CRITICAL_SECTION csList; /* critical section to prevent concurrency issues */
DATAREQUEST *sample_list;
HANDLE *handle_list;
} FileAsyncReader;
static inline FileAsyncReader *impl_from_IAsyncReader( IAsyncReader *iface )
@ -815,20 +808,20 @@ static ULONG WINAPI FileAsyncReaderPin_Release(IPin * iface)
{
FileAsyncReader *This = (FileAsyncReader *)iface;
ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
int x;
TRACE("(%p)->() Release from %d\n", This, refCount + 1);
if (!refCount)
{
DATAREQUEST * pCurrent;
DATAREQUEST * pNext;
for (pCurrent = This->pHead; pCurrent; pCurrent = pNext)
CoTaskMemFree(This->sample_list);
if (This->handle_list)
{
pNext = pCurrent->pNext;
CoTaskMemFree(pCurrent);
for (x = 0; x < This->samples; ++x)
CloseHandle(This->handle_list[x]);
CoTaskMemFree(This->handle_list);
}
CloseHandle(This->hFile);
CloseHandle(This->hEvent);
This->csList.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->csList);
CoTaskMemFree(This);
@ -919,9 +912,10 @@ static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter
FileAsyncReader *pPinImpl = (FileAsyncReader *)*ppPin;
pPinImpl->lpVtblAR = &FileAsyncReader_Vtbl;
pPinImpl->hFile = hFile;
pPinImpl->hEvent = CreateEventW(NULL, 0, 0, NULL);
pPinImpl->bFlushing = FALSE;
pPinImpl->pHead = NULL;
pPinImpl->sample_list = NULL;
pPinImpl->handle_list = NULL;
pPinImpl->queued_number = 0;
pPinImpl->pin.pConnectSpecific = FileAsyncReaderPin_ConnectSpecific;
InitializeCriticalSection(&pPinImpl->csList);
pPinImpl->csList.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FileAsyncReader.csList");
@ -956,6 +950,8 @@ static ULONG WINAPI FileAsyncReader_Release(IAsyncReader * iface)
static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader * iface, IMemAllocator * pPreferred, ALLOCATOR_PROPERTIES * pProps, IMemAllocator ** ppActual)
{
FileAsyncReader *This = impl_from_IAsyncReader(iface);
HRESULT hr = S_OK;
TRACE("(%p, %p, %p)\n", pPreferred, pProps, ppActual);
@ -965,15 +961,14 @@ static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader * iface, IMe
if (pPreferred)
{
ALLOCATOR_PROPERTIES PropsActual;
hr = IMemAllocator_SetProperties(pPreferred, pProps, &PropsActual);
hr = IMemAllocator_SetProperties(pPreferred, pProps, pProps);
/* FIXME: check we are still aligned */
if (SUCCEEDED(hr))
{
IMemAllocator_AddRef(pPreferred);
*ppActual = pPreferred;
TRACE("FileAsyncReader_RequestAllocator -- %x\n", hr);
return S_OK;
goto done;
}
}
@ -983,14 +978,50 @@ static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader * iface, IMe
if (SUCCEEDED(hr))
{
ALLOCATOR_PROPERTIES PropsActual;
hr = IMemAllocator_SetProperties(pPreferred, pProps, &PropsActual);
hr = IMemAllocator_SetProperties(pPreferred, pProps, pProps);
/* FIXME: check we are still aligned */
if (SUCCEEDED(hr))
{
*ppActual = pPreferred;
TRACE("FileAsyncReader_RequestAllocator -- %x\n", hr);
return S_OK;
}
}
done:
if (SUCCEEDED(hr))
{
CoTaskMemFree(This->sample_list);
if (This->handle_list)
{
int x;
for (x = 0; x < This->samples; ++x)
CloseHandle(This->handle_list[x]);
CoTaskMemFree(This->handle_list);
}
This->samples = pProps->cBuffers;
TRACE("Samples: %u\n", This->samples);
This->sample_list = CoTaskMemAlloc(sizeof(This->sample_list[0]) * pProps->cBuffers);
This->handle_list = CoTaskMemAlloc(sizeof(HANDLE) * pProps->cBuffers);
if (This->sample_list && This->handle_list)
{
int x;
ZeroMemory(This->sample_list, sizeof(This->sample_list[0]) * pProps->cBuffers);
for (x = 0; x < This->samples; ++x)
{
This->sample_list[x].ovl.hEvent = This->handle_list[x] = CreateEventW(NULL, 0, 0, NULL);
}
This->pin.allocProps = *pProps;
}
else
{
hr = E_OUTOFMEMORY;
CoTaskMemFree(This->sample_list);
CoTaskMemFree(This->handle_list);
This->samples = 0;
This->sample_list = NULL;
This->handle_list = NULL;
}
}
@ -1009,21 +1040,16 @@ static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader * iface, IMe
* however, this would be quite complicated to do and may be a bit error prone */
static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample * pSample, DWORD_PTR dwUser)
{
HRESULT hr = S_OK;
REFERENCE_TIME Start;
REFERENCE_TIME Stop;
DATAREQUEST * pDataRq;
BYTE * pBuffer;
HRESULT hr = S_OK;
FileAsyncReader *This = impl_from_IAsyncReader(iface);
LPBYTE pBuffer = NULL;
TRACE("(%p, %lx)\n", pSample, dwUser);
/* check flushing state */
if (This->bFlushing)
return VFW_E_WRONG_STATE;
if (!(pDataRq = CoTaskMemAlloc(sizeof(*pDataRq))))
hr = E_OUTOFMEMORY;
if (!pSample)
return E_POINTER;
/* get start and stop positions in bytes */
if (SUCCEEDED(hr))
@ -1032,30 +1058,38 @@ static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample
if (SUCCEEDED(hr))
hr = IMediaSample_GetPointer(pSample, &pBuffer);
EnterCriticalSection(&This->csList);
if (This->bFlushing)
{
LeaveCriticalSection(&This->csList);
return VFW_E_WRONG_STATE;
}
if (SUCCEEDED(hr))
{
DWORD dwLength = (DWORD) BYTES_FROM_MEDIATIME(Stop - Start);
DATAREQUEST *pDataRq;
int x;
for (x = 0; x < This->samples; ++x)
{
if (!This->sample_list[x].pSample)
break;
}
assert(x < This->samples);
InterlockedIncrement(&This->queued_number);
pDataRq = This->sample_list + x;
pDataRq->ovl.u.s.Offset = (DWORD) BYTES_FROM_MEDIATIME(Start);
pDataRq->ovl.u.s.OffsetHigh = (DWORD)(BYTES_FROM_MEDIATIME(Start) >> (sizeof(DWORD) * 8));
pDataRq->ovl.hEvent = This->hEvent;
pDataRq->dwUserData = dwUser;
pDataRq->pNext = NULL;
/* we violate traditional COM rules here by maintaining
* a reference to the sample, but not calling AddRef, but
* that's what MSDN says to do */
pDataRq->pSample = pSample;
EnterCriticalSection(&This->csList);
{
if (This->pHead)
/* adds data request to end of list */
queue(This->pHead, pDataRq);
else
This->pHead = pDataRq;
}
LeaveCriticalSection(&This->csList);
/* this is definitely not how it is implemented on Win9x
* as they do not support async reads on files, but it is
* sooo much easier to use this than messing around with threads!
@ -1068,21 +1102,7 @@ static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample
hr = S_OK;
}
if (FAILED(hr) && pDataRq)
{
EnterCriticalSection(&This->csList);
{
DATAREQUEST * pCurrent;
for (pCurrent = This->pHead; pCurrent && pCurrent->pNext; pCurrent = pCurrent->pNext)
if (pCurrent->pNext == pDataRq)
{
pCurrent->pNext = pDataRq->pNext;
break;
}
}
LeaveCriticalSection(&This->csList);
CoTaskMemFree(pDataRq);
}
TRACE("-- %x\n", hr);
return hr;
@ -1091,47 +1111,61 @@ static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample
static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dwTimeout, IMediaSample ** ppSample, DWORD_PTR * pdwUser)
{
HRESULT hr = S_OK;
DWORD dwBytes = 0;
DATAREQUEST * pDataRq = NULL;
FileAsyncReader *This = impl_from_IAsyncReader(iface);
DWORD buffer = ~0;
TRACE("(%u, %p, %p)\n", dwTimeout, ppSample, pdwUser);
/* FIXME: we could do with improving this by waiting for an array of event handles
* and then determining which one finished and removing that from the list, otherwise
* we will end up waiting for longer than we should do, if a later request finishes
* before an earlier one */
*ppSample = NULL;
*pdwUser = 0;
if (!This->bFlushing)
{
if (!This->pHead)
ERR("Called without samples in queue!\n");
if (!This->queued_number)
{
ERR("Called without samples in queue and not flushing!!\n");
return E_FAIL;
}
/* wait for the read to finish or timeout */
if (WaitForSingleObject(This->hEvent, dwTimeout) == WAIT_TIMEOUT)
/* wait for an object to read, or time out */
buffer = WaitForMultipleObjectsEx(This->samples, This->handle_list, FALSE, dwTimeout, TRUE);
if (buffer >= MAXIMUM_WAIT_OBJECTS)
{
FIXME("Returned: %u (%08x)\n", buffer, GetLastError());
hr = VFW_E_TIMEOUT;
buffer = ~0;
}
else
InterlockedDecrement(&This->queued_number);
}
if (SUCCEEDED(hr))
{
EnterCriticalSection(&This->csList);
if (This->bFlushing && buffer == ~0)
{
pDataRq = This->pHead;
if (pDataRq == NULL)
hr = E_FAIL;
else
This->pHead = pDataRq->pNext;
for (buffer = 0; buffer < This->samples; ++buffer)
{
if (This->sample_list[buffer].pSample)
break;
}
if (buffer == This->samples)
{
assert(!This->queued_number);
hr = E_FAIL;
}
else
{
InterlockedDecrement(&This->queued_number);
hr = S_OK;
}
LeaveCriticalSection(&This->csList);
}
if (SUCCEEDED(hr))
{
REFERENCE_TIME rtStart, rtStop;
REFERENCE_TIME rtSampleStart, rtSampleStop;
DATAREQUEST *pDataRq = This->sample_list + buffer;
DWORD dwBytes = 0;
/* get any errors */
if (!This->bFlushing && !GetOverlappedResult(This->hFile, &pDataRq->ovl, &dwBytes, FALSE))
@ -1165,10 +1199,9 @@ static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dw
else
assert(rtStop == rtStart);
This->sample_list[buffer].pSample = NULL;
}
/* no need to close event handle since we will close it when the pin is destroyed */
CoTaskMemFree(pDataRq);
LeaveCriticalSection(&This->csList);
TRACE("-- %x\n", hr);
return hr;
@ -1260,11 +1293,10 @@ static HRESULT WINAPI FileAsyncReader_BeginFlush(IAsyncReader * iface)
TRACE("()\n");
EnterCriticalSection(&This->csList);
This->bFlushing = TRUE;
CancelIo(This->hFile);
SetEvent(This->hEvent);
/* FIXME: free list */
LeaveCriticalSection(&This->csList);
return S_OK;
}
@ -1275,7 +1307,9 @@ static HRESULT WINAPI FileAsyncReader_EndFlush(IAsyncReader * iface)
TRACE("()\n");
EnterCriticalSection(&This->csList);
This->bFlushing = FALSE;
LeaveCriticalSection(&This->csList);
return S_OK;
}