Implemented IMediaControl_Run that explores the graph, counts

renderers and starts filters.
Better implementation of IBaseFilter_Run for AVI SPlitter and AVI
Decompressor.
Use the standard memory allocator when an output pin does not provide
any allocator.
Set allocator properties for AVI Decompressor output pin and update
the buffers size at connection time.
This commit is contained in:
Christian Costa 2005-01-03 20:23:14 +00:00 committed by Alexandre Julliard
parent 0b14f38d57
commit 45f111a276
4 changed files with 165 additions and 15 deletions

View File

@ -235,6 +235,9 @@ static HRESULT AVIDec_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
pAVIDec->pBihOut->biCompression = 0;
pAVIDec->pBihOut->biSizeImage = pAVIDec->pBihOut->biWidth * pAVIDec->pBihOut->biHeight * pAVIDec->pBihOut->biBitCount / 8;
/* Update buffer size of media samples in output */
((OutputPin*)pAVIDec->ppPins[1])->allocProps.cbBuffer = pAVIDec->pBihOut->biSizeImage;
pAVIDec->init = 1;
TRACE("Connection accepted\n");
return S_OK;
@ -354,7 +357,13 @@ HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv)
if (SUCCEEDED(hr))
{
hr = AVIDec_OutputPin_Construct(&piOutput, NULL, NULL, AVIDec_Output_QueryAccept, &pAVIDec->csFilter, &pAVIDec->ppPins[1]);
ALLOCATOR_PROPERTIES props;
props.cbAlign = 1;
props.cbPrefix = 0;
props.cbBuffer = 0; /* Will be updated at connection time */
props.cBuffers = 2;
hr = AVIDec_OutputPin_Construct(&piOutput, &props, NULL, AVIDec_Output_QueryAccept, &pAVIDec->csFilter, &pAVIDec->ppPins[1]);
if (FAILED(hr))
ERR("Cannot create output pin (%lx)\n", hr);
@ -498,8 +507,8 @@ static HRESULT WINAPI AVIDec_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
EnterCriticalSection(&This->csFilter);
{
This->rtStreamStart = tStart;
This->state = State_Running;
OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
}
LeaveCriticalSection(&This->csFilter);

View File

@ -327,6 +327,7 @@ static HRESULT WINAPI AVISplitter_Run(IBaseFilter * iface, REFERENCE_TIME tStart
{
HRESULT hr = S_OK;
AVISplitter *This = (AVISplitter *)iface;
int i;
TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
@ -334,6 +335,17 @@ static HRESULT WINAPI AVISplitter_Run(IBaseFilter * iface, REFERENCE_TIME tStart
{
This->rtStreamStart = tStart;
This->state = State_Running;
hr = PullPin_InitProcessing(This->pInputPin);
if (SUCCEEDED(hr))
{
for (i = 1; i < This->cStreams + 1; i++)
{
OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
}
hr = PullPin_StartProcessing(This->pInputPin);
}
}
LeaveCriticalSection(&This->csFilter);
@ -840,9 +852,9 @@ static HRESULT AVISplitter_ProcessStreamList(AVISplitter * This, const BYTE * pD
}
dump_AM_MEDIA_TYPE(&amt);
FIXME("fSamplesPerSec = %f\n", (double)fSamplesPerSec);
FIXME("dwSampleSize = %lx\n", dwSampleSize);
FIXME("dwLength = %lx\n", dwLength);
TRACE("fSamplesPerSec = %f\n", (double)fSamplesPerSec);
TRACE("dwSampleSize = %lx\n", dwSampleSize);
TRACE("dwLength = %lx\n", dwLength);
ppOldPins = This->ppPins;

View File

@ -180,6 +180,8 @@ typedef struct _IFilterGraphImpl {
int EcCompleteCount;
int HandleEcComplete;
int HandleEcRepaint;
OAFilterState state;
CRITICAL_SECTION cs;
} IFilterGraphImpl;
@ -245,6 +247,7 @@ static ULONG Filtergraph_Release(IFilterGraphImpl *This) {
IFilterMapper2_Release(This->pFilterMapper2);
CloseHandle(This->hEventCompletion);
EventsQueue_Destroy(&This->evqueue);
DeleteCriticalSection(&This->cs);
HeapFree(GetProcessHeap(), 0, This->ppFiltersInGraph);
HeapFree(GetProcessHeap(), 0, This->pFilterNames);
HeapFree(GetProcessHeap(), 0, This);
@ -519,18 +522,18 @@ static HRESULT GetFilterInfo(IMoniker* pMoniker, GUID* pclsid, VARIANT* pvar)
return hr;
}
static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* poutputpin, IPin*** pppins, ULONG* pnb)
static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
{
HRESULT hr;
ULONG nb = 0;
TRACE("(%p, %p, %p, %p)\n", pfilter, poutputpin, pppins, pnb);
hr = IPin_QueryInternalConnections(poutputpin, NULL, &nb);
TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
if (hr == S_OK) {
/* Rendered input */
} else if (hr == S_FALSE) {
*pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
hr = IPin_QueryInternalConnections(poutputpin, *pppins, &nb);
hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
if (hr != S_OK) {
ERR("Error (%lx)\n", hr);
}
@ -1159,14 +1162,116 @@ static HRESULT WINAPI Mediacontrol_Invoke(IMediaControl *iface,
return S_OK;
}
static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, REFERENCE_TIME tStart)
{
HRESULT hr;
IPin* pInputPin;
IPin** ppPins;
ULONG nb;
ULONG i;
PIN_INFO PinInfo;
TRACE("%p %p %lld\n", pGraph, pOutputPin, tStart);
hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
if (SUCCEEDED(hr))
hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
if (SUCCEEDED(hr))
hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
if (SUCCEEDED(hr))
{
if (nb == 0)
{
TRACE("Reached a renderer\n");
/* Count renderers for end of stream notification */
pGraph->nRenderers++;
}
else
{
for(i = 0; i < nb; i++)
{
/* Explore the graph downstream from this pin
* FIXME: We should prevent exploring from a pin more than once. This can happens when
* several input pins are connected to the same output (a MUX for instance). */
ExploreGraph(pGraph, ppPins[i], tStart);
}
CoTaskMemFree(ppPins);
}
TRACE("Run filter %p\n", PinInfo.pFilter);
IBaseFilter_Run(PinInfo.pFilter, tStart);
}
return hr;
}
/*** IMediaControl methods ***/
static HRESULT WINAPI Mediacontrol_Run(IMediaControl *iface) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
int i;
IBaseFilter* pfilter;
IEnumPins* pEnum;
HRESULT hr;
IPin* pPin;
LONG dummy;
PIN_DIRECTION dir;
TRACE("(%p/%p)->(): stub !!!\n", This, iface);
TRACE("(%p/%p)->()\n", This, iface);
EnterCriticalSection(&This->cs);
if (This->state == State_Running)
{
LeaveCriticalSection(&This->cs);
return S_OK;
}
/* Explorer the graph from source filters to renderers, determine renderers number and
* run filters from renderers to source filters */
This->nRenderers = 0;
ResetEvent(This->hEventCompletion);
for(i = 0; i < This->nFilters; i++)
{
BOOL source = TRUE;
pfilter = This->ppFiltersInGraph[i];
hr = IBaseFilter_EnumPins(pfilter, &pEnum);
if (hr != S_OK)
{
ERR("Enum pins failed %lx\n", hr);
continue;
}
/* Check if it is a source filter */
while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
{
IPin_QueryDirection(pPin, &dir);
if (dir == PINDIR_INPUT)
{
source = FALSE;
break;
}
}
if (source == TRUE)
{
TRACE("Found a source filter\n");
IEnumPins_Reset(pEnum);
while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
{
/* Explore the graph downstream from this pin */
ExploreGraph(This, pPin, 0);
}
IBaseFilter_Run(pfilter, 0);
}
IEnumPins_Release(pEnum);
}
This->state = State_Running;
LeaveCriticalSection(&This->cs);
return S_FALSE;
}
@ -1191,8 +1296,14 @@ static HRESULT WINAPI Mediacontrol_GetState(IMediaControl *iface,
OAFilterState *pfs) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
TRACE("(%p/%p)->(%ld, %p): stub !!!\n", This, iface, msTimeout, pfs);
TRACE("(%p/%p)->(%ld, %p): semi-stub !!!\n", This, iface, msTimeout, pfs);
EnterCriticalSection(&This->cs);
*pfs = This->state;
LeaveCriticalSection(&This->cs);
return S_OK;
}
@ -2876,7 +2987,7 @@ static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, long EventCo
/* We need thread safety here, let's use the events queue's one */
EnterCriticalSection(&This->evqueue.msg_crst);
if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
{
if (++This->EcCompleteCount == This->nRenderers)
@ -2950,7 +3061,9 @@ HRESULT FILTERGRAPH_create(IUnknown *pUnkOuter, LPVOID *ppObj) {
fimpl->notif.disabled = TRUE;
fimpl->nRenderers = 0;
fimpl->EcCompleteCount = 0;
fimpl->state = State_Stopped;
EventsQueue_Init(&fimpl->evqueue);
InitializeCriticalSection(&fimpl->cs);
hr = CoCreateInstance(&CLSID_FilterMapper, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&fimpl->pFilterMapper2);
if (FAILED(hr)) {

View File

@ -82,6 +82,17 @@ static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const
if (SUCCEEDED(hr))
hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc);
if (hr == VFW_E_NO_ALLOCATOR)
{
/* Input pin provides no allocator, use standard memory allocator */
hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc);
if (SUCCEEDED(hr))
{
hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, FALSE);
}
}
if (SUCCEEDED(hr))
hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual);
@ -180,7 +191,6 @@ HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props,
else
ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
return S_OK;
}
@ -217,7 +227,7 @@ ULONG WINAPI IPinImpl_AddRef(IPin * iface)
{
IPinImpl *This = (IPinImpl *)iface;
TRACE("()\n");
TRACE("(%p)->() AddRef from %ld\n", iface, This->refCount);
return InterlockedIncrement(&This->refCount);
}
@ -394,7 +404,7 @@ ULONG WINAPI InputPin_Release(IPin * iface)
{
InputPin *This = (InputPin *)iface;
TRACE("()\n");
TRACE("(%p)->() Release from %ld\n", iface, This->pin.refCount);
if (!InterlockedDecrement(&This->pin.refCount))
{
@ -1142,6 +1152,8 @@ static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), allocProps.cbAlign));
TRACE("Start\n");
while (rtCurrent < This->rtStop)
{
/* FIXME: to improve performance by quite a bit this should be changed
@ -1151,6 +1163,8 @@ static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
REFERENCE_TIME rtSampleStop;
DWORD dwUser;
TRACE("Process sample\n");
hr = IMemAllocator_GetBuffer(This->pAlloc, &pSample, NULL, NULL, 0);
if (SUCCEEDED(hr))
@ -1178,6 +1192,8 @@ static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
}
CoUninitialize();
TRACE("End\n");
}
static void CALLBACK PullPin_Thread_Stop(ULONG_PTR iface)