[QUARTZ] Handle End Of Stream notifications

Christian Costa titan.costa at wanadoo.fr
Sun Feb 27 16:03:55 CST 2005


Hi,

Changelog:
Handle End Of Stream notifications.
Some AVI Splitter fixes.

Christian Costa   titan.costa at wanadoo.fr

-------------- next part --------------
Index: dlls/quartz/avisplit.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/avisplit.c,v
retrieving revision 1.13
diff -u -r1.13 avisplit.c
--- dlls/quartz/avisplit.c	8 Feb 2005 13:43:59 -0000	1.13
+++ dlls/quartz/avisplit.c	27 Feb 2005 20:48:16 -0000
@@ -55,11 +55,14 @@
     AVIMAINHEADER AviHeader;
 } AVISplitterImpl;
 
-static HRESULT AVISplitter_NextChunk(LONGLONG * pllCurrentChunkOffset, RIFFCHUNK * pCurrentChunk, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, const BYTE * pbSrcStream)
+static HRESULT AVISplitter_NextChunk(LONGLONG * pllCurrentChunkOffset, RIFFCHUNK * pCurrentChunk, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, const BYTE * pbSrcStream, int inner)
 {
-    *pllCurrentChunkOffset += MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK) + RIFFROUND(pCurrentChunk->cb));
-
-    if (*pllCurrentChunkOffset > *tStop)
+    if (inner)
+        *pllCurrentChunkOffset += MEDIATIME_FROM_BYTES(sizeof(RIFFLIST));
+    else
+        *pllCurrentChunkOffset += MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK) + RIFFROUND(pCurrentChunk->cb));
+    
+    if (*pllCurrentChunkOffset >= *tStop)
         return S_FALSE; /* no more data - we couldn't even get the next chunk header! */
     else if (*pllCurrentChunkOffset + MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK)) >= *tStop)
     {
@@ -88,7 +91,7 @@
     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
 
     /* trace removed for performance reasons */
-/*  TRACE("(%p)\n", pSample); */
+    /* TRACE("(%p)\n", pSample); */
 
     assert(BYTES_FROM_MEDIATIME(tStop - tStart) == cbSrcStream);
 
@@ -104,7 +107,8 @@
         if (offset >= (DWORD)cbSrcStream)
         {
             FIXME("large offset\n");
-            return S_OK;
+            hr = S_OK;
+            goto skip;
         }
 
         memcpy(&This->CurrentChunk, pbSrcStream + offset, sizeof(RIFFCHUNK));
@@ -132,7 +136,7 @@
         case ckidJUNK:
         case aviFCC('i','d','x','1'): /* Index is not handled */
             /* silently ignore */
-            if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream))
+            if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream, FALSE))
                 bMoreData = FALSE;
             continue;
         case ckidLIST:
@@ -141,12 +145,16 @@
 	    {
 		/* FIXME: We only advanced to the first chunk inside the list without keeping track that we are in it.
 		 *        This is not clean and the parser should be improved for that but it is enough for most AVI files. */
-		This->CurrentChunkOffset = MEDIATIME_FROM_BYTES(BYTES_FROM_MEDIATIME(This->CurrentChunkOffset) + sizeof(RIFFLIST));
+                if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream, TRUE))
+                {
+                    bMoreData = FALSE;
+                    continue;
+                }
 		This->CurrentChunk = *(RIFFCHUNK*) (pbSrcStream + BYTES_FROM_MEDIATIME(This->CurrentChunkOffset-tStart));
             	offset_src = (long)BYTES_FROM_MEDIATIME(This->CurrentChunkOffset - tStart) + sizeof(RIFFCHUNK);
 	        break;
 	    }
-	    else if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream))
+	    else if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream, FALSE))
                 bMoreData = FALSE;
             continue;
         default:
@@ -168,7 +176,7 @@
                 break;
             default:
                 FIXME("Skipping unknown chunk type: %s at file offset 0x%lx\n", debugstr_an((LPSTR)&This->CurrentChunk.fcc, 4), (DWORD)BYTES_FROM_MEDIATIME(This->CurrentChunkOffset));
-                if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream))
+                if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream, FALSE))
                     bMoreData = FALSE;
                 continue;
             }
@@ -180,7 +188,8 @@
         if (streamId > This->Parser.cStreams)
         {
             ERR("Corrupted AVI file (contains stream id %d, but supposed to only have %ld streams)\n", streamId, This->Parser.cStreams);
-            return E_FAIL;
+            hr = E_FAIL;
+            break;
         }
 
         pOutputPin = (Parser_OutputPin *)This->Parser.ppPins[streamId + 1];
@@ -200,7 +209,7 @@
             {
                 TRACE("Skipping sending sample for stream %02d due to error (%lx)\n", streamId, hr);
                 This->pCurrentSample = NULL;
-                if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream))
+                if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream, FALSE))
                     bMoreData = FALSE;
                 continue;
             }
@@ -263,7 +272,7 @@
             
             This->pCurrentSample = NULL;
 
-            if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream))
+            if (S_FALSE == AVISplitter_NextChunk(&This->CurrentChunkOffset, &This->CurrentChunk, &tStart, &tStop, pbSrcStream, FALSE))
                 bMoreData = FALSE;
         }
         else
@@ -276,6 +285,38 @@
             bMoreData = FALSE;
         }
     }
+
+skip:
+    if (tStop >= This->EndOfFile)
+    {
+        int i;
+
+        TRACE("End of file reached\n");
+
+        for (i = 0; i < This->Parser.cStreams; i++)
+        {
+            IPin* ppin;
+            HRESULT hr;
+
+            TRACE("Send End Of Stream to output pin %d\n", i);
+
+            hr = IPin_ConnectedTo(This->Parser.ppPins[i+1], &ppin);
+            if (SUCCEEDED(hr))
+            {
+                hr = IPin_EndOfStream(ppin);
+                IPin_Release(ppin);
+            }
+            if (FAILED(hr))
+            {
+                ERR("%lx\n", hr);
+                break;
+            }
+        }
+
+        /* Force the pullpin thread to stop */
+        hr = S_FALSE;
+    }
+
     return hr;
 }
 
Index: dlls/quartz/dsoundrender.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/dsoundrender.c,v
retrieving revision 1.6
diff -u -r1.6 dsoundrender.c
--- dlls/quartz/dsoundrender.c	6 Jan 2005 19:36:47 -0000	1.6
+++ dlls/quartz/dsoundrender.c	27 Feb 2005 20:48:17 -0000
@@ -550,8 +550,8 @@
 
 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
 {
-    HRESULT hr;
     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
+    HRESULT hr = S_OK;
 
     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
 
@@ -563,7 +563,14 @@
             *This->filterInfo.achName = '\0';
         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
 
-	hr = IFilterGraph_QueryInterface(pGraph, &IID_IMediaEventSink, (LPVOID*)&This->pEventSink);
+        This->pEventSink = NULL;
+        if (pGraph)
+        {
+            /* Cache IMediaEventSink interface w/o increasing filtergraph refcount */
+            hr = IFilterGraph_QueryInterface(pGraph, &IID_IMediaEventSink, (LPVOID*)&This->pEventSink);
+            if (SUCCEEDED(hr))
+                IMediaEventSink_Release(This->pEventSink);
+        }
     }
     LeaveCriticalSection(&This->csFilter);
 
@@ -598,11 +605,11 @@
 
 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
 {
-    /* FIXME: critical section */
     InputPin* This = (InputPin*)iface;
-	
+
     TRACE("(%p/%p)->()\n", This, iface);
-	
+
+    /* FIXME: We should wait that all audio data has been played */
     return IMediaEventSink_Notify(((DSoundRenderImpl*)This->pin.pinInfo.pFilter)->pEventSink, EC_COMPLETE, S_OK, 0);
 }
 
Index: dlls/quartz/filtergraph.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/filtergraph.c,v
retrieving revision 1.25
diff -u -r1.25 filtergraph.c
--- dlls/quartz/filtergraph.c	9 Jan 2005 18:24:41 -0000	1.25
+++ dlls/quartz/filtergraph.c	27 Feb 2005 20:48:22 -0000
@@ -2995,30 +2995,35 @@
 
     if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
     {
-	if (++This->EcCompleteCount == This->nRenderers)
-	{
-	    evt.lEventCode = EC_COMPLETE;
-	    evt.lParam1 = S_OK;
-	    evt.lParam2 = 0;
-	    EventsQueue_PutEvent(&This->evqueue, &evt);
-	    if (!This->notif.disabled && This->notif.hWnd)
-		PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
-	    This->CompletionStatus = EC_COMPLETE;
-	    SetEvent(This->hEventCompletion);
-	}
+        TRACE("Process EC_COMPLETE notification\n");
+        if (++This->EcCompleteCount == This->nRenderers)
+        {
+            evt.lEventCode = EC_COMPLETE;
+            evt.lParam1 = S_OK;
+            evt.lParam2 = 0;
+            TRACE("Send EC_COMPLETE to app\n");
+            EventsQueue_PutEvent(&This->evqueue, &evt);
+            if (!This->notif.disabled && This->notif.hWnd)
+	    {
+                TRACE("Send Window message\n");
+                PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
+            }
+            This->CompletionStatus = EC_COMPLETE;
+            SetEvent(This->hEventCompletion);
+        }
     }
     else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
     {
-	/* FIXME: Not handled yet */
+        /* FIXME: Not handled yet */
     }
     else
     {
-	evt.lEventCode = EventCode;
-	evt.lParam1 = EventParam1;
-	evt.lParam2 = EventParam2;
-	EventsQueue_PutEvent(&This->evqueue, &evt);
-	if (!This->notif.disabled && This->notif.hWnd)
-	    PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
+        evt.lEventCode = EventCode;
+        evt.lParam1 = EventParam1;
+        evt.lParam2 = EventParam2;
+        EventsQueue_PutEvent(&This->evqueue, &evt);
+        if (!This->notif.disabled && This->notif.hWnd)
+            PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
     }
 
     LeaveCriticalSection(&This->evqueue.msg_crst);
@@ -3059,11 +3064,11 @@
     fimpl->nFilters = 0;
     fimpl->filterCapacity = 0;
     fimpl->nameIndex = 1;
-    fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE,0);
+    fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
     fimpl->HandleEcComplete = TRUE;
     fimpl->HandleEcRepaint = TRUE;
     fimpl->notif.hWnd = 0;
-    fimpl->notif.disabled = TRUE;
+    fimpl->notif.disabled = FALSE;
     fimpl->nRenderers = 0;
     fimpl->EcCompleteCount = 0;
     fimpl->state = State_Stopped;
Index: dlls/quartz/pin.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/pin.c,v
retrieving revision 1.12
diff -u -r1.12 pin.c
--- dlls/quartz/pin.c	6 Jan 2005 19:36:47 -0000	1.12
+++ dlls/quartz/pin.c	27 Feb 2005 20:48:27 -0000
@@ -1158,7 +1158,7 @@
 
     TRACE("Start\n");
 
-    while (rtCurrent < This->rtStop)
+    while (rtCurrent < This->rtStop && hr == S_OK)
     {
         /* FIXME: to improve performance by quite a bit this should be changed
          * so that one sample is processed while one sample is fetched. However,
Index: dlls/quartz/transform.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/transform.c,v
retrieving revision 1.2
diff -u -r1.2 transform.c
--- dlls/quartz/transform.c	21 Feb 2005 20:37:45 -0000	1.2
+++ dlls/quartz/transform.c	27 Feb 2005 20:48:28 -0000
@@ -495,6 +495,32 @@
     TransformFilter_QueryVendorInfo
 };
 
+HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
+{
+    InputPin* This = (InputPin*) iface;
+    TransformFilterImpl* pTransform;
+    IPin* ppin;
+    HRESULT hr;
+    
+    TRACE("(%p)->()\n", iface);
+
+    /* Since we process samples synchronously, just forward notification downstream */
+    pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
+    if (!pTransform)
+        hr = E_FAIL;
+    else
+        hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
+    if (SUCCEEDED(hr))
+    {
+        hr = IPin_EndOfStream(ppin);
+        IPin_Release(ppin);
+    }
+
+    if (FAILED(hr))
+        ERR("%lx\n", hr);
+    return hr;
+}
+
 static const IPinVtbl TransformFilter_InputPin_Vtbl = 
 {
     InputPin_QueryInterface,
@@ -511,7 +537,7 @@
     IPinImpl_QueryAccept,
     IPinImpl_EnumMediaTypes,
     IPinImpl_QueryInternalConnections,
-    InputPin_EndOfStream,
+    TransformFilter_InputPin_EndOfStream,
     InputPin_BeginFlush,
     InputPin_EndFlush,
     InputPin_NewSegment
Index: dlls/quartz/videorenderer.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/videorenderer.c,v
retrieving revision 1.6
diff -u -r1.6 videorenderer.c
--- dlls/quartz/videorenderer.c	6 Jan 2005 19:36:47 -0000	1.6
+++ dlls/quartz/videorenderer.c	27 Feb 2005 20:48:31 -0000
@@ -34,6 +34,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "dshow.h"
+#include "evcode.h"
 #include "strmif.h"
 #include "ddraw.h"
 
@@ -61,6 +62,7 @@
     REFERENCE_TIME rtStreamStart;
     IReferenceClock * pClock;
     FILTER_INFO filterInfo;
+    IMediaEventSink * pEventSink;
 
     InputPin * pInputPin;
     IPin ** ppPins;
@@ -593,6 +595,7 @@
 static HRESULT WINAPI VideoRenderer_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
 {
     VideoRendererImpl *This = (VideoRendererImpl *)iface;
+    HRESULT hr = S_OK;
 
     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
 
@@ -603,6 +606,15 @@
         else
             *This->filterInfo.achName = '\0';
         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
+
+        This->pEventSink = NULL;
+        if (pGraph)
+        {
+            /* Cache IMediaEventSink interface w/o increasing filtergraph refcount */
+            hr = IFilterGraph_QueryInterface(pGraph, &IID_IMediaEventSink, (LPVOID*)&This->pEventSink);
+            if (SUCCEEDED(hr))
+                IMediaEventSink_Release(This->pEventSink);
+        }
     }
     LeaveCriticalSection(&This->csFilter);
 
@@ -635,6 +647,15 @@
     VideoRenderer_QueryVendorInfo
 };
 
+static HRESULT WINAPI VideoRenderer_InputPin_EndOfStream(IPin * iface)
+{
+    InputPin* This = (InputPin*)iface;
+
+    TRACE("(%p/%p)->()\n", This, iface);
+
+    return IMediaEventSink_Notify(((VideoRendererImpl*)This->pin.pinInfo.pFilter)->pEventSink, EC_COMPLETE, S_OK, 0);
+}
+
 static const IPinVtbl VideoRenderer_InputPin_Vtbl = 
 {
     InputPin_QueryInterface,
@@ -651,7 +672,7 @@
     IPinImpl_QueryAccept,
     IPinImpl_EnumMediaTypes,
     IPinImpl_QueryInternalConnections,
-    InputPin_EndOfStream,
+    VideoRenderer_InputPin_EndOfStream,
     InputPin_BeginFlush,
     InputPin_EndFlush,
     InputPin_NewSegment
Index: dlls/quartz/waveparser.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/waveparser.c,v
retrieving revision 1.1
diff -u -r1.1 waveparser.c
--- dlls/quartz/waveparser.c	10 Feb 2005 17:13:18 -0000	1.1
+++ dlls/quartz/waveparser.c	27 Feb 2005 20:48:32 -0000
@@ -97,7 +97,7 @@
             {
                 TRACE("Skipping sending sample due to error (%lx)\n", hr);
                 This->pCurrentSample = NULL;
-	        return hr;
+                break;
             }
         }
 
@@ -165,6 +165,36 @@
 	    bMoreData = FALSE;
         }
         offset_src += chunk_remaining_bytes;
+    }
+
+    if (tStop >= This->EndOfFile)
+    {
+        int i;
+
+        TRACE("End of file reached\n");
+
+        for (i = 0; i < This->Parser.cStreams; i++)
+        {
+            IPin* ppin;
+            HRESULT hr;
+
+            TRACE("Send End Of Stream to output pin %d\n", i);
+
+            hr = IPin_ConnectedTo(This->Parser.ppPins[i+1], &ppin);
+            if (SUCCEEDED(hr))
+            {
+                hr = IPin_EndOfStream(ppin);
+                IPin_Release(ppin);
+            }
+            if (FAILED(hr))
+            {
+                ERR("%lx\n", hr);
+                break;
+            }
+        }
+
+        /* Force the pullpin thread to stop */
+        hr = S_FALSE;
     }
 
     return hr;
Index: dlls/quartz/tests/filtergraph.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/tests/filtergraph.c,v
retrieving revision 1.4
diff -u -r1.4 filtergraph.c
--- dlls/quartz/tests/filtergraph.c	16 Dec 2004 14:25:15 -0000	1.4
+++ dlls/quartz/tests/filtergraph.c	27 Feb 2005 20:48:32 -0000
@@ -51,6 +51,8 @@
 {
     HRESULT hr;
     IMediaControl* pmc;
+    IMediaEvent* pme;
+    HANDLE hEvent;
 
     hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
     ok(hr==S_OK, "Cannot get IMediaControl interface returned: %lx\n", hr);
@@ -58,13 +60,23 @@
     hr = IMediaControl_Run(pmc);
     ok(hr==S_FALSE, "Cannot run the graph returned: %lx\n", hr);
 
+    hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
+    ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %lx\n", hr);
+
+    hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
+    ok(hr==S_OK, "Cannot get event handle returned: %lx\n", hr);
+
+    /* WaitForSingleObject(hEvent, INFINITE); */
     Sleep(20000);
 
+    hr = IMediaControl_Release(pme);
+    ok(hr==2, "Releasing mediaevent returned: %lx\n", hr);
+
     hr = IMediaControl_Stop(pmc);
     ok(hr==S_OK, "Cannot stop the graph returned: %lx\n", hr);
     
     hr = IMediaControl_Release(pmc);
-    ok(hr==1, "Releasing mediacontrol returned: %lx\n", hr);     
+    ok(hr==1, "Releasing mediacontrol returned: %lx\n", hr);
 }
 
 static void releasefiltergraph()


More information about the wine-patches mailing list