2 * Generic Implementation of IPin Interface
4 * Copyright 2003 Robert Shearman
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "quartz_private.h"
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
32 static const IPinVtbl PullPin_Vtbl
;
34 #define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary))
35 #define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary)))
37 typedef HRESULT (*SendPinFunc
)( IPin
*to
, LPVOID arg
);
39 /** Helper function, there are a lot of places where the error code is inherited
40 * The following rules apply:
42 * Return the first received error code (E_NOTIMPL is ignored)
43 * If no errors occur: return the first received non-error-code that isn't S_OK
45 static HRESULT
updatehres( HRESULT original
, HRESULT
new )
47 if (FAILED( original
) || new == E_NOTIMPL
)
50 if (FAILED( new ) || original
== S_OK
)
56 /** Sends a message from a pin further to other, similar pins
57 * fnMiddle is called on each pin found further on the stream.
58 * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source)
60 * If the pin given is an input pin, the message will be sent downstream to other input pins
61 * If the pin given is an output pin, the message will be sent upstream to other output pins
63 static HRESULT
SendFurther( IPin
*from
, SendPinFunc fnMiddle
, LPVOID arg
, SendPinFunc fnEnd
)
68 HRESULT hr_return
= S_OK
;
69 IEnumPins
*enumpins
= NULL
;
71 PIN_DIRECTION from_dir
;
73 IPin_QueryDirection( from
, &from_dir
);
75 hr
= IPin_QueryInternalConnections( from
, NULL
, &amount
);
76 if (hr
!= E_NOTIMPL
&& amount
)
77 FIXME("Use QueryInternalConnections!\n");
79 pin_info
.pFilter
= NULL
;
80 hr
= IPin_QueryPinInfo( from
, &pin_info
);
84 hr
= IBaseFilter_EnumPins( pin_info
.pFilter
, &enumpins
);
88 hr
= IEnumPins_Reset( enumpins
);
91 hr
= IEnumPins_Next( enumpins
, 1, &pin
, NULL
);
92 if (hr
== VFW_E_ENUM_OUT_OF_SYNC
)
94 hr
= IEnumPins_Reset( enumpins
);
101 IPin_QueryDirection( pin
, &dir
);
104 IPin
*connected
= NULL
;
107 IPin_ConnectedTo( pin
, &connected
);
112 hr_local
= fnMiddle( connected
, arg
);
113 hr_return
= updatehres( hr_return
, hr_local
);
114 IPin_Release(connected
);
131 hr_local
= fnEnd( from
, arg
);
132 hr_return
= updatehres( hr_return
, hr_local
);
137 IEnumPins_Release( enumpins
);
138 if (pin_info
.pFilter
)
139 IBaseFilter_Release( pin_info
.pFilter
);
144 static void Copy_PinInfo(PIN_INFO
* pDest
, const PIN_INFO
* pSrc
)
146 /* Tempting to just do a memcpy, but the name field is
147 128 characters long! We will probably never exceed 10
148 most of the time, so we are better off copying
149 each field manually */
150 strcpyW(pDest
->achName
, pSrc
->achName
);
151 pDest
->dir
= pSrc
->dir
;
152 pDest
->pFilter
= pSrc
->pFilter
;
155 static HRESULT
deliver_endofstream(IPin
* pin
, LPVOID unused
)
157 return IPin_EndOfStream( pin
);
160 static HRESULT
deliver_beginflush(IPin
* pin
, LPVOID unused
)
162 return IPin_BeginFlush( pin
);
165 static HRESULT
deliver_endflush(IPin
* pin
, LPVOID unused
)
167 return IPin_EndFlush( pin
);
170 typedef struct newsegmentargs
172 REFERENCE_TIME tStart
, tStop
;
176 static HRESULT
deliver_newsegment(IPin
*pin
, LPVOID data
)
178 newsegmentargs
*args
= data
;
179 return IPin_NewSegment(pin
, args
->tStart
, args
->tStop
, args
->rate
);
182 /*** PullPin implementation ***/
184 static HRESULT
PullPin_Init(const IPinVtbl
*PullPin_Vtbl
, const PIN_INFO
* pPinInfo
, SAMPLEPROC_PULL pSampleProc
, LPVOID pUserData
,
185 QUERYACCEPTPROC pQueryAccept
, CLEANUPPROC pCleanUp
, REQUESTPROC pCustomRequest
, STOPPROCESSPROC pDone
, LPCRITICAL_SECTION pCritSec
, PullPin
* pPinImpl
)
187 /* Common attributes */
188 pPinImpl
->pin
.IPin_iface
.lpVtbl
= PullPin_Vtbl
;
189 pPinImpl
->pin
.refCount
= 1;
190 pPinImpl
->pin
.pConnectedTo
= NULL
;
191 pPinImpl
->pin
.pCritSec
= pCritSec
;
192 Copy_PinInfo(&pPinImpl
->pin
.pinInfo
, pPinInfo
);
193 ZeroMemory(&pPinImpl
->pin
.mtCurrent
, sizeof(AM_MEDIA_TYPE
));
195 /* Input pin attributes */
196 pPinImpl
->pUserData
= pUserData
;
197 pPinImpl
->fnQueryAccept
= pQueryAccept
;
198 pPinImpl
->fnSampleProc
= pSampleProc
;
199 pPinImpl
->fnCleanProc
= pCleanUp
;
200 pPinImpl
->fnDone
= pDone
;
201 pPinImpl
->fnPreConnect
= NULL
;
202 pPinImpl
->pAlloc
= NULL
;
203 pPinImpl
->prefAlloc
= NULL
;
204 pPinImpl
->pReader
= NULL
;
205 pPinImpl
->hThread
= NULL
;
206 pPinImpl
->hEventStateChanged
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
207 pPinImpl
->thread_sleepy
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
209 pPinImpl
->rtStart
= 0;
210 pPinImpl
->rtCurrent
= 0;
211 pPinImpl
->rtStop
= ((LONGLONG
)0x7fffffff << 32) | 0xffffffff;
212 pPinImpl
->dRate
= 1.0;
213 pPinImpl
->state
= Req_Die
;
214 pPinImpl
->fnCustomRequest
= pCustomRequest
;
215 pPinImpl
->stop_playback
= TRUE
;
217 InitializeCriticalSection(&pPinImpl
->thread_lock
);
218 pPinImpl
->thread_lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)( __FILE__
": PullPin.thread_lock");
223 HRESULT
PullPin_Construct(const IPinVtbl
*PullPin_Vtbl
, const PIN_INFO
* pPinInfo
, SAMPLEPROC_PULL pSampleProc
, LPVOID pUserData
, QUERYACCEPTPROC pQueryAccept
, CLEANUPPROC pCleanUp
, REQUESTPROC pCustomRequest
, STOPPROCESSPROC pDone
, LPCRITICAL_SECTION pCritSec
, IPin
** ppPin
)
229 if (pPinInfo
->dir
!= PINDIR_INPUT
)
231 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo
->dir
);
235 pPinImpl
= CoTaskMemAlloc(sizeof(*pPinImpl
));
238 return E_OUTOFMEMORY
;
240 if (SUCCEEDED(PullPin_Init(PullPin_Vtbl
, pPinInfo
, pSampleProc
, pUserData
, pQueryAccept
, pCleanUp
, pCustomRequest
, pDone
, pCritSec
, pPinImpl
)))
242 *ppPin
= &pPinImpl
->pin
.IPin_iface
;
246 CoTaskMemFree(pPinImpl
);
250 static HRESULT
PullPin_InitProcessing(PullPin
* This
);
252 HRESULT WINAPI
PullPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
254 PIN_DIRECTION pindirReceive
;
256 PullPin
*This
= impl_PullPin_from_IPin(iface
);
258 TRACE("(%p/%p)->(%p, %p)\n", This
, iface
, pReceivePin
, pmt
);
259 dump_AM_MEDIA_TYPE(pmt
);
261 EnterCriticalSection(This
->pin
.pCritSec
);
262 if (!This
->pin
.pConnectedTo
)
264 ALLOCATOR_PROPERTIES props
;
267 props
.cbBuffer
= 64 * 1024; /* 64 KB */
271 if (This
->fnQueryAccept(This
->pUserData
, pmt
) != S_OK
)
272 hr
= VFW_E_TYPE_NOT_ACCEPTED
; /* FIXME: shouldn't we just map common errors onto
273 * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
277 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
279 if (pindirReceive
!= PINDIR_OUTPUT
)
281 ERR("Can't connect from non-output pin\n");
282 hr
= VFW_E_INVALID_DIRECTION
;
286 This
->pReader
= NULL
;
288 This
->prefAlloc
= NULL
;
291 hr
= IPin_QueryInterface(pReceivePin
, &IID_IAsyncReader
, (LPVOID
*)&This
->pReader
);
294 if (SUCCEEDED(hr
) && This
->fnPreConnect
)
296 hr
= This
->fnPreConnect(iface
, pReceivePin
, &props
);
300 * Some custom filters (such as the one used by Fallout 3
301 * and Fallout: New Vegas) expect to be passed a non-NULL
302 * preferred allocator.
306 hr
= StdMemAllocator_create(NULL
, (LPVOID
*) &This
->prefAlloc
);
311 hr
= IAsyncReader_RequestAllocator(This
->pReader
, This
->prefAlloc
, &props
, &This
->pAlloc
);
316 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
317 This
->pin
.pConnectedTo
= pReceivePin
;
318 IPin_AddRef(pReceivePin
);
319 hr
= IMemAllocator_Commit(This
->pAlloc
);
323 hr
= PullPin_InitProcessing(This
);
328 IAsyncReader_Release(This
->pReader
);
329 This
->pReader
= NULL
;
331 IMemAllocator_Release(This
->prefAlloc
);
332 This
->prefAlloc
= NULL
;
334 IMemAllocator_Release(This
->pAlloc
);
339 hr
= VFW_E_ALREADY_CONNECTED
;
340 LeaveCriticalSection(This
->pin
.pCritSec
);
344 HRESULT WINAPI
PullPin_QueryInterface(IPin
* iface
, REFIID riid
, LPVOID
* ppv
)
346 PullPin
*This
= impl_PullPin_from_IPin(iface
);
348 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
352 if (IsEqualIID(riid
, &IID_IUnknown
))
354 else if (IsEqualIID(riid
, &IID_IPin
))
356 else if (IsEqualIID(riid
, &IID_IMediaSeeking
) ||
357 IsEqualIID(riid
, &IID_IQualityControl
))
359 return IBaseFilter_QueryInterface(This
->pin
.pinInfo
.pFilter
, riid
, ppv
);
364 IUnknown_AddRef((IUnknown
*)(*ppv
));
368 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
370 return E_NOINTERFACE
;
373 ULONG WINAPI
PullPin_Release(IPin
*iface
)
375 PullPin
*This
= impl_PullPin_from_IPin(iface
);
376 ULONG refCount
= InterlockedDecrement(&This
->pin
.refCount
);
378 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
382 WaitForSingleObject(This
->hEventStateChanged
, INFINITE
);
383 assert(!This
->hThread
);
386 IMemAllocator_Release(This
->prefAlloc
);
388 IMemAllocator_Release(This
->pAlloc
);
390 IAsyncReader_Release(This
->pReader
);
391 CloseHandle(This
->thread_sleepy
);
392 CloseHandle(This
->hEventStateChanged
);
393 This
->thread_lock
.DebugInfo
->Spare
[0] = 0;
394 DeleteCriticalSection(&This
->thread_lock
);
401 static void PullPin_Flush(PullPin
*This
)
403 IMediaSample
*pSample
;
404 TRACE("Flushing!\n");
408 /* Do not allow state to change while flushing */
409 EnterCriticalSection(This
->pin
.pCritSec
);
411 /* Flush outstanding samples */
412 IAsyncReader_BeginFlush(This
->pReader
);
419 IAsyncReader_WaitForNext(This
->pReader
, 0, &pSample
, &dwUser
);
424 assert(!IMediaSample_GetActualDataLength(pSample
));
426 IMediaSample_Release(pSample
);
429 IAsyncReader_EndFlush(This
->pReader
);
431 LeaveCriticalSection(This
->pin
.pCritSec
);
435 static void PullPin_Thread_Process(PullPin
*This
)
438 IMediaSample
* pSample
= NULL
;
439 ALLOCATOR_PROPERTIES allocProps
;
441 hr
= IMemAllocator_GetProperties(This
->pAlloc
, &allocProps
);
443 This
->cbAlign
= allocProps
.cbAlign
;
445 if (This
->rtCurrent
< This
->rtStart
)
446 This
->rtCurrent
= MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This
->rtStart
), This
->cbAlign
));
450 if (This
->rtCurrent
>= This
->rtStop
)
452 IPin_EndOfStream(&This
->pin
.IPin_iface
);
456 /* There is no sample in our buffer */
457 hr
= This
->fnCustomRequest(This
->pUserData
);
460 ERR("Request error: %x\n", hr
);
462 EnterCriticalSection(This
->pin
.pCritSec
);
463 SetEvent(This
->hEventStateChanged
);
464 LeaveCriticalSection(This
->pin
.pCritSec
);
471 TRACE("Process sample\n");
474 hr
= IAsyncReader_WaitForNext(This
->pReader
, 10000, &pSample
, &dwUser
);
476 /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */
479 hr
= This
->fnSampleProc(This
->pUserData
, pSample
, dwUser
);
483 if (hr
== VFW_E_TIMEOUT
)
486 WARN("Non-NULL sample returned with VFW_E_TIMEOUT.\n");
489 /* FIXME: Errors are not well handled yet! */
491 ERR("Processing error: %x\n", hr
);
496 IMediaSample_Release(pSample
);
499 } while (This
->rtCurrent
< This
->rtStop
&& hr
== S_OK
&& !This
->stop_playback
);
502 * Sample was rejected, and we are asked to terminate. When there is more than one buffer
503 * it is possible for a filter to have several queued samples, making it necessary to
504 * release all of these pending samples.
506 if (This
->stop_playback
|| FAILED(hr
))
513 IMediaSample_Release(pSample
);
515 IAsyncReader_WaitForNext(This
->pReader
, 0, &pSample
, &dwUser
);
519 /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us
520 * Flush remaining samples
523 This
->fnDone(This
->pUserData
);
525 TRACE("End: %08x, %d\n", hr
, This
->stop_playback
);
528 static void PullPin_Thread_Pause(PullPin
*This
)
532 EnterCriticalSection(This
->pin
.pCritSec
);
533 This
->state
= Req_Sleepy
;
534 SetEvent(This
->hEventStateChanged
);
535 LeaveCriticalSection(This
->pin
.pCritSec
);
538 static void PullPin_Thread_Stop(PullPin
*This
)
540 TRACE("(%p)->()\n", This
);
542 EnterCriticalSection(This
->pin
.pCritSec
);
544 CloseHandle(This
->hThread
);
545 This
->hThread
= NULL
;
546 SetEvent(This
->hEventStateChanged
);
548 LeaveCriticalSection(This
->pin
.pCritSec
);
550 IBaseFilter_Release(This
->pin
.pinInfo
.pFilter
);
556 static DWORD WINAPI
PullPin_Thread_Main(LPVOID pv
)
559 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
565 WaitForSingleObject(This
->thread_sleepy
, INFINITE
);
567 TRACE("State: %d\n", This
->state
);
571 case Req_Die
: PullPin_Thread_Stop(This
); break;
572 case Req_Run
: PullPin_Thread_Process(This
); break;
573 case Req_Pause
: PullPin_Thread_Pause(This
); break;
574 case Req_Sleepy
: ERR("Should not be signalled with SLEEPY!\n"); break;
575 default: ERR("Unknown state request: %d\n", This
->state
); break;
581 static HRESULT
PullPin_InitProcessing(PullPin
* This
)
585 TRACE("(%p)->()\n", This
);
587 /* if we are connected */
592 WaitForSingleObject(This
->hEventStateChanged
, INFINITE
);
593 EnterCriticalSection(This
->pin
.pCritSec
);
595 assert(!This
->hThread
);
596 assert(This
->state
== Req_Die
);
597 assert(This
->stop_playback
);
598 assert(WaitForSingleObject(This
->thread_sleepy
, 0) == WAIT_TIMEOUT
);
599 This
->state
= Req_Sleepy
;
601 /* AddRef the filter to make sure it and its pins will be around
602 * as long as the thread */
603 IBaseFilter_AddRef(This
->pin
.pinInfo
.pFilter
);
606 This
->hThread
= CreateThread(NULL
, 0, PullPin_Thread_Main
, This
, 0, &dwThreadId
);
609 hr
= HRESULT_FROM_WIN32(GetLastError());
610 IBaseFilter_Release(This
->pin
.pinInfo
.pFilter
);
615 SetEvent(This
->hEventStateChanged
);
616 /* If assert fails, that means a command was not processed before the thread previously terminated */
618 LeaveCriticalSection(This
->pin
.pCritSec
);
621 TRACE(" -- %x\n", hr
);
626 HRESULT
PullPin_StartProcessing(PullPin
* This
)
628 /* if we are connected */
629 TRACE("(%p)->()\n", This
);
632 assert(This
->hThread
);
634 PullPin_WaitForStateChange(This
, INFINITE
);
636 assert(This
->state
== Req_Sleepy
);
639 assert(WaitForSingleObject(This
->thread_sleepy
, 0) == WAIT_TIMEOUT
);
640 This
->state
= Req_Run
;
641 This
->stop_playback
= FALSE
;
642 ResetEvent(This
->hEventStateChanged
);
643 SetEvent(This
->thread_sleepy
);
649 HRESULT
PullPin_PauseProcessing(PullPin
* This
)
651 /* if we are connected */
652 TRACE("(%p)->()\n", This
);
655 assert(This
->hThread
);
657 PullPin_WaitForStateChange(This
, INFINITE
);
659 EnterCriticalSection(This
->pin
.pCritSec
);
661 assert(!This
->stop_playback
);
662 assert(This
->state
== Req_Run
|| This
->state
== Req_Sleepy
);
664 assert(WaitForSingleObject(This
->thread_sleepy
, 0) == WAIT_TIMEOUT
);
666 This
->state
= Req_Pause
;
667 This
->stop_playback
= TRUE
;
668 ResetEvent(This
->hEventStateChanged
);
669 SetEvent(This
->thread_sleepy
);
671 /* Release any outstanding samples */
674 IMediaSample
*pSample
;
680 IAsyncReader_WaitForNext(This
->pReader
, 0, &pSample
, &dwUser
);
682 IMediaSample_Release(pSample
);
686 LeaveCriticalSection(This
->pin
.pCritSec
);
692 static HRESULT
PullPin_StopProcessing(PullPin
* This
)
694 TRACE("(%p)->()\n", This
);
696 /* if we are alive */
697 assert(This
->hThread
);
699 PullPin_WaitForStateChange(This
, INFINITE
);
701 assert(This
->state
== Req_Pause
|| This
->state
== Req_Sleepy
);
703 This
->stop_playback
= TRUE
;
704 This
->state
= Req_Die
;
705 assert(WaitForSingleObject(This
->thread_sleepy
, 0) == WAIT_TIMEOUT
);
706 ResetEvent(This
->hEventStateChanged
);
707 SetEvent(This
->thread_sleepy
);
711 HRESULT
PullPin_WaitForStateChange(PullPin
* This
, DWORD dwMilliseconds
)
713 if (WaitForSingleObject(This
->hEventStateChanged
, dwMilliseconds
) == WAIT_TIMEOUT
)
718 HRESULT WINAPI
PullPin_QueryAccept(IPin
* iface
, const AM_MEDIA_TYPE
* pmt
)
720 PullPin
*This
= impl_PullPin_from_IPin(iface
);
722 TRACE("(%p/%p)->(%p)\n", This
, iface
, pmt
);
724 return (This
->fnQueryAccept(This
->pUserData
, pmt
) == S_OK
? S_OK
: S_FALSE
);
727 HRESULT WINAPI
PullPin_EndOfStream(IPin
* iface
)
729 PullPin
*This
= impl_PullPin_from_IPin(iface
);
730 HRESULT hr
= S_FALSE
;
732 TRACE("(%p)->()\n", iface
);
734 EnterCriticalSection(This
->pin
.pCritSec
);
735 hr
= SendFurther( iface
, deliver_endofstream
, NULL
, NULL
);
736 SetEvent(This
->hEventStateChanged
);
737 LeaveCriticalSection(This
->pin
.pCritSec
);
742 HRESULT WINAPI
PullPin_BeginFlush(IPin
* iface
)
744 PullPin
*This
= impl_PullPin_from_IPin(iface
);
745 TRACE("(%p)->()\n", This
);
747 EnterCriticalSection(This
->pin
.pCritSec
);
749 SendFurther( iface
, deliver_beginflush
, NULL
, NULL
);
751 LeaveCriticalSection(This
->pin
.pCritSec
);
753 EnterCriticalSection(&This
->thread_lock
);
756 IAsyncReader_BeginFlush(This
->pReader
);
757 PullPin_WaitForStateChange(This
, INFINITE
);
759 if (This
->hThread
&& This
->state
== Req_Run
)
761 PullPin_PauseProcessing(This
);
762 PullPin_WaitForStateChange(This
, INFINITE
);
765 LeaveCriticalSection(&This
->thread_lock
);
767 EnterCriticalSection(This
->pin
.pCritSec
);
769 This
->fnCleanProc(This
->pUserData
);
771 LeaveCriticalSection(This
->pin
.pCritSec
);
776 HRESULT WINAPI
PullPin_EndFlush(IPin
* iface
)
778 PullPin
*This
= impl_PullPin_from_IPin(iface
);
780 TRACE("(%p)->()\n", iface
);
782 /* Send further first: Else a race condition might terminate processing early */
783 EnterCriticalSection(This
->pin
.pCritSec
);
784 SendFurther( iface
, deliver_endflush
, NULL
, NULL
);
785 LeaveCriticalSection(This
->pin
.pCritSec
);
787 EnterCriticalSection(&This
->thread_lock
);
792 IAsyncReader_EndFlush(This
->pReader
);
794 IBaseFilter_GetState(This
->pin
.pinInfo
.pFilter
, INFINITE
, &state
);
796 if (state
!= State_Stopped
)
797 PullPin_StartProcessing(This
);
799 PullPin_WaitForStateChange(This
, INFINITE
);
801 LeaveCriticalSection(&This
->thread_lock
);
806 HRESULT WINAPI
PullPin_Disconnect(IPin
*iface
)
809 PullPin
*This
= impl_PullPin_from_IPin(iface
);
813 EnterCriticalSection(This
->pin
.pCritSec
);
815 if (FAILED(hr
= IMemAllocator_Decommit(This
->pAlloc
)))
816 ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr
);
818 if (This
->pin
.pConnectedTo
)
820 IPin_Release(This
->pin
.pConnectedTo
);
821 This
->pin
.pConnectedTo
= NULL
;
822 PullPin_StopProcessing(This
);
824 FreeMediaType(&This
->pin
.mtCurrent
);
825 ZeroMemory(&This
->pin
.mtCurrent
, sizeof(This
->pin
.mtCurrent
));
831 LeaveCriticalSection(This
->pin
.pCritSec
);
836 HRESULT WINAPI
PullPin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
839 FIXME("(%p)->(%s, %s, %g) stub\n", iface
, wine_dbgstr_longlong(tStart
), wine_dbgstr_longlong(tStop
), dRate
);
841 args
.tStart
= tStart
;
845 return SendFurther( iface
, deliver_newsegment
, &args
, NULL
);
848 static const IPinVtbl PullPin_Vtbl
=
850 PullPin_QueryInterface
,
853 BaseInputPinImpl_Connect
,
854 PullPin_ReceiveConnection
,
856 BasePinImpl_ConnectedTo
,
857 BasePinImpl_ConnectionMediaType
,
858 BasePinImpl_QueryPinInfo
,
859 BasePinImpl_QueryDirection
,
862 BasePinImpl_EnumMediaTypes
,
863 BasePinImpl_QueryInternalConnections
,