quartz: Fix parser and pins logic to no longer deadlock.
[wine/wine-gecko.git] / dlls / quartz / parser.c
blobb09b397be794b1a341ce1584b743125a7cbd13e9
1 /*
2 * Parser (Base for parsers and splitters)
4 * Copyright 2003 Robert Shearman
5 * Copyright 2004-2005 Christian Costa
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "quartz_private.h"
23 #include "control_private.h"
24 #include "pin.h"
26 #include "vfwmsgs.h"
27 #include "amvideo.h"
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
32 #include <math.h>
33 #include <assert.h>
35 #include "parser.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
39 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
40 static const IBaseFilterVtbl Parser_Vtbl;
41 static const IMediaSeekingVtbl Parser_Seeking_Vtbl;
42 static const IPinVtbl Parser_OutputPin_Vtbl;
43 static const IPinVtbl Parser_InputPin_Vtbl;
45 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt);
46 static HRESULT Parser_ChangeCurrent(IBaseFilter *iface);
47 static HRESULT Parser_ChangeStop(IBaseFilter *iface);
48 static HRESULT Parser_ChangeRate(IBaseFilter *iface);
50 static HRESULT Parser_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
52 static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
54 return (ParserImpl *)((char*)iface - FIELD_OFFSET(ParserImpl, mediaSeeking.lpVtbl));
58 HRESULT Parser_Create(ParserImpl* pParser, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate)
60 HRESULT hr;
61 PIN_INFO piInput;
63 /* pTransformFilter is already allocated */
64 pParser->clsid = *pClsid;
66 pParser->lpVtbl = &Parser_Vtbl;
67 pParser->refCount = 1;
68 InitializeCriticalSection(&pParser->csFilter);
69 pParser->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ParserImpl.csFilter");
70 pParser->state = State_Stopped;
71 pParser->pClock = NULL;
72 pParser->fnCleanup = fnCleanup;
73 ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO));
75 pParser->cStreams = 0;
76 pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
78 /* construct input pin */
79 piInput.dir = PINDIR_INPUT;
80 piInput.pFilter = (IBaseFilter *)pParser;
81 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
83 if (!current)
84 current = Parser_ChangeCurrent;
86 if (!stop)
87 stop = Parser_ChangeStop;
89 if (!rate)
90 rate = Parser_ChangeRate;
92 MediaSeekingImpl_Init((IBaseFilter*)pParser, stop, current, rate, &pParser->mediaSeeking, &pParser->csFilter);
93 pParser->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl;
95 hr = Parser_InputPin_Construct(&piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, &pParser->csFilter, (IPin **)&pParser->pInputPin);
97 if (SUCCEEDED(hr))
99 pParser->ppPins[0] = (IPin *)pParser->pInputPin;
100 pParser->pInputPin->fnPreConnect = fnPreConnect;
102 else
104 CoTaskMemFree(pParser->ppPins);
105 pParser->csFilter.DebugInfo->Spare[0] = 0;
106 DeleteCriticalSection(&pParser->csFilter);
107 CoTaskMemFree(pParser);
110 return hr;
113 static HRESULT Parser_OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, const AM_MEDIA_TYPE * pmt, LPCRITICAL_SECTION pCritSec, Parser_OutputPin * pPinImpl)
115 pPinImpl->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
116 CopyMediaType(pPinImpl->pmt, pmt);
117 pPinImpl->dwSamplesProcessed = 0;
119 return OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, &pPinImpl->pin);
122 static HRESULT Parser_OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, const AM_MEDIA_TYPE * pmt, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
124 Parser_OutputPin * pPinImpl;
126 *ppPin = NULL;
128 assert(pPinInfo->dir == PINDIR_OUTPUT);
130 pPinImpl = CoTaskMemAlloc(sizeof(Parser_OutputPin));
132 if (!pPinImpl)
133 return E_OUTOFMEMORY;
135 if (SUCCEEDED(Parser_OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pmt, pCritSec, pPinImpl)))
137 pPinImpl->pin.pin.lpVtbl = &Parser_OutputPin_Vtbl;
139 *ppPin = (IPin *)pPinImpl;
140 return S_OK;
143 CoTaskMemFree(pPinImpl);
144 return E_FAIL;
147 static HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
149 ParserImpl *This = (ParserImpl *)iface;
150 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
152 *ppv = NULL;
154 if (IsEqualIID(riid, &IID_IUnknown))
155 *ppv = (LPVOID)This;
156 else if (IsEqualIID(riid, &IID_IPersist))
157 *ppv = (LPVOID)This;
158 else if (IsEqualIID(riid, &IID_IMediaFilter))
159 *ppv = (LPVOID)This;
160 else if (IsEqualIID(riid, &IID_IBaseFilter))
161 *ppv = (LPVOID)This;
162 else if (IsEqualIID(riid, &IID_IMediaSeeking))
163 *ppv = (LPVOID)&This->mediaSeeking;
165 if (*ppv)
167 IUnknown_AddRef((IUnknown *)(*ppv));
168 return S_OK;
171 if (!IsEqualIID(riid, &IID_IPin))
172 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
174 return E_NOINTERFACE;
177 static ULONG WINAPI Parser_AddRef(IBaseFilter * iface)
179 ParserImpl *This = (ParserImpl *)iface;
180 ULONG refCount = InterlockedIncrement(&This->refCount);
182 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
184 return refCount;
187 static ULONG WINAPI Parser_Release(IBaseFilter * iface)
189 ParserImpl *This = (ParserImpl *)iface;
190 ULONG refCount = InterlockedDecrement(&This->refCount);
192 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
194 if (!refCount)
196 ULONG i;
198 if (This->fnCleanup)
199 This->fnCleanup(This);
201 if (This->pClock)
202 IReferenceClock_Release(This->pClock);
204 for (i = 0; i < This->cStreams + 1; i++)
206 IPin *pConnectedTo;
208 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
210 IPin_Disconnect(pConnectedTo);
211 IPin_Release(pConnectedTo);
213 IPin_Disconnect(This->ppPins[i]);
215 IPin_Release(This->ppPins[i]);
218 CoTaskMemFree(This->ppPins);
219 This->lpVtbl = NULL;
221 This->csFilter.DebugInfo->Spare[0] = 0;
222 DeleteCriticalSection(&This->csFilter);
224 TRACE("Destroying parser\n");
225 CoTaskMemFree(This);
227 return 0;
229 else
230 return refCount;
233 /** IPersist methods **/
235 static HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid)
237 ParserImpl *This = (ParserImpl *)iface;
239 TRACE("(%p)\n", pClsid);
241 *pClsid = This->clsid;
243 return S_OK;
246 /** IMediaFilter methods **/
248 static HRESULT WINAPI Parser_Stop(IBaseFilter * iface)
250 HRESULT hr;
251 ParserImpl *This = (ParserImpl *)iface;
253 TRACE("()\n");
255 EnterCriticalSection(&This->csFilter);
257 if (This->state == State_Stopped)
259 LeaveCriticalSection(&This->csFilter);
260 return S_OK;
262 This->state = State_Stopped;
264 LeaveCriticalSection(&This->csFilter);
266 hr = PullPin_StopProcessing(This->pInputPin);
267 return hr;
270 static HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
272 HRESULT hr = S_OK;
273 BOOL bInit;
274 ParserImpl *This = (ParserImpl *)iface;
276 TRACE("()\n");
278 EnterCriticalSection(&This->csFilter);
280 if (This->state == State_Paused)
282 LeaveCriticalSection(&This->csFilter);
283 return S_OK;
285 bInit = (This->state == State_Stopped);
286 This->state = State_Paused;
288 LeaveCriticalSection(&This->csFilter);
290 if (bInit)
292 unsigned int i;
294 if (SUCCEEDED(hr))
295 hr = PullPin_InitProcessing(This->pInputPin);
297 if (SUCCEEDED(hr))
299 for (i = 1; i < This->cStreams + 1; i++)
301 LONGLONG duration;
302 DOUBLE speed;
304 IMediaSeeking_GetDuration((IMediaSeeking *)&This->mediaSeeking, &duration);
305 IMediaSeeking_GetRate((IMediaSeeking *)&This->mediaSeeking, &speed);
306 OutputPin_DeliverNewSegment((OutputPin *)This->ppPins[i], 0, duration, speed);
307 OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
310 /* FIXME: this is a little hacky: we have to deliver (at least?) one sample
311 * to each renderer before they will complete their transitions. We should probably
312 * seek through the stream for the first of each, rather than do it this way which is
313 * probably a bit prone to deadlocking */
314 hr = PullPin_StartProcessing(This->pInputPin);
317 /* FIXME: else pause thread */
319 if (SUCCEEDED(hr))
320 hr = PullPin_PauseProcessing(This->pInputPin);
322 return hr;
325 static HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
327 HRESULT hr = S_OK;
328 ParserImpl *This = (ParserImpl *)iface;
329 int i;
331 TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
333 EnterCriticalSection(&This->csFilter);
335 if (This->state == State_Running)
337 LeaveCriticalSection(&This->csFilter);
338 return S_OK;
341 This->rtStreamStart = tStart;
343 if (SUCCEEDED(hr) && (This->state == State_Stopped))
345 LeaveCriticalSection(&This->csFilter);
346 hr = PullPin_InitProcessing(This->pInputPin);
347 EnterCriticalSection(&This->csFilter);
349 if (SUCCEEDED(hr))
351 for (i = 1; i < (This->cStreams + 1); i++)
353 OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
358 if (SUCCEEDED(hr))
360 LeaveCriticalSection(&This->csFilter);
361 hr = PullPin_StartProcessing(This->pInputPin);
362 EnterCriticalSection(&This->csFilter);
365 if (SUCCEEDED(hr))
366 This->state = State_Running;
368 LeaveCriticalSection(&This->csFilter);
370 return hr;
373 static HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
375 ParserImpl *This = (ParserImpl *)iface;
377 TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
379 EnterCriticalSection(&This->csFilter);
381 *pState = This->state;
383 LeaveCriticalSection(&This->csFilter);
385 /* FIXME: this is a little bit unsafe, but I don't see that we can do this
386 * while in the critical section. Maybe we could copy the pointer and addref in the
387 * critical section and then release after this.
389 if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
390 return VFW_S_STATE_INTERMEDIATE;
392 return S_OK;
395 static HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
397 ParserImpl *This = (ParserImpl *)iface;
399 TRACE("(%p)\n", pClock);
401 EnterCriticalSection(&This->csFilter);
403 if (This->pClock)
404 IReferenceClock_Release(This->pClock);
405 This->pClock = pClock;
406 if (This->pClock)
407 IReferenceClock_AddRef(This->pClock);
409 LeaveCriticalSection(&This->csFilter);
411 return S_OK;
414 static HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
416 ParserImpl *This = (ParserImpl *)iface;
418 TRACE("(%p)\n", ppClock);
420 EnterCriticalSection(&This->csFilter);
422 *ppClock = This->pClock;
423 if (This->pClock)
424 IReferenceClock_AddRef(This->pClock);
426 LeaveCriticalSection(&This->csFilter);
428 return S_OK;
431 /** IBaseFilter implementation **/
433 static HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
435 ENUMPINDETAILS epd;
436 ParserImpl *This = (ParserImpl *)iface;
438 TRACE("(%p)\n", ppEnum);
440 epd.cPins = This->cStreams + 1; /* +1 for input pin */
441 epd.ppPins = This->ppPins;
442 return IEnumPinsImpl_Construct(&epd, ppEnum);
445 static HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
447 FIXME("(%p)->(%s,%p)\n", iface, debugstr_w(Id), ppPin);
449 /* FIXME: critical section */
451 return E_NOTIMPL;
454 static HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
456 ParserImpl *This = (ParserImpl *)iface;
458 TRACE("(%p)\n", pInfo);
460 strcpyW(pInfo->achName, This->filterInfo.achName);
461 pInfo->pGraph = This->filterInfo.pGraph;
463 if (pInfo->pGraph)
464 IFilterGraph_AddRef(pInfo->pGraph);
466 return S_OK;
469 static HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
471 HRESULT hr = S_OK;
472 ParserImpl *This = (ParserImpl *)iface;
474 TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
476 EnterCriticalSection(&This->csFilter);
478 if (pName)
479 strcpyW(This->filterInfo.achName, pName);
480 else
481 *This->filterInfo.achName = '\0';
482 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
484 LeaveCriticalSection(&This->csFilter);
486 return hr;
489 static HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
491 TRACE("(%p)\n", pVendorInfo);
492 return E_NOTIMPL;
495 static const IBaseFilterVtbl Parser_Vtbl =
497 Parser_QueryInterface,
498 Parser_AddRef,
499 Parser_Release,
500 Parser_GetClassID,
501 Parser_Stop,
502 Parser_Pause,
503 Parser_Run,
504 Parser_GetState,
505 Parser_SetSyncSource,
506 Parser_GetSyncSource,
507 Parser_EnumPins,
508 Parser_FindPin,
509 Parser_QueryFilterInfo,
510 Parser_JoinFilterGraph,
511 Parser_QueryVendorInfo
514 HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt)
516 IPin ** ppOldPins;
517 HRESULT hr;
519 ppOldPins = This->ppPins;
521 This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *));
522 memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
524 hr = Parser_OutputPin_Construct(piOutput, props, NULL, Parser_OutputPin_QueryAccept, amt, &This->csFilter, This->ppPins + This->cStreams + 1);
526 if (SUCCEEDED(hr))
528 ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1];
529 This->cStreams++;
530 CoTaskMemFree(ppOldPins);
532 else
534 CoTaskMemFree(This->ppPins);
535 This->ppPins = ppOldPins;
536 ERR("Failed with error %x\n", hr);
539 return hr;
542 static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
544 /* NOTE: should be in critical section when calling this function */
546 ULONG i;
547 IPin ** ppOldPins = This->ppPins;
549 /* reduce the pin array down to 1 (just our input pin) */
550 This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1);
551 memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
553 for (i = 0; i < This->cStreams; i++)
555 OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
556 IPin_Release(ppOldPins[i + 1]);
559 This->cStreams = 0;
560 CoTaskMemFree(ppOldPins);
562 return S_OK;
565 static HRESULT Parser_ChangeCurrent(IBaseFilter *iface)
567 FIXME("(%p) filter hasn't implemented current position change!\n", iface);
568 return S_OK;
571 static HRESULT Parser_ChangeStop(IBaseFilter *iface)
573 FIXME("(%p) filter hasn't implemented stop position change!\n", iface);
574 return S_OK;
577 static HRESULT Parser_ChangeRate(IBaseFilter *iface)
579 FIXME("(%p) filter hasn't implemented rate change!\n", iface);
580 return S_OK;
584 static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
586 ParserImpl *This = impl_from_IMediaSeeking(iface);
588 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
591 static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
593 ParserImpl *This = impl_from_IMediaSeeking(iface);
595 return IUnknown_AddRef((IUnknown *)This);
598 static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
600 ParserImpl *This = impl_from_IMediaSeeking(iface);
602 return IUnknown_Release((IUnknown *)This);
605 static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
607 Parser_Seeking_QueryInterface,
608 Parser_Seeking_AddRef,
609 Parser_Seeking_Release,
610 MediaSeekingImpl_GetCapabilities,
611 MediaSeekingImpl_CheckCapabilities,
612 MediaSeekingImpl_IsFormatSupported,
613 MediaSeekingImpl_QueryPreferredFormat,
614 MediaSeekingImpl_GetTimeFormat,
615 MediaSeekingImpl_IsUsingTimeFormat,
616 MediaSeekingImpl_SetTimeFormat,
617 MediaSeekingImpl_GetDuration,
618 MediaSeekingImpl_GetStopPosition,
619 MediaSeekingImpl_GetCurrentPosition,
620 MediaSeekingImpl_ConvertTimeFormat,
621 MediaSeekingImpl_SetPositions,
622 MediaSeekingImpl_GetPositions,
623 MediaSeekingImpl_GetAvailable,
624 MediaSeekingImpl_SetRate,
625 MediaSeekingImpl_GetRate,
626 MediaSeekingImpl_GetPreroll
629 static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
631 Parser_OutputPin *This = (Parser_OutputPin *)iface;
633 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
635 *ppv = NULL;
637 if (IsEqualIID(riid, &IID_IUnknown))
638 *ppv = (LPVOID)iface;
639 else if (IsEqualIID(riid, &IID_IPin))
640 *ppv = (LPVOID)iface;
641 else if (IsEqualIID(riid, &IID_IMediaSeeking))
643 return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
646 if (*ppv)
648 IUnknown_AddRef((IUnknown *)(*ppv));
649 return S_OK;
652 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
654 return E_NOINTERFACE;
657 static ULONG WINAPI Parser_OutputPin_Release(IPin * iface)
659 Parser_OutputPin *This = (Parser_OutputPin *)iface;
660 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
662 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
664 if (!refCount)
666 FreeMediaType(This->pmt);
667 CoTaskMemFree(This->pmt);
668 FreeMediaType(&This->pin.pin.mtCurrent);
669 CoTaskMemFree(This);
670 return 0;
672 return refCount;
675 static HRESULT WINAPI Parser_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
677 ENUMMEDIADETAILS emd;
678 Parser_OutputPin *This = (Parser_OutputPin *)iface;
680 TRACE("(%p)\n", ppEnum);
682 /* override this method to allow enumeration of your types */
683 emd.cMediaTypes = 1;
684 emd.pMediaTypes = This->pmt;
686 return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
689 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
691 Parser_OutputPin *This = (Parser_OutputPin *)iface;
693 TRACE("()\n");
694 dump_AM_MEDIA_TYPE(pmt);
696 return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
699 static const IPinVtbl Parser_OutputPin_Vtbl =
701 Parser_OutputPin_QueryInterface,
702 IPinImpl_AddRef,
703 Parser_OutputPin_Release,
704 OutputPin_Connect,
705 OutputPin_ReceiveConnection,
706 OutputPin_Disconnect,
707 IPinImpl_ConnectedTo,
708 IPinImpl_ConnectionMediaType,
709 IPinImpl_QueryPinInfo,
710 IPinImpl_QueryDirection,
711 IPinImpl_QueryId,
712 IPinImpl_QueryAccept,
713 Parser_OutputPin_EnumMediaTypes,
714 IPinImpl_QueryInternalConnections,
715 OutputPin_EndOfStream,
716 OutputPin_BeginFlush,
717 OutputPin_EndFlush,
718 OutputPin_NewSegment
721 static HRESULT Parser_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
723 PullPin * pPinImpl;
725 *ppPin = NULL;
727 if (pPinInfo->dir != PINDIR_INPUT)
729 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
730 return E_INVALIDARG;
733 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
735 if (!pPinImpl)
736 return E_OUTOFMEMORY;
738 if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
740 pPinImpl->pin.lpVtbl = &Parser_InputPin_Vtbl;
742 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
743 return S_OK;
746 CoTaskMemFree(pPinImpl);
747 return E_FAIL;
750 static HRESULT WINAPI Parser_InputPin_Disconnect(IPin * iface)
752 HRESULT hr;
753 IPinImpl *This = (IPinImpl *)iface;
755 TRACE("()\n");
757 EnterCriticalSection(This->pCritSec);
759 if (This->pConnectedTo)
761 FILTER_STATE state;
763 hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
765 if (SUCCEEDED(hr) && (state == State_Stopped))
767 IPin_Release(This->pConnectedTo);
768 This->pConnectedTo = NULL;
769 hr = Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
771 else
772 hr = VFW_E_NOT_STOPPED;
774 else
775 hr = S_FALSE;
777 LeaveCriticalSection(This->pCritSec);
779 return hr;
782 HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
784 HRESULT hr;
786 TRACE("()\n");
788 hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt);
789 if (FAILED(hr))
791 IPinImpl *This = (IPinImpl *)iface;
793 EnterCriticalSection(This->pCritSec);
794 Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
795 LeaveCriticalSection(This->pCritSec);
798 return hr;
801 static const IPinVtbl Parser_InputPin_Vtbl =
803 PullPin_QueryInterface,
804 IPinImpl_AddRef,
805 PullPin_Release,
806 OutputPin_Connect,
807 Parser_PullPin_ReceiveConnection,
808 Parser_InputPin_Disconnect,
809 IPinImpl_ConnectedTo,
810 IPinImpl_ConnectionMediaType,
811 IPinImpl_QueryPinInfo,
812 IPinImpl_QueryDirection,
813 IPinImpl_QueryId,
814 IPinImpl_QueryAccept,
815 IPinImpl_EnumMediaTypes,
816 IPinImpl_QueryInternalConnections,
817 PullPin_EndOfStream,
818 PullPin_BeginFlush,
819 PullPin_EndFlush,
820 PullPin_NewSegment