quartz: Handle flushing and end of stream notifications for input pins.
authorMaarten Lankhorst <m.b.lankhorst@gmail.com>
Fri, 4 Apr 2008 23:27:29 +0000 (16:27 -0700)
committerAlexandre Julliard <julliard@winehq.org>
Mon, 7 Apr 2008 09:35:36 +0000 (11:35 +0200)
dlls/quartz/dsoundrender.c
dlls/quartz/nullrenderer.c
dlls/quartz/pin.c
dlls/quartz/pin.h
dlls/quartz/transform.c
dlls/quartz/videorenderer.c

index 7a2d461e4ec65f926ef6a70bdf94e45ae15c8224..0cfd163db5ccf9385ab4f8ecb8ccde894342673c 100644 (file)
@@ -96,14 +96,39 @@ static HRESULT sound_mod_rate(IBaseFilter *iface)
     return S_OK;
 }
 
-static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, DWORD *pWritePos, REFERENCE_TIME *pRefTime)
+static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
 {
     HRESULT hr;
 
     EnterCriticalSection(&This->csFilter);
     {
-        hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, pWritePos);
-        if (hr == DS_OK)
+        DWORD state;
+
+        hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
+        if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
+        {
+            LPBYTE buf;
+            DWORD size;
+            TRACE("Not playing, kickstarting the engine\n");
+            This->write_pos = 0;
+            IDirectSoundBuffer_SetCurrentPosition(This->dsbuffer, 0);
+
+            hr = IDirectSoundBuffer_Lock(This->dsbuffer, 0, 0, (void**)&buf, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
+            if (hr != DS_OK)
+                ERR("Unable to lock sound buffer! (%x)\n", hr);
+            else
+                memset(buf, 0, size);
+            hr = IDirectSoundBuffer_Unlock(This->dsbuffer, buf, size, NULL, 0);
+
+            hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
+            if (FAILED(hr))
+                ERR("Can't play sound buffer (%x)\n", hr);
+            hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, &This->last_play_pos, &This->write_pos);
+            *pPlayPos = This->last_play_pos;
+        }
+        else if (SUCCEEDED(hr))
+            hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, NULL);
+        if (hr == S_OK)
         {
             DWORD play_pos = *pPlayPos;
 
@@ -139,7 +164,7 @@ static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPo
 
 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
 {
-    HRESULT hr;
+    HRESULT hr = S_OK;
     LPBYTE lpbuf1 = NULL;
     LPBYTE lpbuf2 = NULL;
     DWORD dwsize1 = 0;
@@ -147,8 +172,9 @@ static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *d
     DWORD size2;
     DWORD play_pos,buf_free;
 
-    do {
-        hr = DSoundRender_GetPos(This, &play_pos, NULL, NULL);
+    while (size && This->state == State_Running && !This->pInputPin->flushing) {
+
+        hr = DSoundRender_GetPos(This, &play_pos, NULL);
         if (hr != DS_OK)
         {
             ERR("GetPos returned error: %x\n", hr);
@@ -190,7 +216,7 @@ static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *d
             This->write_pos -= This->buf_size;
             This->write_loops++;
         }
-    } while (size && This->state == State_Running);
+    }
 
     return hr;
 }
@@ -205,9 +231,9 @@ static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
 
     TRACE("%p %p\n", iface, pSample);
 
-    if (This->state != State_Running)
+    if (This->state == State_Stopped)
         return VFW_E_WRONG_STATE;
-    
+
     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
     if (FAILED(hr))
     {
@@ -463,6 +489,9 @@ static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
     EnterCriticalSection(&This->csFilter);
     {
         DWORD state = 0;
+        if (This->state == State_Stopped)
+            This->pInputPin->end_of_stream = 0;
+
         if (This->dsbuffer)
         {
             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
@@ -489,27 +518,9 @@ static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStar
 
     EnterCriticalSection(&This->csFilter);
     {
-        /* It's okay if there's no buffer yet. It'll start when it's created */
-        if (This->dsbuffer)
-        {
-            if (This->state == State_Stopped)
-            {
-                char *buf1;
-                DWORD size1;
-
-                IDirectSoundBuffer_Lock(This->dsbuffer, 0, 0, (void**)&buf1, &size1, NULL, NULL, DSBLOCK_ENTIREBUFFER);
-                memset(buf1, 0, size1);
-                IDirectSoundBuffer_Unlock(This->dsbuffer, buf1, size1, NULL, 0);
-            }
-            hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
-            if (FAILED(hr))
-                ERR("Can't start playing! (%x)\n", hr);
-        }
-        if (SUCCEEDED(hr))
-        {
-            This->rtStreamStart = tStart;
-            This->state = State_Running;
-        }
+        This->rtStreamStart = tStart;
+        This->state = State_Running;
+        This->pInputPin->end_of_stream = 0;
     }
     LeaveCriticalSection(&This->csFilter);
 
@@ -722,10 +733,6 @@ static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin
 
             DSImpl->write_pos = 0;
             hr = S_OK;
-            if (DSImpl->state == State_Running)
-                hr = IDirectSoundBuffer_Play(DSImpl->dsbuffer, 0, 0, DSBPLAY_LOOPING);
-            if (FAILED(hr))
-                ERR("Can't play sound buffer (%x)\n", hr);
         }
 
         if (SUCCEEDED(hr))
@@ -791,6 +798,23 @@ static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
     return hr;
 }
 
+static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
+{
+    InputPin *This = (InputPin *)iface;
+    DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
+    HRESULT hr;
+
+    hr = InputPin_BeginFlush(iface);
+
+    FIXME("Requested flush\n");
+    EnterCriticalSection(This->pin.pCritSec);
+    if (pFilter->dsbuffer)
+        IDirectSoundBuffer_Stop(pFilter->dsbuffer);
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    return hr;
+}
+
 static const IPinVtbl DSoundRender_InputPin_Vtbl =
 {
     InputPin_QueryInterface,
@@ -808,7 +832,7 @@ static const IPinVtbl DSoundRender_InputPin_Vtbl =
     IPinImpl_EnumMediaTypes,
     IPinImpl_QueryInternalConnections,
     DSoundRender_InputPin_EndOfStream,
-    InputPin_BeginFlush,
+    DSoundRender_InputPin_BeginFlush,
     InputPin_EndFlush,
     InputPin_NewSegment
 };
@@ -1023,7 +1047,7 @@ static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
     TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
 
     if (This->dsbuffer)
-        hr = DSoundRender_GetPos(This, &play_pos, NULL, pTime);
+        hr = DSoundRender_GetPos(This, &play_pos, pTime);
     if (FAILED(hr))
         ERR("Could not get reference time (%x)!\n", hr);
 
index 131ea7e2dfc84372050af95482d2716ec586d5af..191771b8c403eb58ddb0b43ae57305162704091b 100644 (file)
@@ -394,6 +394,8 @@ static HRESULT WINAPI NullRenderer_Pause(IBaseFilter * iface)
 
     EnterCriticalSection(&This->csFilter);
     {
+        if (This->state == State_Stopped)
+            This->pInputPin->end_of_stream = 0;
         This->state = State_Paused;
     }
     LeaveCriticalSection(&This->csFilter);
@@ -411,6 +413,7 @@ static HRESULT WINAPI NullRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStar
     {
         This->rtStreamStart = tStart;
         This->state = State_Running;
+        This->pInputPin->end_of_stream = 0;
     }
     LeaveCriticalSection(&This->csFilter);
 
index d88b7627f135ea23e3f90a56272df927c98cf783..f762eb8b5b08d4afd43a095f123ff4c9a56fd27f 100644 (file)
@@ -248,6 +248,7 @@ static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPi
     pPinImpl->dRate = 0;
     pPinImpl->pin.lpVtbl = InputPin_Vtbl;
     pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
+    pPinImpl->flushing = pPinImpl->end_of_stream = 0;
 
     return S_OK;
 }
@@ -598,12 +599,10 @@ static HRESULT deliver_endofstream(IPin* pin, LPVOID unused)
 
 HRESULT WINAPI InputPin_EndOfStream(IPin * iface)
 {
-    FIXME("() stub\n");
+    InputPin *This = (InputPin *)iface;
+    TRACE("(%p)\n", This);
 
-    /* Should do an end of stream notification?
-     * Also, don't accept any more samples from now!
-     * TODO: Don't accept any more packets
-     */
+    This->end_of_stream = 1;
 
     return SendFurther( iface, deliver_endofstream, NULL, NULL );
 }
@@ -615,10 +614,21 @@ static HRESULT deliver_beginflush(IPin* pin, LPVOID unused)
 
 HRESULT WINAPI InputPin_BeginFlush(IPin * iface)
 {
-    FIXME("() stub\n");
+    InputPin *This = (InputPin *)iface;
+    HRESULT hr;
+    TRACE("() semi-stub\n");
+
+    /* Assign this outside the critical section so that _Receive loops can be broken */
+    This->flushing = 1;
+
+    EnterCriticalSection(This->pin.pCritSec);
 
-    /* TODO: Drop all cached packets, and don't accept any more samples! */
-    return SendFurther( iface, deliver_beginflush, NULL, NULL );
+    if (This->fnCleanProc)
+        This->fnCleanProc(This->pin.pUserData);
+
+    hr = SendFurther( iface, deliver_beginflush, NULL, NULL );
+    LeaveCriticalSection(This->pin.pCritSec);
+    return hr;
 }
 
 static HRESULT deliver_endflush(IPin* pin, LPVOID unused)
@@ -628,10 +638,17 @@ static HRESULT deliver_endflush(IPin* pin, LPVOID unused)
 
 HRESULT WINAPI InputPin_EndFlush(IPin * iface)
 {
-    FIXME("() stub\n");
+    InputPin *This = (InputPin *)iface;
+    HRESULT hr;
+    TRACE("(%p)\n", This);
 
-    /* TODO: Accept any samples again */
-    return SendFurther( iface, deliver_endflush, NULL, NULL );
+    EnterCriticalSection(This->pin.pCritSec);
+    This->flushing = 0;
+
+    hr = SendFurther( iface, deliver_endflush, NULL, NULL );
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    return hr;
 }
 
 typedef struct newsegmentargs
@@ -747,11 +764,18 @@ HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCA
 HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
 {
     InputPin *This = impl_from_IMemInputPin(iface);
+    HRESULT hr;
 
     /* this trace commented out for performance reasons */
     /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
 
-    return This->fnSampleProc(This->pin.pUserData, pSample);
+    EnterCriticalSection(This->pin.pCritSec);
+    if (!This->end_of_stream && !This->flushing && !This->end_of_stream)
+        hr = This->fnSampleProc(This->pin.pUserData, pSample);
+    else
+        hr = S_FALSE;
+    LeaveCriticalSection(This->pin.pCritSec);
+    return hr;
 }
 
 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
index 0991963e6b79ce9375754500f9ba731cfa04df26..f97a33dce20f0761252625a846357e848411ceb4 100644 (file)
@@ -67,6 +67,7 @@ typedef struct InputPin
        REFERENCE_TIME tStart;
        REFERENCE_TIME tStop;
        double dRate;
+       BOOL flushing, end_of_stream;
 } InputPin;
 
 typedef struct OutputPin
index 5928ba39995a5f88aa83d57136f4f945375dbf93..85962d1850541e925aa5b5db82c52392bc31e745 100644 (file)
@@ -341,6 +341,9 @@ static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface)
 
     EnterCriticalSection(&This->csFilter);
     {
+        if (This->state == State_Stopped)
+            ((InputPin *)This->ppPins[0])->end_of_stream = 0;
+
         This->state = State_Paused;
     }
     LeaveCriticalSection(&This->csFilter);
@@ -357,6 +360,9 @@ static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tS
 
     EnterCriticalSection(&This->csFilter);
     {
+        if (This->state == State_Stopped)
+            ((InputPin *)This->ppPins[0])->end_of_stream = 0;
+
         This->rtStreamStart = tStart;
         This->state = State_Running;
         OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
index b331211c4a10fc588e91446e82e26a4a7adffa08..f363b82ed1d378424c924e1edaecc1f2aa2b689a 100644 (file)
@@ -645,6 +645,9 @@ static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface)
 
     EnterCriticalSection(&This->csFilter);
     {
+        if (This->state == State_Stopped)
+            This->pInputPin->end_of_stream = 0;
+
         This->state = State_Paused;
     }
     LeaveCriticalSection(&This->csFilter);
@@ -660,6 +663,9 @@ static HRESULT WINAPI VideoRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tSta
 
     EnterCriticalSection(&This->csFilter);
     {
+        if (This->state == State_Stopped)
+            This->pInputPin->end_of_stream = 0;
+
         This->rtStreamStart = tStart;
         This->state = State_Running;
     }