Commit 7dea79c4 authored by Christian Costa's avatar Christian Costa Committed by Alexandre Julliard

Handle End Of Stream notifications.

Some AVI Splitter fixes.
parent 46ebd667
......@@ -55,11 +55,14 @@ typedef struct AVISplitterImpl
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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
{
/* 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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
{
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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
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;
}
......
......@@ -58,7 +58,6 @@ typedef struct DSoundRenderImpl
REFERENCE_TIME rtStreamStart;
IReferenceClock * pClock;
FILTER_INFO filterInfo;
IMediaEventSink * pEventSink;
InputPin * pInputPin;
IPin ** ppPins;
......@@ -550,7 +549,6 @@ static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_I
static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
{
HRESULT hr;
DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
......@@ -562,12 +560,10 @@ static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterG
else
*This->filterInfo.achName = '\0';
This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
hr = IFilterGraph_QueryInterface(pGraph, &IID_IMediaEventSink, (LPVOID*)&This->pEventSink);
}
LeaveCriticalSection(&This->csFilter);
return hr;
return S_OK;
}
static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
......@@ -598,12 +594,21 @@ static const IBaseFilterVtbl DSoundRender_Vtbl =
static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
{
/* FIXME: critical section */
InputPin* This = (InputPin*)iface;
IMediaEventSink* pEventSink;
HRESULT hr;
TRACE("(%p/%p)->()\n", This, iface);
return IMediaEventSink_Notify(((DSoundRenderImpl*)This->pin.pinInfo.pFilter)->pEventSink, EC_COMPLETE, S_OK, 0);
hr = IFilterGraph_QueryInterface(((DSoundRenderImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
if (SUCCEEDED(hr))
{
/* FIXME: We should wait that all audio data has been played */
hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
IMediaEventSink_Release(pEventSink);
}
return hr;
}
static const IPinVtbl DSoundRender_InputPin_Vtbl =
......
......@@ -2995,30 +2995,35 @@ static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, long EventCo
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 @@ HRESULT FILTERGRAPH_create(IUnknown *pUnkOuter, LPVOID *ppObj) {
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;
......
......@@ -1158,7 +1158,7 @@ static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
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,
......
......@@ -51,6 +51,8 @@ static void rungraph()
{
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 @@ static void rungraph()
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()
......
......@@ -495,6 +495,32 @@ static const IBaseFilterVtbl TransformFilter_Vtbl =
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 @@ static const IPinVtbl TransformFilter_InputPin_Vtbl =
IPinImpl_QueryAccept,
IPinImpl_EnumMediaTypes,
IPinImpl_QueryInternalConnections,
InputPin_EndOfStream,
TransformFilter_InputPin_EndOfStream,
InputPin_BeginFlush,
InputPin_EndFlush,
InputPin_NewSegment
......
......@@ -34,6 +34,7 @@
#include "windef.h"
#include "winbase.h"
#include "dshow.h"
#include "evcode.h"
#include "strmif.h"
#include "ddraw.h"
......@@ -635,6 +636,24 @@ static const IBaseFilterVtbl VideoRenderer_Vtbl =
VideoRenderer_QueryVendorInfo
};
static HRESULT WINAPI VideoRenderer_InputPin_EndOfStream(IPin * iface)
{
InputPin* This = (InputPin*)iface;
IMediaEventSink* pEventSink;
HRESULT hr;
TRACE("(%p/%p)->()\n", This, iface);
hr = IFilterGraph_QueryInterface(((VideoRendererImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
if (SUCCEEDED(hr))
{
hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
IMediaEventSink_Release(pEventSink);
}
return hr;
}
static const IPinVtbl VideoRenderer_InputPin_Vtbl =
{
InputPin_QueryInterface,
......@@ -651,7 +670,7 @@ static const IPinVtbl VideoRenderer_InputPin_Vtbl =
IPinImpl_QueryAccept,
IPinImpl_EnumMediaTypes,
IPinImpl_QueryInternalConnections,
InputPin_EndOfStream,
VideoRenderer_InputPin_EndOfStream,
InputPin_BeginFlush,
InputPin_EndFlush,
InputPin_NewSegment
......
......@@ -97,7 +97,7 @@ static HRESULT WAVEParser_Sample(LPVOID iface, IMediaSample * pSample)
{
TRACE("Skipping sending sample due to error (%lx)\n", hr);
This->pCurrentSample = NULL;
return hr;
break;
}
}
......@@ -167,6 +167,36 @@ static HRESULT WAVEParser_Sample(LPVOID iface, IMediaSample * pSample)
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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment