diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index 614fa68be07..10e9afeca46 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -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); diff --git a/dlls/quartz/avisplit.c b/dlls/quartz/avisplit.c index 0145b103f3a..d47163f6e33 100644 --- a/dlls/quartz/avisplit.c +++ b/dlls/quartz/avisplit.c @@ -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; diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 3e11e138ead..3d4a80d10fc 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -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)) { diff --git a/dlls/quartz/pin.c b/dlls/quartz/pin.c index b81c26677c6..ef31e6ca3e5 100644 --- a/dlls/quartz/pin.c +++ b/dlls/quartz/pin.c @@ -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)