[QUARTZ] Some stuff to start the graph (take 3)

Christian Costa titan.costa at wanadoo.fr
Wed Dec 29 07:40:46 CST 2004


Hi,

This time including last Rob's suggestion. :-)

Changelog:
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.

Christian Costa   titan.costa at wanadoo.fr

-------------- next part --------------
Index: dlls/quartz/avidec.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/avidec.c,v
retrieving revision 1.12
diff -u -r1.12 avidec.c
--- dlls/quartz/avidec.c	27 Dec 2004 17:15:58 -0000	1.12
+++ dlls/quartz/avidec.c	29 Dec 2004 12:29:08 -0000
@@ -235,6 +235,9 @@
             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 @@
 
     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 @@
     EnterCriticalSection(&This->csFilter);
     {
         This->rtStreamStart = tStart;
-
         This->state = State_Running;
+        OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
     }
     LeaveCriticalSection(&This->csFilter);
 
Index: dlls/quartz/avisplit.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/avisplit.c,v
retrieving revision 1.10
diff -u -r1.10 avisplit.c
--- dlls/quartz/avisplit.c	27 Dec 2004 17:15:58 -0000	1.10
+++ dlls/quartz/avisplit.c	29 Dec 2004 12:29:11 -0000
@@ -327,6 +327,7 @@
 {
     HRESULT hr = S_OK;
     AVISplitter *This = (AVISplitter *)iface;
+    int i;
 
     TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
 
@@ -334,6 +335,17 @@
     {
         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 @@
     }
 
     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;
 
Index: dlls/quartz/filtergraph.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/filtergraph.c,v
retrieving revision 1.22
diff -u -r1.22 filtergraph.c
--- dlls/quartz/filtergraph.c	27 Dec 2004 17:15:58 -0000	1.22
+++ dlls/quartz/filtergraph.c	29 Dec 2004 12:29:17 -0000
@@ -180,6 +180,8 @@
     int EcCompleteCount;
     int HandleEcComplete;
     int HandleEcRepaint;
+    OAFilterState state;
+    CRITICAL_SECTION cs;
 } IFilterGraphImpl;
 
 
@@ -245,6 +247,7 @@
 	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 @@
     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 @@
     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 @@
 					    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 @@
 
     /* 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 @@
     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)) {
Index: dlls/quartz/filtermapper.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/filtermapper.c,v
retrieving revision 1.18
diff -u -r1.18 filtermapper.c
--- dlls/quartz/filtermapper.c	30 Nov 2004 21:38:59 -0000	1.18
+++ dlls/quartz/filtermapper.c	29 Dec 2004 12:29:20 -0000
@@ -163,7 +163,7 @@
     TRACE("(%p, %p)\n", pUnkOuter, ppObj);
 
     if (pUnkOuter)
-        return CLASS_E_NOAGGREGATION;
+        ;//return CLASS_E_NOAGGREGATION;
 
     pFM2impl = CoTaskMemAlloc(sizeof(*pFM2impl));
     if (!pFM2impl)
Index: dlls/quartz/pin.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/pin.c,v
retrieving revision 1.10
diff -u -r1.10 pin.c
--- dlls/quartz/pin.c	27 Dec 2004 17:15:58 -0000	1.10
+++ dlls/quartz/pin.c	29 Dec 2004 12:29:22 -0000
@@ -82,6 +82,17 @@
         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 @@
     else
         ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
 
-
     return S_OK;
 }
 
@@ -217,7 +227,7 @@
 {
     IPinImpl *This = (IPinImpl *)iface;
     
-    TRACE("()\n");
+    TRACE("(%p)->() AddRef from %ld\n", iface, This->refCount);
     
     return InterlockedIncrement(&This->refCount);
 }
@@ -394,7 +404,7 @@
 {
     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 @@
 
     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 @@
         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 @@
     }
 
     CoUninitialize();
+
+    TRACE("End\n");
 }
 
 static void CALLBACK PullPin_Thread_Stop(ULONG_PTR iface)


More information about the wine-patches mailing list