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:
parent
0b14f38d57
commit
45f111a276
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue