[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